├── examples └── src │ ├── scss │ └── index.scss │ ├── js │ ├── app.js │ └── components │ │ ├── App.js │ │ ├── Examples.js │ │ └── examples │ │ ├── SingleDatePicker.js │ │ ├── Internationalization.js │ │ ├── DateRangePicker.js │ │ ├── InputInitiallyEmpty.js │ │ ├── PredefinedRanges.js │ │ └── DateAndTime.js │ └── index.html ├── CHANGELOG.md ├── .travis.yml ├── .eslintrc ├── .npmignore ├── .babelrc ├── .editorconfig ├── lib ├── getOptions.js └── index.js ├── src ├── getOptions.js └── index.js ├── config.js ├── .gitignore ├── gulpfile.js ├── package.json └── README.md /examples/src/scss/index.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'stable' 4 | - '6' 5 | 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "onefe", 4 | "globals": { 5 | "__DEV__": true 6 | }, 7 | "rules": { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.idea 2 | .publish/ 3 | .babelrc 4 | .editorconfig 5 | .eslintrc 6 | .travis.yml 7 | .npmignore 8 | config.js 9 | gulpfile.js 10 | examples/ 11 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "env", 5 | "stage-0" 6 | ], 7 | "plugins": [ "transform-runtime", "transform-object-assign", "add-module-exports" ] 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /examples/src/js/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import { Router, Route, IndexRoute } from 'react-router'; 5 | import createHistory from 'history/lib/createHashHistory'; 6 | 7 | const history = createHistory({ queryKey: false }); 8 | 9 | import App from './components/App'; 10 | import Examples from './components/Examples'; 11 | 12 | const routes = ( 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | 20 | ReactDOM.render(routes, document.querySelector('#app')); 21 | -------------------------------------------------------------------------------- /lib/getOptions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | function getOptions() { 7 | return ['', 'applyClass', 'autoApply', 'autoUpdateInput', 'alwaysShowCalendars', 'buttonClasses', 'cancelClass', 'dateLimit', 'drops', 'endDate', 'isInvalidDate', 'linkedCalendars', 'locale', 'maxDate', 'minDate', 'opens', 'parentEl', 'ranges', 'showDropdowns', 'showWeekNumbers', 'singleDatePicker', 'startDate', 'template', 'timePicker', 'timePicker24Hour', 'timePickerIncrement', 'timePickerSeconds', 'timeZone']; 8 | } 9 | 10 | exports.default = getOptions; 11 | module.exports = exports['default']; -------------------------------------------------------------------------------- /examples/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | react-bootstrap-datetimerangepicker 7 | 8 | 9 | <%= links %> 10 | 11 | 12 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/getOptions.js: -------------------------------------------------------------------------------- 1 | function getOptions() { 2 | return [ 3 | '', 4 | 'applyClass', 5 | 'autoApply', 6 | 'autoUpdateInput', 7 | 'alwaysShowCalendars', 8 | 'buttonClasses', 9 | 'cancelClass', 10 | 'dateLimit', 11 | 'drops', 12 | 'endDate', 13 | 'isInvalidDate', 14 | 'linkedCalendars', 15 | 'locale', 16 | 'maxDate', 17 | 'minDate', 18 | 'opens', 19 | 'parentEl', 20 | 'ranges', 21 | 'showDropdowns', 22 | 'showWeekNumbers', 23 | 'singleDatePicker', 24 | 'startDate', 25 | 'template', 26 | 'timePicker', 27 | 'timePicker24Hour', 28 | 'timePickerIncrement', 29 | 'timePickerSeconds', 30 | 'timeZone', 31 | ]; 32 | } 33 | 34 | export default getOptions; 35 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var taskConfig = { 4 | 5 | component: { 6 | name: 'react-bootstrap-datetimerangepicker', 7 | lib: './lib', 8 | scripts: { 9 | entry: './src/index.js', 10 | output: { 11 | library: 'react-bootstrap-datetimerangepicker' 12 | }, 13 | externals: { 14 | react: { 15 | root: 'React', 16 | commonjs2: 'react', 17 | commonjs: 'react', 18 | amd: 'react' 19 | } 20 | } 21 | } 22 | }, 23 | 24 | example: { 25 | src: './examples/src', 26 | dist: './examples/dist', 27 | index: 'index.html', 28 | script: 'js/app.js', 29 | alias: { 30 | 'react-bootstrap-datetimerangepicker': path.resolve(__dirname, './src') 31 | }, 32 | files: [] 33 | } 34 | 35 | }; 36 | 37 | module.exports = taskConfig; 38 | -------------------------------------------------------------------------------- /examples/src/js/components/App.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.css'; 2 | import 'font-awesome/css/font-awesome.css'; 3 | 4 | import React from 'react'; 5 | import { 6 | Navbar, 7 | NavBrand, 8 | Nav, 9 | NavItem, 10 | } from 'react-bootstrap'; 11 | 12 | class App extends React.Component { 13 | 14 | static propTypes = { 15 | children: React.PropTypes.node, 16 | }; 17 | 18 | render() { 19 | return ( 20 |
21 | 22 | React Bootstrap Date&Time Range Picker 23 | 32 | 33 | 34 | {this.props.children} 35 |
36 | ); 37 | } 38 | 39 | } 40 | 41 | export default App; 42 | -------------------------------------------------------------------------------- /examples/src/js/components/Examples.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap-daterangepicker/daterangepicker.css'; 2 | 3 | import React from 'react'; 4 | import { 5 | Alert, 6 | Grid, 7 | Glyphicon, 8 | } from 'react-bootstrap'; 9 | 10 | import DateRangePicker from './examples/DateRangePicker'; 11 | import DateAndTime from './examples/DateAndTime'; 12 | import SingleDatePicker from './examples/SingleDatePicker'; 13 | import PredefinedRanges from './examples/PredefinedRanges'; 14 | import InputInitiallyEmpty from './examples/InputInitiallyEmpty'; 15 | // import Internationalization from './examples/Internationalization'; 16 | 17 | class Examples extends React.Component { 18 | 19 | render() { 20 | return ( 21 | 22 |

