@fluentui/react-northstar
Version:
A themable React component library.
403 lines (401 loc) • 18.1 kB
JavaScript
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