UNPKG

@wix/design-system

Version:

@wix/design-system

160 lines 7.07 kB
import React from 'react'; import { FocusScope } from '@react-aria/focus'; import addMonths from 'date-fns/addMonths'; import subMonths from 'date-fns/subMonths'; import startOfMonth from 'date-fns/startOfMonth'; import isSameDay from 'date-fns/isSameDay'; import { SupportedWixLocales } from '@wix/design-systems-locale-utils'; import { CalendarView } from './utils'; import localeUtilsFactory from '../common/LocaleUtils/LocaleUtils'; import BaseCalendar from './BaseCalendar/BaseCalendar'; import DatePickerHead from './DatePickerHead'; import { WixStyleReactEnvironmentContext } from '../WixStyleReactEnvironmentProvider/context'; import { st, classes } from './Calendar.st.css.js'; import { dataHooks } from './constants'; class Calendar extends React.PureComponent { constructor(props) { super(props); this._setMonth = month => { this.setState({ month }); const { onMonthChange } = this.props; if (onMonthChange) { onMonthChange(month); } }; this._getLocaleUtilsFactory = (locale, firstDayOfWeek) => { return localeUtilsFactory(locale, firstDayOfWeek); }; this._createCaptionElement = () => { const { showMonthDropdown, showYearDropdown, leftArrowAriaLabel, leftArrowAriaLabelledBy, rightArrowAriaLabel, rightArrowAriaLabelledBy, monthDropdownAriaLabel, monthDropdownAriaLabelledBy, yearDropdownAriaLabel, yearDropdownAriaLabelledBy, size, } = this.props; const { month } = this.state; const locale = this._getLocale(); const localeUtils = this._getLocaleUtilsFactory(locale); return (React.createElement(DatePickerHead, { className: classes.header, date: month, showYearDropdown, showMonthDropdown, locale: typeof locale === 'string' ? locale : '', localeUtils, onChange: this._setMonth, onLeftArrowClick: () => this._setMonth(startOfMonth(addMonths(month, -1))), onRightArrowClick: () => this._setMonth(startOfMonth(addMonths(month, 1))), leftArrowAriaLabel, leftArrowAriaLabelledBy, rightArrowAriaLabel, rightArrowAriaLabelledBy, monthDropdownAriaLabel, monthDropdownAriaLabelledBy, yearDropdownAriaLabel, yearDropdownAriaLabelledBy, size })); }; const initialMonth = Calendar.getUpdatedMonth(props.value, props.numOfMonths); this.state = { month: initialMonth || new Date(), }; } UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.value !== this.props.value) { const month = Calendar.getUpdatedMonth(nextProps.value, nextProps.numOfMonths, this.state.month); if (month) { this.setState({ month }); } } } static areValuesEqual(value1 = {}, value2 = {}) { 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); } static isSingleDay(value) { return value instanceof Date; } static isRangeValue(value) { return Boolean(value.from || value.to); } _getLocale() { return this.props.locale || this.context.locale || 'en'; } render() { const { dataHook, className, autoFocus, numOfMonths, firstDayOfWeek, onChange, onClose, excludePastDates, filterDate, value, selectionMode, shouldCloseOnSelect, locale, rtl, dateIndication, today, size, onKeyDown, containFocus, } = this.props; const { month } = this.state; return (React.createElement("div", null, React.createElement(FocusScope, { contain: autoFocus && containFocus, restoreFocus: containFocus }, React.createElement(BaseCalendar, { dataHook: dataHook || dataHooks.baseCalendar, size: size, className: st(classes.root, className), autoFocus: autoFocus, numOfMonths: numOfMonths, firstDayOfWeek: firstDayOfWeek, onChange: onChange, onClose: onClose, excludePastDates: excludePastDates, filterDate: filterDate, value: value, selectionMode: selectionMode, shouldCloseOnSelect: shouldCloseOnSelect, locale: locale, rtl: rtl, dateIndication: dateIndication, today: today, onDisplayedViewChange: this._setMonth, displayedMonth: month, captionElement: this._createCaptionElement(), onKeyDown: onKeyDown })))); } } Calendar.displayName = 'Calendar'; Calendar.defaultProps = { className: '', filterDate: () => true, dateIndication: () => null, shouldCloseOnSelect: true, onClose: () => { }, autoFocus: true, excludePastDates: false, selectionMode: 'day', showMonthDropdown: false, showYearDropdown: false, numOfMonths: 1, size: 'medium', }; Calendar.optionalParse = BaseCalendar.optionalParse; /** Return a value in which all string-dates are parsed into Date objects */ Calendar.parseValue = BaseCalendar.parseValue; Calendar.nextDay = BaseCalendar.nextDay; Calendar.prevDay = BaseCalendar.prevDay; Calendar.getUpdatedMonth = (nextPropsValue, numOfMonths, currentMonthDate) => { const nextValue = Calendar.parseValue(nextPropsValue); if (!currentMonthDate) { return Calendar.isSingleDay(nextValue) ? nextValue : nextValue.from || nextValue.to; } const view = new CalendarView(currentMonthDate, numOfMonths); if (Calendar.isSingleDay(nextValue)) { if (!view.isContained(nextValue)) { return nextValue; } } else { const { from, to } = nextValue; 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 arbitrarily } } /* * 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; }; export default Calendar; Calendar.contextType = WixStyleReactEnvironmentContext; //# sourceMappingURL=Calendar.js.map