Examples

23 | 24 |  You can find examples source code here. 25 | 26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | {/* */} 35 |
36 |
37 |
38 | ); 39 | } 40 | } 41 | 42 | export default Examples; 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # ========================= 31 | # Operating System Files 32 | # ========================= 33 | 34 | # OSX 35 | # ========================= 36 | 37 | .DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | 41 | # Thumbnails 42 | ._* 43 | 44 | # Files that might appear on external disk 45 | .Spotlight-V100 46 | .Trashes 47 | 48 | # Directories potentially created on remote AFP share 49 | .AppleDB 50 | .AppleDesktop 51 | Network Trash Folder 52 | Temporary Items 53 | .apdisk 54 | 55 | # Windows 56 | # ========================= 57 | 58 | # Windows image file caches 59 | Thumbs.db 60 | ehthumbs.db 61 | 62 | # Folder config file 63 | Desktop.ini 64 | 65 | # Recycle Bin used on file shares 66 | $RECYCLE.BIN/ 67 | 68 | # Windows Installer files 69 | *.cab 70 | *.msi 71 | *.msm 72 | *.msp 73 | 74 | # Windows shortcuts 75 | *.lnk 76 | 77 | # IDEA 78 | # ========================= 79 | 80 | .idea 81 | 82 | .publish 83 | examples/dist 84 | .vs 85 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var initGulpTasks = require('react-pack'); 3 | var request = require('request'); 4 | var cheerio = require('cheerio'); 5 | var fs = require('fs'); 6 | 7 | var taskConfig = require('./config'); 8 | 9 | initGulpTasks(gulp, taskConfig); 10 | 11 | gulp.task('getoptions', function () { 12 | request('http://www.daterangepicker.com/', function (error, response, body) { 13 | var $ = cheerio.load(body); 14 | var options = $('#options ul li code').map(function () { 15 | return $(this).text().trim(); 16 | }).get(); 17 | // add options that aren't documented 18 | options.push('template'); 19 | // de-dupe and sort 20 | options = options.filter(function (item, index) { 21 | return options.indexOf(item) === index; 22 | }).sort(); 23 | 24 | fs.writeFile('./src/get-options.js', [ 25 | '/* generated by gulpfile.js */', 26 | 'module.exports = exports = function () {', 27 | '\treturn ' + JSON.stringify(options, null, '\t\t') + ';', 28 | '};' 29 | ].join('\n'), 'utf-8'); 30 | 31 | // fix options that contain html strings 32 | options = options.map(function (option) { 33 | return option.replace(/\/gi, '>'); 34 | }); 35 | // update README.md 36 | var before = 'You can pass all the same props as the original plugin:', 37 | after = 'You can listen to the following 7 events:', 38 | readme = fs.readFileSync('./README.md').toString(), 39 | newReadme = readme.slice(0, readme.indexOf(before) + before.length) + 40 | '\n\n- **' + 41 | wrap(options.join(', ')).slice(2) + 42 | '**\n\n' + 43 | readme.slice(readme.indexOf(after)); 44 | fs.writeFileSync('./README.md', newReadme, 'utf-8'); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/SingleDatePicker.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | import moment from 'moment'; 4 | 5 | import { 6 | Button, 7 | } from 'react-bootstrap'; 8 | 9 | class SingleDatePicker extends React.Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | 14 | this.handleEvent = this.handleEvent.bind(this); 15 | 16 | this.state = { 17 | startDate: moment().subtract(29, 'days'), 18 | }; 19 | } 20 | 21 | handleEvent(event, picker) { 22 | this.setState({ 23 | startDate: picker.startDate, 24 | }); 25 | } 26 | 27 | render() { 28 | let label = this.state.startDate.format('YYYY-MM-DD'); 29 | 30 | let locale = { 31 | format: 'YYYY-MM-DD', 32 | separator: ' - ', 33 | applyLabel: 'Apply', 34 | cancelLabel: 'Cancel', 35 | weekLabel: 'W', 36 | customRangeLabel: 'Custom Range', 37 | daysOfWeek: moment.weekdaysMin(), 38 | monthNames: moment.monthsShort(), 39 | firstDay: moment.localeData().firstDayOfWeek(), 40 | }; 41 | 42 | let buttonStyle = { width: '100%' }; 43 | 44 | return ( 45 |
46 | 47 |
48 | 55 | 67 | 68 |
69 |
70 | ); 71 | } 72 | 73 | } 74 | 75 | export default SingleDatePicker; 76 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/Internationalization.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | import moment from 'moment'; 4 | 5 | import { 6 | Button, 7 | } from 'react-bootstrap'; 8 | 9 | class Internationalization extends React.Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | 14 | this.handleEvent = this.handleEvent.bind(this); 15 | 16 | this.state = { 17 | startDate: moment().subtract(29, 'days'), 18 | endDate: moment(), 19 | }; 20 | } 21 | 22 | handleEvent(event, picker) { 23 | this.setState({ 24 | startDate: picker.startDate, 25 | endDate: picker.endDate, 26 | }); 27 | } 28 | 29 | render() { 30 | let start = this.state.startDate.format('YYYY-MM-DD'); 31 | let end = this.state.endDate.format('YYYY-MM-DD'); 32 | let label = start + ' - ' + end; 33 | if (start === end) { 34 | label = start; 35 | } 36 | 37 | let locale = { 38 | format: 'YYYY-MM-DD', 39 | separator: ' - ', 40 | applyLabel: 'Apply', 41 | cancelLabel: 'Clear', 42 | weekLabel: 'W', 43 | customRangeLabel: 'Custom Range', 44 | daysOfWeek: moment.weekdaysMin(), 45 | monthNames: moment.monthsShort(), 46 | firstDay: moment.localeData().firstDayOfWeek(), 47 | }; 48 | 49 | return ( 50 |
51 | 52 |
53 | 60 |
61 | 62 | 63 | 66 | 67 |
68 |
69 |
70 |
71 | ); 72 | } 73 | 74 | } 75 | 76 | export default Internationalization; 77 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/DateRangePicker.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | import moment from 'moment'; 4 | 5 | import { 6 | Button, 7 | } from 'react-bootstrap'; 8 | 9 | class DateRangePicker extends React.Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | 14 | this.handleApply = this.handleApply.bind(this); 15 | 16 | this.state = { 17 | startDate: moment().subtract(29, 'days'), 18 | endDate: moment(), 19 | ranges: { 20 | 'Today': [moment(), moment()], 21 | 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], 22 | 'Last 7 Days': [moment().subtract(6, 'days'), moment()], 23 | 'Last 30 Days': [moment().subtract(29, 'days'), moment()], 24 | 'This Month': [moment().startOf('month'), moment().endOf('month')], 25 | 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')], 26 | }, 27 | }; 28 | } 29 | 30 | handleApply(event, picker) { 31 | this.setState({ 32 | startDate: picker.startDate, 33 | endDate: picker.endDate, 34 | }); 35 | } 36 | 37 | render() { 38 | let start = this.state.startDate.format('YYYY-MM-DD'); 39 | let end = this.state.endDate.format('YYYY-MM-DD'); 40 | let label = start + ' - ' + end; 41 | if (start === end) { 42 | label = start; 43 | } 44 | 45 | return ( 46 |
47 | 48 |
49 | 54 |
55 | 56 | 57 | 60 | 61 |
62 |
63 |
64 |
65 | ); 66 | } 67 | 68 | } 69 | 70 | export default DateRangePicker; 71 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/InputInitiallyEmpty.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | 4 | import { 5 | Button, 6 | } from 'react-bootstrap'; 7 | 8 | class InputInitiallyEmpty extends React.Component { 9 | 10 | constructor(props) { 11 | super(props); 12 | 13 | this.handleApply = this.handleApply.bind(this); 14 | this.handleCancel = this.handleCancel.bind(this); 15 | 16 | this.state = { 17 | startDate: undefined, 18 | endDate: undefined, 19 | }; 20 | } 21 | 22 | handleApply(event, picker) { 23 | this.setState({ 24 | startDate: picker.startDate, 25 | endDate: picker.endDate, 26 | }); 27 | } 28 | 29 | handleCancel() { 30 | this.setState({ 31 | startDate: undefined, 32 | endDate: undefined, 33 | }); 34 | } 35 | 36 | render() { 37 | let { startDate, endDate } = this.state; 38 | 39 | let label = ''; 40 | let start = startDate && startDate.format('YYYY-MM-DD') || ''; 41 | let end = endDate && endDate.format('YYYY-MM-DD') || ''; 42 | label = start + ' - ' + end; 43 | if (start === end) { 44 | label = start; 45 | } 46 | 47 | let locale = { 48 | format: 'YYYY-MM-DD', 49 | cancelLabel: 'Clear', 50 | }; 51 | 52 | let pickerProps = { 53 | startDate, 54 | endDate, 55 | }; 56 | 57 | return ( 58 |
59 | 60 |
61 | 68 |
69 | 70 | 71 | 74 | 75 |
76 |
77 |
78 |
79 | ); 80 | } 81 | 82 | } 83 | 84 | export default InputInitiallyEmpty; 85 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/PredefinedRanges.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | import moment from 'moment'; 4 | 5 | import { 6 | Button, 7 | } from 'react-bootstrap'; 8 | 9 | class PredefinedRanges extends React.Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | 14 | this.handleEvent = this.handleEvent.bind(this); 15 | 16 | this.state = { 17 | startDate: moment().subtract(29, 'days'), 18 | endDate: moment(), 19 | ranges: { 20 | 'Today': [moment(), moment()], 21 | 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], 22 | 'Last 7 Days': [moment().subtract(6, 'days'), moment()], 23 | 'Last 30 Days': [moment().subtract(29, 'days'), moment()], 24 | 'This Month': [moment().startOf('month'), moment().endOf('month')], 25 | 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')], 26 | }, 27 | }; 28 | } 29 | 30 | handleEvent(event, picker) { 31 | this.setState({ 32 | startDate: picker.startDate, 33 | endDate: picker.endDate, 34 | }); 35 | } 36 | 37 | render() { 38 | let start = this.state.startDate.format('MMMM D, YYYY'); 39 | let end = this.state.endDate.format('MMMM D, YYYY'); 40 | let label = start + ' - ' + end; 41 | if (start === end) { 42 | label = start; 43 | } 44 | 45 | let buttonStyle = { width: '100%' }; 46 | 47 | return ( 48 |
49 | 50 |
51 | 57 | 69 | 70 |
71 |
72 | ); 73 | } 74 | 75 | } 76 | 77 | export default PredefinedRanges; 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bootstrap-datetimerangepicker", 3 | "version": "2.0.5", 4 | "description": "React date & time range picker component base on bootstrap-daterangepicker. This date range picker component for Bootstrap creates a dropdown menu from which a user can select a range of dates. Features include limiting the selectable date range, localizable strings and date formats, a single date picker mode, optional time picker", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "babel ./src -d lib", 8 | "prepublish": "npm run build", 9 | "gh-pages": "gulp publish:examples", 10 | "lint": "eslint src examples/src", 11 | "start": "gulp dev", 12 | "test": "npm run lint" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/luqin/react-bootstrap-datetimerangepicker" 17 | }, 18 | "license": "ISC", 19 | "peerDependencies": { 20 | "jquery": ">=1.11.3", 21 | "react": ">=0.14.0", 22 | "bootstrap-daterangepicker": "^2.1.19" 23 | }, 24 | "dependencies": { 25 | "babel-runtime": "^6.26.0", 26 | "classnames": "^2.2.3", 27 | "prop-types": "^15.5.9" 28 | }, 29 | "devDependencies": { 30 | "babel-plugin-add-module-exports": "~0.2.1", 31 | "babel-cli": "~6.26.0", 32 | "babel-core": "~6.26.0", 33 | "babel-eslint": "~7.2.3", 34 | "babel-preset-env": "1.6.0", 35 | "babel-preset-react": "~6.24.1", 36 | "babel-plugin-transform-object-assign": "~6.22.0", 37 | "babel-plugin-transform-runtime": "~6.23.0", 38 | "babel-preset-stage-0": "~6.24.1", 39 | "bootstrap": "3.3.5", 40 | "bootstrap-daterangepicker": "^2.1.19", 41 | "cheerio": "^0.19.0", 42 | "eslint": "^1.10.3", 43 | "eslint-config-airbnb": "2.1.1", 44 | "eslint-config-onefe": "0.2.0", 45 | "eslint-plugin-react": "^3.11.3", 46 | "font-awesome": "^4.5.0", 47 | "gulp": "^3.9.0", 48 | "history": "1.13.x", 49 | "jquery": "^2.1.4", 50 | "moment": "^2.12.0", 51 | "node-sass": "3.4.2", 52 | "react": "^0.14.3", 53 | "react-bootstrap": "^0.28.1", 54 | "react-dom": "^0.14.3", 55 | "react-pack": "^0.3.0", 56 | "react-router": "1.0.2", 57 | "react-router-bootstrap": "^0.19.3", 58 | "request": "^2.67.0", 59 | "webpack": "1.12.6", 60 | "webpack-dev-server": "1.12.1" 61 | }, 62 | "keywords": [ 63 | "react", 64 | "react-dom", 65 | "ui", 66 | "react-component", 67 | "bootstrap", 68 | "date", 69 | "range", 70 | "picker", 71 | "selector", 72 | "datetime" 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /examples/src/js/components/examples/DateAndTime.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 3 | import moment from 'moment'; 4 | 5 | import { 6 | Button, 7 | } from 'react-bootstrap'; 8 | 9 | class DateAndTime extends React.Component { 10 | 11 | constructor(props) { 12 | super(props); 13 | 14 | this.handleApply = this.handleApply.bind(this); 15 | 16 | this.state = { 17 | startDate: moment().subtract(29, 'days'), 18 | endDate: moment(), 19 | ranges: { 20 | 'Today': [moment(), moment()], 21 | 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], 22 | 'Last 7 Days': [moment().subtract(6, 'days'), moment()], 23 | 'Last 30 Days': [moment().subtract(29, 'days'), moment()], 24 | 'This Month': [moment().startOf('month'), moment().endOf('month')], 25 | 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')], 26 | }, 27 | }; 28 | } 29 | 30 | handleApply(event, picker) { 31 | this.setState({ 32 | startDate: picker.startDate, 33 | endDate: picker.endDate, 34 | }); 35 | } 36 | 37 | render() { 38 | let start = this.state.startDate.format('YYYY-MM-DD HH:mm:ss'); 39 | let end = this.state.endDate.format('YYYY-MM-DD HH:mm:ss'); 40 | let label = start + ' - ' + end; 41 | if (start === end) { 42 | label = start; 43 | } 44 | 45 | let locale = { 46 | format: 'YYYY-MM-DD HH:mm:ss', 47 | separator: ' - ', 48 | applyLabel: 'Apply', 49 | cancelLabel: 'Cancel', 50 | weekLabel: 'W', 51 | customRangeLabel: 'Custom Range', 52 | daysOfWeek: moment.weekdaysMin(), 53 | monthNames: moment.monthsShort(), 54 | firstDay: moment.localeData().firstDayOfWeek(), 55 | }; 56 | 57 | return ( 58 |
59 | 60 |
61 | 71 |
72 | 73 | 74 | 77 | 78 |
79 |
80 |
81 |
82 | ); 83 | } 84 | 85 | } 86 | 87 | export default DateAndTime; 88 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import $ from 'jquery'; 4 | import 'bootstrap-daterangepicker'; 5 | import getOptions from './getOptions'; 6 | 7 | let events = ['Show', 'Hide', 'ShowCalendar', 'HideCalendar', 'Apply', 'Cancel']; 8 | 9 | class DatetimeRangePicker extends React.Component { 10 | 11 | static propTypes = { 12 | 13 | startDate: PropTypes.any, 14 | endDate: PropTypes.any, 15 | children: PropTypes.any, 16 | className: PropTypes.string, 17 | style: PropTypes.object, 18 | 19 | callback: PropTypes.func, 20 | onEvent: PropTypes.func, 21 | onShow: PropTypes.func, 22 | onHide: PropTypes.func, 23 | onShowCalendar: PropTypes.func, 24 | onHideCalendar: PropTypes.func, 25 | onApply: PropTypes.func, 26 | onCancel: PropTypes.func, 27 | }; 28 | 29 | static defaultProps = {}; 30 | 31 | constructor(props) { 32 | super(props); 33 | this.state = {}; 34 | 35 | this.$picker = undefined; 36 | this.picker = undefined; 37 | this.options = getOptions(); 38 | 39 | this.handleCallback = this.handleCallback.bind(this); 40 | } 41 | 42 | componentDidMount() { 43 | this.$picker = $(this.refs.picker); 44 | // initialize 45 | this.$picker.daterangepicker(this.getOptionsFromProps(), this.handleCallback); 46 | // attach event listeners 47 | events.forEach(event => { 48 | let cCase = event.charAt(0).toLowerCase() + event.slice(1); 49 | this.$picker.on(cCase + '.daterangepicker', this.makeEventHandler('on' + event)); 50 | }); 51 | } 52 | 53 | componentWillUnmount() { 54 | this.getPicker().remove(); 55 | } 56 | 57 | setOptionsFromProps() { 58 | let currentOptions = this.getOptionsFromProps(); 59 | let keys = Object.keys(currentOptions); 60 | if (this.$picker) { 61 | if (currentOptions) { 62 | keys.forEach(key => { 63 | this.applyOptionToPicker(key, currentOptions[key]); 64 | }); 65 | } 66 | } 67 | } 68 | 69 | getPicker() { 70 | return this.$picker && this.$picker.data('daterangepicker'); 71 | } 72 | 73 | getOptionsFromProps() { 74 | let options = {}; 75 | let props = this.props; 76 | let value; 77 | this.options.forEach(name => { 78 | if (props.hasOwnProperty(name)) { 79 | value = props[name]; 80 | 81 | switch (name) { 82 | case 'startDate': 83 | case 'endDate': 84 | if (value) { 85 | options[name] = value; 86 | } 87 | break; 88 | 89 | case 'locale': 90 | if (value && typeof value === 'object') { 91 | let picker = this.getPicker(); 92 | if (picker) { 93 | value = $.extend({}, value, picker.locale); 94 | } 95 | } 96 | options[name] = value; 97 | break; 98 | 99 | default: 100 | options[name] = value; 101 | } 102 | } 103 | }); 104 | return options; 105 | } 106 | 107 | applyOptionToPicker(key, value) { 108 | if (this.$picker) { 109 | this.$picker.data('daterangepicker')[key] = value; 110 | } 111 | } 112 | 113 | handleCallback(start, end) { 114 | if (typeof this.props.callback === 'function') { 115 | this.props.callback(start, end); 116 | } 117 | } 118 | 119 | makeEventHandler(eventType) { 120 | return (event, picker) => { 121 | if (this.props.onEvent) { 122 | this.props.onEvent(event, picker); 123 | } 124 | if (typeof this.props[eventType] === 'function') { 125 | this.props[eventType](event, picker); 126 | } 127 | }; 128 | } 129 | 130 | render() { 131 | this.setOptionsFromProps(); 132 | 133 | return ( 134 |
135 | {this.props.children} 136 |
137 | ); 138 | } 139 | 140 | } 141 | 142 | export default DatetimeRangePicker; 143 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _typeof2 = require('babel-runtime/helpers/typeof'); 8 | 9 | var _typeof3 = _interopRequireDefault(_typeof2); 10 | 11 | var _keys = require('babel-runtime/core-js/object/keys'); 12 | 13 | var _keys2 = _interopRequireDefault(_keys); 14 | 15 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); 16 | 17 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); 18 | 19 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 20 | 21 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 22 | 23 | var _createClass2 = require('babel-runtime/helpers/createClass'); 24 | 25 | var _createClass3 = _interopRequireDefault(_createClass2); 26 | 27 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 28 | 29 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 30 | 31 | var _inherits2 = require('babel-runtime/helpers/inherits'); 32 | 33 | var _inherits3 = _interopRequireDefault(_inherits2); 34 | 35 | var _react = require('react'); 36 | 37 | var _react2 = _interopRequireDefault(_react); 38 | 39 | var _propTypes = require('prop-types'); 40 | 41 | var _propTypes2 = _interopRequireDefault(_propTypes); 42 | 43 | var _jquery = require('jquery'); 44 | 45 | var _jquery2 = _interopRequireDefault(_jquery); 46 | 47 | require('bootstrap-daterangepicker'); 48 | 49 | var _getOptions = require('./getOptions'); 50 | 51 | var _getOptions2 = _interopRequireDefault(_getOptions); 52 | 53 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 54 | 55 | var events = ['Show', 'Hide', 'ShowCalendar', 'HideCalendar', 'Apply', 'Cancel']; 56 | 57 | var DatetimeRangePicker = function (_React$Component) { 58 | (0, _inherits3.default)(DatetimeRangePicker, _React$Component); 59 | 60 | function DatetimeRangePicker(props) { 61 | (0, _classCallCheck3.default)(this, DatetimeRangePicker); 62 | 63 | var _this = (0, _possibleConstructorReturn3.default)(this, (DatetimeRangePicker.__proto__ || (0, _getPrototypeOf2.default)(DatetimeRangePicker)).call(this, props)); 64 | 65 | _this.state = {}; 66 | 67 | _this.$picker = undefined; 68 | _this.picker = undefined; 69 | _this.options = (0, _getOptions2.default)(); 70 | 71 | _this.handleCallback = _this.handleCallback.bind(_this); 72 | return _this; 73 | } 74 | 75 | (0, _createClass3.default)(DatetimeRangePicker, [{ 76 | key: 'componentDidMount', 77 | value: function componentDidMount() { 78 | var _this2 = this; 79 | 80 | this.$picker = (0, _jquery2.default)(this.refs.picker); 81 | // initialize 82 | this.$picker.daterangepicker(this.getOptionsFromProps(), this.handleCallback); 83 | // attach event listeners 84 | events.forEach(function (event) { 85 | var cCase = event.charAt(0).toLowerCase() + event.slice(1); 86 | _this2.$picker.on(cCase + '.daterangepicker', _this2.makeEventHandler('on' + event)); 87 | }); 88 | } 89 | }, { 90 | key: 'componentWillUnmount', 91 | value: function componentWillUnmount() { 92 | this.getPicker().remove(); 93 | } 94 | }, { 95 | key: 'setOptionsFromProps', 96 | value: function setOptionsFromProps() { 97 | var _this3 = this; 98 | 99 | var currentOptions = this.getOptionsFromProps(); 100 | var keys = (0, _keys2.default)(currentOptions); 101 | if (this.$picker) { 102 | if (currentOptions) { 103 | keys.forEach(function (key) { 104 | _this3.applyOptionToPicker(key, currentOptions[key]); 105 | }); 106 | } 107 | } 108 | } 109 | }, { 110 | key: 'getPicker', 111 | value: function getPicker() { 112 | return this.$picker && this.$picker.data('daterangepicker'); 113 | } 114 | }, { 115 | key: 'getOptionsFromProps', 116 | value: function getOptionsFromProps() { 117 | var _this4 = this; 118 | 119 | var options = {}; 120 | var props = this.props; 121 | var value = void 0; 122 | this.options.forEach(function (name) { 123 | if (props.hasOwnProperty(name)) { 124 | value = props[name]; 125 | 126 | switch (name) { 127 | case 'startDate': 128 | case 'endDate': 129 | if (value) { 130 | options[name] = value; 131 | } 132 | break; 133 | 134 | case 'locale': 135 | if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { 136 | var picker = _this4.getPicker(); 137 | if (picker) { 138 | value = _jquery2.default.extend({}, value, picker.locale); 139 | } 140 | } 141 | options[name] = value; 142 | break; 143 | 144 | default: 145 | options[name] = value; 146 | } 147 | } 148 | }); 149 | return options; 150 | } 151 | }, { 152 | key: 'applyOptionToPicker', 153 | value: function applyOptionToPicker(key, value) { 154 | if (this.$picker) { 155 | this.$picker.data('daterangepicker')[key] = value; 156 | } 157 | } 158 | }, { 159 | key: 'handleCallback', 160 | value: function handleCallback(start, end) { 161 | if (typeof this.props.callback === 'function') { 162 | this.props.callback(start, end); 163 | } 164 | } 165 | }, { 166 | key: 'makeEventHandler', 167 | value: function makeEventHandler(eventType) { 168 | var _this5 = this; 169 | 170 | return function (event, picker) { 171 | if (_this5.props.onEvent) { 172 | _this5.props.onEvent(event, picker); 173 | } 174 | if (typeof _this5.props[eventType] === 'function') { 175 | _this5.props[eventType](event, picker); 176 | } 177 | }; 178 | } 179 | }, { 180 | key: 'render', 181 | value: function render() { 182 | this.setOptionsFromProps(); 183 | 184 | return _react2.default.createElement( 185 | 'div', 186 | { ref: 'picker', style: this.props.style, className: this.props.className }, 187 | this.props.children 188 | ); 189 | } 190 | }]); 191 | return DatetimeRangePicker; 192 | }(_react2.default.Component); 193 | 194 | DatetimeRangePicker.propTypes = { 195 | 196 | startDate: _propTypes2.default.any, 197 | endDate: _propTypes2.default.any, 198 | children: _propTypes2.default.any, 199 | className: _propTypes2.default.string, 200 | style: _propTypes2.default.object, 201 | 202 | callback: _propTypes2.default.func, 203 | onEvent: _propTypes2.default.func, 204 | onShow: _propTypes2.default.func, 205 | onHide: _propTypes2.default.func, 206 | onShowCalendar: _propTypes2.default.func, 207 | onHideCalendar: _propTypes2.default.func, 208 | onApply: _propTypes2.default.func, 209 | onCancel: _propTypes2.default.func 210 | }; 211 | DatetimeRangePicker.defaultProps = {}; 212 | exports.default = DatetimeRangePicker; 213 | module.exports = exports['default']; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Date&Time Range Picker for Bootstrap 2 | 3 | [![NPM version][npm-badge]][npm] [![Build Status][travis-ci-image]][travis-ci-url] 4 | 5 | [![Dependency Status][deps-badge]][deps] 6 | [![devDependency Status][dev-deps-badge]][dev-deps] 7 | [![peerDependency Status][peer-deps-badge]][peer-deps] 8 | 9 | ![Improvely.com](http://i.imgur.com/LbAMf3D.png) 10 | 11 | This date range picker component for Bootstrap creates a dropdown menu from which a user can select a range of dates. 12 | 13 | Base on [bootstrap-daterangepicker](https://github.com/dangrossman/bootstrap-daterangepicker) 14 | 15 | Online demo: http://luqin.github.io/react-bootstrap-datetimerangepicker 16 | 17 | ## Features 18 | 19 | * limiting the selectable date range 20 | * localizable strings and date formats 21 | * a single date picker mode 22 | * optional time picker (for e.g. making appointments or reservations) 23 | * styles that match the default Bootstrap 3 theme 24 | 25 | 26 | 27 | ## Upgrade guide 28 | 29 | **<2.0 to 2.x** 30 | 31 | Using official `bootstrap-daterangepicker` 32 | 33 | ```sh 34 | # <2.0 35 | npm install react-bootstrap-datetimerangepicker onefe-bootstrap-daterangepicker --save 36 | 37 | # 2.x 38 | npm install react-bootstrap-datetimerangepicker bootstrap-daterangepicker --save 39 | ``` 40 | 41 | ```js 42 | // <2.0 43 | import 'bootstrap/dist/css/bootstrap.css'; 44 | import 'onefe-bootstrap-daterangepicker/daterangepicker.css'; 45 | 46 | // 2.x 47 | import 'bootstrap/dist/css/bootstrap.css'; 48 | import 'bootstrap-daterangepicker/daterangepicker.css'; 49 | ``` 50 | 51 | ## Installation 52 | 53 | ``` 54 | npm install react-bootstrap-datetimerangepicker bootstrap-daterangepicker --save 55 | ``` 56 | 57 | ## Usage 58 | 59 | Date Range Picker relies on [Bootstrap](http://getbootstrap.com/), [jQuery](http://www.jquery.com/) and [Moment.js](http://momentjs.com/). Include the required stylesheet in your page: 60 | 61 | ```js 62 | import 'bootstrap/dist/css/bootstrap.css'; 63 | import 'bootstrap-daterangepicker/daterangepicker.css'; 64 | ``` 65 | 66 | ```js 67 | import DatetimeRangePicker from 'react-bootstrap-datetimerangepicker'; 68 | 69 | 74 | 75 | 76 | 77 | 87 | 92 | 93 | ``` 94 | 95 | More examples: [Online demo](http://luqin.github.io/react-bootstrap-datetimerangepicker), [Source](https://github.com/luqin/react-bootstrap-datetimerangepicker/tree/master/examples) 96 | 97 | ## Documentation 98 | 99 | For in depth documentation, see the original 100 | [bootstrap-daterangepicker](https://github.com/dangrossman/bootstrap-daterangepicker) project page. 101 | 102 | ### Options 103 | 104 | - **startDate**: (Date object, moment object or string) The start of the initially selected date range 105 | - **endDate**: (Date object, moment object or string) The end of the initially selected date range 106 | - **minDate**: (Date object, moment object or string) The earliest date a user may select 107 | - **maxDate**: (Date object, moment object or string) The latest date a user may select 108 | - **dateLimit**: (object) The maximum span between the selected start and end dates. Can have any property you can add to a moment object (i.e. days, months) 109 | - **showDropdowns**: (boolean) Show year and month select boxes above calendars to jump to a specific month and year 110 | - **showWeekNumbers**: (boolean) Show week numbers at the start of each week on the calendars 111 | - **timePicker**: (boolean) Allow selection of dates with times, not just dates 112 | - **timePickerIncrement**: (number) Increment of the minutes selection list for times (i.e. 30 to allow only selection of times ending in 0 or 30) 113 | - **timePicker24Hour**: (boolean) Use 24-hour instead of 12-hour times, removing the AM/PM selection 114 | - **timePickerSeconds**: (boolean) Show seconds in the timePicker 115 | - **ranges**: (object) Set predefined date ranges the user can select from. Each key is the label for the range, and its value an array with two dates representing the bounds of the range 116 | - **opens**: (string: 'left'/'right'/'center') Whether the picker appears aligned to the left, to the right, or centered under the HTML element it's attached to 117 | - **drops**: (string: 'down' or 'up') Whether the picker appears below (default) or above the HTML element it's attached to 118 | - **buttonClasses**: (array) CSS class names that will be added to all buttons in the picker 119 | - **applyClass**: (string) CSS class string that will be added to the apply button 120 | - **cancelClass**: (string) CSS class string that will be added to the cancel button 121 | - **locale**: (object) Allows you to provide localized strings for buttons and labels, customize the date display format, and change the first day of week for the calendars 122 | - **singleDatePicker**: (boolean) Show only a single calendar to choose one date, instead of a range picker with two calendars; the start and end dates provided to your callback will be the same single date chosen 123 | - **autoApply**: (boolean) Hide the apply and cancel buttons, and automatically apply a new date range as soon as two dates or a predefined range is selected 124 | - **linkedCalendars**: (boolean) When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year. 125 | - **parentEl**: (string) jQuery selector of the parent element that the date range picker will be added to, if not provided this will be 'body' 126 | - **isInvalidDate**: (function) A function that is passed each date in the two calendars before they are displayed, and may return true or false to indicate whether that date should be available for selection or not. 127 | - **autoUpdateInput**: (boolean) Indicates whether the date range picker should automatically update the value of an element it's attached to at initialization and when the selected dates change. 128 | 129 | ### Events 130 | 131 | - **onShow**: Triggered when the picker is shown 132 | - **onHide**: Triggered when the picker is hidden 133 | - **onHideCalendar**: Triggered when the calendar(s) are shown 134 | - **onApply**: Triggered when the calendar(s) are hidden 135 | - **onCancel**: Triggered when the apply button is clicked, or when a predefined range is clicked 136 | - **onEvent**: Triggered when the cancel button is clicked 137 | 138 | All of the events above should take a handler that is passed 2 arguments: **event** and **picker** 139 | 140 | #### Example event handler: 141 | 142 | ```js 143 | var SomeReactComponent = React.createClass({ 144 | handleEvent: function (event, picker) { 145 | console.log(picker.startDate); 146 | }, 147 | render: function () { 148 | return ( 149 | 150 | ); 151 | } 152 | }); 153 | ``` 154 | 155 | ## Browser support 156 | 157 | * Google Chrome 158 | * Firefox (2+) 159 | * IE (9+) 160 | * Opera (11.6+) 161 | * Safari (6+) 162 | 163 | ## Local Setup 164 | 165 | * Install the dependencies with `npm install` 166 | * Run the docs site in development mode with `npm start`. This will watch for file changes as you work. And auto refresh the page to see the updates. 167 | 168 | [npm-badge]: http://badge.fury.io/js/react-bootstrap-datetimerangepicker.svg 169 | [npm]: https://www.npmjs.com/package/react-bootstrap-datetimerangepicker 170 | 171 | [deps-badge]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker.svg 172 | [deps]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker 173 | 174 | [dev-deps-badge]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker/dev-status.svg 175 | [dev-deps]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker#info=devDependencies 176 | 177 | [peer-deps-badge]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker/peer-status.svg 178 | [peer-deps]: https://david-dm.org/luqin/react-bootstrap-datetimerangepicker#info=peerDependencies 179 | 180 | [travis-ci-image]: https://travis-ci.org/luqin/react-bootstrap-datetimerangepicker.svg 181 | [travis-ci-url]: https://travis-ci.org/luqin/react-bootstrap-datetimerangepicker 182 | --------------------------------------------------------------------------------