UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

427 lines (426 loc) 16.2 kB
"use client"; var _AlignmentHelper; import withComponentMarkers from "../../shared/helpers/withComponentMarkers.js"; import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import clsx from 'clsx'; import { warn, extendPropsWithContext, getStatusState, combineDescribedBy, validateDOMAttributes } from "../../shared/component-helper.js"; import AlignmentHelper from "../../shared/AlignmentHelper.js"; import { applySpacing } from "../space/SpacingUtils.js"; import { skeletonDOMAttributes } from "../skeleton/SkeletonHelper.js"; import Context from "../../shared/Context.js"; import Suffix from "../../shared/helpers/Suffix.js"; import FormLabel from "../form-label/FormLabel.js"; import FormStatus from "../form-status/FormStatus.js"; import DatePickerProvider from "./DatePickerProvider.js"; import DatePickerRange from "./DatePickerRange.js"; import DatePickerInput from "./DatePickerInput.js"; import DatePickerAddon from "./DatePickerAddon.js"; import DatePickerFooter from "./DatePickerFooter.js"; import { pickFormElementProps } from "../../shared/helpers/filterValidProps.js"; import { useTranslation } from "../../shared/index.js"; import Popover from "../popover/Popover.js"; import { formatDate, formatDateRange } from "../date-format/DateFormatUtils.js"; import useId from "../../shared/helpers/useId.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const defaultProps = { hideNavigation: false, hideDays: false, onlyMonth: false, hideLastWeek: false, disableAutofocus: false, enableKeyboardNav: false, showInput: false, inline: false, resetDate: true, range: false, link: false, sync: true, statusState: 'error', open: false, noAnimation: false, direction: 'auto', skipPortal: false, yearNavigation: false, labelDirection: 'vertical' }; function DatePicker(externalProps) { var _externalProps$maskOr, _externalProps$maskPl; const props = { ...defaultProps, ...externalProps }; const { preventClose, onClose, onOpen, onSubmit, onCancel, onReset, noAnimation, showInput, inline, alignPicker, showSubmitButton, showCancelButton, range, hideDays, hideNavigation, open: openProp, endDate: endDateProp } = props; const [open, setOpen] = useState(inline ? true : openProp); const [hidden, setHidden] = useState(inline ? false : !open); const [dates, setDates] = useState({}); const context = useContext(Context); const blurDelay = 201; const id = useId(props.id); const shellRef = useRef(undefined); const submitButtonRef = useRef(undefined); const getReturnObject = useRef(undefined); const hideTimeout = useRef(undefined); const calendarContainerRef = useRef(null); const translation = useTranslation().DatePicker; const focusCalendarTable = useCallback(() => { var _calendarContainerRef; return (_calendarContainerRef = calendarContainerRef.current) === null || _calendarContainerRef === void 0 ? void 0 : _calendarContainerRef.querySelector('table'); }, []); if (endDateProp && !range) { warn(`The DatePicker got a "endDate". You have to set range={true} as well!.`); } const hidePicker = useCallback(args => { if (preventClose) { return; } setOpen(false); hideTimeout.current = setTimeout(() => { setHidden(true); onClose === null || onClose === void 0 || onClose({ ...getReturnObject.current(args) }); if (args !== null && args !== void 0 && args['focusOnClose']) { try { var _submitButtonRef$curr; (_submitButtonRef$curr = submitButtonRef.current) === null || _submitButtonRef$curr === void 0 || _submitButtonRef$curr.focus({ preventScroll: true }); } catch (e) { warn(e); } } }, noAnimation ? 1 : blurDelay); }, [noAnimation, preventClose, onClose]); const showPicker = useCallback(event => { if (hideTimeout.current) { clearTimeout(hideTimeout.current); } setOpen(true); setHidden(false); onOpen === null || onOpen === void 0 || onOpen({ ...getReturnObject.current(event) }); }, [onOpen]); useEffect(() => { if (openProp && !inline) { showPicker(); } }, [openProp, showPicker, inline]); const onPickerChange = useCallback(({ hidePicker: shouldHidePicker = true, ...args }) => { if (shouldHidePicker && !showSubmitButton && !showCancelButton) { hidePicker({ focusOnClose: true }); } setDates({ startDate: args.startDate, endDate: args.endDate }); }, [hidePicker, showSubmitButton, showCancelButton]); const onSubmitHandler = useCallback(event => { if (open) { hidePicker(event); onSubmit === null || onSubmit === void 0 || onSubmit({ ...getReturnObject.current({ event }) }); } else { showPicker(event); } }, [open, hidePicker, showPicker, onSubmit]); const onCancelHandler = useCallback(event => { hidePicker(); onCancel === null || onCancel === void 0 || onCancel({ ...getReturnObject.current(event) }); }, [hidePicker, onCancel]); const onResetHandler = useCallback(event => { hidePicker(); onReset === null || onReset === void 0 || onReset({ ...getReturnObject.current(event) }); }, [hidePicker, onReset]); const togglePicker = useCallback(args => { !open ? showPicker(args) : hidePicker(args); }, [open, showPicker, hidePicker]); const extendedProps = extendPropsWithContext(props, defaultProps, { skeleton: context === null || context === void 0 ? void 0 : context.skeleton }, context.getTranslation(props).DatePicker, pickFormElementProps(context === null || context === void 0 ? void 0 : context.formElement), context.DatePicker); const { label, title, labelDirection, labelSrOnly, onlyMonth, hideLastWeek, disableAutofocus, firstDay, resetDate, link, sync, inputElement, addonElement, shortcuts, disabled, stretch, skeleton, size, status, statusState, statusProps, statusNoAnimation, globalStatus, suffix, maskOrder, maskPlaceholder, submitButtonText, cancelButtonText, resetButtonText, showResetButton, className, tooltip, skipPortal, labelAlignment, _omitInputShellClass, ...restProps } = extendedProps; const resolvedMaskOrder = (_externalProps$maskOr = externalProps.maskOrder) !== null && _externalProps$maskOr !== void 0 ? _externalProps$maskOr : context.locale === 'en-US' ? 'mm/dd/yyyy' : maskOrder; const resolvedMaskPlaceholder = (_externalProps$maskPl = externalProps.maskPlaceholder) !== null && _externalProps$maskPl !== void 0 ? _externalProps$maskPl : context.locale === 'en-US' ? 'mm/dd/yyyy' : maskPlaceholder; const attributes = useMemo(() => filterOutNonAttributes(restProps), [restProps]); const showStatus = getStatusState(status); const pickerParams = {}; if (showStatus || suffix) { pickerParams['aria-describedby'] = combineDescribedBy(pickerParams, showStatus ? id + '-status' : null, suffix ? id + '-suffix' : null); } const submitParams = { ['aria-expanded']: open, ref: submitButtonRef, tabIndex: extendedProps.tabIndex, tooltip }; const selectedDateTitle = useMemo(() => { const { selectedDate, selectedDateRange } = translation; const { startDate, endDate } = dates; if (!startDate) { return ''; } const options = { locale: context.locale, options: { dateStyle: 'full' } }; return range && endDate ? selectedDateRange.replace(/%s/, formatDateRange({ startDate, endDate }, options)) : selectedDate.replace(/%s/, formatDate(startDate, options)); }, [range, translation, dates, context.locale]); const mainParams = applySpacing(props, { className: clsx("dnb-date-picker dnb-form-component", className, status && `dnb-date-picker__status--${statusState}`, labelDirection && `dnb-date-picker--${labelDirection}`, open && 'dnb-date-picker--open', hidden && 'dnb-date-picker--hidden', showInput && 'dnb-date-picker--show-input', inline && 'dnb-date-picker--inline', label && labelAlignment === 'right' && 'dnb-date-picker__input--label-alignment-right', stretch && `dnb-date-picker--stretch`, size && `dnb-date-picker--${size}`), lang: context.locale }); const containerClassNames = clsx('dnb-date-picker__container', ((inline ? false : range) || showSubmitButton || showCancelButton || showResetButton) && 'dnb-date-picker__container--show-footer', open ? 'dnb-date-picker__container--open' : 'dnb-date-picker__container--closed', hidden && 'dnb-date-picker__container--hidden', showInput && 'dnb-date-picker__container--show-input', size && `dnb-date-picker--${size}`); const remainingDOMProps = validateDOMAttributes(props, attributes); const remainingSubmitProps = validateDOMAttributes(null, submitParams); const remainingPickerProps = validateDOMAttributes(null, skeletonDOMAttributes(pickerParams, skeleton, context)); return _jsx(DatePickerProvider, { ...props, open: open, attributes: remainingDOMProps, setReturnObject: fn => getReturnObject.current = fn, hidePicker: hidePicker, children: _jsxs("span", { ...mainParams, children: [label && _jsx(FormLabel, { id: id + '-label', forId: id, text: label, labelDirection: labelDirection, srOnly: labelSrOnly, disabled: disabled, skeleton: skeleton }), _jsxs("span", { className: "dnb-date-picker__inner", ref: shellRef, ...remainingPickerProps, children: [_AlignmentHelper || (_AlignmentHelper = _jsx(AlignmentHelper, {})), _jsx(FormStatus, { show: showStatus, id: id + '-form-status', globalStatus: globalStatus, label: String(label), textId: id + '-status', widthSelector: id + '-shell', text: status, state: statusState, noAnimation: statusNoAnimation, skeleton: skeleton, ...statusProps }), _jsxs("span", { className: "dnb-date-picker__row", children: [inline ? _jsxs("span", { className: containerClassNames, ref: calendarContainerRef, children: [_jsx(DatePickerRange, { id: id, firstDayOfWeek: firstDay, resetDate: resetDate, isRange: range, isLink: link, isSync: sync, hideDays: hideDays, hideNavigation: hideNavigation, onlyMonth: onlyMonth, hideNextMonthWeek: hideLastWeek, onPickerChange: onPickerChange, locale: context.locale }), (addonElement || shortcuts) && _jsx(DatePickerAddon, { renderElement: addonElement, shortcuts: shortcuts }), _jsx(DatePickerFooter, { isRange: inline ? false : range, onSubmit: onSubmitHandler, onCancel: onCancelHandler, onReset: onResetHandler, submitButtonText: submitButtonText, cancelButtonText: cancelButtonText, resetButtonText: resetButtonText })] }) : _jsxs("span", { className: "dnb-date-picker__shell", id: `${id}-shell`, children: [_jsx(DatePickerInput, { id: id, title: title, disabled: disabled, stretch: stretch, skeleton: skeleton, maskOrder: resolvedMaskOrder, maskPlaceholder: resolvedMaskPlaceholder, isRange: range, showInput: showInput, selectedDateTitle: selectedDateTitle, inputElement: inputElement, open: open, hidden: hidden, size: size, status: status ? 'error' : null, statusState: statusState, lang: context.locale, _omitInputShellClass: _omitInputShellClass, ...attributes, submitAttributes: remainingSubmitProps, onSubmit: togglePicker, ...statusProps }), _jsx(Popover, { open: open, targetElement: { verticalRef: submitButtonRef, horizontalRef: shellRef }, noAnimation: noAnimation, skipPortal: skipPortal, keepInDOM: !hidden, focusOnOpen: !disableAutofocus, focusOnOpenElement: focusCalendarTable, alignOnTarget: alignPicker === 'right' || stretch ? 'right' : 'left', horizontalOffset: showInput ? 8 : -8, placement: props.direction === 'auto' ? 'bottom' : props.direction, onOpenChange: isOpen => !isOpen && hidePicker(), hideCloseButton: true, hideOutline: true, preventClose: preventClose, triggerOffset: 0, arrowEdgeOffset: 4, noInnerSpace: true, noMaxWidth: true, portalRootClass: "dnb-date-picker__portal", arrowPosition: alignPicker === 'right' ? 'right' : 'left', arrowPositionSelector: `#${id}`, children: _jsxs("span", { className: containerClassNames, ref: calendarContainerRef, children: [_jsx(DatePickerRange, { id: id, firstDayOfWeek: firstDay, resetDate: resetDate, isRange: range, isLink: link, isSync: sync, hideDays: hideDays, hideNavigation: hideNavigation, onlyMonth: onlyMonth, hideNextMonthWeek: hideLastWeek, onPickerChange: onPickerChange, locale: context.locale }), (addonElement || shortcuts) && _jsx(DatePickerAddon, { renderElement: addonElement, shortcuts: shortcuts }), _jsx(DatePickerFooter, { isRange: inline ? false : range, onSubmit: onSubmitHandler, onCancel: onCancelHandler, onReset: onResetHandler, submitButtonText: submitButtonText, cancelButtonText: cancelButtonText, resetButtonText: resetButtonText })] }) })] }), suffix && _jsx(Suffix, { className: "dnb-date-picker__suffix", id: id + '-suffix', context: props, children: suffix })] })] }), _jsx("p", { className: "dnb-sr-only", "aria-live": "assertive", children: selectedDateTitle })] }) }); } const NonAttributes = ['locale', 'id', 'day', 'month', 'year', 'date', 'start', 'end', 'startDate', 'endDate', 'minDate', 'maxDate', 'hidden', 'stretch', 'enableKeyboardNav', 'hideNavigation', 'returnFormat', 'dateFormat', 'hideDays', 'open', 'direction', 'range', 'showInput', 'inline', 'noAnimation', 'onDaysRender', 'onOpen', 'onType', 'onClose', 'showSubmitButton', 'showCancelButton', 'selectedDate', 'selectedMonth', 'selectedYear', 'nextMonth', 'nextYear', 'openPickerText', 'placeholderCharacters', 'prevMonth', 'prevYear', 'endMonth', 'startMonth', 'alignPicker', 'preventClose', 'selectedDateRange', 'yearNavigation']; function filterOutNonAttributes(props) { return Object.keys(props).reduce((attributes, key) => { if (!NonAttributes.includes(key)) { attributes[key] = props[key]; } return attributes; }, {}); } withComponentMarkers(DatePicker, { _formElement: true, _supportsSpacingProps: true }); export default DatePicker; //# sourceMappingURL=DatePicker.js.map