UNPKG

@fluentui/react-northstar

Version:
403 lines (401 loc) 18.1 kB
import _times from "lodash/times"; import _map from "lodash/map"; import _invoke from "lodash/invoke"; import _find from "lodash/find"; import { datepickerCalendarBehavior } from '@fluentui/accessibility'; import { DateRangeType, DayOfWeek, DAYS_IN_WEEK, FirstWeekOfYear, getDayGrid, DEFAULT_CALENDAR_STRINGS, compareDates, compareDatePart, getMonthStart, getMonthEnd, getStartDateOfWeek, getEndDateOfWeek } from '../../utils/date-time-utilities'; import { getElementType, useAccessibility, useFluentContext, useStyles, useTelemetry, useUnhandledProps } from '@fluentui/react-bindings'; import * as customPropTypes from '@fluentui/react-proptypes'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import { commonPropTypes, createShorthand } from '../../utils'; import { DatepickerCalendarGrid } from './DatepickerCalendarGrid'; import { DatepickerCalendarGridRow } from './DatepickerCalendarGridRow'; import { DatepickerCalendarHeader } from './DatepickerCalendarHeader'; import { DatepickerCalendarCell } from './DatepickerCalendarCell'; import { DatepickerCalendarCellButton } from './DatepickerCalendarCellButton'; import { DatepickerCalendarHeaderCell } from './DatepickerCalendarHeaderCell'; import { navigateToNewDate, contstraintNavigatedDate } from './navigateToNewDate'; export var datepickerCalendarClassName = 'ui-datepicker__calendar'; var normalizeDateInGrid = function normalizeDateInGrid(date) { var result = new Date(date.getTime()); result.setDate(1); return result; }; /** * A DatepickerCalendar is used to display dates in sematically grouped way. */ export var DatepickerCalendar = /*#__PURE__*/function () { var DatepickerCalendar = /*#__PURE__*/React.forwardRef(function (props, ref) { var context = useFluentContext(); var _useTelemetry = useTelemetry(DatepickerCalendar.displayName, context.telemetry), setStart = _useTelemetry.setStart, setEnd = _useTelemetry.setEnd; setStart(); var className = props.className, design = props.design, styles = props.styles, variables = props.variables, calendarHeaderCell = props.calendarHeaderCell, calendarCell = props.calendarCell, calendarCellButton = props.calendarCellButton, calendarGrid = props.calendarGrid, calendarGridRow = props.calendarGridRow, dateRangeType = props.dateRangeType, header = props.header, selectedDate = props.selectedDate, navigatedDate = props.navigatedDate, firstDayOfWeek = props.firstDayOfWeek, today = props.today, formatMonthDayYear = props.formatMonthDayYear, formatMonthYear = props.formatMonthYear, shortDays = props.shortDays, days = props.days, minDate = props.minDate, maxDate = props.maxDate, restrictedDates = props.restrictedDates; var restrictedDatesOptions = { minDate: minDate, maxDate: maxDate, restrictedDates: restrictedDates }; var ElementType = getElementType(props); var unhandledProps = useUnhandledProps(DatepickerCalendar.handledProps, props); var updateNavigatedDate = function updateNavigatedDate(date) { if (!!date) { if (!shouldFocusInDayGrid) { setShouldFocusInDayGrid(true); } setGridNavigatedDate(date); } }; var getA11yProps = useAccessibility(props.accessibility, { debugName: DatepickerCalendar.displayName, actionHandlers: { addWeek: function addWeek(e) { e.preventDefault(); var newNavigatedDate = navigateToNewDate(gridNavigatedDate, 'Week', 1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, subtractWeek: function subtractWeek(e) { e.preventDefault(); var newNavigatedDate = navigateToNewDate(gridNavigatedDate, 'Week', -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, addDay: function addDay(e) { e.preventDefault(); var newNavigatedDate = navigateToNewDate(gridNavigatedDate, 'Day', 1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, subtractDay: function subtractDay(e) { e.preventDefault(); var newNavigatedDate = navigateToNewDate(gridNavigatedDate, 'Day', -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, moveToStartOfWeek: function moveToStartOfWeek(e) { e.preventDefault(); var targetDate = getStartDateOfWeek(gridNavigatedDate, firstDayOfWeek); var newNavigatedDate = contstraintNavigatedDate(gridNavigatedDate, targetDate, -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, moveToEndOfWeek: function moveToEndOfWeek(e) { e.preventDefault(); var targetDate = getEndDateOfWeek(gridNavigatedDate, firstDayOfWeek); var newNavigatedDate = contstraintNavigatedDate(gridNavigatedDate, targetDate, -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, moveToStartOfColumn: function moveToStartOfColumn(e) { var _find2; e.preventDefault(); var targetDayOfWeek = gridNavigatedDate.getDay(); var targetDate = (_find2 = _find(visibleGrid[0], function (day) { return day.originalDate.getDay() === targetDayOfWeek; })) == null ? void 0 : _find2.originalDate; var newNavigatedDate = contstraintNavigatedDate(gridNavigatedDate, targetDate, -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); }, moveToEndOfColumn: function moveToEndOfColumn(e) { var _find3; e.preventDefault(); var targetDayOfWeek = gridNavigatedDate.getDay(); var targetDate = (_find3 = _find(visibleGrid[visibleGrid.length - 1], function (day) { return day.originalDate.getDay() === targetDayOfWeek; })) == null ? void 0 : _find3.originalDate; var newNavigatedDate = contstraintNavigatedDate(gridNavigatedDate, targetDate, -1, restrictedDatesOptions, true); updateNavigatedDate(newNavigatedDate); } }, rtl: context.rtl }); var _React$useState = React.useState(function () { return new Date((navigatedDate || today || new Date()).getTime()); }), gridNavigatedDate = _React$useState[0], setGridNavigatedDate = _React$useState[1]; var _React$useState2 = React.useState(function () { return normalizeDateInGrid(gridNavigatedDate); }), normalizedGridDate = _React$useState2[0], setNormalizedGridDate = _React$useState2[1]; var _React$useState3 = React.useState(true), shouldFocusInDayGrid = _React$useState3[0], setShouldFocusInDayGrid = _React$useState3[1]; var _useStyles = useStyles(DatepickerCalendar.displayName, { className: datepickerCalendarClassName, mapPropsToInlineStyles: function mapPropsToInlineStyles() { return { className: className, design: design, styles: styles, variables: variables }; }, rtl: context.rtl }), classes = _useStyles.classes; var visibleGrid = React.useMemo(function () { var dayGridOptions = { selectedDate: selectedDate, navigatedDate: normalizedGridDate, weeksToShow: props.weeksToShow, firstDayOfWeek: props.firstDayOfWeek, firstWeekOfYear: props.firstWeekOfYear, dateRangeType: props.dateRangeType, daysToSelectInDayView: props.daysToSelectInDayView, today: props.today, showWeekNumbers: props.showWeekNumbers, workWeekDays: props.workWeekDays, minDate: props.minDate, maxDate: props.maxDate, restrictedDates: props.restrictedDates }; var grid = getDayGrid(dayGridOptions); return grid.slice(1, grid.length - 1); // slicing off first and last weeks, cause we don't use them for transitions }, [selectedDate, normalizedGridDate, props]); React.useEffect(function () { var newNormalizedDate = normalizeDateInGrid(gridNavigatedDate); if (compareDatePart(newNormalizedDate, normalizedGridDate)) { // Do not change the grid immediately the month changes but only once the date stops being visible. var gridContainsNavigatedDate = visibleGrid.find(function (week) { return week.find(function (day) { return compareDatePart(day.originalDate, gridNavigatedDate) === 0; }); }); if (!gridContainsNavigatedDate) { setNormalizedGridDate(newNormalizedDate); } } }, [gridNavigatedDate, visibleGrid, normalizedGridDate]); var dateFormatting = { months: props.months, shortMonths: props.shortMonths, days: props.days, shortDays: props.shortDays }; var focusDateRef = React.useRef(null); var changeMonth = function changeMonth(nextMonth) { var newNavigatedDate = navigateToNewDate(normalizedGridDate, 'Month', nextMonth ? 1 : -1, restrictedDatesOptions, true); if (!!newNavigatedDate) { setGridNavigatedDate(newNavigatedDate); setShouldFocusInDayGrid(false); setNormalizedGridDate(normalizeDateInGrid(newNavigatedDate)); } }; var prevMonthOutOfBounds = minDate ? compareDatePart(minDate, getMonthStart(normalizedGridDate)) >= 0 : false; var nextMonthOutOfBounds = maxDate ? compareDatePart(getMonthEnd(normalizedGridDate), maxDate) >= 0 : false; React.useEffect(function () { if (shouldFocusInDayGrid) { var _focusDateRef$current; (_focusDateRef$current = focusDateRef.current) == null ? void 0 : _focusDateRef$current.focus(); } }, [gridNavigatedDate, normalizedGridDate, shouldFocusInDayGrid]); var renderCell = function renderCell(day, content) { return createShorthand(DatepickerCalendarCell, calendarCell, { defaultProps: function defaultProps() { var _props$today; return getA11yProps('calendarCell', { content: content, key: day.key, selected: day.isSelected, disabled: !day.isInBounds, quiet: !day.isInMonth, today: compareDates(day.originalDate, (_props$today = props.today) != null ? _props$today : new Date()) }); } }); }; var renderCellButton = function renderCellButton(day, dateRange) { return createShorthand(DatepickerCalendarCellButton, calendarCellButton, { defaultProps: function defaultProps() { var _props$today2; return getA11yProps('calendarCell', { content: day.date, 'aria-label': formatMonthDayYear(day.originalDate, dateFormatting), selected: day.isSelected, disabled: !day.isInBounds, quiet: !day.isInMonth, today: compareDates(day.originalDate, (_props$today2 = props.today) != null ? _props$today2 : new Date()) }); }, overrideProps: function overrideProps(predefinedProps) { return { onFocus: function onFocus(e) { setGridNavigatedDate(day.originalDate); _invoke(predefinedProps, 'onFocus', e, predefinedProps); }, onClick: function onClick(e) { _invoke(props, 'onDateChange', e, Object.assign({}, props, { value: day, selectedDateRange: dateRangeType !== DateRangeType.Day ? dateRange : [day] })); _invoke(predefinedProps, 'onClick', e, predefinedProps); }, ref: compareDates(gridNavigatedDate, day.originalDate) ? focusDateRef : null }; } }); }; var renderWeekRow = function renderWeekRow(week) { return _map(week, function (day) { return renderCell(day, renderCellButton(day, week)); }); }; var element = /*#__PURE__*/React.createElement(ElementType, getA11yProps('root', Object.assign({ className: classes.root, ref: ref }, unhandledProps)), createShorthand(DatepickerCalendarHeader, header, { defaultProps: function defaultProps() { return { label: formatMonthYear(normalizedGridDate, dateFormatting), 'aria-label': formatMonthYear(normalizedGridDate, dateFormatting), disabledNextButton: nextMonthOutOfBounds, disabledPreviousButton: prevMonthOutOfBounds, prevMonthAriaLabel: props.prevMonthAriaLabel, nextMonthAriaLabel: props.nextMonthAriaLabel }; }, overrideProps: function overrideProps(predefinedProps) { return { onPreviousClick: function onPreviousClick(e, data) { changeMonth(false); _invoke(predefinedProps, 'onPreviousClick', e, data); }, onNextClick: function onNextClick(e, data) { changeMonth(true); _invoke(predefinedProps, 'onNextClick', e, data); } }; } }), createShorthand(DatepickerCalendarGrid, calendarGrid, { defaultProps: function defaultProps() { return getA11yProps('calendarGrid', { content: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("thead", null, createShorthand(DatepickerCalendarGridRow, calendarGridRow, { defaultProps: function defaultProps() { return getA11yProps('calendarGridRow', { children: _times(DAYS_IN_WEEK, function (dayNumber) { return createShorthand(DatepickerCalendarHeaderCell, calendarHeaderCell, { defaultProps: function defaultProps() { return getA11yProps('calendarHeaderCell', { 'aria-label': days[(dayNumber + firstDayOfWeek) % DAYS_IN_WEEK], content: shortDays[(dayNumber + firstDayOfWeek) % DAYS_IN_WEEK], key: dayNumber }); } }); }) }); } })), /*#__PURE__*/React.createElement("tbody", null, _map(visibleGrid, function (week) { return createShorthand(DatepickerCalendarGridRow, calendarGridRow, { defaultProps: function defaultProps() { return getA11yProps('calendarGridRow', { children: renderWeekRow(week), isRowSelectionActive: dateRangeType === DateRangeType.Week, key: week[0].key }); } }); }))) }); } })); setEnd(); return element; }); DatepickerCalendar.displayName = 'DatepickerCalendar'; DatepickerCalendar.propTypes = Object.assign({}, commonPropTypes.createCommon(), { calendarCell: customPropTypes.itemShorthand, calendarCellButton: customPropTypes.itemShorthand, calendarHeaderCell: customPropTypes.itemShorthand, header: customPropTypes.itemShorthand, calendarGrid: customPropTypes.itemShorthand, calendarGridRow: customPropTypes.itemShorthand, onDateChange: PropTypes.func, selectedDate: PropTypes.instanceOf(Date), navigatedDate: PropTypes.instanceOf(Date), minDate: PropTypes.instanceOf(Date), maxDate: PropTypes.instanceOf(Date), restrictedDates: PropTypes.arrayOf(PropTypes.instanceOf(Date)), firstDayOfWeek: PropTypes.oneOf(Object.keys(DayOfWeek).map(function (name) { return DayOfWeek[name]; })), firstWeekOfYear: PropTypes.oneOf(Object.keys(FirstWeekOfYear).map(function (name) { return FirstWeekOfYear[name]; })), dateRangeType: PropTypes.oneOf(Object.keys(DateRangeType).map(function (name) { return DateRangeType[name]; })), daysToSelectInDayView: PropTypes.number, today: PropTypes.instanceOf(Date), showWeekNumbers: PropTypes.bool, workWeekDays: PropTypes.arrayOf(PropTypes.oneOf(Object.keys(DayOfWeek).map(function (name) { return DayOfWeek[name]; }))), weeksToShow: PropTypes.number, formatDay: PropTypes.func, formatYear: PropTypes.func, formatMonthDayYear: PropTypes.func, formatMonthYear: PropTypes.func, parseDate: PropTypes.func, months: PropTypes.arrayOf(PropTypes.string), shortMonths: PropTypes.arrayOf(PropTypes.string), days: PropTypes.arrayOf(PropTypes.string), shortDays: PropTypes.arrayOf(PropTypes.string), isRequiredErrorMessage: PropTypes.string, invalidInputErrorMessage: PropTypes.string, isOutOfBoundsErrorMessage: PropTypes.string, openCalendarTitle: PropTypes.string, inputPlaceholder: PropTypes.string, prevMonthAriaLabel: PropTypes.string, nextMonthAriaLabel: PropTypes.string, prevYearAriaLabel: PropTypes.string, nextYearAriaLabel: PropTypes.string, prevYearRangeAriaLabel: PropTypes.string, nextYearRangeAriaLabel: PropTypes.string, monthPickerHeaderAriaLabel: PropTypes.string, yearPickerHeaderAriaLabel: PropTypes.string, closeButtonAriaLabel: PropTypes.string, weekNumberFormatString: PropTypes.string, selectedDateFormatString: PropTypes.string, todayDateFormatString: PropTypes.string, inputAriaLabel: PropTypes.string, inputBoundedFormatString: PropTypes.string, inputMinBoundedFormatString: PropTypes.string, inputMaxBoundedFormatString: PropTypes.string }); DatepickerCalendar.defaultProps = Object.assign({ accessibility: datepickerCalendarBehavior, firstDayOfWeek: DayOfWeek.Monday, firstWeekOfYear: FirstWeekOfYear.FirstDay, dateRangeType: DateRangeType.Day, header: {}, calendarCell: {}, calendarCellButton: {}, calendarHeaderCell: {}, calendarGrid: {}, calendarGridRow: {} }, DEFAULT_CALENDAR_STRINGS); DatepickerCalendar.handledProps = Object.keys(DatepickerCalendar.propTypes); return DatepickerCalendar; }(); //# sourceMappingURL=DatepickerCalendar.js.map