@wix/design-system
Version:
@wix/design-system
160 lines • 7.07 kB
JavaScript
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