@codecademy/gamut
72.2.272.2.3-alpha.303f64.0
dist/DatePicker/DatePickerInput/index.js~
dist/DatePicker/DatePickerInput/index.jsModified+89−33
Index: package/dist/DatePicker/DatePickerInput/index.js
===================================================================
--- package/dist/DatePicker/DatePickerInput/index.js
+++ package/dist/DatePicker/DatePickerInput/index.js
@@ -1,7 +1,11 @@
+import _styled from "@emotion/styled/base";
import { MiniCalendarIcon } from '@codecademy/gamut-icons';
+import { css } from '@codecademy/gamut-styles';
import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
import { FlexBox } from '../../Box';
+import { IconButton } from '../../Button';
+import { FormError } from '../../Form/elements/FormError';
import { FormGroup } from '../../Form/elements/FormGroup';
import { isSameDay } from '../DatePickerCalendar/Calendar/utils/dateGrid';
import { handleDateSelectRange } from '../DatePickerCalendar/utils/dateSelect';
import { useDatePicker } from '../DatePickerContext';
@@ -9,9 +13,25 @@
import { DatePickerInputSegment } from './Segment';
import { SegmentLiteral } from './Segment/elements';
import { getDateSegmentsFromDate, normalizeSegmentValues, parseSegmentsToDate } from './Segment/utils';
import { formatDateISO8601DateOnly, getDateFieldOrder, getDateFormatLayout } from './utils';
+import { validateSegments } from './utils/validation';
+
+/* FormError's `absolute` variant takes the message out of layout flow (anchored
+ to FormGroup's position: relative container), so the input never changes height:
+ the range-mode arrow stays aligned and no space is reserved when there's no error. */
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
+const AbsoluteFormError = /*#__PURE__*/_styled(FormError, {
+ target: "ev4y6f30",
+ label: "AbsoluteFormError"
+})(css({
+ // max-content keeps the message on one line rather than wrapping into the
+ // narrow input width.
+ width: 'max-content',
+ // The `absolute` variant anchors at top: calc(100% - 8px), which overlaps the
+ // bottom of the input. Nudge it down below the input with a small gap.
+ mt: 12
+}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9EYXRlUGlja2VyL0RhdGVQaWNrZXJJbnB1dC9pbmRleC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMEMwQiIsImZpbGUiOiIuLi8uLi8uLi9zcmMvRGF0ZVBpY2tlci9EYXRlUGlja2VySW5wdXQvaW5kZXgudHN4Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWluaUNhbGVuZGFySWNvbiB9IGZyb20gJ0Bjb2RlY2FkZW15L2dhbXV0LWljb25zJztcbmltcG9ydCB7IGNzcyB9IGZyb20gJ0Bjb2RlY2FkZW15L2dhbXV0LXN0eWxlcyc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5pbXBvcnQge1xuICB0eXBlIEZvY3VzRXZlbnQsXG4gIGZvcndhcmRSZWYsXG4gIHVzZUNhbGxiYWNrLFxuICB1c2VFZmZlY3QsXG4gIHVzZUlkLFxuICB1c2VNZW1vLFxuICB1c2VSZWYsXG4gIHVzZVN0YXRlLFxufSBmcm9tICdyZWFjdCc7XG5cbmltcG9ydCB7IEZsZXhCb3ggfSBmcm9tICcuLi8uLi9Cb3gnO1xuaW1wb3J0IHsgSWNvbkJ1dHRvbiB9IGZyb20gJy4uLy4uL0J1dHRvbic7XG5pbXBvcnQgeyBGb3JtRXJyb3IgfSBmcm9tICcuLi8uLi9Gb3JtL2VsZW1lbnRzL0Zvcm1FcnJvcic7XG5pbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICcuLi8uLi9Gb3JtL2VsZW1lbnRzL0Zvcm1Hcm91cCc7XG5pbXBvcnQgdHlwZSB7IElucHV0V3JhcHBlclByb3BzIH0gZnJvbSAnLi4vLi4vRm9ybS9pbnB1dHMvSW5wdXQnO1xuaW1wb3J0IHsgaXNTYW1lRGF5IH0gZnJvbSAnLi4vRGF0ZVBpY2tlckNhbGVuZGFyL0NhbGVuZGFyL3V0aWxzL2RhdGVHcmlkJztcbmltcG9ydCB7IGhhbmRsZURhdGVTZWxlY3RSYW5nZSB9IGZyb20gJy4uL0RhdGVQaWNrZXJDYWxlbmRhci91dGlscy9kYXRlU2VsZWN0JztcbmltcG9ydCB7IHVzZURhdGVQaWNrZXIgfSBmcm9tICcuLi9EYXRlUGlja2VyQ29udGV4dCc7XG5pbXBvcnQgeyBTZWdtZW50ZWRTaGVsbCB9IGZyb20gJy4vZWxlbWVudHMnO1xuaW1wb3J0IHsgRGF0ZVBpY2tlcklucHV0U2VnbWVudCB9IGZyb20gJy4vU2VnbWVudCc7XG5pbXBvcnQgeyBTZWdtZW50TGl0ZXJhbCB9IGZyb20gJy4vU2VnbWVudC9lbGVtZW50cyc7XG5pbXBvcnQge1xuICB0eXBlIFNlZ21lbnRWYWx1ZXMsXG4gIGdldERhdGVTZWdtZW50c0Zyb21EYXRlLFxuICBub3JtYWxpemVTZWdtZW50VmFsdWVzLFxuICBwYXJzZVNlZ21lbnRzVG9EYXRlLFxufSBmcm9tICcuL1NlZ21lbnQvdXRpbHMnO1xuaW1wb3J0IHtcbiAgdHlwZSBEYXRlUGFydEtpbmQsXG4gIGZvcm1hdERhdGVJU084NjAxRGF0ZU9ubHksXG4gIGdldERhdGVGaWVsZE9yZGVyLFxuICBnZXREYXRlRm9ybWF0TGF5b3V0LFxufSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7IHZhbGlkYXRlU2VnbWVudHMgfSBmcm9tICcuL3V0aWxzL3ZhbGlkYXRpb24nO1xuXG4vKiBGb3JtRXJyb3IncyBgYWJzb2x1dGVgIHZhcmlhbnQgdGFrZXMgdGhlIG1lc3NhZ2Ugb3V0IG9mIGxheW91dCBmbG93IChhbmNob3JlZFxuICAgdG8gRm9ybUdyb3VwJ3MgcG9zaXRpb246IHJlbGF0aXZlIGNvbnRhaW5lciksIHNvIHRoZSBpbnB1dCBuZXZlciBjaGFuZ2VzIGhlaWdodDpcbiAgIHRoZSByYW5nZS1tb2RlIGFycm93IHN0YXlzIGFsaWduZWQgYW5kIG5vIHNwYWNlIGlzIHJlc2VydmVkIHdoZW4gdGhlcmUncyBubyBlcnJvci4gKi9cbmNvbnN0IEFic29sdXRlRm9ybUVycm9yID0gc3R5bGVkKEZvcm1FcnJvcikoXG4gIGNzcyh7XG4gICAgLy8gbWF4LWNvbnRlbnQga2VlcHMgdGhlIG1lc3NhZ2Ugb24gb25lIGxpbmUgcmF0aGVyIHRoYW4gd3JhcHBpbmcgaW50byB0aGVcbiAgICAvLyBuYXJyb3cgaW5wdXQgd2lkdGguXG4gICAgd2lkdGg6ICdtYXgtY29udGVudCcsXG4gICAgLy8gVGhlIGBhYnNvbHV0ZWAgdmFyaWFudCBhbmNob3JzIGF0IHRvcDogY2FsYygxMDAlIC0gOHB4KSwgd2hpY2ggb3ZlcmxhcHMgdGhlXG4gICAgLy8gYm90dG9tIG9mIHRoZSBpbnB1dC4gTnVkZ2UgaXQgZG93biBiZWxvdyB0aGUgaW5wdXQgd2l0aCBhIHNtYWxsIGdhcC5cbiAgICBtdDogMTIsXG4gIH0pXG4pO1xuXG5leHBvcnQgdHlwZSBEYXRlUGlja2VySW5wdXRQcm9wcyA9IE9taXQ8XG4gIElucHV0V3JhcHBlclByb3BzLFxuICAnY2xhc3NOYW1lJyB8ICd0eXBlJyB8ICdpY29uJyB8ICd2YWx1ZScgfCAnb25DaGFuZ2UnIHwgJ2NvbG9yJyB8ICdlcnJvcidcbj4gJiB7XG4gIC8qKiBJbiByYW5nZSBtb2RlOiB3aGljaCBwYXJ0IG9mIHRoZSByYW5nZSB0aGlzIGlucHV0IGVkaXRzLiBPbWl0IGZvciBzaW5nbGUtZGF0ZSBvciBjb21iaW5lZCBkaXNwbGF5LiAqL1xuICByYW5nZVBhcnQ/OiAnc3RhcnQnIHwgJ2VuZCc7XG4gIC8qKiBFcnJvciBtZXNzYWdlIHRvIGRpc3BsYXkuIFN0cmluZyBmb3Igc3BlY2lmaWMgZXJyb3IsIHVuZGVmaW5lZCBmb3Igbm8gZXJyb3IuICovXG4gIGVycm9yPzogc3RyaW5nO1xufTtcblxuZXhwb3J0IGNvbnN0IERhdGVQaWNrZXJJbnB1dCA9IGZvcndhcmRSZWY8SFRNTERpdkVsZW1lbnQsIERhdGVQaWNrZXJJbnB1dFByb3BzPihcbiAgKFxuICAgIHsgZGlzYWJsZWQsIGVycm9yLCBmb3JtLCBsYWJlbCwgbmFtZSwgcmFuZ2VQYXJ0LCBzaXplID0gJ2Jhc2UnLCAuLi5yZXN0IH0sXG4gICAgcmVmXG4gICkgPT4ge1xuICAgIGNvbnN0IGNvbnRleHQgPSB1c2VEYXRlUGlja2VyKCk7XG5cbiAgICBpZiAoY29udGV4dCA9PT0gbnVsbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnRGF0ZVBpY2tlcklucHV0IG11c3QgYmUgdXNlZCBpbnNpZGUgYSBEYXRlUGlja2VyIChpdCByZWFkcyBzaGFyZWQgc3RhdGUgZnJvbSBjb250ZXh0KS4nXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHtcbiAgICAgIG1vZGUsXG4gICAgICBvcGVuQ2FsZW5kYXIsXG4gICAgICBmb2N1c0NhbGVuZGFyLFxuICAgICAgbG9jYWxlLFxuICAgICAgaXNDYWxlbmRhck9wZW4sXG4gICAgICB0cmFuc2xhdGlvbnMsXG4gICAgICBkaXNhYmxlRGF0ZSxcbiAgICAgIHNldEhhc0Vycm9yLFxuICAgIH0gPSBjb250ZXh0O1xuXG4gICAgY29uc3QgaXNSYW5nZSA9IG1vZGUgPT09ICdyYW5nZSc7XG4gICAgY29uc3QgZW5kRGF0ZSA9IGlzUmFuZ2UgPyBjb250ZXh0LmVuZERhdGUgOiBudWxsO1xuICAgIGNvbnN0IGRhdGUgPSBpc1JhbmdlID8gY29udGV4dC5zdGFydERhdGUgOiBjb250ZXh0LnNlbGVjdGVkRGF0ZTtcblxuICAgIGNvbnN0IGlucHV0SUQgPSB1c2VJZCgpO1xuICAgIGNvbnN0IGlucHV0SWQgPSBgZGF0ZXBpY2tlci1pbnB1dC0ke2lucHV0SUQucmVwbGFjZSgvOi9nLCAnJyl9YDtcblxuICAgIGNvbnN0IHsgbGF5b3V0LCBmaWVsZE9yZGVyIH0gPSB1c2VNZW1vKCgpID0+IHtcbiAgICAgIGNvbnN0IGxheW91dCA9IGdldERhdGVGb3JtYXRMYXlvdXQobG9jYWxlKTtcbiAgICAgIHJldHVybiB7IGxheW91dCwgZmllbGRPcmRlcjogZ2V0RGF0ZUZpZWxkT3JkZXIobGF5b3V0KSB9O1xuICAgIH0sIFtsb2NhbGVdKTtcblxuICAgIGNvbnN0IGRlZmF1bHRMYWJlbCA9ICFpc1JhbmdlXG4gICAgICA/IHRyYW5zbGF0aW9ucy5kYXRlTGFiZWxcbiAgICAgIDogcmFuZ2VQYXJ0ID09PSAnZW5kJ1xuICAgICAgPyB0cmFuc2xhdGlvbnMuZW5kRGF0ZUxhYmVsXG4gICAgICA6IHRyYW5zbGF0aW9ucy5zdGFydERhdGVMYWJlbDtcblxuICAgIGNvbnN0IGJvdW5kRGF0ZSA9IGlzUmFuZ2UgJiYgcmFuZ2VQYXJ0ID09PSAnZW5kJyA/IGVuZERhdGUgOiBkYXRlO1xuICAgIGNvbnN0IHNlZ21lbnRzRnJvbUJvdW5kID0gdXNlTWVtbyhcbiAgICAgICgpID0+IGdldERhdGVTZWdtZW50c0Zyb21EYXRlKGJvdW5kRGF0ZSksXG4gICAgICBbYm91bmREYXRlXVxuICAgICk7XG4gICAgY29uc3QgW3NlZ21lbnRzLCBzZXRTZWdtZW50c10gPSB1c2VTdGF0ZTxTZWdtZW50VmFsdWVzPihzZWdtZW50c0Zyb21Cb3VuZCk7XG4gICAgY29uc3QgW2lucHV0RXJyb3IsIHNldElucHV0RXJyb3JdID0gdXNlU3RhdGU8c3RyaW5nPignJyk7XG5cbiAgICBjb25zdCBwYXJzZWRGb3JIaWRkZW4gPSBwYXJzZVNlZ21lbnRzVG9EYXRlKHNlZ21lbnRzKTtcbiAgICBjb25zdCBoaWRkZW5WYWx1ZSA9IHBhcnNlZEZvckhpZGRlblxuICAgICAgPyBmb3JtYXREYXRlSVNPODYwMURhdGVPbmx5KHBhcnNlZEZvckhpZGRlbilcbiAgICAgIDogJyc7XG5cbiAgICBjb25zdCBpc0lucHV0Rm9jdXNlZFJlZiA9IHVzZVJlZihmYWxzZSk7XG4gICAgY29uc3QgY29udGFpbmVyUmVmID0gdXNlUmVmPEhUTUxEaXZFbGVtZW50IHwgbnVsbD4obnVsbCk7XG4gICAgY29uc3QgYnV0dG9uUmVmID0gdXNlUmVmPEhUTUxCdXR0b25FbGVtZW50PihudWxsKTtcbiAgICBjb25zdCBzZWdtZW50RWxSZWZzID0gdXNlUmVmPFxuICAgICAgUGFydGlhbDxSZWNvcmQ8RGF0ZVBhcnRLaW5kLCBIVE1MU3BhbkVsZW1lbnQgfCBudWxsPj5cbiAgICA+KHt9KTtcblxuICAgIGNvbnN0IGFzc2lnblNlZ21lbnRSZWYgPSB1c2VDYWxsYmFjayhcbiAgICAgIChmaWVsZDogRGF0ZVBhcnRLaW5kLCBlbDogSFRNTFNwYW5FbGVtZW50IHwgbnVsbCkgPT4ge1xuICAgICAgICBzZWdtZW50RWxSZWZzLmN1cnJlbnRbZmllbGRdID0gZWw7XG4gICAgICB9LFxuICAgICAgW3NlZ21lbnRFbFJlZnNdXG4gICAgKTtcblxuICAgIGNvbnN0IG9uU2libGluZ1NlZ21lbnRGb2N1cyA9IHVzZUNhbGxiYWNrKFxuICAgICAgKGZpZWxkOiBEYXRlUGFydEtpbmQpID0+IHtcbiAgICAgICAgc2VnbWVudEVsUmVmcy5jdXJyZW50W2ZpZWxkXT8uZm9jdXMoKTtcbiAgICAgIH0sXG4gICAgICBbc2VnbWVudEVsUmVmc11cbiAgICApO1xuXG4gICAgY29uc3Qgc2hlbGxSZWYgPSB1c2VDYWxsYmFjayhcbiAgICAgIChlbDogSFRNTERpdkVsZW1lbnQgfCBudWxsKSA9PiB7XG4gICAgICAgIGNvbnRhaW5lclJlZi5jdXJyZW50ID0gZWw7XG4gICAgICAgIGlmICh0eXBlb2YgcmVmID09PSAnZnVuY3Rpb24nKSByZWYoZWwpO1xuICAgICAgICBlbHNlIGlmIChyZWYgIT09IG51bGwpIHJlZi5jdXJyZW50ID0gZWw7XG4gICAgICB9LFxuICAgICAgW3JlZl1cbiAgICApO1xuXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgIGlmICghaXNJbnB1dEZvY3VzZWRSZWYuY3VycmVudCkge1xuICAgICAgICBzZXRTZWdtZW50cyhzZWdtZW50c0Zyb21Cb3VuZCk7XG4gICAgICB9XG4gICAgfSwgW3NlZ21lbnRzRnJvbUJvdW5kXSk7XG5cbiAgICBjb25zdCBjb21taXRQYXJzZWREYXRlID0gdXNlQ2FsbGJhY2soXG4gICAgICAocGFyc2VkOiBEYXRlKSA9PiB7XG4gICAgICAgIGlmICghaXNSYW5nZSkge1xuICAgICAgICAgIGNvbnRleHQub25TZWxlY3Rpb24ocGFyc2VkKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNSYW5nZSAmJiByYW5nZVBhcnQpIHtcbiAgICAgICAgICBoYW5kbGVEYXRlU2VsZWN0UmFuZ2Uoe1xuICAgICAgICAgICAgZGF0ZTogcGFyc2VkLFxuICAgICAgICAgICAgYWN0aXZlUmFuZ2VQYXJ0OiByYW5nZVBhcnQsXG4gICAgICAgICAgICBzdGFydERhdGU6IGRhdGUsXG4gICAgICAgICAgICBlbmREYXRlLFxuICAgICAgICAgICAgb25SYW5nZVNlbGVjdGlvbjogY29udGV4dC5vblJhbmdlU2VsZWN0aW9uLFxuICAgICAgICAgICAgZGlzYWJsZURhdGUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBbaXNSYW5nZSwgcmFuZ2VQYXJ0LCBjb250ZXh0LCBlbmREYXRlLCBkYXRlLCBkaXNhYmxlRGF0ZV1cbiAgICApO1xuXG4gICAgY29uc3QgY2xlYXJTZWxlY3Rpb24gPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgICBpZiAoIWlzUmFuZ2UpIHtcbiAgICAgICAgY29udGV4dC5vblNlbGVjdGlvbihudWxsKTtcbiAgICAgIH1cbiAgICAgIGlmIChpc1JhbmdlICYmIHJhbmdlUGFydCkge1xuICAgICAgICBpZiAocmFuZ2VQYXJ0ID09PSAnc3RhcnQnKSBjb250ZXh0Lm9uUmFuZ2VTZWxlY3Rpb24obnVsbCwgZW5kRGF0ZSk7XG4gICAgICAgIGVsc2UgY29udGV4dC5vblJhbmdlU2VsZWN0aW9uKGRhdGUsIG51bGwpO1xuICAgICAgfVxuICAgIH0sIFtpc1JhbmdlLCByYW5nZVBhcnQsIGNvbnRleHQsIGVuZERhdGUsIGRhdGVdKTtcblxuICAgIGNvbnN0IG9uU2VnbWVudENoYW5nZSA9IHVzZUNhbGxiYWNrKFxuICAgICAgKG5leHQ6IFNlZ21lbnRWYWx1ZXMpID0+IHtcbiAgICAgICAgY29uc3QgdmFsaWRhdGlvblJlc3VsdCA9IHZhbGlkYXRlU2VnbWVudHMoXG4gICAgICAgICAgbmV4dCxcbiAgICAgICAgICB0cmFuc2xhdGlvbnMsXG4gICAgICAgICAgZGlzYWJsZURhdGVcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHZhbGlkYXRpb25SZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICAgIHNldElucHV0RXJyb3IoJycpO1xuICAgICAgICAgIHNldEhhc0Vycm9yKGZhbHNlKTtcbiAgICAgICAgICBjb21taXRQYXJzZWREYXRlKHZhbGlkYXRpb25SZXN1bHQuZGF0ZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIW5leHQubW9udGggJiYgIW5leHQuZGF5ICYmICFuZXh0LnllYXIpIHtcbiAgICAgICAgICBzZXRJbnB1dEVycm9yKCcnKTtcbiAgICAgICAgICBzZXRIYXNFcnJvcihmYWxzZSk7XG4gICAgICAgICAgY2xlYXJTZWxlY3Rpb24oKTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWxpZGF0aW9uUmVzdWx0LmVycm9yTWVzc2FnZSkge1xuICAgICAgICAgIHNldElucHV0RXJyb3IodmFsaWRhdGlvblJlc3VsdC5lcnJvck1lc3NhZ2UpO1xuICAgICAgICAgIHNldEhhc0Vycm9yKHRydWUpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgW2NsZWFyU2VsZWN0aW9uLCBjb21taXRQYXJzZWREYXRlLCB0cmFuc2xhdGlvbnMsIGRpc2FibGVEYXRlLCBzZXRIYXNFcnJvcl1cbiAgICApO1xuXG4gICAgY29uc3Qgb25Db250YWluZXJCbHVyID0gdXNlQ2FsbGJhY2soXG4gICAgICAoZTogRm9jdXNFdmVudDxIVE1MRGl2RWxlbWVudD4pID0+IHtcbiAgICAgICAgaWYgKGNvbnRhaW5lclJlZi5jdXJyZW50Py5jb250YWlucyhlLnJlbGF0ZWRUYXJnZXQgYXMgTm9kZSkpIHJldHVybjtcbiAgICAgICAgaXNJbnB1dEZvY3VzZWRSZWYuY3VycmVudCA9IGZhbHNlO1xuICAgICAgICBzZXRTZWdtZW50cygocHJldikgPT4ge1xuICAgICAgICAgIC8vIENoZWNrIGlmIGFsbCBzZWdtZW50cyBhcmUgZW1wdHlcbiAgICAgICAgICBpZiAoIXByZXYubW9udGggJiYgIXByZXYuZGF5ICYmICFwcmV2LnllYXIpIHtcbiAgICAgICAgICAgIHNldElucHV0RXJyb3IoJycpO1xuICAgICAgICAgICAgc2V0SGFzRXJyb3IoZmFsc2UpO1xuICAgICAgICAgICAgcXVldWVNaWNyb3Rhc2soKCkgPT4ge1xuICAgICAgICAgICAgICBjbGVhclNlbGVjdGlvbigpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gZ2V0RGF0ZVNlZ21lbnRzRnJvbURhdGUobnVsbCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gVmFsaWRhdGUgcmF3IGlucHV0ICh3aXRob3V0IG5vcm1hbGl6aW5nL2NsYW1waW5nKVxuICAgICAgICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSB2YWxpZGF0ZVNlZ21lbnRzKFxuICAgICAgICAgICAgcHJldixcbiAgICAgICAgICAgIHRyYW5zbGF0aW9ucyxcbiAgICAgICAgICAgIGRpc2FibGVEYXRlXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmICh2YWxpZGF0aW9uUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgICAgIC8vIFZhbGlkIGNvbXBsZXRlIGRhdGUgLSBub3JtYWxpemUgYW5kIGNvbW1pdFxuICAgICAgICAgICAgc2V0SW5wdXRFcnJvcignJyk7XG4gICAgICAgICAgICBzZXRIYXNFcnJvcihmYWxzZSk7XG4gICAgICAgICAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplU2VnbWVudFZhbHVlcyhwcmV2KTtcbiAgICAgICAgICAgIGNvbnN0IHNhbWVBc0JvdW5kID0gaXNTYW1lRGF5KHZhbGlkYXRpb25SZXN1bHQuZGF0ZSwgYm91bmREYXRlKTtcbiAgICAgICAgICAgIGlmIChpc0NhbGVuZGFyT3BlbiAmJiAhc2FtZUFzQm91bmQpIHtcbiAgICAgICAgICAgICAgcXVldWVNaWNyb3Rhc2soKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbW1pdFBhcnNlZERhdGUodmFsaWRhdGlvblJlc3VsdC5kYXRlKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbm9ybWFsaXplZDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBJbmNvbXBsZXRlIGVudHJ5IG9uIGJsdXIgLSBzaG93IHRoZSBpbmNvbXBsZXRlLWRhdGUgZXJyb3JcbiAgICAgICAgICBpZiAoIXZhbGlkYXRpb25SZXN1bHQuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgICAgICBzZXRJbnB1dEVycm9yKHRyYW5zbGF0aW9ucy5pbnZhbGlkRGF0ZUluY29tcGxldGUpO1xuICAgICAgICAgICAgc2V0SGFzRXJyb3IodHJ1ZSk7XG4gICAgICAgICAgICByZXR1cm4gcHJldjsgLy8gS2VlcCBpbmNvbXBsZXRlIGlucHV0IHZpc2libGUgc28gdXNlciBjYW4gY29ycmVjdCBpdFxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEludmFsaWQgY29tcGxldGUgZW50cnkgLSBzaG93IGVycm9yIGFuZCBrZWVwIGludmFsaWQgaW5wdXQgdmlzaWJsZVxuICAgICAgICAgIHNldElucHV0RXJyb3IodmFsaWRhdGlvblJlc3VsdC5lcnJvck1lc3NhZ2UpO1xuICAgICAgICAgIHNldEhhc0Vycm9yKHRydWUpO1xuICAgICAgICAgIHJldHVybiBwcmV2O1xuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBbXG4gICAgICAgIGNvbnRhaW5lclJlZixcbiAgICAgICAgYm91bmREYXRlLFxuICAgICAgICBzZWdtZW50c0Zyb21Cb3VuZCxcbiAgICAgICAgY2xlYXJTZWxlY3Rpb24sXG4gICAgICAgIGNvbW1pdFBhcnNlZERhdGUsXG4gICAgICAgIGlzQ2FsZW5kYXJPcGVuLFxuICAgICAgICB0cmFuc2xhdGlvbnMsXG4gICAgICAgIGRpc2FibGVEYXRlLFxuICAgICAgICBzZXRIYXNFcnJvcixcbiAgICAgIF1cbiAgICApO1xuXG4gICAgY29uc3Qgc2V0QWN0aXZlUmFuZ2VQYXJ0Rm9yRmllbGQgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgICBpZiAoaXNSYW5nZSAmJiByYW5nZVBhcnQpIGNvbnRleHQuc2V0QWN0aXZlUmFuZ2VQYXJ0KHJhbmdlUGFydCk7XG4gICAgfSwgW2lzUmFuZ2UsIHJhbmdlUGFydCwgY29udGV4dF0pO1xuXG4gICAgY29uc3Qgb25TZWdtZW50Rm9jdXMgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgICBpc0lucHV0Rm9jdXNlZFJlZi5jdXJyZW50ID0gdHJ1ZTtcbiAgICAgIHNldEFjdGl2ZVJhbmdlUGFydEZvckZpZWxkKCk7XG4gICAgfSwgW2lzSW5wdXRGb2N1c2VkUmVmLCBzZXRBY3RpdmVSYW5nZVBhcnRGb3JGaWVsZF0pO1xuXG4gICAgY29uc3Qgb25TaGVsbEZvY3VzID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgICAgc2V0QWN0aXZlUmFuZ2VQYXJ0Rm9yRmllbGQoKTtcbiAgICB9LCBbc2V0QWN0aXZlUmFuZ2VQYXJ0Rm9yRmllbGRdKTtcblxuICAgIGNvbnN0IG9uU2hlbGxDbGljayA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICAgIGlmIChkaXNhYmxlZCkgcmV0dXJuO1xuICAgICAgc2V0QWN0aXZlUmFuZ2VQYXJ0Rm9yRmllbGQoKTtcbiAgICAgIG9wZW5DYWxlbmRhcigpO1xuICAgIH0sIFtkaXNhYmxlZCwgc2V0QWN0aXZlUmFuZ2VQYXJ0Rm9yRmllbGQsIG9wZW5DYWxlbmRhcl0pO1xuXG4gICAgY29uc3Qgb25TZWdtZW50QWx0QXJyb3dEb3duID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgICAgaWYgKCFpc0NhbGVuZGFyT3Blbikgb3BlbkNhbGVuZGFyKCk7XG4gICAgICBmb2N1c0NhbGVuZGFyKCk7XG4gICAgfSwgW2lzQ2FsZW5kYXJPcGVuLCBvcGVuQ2FsZW5kYXIsIGZvY3VzQ2FsZW5kYXJdKTtcblxuICAgIHJldHVybiAoXG4gICAgICA8Rm9ybUdyb3VwXG4gICAgICAgIGlkPXtpbnB1dElkfVxuICAgICAgICBpc1NvbG9GaWVsZFxuICAgICAgICBsYWJlbD17bGFiZWwgPz8gZGVmYXVsdExhYmVsfVxuICAgICAgICBtYj17MH1cbiAgICAgICAgcGI9ezB9XG4gICAgICAgIHNwYWNpbmc9XCJ0aWdodFwiXG4gICAgICAgIHdpZHRoPVwiZml0LWNvbnRlbnRcIlxuICAgICAgPlxuICAgICAgICA8U2VnbWVudGVkU2hlbGxcbiAgICAgICAgICBhcmlhLWludmFsaWQ9eyEhaW5wdXRFcnJvcn1cbiAgICAgICAgICBhcmlhLWxhYmVsbGVkYnk9e2lucHV0SWR9XG4gICAgICAgICAgaW5wdXRTaXplPXtzaXplfVxuICAgICAgICAgIHJlZj17c2hlbGxSZWZ9XG4gICAgICAgICAgcm9sZT1cImdyb3VwXCJcbiAgICAgICAgICB2YXJpYW50PXtpbnB1dEVycm9yID8gJ2Vycm9yJyA6ICdkZWZhdWx0J31cbiAgICAgICAgICB3aWR0aD1cIjExM3B4XCJcbiAgICAgICAgICBvbkJsdXI9e29uQ29udGFpbmVyQmx1cn1cbiAgICAgICAgICBvbkNsaWNrPXtvblNoZWxsQ2xpY2t9XG4gICAgICAgICAgb25Gb2N1cz17b25TaGVsbEZvY3VzfVxuICAgICAgICAgIHsuLi5yZXN0fVxuICAgICAgICA+XG4gICAgICAgICAgPEZsZXhCb3ggYWxpZ25JdGVtcz1cImNlbnRlclwiIGp1c3RpZnlDb250ZW50PVwiY2VudGVyXCI+XG4gICAgICAgICAgICB7bGF5b3V0Lm1hcCgoaXRlbSwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgICAgaWYgKGl0ZW0ua2luZCA9PT0gJ2xpdGVyYWwnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgIDxTZWdtZW50TGl0ZXJhbFxuICAgICAgICAgICAgICAgICAgICBhcmlhLWhpZGRlblxuICAgICAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3Qvbm8tYXJyYXktaW5kZXgta2V5XG4gICAgICAgICAgICAgICAgICAgIGtleT17YGxpdGVyYWwtJHtpdGVtLnRleHR9LSR7aW5kZXh9YH1cbiAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAge2Ake2l0ZW0udGV4dH1gfVxuICAgICAgICAgICAgICAgICAgPC9TZWdtZW50TGl0ZXJhbD5cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGlkeCA9IGZpZWxkT3JkZXIuaW5kZXhPZihpdGVtLmZpZWxkKTtcbiAgICAgICAgICAgICAgY29uc3QgcHJldkZpZWxkID0gaWR4ID4gMCA/IGZpZWxkT3JkZXJbaWR4IC0gMV0gOiBudWxsO1xuICAgICAgICAgICAgICBjb25zdCBuZXh0RmllbGQgPVxuICAgICAgICAgICAgICAgIGlkeCA8IGZpZWxkT3JkZXIubGVuZ3RoIC0gMSA/IGZpZWxkT3JkZXJbaWR4ICsgMV0gOiBudWxsO1xuXG4gICAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgPERhdGVQaWNrZXJJbnB1dFNlZ21lbnRcbiAgICAgICAgICAgICAgICAgIGFwcGx5U2VnbWVudHM9e29uU2VnbWVudENoYW5nZX1cbiAgICAgICAgICAgICAgICAgIGFzc2lnblNlZ21lbnRSZWY9e2Fzc2lnblNlZ21lbnRSZWZ9XG4gICAgICAgICAgICAgICAgICBkaXNhYmxlZD17ISFkaXNhYmxlZH1cbiAgICAgICAgICAgICAgICAgIGVycm9yPXshIWlucHV0RXJyb3J9XG4gICAgICAgICAgICAgICAgICBmaWVsZD17aXRlbS5maWVsZH1cbiAgICAgICAgICAgICAgICAgIGtleT17aXRlbS5maWVsZH1cbiAgICAgICAgICAgICAgICAgIG5leHRGaWVsZD17bmV4dEZpZWxkfVxuICAgICAgICAgICAgICAgICAgcHJldkZpZWxkPXtwcmV2RmllbGR9XG4gICAgICAgICAgICAgICAgICBzZWdtZW50cz17c2VnbWVudHN9XG4gICAgICAgICAgICAgICAgICBzZXRTZWdtZW50cz17c2V0U2VnbWVudHN9XG4gICAgICAgICAgICAgICAgICBvbkFsdEFycm93RG93bj17b25TZWdtZW50QWx0QXJyb3dEb3dufVxuICAgICAgICAgICAgICAgICAgb25Gb2N1cz17b25TZWdtZW50Rm9jdXN9XG4gICAgICAgICAgICAgICAgICBvblNpYmxpbmdGb2N1cz17b25TaWJsaW5nU2VnbWVudEZvY3VzfVxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KX1cbiAgICAgICAgICA8L0ZsZXhCb3g+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBhcmlhLWhpZGRlblxuICAgICAgICAgICAgZm9ybT17Zm9ybX1cbiAgICAgICAgICAgIG5hbWU9e25hbWUgPz8gJ2RhdGVQaWNrZXJJbnB1dCd9XG4gICAgICAgICAgICB0YWJJbmRleD17LTF9XG4gICAgICAgICAgICB0eXBlPVwiaGlkZGVuXCJcbiAgICAgICAgICAgIHZhbHVlPXtoaWRkZW5WYWx1ZX1cbiAgICAgICAgICAvPlxuICAgICAgICAgIDxJY29uQnV0dG9uXG4gICAgICAgICAgICBteD17NH1cbiAgICAgICAgICAgIGljb249e01pbmlDYWxlbmRhckljb259XG4gICAgICAgICAgICBzaXplPVwic21hbGxcIlxuICAgICAgICAgICAgdGlwPXt0cmFuc2xhdGlvbnMub3BlbkNhbGVuZGFyTGFiZWx9XG4gICAgICAgICAgICByZWY9e2J1dHRvblJlZn1cbiAgICAgICAgICAgIG9uQ2xpY2s9eygpID0+IGJ1dHRvblJlZi5jdXJyZW50Py5ibHVyKCl9XG4gICAgICAgICAgLz5cbiAgICAgICAgPC9TZWdtZW50ZWRTaGVsbD5cbiAgICAgICAge2lucHV0RXJyb3IgJiYgKFxuICAgICAgICAgIDxBYnNvbHV0ZUZvcm1FcnJvciBhcmlhLWxpdmU9XCJwb2xpdGVcIiByb2xlPVwiYWxlcnRcIiB2YXJpYW50PVwiYWJzb2x1dGVcIj5cbiAgICAgICAgICAgIHtpbnB1dEVycm9yfVxuICAgICAgICAgIDwvQWJzb2x1dGVGb3JtRXJyb3I+XG4gICAgICAgICl9XG4gICAgICA8L0Zvcm1Hcm91cD5cbiAgICApO1xuICB9XG4pO1xuIl19 */");
export const DatePickerInput = /*#__PURE__*/forwardRef(({
disabled,
error,
form,
@@ -31,9 +51,10 @@
focusCalendar,
locale,
isCalendarOpen,
translations,
- disableDate
+ disableDate,
+ setHasError
} = context;
const isRange = mode === 'range';
const endDate = isRange ? context.endDate : null;
const date = isRange ? context.startDate : context.selectedDate;
@@ -52,12 +73,14 @@
const defaultLabel = !isRange ? translations.dateLabel : rangePart === 'end' ? translations.endDateLabel : translations.startDateLabel;
const boundDate = isRange && rangePart === 'end' ? endDate : date;
const segmentsFromBound = useMemo(() => getDateSegmentsFromDate(boundDate), [boundDate]);
const [segments, setSegments] = useState(segmentsFromBound);
+ const [inputError, setInputError] = useState('');
const parsedForHidden = parseSegmentsToDate(segments);
const hiddenValue = parsedForHidden ? formatDateISO8601DateOnly(parsedForHidden) : '';
const isInputFocusedRef = useRef(false);
const containerRef = useRef(null);
+ const buttonRef = useRef(null);
const segmentElRefs = useRef({});
const assignSegmentRef = useCallback((field, el) => {
segmentElRefs.current[field] = el;
}, [segmentElRefs]);
@@ -96,35 +119,65 @@
if (rangePart === 'start') context.onRangeSelection(null, endDate);else context.onRangeSelection(date, null);
}
}, [isRange, rangePart, context, endDate, date]);
const onSegmentChange = useCallback(next => {
- const parsed = parseSegmentsToDate(next);
- if (parsed) commitParsedDate(parsed);else if (!next.month && !next.day && !next.year) clearSelection();
- }, [clearSelection, commitParsedDate]);
+ const validationResult = validateSegments(next, translations, disableDate);
+ if (validationResult.isValid) {
+ setInputError('');
+ setHasError(false);
+ commitParsedDate(validationResult.date);
+ } else if (!next.month && !next.day && !next.year) {
+ setInputError('');
+ setHasError(false);
+ clearSelection();
+ } else if (validationResult.errorMessage) {
+ setInputError(validationResult.errorMessage);
+ setHasError(true);
+ }
+ }, [clearSelection, commitParsedDate, translations, disableDate, setHasError]);
const onContainerBlur = useCallback(e => {
if (containerRef.current?.contains(e.relatedTarget)) return;
isInputFocusedRef.current = false;
setSegments(prev => {
- const normalized = normalizeSegmentValues(prev);
- const parsed = parseSegmentsToDate(normalized);
- if (parsed) {
- const sameAsBound = isSameDay(parsed, boundDate);
+ // Check if all segments are empty
+ if (!prev.month && !prev.day && !prev.year) {
+ setInputError('');
+ setHasError(false);
+ queueMicrotask(() => {
+ clearSelection();
+ });
+ return getDateSegmentsFromDate(null);
+ }
+
+ // Validate raw input (without normalizing/clamping)
+ const validationResult = validateSegments(prev, translations, disableDate);
+ if (validationResult.isValid) {
+ // Valid complete date - normalize and commit
+ setInputError('');
+ setHasError(false);
+ const normalized = normalizeSegmentValues(prev);
+ const sameAsBound = isSameDay(validationResult.date, boundDate);
if (isCalendarOpen && !sameAsBound) {
queueMicrotask(() => {
- commitParsedDate(parsed);
+ commitParsedDate(validationResult.date);
});
}
return normalized;
}
- if (!normalized.month && !normalized.day && !normalized.year) {
- queueMicrotask(() => {
- clearSelection();
- });
- return getDateSegmentsFromDate(null);
+
+ // Incomplete entry on blur - show the incomplete-date error
+ if (!validationResult.errorMessage) {
+ setInputError(translations.invalidDateIncomplete);
+ setHasError(true);
+ return prev; // Keep incomplete input visible so user can correct it
}
- return segmentsFromBound;
+
+ // Invalid complete entry - show error and keep invalid input visible
+ setInputError(validationResult.errorMessage);
+ setHasError(true);
+ return prev;
});
- }, [containerRef, boundDate, segmentsFromBound, clearSelection, commitParsedDate, isCalendarOpen]);
+ }, [containerRef, boundDate, segmentsFromBound, clearSelection, commitParsedDate, isCalendarOpen, translations, disableDate, setHasError]);
const setActiveRangePartForField = useCallback(() => {
if (isRange && rangePart) context.setActiveRangePart(rangePart);
}, [isRange, rangePart, context]);
const onSegmentFocus = useCallback(() => {
@@ -142,22 +195,23 @@
const onSegmentAltArrowDown = useCallback(() => {
if (!isCalendarOpen) openCalendar();
focusCalendar();
}, [isCalendarOpen, openCalendar, focusCalendar]);
- return /*#__PURE__*/_jsx(FormGroup, {
- htmlFor: inputId,
+ return /*#__PURE__*/_jsxs(FormGroup, {
+ id: inputId,
isSoloField: true,
label: label ?? defaultLabel,
mb: 0,
pb: 0,
spacing: "tight",
width: "fit-content",
- children: /*#__PURE__*/_jsxs(SegmentedShell, {
- id: inputId,
+ children: [/*#__PURE__*/_jsxs(SegmentedShell, {
+ "aria-invalid": !!inputError,
+ "aria-labelledby": inputId,
inputSize: size,
ref: shellRef,
role: "group",
- variant: error ? 'error' : 'default',
+ variant: inputError ? 'error' : 'default',
width: "113px",
onBlur: onContainerBlur,
onClick: onShellClick,
onFocus: onShellFocus,
@@ -180,9 +234,9 @@
return /*#__PURE__*/_jsx(DatePickerInputSegment, {
applySegments: onSegmentChange,
assignSegmentRef: assignSegmentRef,
disabled: !!disabled,
- error: !!error,
+ error: !!inputError,
field: item.field,
nextField: nextField,
prevField: prevField,
segments: segments,
@@ -198,18 +252,20 @@
name: name ?? 'datePickerInput',
tabIndex: -1,
type: "hidden",
value: hiddenValue
- }), /*#__PURE__*/_jsx(FlexBox, {
- alignItems: "center",
- justifyContent: "center",
- pl: 16,
- pr: 8,
- role: "presentation",
- children: /*#__PURE__*/_jsx(MiniCalendarIcon, {
- "aria-hidden": true,
- size: 16
- })
+ }), /*#__PURE__*/_jsx(IconButton, {
+ mx: 4,
+ icon: MiniCalendarIcon,
+ size: "small",
+ tip: translations.openCalendarLabel,
+ ref: buttonRef,
+ onClick: () => buttonRef.current?.blur()
})]
- })
+ }), inputError && /*#__PURE__*/_jsx(AbsoluteFormError, {
+ "aria-live": "polite",
+ role: "alert",
+ variant: "absolute",
+ children: inputError
+ })]
});
});
\ No newline at end of file