react-date-picker
Version:
A carefully crafted date picker for React
707 lines (544 loc) • 20.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.renderNavBar = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactClass = require('react-class');
var _reactClass2 = _interopRequireDefault(_reactClass);
var _reactFlex = require('react-flex');
var _reactInlineBlock = require('react-inline-block');
var _reactInlineBlock2 = _interopRequireDefault(_reactInlineBlock);
var _objectAssign = require('object-assign');
var _objectAssign2 = _interopRequireDefault(_objectAssign);
var _clampRange = require('./clampRange');
var _clampRange2 = _interopRequireDefault(_clampRange);
var _NavBar = require('./NavBar');
var _NavBar2 = _interopRequireDefault(_NavBar);
var _toMoment = require('./toMoment');
var _toMoment2 = _interopRequireDefault(_toMoment);
var _join = require('./join');
var _join2 = _interopRequireDefault(_join);
var _isInRange2 = require('./utils/isInRange');
var _isInRange3 = _interopRequireDefault(_isInRange2);
var _BasicMonthView = require('./BasicMonthView');
var _MonthView = require('./MonthView');
var _MonthView2 = _interopRequireDefault(_MonthView);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var times = function times(count) {
return [].concat(_toConsumableArray(new Array(count))).map(function (v, i) {
return i;
});
};
var prepareDate = function prepareDate(props, state) {
if (props.range) {
return null;
}
return props.date === undefined ? state.date : props.date;
};
var prepareViewDate = function prepareViewDate(props, state) {
return props.viewDate === undefined ? state.viewDate : state.propViewDate || props.viewDate;
};
var prepareRange = function prepareRange(props, state) {
return props.range && props.range.length ? props.range : state.range;
};
var prepareActiveDate = function prepareActiveDate(props, state) {
var fallbackDate = prepareDate(props, state) || (prepareRange(props, state) || [])[0];
var activeDate = props.activeDate === undefined ?
// only fallback to date if activeDate not specified
state.activeDate || fallbackDate : props.activeDate;
if (activeDate && props.inViewStart && props.inViewEnd && props.constrainActiveInView) {
var activeMoment = this.toMoment(activeDate);
if (!(0, _isInRange3.default)(activeMoment, [props.inViewStart, props.inViewEnd])) {
var date = fallbackDate;
var dateMoment = this.toMoment(date);
if (date && (0, _isInRange3.default)(dateMoment, [props.inViewStart, props.inViewEnd])) {
return date;
}
return null;
}
}
return activeDate;
};
var prepareViews = function prepareViews(props) {
var daysInView = [];
var viewMoments = [];
var viewMoment = props.viewMoment;
var index = 0;
var size = props.size;
while (index < size) {
var mom = this.toMoment(viewMoment).startOf('day').add(index, 'month');
var days = (0, _BasicMonthView.getDaysInMonthView)(mom, props);
viewMoments.push(mom);
daysInView.push(days);
index++;
}
props.daysInView = daysInView;
props.viewMoments = viewMoments;
var lastViewDays = daysInView[size - 1];
props.inViewStart = daysInView[0][0];
props.inViewEnd = lastViewDays[lastViewDays.length - 1];
};
var _renderNavBar = function _renderNavBar(config, navBarProps) {
var props = this.props;
var index = config.index;
var viewMoment = config.viewMoment;
navBarProps = (0, _objectAssign2.default)({}, navBarProps, {
secondary: true,
minDate: config.minDate || props.minDate,
maxDate: config.maxDate || props.maxDate,
renderNavNext: config.renderHiddenNav || this.renderHiddenNav,
renderNavPrev: config.renderHiddenNav || this.renderHiddenNav,
viewMoment: viewMoment,
onViewDateChange: config.onViewDateChange || this.onNavViewDateChange,
onUpdate: config.onUpdate || this.updateViewMoment,
enableHistoryView: props.enableHistoryView
});
if (index == 0) {
delete navBarProps.renderNavPrev;
}
if (index == props.perRow - 1) {
delete navBarProps.renderNavNext;
}
return _react2.default.createElement(_NavBar2.default, navBarProps);
};
exports.renderNavBar = _renderNavBar;
var MultiMonthView = function (_Component) {
_inherits(MultiMonthView, _Component);
function MultiMonthView(props) {
_classCallCheck(this, MultiMonthView);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(MultiMonthView).call(this, props));
_this.state = {
hoverRange: null,
range: props.defaultRange,
date: props.defaultDate,
activeDate: props.defaultActiveDate,
viewDate: props.defaultViewDate
};
return _this;
}
_createClass(MultiMonthView, [{
key: 'componentWillMount',
value: function componentWillMount() {
this.updateToMoment(this.props);
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (nextProps.locale != this.props.locale || nextProps.dateFormat != this.props.dateFormat) {
this.updateToMoment(nextProps);
}
// if (nextProps.viewDate && !nextProps.forceViewUpdate){
// //this is here in order not to change view if already in view
// const viewMoment = this.toMoment(nextProps.viewDate)
// if (this.isInRange(viewMoment) && !nextProps.forceViewUpdate){
// console.log(this.format(viewMoment), this.format(this.p.viewStart),
// this.format(this.p.viewEnd))
// this.setState({
// propViewDate: this.p.viewMoment
// })
// } else {
// debugger
// this.setState({
// propViewDate: null
// })
// }
// }
}
}, {
key: 'updateToMoment',
value: function updateToMoment(props) {
this.toMoment = function (value, dateFormat) {
return (0, _toMoment2.default)(value, {
locale: props.locale,
dateFormat: dateFormat || props.dateFormat
});
};
}
}, {
key: 'prepareProps',
value: function prepareProps(thisProps, state) {
var _this2 = this;
var props = (0, _objectAssign2.default)({}, thisProps);
state = state || this.state;
props.viewMoment = this.toMoment(prepareViewDate(props, state));
// viewStart is the first day of the first month displayed
// viewEnd is the last day of the last month displayed
props.viewStart = this.toMoment(props.viewMoment).startOf('month');
props.viewEnd = this.toMoment(props.viewStart).add(props.size - 1, 'month').endOf('month');
// but we also have inViewStart, which can be a day before viewStart
// which is in displayed as belonging to the prev month
// but is displayed in the current view since it's on the same week
// as viewStart
//
// same for inViewEnd, which is a day after viewEnd - the last day in the same week
prepareViews.call(this, props);
var activeDate = prepareActiveDate.call(this, props, state);
if (activeDate) {
props.activeDate = +this.toMoment(activeDate);
}
props.date = prepareDate(props, state);
if (!props.date) {
var range = prepareRange(props, state);
if (range) {
props.range = range.map(function (d) {
return _this2.toMoment(d).startOf('day');
});
props.rangeStart = state.rangeStart || (props.range.length == 1 ? props.range[0] : null);
}
}
return props;
}
}, {
key: 'render',
value: function render() {
this.views = [];
var props = this.p = this.prepareProps(this.props, this.state);
var size = props.size;
var rowCount = Math.ceil(size / props.perRow);
var children = times(rowCount).map(this.renderRow).filter(function (x) {
return !!x;
});
var className = (0, _join2.default)(props.className, 'react-date-picker__multi-month-view', props.theme && 'react-date-picker__multi-month-view--theme-' + props.theme);
var footer = (0, _MonthView.renderFooter)(props, this);
if (footer) {
children.push(footer);
}
return _react2.default.createElement(_reactFlex.Flex, _extends({
column: true,
inline: true,
alignItems: 'stretch',
wrap: false
}, props, {
className: className,
children: children
}));
}
}, {
key: 'renderRow',
value: function renderRow(rowIndex) {
var _this3 = this;
var props = this.p;
var children = times(props.perRow).map(function (i) {
var index = rowIndex * props.perRow + i;
if (index >= props.size) {
return null;
}
return _this3.renderView(index, props.size);
});
return _react2.default.createElement(_reactFlex.Flex, { inline: true, row: true, wrap: false, children: children });
}
}, {
key: 'renderView',
value: function renderView(index, size) {
var _this4 = this;
var props = this.p;
var viewMoment = props.viewMoments[index];
var range = void 0;
if (props.range) {
range = props.rangeStart && props.range.length == 0 ? [props.rangeStart] : props.range;
}
return _react2.default.createElement(_MonthView2.default, _extends({
ref: function ref(view) {
_this4.views[index] = view;
},
constrainViewDate: false
}, this.props, {
className: null,
index: index,
footer: false,
constrainActiveInView: false,
navigate: this.onMonthNavigate.bind(this, index),
hoverRange: this.state.hoverRange,
onHoverRangeChange: this.setHoverRange,
activeDate: props.activeDate,
onActiveDateChange: this.onActiveDateChange,
onViewDateChange: this.onAdjustViewDateChange,
date: props.date,
defaultDate: null,
onChange: this.onChange,
range: range,
defaultRange: null,
onRangeChange: this.onRangeChange,
viewMoment: viewMoment,
insideMultiView: true,
daysInView: props.daysInView[index],
showDaysBeforeMonth: index == 0,
showDaysAfterMonth: index == size - 1,
select: this.select,
renderNavBar: this.props.navigation && (this.props.renderNavBar || this.renderNavBar).bind(this, { index: index, viewMoment: viewMoment })
}));
}
}, {
key: 'onFooterTodayClick',
value: function onFooterTodayClick() {
this.views[0].onFooterTodayClick();
}
}, {
key: 'onFooterClearClick',
value: function onFooterClearClick() {
this.views[0].onFooterClearClick();
}
}, {
key: 'onFooterOkClick',
value: function onFooterOkClick() {
this.views[0].onFooterOkClick();
}
}, {
key: 'onFooterCancelClick',
value: function onFooterCancelClick() {
this.views[0].onFooterCancelClick();
}
}, {
key: 'isFocused',
value: function isFocused() {
var firstView = this.views[0];
if (firstView) {
return firstView.isFocused();
}
return false;
}
}, {
key: 'focus',
value: function focus() {
var firstView = this.views[0];
if (firstView) {
firstView.focus();
}
}
}, {
key: 'setHoverRange',
value: function setHoverRange(hoverRange) {
this.setState({
hoverRange: hoverRange
});
}
}, {
key: 'select',
value: function select(_ref) {
var dateMoment = _ref.dateMoment;
var timestamp = _ref.timestamp;
// if (!dateMoment) {
// return
// }
var props = this.p;
var visibleRange = [props.inViewStart, props.inViewEnd];
// TODO check why this was needed
// if (!isInRange(dateMoment, { range: visibleRange, inclusive: true })) {
// return
// }
this.onAdjustViewDateChange({ dateMoment: dateMoment, timestamp: timestamp });
this.onActiveDateChange({ dateMoment: dateMoment, timestamp: timestamp });
var range = props.range;
if (range) {
this.selectRange({ dateMoment: dateMoment, timestamp: timestamp });
} else {
this.onChange({ dateMoment: dateMoment, timestamp: timestamp }, event);
}
}
}, {
key: 'selectRange',
value: function selectRange(_ref2) {
var dateMoment = _ref2.dateMoment;
var timestamp = _ref2.timestamp;
return _MonthView2.default.prototype.selectRange.call(this, { dateMoment: dateMoment, timestamp: timestamp });
}
}, {
key: 'onRangeChange',
value: function onRangeChange(range) {
return _MonthView2.default.prototype.onRangeChange.call(this, range);
}
}, {
key: 'onViewKeyDown',
value: function onViewKeyDown() {
var view = this.views[0];
if (view) {
view.onViewKeyDown.apply(view, arguments);
}
}
}, {
key: 'renderNavBar',
value: function renderNavBar(config, navBarProps) {
return _renderNavBar.call(this, config, navBarProps);
}
}, {
key: 'onMonthNavigate',
value: function onMonthNavigate(index, dir, event, getNavigationDate) {
var props = this.p;
event.preventDefault();
if (!props.activeDate) {
return;
}
var key = event.key;
var homeEndDate = key == 'Home' ? props.viewStart : props.viewEnd;
var mom = key == 'Home' || key == 'End' ? homeEndDate : props.activeDate;
var nextMoment = getNavigationDate(dir, this.toMoment(mom));
var viewMoment = this.toMoment(nextMoment);
this.onActiveDateChange({
dateMoment: nextMoment,
timestamp: +nextMoment
});
if (this.isInRange(viewMoment)) {
return;
}
if (viewMoment.isAfter(props.viewEnd)) {
viewMoment.add(-props.size + 1, 'month');
}
this.onViewDateChange({
dateMoment: viewMoment,
timestamp: +viewMoment
});
}
}, {
key: 'onAdjustViewDateChange',
value: function onAdjustViewDateChange(_ref3) {
var dateMoment = _ref3.dateMoment;
var timestamp = _ref3.timestamp;
var props = this.p;
var update = dateMoment == null;
if (dateMoment && dateMoment.isAfter(props.viewEnd)) {
dateMoment = this.toMoment(dateMoment).add(-props.size + 1, 'month');
timestamp = +dateMoment;
update = true;
} else if (dateMoment && dateMoment.isBefore(props.viewStart)) {
update = true;
}
if (update) {
this.onViewDateChange({ dateMoment: dateMoment, timestamp: timestamp });
}
}
}, {
key: 'updateViewMoment',
value: function updateViewMoment(dateMoment, dir) {
var sign = dir < 0 ? -1 : 1;
var abs = Math.abs(dir);
var newMoment = this.toMoment(this.p.viewStart);
newMoment.add(sign, abs == 1 ? 'month' : 'year');
return newMoment;
}
}, {
key: 'renderHiddenNav',
value: function renderHiddenNav(props) {
return _react2.default.createElement(_reactInlineBlock2.default, _extends({}, props, { style: { visibility: 'hidden' } }));
}
}, {
key: 'isInRange',
value: function isInRange(moment) {
return (0, _isInRange3.default)(moment, [this.p.viewStart, this.p.viewEnd]);
}
}, {
key: 'isInView',
value: function isInView(moment) {
return this.isInRange(moment);
}
}, {
key: 'onNavViewDateChange',
value: function onNavViewDateChange(dateString, _ref4) {
var dateMoment = _ref4.dateMoment;
var timestamp = _ref4.timestamp;
this.onViewDateChange({ dateMoment: dateMoment, timestamp: timestamp });
}
}, {
key: 'onViewDateChange',
value: function onViewDateChange(_ref5) {
var dateMoment = _ref5.dateMoment;
var timestamp = _ref5.timestamp;
if (this.props.viewDate === undefined) {
this.setState({
viewDate: timestamp
});
}
if (this.props.onViewDateChange) {
var dateString = this.format(dateMoment);
this.props.onViewDateChange(dateString, { dateMoment: dateMoment, dateString: dateString, timestamp: timestamp });
}
}
}, {
key: 'onActiveDateChange',
value: function onActiveDateChange(_ref6) {
var dateMoment = _ref6.dateMoment;
var timestamp = _ref6.timestamp;
var valid = this.views.reduce(function (isValid, view) {
return isValid && view.isValidActiveDate(timestamp);
}, true);
if (!valid) {
return;
}
var props = this.p;
var range = props.range;
if (range && props.rangeStart) {
this.setState({
rangeStart: props.rangeStart,
range: (0, _clampRange2.default)([props.rangeStart, dateMoment])
});
}
if (this.props.activeDate === undefined) {
this.setState({
activeDate: timestamp
});
}
if (this.props.onActiveDateChange) {
var dateString = this.format(dateMoment);
this.props.onActiveDateChange(dateString, { dateMoment: dateMoment, dateString: dateString, timestamp: timestamp });
}
}
}, {
key: 'gotoViewDate',
value: function gotoViewDate(_ref7) {
var dateMoment = _ref7.dateMoment;
var timestamp = _ref7.timestamp;
if (!timestamp) {
timestamp = +dateMoment;
}
this.onViewDateChange({ dateMoment: dateMoment, timestamp: timestamp });
this.onActiveDateChange({ dateMoment: dateMoment, timestamp: timestamp });
}
}, {
key: 'format',
value: function format(mom) {
return mom == null ? '' : mom.format(this.props.dateFormat);
}
}, {
key: 'onChange',
value: function onChange(_ref8, event) {
var dateMoment = _ref8.dateMoment;
var timestamp = _ref8.timestamp;
if (this.props.date === undefined) {
this.setState({
date: timestamp
});
}
if (this.props.onChange) {
var dateString = this.format(dateMoment);
this.props.onChange(dateString, { dateMoment: dateMoment, dateString: dateString, timestamp: timestamp }, event);
}
}
}, {
key: 'getViewSize',
value: function getViewSize() {
return this.props.size;
}
}]);
return MultiMonthView;
}(_reactClass2.default);
exports.default = MultiMonthView;
MultiMonthView.defaultProps = {
perRow: 2,
size: 2,
enableHistoryView: true,
footerClearDate: null,
isDatePicker: true,
forceViewUpdate: false,
navigation: true,
theme: 'default',
constrainActiveInView: true,
dateFormat: 'YYYY-MM-DD'
};
MultiMonthView.propTypes = {};