UNPKG

wix-style-react

Version:
445 lines (371 loc) • 15.6 kB
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 _class, _temp; 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; } import styles from './Calendar.scss'; import React from 'react'; import PropTypes from 'prop-types'; import DayPicker from 'react-day-picker/DayPicker'; import classNames from 'classnames'; import addMonths from 'date-fns/add_months'; import subMonths from 'date-fns/sub_months'; import startOfMonth from 'date-fns/start_of_month'; import parse from 'date-fns/parse'; import isSameDay from 'date-fns/is_same_day'; import { CalendarView } from './utils'; import WixComponent from '../BaseComponents/WixComponent'; import localeUtilsFactory from '../LocaleUtils'; import DatePickerHead from './DatePickerHead'; var Calendar = (_temp = _class = function (_WixComponent) { _inherits(Calendar, _WixComponent); function Calendar(props) { _classCallCheck(this, Calendar); var _this = _possibleConstructorReturn(this, (Calendar.__proto__ || Object.getPrototypeOf(Calendar)).call(this, props)); _this._setMonth = function (month) { _this.setState({ month: month }); }; _this._handleDayClick = function (value) { var modifiers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var event = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; _this._preventActionEventDefault(event); var propsValue = _this.props.value || {}; var _this$props = _this.props, onChange = _this$props.onChange, shouldCloseOnSelect = _this$props.shouldCloseOnSelect; if (_this.props.selectionMode === 'range') { if (!propsValue.from && !propsValue.to || propsValue.from && propsValue.to) { onChange({ from: value }, modifiers); } else { var anchor = propsValue.from || propsValue.to; var newVal = anchor < value ? { from: anchor, to: value } : { from: value, to: anchor }; onChange(newVal, modifiers); shouldCloseOnSelect && _this.props.onClose(event); } } else { onChange(value, modifiers); shouldCloseOnSelect && _this.props.onClose(event); } }; _this._preventActionEventDefault = function () { var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; // We should not prevent "TAB"/"ESC" key if (event && (!event.keyCode || !_this.keyHandlers[event.keyCode])) { event.preventDefault(); } }; _this._createCaptionElement = function (month) { var _this$props2 = _this.props, locale = _this$props2.locale, showMonthDropdown = _this$props2.showMonthDropdown, showYearDropdown = _this$props2.showYearDropdown; var localeUtils = localeUtilsFactory(locale); return React.createElement(DatePickerHead, { date: month, showYearDropdown: showYearDropdown, showMonthDropdown: showMonthDropdown, localeUtils: localeUtils, onChange: _this._setMonth, onLeftArrowClick: function onLeftArrowClick() { return _this._setMonth(startOfMonth(addMonths(month, -1))); }, onRightArrowClick: function onRightArrowClick() { return _this._setMonth(startOfMonth(addMonths(month, 1))); } }); }; _this._createDayPickerProps = function () { var _this$props3 = _this.props, locale = _this$props3.locale, filterDate = _this$props3.filterDate, excludePastDates = _this$props3.excludePastDates, numOfMonths = _this$props3.numOfMonths; var value = Calendar.parseValue(_this.props.value); var month = _this.state.month; var localeUtils = localeUtilsFactory(locale); var _ref = value || {}, from = _ref.from, to = _ref.to; var singleDay = !from && !to && value; var firstOfMonth = [new Date(month.getFullYear(), month.getMonth(), 1), new Date(month.getFullYear(), month.getMonth() + 1, 1)]; var lastOfMonth = [new Date(month.getFullYear(), month.getMonth() + 1, 0), new Date(month.getFullYear(), month.getMonth() + 2, 0)]; var captionElement = _this._createCaptionElement(month); var selectedDays = _this._getSelectedDays(value); return { disabledDays: excludePastDates ? { before: new Date() } : function (date) { return !filterDate(date); }, initialMonth: month, initialYear: month, selectedDays: selectedDays, month: month, year: month, firstDayOfWeek: 1, locale: typeof locale === 'string' ? locale : '', fixedWeeks: true, onKeyDown: _this._handleKeyDown, onDayClick: _this._handleDayClick, localeUtils: localeUtils, navbarElement: function navbarElement() { return null; }, captionElement: captionElement, onCaptionClick: _this._preventActionEventDefault, onDayKeyDown: _this._handleDayKeyDown, numberOfMonths: numOfMonths, className: numOfMonths > 1 ? styles.TwoMonths : '', modifiers: { start: from, end: to, firstOfMonth: firstOfMonth, lastOfMonth: lastOfMonth, singleDay: singleDay }, renderDay: Calendar.renderDay }; }; _this._handleKeyDown = function (event) { var keyHandler = _this.keyHandlers[event.keyCode]; keyHandler && keyHandler(event); }; _this.keyHandlers = { // escape 27: _this.props.onClose, // tab 9: _this.props.onClose }; _this._focusSelectedDay = function (dayPickerRef) { if (dayPickerRef) { _this.dayPickerRef = dayPickerRef; var selectedDay = _this.dayPickerRef.dayPicker.querySelector('.DayPicker-Day--selected'); if (selectedDay) { selectedDay.classList.add('DayPicker-Day--unfocused'); selectedDay.focus(); } } }; _this._handleDayKeyDown = function (_value) { var _modifiers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var event = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; _this._preventActionEventDefault(event); var unfocusedDay = _this.dayPickerRef.dayPicker.querySelector('.DayPicker-Day--unfocused'); if (unfocusedDay) { unfocusedDay.classList.remove('DayPicker-Day--unfocused'); } }; var initialMonth = Calendar.getUpdatedMonth(props.value, props.numOfMonths); _this.state = { month: initialMonth || new Date() }; return _this; } _createClass(Calendar, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.value !== this.props.value) { var month = Calendar.getUpdatedMonth(nextProps.value, nextProps.numOfMonths, this.state.month); if (month) { this.setState({ month: month }); } } } }, { key: '_getSelectedDays', value: function _getSelectedDays(value) { var _ref2 = value || {}, from = _ref2.from, to = _ref2.to; if (from && to) { return { from: from, to: to }; } else if (from) { return { after: prevDay(from) }; } else if (to) { return { before: nextDay(to) }; } else { // Single day OR empty value return value; } } }, { key: 'render', value: function render() { return React.createElement( 'div', { className: classNames(styles.calendar, this.props.className), onClick: this._preventActionEventDefault }, React.createElement(DayPicker, _extends({ ref: this._focusSelectedDay }, this._createDayPickerProps())) ); } }], [{ key: 'areValuesEqual', value: function areValuesEqual() { var value1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var value2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!Boolean(value1) && !Boolean(value2)) { return true; } if (Calendar.isRangeValue(value1) && Calendar.isRangeValue(value2)) { return isSameDay(value1.from, value2.from) && isSameDay(value1.to, value2.to); } return isSameDay(value1, value2); } }, { key: 'renderDay', value: function renderDay(day, modifiers) { var relevantModifiers = ['start', 'end', 'selected']; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = relevantModifiers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var modifier = _step.value; if (modifier in modifiers) { return React.createElement( 'div', { className: styles.dayCircle, 'data-date': day.getFullYear() + '-' + day.getMonth() + '-' + day.getDate() }, day.getDate() ); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return React.createElement( 'div', { 'data-date': day.getFullYear() + '-' + day.getMonth() + '-' + day.getDate() }, day.getDate() ); } /** Return a value in which all string-dates are parsed into Date objects */ }, { key: 'isSingleDay', value: function isSingleDay(value) { return value instanceof Date; } }, { key: 'isRangeValue', value: function isRangeValue(value) { return Boolean(value.from || value.to); } }]); return Calendar; }(WixComponent), _class.displayName = 'Calendar', _class.defaultProps = { locale: 'en', className: '', filterDate: function filterDate() { return true; }, shouldCloseOnSelect: true, onClose: function onClose() {} }, _class.optionalParse = function (dateOrString) { return typeof dateOrString === 'string' ? parse(dateOrString) : dateOrString; }, _class.parseValue = function (value) { if (!value) { return new Date(); } if (typeof value === 'string') { return parse(value); } else if (value instanceof Date) { return value; } else { return { from: Calendar.optionalParse(value.from), to: Calendar.optionalParse(value.to) }; } }, _class.getUpdatedMonth = function (nextPropsValue, numOfMonths, currentMonthDate) { var nextValue = Calendar.parseValue(nextPropsValue); if (!currentMonthDate) { return Calendar.isSingleDay(nextValue) ? nextValue : nextValue.from || nextValue.to; } var view = new CalendarView(currentMonthDate, numOfMonths); if (Calendar.isSingleDay(nextValue)) { if (!view.isContained(nextValue)) { return nextValue; } } else { var from = nextValue.from, to = nextValue.to; if (from && view.isAfterView(from)) { // F--- => F--- // VVVVV => VVVVV return from; } else if (to && view.isBeforeView(to)) { if (view.isRangeFits(from, to)) { // F-T => F-T // VVVVV => VVVVV return from; } else { // F-----T => F-----T // VVVVV => VVVVV return subMonths(to, numOfMonths - 1); } } else if (from && view.isBeforeView(from) && to && view.isAfterView(to)) { // F-------T => F-------T // VVVVV => VVVVV return from; // choose the 'from' anchor arbitrarly } } /* * We only changed the month if the day (or range.edges) are outside the view. * This is to avoid changing the month right after a user clicks on the calendar. */ return null; }, _temp); export { Calendar as default }; Calendar.propTypes = { /** Display multiple months, currently allowing only 1 or 2 */ numOfMonths: PropTypes.oneOf([1, 2]), className: PropTypes.string, /** Callback function called with a Date or a Range whenever the user selects a day in the calendar */ onChange: PropTypes.func.isRequired, /** Callback function called whenever user press escape or click outside of the element or a date is selected and `shouldCloseOnSelect` is set. Receives an event as first argument */ onClose: PropTypes.func, /** Past dates are unselectable */ excludePastDates: PropTypes.bool, /** Only the truthy dates are selectable */ filterDate: PropTypes.func, /** The selected date */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date), PropTypes.shape({ from: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), to: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]) })]), /** Whether the user should be able to select a date range, or just a single day */ selectionMode: PropTypes.oneOf(['day', 'range']), /** Display a selectable yearDropdown */ showYearDropdown: PropTypes.bool, /** Display a selectable monthDropdown */ showMonthDropdown: PropTypes.bool, /** should the calendar close on day selection */ shouldCloseOnSelect: PropTypes.bool, /** DatePicker instance locale */ locale: PropTypes.oneOfType([PropTypes.oneOf(['en', 'es', 'pt', 'fr', 'de', 'pl', 'it', 'ru', 'ja', 'ko', 'tr', 'sv', 'no', 'nl', 'da']), PropTypes.shape({ distanceInWords: PropTypes.object, format: PropTypes.object })]) }; function nextDay(date) { var day = new Date(date); day.setDate(day.getDate() + 1); return day; } function prevDay(date) { var day = new Date(date); day.setDate(day.getDate() - 1); return day; }