@fluentui/react-northstar
Version:
A themable React component library.
427 lines (423 loc) • 19.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.datepickerClassName = exports.Datepicker = void 0;
var _invoke2 = _interopRequireDefault(require("lodash/invoke"));
var _accessibility = require("@fluentui/accessibility");
var _dateTimeUtilities = require("../../utils/date-time-utilities");
var _reactBindings = require("@fluentui/react-bindings");
var _reactIconsNorthstar = require("@fluentui/react-icons-northstar");
var customPropTypes = _interopRequireWildcard(require("@fluentui/react-proptypes"));
var _reactComponentRef = require("@fluentui/react-component-ref");
var PropTypes = _interopRequireWildcard(require("prop-types"));
var React = _interopRequireWildcard(require("react"));
var _utils = require("../../utils");
var _Button = require("../Button/Button");
var _Input = require("../Input/Input");
var _Popup = require("../Popup/Popup");
var _DatepickerCalendar = require("./DatepickerCalendar");
var _DatepickerCalendarCell = require("./DatepickerCalendarCell");
var _DatepickerCalendarCellButton = require("./DatepickerCalendarCellButton");
var _DatepickerCalendarHeader = require("./DatepickerCalendarHeader");
var _DatepickerCalendarHeaderAction = require("./DatepickerCalendarHeaderAction");
var _DatepickerCalendarHeaderCell = require("./DatepickerCalendarHeaderCell");
var _DatepickerCalendarGrid = require("./DatepickerCalendarGrid");
var _DatepickerCalendarGridRow = require("./DatepickerCalendarGridRow");
var _validateDate = require("./validateDate");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var datepickerClassName = 'ui-datepicker';
exports.datepickerClassName = datepickerClassName;
var formatRestrictedInput = function formatRestrictedInput(restrictedOptions, localizationStrings) {
var formattedString = '';
if (!!restrictedOptions.minDate && !!restrictedOptions.maxDate) {
formattedString = (0, _utils.format)(localizationStrings.inputBoundedFormatString, localizationStrings.formatMonthDayYear(restrictedOptions.minDate, localizationStrings), localizationStrings.formatMonthDayYear(restrictedOptions.maxDate, localizationStrings));
} else if (!!restrictedOptions.minDate) {
formattedString = (0, _utils.format)(localizationStrings.inputMinBoundedFormatString, localizationStrings.formatMonthDayYear(restrictedOptions.minDate, localizationStrings));
} else if (!!restrictedOptions.maxDate) {
formattedString = (0, _utils.format)(localizationStrings.inputMaxBoundedFormatString, localizationStrings.formatMonthDayYear(restrictedOptions.maxDate, localizationStrings));
} else {
formattedString = localizationStrings.inputAriaLabel;
}
return formattedString;
};
/**
* A Datepicker is a control which is used to display dates grid and allow user to select them.
*
* @accessibilityIssues
* [NVDA - Aria-selected is not narrated for the gridcell](https://github.com/nvaccess/nvda/issues/11986)
*/
var Datepicker = /*#__PURE__*/React.forwardRef(function (props, ref) {
var _props$today;
var context = (0, _reactBindings.useFluentContext)();
var _useTelemetry = (0, _reactBindings.useTelemetry)(Datepicker.displayName, context.telemetry),
setStart = _useTelemetry.setStart,
setEnd = _useTelemetry.setEnd;
setStart();
var _inputRef = React.useRef();
// FIXME: This object is created every render, causing a cascade of useCallback/useEffect re-runs.
// Needs to be reworked by someone who understands the intent for when various updates ought to happen.
// eslint-disable-next-line react-hooks/exhaustive-deps
var dateFormatting = {
formatDay: props.formatDay,
formatYear: props.formatYear,
formatMonthDayYear: props.formatMonthDayYear,
formatMonthYear: props.formatMonthYear,
parseDate: props.parseDate,
months: props.months,
shortMonths: props.shortMonths,
days: props.days,
shortDays: props.shortDays,
isRequiredErrorMessage: props.isRequiredErrorMessage,
invalidInputErrorMessage: props.invalidInputErrorMessage,
isOutOfBoundsErrorMessage: props.isOutOfBoundsErrorMessage,
openCalendarTitle: props.openCalendarTitle,
inputPlaceholder: props.inputPlaceholder,
prevMonthAriaLabel: props.prevMonthAriaLabel,
nextMonthAriaLabel: props.nextMonthAriaLabel,
prevYearAriaLabel: props.prevYearAriaLabel,
nextYearAriaLabel: props.nextYearAriaLabel,
prevYearRangeAriaLabel: props.prevYearRangeAriaLabel,
nextYearRangeAriaLabel: props.nextYearRangeAriaLabel,
monthPickerHeaderAriaLabel: props.monthPickerHeaderAriaLabel,
yearPickerHeaderAriaLabel: props.yearPickerHeaderAriaLabel,
closeButtonAriaLabel: props.closeButtonAriaLabel,
weekNumberFormatString: props.weekNumberFormatString,
selectedDateFormatString: props.selectedDateFormatString,
todayDateFormatString: props.todayDateFormatString,
inputAriaLabel: props.inputAriaLabel,
inputBoundedFormatString: props.inputBoundedFormatString,
inputMinBoundedFormatString: props.inputMinBoundedFormatString,
inputMaxBoundedFormatString: props.inputMaxBoundedFormatString
};
var calendar = props.calendar,
popup = props.popup,
input = props.input,
className = props.className,
design = props.design,
styles = props.styles,
variables = props.variables,
formatMonthDayYear = props.formatMonthDayYear,
allowManualInput = props.allowManualInput,
ariaLabelledby = props['aria-labelledby'],
ariaInvalid = props['aria-invalid'];
var valueFormatter = React.useCallback(function (date) {
return date ? formatMonthDayYear(date, {
months: dateFormatting.months,
shortMonths: dateFormatting.shortMonths,
days: dateFormatting.days,
shortDays: dateFormatting.shortDays
}) : '';
}, [dateFormatting.days, dateFormatting.months, dateFormatting.shortDays, dateFormatting.shortMonths, formatMonthDayYear]);
var _useAutoControlled = (0, _reactBindings.useAutoControlled)({
defaultValue: props.defaultCalendarOpenState,
value: props.calendarOpenState,
initialValue: false
}),
openState = _useAutoControlled[0],
setOpenState = _useAutoControlled[1];
var _useAutoControlled2 = (0, _reactBindings.useAutoControlled)({
defaultValue: props.defaultSelectedDate,
value: props.selectedDate,
initialValue: undefined
}),
selectedDate = _useAutoControlled2[0],
setSelectedDate = _useAutoControlled2[1];
var _React$useState = React.useState(valueFormatter(selectedDate)),
formattedDate = _React$useState[0],
setFormattedDate = _React$useState[1];
React.useEffect(function () {
setFormattedDate(valueFormatter(selectedDate));
}, [selectedDate, valueFormatter]);
var restrictedDatesOptions = {
minDate: props.minDate,
maxDate: props.maxDate,
restrictedDates: props.restrictedDates
};
var _React$useState2 = React.useState(function () {
return !!props.selectedDate || !!props.defaultSelectedDate ? (0, _validateDate.validateDate)(selectedDate, formattedDate, restrictedDatesOptions, dateFormatting, props.required) : '';
}),
error = _React$useState2[0],
setError = _React$useState2[1];
var trySetOpenState = function trySetOpenState(newValue, event) {
setOpenState(newValue);
(0, _invoke2.default)(props, 'onCalendarOpenStateChange', event, Object.assign({}, props, {
calendarOpenState: newValue
}));
};
var calendarOptions = Object.assign({
selectedDate: selectedDate,
navigatedDate: !!selectedDate && !error ? selectedDate : (_props$today = props.today) != null ? _props$today : new Date(),
firstDayOfWeek: props.firstDayOfWeek,
firstWeekOfYear: props.firstWeekOfYear,
dateRangeType: props.dateRangeType,
daysToSelectInDayView: props.daysToSelectInDayView,
today: props.today,
showWeekNumbers: props.showWeekNumbers,
workWeekDays: props.workWeekDays
}, restrictedDatesOptions);
var ElementType = (0, _reactBindings.getElementType)(props);
var unhandledProps = (0, _reactBindings.useUnhandledProps)(Datepicker.handledProps, props);
var getA11yProps = (0, _reactBindings.useAccessibility)(props.accessibility, {
debugName: Datepicker.displayName,
actionHandlers: {
open: function open(e) {
if (allowManualInput) {
trySetOpenState(!openState, e);
} else {
// Keep popup open in case we can only enter the date through calendar.
trySetOpenState(true, e);
}
e.preventDefault();
}
},
mapPropsToBehavior: function mapPropsToBehavior() {
return {
'aria-invalid': ariaInvalid,
'aria-labelledby': ariaLabelledby,
allowManualInput: allowManualInput
};
},
rtl: context.rtl
});
var _useStyles = (0, _reactBindings.useStyles)(Datepicker.displayName, {
className: datepickerClassName,
mapPropsToStyles: function mapPropsToStyles() {
return {
allowManualInput: allowManualInput
};
},
mapPropsToInlineStyles: function mapPropsToInlineStyles() {
return {
className: className,
design: design,
styles: styles,
variables: variables
};
},
rtl: context.rtl
}),
classes = _useStyles.classes;
var overrideDatepickerCalendarProps = function overrideDatepickerCalendarProps(predefinedProps) {
return {
onDateChange: function onDateChange(e, itemProps) {
var targetDay = itemProps.value;
setSelectedDate(targetDay.originalDate);
trySetOpenState(false, e);
setError('');
setFormattedDate(valueFormatter(targetDay.originalDate));
(0, _invoke2.default)(props, 'onDateChange', e, {
itemProps: itemProps,
value: targetDay.originalDate
});
}
};
};
var calendarElement = (0, _utils.createShorthand)(_DatepickerCalendar.DatepickerCalendar, calendar, {
defaultProps: function defaultProps() {
return getA11yProps('calendar', Object.assign({}, calendarOptions, dateFormatting));
},
overrideProps: overrideDatepickerCalendarProps
});
var overrideInputProps = function overrideInputProps(predefinedProps) {
return {
onClick: function onClick(e) {
if (allowManualInput) {
trySetOpenState(!openState, e);
} else {
// Keep popup open in case we can only enter the date through calendar.
trySetOpenState(true, e);
}
(0, _invoke2.default)(predefinedProps, 'onClick', e, predefinedProps);
},
onChange: function onChange(e, target) {
var parsedDate = props.parseDate(target.value);
var validationError = (0, _validateDate.validateDate)(parsedDate, target.value, calendarOptions, dateFormatting, props.required);
setError(validationError);
setFormattedDate(target.value);
if (!!validationError) {
(0, _invoke2.default)(props, 'onDateChangeError', e, Object.assign({}, props, {
error: validationError
}));
} else {
setSelectedDate(parsedDate);
(0, _invoke2.default)(props, 'onDateChange', e, Object.assign({}, props, {
value: parsedDate
}));
}
(0, _invoke2.default)(predefinedProps, 'onChange', e, predefinedProps);
},
onBlur: function onBlur(e) {
if (props.fallbackToLastCorrectDateOnBlur && !!error) {
var futureFormattedDate = valueFormatter(selectedDate);
var validationError = (0, _validateDate.validateDate)(selectedDate, futureFormattedDate, calendarOptions, dateFormatting, props.required);
setError(validationError);
setFormattedDate(futureFormattedDate);
if (!!validationError) {
(0, _invoke2.default)(props, 'onDateChangeError', e, Object.assign({}, props, {
error: validationError
}));
}
}
(0, _invoke2.default)(predefinedProps, 'onBlur', e, predefinedProps);
},
inputRef: function inputRef(node) {
(0, _reactComponentRef.handleRef)(predefinedProps.inputRef, node);
_inputRef.current = node;
}
};
};
var triggerButtonElement = props.inputOnly ? null : /*#__PURE__*/React.createElement(_Button.Button, {
icon: /*#__PURE__*/React.createElement(_reactIconsNorthstar.CalendarIcon, null),
title: props.openCalendarTitle,
iconOnly: true,
disabled: props.disabled,
type: "button"
});
var element = getA11yProps.unstable_wrapWithFocusZone( /*#__PURE__*/React.createElement(ElementType, getA11yProps('root', Object.assign({
className: classes.root,
ref: ref
}, unhandledProps)), !props.buttonOnly && (0, _utils.createShorthand)(_Input.Input, input, {
defaultProps: function defaultProps() {
return getA11yProps('input', {
placeholder: props.inputPlaceholder,
disabled: props.disabled,
error: !!error,
value: formattedDate,
readOnly: !allowManualInput,
required: props.required,
'aria-label': formatRestrictedInput(restrictedDatesOptions, dateFormatting)
});
},
overrideProps: overrideInputProps
}), (0, _utils.createShorthand)(_Popup.Popup, popup, {
defaultProps: function defaultProps() {
return {
open: openState && !props.disabled,
trapFocus: {
disableFirstFocus: true
},
position: 'below',
align: 'start'
};
},
overrideProps: function overrideProps(predefinedProps) {
var _predefinedProps$trig;
return {
trigger: (_predefinedProps$trig = predefinedProps.trigger) != null ? _predefinedProps$trig : triggerButtonElement,
target: props.buttonOnly ? null : _inputRef.current,
content: calendarElement,
onOpenChange: function onOpenChange(e, _ref) {
var open = _ref.open;
// In case the event is a click on input, we ignore such events as it should be directly handled by input.
if (!(e.type === 'click' && e.target === (_inputRef == null ? void 0 : _inputRef.current))) {
trySetOpenState(open, e);
(0, _invoke2.default)(predefinedProps, 'onOpenChange', e, {
open: open
});
}
}
};
}
})));
setEnd();
return element;
});
exports.Datepicker = Datepicker;
Datepicker.displayName = 'Datepicker';
Datepicker.propTypes = Object.assign({}, _utils.commonPropTypes.createCommon(), {
calendar: customPropTypes.itemShorthand,
popup: customPropTypes.itemShorthand,
input: customPropTypes.itemShorthand,
disabled: PropTypes.bool,
required: PropTypes.bool,
onDateChange: PropTypes.func,
onDateChangeError: PropTypes.func,
allowManualInput: PropTypes.bool,
fallbackToLastCorrectDateOnBlur: PropTypes.bool,
defaultCalendarOpenState: PropTypes.bool,
calendarOpenState: PropTypes.bool,
onCalendarOpenStateChange: PropTypes.func,
selectedDate: PropTypes.instanceOf(Date),
defaultSelectedDate: PropTypes.instanceOf(Date),
inputOnly: PropTypes.bool,
buttonOnly: PropTypes.bool,
minDate: PropTypes.instanceOf(Date),
maxDate: PropTypes.instanceOf(Date),
restrictedDates: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
firstDayOfWeek: PropTypes.oneOf(Object.keys(_dateTimeUtilities.DayOfWeek).map(function (name) {
return _dateTimeUtilities.DayOfWeek[name];
})),
firstWeekOfYear: PropTypes.oneOf(Object.keys(_dateTimeUtilities.FirstWeekOfYear).map(function (name) {
return _dateTimeUtilities.FirstWeekOfYear[name];
})),
dateRangeType: PropTypes.oneOf(Object.keys(_dateTimeUtilities.DateRangeType).map(function (name) {
return _dateTimeUtilities.DateRangeType[name];
})),
daysToSelectInDayView: PropTypes.number,
today: PropTypes.instanceOf(Date),
showWeekNumbers: PropTypes.bool,
workWeekDays: PropTypes.arrayOf(PropTypes.oneOf(Object.keys(_dateTimeUtilities.DayOfWeek).map(function (name) {
return _dateTimeUtilities.DayOfWeek[name];
}))),
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,
'aria-labelledby': PropTypes.string,
'aria-invalid': PropTypes.bool
});
Datepicker.defaultProps = Object.assign({
accessibility: _accessibility.datepickerBehavior,
inputOnly: false,
buttonOnly: false,
calendar: {},
popup: {},
input: {},
firstDayOfWeek: _dateTimeUtilities.DayOfWeek.Monday,
firstWeekOfYear: _dateTimeUtilities.FirstWeekOfYear.FirstDay,
dateRangeType: _dateTimeUtilities.DateRangeType.Day,
fallbackToLastCorrectDateOnBlur: true,
allowManualInput: true,
required: false
}, _dateTimeUtilities.DEFAULT_CALENDAR_STRINGS);
Datepicker.handledProps = Object.keys(Datepicker.propTypes);
Datepicker.create = (0, _utils.createShorthandFactory)({
Component: Datepicker
});
Datepicker.Calendar = _DatepickerCalendar.DatepickerCalendar;
Datepicker.CalendarHeader = _DatepickerCalendarHeader.DatepickerCalendarHeader;
Datepicker.CalendarHeaderAction = _DatepickerCalendarHeaderAction.DatepickerCalendarHeaderAction;
Datepicker.CalendarHeaderCell = _DatepickerCalendarHeaderCell.DatepickerCalendarHeaderCell;
Datepicker.CalendarCell = _DatepickerCalendarCell.DatepickerCalendarCell;
Datepicker.CalendarCellButton = _DatepickerCalendarCellButton.DatepickerCalendarCellButton;
Datepicker.CalendarGrid = _DatepickerCalendarGrid.DatepickerCalendarGrid;
Datepicker.CalendarGridRow = _DatepickerCalendarGridRow.DatepickerCalendarGridRow;
Datepicker.Input = _Input.Input;
//# sourceMappingURL=Datepicker.js.map