UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

384 lines (383 loc) 13.9 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.DEFAULT_DATE_FORMAT = void 0; var _react = _interopRequireWildcard(require("react")); var _index = _interopRequireDefault(require("../String/index.js")); var _index2 = _interopRequireDefault(require("../Composition/index.js")); var _index3 = _interopRequireDefault(require("../Selection/index.js")); var _Context = _interopRequireDefault(require("../../../../shared/Context.js")); var _dateFns = require("date-fns"); var _useTranslation = _interopRequireDefault(require("../../hooks/useTranslation.js")); var _DateFormatUtils = require("../../../../components/date-format/DateFormatUtils.js"); var _index4 = require("../../hooks/index.js"); var _useIterateItemNo = require("../../Iterate/ItemNo/useIterateItemNo.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } const DEFAULT_DATE_FORMAT = exports.DEFAULT_DATE_FORMAT = 'yyyy-MM-dd'; function DateOfBirth(props) { const [, forceUpdate] = (0, _react.useReducer)(() => ({}), {}); const { errorDateOfBirth, errorDateOfBirthFuture, errorRequired, label, dayLabel, monthLabel, yearLabel, dayPlaceholder, monthPlaceholder, yearPlaceholder } = (0, _useTranslation.default)().DateOfBirth; const { locale } = (0, _react.useContext)(_Context.default); const { dateFormat = DEFAULT_DATE_FORMAT, labelSuffix, required } = props; const dayRef = (0, _react.useRef)(props === null || props === void 0 ? void 0 : props.emptyValue); const monthRef = (0, _react.useRef)(props === null || props === void 0 ? void 0 : props.emptyValue); const yearRef = (0, _react.useRef)(props === null || props === void 0 ? void 0 : props.emptyValue); const errorMessages = (0, _react.useMemo)(() => { return { 'Field.errorRequired': errorRequired, 'Field.errorPattern': errorDateOfBirth, ...props.errorMessages }; }, [errorDateOfBirth, errorRequired, props.errorMessages]); const provideAdditionalArgs = (0, _react.useCallback)(value => { const [year, month, day] = splitValue(value, dateFormat); if (year && month && day) { return { year, month, day }; } }, [dateFormat]); const dateOfBirthValidator = (0, _react.useCallback)(value => { const [year, month, day] = splitValue(value, dateFormat); if (year && month && day) { const isoValue = `${year}-${month}-${day}`; const dateValue = (0, _dateFns.parseISO)(isoValue); if (!(0, _dateFns.isValid)(dateValue)) { return Error(errorDateOfBirth); } if ((0, _dateFns.isAfter)(dateValue, new Date())) { return Error(errorDateOfBirthFuture); } } }, [errorDateOfBirth, errorDateOfBirthFuture, dateFormat]); const { onBlurValidator: propOnBlurValidator, onChangeValidator, value: propValue, space, ...otherProps } = props; const onBlurValidator = (0, _react.useMemo)(() => { if (propOnBlurValidator === false) { return undefined; } if (typeof propOnBlurValidator === 'function') { return (value, args) => { const coreResult = dateOfBirthValidator(value); if (coreResult instanceof Error) { return coreResult; } return propOnBlurValidator(value, args); }; } return dateOfBirthValidator; }, [propOnBlurValidator, dateOfBirthValidator]); const preparedProps = (0, _react.useMemo)(() => ({ ...otherProps, value: propValue, errorMessages, onBlurValidator, onChangeValidator, exportValidators: { dateOfBirthValidator }, provideAdditionalArgs }), [otherProps, propValue, errorMessages, onBlurValidator, onChangeValidator, dateOfBirthValidator, provideAdditionalArgs]); const { emptyValue, label: labelProp, width = 'large', help, labelSrOnly, labelSize, labelDescription, labelDescriptionInline, error, disabled, htmlAttributes, handleChange, onDayChange, onMonthChange, onYearChange, setHasFocus, value: fieldValue } = (0, _index4.useFieldProps)(preparedProps); const labelWithItemNo = (0, _useIterateItemNo.useIterateItemNo)({ label: labelProp !== null && labelProp !== void 0 ? labelProp : label, labelSuffix, required }); const prepareEventValues = (0, _react.useCallback)(({ day = dayRef.current || emptyValue, month = monthRef.current || emptyValue, year = yearRef.current || emptyValue } = {}) => { return { year, month, day }; }, [emptyValue]); const callOnChange = (0, _react.useCallback)(data => { const eventValues = prepareEventValues(data); handleChange(joinValue([eventValues.year, eventValues.month, eventValues.day], dateFormat), eventValues); }, [prepareEventValues, handleChange, dateFormat]); const callOnBlurOrFocus = (0, _react.useCallback)(hasFocus => { setHasFocus(hasFocus, undefined, prepareEventValues()); }, [prepareEventValues, setHasFocus]); (0, _react.useEffect)(() => { if (fieldValue) { const [year, month, day] = splitValue(fieldValue, dateFormat); const currentValues = joinValue([yearRef.current, monthRef.current, dayRef.current], dateFormat); const shouldUpdate = !dayRef.current && !monthRef.current && !yearRef.current || fieldValue !== currentValues; if (shouldUpdate) { dayRef.current = day; monthRef.current = month; yearRef.current = year; forceUpdate(); } } }, [fieldValue, dateFormat]); const handleDayChange = (0, _react.useCallback)(value => { const day = dayRef.current = value || emptyValue; forceUpdate(); callOnChange({ day, month: monthRef.current, year: yearRef.current }); onDayChange === null || onDayChange === void 0 || onDayChange(day); }, [emptyValue, callOnChange, onDayChange]); const handleMonthChange = (0, _react.useCallback)(value => { const month = monthRef.current = value || emptyValue; forceUpdate(); callOnChange({ day: dayRef.current, month, year: yearRef.current }); onMonthChange === null || onMonthChange === void 0 || onMonthChange(month); }, [emptyValue, callOnChange, onMonthChange]); const handleYearChange = (0, _react.useCallback)(value => { const year = yearRef.current = value || emptyValue; forceUpdate(); callOnChange({ day: dayRef.current, month: monthRef.current, year }); onYearChange === null || onYearChange === void 0 || onYearChange(year); }, [emptyValue, callOnChange, onYearChange]); const normalizeDay = (0, _react.useCallback)(value => { if (!value) { return value; } const trimmed = value.trim(); if (/^[1-9]$/.test(trimmed)) { return trimmed.padStart(2, '0'); } return trimmed; }, []); const normalizeYear = (0, _react.useCallback)(value => { if (!value) { return value; } const trimmed = value.trim(); if (/^\d{1,2}$/.test(trimmed)) { const padded = trimmed.padStart(2, '0'); const currentYear = new Date().getFullYear(); const currentCentury = Math.floor(currentYear / 100) * 100; let normalized = currentCentury + parseInt(padded, 10); if (normalized > currentYear) { normalized -= 100; } return String(normalized); } return trimmed; }, []); const handleOnBlur = (0, _react.useCallback)(() => { callOnBlurOrFocus(false); }, [callOnBlurOrFocus]); const handleDayBlur = (0, _react.useCallback)(() => { const normalized = normalizeDay(dayRef.current); if (normalized && normalized !== dayRef.current) { handleDayChange(normalized); } handleOnBlur(); }, [handleDayChange, handleOnBlur, normalizeDay]); const handleYearBlur = (0, _react.useCallback)(() => { const normalized = normalizeYear(yearRef.current); if (normalized && normalized !== yearRef.current) { handleYearChange(normalized); } handleOnBlur(); }, [handleOnBlur, handleYearChange, normalizeYear]); const handleOnFocus = (0, _react.useCallback)(() => { callOnBlurOrFocus(true); }, [callOnBlurOrFocus]); const compositionFieldProps = { className: 'dnb-forms-field-date-of-birth', error, label: labelWithItemNo, labelSrOnly, labelSize, labelDescription, labelDescriptionInline, space }; const months = (0, _react.useMemo)(() => { return [...Array(12)].map((_, i) => { const nr = String(i + 1); const value = nr.padStart(2, '0'); const title = capitalizeFirstLetter((0, _DateFormatUtils.formatDate)(new Date(0, i, 1), { locale, options: { month: 'long' } })); return { value, title, search_content: [title, nr, value] }; }); }, [locale]); const onBlurAutocomplete = (0, _react.useCallback)(({ value }) => { const nr = parseFloat(value); if (!isNaN(nr)) { var _months$find; const monthValue = (_months$find = months.find(m => parseFloat(m.value) === nr)) === null || _months$find === void 0 ? void 0 : _months$find.value; const month = monthValue || emptyValue; monthRef.current = month; forceUpdate(); callOnChange({ month }); } else { var _months$find2; const monthValue = (_months$find2 = months.find(m => m.title === value)) === null || _months$find2 === void 0 ? void 0 : _months$find2.value; if (monthValue) { monthRef.current = monthValue; forceUpdate(); callOnChange({ month: monthValue }); } } }, [callOnChange, emptyValue, months]); return _react.default.createElement(_index2.default, _extends({ width: width, help: help }, compositionFieldProps), _react.default.createElement(_index.default, { value: dayRef.current, autoComplete: "bday-day", labelDescription: dayLabel, labelSize: labelSize, width: "3.5rem", inputMode: "numeric", mask: [/[0-9]/, /[0-9]/], placeholder: dayPlaceholder, onChange: handleDayChange, onFocus: handleOnFocus, onBlur: handleDayBlur, disabled: disabled, htmlAttributes: htmlAttributes }), _react.default.createElement(_index3.default, { className: "dnb-forms-field-date-of-birth__month", value: monthRef.current, variant: "autocomplete", labelDescription: monthLabel, labelSize: labelSize, width: "stretch", placeholder: "", autocompleteProps: { openOnFocus: true, inputIcon: '', placeholder: monthPlaceholder, autoComplete: 'bday-month', independentWidth: true, disableReorder: true, onBlur: onBlurAutocomplete }, data: months, onChange: handleMonthChange, onFocus: handleOnFocus, onBlur: handleOnBlur, disabled: disabled, htmlAttributes: htmlAttributes }), _react.default.createElement(_index.default, { value: yearRef.current, autoComplete: "bday-year", labelDescription: yearLabel, width: "stretch", inputMode: "numeric", mask: [/[0-9]/, /[0-9]/, /[0-9]/, /[0-9]/], placeholder: yearPlaceholder, onChange: handleYearChange, onFocus: handleOnFocus, onBlur: handleYearBlur, disabled: disabled, htmlAttributes: htmlAttributes })); } DateOfBirth._supportsSpacingProps = undefined; var _default = exports.default = DateOfBirth; function capitalizeFirstLetter(s) { return s.charAt(0).toUpperCase() + s.slice(1); } function joinValue(array, dateFormat = DEFAULT_DATE_FORMAT) { const [year, month, day] = array; if (!year || !month || !day) { return undefined; } return dateFormat.replace('yyyy', year).replace('MM', month).replace('dd', day); } function splitValue(value, dateFormat = DEFAULT_DATE_FORMAT) { if (typeof value !== 'string' || !value) { return [undefined, undefined, undefined]; } const formatPattern = dateFormat.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/yyyy/g, '(\\d{4})').replace(/MM/g, '(\\d{2})').replace(/dd/g, '(\\d{2})'); const regex = new RegExp(`^${formatPattern}$`); const match = value.match(regex); if (!match) { return [undefined, undefined, undefined]; } const yearIndex = dateFormat.indexOf('yyyy'); const monthIndex = dateFormat.indexOf('MM'); const dayIndex = dateFormat.indexOf('dd'); const sortedIndices = [yearIndex, monthIndex, dayIndex].sort((a, b) => a - b); const result = sortedIndices.map((originalIndex, sortedPosition) => { const matchGroupIndex = sortedPosition + 1; return match[matchGroupIndex]; }); const year = result[sortedIndices.indexOf(yearIndex)]; const month = result[sortedIndices.indexOf(monthIndex)]; const day = result[sortedIndices.indexOf(dayIndex)]; return [year, month, day]; } //# sourceMappingURL=DateOfBirth.js.map