UNPKG

react-flex-picker

Version:

Helps to build your own calendar by using prepared components and api to control them

321 lines (263 loc) 9.51 kB
# react-flex-picker [![Build Status](https://travis-ci.org/unbugx/react-flex-picker.svg?branch=master)](https://travis-ci.org/unbugx/react-flex-picker) For online demo go to https://unbugx.github.io/react-flex-picker/ To run demo on your own computer: * Clone this repository * `npm install` * `npm run storybook` * Open http://localhost:9002/ ## Getting Started ``` npm install --save react-flex-picker ``` Add the following import to your application if you use Webpack with CSS loader: ``` import 'react-flex-picker/dist/react-flex-picker.css'; ``` #### Make own datepickers Using a few simple components you can build your own calendar with any logic you want. Just import these components: ``` import {PickerProvider, PickerConsumer, DayPickerController, MonthPickerController} from 'react-flex-picker'; ``` ##### PickerProvider This picker based on React Context Api. It creates provider that keeps all business logic and all data to control calendar. PickerProvider has following list of properties: |name|type|description| |---|---|---| |initialEndDate|Moment|Initial end date in range for range picker. Ignore for single picker.| |initialStartDate|Moment|Initial start date in range for range picker. Also it is used as initial date for single picker.| |isSingle|boolean|Switch to single picker.| |isWeeksSelection|boolean|Switch to weeks selection.| |locale|string|Current locale. Default value: `en`| |maxDate|Moment|Maximum available date for choosing. All dates after maximum date will be disabled.| |maxDaysCount|number|Maximum number of days in range.| |minDate|Moment|Minimum available date for choosing. All dates before minimum date will be disabled.| |minDaysCount|number|Minimum number of days in range.| |onChangeWidth|function|Executes when picker width was changed. Sometimes this info can be useful when you build your own calendar.| |onDatesChange|function(startDate: Moment, endDate: Moment)|Executes when new date is picked up.| |onTitleClick|function|Executes when calendar title is clicked.| |pickerType|string|PickerProvider has to know what type of picker it controls. Available values are `day`, `month`. Default value: `day`| |showOutsideDays|boolean|First and last week of month will be filled with days from nearby months.| |styles|object|Object with class names to override current css styles.| |unitCount|number|Number of months for DayPickerController and number of years for MonthPickerController visible at a time. Default value: `1`| ##### PickerConsumer Works as common consumer in context api. It takes function as child that has one arguments with set of useful properties. The most useful properties are `handlePrevUnit` and `handleNextUnit` to switch months or years. ``` import * as React from 'react'; import {PickerProvider, PickerConsumer, DayPickerController} from 'react-flex-picker'; import * as moment from 'moment'; <PickerProvider initialStartDate={moment().add(-7, 'day')} onDatesChange={(startDate) => {console.log(startDate)}} isSingle > <PickerConsumer> {({handlePrevUnit, handleNextUnit}) => ( <div className='calendar'}> <div className='right' onClick={handleNextUnit}>&rarr;</div> <div className='left' onClick={handlePrevUnit}>&larr;</div> <DayPickerController /> </div> )} </PickerConsumer> </PickerProvider> ``` ##### DayPickerController and MonthPickerController Widgets of day picker and month picker accordingly. #### Overriding styles Here it's supposed you use webpack and css-loader. Css-loader allows you import styles as object with classes in keys: ``` import * as styles from '../styles.styl'; console.log(styles); ``` It will print out object like this: ``` { day: "customCalendarStyles___day" dayClickable: "customCalendarStyles___dayClickable" dayFirstSelected: "customCalendarStyles___dayFirstSelected" dayHovered: "customCalendarStyles___dayHovered" } ``` Where `key` is class name in `styles.styl` file and value is dynamic class name generated by css-loader that will be inserted in resulting html. To override existing styles just pass `styles` property to PickerProvider. Look at example below: ``` // calendar.styl .wrapper { background: #29323f; overflow: hidden; display: inline-block; user-select: none; font-family: 'Courier', sans-serif; > div { white-space: nowrap; } } .month { margin: 0 10px; width: 280px; display: inline-block; vertical-align: top; white-space: normal; .day { cursor: pointer; display: inline-block; text-align: center; width: 36px; height: 36px; line-height: 36px; border: 2px solid #29323f; color: #fff; border-radius: 50%; } .headerMonth { font-weight: bold; height: 30px; line-height: 30px; text-align: center; display: inline-block; width: 100%; cursor: default; color: #fcee6d; } .headerWeekDays { border-bottom: 1px grey solid; span { display: inline-block; width: 40px; height: 40px; text-align: center; line-height: 40px; cursor: default; color: #999; } } .dayClickable:hover { border-color: #e7d84f; } .dayFirstSelected, .dayLastSelected { border-color: #e7d84f; background: #e7d84f !important; color: #29323f; font-weight: bold; } .daySelected, .dayHovered { border-color: #e7d84f; background: #29323f; } } ``` ``` import * as React from 'react'; import {PickerProvider, PickerConsumer, DayPickerController} from 'react-flex-picker'; import * as moment from 'moment'; import * as styles from './calendar.styl'; <PickerProvider onDatesChange={() => {}} styles={customStyles} > <PickerConsumer> {({handlePrevUnit, handleNextUnit}) => ( <div className='calendar'> <div className='right' onClick={handleNextUnit}>&rarr;</div> <div className='left' onClick={handlePrevUnit}>&larr;</div> <DayPickerController /> </div> )} </PickerConsumer> </PickerProvider> ``` Below list of all available class that can be overridden: `wrapper`, `transition`, `day`, `dayDisabled`, `dayOff`, `daySelected`, `dayFirstSelected`, `dayLastSelected`, `dayClickable`, `dayHovered`, `month`, `headerMonthWrapper`, `headerMonth`, `headerClickable`, `headerWeekDays`, `daysWeek`, `year`, `headerYear`. #### Examples For more examples go to https://unbugx.github.io/react-flex-picker/ and source code of storybook examples https://github.com/unbugx/react-flex-picker/tree/master/src/stories Below a few more interested examples. ##### Date presets and Apply button ``` import * as React from 'react'; import {PickerProvider, PickerConsumer, DayPickerController} from 'react-flex-picker'; import * as moment from 'moment'; import * as styles from './styles.styl'; // here is should be your own file with css const today = moment(); const yesterday = moment().add(-1, 'day'); const nextMonthStart = moment().add(1, 'month').startOf('month'); const nextMonthEnd = moment().add(1, 'month').endOf('month'); class CalendarWithPresets extends React.Component { constructor(props) { super(props); this.state = { initialStartDate: moment().add(-7, 'day'), initialEndDate: moment(), selectedStartDate: moment().add(-7, 'day'), selectedEndDate: moment(), }; this.handlePreset = this.handlePreset.bind(this); this.handleDatesChange = this.handleDatesChange.bind(this); this.handleApply = this.handleApply.bind(this); } handlePreset(newStartDate, newEndDate) { this.setState({ initialStartDate: newStartDate, initialEndDate: newEndDate, selectedStartDate: newStartDate, selectedEndDate: newEndDate, }); } handleDatesChange(selectedStartDate, selectedEndDate) { this.setState({selectedStartDate, selectedEndDate}); } handleApply() { if (this.state.selectedStartDate && this.state.selectedEndDate) { // you can execute any callback here to pass selected data and hide calendar console.log(this.state.selectedStartDate.format('DD.MM.YYYY'), this.state.selectedEndDate.format('DD.MM.YYYY')); } } render() { return ( <PickerProvider onDatesChange={this.handleDatesChange} unitCount={3} showOutsideDays initialStartDate={this.state.initialStartDate} initialEndDate={this.state.initialEndDate} > <PickerConsumer> {({handlePrevUnit, handleNextUnit}) => ( <div className={styles.calendar}> <div className={styles.right} onClick={handleNextUnit}>&rarr;</div> <div className={styles.left} onClick={handlePrevUnit}>&larr;</div> <DayPickerController /> <div> <button onClick={() => this.handlePreset(today, today)} > Today </button> <button onClick={() => this.handlePreset(yesterday, yesterday)} > Yesterday </button> <button onClick={() => this.handlePreset(nextMonthStart, nextMonthEnd)} > Next month </button> <button onClick={this.handleApply}>Apply</button> </div> </div> )} </PickerConsumer> </PickerProvider> ); } } ``` More examples are coming soon...