@allxsmith/bestax-bulma 5.27.0 → 5.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/columns/Column.js +48 -0
- package/dist/esm/columns/Column.js.map +1 -0
- package/dist/esm/columns/Columns.js +53 -0
- package/dist/esm/columns/Columns.js.map +1 -0
- package/dist/esm/components/Avatar.js +299 -0
- package/dist/esm/components/Avatar.js.map +1 -0
- package/dist/esm/components/Avatars.js +81 -0
- package/dist/esm/components/Avatars.js.map +1 -0
- package/dist/esm/components/Badge.js +105 -0
- package/dist/esm/components/Badge.js.map +1 -0
- package/dist/esm/components/Breadcrumb.js +36 -0
- package/dist/esm/components/Breadcrumb.js.map +1 -0
- package/dist/esm/components/Card.js +252 -0
- package/dist/esm/components/Card.js.map +1 -0
- package/dist/esm/components/Carousel.js +351 -0
- package/dist/esm/components/Carousel.js.map +1 -0
- package/dist/esm/components/Collapse.js +193 -0
- package/dist/esm/components/Collapse.js.map +1 -0
- package/dist/esm/components/Collapses.js +99 -0
- package/dist/esm/components/Collapses.js.map +1 -0
- package/dist/esm/components/Dialog.js +230 -0
- package/dist/esm/components/Dialog.js.map +1 -0
- package/dist/esm/components/Dropdown.js +362 -0
- package/dist/esm/components/Dropdown.js.map +1 -0
- package/dist/esm/components/Loading.js +87 -0
- package/dist/esm/components/Loading.js.map +1 -0
- package/dist/esm/components/Menu.js +117 -0
- package/dist/esm/components/Menu.js.map +1 -0
- package/dist/esm/components/Message.js +56 -0
- package/dist/esm/components/Message.js.map +1 -0
- package/dist/esm/components/Modal.js +354 -0
- package/dist/esm/components/Modal.js.map +1 -0
- package/dist/esm/components/Navbar.js +287 -0
- package/dist/esm/components/Navbar.js.map +1 -0
- package/dist/esm/components/Pagination.js +191 -0
- package/dist/esm/components/Pagination.js.map +1 -0
- package/dist/esm/components/Panel.js +100 -0
- package/dist/esm/components/Panel.js.map +1 -0
- package/dist/esm/components/Popover.js +298 -0
- package/dist/esm/components/Popover.js.map +1 -0
- package/dist/esm/components/Reveal.js +157 -0
- package/dist/esm/components/Reveal.js.map +1 -0
- package/dist/esm/components/Sidebar.js +209 -0
- package/dist/esm/components/Sidebar.js.map +1 -0
- package/dist/esm/components/Steps.js +128 -0
- package/dist/esm/components/Steps.js.map +1 -0
- package/dist/esm/components/Tabs.js +335 -0
- package/dist/esm/components/Tabs.js.map +1 -0
- package/dist/esm/components/Toast.js +322 -0
- package/dist/esm/components/Toast.js.map +1 -0
- package/dist/esm/components/Tooltip.js +202 -0
- package/dist/esm/components/Tooltip.js.map +1 -0
- package/dist/esm/components/collapsesContext.js +12 -0
- package/dist/esm/components/collapsesContext.js.map +1 -0
- package/dist/esm/elements/Block.js +29 -0
- package/dist/esm/elements/Block.js.map +1 -0
- package/dist/esm/elements/Box.js +32 -0
- package/dist/esm/elements/Box.js.map +1 -0
- package/dist/esm/elements/Button.js +139 -0
- package/dist/esm/elements/Button.js.map +1 -0
- package/dist/esm/elements/Buttons.js +42 -0
- package/dist/esm/elements/Buttons.js.map +1 -0
- package/dist/esm/elements/Code.js +25 -0
- package/dist/esm/elements/Code.js.map +1 -0
- package/dist/esm/elements/Content.js +33 -0
- package/dist/esm/elements/Content.js.map +1 -0
- package/dist/esm/elements/Delete.js +35 -0
- package/dist/esm/elements/Delete.js.map +1 -0
- package/dist/esm/elements/Divider.js +27 -0
- package/dist/esm/elements/Divider.js.map +1 -0
- package/dist/esm/elements/Emphasis.js +25 -0
- package/dist/esm/elements/Emphasis.js.map +1 -0
- package/dist/esm/elements/Figure.js +58 -0
- package/dist/esm/elements/Figure.js.map +1 -0
- package/dist/esm/elements/Icon.js +256 -0
- package/dist/esm/elements/Icon.js.map +1 -0
- package/dist/esm/elements/IconText.js +36 -0
- package/dist/esm/elements/IconText.js.map +1 -0
- package/dist/esm/elements/Image.js +46 -0
- package/dist/esm/elements/Image.js.map +1 -0
- package/dist/esm/elements/Link.js +36 -0
- package/dist/esm/elements/Link.js.map +1 -0
- package/dist/esm/elements/LinkButton.js +37 -0
- package/dist/esm/elements/LinkButton.js.map +1 -0
- package/dist/esm/elements/ListItem.js +28 -0
- package/dist/esm/elements/ListItem.js.map +1 -0
- package/dist/esm/elements/Loader.js +37 -0
- package/dist/esm/elements/Loader.js.map +1 -0
- package/dist/esm/elements/Notification.js +316 -0
- package/dist/esm/elements/Notification.js.map +1 -0
- package/dist/esm/elements/OrderedList.js +31 -0
- package/dist/esm/elements/OrderedList.js.map +1 -0
- package/dist/esm/elements/Paragraph.js +28 -0
- package/dist/esm/elements/Paragraph.js.map +1 -0
- package/dist/esm/elements/Pre.js +25 -0
- package/dist/esm/elements/Pre.js.map +1 -0
- package/dist/esm/elements/Progress.js +33 -0
- package/dist/esm/elements/Progress.js.map +1 -0
- package/dist/esm/elements/Skeleton.js +30 -0
- package/dist/esm/elements/Skeleton.js.map +1 -0
- package/dist/esm/elements/Span.js +28 -0
- package/dist/esm/elements/Span.js.map +1 -0
- package/dist/esm/elements/Strong.js +25 -0
- package/dist/esm/elements/Strong.js.map +1 -0
- package/dist/esm/elements/SubTitle.js +51 -0
- package/dist/esm/elements/SubTitle.js.map +1 -0
- package/dist/esm/elements/Table.js +51 -0
- package/dist/esm/elements/Table.js.map +1 -0
- package/dist/esm/elements/Tag.js +49 -0
- package/dist/esm/elements/Tag.js.map +1 -0
- package/dist/esm/elements/Tags.js +34 -0
- package/dist/esm/elements/Tags.js.map +1 -0
- package/dist/esm/elements/Tbody.js +26 -0
- package/dist/esm/elements/Tbody.js.map +1 -0
- package/dist/esm/elements/Td.js +61 -0
- package/dist/esm/elements/Td.js.map +1 -0
- package/dist/esm/elements/Tfoot.js +26 -0
- package/dist/esm/elements/Tfoot.js.map +1 -0
- package/dist/esm/elements/Th.js +34 -0
- package/dist/esm/elements/Th.js.map +1 -0
- package/dist/esm/elements/Thead.js +26 -0
- package/dist/esm/elements/Thead.js.map +1 -0
- package/dist/esm/elements/Title.js +44 -0
- package/dist/esm/elements/Title.js.map +1 -0
- package/dist/esm/elements/Tr.js +31 -0
- package/dist/esm/elements/Tr.js.map +1 -0
- package/dist/esm/elements/UnorderedList.js +31 -0
- package/dist/esm/elements/UnorderedList.js.map +1 -0
- package/dist/esm/elements/iconProps.js +49 -0
- package/dist/esm/elements/iconProps.js.map +1 -0
- package/dist/esm/form/Autocomplete.js +279 -0
- package/dist/esm/form/Autocomplete.js.map +1 -0
- package/dist/esm/form/Checkbox.js +111 -0
- package/dist/esm/form/Checkbox.js.map +1 -0
- package/dist/esm/form/Checkboxes.js +89 -0
- package/dist/esm/form/Checkboxes.js.map +1 -0
- package/dist/esm/form/Control.js +79 -0
- package/dist/esm/form/Control.js.map +1 -0
- package/dist/esm/form/DateInput.js +87 -0
- package/dist/esm/form/DateInput.js.map +1 -0
- package/dist/esm/form/DateInputBase.js +263 -0
- package/dist/esm/form/DateInputBase.js.map +1 -0
- package/dist/esm/form/DateRangeInput.js +76 -0
- package/dist/esm/form/DateRangeInput.js.map +1 -0
- package/dist/esm/form/DateRangeInputBase.js +301 -0
- package/dist/esm/form/DateRangeInputBase.js.map +1 -0
- package/dist/esm/form/DateTimeInput.js +87 -0
- package/dist/esm/form/DateTimeInput.js.map +1 -0
- package/dist/esm/form/DateTimeInputBase.js +333 -0
- package/dist/esm/form/DateTimeInputBase.js.map +1 -0
- package/dist/esm/form/Field.js +153 -0
- package/dist/esm/form/Field.js.map +1 -0
- package/dist/esm/form/File.js +109 -0
- package/dist/esm/form/File.js.map +1 -0
- package/dist/esm/form/FormContext.js +170 -0
- package/dist/esm/form/FormContext.js.map +1 -0
- package/dist/esm/form/Input.js +88 -0
- package/dist/esm/form/Input.js.map +1 -0
- package/dist/esm/form/InputBase.js +40 -0
- package/dist/esm/form/InputBase.js.map +1 -0
- package/dist/esm/form/Numberinput.js +199 -0
- package/dist/esm/form/Numberinput.js.map +1 -0
- package/dist/esm/form/Radio.js +108 -0
- package/dist/esm/form/Radio.js.map +1 -0
- package/dist/esm/form/Radios.js +91 -0
- package/dist/esm/form/Radios.js.map +1 -0
- package/dist/esm/form/Rate.js +279 -0
- package/dist/esm/form/Rate.js.map +1 -0
- package/dist/esm/form/Select.js +81 -0
- package/dist/esm/form/Select.js.map +1 -0
- package/dist/esm/form/SelectBase.js +54 -0
- package/dist/esm/form/SelectBase.js.map +1 -0
- package/dist/esm/form/Slider.js +459 -0
- package/dist/esm/form/Slider.js.map +1 -0
- package/dist/esm/form/Switch.js +96 -0
- package/dist/esm/form/Switch.js.map +1 -0
- package/dist/esm/form/Taginput.js +352 -0
- package/dist/esm/form/Taginput.js.map +1 -0
- package/dist/esm/form/TextArea.js +77 -0
- package/dist/esm/form/TextArea.js.map +1 -0
- package/dist/esm/form/TextAreaBase.js +45 -0
- package/dist/esm/form/TextAreaBase.js.map +1 -0
- package/dist/esm/form/TimeInput.js +83 -0
- package/dist/esm/form/TimeInput.js.map +1 -0
- package/dist/esm/form/TimeInputBase.js +246 -0
- package/dist/esm/form/TimeInputBase.js.map +1 -0
- package/dist/esm/form/_pickerInternals/Calendar.js +760 -0
- package/dist/esm/form/_pickerInternals/Calendar.js.map +1 -0
- package/dist/esm/form/_pickerInternals/PickerPopover.js +95 -0
- package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -0
- package/dist/esm/form/_pickerInternals/TimeWheels.js +721 -0
- package/dist/esm/form/_pickerInternals/TimeWheels.js.map +1 -0
- package/dist/esm/form/_pickerInternals/audioTick.js +109 -0
- package/dist/esm/form/_pickerInternals/audioTick.js.map +1 -0
- package/dist/esm/form/_pickerInternals/dateUtils.js +267 -0
- package/dist/esm/form/_pickerInternals/dateUtils.js.map +1 -0
- package/dist/esm/form/_pickerInternals/formatters.js +322 -0
- package/dist/esm/form/_pickerInternals/formatters.js.map +1 -0
- package/dist/esm/form/_pickerInternals/haptics.js +38 -0
- package/dist/esm/form/_pickerInternals/haptics.js.map +1 -0
- package/dist/esm/form/_pickerInternals/nativeInputSupport.js +25 -0
- package/dist/esm/form/_pickerInternals/nativeInputSupport.js.map +1 -0
- package/dist/esm/form/_pickerInternals/pickerTypes.js +50 -0
- package/dist/esm/form/_pickerInternals/pickerTypes.js.map +1 -0
- package/dist/esm/form/_pickerInternals/segmentMap.js +315 -0
- package/dist/esm/form/_pickerInternals/segmentMap.js.map +1 -0
- package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js +49 -0
- package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js.map +1 -0
- package/dist/esm/form/_pickerInternals/useSegmentedEntry.js +427 -0
- package/dist/esm/form/_pickerInternals/useSegmentedEntry.js.map +1 -0
- package/dist/esm/form/controlLoading.js +18 -0
- package/dist/esm/form/controlLoading.js.map +1 -0
- package/dist/esm/form/useAutoLabelId.js +54 -0
- package/dist/esm/form/useAutoLabelId.js.map +1 -0
- package/dist/esm/grid/Cell.js +35 -0
- package/dist/esm/grid/Cell.js.map +1 -0
- package/dist/esm/grid/Grid.js +51 -0
- package/dist/esm/grid/Grid.js.map +1 -0
- package/dist/esm/helpers/ClientOnly.js +33 -0
- package/dist/esm/helpers/ClientOnly.js.map +1 -0
- package/dist/esm/helpers/Config.js +60 -0
- package/dist/esm/helpers/Config.js.map +1 -0
- package/dist/esm/helpers/Theme.js +947 -0
- package/dist/esm/helpers/Theme.js.map +1 -0
- package/dist/esm/helpers/anchorAttrs.js +72 -0
- package/dist/esm/helpers/anchorAttrs.js.map +1 -0
- package/dist/esm/helpers/bulmaClassHelpers.js +415 -0
- package/dist/esm/helpers/bulmaClassHelpers.js.map +1 -0
- package/dist/esm/helpers/buttonType.js +24 -0
- package/dist/esm/helpers/buttonType.js.map +1 -0
- package/dist/esm/helpers/classNames.js +137 -0
- package/dist/esm/helpers/classNames.js.map +1 -0
- package/dist/esm/helpers/colorDeprecations.js +50 -0
- package/dist/esm/helpers/colorDeprecations.js.map +1 -0
- package/dist/esm/helpers/devWarnings.js +27 -0
- package/dist/esm/helpers/devWarnings.js.map +1 -0
- package/dist/esm/helpers/inertProps.js +27 -0
- package/dist/esm/helpers/inertProps.js.map +1 -0
- package/dist/esm/helpers/mergeBulmaStyles.js +20 -0
- package/dist/esm/helpers/mergeBulmaStyles.js.map +1 -0
- package/dist/esm/helpers/polymorphic.js +18 -0
- package/dist/esm/helpers/polymorphic.js.map +1 -0
- package/dist/esm/helpers/portal.js +76 -0
- package/dist/esm/helpers/portal.js.map +1 -0
- package/dist/esm/helpers/positionStacks.js +45 -0
- package/dist/esm/helpers/positionStacks.js.map +1 -0
- package/dist/esm/helpers/scrollLock.js +38 -0
- package/dist/esm/helpers/scrollLock.js.map +1 -0
- package/dist/esm/helpers/shadowDom.js +71 -0
- package/dist/esm/helpers/shadowDom.js.map +1 -0
- package/dist/esm/helpers/statusRegion.js +282 -0
- package/dist/esm/helpers/statusRegion.js.map +1 -0
- package/dist/esm/helpers/useAnchoredPosition.js +86 -0
- package/dist/esm/helpers/useAnchoredPosition.js.map +1 -0
- package/dist/esm/helpers/useBulmaClasses.js +158 -0
- package/dist/esm/helpers/useBulmaClasses.js.map +1 -0
- package/dist/esm/helpers/useClientLayoutEffect.js +13 -0
- package/dist/esm/helpers/useClientLayoutEffect.js.map +1 -0
- package/dist/esm/helpers/useColorClasses.js +84 -0
- package/dist/esm/helpers/useColorClasses.js.map +1 -0
- package/dist/esm/helpers/useFlexboxClasses.js +92 -0
- package/dist/esm/helpers/useFlexboxClasses.js.map +1 -0
- package/dist/esm/helpers/useFocusTrap.js +470 -0
- package/dist/esm/helpers/useFocusTrap.js.map +1 -0
- package/dist/esm/helpers/useIsHydrated.js +31 -0
- package/dist/esm/helpers/useIsHydrated.js.map +1 -0
- package/dist/esm/helpers/useOtherClasses.js +115 -0
- package/dist/esm/helpers/useOtherClasses.js.map +1 -0
- package/dist/esm/helpers/useSpacingClasses.js +82 -0
- package/dist/esm/helpers/useSpacingClasses.js.map +1 -0
- package/dist/esm/helpers/useTypographyClasses.js +93 -0
- package/dist/esm/helpers/useTypographyClasses.js.map +1 -0
- package/dist/esm/helpers/useVisibilityClasses.js +134 -0
- package/dist/esm/helpers/useVisibilityClasses.js.map +1 -0
- package/dist/esm/helpers/withSubComponents.js +24 -0
- package/dist/esm/helpers/withSubComponents.js.map +1 -0
- package/dist/esm/layout/Container.js +48 -0
- package/dist/esm/layout/Container.js.map +1 -0
- package/dist/esm/layout/Footer.js +33 -0
- package/dist/esm/layout/Footer.js.map +1 -0
- package/dist/esm/layout/Hero.js +90 -0
- package/dist/esm/layout/Hero.js.map +1 -0
- package/dist/esm/layout/Level.js +110 -0
- package/dist/esm/layout/Level.js.map +1 -0
- package/dist/esm/layout/Media.js +86 -0
- package/dist/esm/layout/Media.js.map +1 -0
- package/dist/esm/layout/Section.js +30 -0
- package/dist/esm/layout/Section.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +75 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +115 -17516
- package/dist/index.esm.js.map +1 -1
- package/dist/types/elements/Icon.d.ts +10 -7
- package/dist/types/form/DateInputBase.d.ts +3 -4
- package/dist/types/form/DateTimeInputBase.d.ts +3 -4
- package/dist/types/form/File.d.ts +3 -3
- package/dist/types-cjs/elements/Icon.d.ts +10 -7
- package/dist/types-cjs/form/DateInputBase.d.ts +3 -4
- package/dist/types-cjs/form/DateTimeInputBase.d.ts +3 -4
- package/dist/types-cjs/form/File.d.ts +3 -3
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/form/_dateinput.scss +37 -6
- package/src/scss/form/_datetimeinput.scss +7 -2
- package/src/scss/form/_picker-popover.scss +1 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeWheels.js","sources":["../../../../src/form/_pickerInternals/TimeWheels.tsx"],"sourcesContent":["/* eslint-disable react-hooks/refs --\n * This wheel/momentum picker intentionally accesses refs during render:\n * - state is mirrored into refs (positionRef, audioTickEnabledRef) so the\n * RAF/drag/tick callbacks read the latest values in lockstep with rendering\n * (refactoring to effect-synced refs would desync drag from the frame);\n * - a MediaQueryList is lazily cached in a ref (reducedMotionMqlRef);\n * - per-column Wheel handle refs build the keyboard focus order.\n * These are deliberate, established patterns; behavior is covered by unit tests\n * and certified interactively in-browser (drag, ticks, keyboard focus nav).\n */\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n classNames,\n prefixedClassNames,\n usePrefixedClassNames,\n} from '../../helpers/classNames';\nimport { useConfig } from '../../helpers/Config';\nimport {\n HourFormat,\n PickerLabels,\n isPopoverToggleKey,\n mergeLabels,\n} from './pickerTypes';\nimport { setTimeOfDay } from './dateUtils';\nimport { tickHaptic as fireTickHaptic } from './haptics';\nimport { playAudioTick, unlockAudioTick } from './audioTick';\n\nexport interface TimeWheelsValue {\n hours: number;\n minutes: number;\n seconds?: number;\n}\n\nexport interface TimeWheelsProps {\n value: TimeWheelsValue;\n onChange: (v: TimeWheelsValue) => void;\n hourFormat?: HourFormat;\n enableSeconds?: boolean;\n /** Step between visible values in the wheel. Default `1`. */\n incrementHours?: number;\n incrementMinutes?: number;\n incrementSeconds?: number;\n unselectableTimes?: (d: Date) => boolean;\n size?: 'small' | 'medium' | 'large';\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n disabled?: boolean;\n className?: string;\n id?: string;\n labels?: PickerLabels;\n /** Number of items visible at once (must be odd). Default 5. */\n visibleCount?: number;\n /** Item height in px. Default 32. */\n itemHeight?: number;\n /**\n * Play a short audible tick on each item crossing. Useful as a fallback on\n * iOS Safari, where there is no web-accessible haptic API. Off by default\n * to avoid surprising users with sound; flip on for iOS-targeted UIs.\n */\n audioTick?: boolean;\n /**\n * Fired when the user presses Enter on a wheel column. The current value is\n * already committed (each wheel-tick calls onChange), so this typically just\n * needs to close the surrounding popover.\n */\n onCommit?: () => void;\n}\n\nconst wrap = (n: number, max: number): number => ((n % max) + max) % max;\n\n/**\n * Walk forward (or backward) from `start` in `step` steps until `test` returns\n * true or we've cycled all `max` candidates. Used to skip past unselectable\n * values without freezing the wheel.\n */\nfunction nextValid(\n start: number,\n step: number,\n max: number,\n test: (n: number) => boolean\n): number {\n let candidate = wrap(start, max);\n for (let i = 0; i < max; i++) {\n if (test(candidate)) return candidate;\n candidate = wrap(candidate + step, max);\n }\n return start;\n}\n\nconst pad2 = (n: number): string => String(n).padStart(2, '0');\n\ninterface WheelHandle {\n focus: () => void;\n /**\n * Begin a drag externally — used by the parent's empty-space forwarder so\n * the user can grab the wheel by touching anywhere in the wheels row, not\n * just on the column itself (matches iOS native picker behavior).\n *\n * The pointer must already be active (i.e., a real `pointerdown` is in\n * flight). We immediately capture the pointer on the wheel root so the\n * existing `onPointerMove` / `onPointerUp` handlers will fire here.\n */\n startDrag: (pointerId: number, clientY: number) => void;\n}\n\ninterface WheelProps<T> {\n values: T[];\n index: number;\n onChange: (nextIndex: number) => void;\n formatLabel: (v: T) => string;\n formatAriaText?: (v: T) => string;\n ariaLabel: string;\n visibleCount: number;\n itemHeight: number;\n disabled?: boolean;\n size?: 'small' | 'medium' | 'large';\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n onFocusPrev?: () => void;\n onFocusNext?: () => void;\n /** Fired when Enter is pressed (current value is already committed live). */\n onCommit?: () => void;\n /**\n * Whether the wheel wraps at the edges. When true, scrolling past the last\n * value rolls back to the first (and vice versa) and neighbouring values\n * are visible above the first / below the last item.\n */\n wrap?: boolean;\n /**\n * Optional predicate. Items for which it returns `true` are rendered with\n * the `disabled` attribute (and visually dimmed via the `:disabled` SCSS\n * rule), giving users a clear cue that the value is blocked. Keyboard /\n * wheel navigation may still pass over these positions, but `onChange`\n * callers (`TimeWheels`) skip them via `nextValid`.\n */\n disabledFor?: (v: T) => boolean;\n /**\n * Play an audible tick on each item crossing. Used as the iOS substitute\n * for haptic feedback; threaded from `TimeWheels.audioTick`.\n */\n audioTick?: boolean;\n}\n\nconst WheelInner = <T,>(\n {\n values,\n index,\n onChange,\n formatLabel,\n formatAriaText,\n ariaLabel,\n visibleCount,\n itemHeight,\n disabled,\n size,\n color,\n onFocusPrev,\n onFocusNext,\n onCommit,\n wrap = false,\n disabledFor,\n audioTick = false,\n }: WheelProps<T>,\n ref: React.Ref<WheelHandle>\n) => {\n const { classPrefix } = useConfig();\n const N = values.length;\n const half = Math.floor(visibleCount / 2);\n const containerHeight = visibleCount * itemHeight;\n // Buffer around the visible window so adjacent items animate in/out smoothly.\n const BUFFER = half + 2;\n\n // Continuous wheel position in units of items. Math.round(position) is the\n // \"active\" virtual index; the fractional part is the drag/momentum offset\n // within an item slot. Using a single float (rather than virtualIdx +\n // dragOffset) keeps drag and tick-update in lockstep so items move with the\n // finger without a 40px overshoot when crossing item boundaries.\n const [position, setPosition] = useState<number>(index);\n const positionRef = useRef<number>(index);\n positionRef.current = position;\n const [isDragging, setIsDragging] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n // Ref to the stationary selection band — populated by the JSX below. The\n // band briefly scales + brightens on each item tick so users perceive a\n // body-felt \"thunk\" even on iOS where no haptic API exists.\n const bandRef = useRef<HTMLDivElement>(null);\n // Cached MediaQueryList for `prefers-reduced-motion`. We read this on\n // every tick to decide whether to fire the band pulse; caching the MQL\n // saves a `matchMedia` call per tick (which can fire at ~20Hz during a\n // momentum flick).\n const reducedMotionMqlRef = useRef<MediaQueryList | null>(null);\n if (\n reducedMotionMqlRef.current === null &&\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function'\n ) {\n reducedMotionMqlRef.current = window.matchMedia(\n '(prefers-reduced-motion: reduce)'\n );\n }\n // In-flight band pulse animation (Web Animations API). Tracked so we can\n // cancel on unmount; the WAI's `composite: 'replace'` semantics handle\n // re-trigger automatically without us needing to cancel between ticks.\n const pulseAnimRef = useRef<Animation | null>(null);\n // True while the external `index` prop sync useEffect runs, so we don't\n // fire a haptic blip when the parent updates the value programmatically.\n const isSyncingRef = useRef<boolean>(false);\n\n // Tiny haptic/audio/visual blip per item tick. Haptic uses\n // `navigator.vibrate` where available (Android Chrome / Firefox Android /\n // Samsung Internet); iOS has no web-accessible haptic path as of May\n // 2026, so the optional `audioTick` plays a low-frequency thunk as the\n // closest UX substitute. The visual band-pulse fires on every tick on\n // every platform (gated only by `prefers-reduced-motion`) so the\n // selection band feels reactive — visual reinforcement of the tactile\n // feedback. We skip all three during programmatic prop sync so a parent\n // re-render doesn't blip.\n const audioTickEnabledRef = useRef<boolean>(audioTick);\n audioTickEnabledRef.current = audioTick;\n const playBandPulse = useCallback(() => {\n const el = bandRef.current;\n if (!el || typeof el.animate !== 'function') return;\n if (reducedMotionMqlRef.current?.matches) return;\n // Compound scale + brightness pulse, peaking at 40% through the 110ms\n // duration. `composite: 'replace'` means a re-trigger mid-pulse cleanly\n // restarts rather than queueing — important at fling rates where ticks\n // can fire every ~50ms.\n pulseAnimRef.current = el.animate(\n [\n { transform: 'scale(1)', filter: 'brightness(1)' },\n {\n transform: 'scale(1.04)',\n filter: 'brightness(1.15)',\n offset: 0.4,\n },\n { transform: 'scale(1)', filter: 'brightness(1)' },\n ],\n { duration: 110, easing: 'ease-out', composite: 'replace' }\n );\n }, []);\n const tickFeedback = useCallback(() => {\n /* istanbul ignore next: the sync flag is only true synchronously inside the prop-sync effect, which sets position directly and never routes through commitPosition */\n if (isSyncingRef.current) return;\n fireTickHaptic();\n if (audioTickEnabledRef.current) playAudioTick();\n playBandPulse();\n }, [playBandPulse]);\n const dragStateRef = useRef<{\n pointerId: number | null;\n startY: number;\n startPosition: number;\n captured: boolean;\n samples: { t: number; y: number }[];\n }>({\n pointerId: null,\n startY: 0,\n startPosition: 0,\n captured: false,\n samples: [],\n });\n // RAF id for the in-flight momentum / snap animation, so we can cancel when\n // the user grabs the wheel again or the component unmounts.\n const rafIdRef = useRef<number | null>(null);\n\n const virtualIdx = Math.round(position);\n\n const cancelRaf = useCallback(() => {\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n rafIdRef.current = null;\n }\n }, []);\n\n useEffect(\n () => () => {\n cancelRaf();\n // Cancel any in-flight band pulse so it doesn't keep a reference to\n // a detached DOM node. WAI Animation.cancel() is safe to call even\n // if the animation has already finished.\n pulseAnimRef.current?.cancel();\n pulseAnimRef.current = null;\n },\n [cancelRaf]\n );\n\n React.useImperativeHandle(\n ref,\n () => ({\n focus: () => rootRef.current?.focus(),\n startDrag: (pointerId: number, clientY: number) => {\n /* istanbul ignore next: the empty-space forwarder (sole caller) already returns on the same disabled prop */\n if (disabled) return;\n cancelRaf();\n if (audioTickEnabledRef.current) unlockAudioTick();\n const now =\n typeof performance !== 'undefined' ? performance.now() : Date.now();\n dragStateRef.current = {\n pointerId,\n startY: clientY,\n startPosition: positionRef.current,\n // Skip the drag-threshold gate: the parent forwarder has already\n // decided this is a drag (a pointerdown landed on empty space,\n // which has no click target).\n captured: true,\n samples: [{ t: now, y: clientY }],\n };\n try {\n rootRef.current?.setPointerCapture(pointerId);\n } catch {\n // setPointerCapture can throw if the pointer isn't currently\n // active for this element; the existing onPointerMove handler\n // still matches on pointerId so the drag will work either way.\n }\n setIsDragging(true);\n },\n }),\n [disabled, cancelRaf]\n );\n\n // Resolve a virtualIdx into an actual values[] index (modulo wrap if `wrap`).\n const toActual = useCallback(\n (v: number) => {\n if (wrap) return ((v % N) + N) % N;\n return Math.max(0, Math.min(N - 1, v));\n },\n [wrap, N]\n );\n\n const clampPosition = useCallback(\n (p: number) => {\n if (wrap) return p;\n return Math.max(0, Math.min(N - 1, p));\n },\n [wrap, N]\n );\n\n // Update position and fire onChange if the rounded value changed.\n const commitPosition = useCallback(\n (next: number) => {\n const clamped = clampPosition(next);\n const prevRound = Math.round(positionRef.current);\n const nextRound = Math.round(clamped);\n positionRef.current = clamped;\n setPosition(clamped);\n if (nextRound !== prevRound) {\n onChange(toActual(nextRound));\n tickFeedback();\n }\n },\n [clampPosition, onChange, toActual, tickFeedback]\n );\n\n // When the external `index` changes (e.g. from typed input), re-sync\n // position to the closest virtual position that maps to it.\n //\n // Crucial subtlety: this effect re-runs every time the parent value\n // changes — including the round-trip case where the user's own scroll\n // commits a tick → fires onChange → parent re-renders with the new\n // index → here. If we cancelled the in-flight momentum/snap RAF on\n // every such echo, the snap would never get to land on an integer\n // (the user's wheel would stop wherever the last tick fired). So we\n // bail out early when the rounded position already matches the\n // incoming index — the echo case — and only cancel + apply an actual\n // jump when the parent has moved us somewhere we don't already round\n // to.\n useEffect(() => {\n const prev = positionRef.current;\n const wrappedRoundPrev = ((Math.round(prev) % N) + N) % N;\n if (wrappedRoundPrev === index) return;\n cancelRaf();\n isSyncingRef.current = true;\n setPosition(prevPos => {\n if (!wrap) {\n positionRef.current = index;\n return index;\n }\n const wrappedPrev = ((prevPos % N) + N) % N;\n const forward = (index - wrappedPrev + N) % N;\n const backward = forward - N;\n const delta =\n Math.abs(forward) <= Math.abs(backward) ? forward : backward;\n const next = prevPos + delta;\n positionRef.current = next;\n return next;\n });\n isSyncingRef.current = false;\n }, [index, N, wrap, cancelRaf]);\n\n const moveBy = useCallback(\n (delta: number) => {\n if (disabled) return;\n cancelRaf();\n commitPosition(Math.round(positionRef.current) + delta);\n },\n [disabled, cancelRaf, commitPosition]\n );\n\n // The keys are a spinbutton's: up raises the value and down lowers it. The\n // values run down the wheel, so up brings the one below the band into it,\n // the way a drag or a scroll that moves the items up does.\n const onKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (isPopoverToggleKey(e)) return;\n switch (e.key) {\n case 'ArrowUp':\n e.preventDefault();\n moveBy(1);\n break;\n case 'ArrowDown':\n e.preventDefault();\n moveBy(-1);\n break;\n case 'PageUp':\n e.preventDefault();\n moveBy(5);\n break;\n case 'PageDown':\n e.preventDefault();\n moveBy(-5);\n break;\n case 'Home':\n e.preventDefault();\n if (disabled) break;\n cancelRaf();\n commitPosition(0);\n break;\n case 'End':\n e.preventDefault();\n if (disabled) break;\n cancelRaf();\n commitPosition(N - 1);\n break;\n case 'ArrowLeft':\n e.preventDefault();\n onFocusPrev?.();\n break;\n case 'ArrowRight':\n e.preventDefault();\n onFocusNext?.();\n break;\n case 'Enter':\n e.preventDefault();\n onCommit?.();\n break;\n }\n },\n [\n moveBy,\n disabled,\n commitPosition,\n cancelRaf,\n N,\n onFocusPrev,\n onFocusNext,\n onCommit,\n ]\n );\n\n // Animate position to the nearest integer with ease-out cubic. Used after a\n // drag / momentum settles, so the wheel always rests aligned to an item.\n const animateSnap = useCallback(() => {\n cancelRaf();\n const start = positionRef.current;\n const target = Math.round(start);\n if (start === target) return;\n const duration = 180;\n const startTime =\n typeof performance !== 'undefined' ? performance.now() : Date.now();\n const tick = (now: number) => {\n const t = Math.min(1, (now - startTime) / duration);\n const eased = 1 - Math.pow(1 - t, 3);\n const next = start + (target - start) * eased;\n commitPosition(next);\n if (t < 1) {\n rafIdRef.current = requestAnimationFrame(tick);\n } else {\n rafIdRef.current = null;\n }\n };\n rafIdRef.current = requestAnimationFrame(tick);\n }, [cancelRaf, commitPosition]);\n\n // Kinetic momentum after a flick. Uses exponential friction so the velocity\n // tapers smoothly. Updates `position` in items/ms; commitPosition handles\n // the onChange ticks as virtualIdx crosses integers.\n const startMomentum = useCallback(\n (initialPxPerMs: number) => {\n cancelRaf();\n // Drag-up (negative dy/dt in screen coords) should INCREASE position\n // (later values come into view), so flip the sign.\n let velocity = -initialPxPerMs / itemHeight; // items / ms\n // Cap initial velocity so a frantic swipe doesn't blast through the\n // whole list. Empirically tuned to match iOS feel.\n const MAX_VEL = 0.05; // items/ms (≈ 50 items/sec)\n if (velocity > MAX_VEL) velocity = MAX_VEL;\n if (velocity < -MAX_VEL) velocity = -MAX_VEL;\n const STOP_VEL = 0.0015; // items/ms (≈ 1.5 items/sec)\n // Friction coefficient per millisecond — chosen so velocity halves\n // every ~120ms.\n const FRICTION_PER_MS = Math.pow(0.5, 1 / 120);\n let lastTime =\n typeof performance !== 'undefined' ? performance.now() : Date.now();\n const tick = (now: number) => {\n const dt = Math.max(1, now - lastTime);\n lastTime = now;\n let next = positionRef.current + velocity * dt;\n // Boundary handling for non-wrapping wheels: clamp and zero the\n // velocity so we don't keep ticking against the wall.\n if (!wrap) {\n if (next <= 0) {\n next = 0;\n velocity = 0;\n } else if (next >= N - 1) {\n next = N - 1;\n velocity = 0;\n }\n }\n commitPosition(next);\n velocity *= Math.pow(FRICTION_PER_MS, dt);\n if (Math.abs(velocity) < STOP_VEL) {\n animateSnap();\n return;\n }\n rafIdRef.current = requestAnimationFrame(tick);\n };\n rafIdRef.current = requestAnimationFrame(tick);\n },\n [cancelRaf, commitPosition, itemHeight, wrap, N, animateSnap]\n );\n\n // Mouse wheel: accumulate deltaY across events and step when the\n // accumulator crosses SCROLL_STEP_PX. Trackpads emit dozens of small\n // events per swipe; without accumulation a single gesture flies the wheel.\n useEffect(() => {\n const el = rootRef.current;\n if (!el || disabled) return undefined;\n const SCROLL_STEP_PX = 60;\n const QUIET_MS = 250;\n let accumulated = 0;\n let resetTimer: ReturnType<typeof setTimeout> | null = null;\n const resetAccumulator = () => {\n accumulated = 0;\n };\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n // Reset accumulator if scroll direction reversed mid-gesture.\n if (accumulated !== 0 && Math.sign(accumulated) !== Math.sign(e.deltaY)) {\n accumulated = 0;\n }\n accumulated += e.deltaY;\n while (Math.abs(accumulated) >= SCROLL_STEP_PX) {\n if (accumulated > 0) {\n moveBy(1);\n accumulated -= SCROLL_STEP_PX;\n } else {\n moveBy(-1);\n accumulated += SCROLL_STEP_PX;\n }\n }\n if (resetTimer) clearTimeout(resetTimer);\n resetTimer = setTimeout(resetAccumulator, QUIET_MS);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => {\n el.removeEventListener('wheel', onWheel);\n if (resetTimer) clearTimeout(resetTimer);\n };\n }, [moveBy, disabled]);\n\n // Pointer drag.\n // We DELAY capturing the pointer until the user moves more than\n // DRAG_THRESHOLD_PX. Without this, capturing on pointerdown would redirect\n // mouseup → wheel root, which suppresses the click event on the item button\n // the user pressed (so single-clicks on neighbouring items would no-op).\n const DRAG_THRESHOLD_PX = 4;\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (disabled) return;\n cancelRaf();\n if (audioTickEnabledRef.current) {\n // Resume the AudioContext from inside the user gesture so the first\n // tick of this drag can play (iOS Safari requires this; other browsers\n // are forgiving but it's a cheap idempotent call).\n unlockAudioTick();\n }\n const now =\n typeof performance !== 'undefined' ? performance.now() : Date.now();\n dragStateRef.current = {\n pointerId: e.pointerId,\n startY: e.clientY,\n startPosition: positionRef.current,\n captured: false,\n samples: [{ t: now, y: e.clientY }],\n };\n };\n const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const s = dragStateRef.current;\n if (s.pointerId !== e.pointerId) return;\n const dy = e.clientY - s.startY;\n if (!s.captured) {\n if (Math.abs(dy) < DRAG_THRESHOLD_PX) return;\n rootRef.current?.setPointerCapture(e.pointerId);\n s.captured = true;\n setIsDragging(true);\n }\n const now =\n typeof performance !== 'undefined' ? performance.now() : Date.now();\n s.samples.push({ t: now, y: e.clientY });\n // Keep the velocity sample window short so the post-flick velocity\n // reflects the *recent* finger speed, not the whole-drag average.\n const VELOCITY_WINDOW_MS = 100;\n while (s.samples.length > 2 && now - s.samples[0].t > VELOCITY_WINDOW_MS) {\n s.samples.shift();\n }\n // Continuous position: every itemHeight worth of finger drag advances\n // the wheel by 1 unit. Pulling the finger DOWN (positive dy) shows\n // EARLIER values, which means position decreases.\n commitPosition(s.startPosition - dy / itemHeight);\n };\n const onPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n const s = dragStateRef.current;\n if (s.pointerId !== e.pointerId) return;\n if (s.captured) {\n rootRef.current?.releasePointerCapture(e.pointerId);\n // Drags don't fire click → focus would be left on whichever child\n // received pointerdown. Pull it back to the wheel root so :focus\n // emphasis still reads correctly after a drag.\n rootRef.current?.focus();\n // Compute fling velocity from the recent sample window.\n const samples = s.samples;\n let pxPerMs = 0;\n if (samples.length >= 2) {\n const first = samples[0];\n const last = samples[samples.length - 1];\n const dt = last.t - first.t;\n if (dt > 0) pxPerMs = (last.y - first.y) / dt;\n }\n // Threshold below which we just snap to the nearest item; above which\n // we kick off momentum.\n const FLING_THRESHOLD = 0.25; // px/ms ≈ 250 px/sec\n if (Math.abs(pxPerMs) > FLING_THRESHOLD) {\n startMomentum(pxPerMs);\n } else {\n animateSnap();\n }\n }\n s.pointerId = null;\n s.captured = false;\n s.samples = [];\n setIsDragging(false);\n };\n\n const rootClass = prefixedClassNames(classPrefix, 'timeinput-wheel', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-disabled': disabled,\n 'is-dragging': isDragging,\n });\n const itemClass = (selected: boolean) =>\n prefixedClassNames(classPrefix, 'timeinput-wheel-item', {\n 'is-selected': selected,\n [`is-${color}`]: selected && !!color,\n });\n const bandClass = prefixedClassNames(classPrefix, 'timeinput-wheel-band', {\n [`is-${color}`]: !!color,\n });\n\n // Build the buffered window of items to render around the current position.\n const items: { vIdx: number; aIdx: number }[] = [];\n for (let off = -BUFFER; off <= BUFFER; off++) {\n const vIdx = virtualIdx + off;\n if (!wrap && (vIdx < 0 || vIdx >= N)) continue;\n const aIdx = toActual(vIdx);\n items.push({ vIdx, aIdx });\n }\n\n const ariaText = formatAriaText\n ? formatAriaText(values[toActual(virtualIdx)])\n : formatLabel(values[toActual(virtualIdx)]);\n\n // Center of the wheel viewport, in px from the top.\n const centreTop = containerHeight / 2 - itemHeight / 2;\n\n return (\n <div\n ref={rootRef}\n role=\"spinbutton\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={N - 1}\n aria-valuenow={toActual(virtualIdx)}\n aria-valuetext={ariaText}\n tabIndex={disabled ? -1 : 0}\n className={rootClass}\n style={{ height: containerHeight }}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n >\n {/* Stationary selection band — sits at the centre of the viewport while\n items slide through it, like the iOS native picker. The ref lets\n `playBandPulse` animate scale + brightness on each item tick. */}\n <div\n ref={bandRef}\n className={bandClass}\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n top: centreTop,\n height: itemHeight,\n pointerEvents: 'none',\n }}\n />\n {items.map(({ vIdx, aIdx }) => {\n // Continuous offset in items: items at the centre have offset ≈ 0;\n // top of viewport is negative, bottom positive.\n const offCentreItems = vIdx - position;\n const top = centreTop + offCentreItems * itemHeight;\n const selected = vIdx === virtualIdx;\n const itemDisabled =\n disabled || (disabledFor ? disabledFor(values[aIdx]) : false);\n return (\n <button\n key={vIdx}\n type=\"button\"\n // A spinbutton owns no options: it states its value through\n // aria-valuetext, so the items are pointer targets only.\n aria-hidden=\"true\"\n tabIndex={-1}\n className={itemClass(selected)}\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n height: itemHeight,\n top: `${top}px`,\n }}\n disabled={itemDisabled}\n // Keep a press from focusing the item, which assistive technology\n // can't see; the click below hands focus to the wheel instead.\n onMouseDown={e => e.preventDefault()}\n onClick={() => {\n moveBy(vIdx - virtualIdx);\n // Click focuses the <button> child by default; pull focus back\n // to the wheel root so the column emphasis (:focus rules) match.\n rootRef.current?.focus();\n }}\n >\n {formatLabel(values[aIdx])}\n </button>\n );\n })}\n </div>\n );\n};\n\nconst Wheel = React.forwardRef(WheelInner) as <T>(\n props: WheelProps<T> & { ref?: React.Ref<WheelHandle> }\n) => React.ReactElement;\n\nexport const TimeWheels: React.FC<TimeWheelsProps> = ({\n value,\n onChange,\n hourFormat = '24',\n enableSeconds = false,\n incrementHours = 1,\n incrementMinutes = 1,\n incrementSeconds = 1,\n unselectableTimes,\n size,\n color,\n disabled,\n className,\n id,\n labels,\n visibleCount = 5,\n itemHeight = 32,\n audioTick = false,\n onCommit,\n}) => {\n const t = mergeLabels(labels);\n\n const rootClass = usePrefixedClassNames('timeinput', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-disabled': disabled,\n });\n const wheelsClass = usePrefixedClassNames('timeinput-wheels');\n const sepClass = usePrefixedClassNames('timeinput-separator');\n // Use the prefixed class through the same helper the wheels themselves do,\n // so the selector matches the actual rendered class regardless of whether\n // the consumer configured `classPrefix` via ConfigProvider. Building the\n // selector with `${classPrefix}timeinput-wheel` is wrong when classPrefix\n // is undefined (defaults to the empty prefix) — it would stringify to\n // \"undefinedtimeinput-wheel\".\n const wheelSingleClass = usePrefixedClassNames('timeinput-wheel');\n const wheelsContainerRef = useRef<HTMLDivElement>(null);\n\n const isPm = value.hours >= 12;\n\n const isTimeAllowed = useCallback(\n (h: number, m: number, s: number) => {\n if (!unselectableTimes) return true;\n const probe = setTimeOfDay(new Date(), {\n hours: h,\n minutes: m,\n seconds: s,\n milliseconds: 0,\n });\n return !unselectableTimes(probe);\n },\n [unselectableTimes]\n );\n\n // Per-column \"is this value disabled?\" predicates. We compute them against\n // the current value's other parts, so e.g. a predicate that only blocks\n // 12:00–12:59 leaves all minutes selectable when the user moves the hour\n // off 12. Returning `undefined` (rather than a function) when there is no\n // unselectableTimes lets the Wheel skip the disabled-attribute branch.\n const isHourDisabled = useCallback(\n (display: number) => {\n let h24 = display;\n if (hourFormat === '12') {\n const base = display % 12;\n h24 = isPm ? base + 12 : base;\n }\n return !isTimeAllowed(h24, value.minutes, value.seconds ?? 0);\n },\n [hourFormat, isPm, isTimeAllowed, value.minutes, value.seconds]\n );\n const isMinuteDisabled = useCallback(\n (m: number) => !isTimeAllowed(value.hours, m, value.seconds ?? 0),\n [isTimeAllowed, value.hours, value.seconds]\n );\n const isSecondDisabled = useCallback(\n (s: number) => !isTimeAllowed(value.hours, value.minutes, s),\n [isTimeAllowed, value.hours, value.minutes]\n );\n const hourDisabledFor = unselectableTimes ? isHourDisabled : undefined;\n const minuteDisabledFor = unselectableTimes ? isMinuteDisabled : undefined;\n const secondDisabledFor = unselectableTimes ? isSecondDisabled : undefined;\n\n const commit = useCallback(\n (next: Partial<TimeWheelsValue>) => {\n const merged: TimeWheelsValue = {\n hours: next.hours ?? value.hours,\n minutes: next.minutes ?? value.minutes,\n seconds: enableSeconds\n ? (next.seconds ?? value.seconds ?? 0)\n : undefined,\n };\n if (!isTimeAllowed(merged.hours, merged.minutes, merged.seconds ?? 0)) {\n return;\n }\n onChange(merged);\n },\n [value, enableSeconds, isTimeAllowed, onChange]\n );\n\n // Build the value lists per column.\n const hourValues = useMemo<number[]>(() => {\n const step = Math.max(1, incrementHours);\n if (hourFormat === '12') {\n const out: number[] = [];\n for (let h = 1; h <= 12; h += step) out.push(h);\n return out;\n }\n const out: number[] = [];\n for (let h = 0; h < 24; h += step) out.push(h);\n return out;\n }, [hourFormat, incrementHours]);\n\n const minuteValues = useMemo<number[]>(() => {\n const step = Math.max(1, incrementMinutes);\n const out: number[] = [];\n for (let m = 0; m < 60; m += step) out.push(m);\n return out;\n }, [incrementMinutes]);\n\n const secondValues = useMemo<number[]>(() => {\n const step = Math.max(1, incrementSeconds);\n const out: number[] = [];\n for (let s = 0; s < 60; s += step) out.push(s);\n return out;\n }, [incrementSeconds]);\n\n // Map current value → wheel index.\n const displayedHours =\n hourFormat === '12'\n ? value.hours % 12 === 0\n ? 12\n : value.hours % 12\n : value.hours;\n const hourIndex = Math.max(0, hourValues.indexOf(displayedHours));\n const minuteIndex = Math.max(0, minuteValues.indexOf(value.minutes));\n const secondIndex = Math.max(0, secondValues.indexOf(value.seconds ?? 0));\n const ampmIndex = isPm ? 1 : 0;\n\n // Refs for column focus management.\n const hoursRef = useRef<WheelHandle>(null);\n const minutesRef = useRef<WheelHandle>(null);\n const secondsRef = useRef<WheelHandle>(null);\n const ampmRef = useRef<WheelHandle>(null);\n\n // Build the focus order at runtime.\n const columnOrder: React.RefObject<WheelHandle | null>[] = [];\n columnOrder.push(hoursRef);\n columnOrder.push(minutesRef);\n if (enableSeconds) columnOrder.push(secondsRef);\n if (hourFormat === '12') columnOrder.push(ampmRef);\n const focusAt = (i: number) => columnOrder[i]?.current?.focus();\n const indexOf = (r: React.RefObject<WheelHandle | null>): number =>\n columnOrder.indexOf(r);\n const focusPrevOf = (r: React.RefObject<WheelHandle | null>) => () =>\n focusAt(indexOf(r) - 1);\n const focusNextOf = (r: React.RefObject<WheelHandle | null>) => () =>\n focusAt(indexOf(r) + 1);\n\n // Hour change — translate displayed value back into 24h.\n const onHourIndex = (next: number) => {\n const display =\n hourValues[Math.max(0, Math.min(hourValues.length - 1, next))];\n let next24 = display;\n if (hourFormat === '12') {\n const baseHour = display % 12;\n next24 = isPm ? baseHour + 12 : baseHour;\n }\n // Skip past any blocked hour using nextValid.\n const allowed = nextValid(next24, next24 >= value.hours ? 1 : -1, 24, h =>\n isTimeAllowed(h, value.minutes, value.seconds ?? 0)\n );\n commit({ hours: allowed });\n };\n\n const onMinuteIndex = (next: number) => {\n const m =\n minuteValues[Math.max(0, Math.min(minuteValues.length - 1, next))];\n const allowed = nextValid(m, m >= value.minutes ? 1 : -1, 60, mm =>\n isTimeAllowed(value.hours, mm, value.seconds ?? 0)\n );\n commit({ minutes: allowed });\n };\n\n const onSecondIndex = (next: number) => {\n const s =\n secondValues[Math.max(0, Math.min(secondValues.length - 1, next))];\n const allowed = nextValid(s, s >= (value.seconds ?? 0) ? 1 : -1, 60, ss =>\n isTimeAllowed(value.hours, value.minutes, ss)\n );\n commit({ seconds: allowed });\n };\n\n const onAmpmIndex = (next: number) => {\n if (next === ampmIndex) return;\n commit({ hours: (value.hours + 12) % 24 });\n };\n\n // Forward drags that originate on the empty space inside the wheels row\n // (left of the leftmost wheel, right of the rightmost wheel, on the\n // separator) to whichever wheel column is nearest to the pointer X — so\n // the picker behaves like the iOS native one, where the whole picker\n // surface is grabbable, not just the column itself.\n const onWheelsContainerPointerDown = (\n e: React.PointerEvent<HTMLDivElement>\n ) => {\n if (disabled) return;\n // If the pointerdown landed on a real wheel column, the wheel's own\n // handler takes over — don't double-dispatch.\n if ((e.target as HTMLElement).closest(`.${wheelSingleClass}`)) return;\n const container = wheelsContainerRef.current;\n /* istanbul ignore next: the handler is attached to the very element this ref points to, so it can't be null while events fire */\n if (!container) return;\n const wheels = container.querySelectorAll<HTMLElement>(\n `.${wheelSingleClass}`\n );\n if (wheels.length === 0) return;\n let nearestIdx = 0;\n let nearestDist = Infinity;\n const x = e.clientX;\n wheels.forEach((el, i) => {\n const r = el.getBoundingClientRect();\n const cx = (r.left + r.right) / 2;\n const d = Math.abs(x - cx);\n if (d < nearestDist) {\n nearestDist = d;\n nearestIdx = i;\n }\n });\n columnOrder[nearestIdx]?.current?.startDrag(e.pointerId, e.clientY);\n };\n\n return (\n <div\n id={id}\n className={classNames(rootClass, className)}\n aria-disabled={disabled}\n >\n <div\n className={wheelsClass}\n ref={wheelsContainerRef}\n onPointerDown={onWheelsContainerPointerDown}\n >\n <Wheel\n ref={hoursRef}\n values={hourValues}\n index={hourIndex}\n onChange={onHourIndex}\n formatLabel={pad2}\n ariaLabel={t.hours}\n visibleCount={visibleCount}\n itemHeight={itemHeight}\n disabled={disabled}\n size={size}\n color={color}\n wrap\n onCommit={onCommit}\n onFocusPrev={focusPrevOf(hoursRef)}\n onFocusNext={focusNextOf(hoursRef)}\n disabledFor={hourDisabledFor}\n audioTick={audioTick}\n />\n <div className={sepClass} aria-hidden=\"true\">\n :\n </div>\n <Wheel\n ref={minutesRef}\n values={minuteValues}\n index={minuteIndex}\n onChange={onMinuteIndex}\n formatLabel={pad2}\n ariaLabel={t.minutes}\n visibleCount={visibleCount}\n itemHeight={itemHeight}\n disabled={disabled}\n size={size}\n color={color}\n wrap\n onCommit={onCommit}\n onFocusPrev={focusPrevOf(minutesRef)}\n onFocusNext={focusNextOf(minutesRef)}\n disabledFor={minuteDisabledFor}\n audioTick={audioTick}\n />\n {enableSeconds && (\n <>\n <div className={sepClass} aria-hidden=\"true\">\n :\n </div>\n <Wheel\n ref={secondsRef}\n values={secondValues}\n index={secondIndex}\n onChange={onSecondIndex}\n formatLabel={pad2}\n ariaLabel={t.seconds}\n visibleCount={visibleCount}\n itemHeight={itemHeight}\n disabled={disabled}\n size={size}\n color={color}\n wrap\n onCommit={onCommit}\n onFocusPrev={focusPrevOf(secondsRef)}\n onFocusNext={focusNextOf(secondsRef)}\n disabledFor={secondDisabledFor}\n audioTick={audioTick}\n />\n </>\n )}\n {hourFormat === '12' && (\n <Wheel\n ref={ampmRef}\n values={['AM', 'PM']}\n index={ampmIndex}\n onChange={onAmpmIndex}\n formatLabel={v => v}\n ariaLabel={t.ampm}\n visibleCount={visibleCount}\n itemHeight={itemHeight}\n disabled={disabled}\n size={size}\n color={color}\n onCommit={onCommit}\n onFocusPrev={focusPrevOf(ampmRef)}\n onFocusNext={focusNextOf(ampmRef)}\n audioTick={audioTick}\n />\n )}\n </div>\n </div>\n );\n};\n\nTimeWheels.displayName = 'TimeWheels';\n\nexport default TimeWheels;\n"],"names":["fireTickHaptic","_jsxs","_jsx","_Fragment"],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
/**
|
|
3
|
+
* Audio-tick fallback for platforms with no haptic API. iOS Safari has no
|
|
4
|
+
* web-accessible Taptic path (see `./haptics.ts` for the full story), so the
|
|
5
|
+
* closest UX substitute is a very short audible thunk played per item tick.
|
|
6
|
+
*
|
|
7
|
+
* Sound design — tuned to read as a body-felt impact, not an ear-felt beep:
|
|
8
|
+
*
|
|
9
|
+
* - Single triangle-wave oscillator at 160Hz, exponentially sweeping down to
|
|
10
|
+
* 110Hz over ~30ms. The low fundamental matches the frequency band where
|
|
11
|
+
* the Taptic Engine fires its UI pops (~150–200Hz); the downward sweep is
|
|
12
|
+
* the single biggest contributor to the perception of a damped physical
|
|
13
|
+
* impact (vs. a flat tone, which reads as a beep).
|
|
14
|
+
*
|
|
15
|
+
* - Triangle adds one odd harmonic over sine — just enough body to feel
|
|
16
|
+
* "soft" without the buzz of square or sawtooth.
|
|
17
|
+
*
|
|
18
|
+
* - Quick 1ms attack to 0.08 gain; exponential decay to silence over ~30ms;
|
|
19
|
+
* oscillator stops at +0.04s. Ramped envelope (no hard 0→1 jumps) avoids
|
|
20
|
+
* the classic Web Audio speaker pop on attack/release.
|
|
21
|
+
*
|
|
22
|
+
* - Uses a single oscillator + envelope rather than an audio buffer /
|
|
23
|
+
* decoded sample so there's no asset to ship and no `decodeAudioData`
|
|
24
|
+
* round-trip.
|
|
25
|
+
*
|
|
26
|
+
* - iOS Safari requires a user gesture to *resume* a suspended
|
|
27
|
+
* `AudioContext`. Call `unlockAudioTick()` from inside a touch / click
|
|
28
|
+
* handler before the first `playAudioTick()`. After that single resume,
|
|
29
|
+
* the context stays running and subsequent ticks play with no further
|
|
30
|
+
* gesture needed.
|
|
31
|
+
*
|
|
32
|
+
* - Silent / Ring switch behaviour on iOS: with the side switch in silent
|
|
33
|
+
* mode, this tick is suppressed (Web Audio respects the ringer). That
|
|
34
|
+
* matches iOS native UX expectations — silent mode means silent UI.
|
|
35
|
+
*
|
|
36
|
+
* - On hardware with neither speakers nor an audio device, every call
|
|
37
|
+
* silently no-ops.
|
|
38
|
+
*/
|
|
39
|
+
let audioCtx = null;
|
|
40
|
+
const getAudioContextCtor = () => {
|
|
41
|
+
if (typeof window === 'undefined')
|
|
42
|
+
return null;
|
|
43
|
+
const w = window;
|
|
44
|
+
return w.AudioContext ?? w.webkitAudioContext ?? null;
|
|
45
|
+
};
|
|
46
|
+
const ensureAudioCtx = () => {
|
|
47
|
+
if (audioCtx)
|
|
48
|
+
return audioCtx;
|
|
49
|
+
const Ctor = getAudioContextCtor();
|
|
50
|
+
if (!Ctor)
|
|
51
|
+
return null;
|
|
52
|
+
try {
|
|
53
|
+
audioCtx = new Ctor();
|
|
54
|
+
return audioCtx;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Call from inside a user-gesture handler (pointerdown, click, touchstart)
|
|
62
|
+
* to resume the AudioContext on iOS Safari. Idempotent and cheap; safe to
|
|
63
|
+
* call on every gesture. No-ops on platforms without Web Audio.
|
|
64
|
+
*/
|
|
65
|
+
const unlockAudioTick = () => {
|
|
66
|
+
const ctx = ensureAudioCtx();
|
|
67
|
+
if (!ctx)
|
|
68
|
+
return;
|
|
69
|
+
if (ctx.state === 'suspended') {
|
|
70
|
+
// Fire-and-forget: if the resume promise rejects (no gesture in
|
|
71
|
+
// progress), the next call from a real gesture will succeed.
|
|
72
|
+
void ctx.resume().catch(() => { });
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Play a single short tick. No-op if Web Audio is unavailable or the
|
|
77
|
+
* context hasn't been unlocked yet.
|
|
78
|
+
*/
|
|
79
|
+
const playAudioTick = () => {
|
|
80
|
+
const ctx = ensureAudioCtx();
|
|
81
|
+
if (!ctx || ctx.state !== 'running')
|
|
82
|
+
return;
|
|
83
|
+
try {
|
|
84
|
+
const now = ctx.currentTime;
|
|
85
|
+
const osc = ctx.createOscillator();
|
|
86
|
+
const gain = ctx.createGain();
|
|
87
|
+
osc.type = 'triangle';
|
|
88
|
+
// Pitch sweep: 160Hz → 110Hz over 30ms. The downward exponential ramp
|
|
89
|
+
// is what makes this read as a damped impact rather than a flat beep.
|
|
90
|
+
osc.frequency.setValueAtTime(160, now);
|
|
91
|
+
osc.frequency.exponentialRampToValueAtTime(110, now + 0.03);
|
|
92
|
+
// Envelope: 1ms attack to 0.08, exponential-style decay to near-zero
|
|
93
|
+
// over 30ms. `exponentialRampToValueAtTime` requires a strictly
|
|
94
|
+
// positive target — 0.0001 is inaudible and stops cleanly.
|
|
95
|
+
gain.gain.setValueAtTime(0, now);
|
|
96
|
+
gain.gain.linearRampToValueAtTime(0.08, now + 0.001);
|
|
97
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.03);
|
|
98
|
+
osc.connect(gain).connect(ctx.destination);
|
|
99
|
+
osc.start(now);
|
|
100
|
+
osc.stop(now + 0.04);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Connecting / starting an oscillator in an aborted context can throw;
|
|
104
|
+
// best-effort, never propagate.
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export { playAudioTick, unlockAudioTick };
|
|
109
|
+
//# sourceMappingURL=audioTick.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioTick.js","sources":["../../../../src/form/_pickerInternals/audioTick.ts"],"sourcesContent":["/**\n * Audio-tick fallback for platforms with no haptic API. iOS Safari has no\n * web-accessible Taptic path (see `./haptics.ts` for the full story), so the\n * closest UX substitute is a very short audible thunk played per item tick.\n *\n * Sound design — tuned to read as a body-felt impact, not an ear-felt beep:\n *\n * - Single triangle-wave oscillator at 160Hz, exponentially sweeping down to\n * 110Hz over ~30ms. The low fundamental matches the frequency band where\n * the Taptic Engine fires its UI pops (~150–200Hz); the downward sweep is\n * the single biggest contributor to the perception of a damped physical\n * impact (vs. a flat tone, which reads as a beep).\n *\n * - Triangle adds one odd harmonic over sine — just enough body to feel\n * \"soft\" without the buzz of square or sawtooth.\n *\n * - Quick 1ms attack to 0.08 gain; exponential decay to silence over ~30ms;\n * oscillator stops at +0.04s. Ramped envelope (no hard 0→1 jumps) avoids\n * the classic Web Audio speaker pop on attack/release.\n *\n * - Uses a single oscillator + envelope rather than an audio buffer /\n * decoded sample so there's no asset to ship and no `decodeAudioData`\n * round-trip.\n *\n * - iOS Safari requires a user gesture to *resume* a suspended\n * `AudioContext`. Call `unlockAudioTick()` from inside a touch / click\n * handler before the first `playAudioTick()`. After that single resume,\n * the context stays running and subsequent ticks play with no further\n * gesture needed.\n *\n * - Silent / Ring switch behaviour on iOS: with the side switch in silent\n * mode, this tick is suppressed (Web Audio respects the ringer). That\n * matches iOS native UX expectations — silent mode means silent UI.\n *\n * - On hardware with neither speakers nor an audio device, every call\n * silently no-ops.\n */\n\nlet audioCtx: AudioContext | null = null;\n\ninterface WindowWithWebkitAudio extends Window {\n // `AudioContext` lives on `typeof globalThis`, which a plain `Window` cast\n // drops — declare both the standard and the legacy webkit-prefixed ctor.\n AudioContext?: typeof AudioContext;\n webkitAudioContext?: typeof AudioContext;\n}\n\nconst getAudioContextCtor = (): typeof AudioContext | null => {\n if (typeof window === 'undefined') return null;\n const w = window as WindowWithWebkitAudio;\n return w.AudioContext ?? w.webkitAudioContext ?? null;\n};\n\nconst ensureAudioCtx = (): AudioContext | null => {\n if (audioCtx) return audioCtx;\n const Ctor = getAudioContextCtor();\n if (!Ctor) return null;\n try {\n audioCtx = new Ctor();\n return audioCtx;\n } catch {\n return null;\n }\n};\n\n/**\n * Call from inside a user-gesture handler (pointerdown, click, touchstart)\n * to resume the AudioContext on iOS Safari. Idempotent and cheap; safe to\n * call on every gesture. No-ops on platforms without Web Audio.\n */\nexport const unlockAudioTick = (): void => {\n const ctx = ensureAudioCtx();\n if (!ctx) return;\n if (ctx.state === 'suspended') {\n // Fire-and-forget: if the resume promise rejects (no gesture in\n // progress), the next call from a real gesture will succeed.\n void ctx.resume().catch(() => {});\n }\n};\n\n/**\n * Play a single short tick. No-op if Web Audio is unavailable or the\n * context hasn't been unlocked yet.\n */\nexport const playAudioTick = (): void => {\n const ctx = ensureAudioCtx();\n if (!ctx || ctx.state !== 'running') return;\n try {\n const now = ctx.currentTime;\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.type = 'triangle';\n // Pitch sweep: 160Hz → 110Hz over 30ms. The downward exponential ramp\n // is what makes this read as a damped impact rather than a flat beep.\n osc.frequency.setValueAtTime(160, now);\n osc.frequency.exponentialRampToValueAtTime(110, now + 0.03);\n // Envelope: 1ms attack to 0.08, exponential-style decay to near-zero\n // over 30ms. `exponentialRampToValueAtTime` requires a strictly\n // positive target — 0.0001 is inaudible and stops cleanly.\n gain.gain.setValueAtTime(0, now);\n gain.gain.linearRampToValueAtTime(0.08, now + 0.001);\n gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.03);\n osc.connect(gain).connect(ctx.destination);\n osc.start(now);\n osc.stop(now + 0.04);\n } catch {\n // Connecting / starting an oscillator in an aborted context can throw;\n // best-effort, never propagate.\n }\n};\n\n/** Test-only hook to drop the singleton AudioContext. */\nexport const __resetAudioTickForTest = (): void => {\n if (audioCtx) {\n try {\n void audioCtx.close();\n } catch {\n // ignore\n }\n }\n audioCtx = null;\n};\n"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCG;AAEH,IAAI,QAAQ,GAAwB,IAAI;AASxC,MAAM,mBAAmB,GAAG,MAAiC;IAC3D,IAAI,OAAO,MAAM,KAAK,WAAW;AAAE,QAAA,OAAO,IAAI;IAC9C,MAAM,CAAC,GAAG,MAA+B;IACzC,OAAO,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,kBAAkB,IAAI,IAAI;AACvD,CAAC;AAED,MAAM,cAAc,GAAG,MAA0B;AAC/C,IAAA,IAAI,QAAQ;AAAE,QAAA,OAAO,QAAQ;AAC7B,IAAA,MAAM,IAAI,GAAG,mBAAmB,EAAE;AAClC,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AACtB,IAAA,IAAI;AACF,QAAA,QAAQ,GAAG,IAAI,IAAI,EAAE;AACrB,QAAA,OAAO,QAAQ;IACjB;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,IAAI;IACb;AACF,CAAC;AAED;;;;AAIG;AACI,MAAM,eAAe,GAAG,MAAW;AACxC,IAAA,MAAM,GAAG,GAAG,cAAc,EAAE;AAC5B,IAAA,IAAI,CAAC,GAAG;QAAE;AACV,IAAA,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE;;;AAG7B,QAAA,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;IACnC;AACF;AAEA;;;AAGG;AACI,MAAM,aAAa,GAAG,MAAW;AACtC,IAAA,MAAM,GAAG,GAAG,cAAc,EAAE;AAC5B,IAAA,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE;AACrC,IAAA,IAAI;AACF,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW;AAC3B,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,gBAAgB,EAAE;AAClC,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE;AAC7B,QAAA,GAAG,CAAC,IAAI,GAAG,UAAU;;;QAGrB,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC;QACtC,GAAG,CAAC,SAAS,CAAC,4BAA4B,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;;;;QAI3D,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC;AAC1D,QAAA,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AAC1C,QAAA,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;AACd,QAAA,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IACtB;AAAE,IAAA,MAAM;;;IAGR;AACF;;"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
function isSameDay(a, b) {
|
|
3
|
+
return (a.getFullYear() === b.getFullYear() &&
|
|
4
|
+
a.getMonth() === b.getMonth() &&
|
|
5
|
+
a.getDate() === b.getDate());
|
|
6
|
+
}
|
|
7
|
+
function isSameMonth(a, b) {
|
|
8
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
|
|
9
|
+
}
|
|
10
|
+
function isBefore(a, b) {
|
|
11
|
+
return a.getTime() < b.getTime();
|
|
12
|
+
}
|
|
13
|
+
function isAfter(a, b) {
|
|
14
|
+
return a.getTime() > b.getTime();
|
|
15
|
+
}
|
|
16
|
+
function isWithin(d, min, max) {
|
|
17
|
+
if (min && isBefore(d, min))
|
|
18
|
+
return false;
|
|
19
|
+
if (max && isAfter(d, max))
|
|
20
|
+
return false;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
// The boundaries build on `makeDate` (below), so a date in years 0–99 keeps
|
|
24
|
+
// its year.
|
|
25
|
+
function startOfDay(d) {
|
|
26
|
+
return makeDate(d.getFullYear(), d.getMonth(), d.getDate());
|
|
27
|
+
}
|
|
28
|
+
function endOfDay(d) {
|
|
29
|
+
const r = makeDate(d.getFullYear(), d.getMonth(), d.getDate());
|
|
30
|
+
r.setHours(23, 59, 59, 999);
|
|
31
|
+
return r;
|
|
32
|
+
}
|
|
33
|
+
function startOfMonth(d) {
|
|
34
|
+
return makeDate(d.getFullYear(), d.getMonth());
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Local midnight on `year`-`month`-`day` (`month` from 0), like the
|
|
38
|
+
* `Date(y, m, d)` constructor except that years 0–99 stay as given rather than
|
|
39
|
+
* turning into 1900–1999.
|
|
40
|
+
*/
|
|
41
|
+
function makeDate(year, month = 0, day = 1) {
|
|
42
|
+
const d = new Date(2000, 0, 1);
|
|
43
|
+
d.setFullYear(year, month, day);
|
|
44
|
+
return d;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The earliest year the pickers accept. HTML's date, month and datetime-local
|
|
48
|
+
* inputs hold no year below 1, so the calendar, typing and parsing stop there
|
|
49
|
+
* too.
|
|
50
|
+
*/
|
|
51
|
+
const FIRST_YEAR = 1;
|
|
52
|
+
/**
|
|
53
|
+
* The lower bound a picker applies: `min`, raised to local midnight on
|
|
54
|
+
* 1 January of {@link FIRST_YEAR} when it is earlier or absent. A `min` in
|
|
55
|
+
* range comes back as the same object.
|
|
56
|
+
*/
|
|
57
|
+
function floorMin(min) {
|
|
58
|
+
const floor = makeDate(FIRST_YEAR);
|
|
59
|
+
return min && min.getTime() >= floor.getTime() ? min : floor;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* First instant of the day, month or year containing `d`. Works by setters on
|
|
63
|
+
* a copy rather than the `Date(y, m, d)` constructor, which reads years 0–99
|
|
64
|
+
* as 1900–1999: segmented typing passes through such years on the way to a
|
|
65
|
+
* four-digit one.
|
|
66
|
+
*/
|
|
67
|
+
function startOfPeriod(d, granularity) {
|
|
68
|
+
const r = new Date(d);
|
|
69
|
+
if (granularity === 'year')
|
|
70
|
+
r.setMonth(0, 1);
|
|
71
|
+
else if (granularity === 'month')
|
|
72
|
+
r.setDate(1);
|
|
73
|
+
r.setHours(0, 0, 0, 0);
|
|
74
|
+
return r;
|
|
75
|
+
}
|
|
76
|
+
/** Last instant of the day, month or year containing `d`. */
|
|
77
|
+
function endOfPeriod(d, granularity) {
|
|
78
|
+
const r = new Date(d);
|
|
79
|
+
if (granularity === 'year')
|
|
80
|
+
r.setMonth(11, 31);
|
|
81
|
+
// Day 0 of the next month is this month's last day.
|
|
82
|
+
else if (granularity === 'month')
|
|
83
|
+
r.setMonth(r.getMonth() + 1, 0);
|
|
84
|
+
r.setHours(23, 59, 59, 999);
|
|
85
|
+
return r;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether the day `d` falls outside `[min, max]` or is blocked by
|
|
89
|
+
* `shouldDisableDate` / `unselectableDates`. This is the day grid's rule for a
|
|
90
|
+
* disabled cell.
|
|
91
|
+
*/
|
|
92
|
+
function isDayUnselectable(d, c) {
|
|
93
|
+
if (!isWithin(d, c.min, c.max))
|
|
94
|
+
return true;
|
|
95
|
+
if (c.shouldDisableDate?.(d))
|
|
96
|
+
return true;
|
|
97
|
+
if (c.unselectableDates?.some(u => isSameDay(u, d)))
|
|
98
|
+
return true;
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Whether every day of the month or year containing `d` is unselectable, so
|
|
103
|
+
* the period as a whole can't be picked. Walks the period's days and stops at
|
|
104
|
+
* the first selectable one. `min` and `max` count whole days here, so a `min`
|
|
105
|
+
* of 3pm on a month's last day leaves that day, and so its month, selectable.
|
|
106
|
+
*/
|
|
107
|
+
function isPeriodUnselectable(d, granularity, c) {
|
|
108
|
+
const days = {
|
|
109
|
+
...c,
|
|
110
|
+
min: c.min && startOfDay(c.min),
|
|
111
|
+
max: c.max && endOfDay(c.max),
|
|
112
|
+
};
|
|
113
|
+
const start = startOfPeriod(d, granularity);
|
|
114
|
+
const end = endOfPeriod(d, granularity).getTime();
|
|
115
|
+
// A period wholly outside the bounds needs no walk.
|
|
116
|
+
if (days.min && end < days.min.getTime())
|
|
117
|
+
return true;
|
|
118
|
+
if (days.max && start.getTime() > days.max.getTime())
|
|
119
|
+
return true;
|
|
120
|
+
for (let day = start; day.getTime() <= end; day = addDays(day, 1)) {
|
|
121
|
+
if (!isDayUnselectable(day, days))
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The most days {@link canCloseRange} walks between a range's ends, about
|
|
128
|
+
* eleven years. A span it would have to walk further is refused, so the check
|
|
129
|
+
* stays cheap enough to run on every pointer move over the calendar.
|
|
130
|
+
*/
|
|
131
|
+
const RANGE_WALK_LIMIT = 4000;
|
|
132
|
+
/**
|
|
133
|
+
* Whether `end` can close a range that opens on `start`: it falls on `start`'s
|
|
134
|
+
* day or later, and, unless `allowDisabled`, no day between the two is one
|
|
135
|
+
* that `shouldDisableDate` or `unselectableDates` disables. Checking that
|
|
136
|
+
* walks the days between, so with either rule set and `allowDisabled` off,
|
|
137
|
+
* an `end` more than {@link RANGE_WALK_LIMIT} days after `start` is refused.
|
|
138
|
+
* The ends' own constraints, `min` and `max` among them, are the caller's to
|
|
139
|
+
* check. Bounds can't fall between two days inside them, so they are not
|
|
140
|
+
* walked.
|
|
141
|
+
*/
|
|
142
|
+
function canCloseRange(start, end, c, allowDisabled = false) {
|
|
143
|
+
const first = startOfDay(start);
|
|
144
|
+
const last = startOfDay(end).getTime();
|
|
145
|
+
if (last < first.getTime())
|
|
146
|
+
return false;
|
|
147
|
+
if (allowDisabled)
|
|
148
|
+
return true;
|
|
149
|
+
const blocks = {
|
|
150
|
+
shouldDisableDate: c.shouldDisableDate,
|
|
151
|
+
unselectableDates: c.unselectableDates,
|
|
152
|
+
};
|
|
153
|
+
if (!blocks.shouldDisableDate && !blocks.unselectableDates?.length) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
for (let d = addDays(first, 1), walked = 1; d.getTime() < last; d = addDays(d, 1), walked++) {
|
|
157
|
+
if (walked >= RANGE_WALK_LIMIT || isDayUnselectable(d, blocks)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
function addDays(d, n) {
|
|
164
|
+
const r = new Date(d);
|
|
165
|
+
r.setDate(r.getDate() + n);
|
|
166
|
+
return r;
|
|
167
|
+
}
|
|
168
|
+
function addMonths(d, n) {
|
|
169
|
+
const r = new Date(d);
|
|
170
|
+
const day = r.getDate();
|
|
171
|
+
r.setDate(1);
|
|
172
|
+
r.setMonth(r.getMonth() + n);
|
|
173
|
+
// Clamp day to last day of new month if original day is out of range.
|
|
174
|
+
const lastDay = makeDate(r.getFullYear(), r.getMonth() + 1, 0).getDate();
|
|
175
|
+
r.setDate(Math.min(day, lastDay));
|
|
176
|
+
return r;
|
|
177
|
+
}
|
|
178
|
+
function addYears(d, n) {
|
|
179
|
+
return addMonths(d, n * 12);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* A copy of `d` with the given parts of its time of day set and the rest
|
|
183
|
+
* left as they are. A time started from the clock rather than from a value
|
|
184
|
+
* should pass the seconds its picker does not show, and the milliseconds,
|
|
185
|
+
* as `0`, or it keeps the ones the clock had.
|
|
186
|
+
*/
|
|
187
|
+
function setTimeOfDay(d, parts) {
|
|
188
|
+
const r = new Date(d);
|
|
189
|
+
if (parts.hours !== undefined)
|
|
190
|
+
r.setHours(parts.hours);
|
|
191
|
+
if (parts.minutes !== undefined)
|
|
192
|
+
r.setMinutes(parts.minutes);
|
|
193
|
+
if (parts.seconds !== undefined)
|
|
194
|
+
r.setSeconds(parts.seconds);
|
|
195
|
+
if (parts.milliseconds !== undefined)
|
|
196
|
+
r.setMilliseconds(parts.milliseconds);
|
|
197
|
+
return r;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* A copy of `d` moved into `[min, max]`. When `min` is after `max` nothing is
|
|
201
|
+
* in range and `min` wins, so clamping twice gives the same date and a
|
|
202
|
+
* picker's focus stays off the years before 1 under a `max` before then.
|
|
203
|
+
*/
|
|
204
|
+
function clampDate(d, min, max) {
|
|
205
|
+
const capped = max && isAfter(d, max) ? max : d;
|
|
206
|
+
return new Date(min && isBefore(capped, min) ? min : capped);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Snap a Date's time-of-day to the nearest grid defined by the given
|
|
210
|
+
* increment steps. Used by the "Now" button in pickers configured with
|
|
211
|
+
* non-1 hour / minute / second steps so the committed time always lands on
|
|
212
|
+
* a slot that exists on the wheel. Overflows roll up: e.g.
|
|
213
|
+
* 13:58 with step=15 → 14:00. Seconds are zeroed when `enableSeconds` is
|
|
214
|
+
* false, regardless of step.
|
|
215
|
+
*/
|
|
216
|
+
function snapTimeToIncrement(d, opts = {}) {
|
|
217
|
+
const { incrementHours = 1, incrementMinutes = 1, incrementSeconds = 1, enableSeconds = false, } = opts;
|
|
218
|
+
const r = new Date(d);
|
|
219
|
+
let h = r.getHours();
|
|
220
|
+
let m = r.getMinutes();
|
|
221
|
+
let s = enableSeconds ? r.getSeconds() : 0;
|
|
222
|
+
if (enableSeconds && incrementSeconds > 1) {
|
|
223
|
+
s = Math.round(s / incrementSeconds) * incrementSeconds;
|
|
224
|
+
if (s >= 60) {
|
|
225
|
+
s -= 60;
|
|
226
|
+
m += 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (incrementMinutes > 1) {
|
|
230
|
+
m = Math.round(m / incrementMinutes) * incrementMinutes;
|
|
231
|
+
if (m >= 60) {
|
|
232
|
+
m -= 60;
|
|
233
|
+
h += 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (incrementHours > 1) {
|
|
237
|
+
h = Math.round(h / incrementHours) * incrementHours;
|
|
238
|
+
// setHours handles 24+ overflow naturally (rolls forward into next day).
|
|
239
|
+
}
|
|
240
|
+
r.setHours(h, m, s, 0);
|
|
241
|
+
return r;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Build a 6-week × 7-day grid (42 cells) anchored on the month containing
|
|
245
|
+
* `monthAnchor`. The first cell is the start of the week containing the first
|
|
246
|
+
* of the month, where the week starts on `firstDayOfWeek`.
|
|
247
|
+
*/
|
|
248
|
+
function buildMonthGrid(monthAnchor, firstDayOfWeek = 0) {
|
|
249
|
+
const monthStart = startOfMonth(monthAnchor);
|
|
250
|
+
const firstWeekday = monthStart.getDay();
|
|
251
|
+
const offset = (firstWeekday - firstDayOfWeek + 7) % 7;
|
|
252
|
+
const gridStart = addDays(monthStart, -offset);
|
|
253
|
+
const today = startOfDay(new Date());
|
|
254
|
+
const cells = [];
|
|
255
|
+
for (let i = 0; i < 42; i++) {
|
|
256
|
+
const date = addDays(gridStart, i);
|
|
257
|
+
cells.push({
|
|
258
|
+
date,
|
|
259
|
+
inCurrentMonth: date.getMonth() === monthAnchor.getMonth(),
|
|
260
|
+
isToday: isSameDay(date, today),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return cells;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { FIRST_YEAR, RANGE_WALK_LIMIT, addDays, addMonths, addYears, buildMonthGrid, canCloseRange, clampDate, endOfDay, endOfPeriod, floorMin, isAfter, isBefore, isDayUnselectable, isPeriodUnselectable, isSameDay, isSameMonth, isWithin, makeDate, setTimeOfDay, snapTimeToIncrement, startOfDay, startOfMonth, startOfPeriod };
|
|
267
|
+
//# sourceMappingURL=dateUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateUtils.js","sources":["../../../../src/form/_pickerInternals/dateUtils.ts"],"sourcesContent":["import { DateGranularity, DayOfWeek } from './pickerTypes';\n\nexport interface CalendarCell {\n date: Date;\n inCurrentMonth: boolean;\n isToday: boolean;\n}\n\nexport function isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nexport function isSameMonth(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\nexport function isBefore(a: Date, b: Date): boolean {\n return a.getTime() < b.getTime();\n}\n\nexport function isAfter(a: Date, b: Date): boolean {\n return a.getTime() > b.getTime();\n}\n\nexport function isWithin(d: Date, min?: Date, max?: Date): boolean {\n if (min && isBefore(d, min)) return false;\n if (max && isAfter(d, max)) return false;\n return true;\n}\n\n// The boundaries build on `makeDate` (below), so a date in years 0–99 keeps\n// its year.\n\nexport function startOfDay(d: Date): Date {\n return makeDate(d.getFullYear(), d.getMonth(), d.getDate());\n}\n\nexport function endOfDay(d: Date): Date {\n const r = makeDate(d.getFullYear(), d.getMonth(), d.getDate());\n r.setHours(23, 59, 59, 999);\n return r;\n}\n\nexport function startOfMonth(d: Date): Date {\n return makeDate(d.getFullYear(), d.getMonth());\n}\n\nexport function endOfMonth(d: Date): Date {\n // Day 0 of the next month is this month's last day.\n const r = makeDate(d.getFullYear(), d.getMonth() + 1, 0);\n r.setHours(23, 59, 59, 999);\n return r;\n}\n\n/**\n * Local midnight on `year`-`month`-`day` (`month` from 0), like the\n * `Date(y, m, d)` constructor except that years 0–99 stay as given rather than\n * turning into 1900–1999.\n */\nexport function makeDate(year: number, month = 0, day = 1): Date {\n const d = new Date(2000, 0, 1);\n d.setFullYear(year, month, day);\n return d;\n}\n\n/**\n * The earliest year the pickers accept. HTML's date, month and datetime-local\n * inputs hold no year below 1, so the calendar, typing and parsing stop there\n * too.\n */\nexport const FIRST_YEAR = 1;\n\n/**\n * The lower bound a picker applies: `min`, raised to local midnight on\n * 1 January of {@link FIRST_YEAR} when it is earlier or absent. A `min` in\n * range comes back as the same object.\n */\nexport function floorMin(min?: Date): Date {\n const floor = makeDate(FIRST_YEAR);\n return min && min.getTime() >= floor.getTime() ? min : floor;\n}\n\n/**\n * First instant of the day, month or year containing `d`. Works by setters on\n * a copy rather than the `Date(y, m, d)` constructor, which reads years 0–99\n * as 1900–1999: segmented typing passes through such years on the way to a\n * four-digit one.\n */\nexport function startOfPeriod(d: Date, granularity: DateGranularity): Date {\n const r = new Date(d);\n if (granularity === 'year') r.setMonth(0, 1);\n else if (granularity === 'month') r.setDate(1);\n r.setHours(0, 0, 0, 0);\n return r;\n}\n\n/** Last instant of the day, month or year containing `d`. */\nexport function endOfPeriod(d: Date, granularity: DateGranularity): Date {\n const r = new Date(d);\n if (granularity === 'year') r.setMonth(11, 31);\n // Day 0 of the next month is this month's last day.\n else if (granularity === 'month') r.setMonth(r.getMonth() + 1, 0);\n r.setHours(23, 59, 59, 999);\n return r;\n}\n\n/** The rules that make a single calendar day unselectable. */\nexport interface DayConstraints {\n min?: Date;\n max?: Date;\n shouldDisableDate?: (d: Date) => boolean;\n unselectableDates?: Date[];\n}\n\n/**\n * Whether the day `d` falls outside `[min, max]` or is blocked by\n * `shouldDisableDate` / `unselectableDates`. This is the day grid's rule for a\n * disabled cell.\n */\nexport function isDayUnselectable(d: Date, c: DayConstraints): boolean {\n if (!isWithin(d, c.min, c.max)) return true;\n if (c.shouldDisableDate?.(d)) return true;\n if (c.unselectableDates?.some(u => isSameDay(u, d))) return true;\n return false;\n}\n\n/**\n * Whether every day of the month or year containing `d` is unselectable, so\n * the period as a whole can't be picked. Walks the period's days and stops at\n * the first selectable one. `min` and `max` count whole days here, so a `min`\n * of 3pm on a month's last day leaves that day, and so its month, selectable.\n */\nexport function isPeriodUnselectable(\n d: Date,\n granularity: DateGranularity,\n c: DayConstraints\n): boolean {\n const days: DayConstraints = {\n ...c,\n min: c.min && startOfDay(c.min),\n max: c.max && endOfDay(c.max),\n };\n const start = startOfPeriod(d, granularity);\n const end = endOfPeriod(d, granularity).getTime();\n // A period wholly outside the bounds needs no walk.\n if (days.min && end < days.min.getTime()) return true;\n if (days.max && start.getTime() > days.max.getTime()) return true;\n for (let day = start; day.getTime() <= end; day = addDays(day, 1)) {\n if (!isDayUnselectable(day, days)) return false;\n }\n return true;\n}\n\n/**\n * The most days {@link canCloseRange} walks between a range's ends, about\n * eleven years. A span it would have to walk further is refused, so the check\n * stays cheap enough to run on every pointer move over the calendar.\n */\nexport const RANGE_WALK_LIMIT = 4000;\n\n/**\n * Whether `end` can close a range that opens on `start`: it falls on `start`'s\n * day or later, and, unless `allowDisabled`, no day between the two is one\n * that `shouldDisableDate` or `unselectableDates` disables. Checking that\n * walks the days between, so with either rule set and `allowDisabled` off,\n * an `end` more than {@link RANGE_WALK_LIMIT} days after `start` is refused.\n * The ends' own constraints, `min` and `max` among them, are the caller's to\n * check. Bounds can't fall between two days inside them, so they are not\n * walked.\n */\nexport function canCloseRange(\n start: Date,\n end: Date,\n c: DayConstraints,\n allowDisabled = false\n): boolean {\n const first = startOfDay(start);\n const last = startOfDay(end).getTime();\n if (last < first.getTime()) return false;\n if (allowDisabled) return true;\n const blocks: DayConstraints = {\n shouldDisableDate: c.shouldDisableDate,\n unselectableDates: c.unselectableDates,\n };\n if (!blocks.shouldDisableDate && !blocks.unselectableDates?.length) {\n return true;\n }\n for (\n let d = addDays(first, 1), walked = 1;\n d.getTime() < last;\n d = addDays(d, 1), walked++\n ) {\n if (walked >= RANGE_WALK_LIMIT || isDayUnselectable(d, blocks)) {\n return false;\n }\n }\n return true;\n}\n\nexport function addDays(d: Date, n: number): Date {\n const r = new Date(d);\n r.setDate(r.getDate() + n);\n return r;\n}\n\nexport function addMonths(d: Date, n: number): Date {\n const r = new Date(d);\n const day = r.getDate();\n r.setDate(1);\n r.setMonth(r.getMonth() + n);\n // Clamp day to last day of new month if original day is out of range.\n const lastDay = makeDate(r.getFullYear(), r.getMonth() + 1, 0).getDate();\n r.setDate(Math.min(day, lastDay));\n return r;\n}\n\nexport function addYears(d: Date, n: number): Date {\n return addMonths(d, n * 12);\n}\n\nexport function addHours(d: Date, n: number): Date {\n const r = new Date(d);\n r.setHours(r.getHours() + n);\n return r;\n}\n\nexport function addMinutes(d: Date, n: number): Date {\n const r = new Date(d);\n r.setMinutes(r.getMinutes() + n);\n return r;\n}\n\nexport function addSeconds(d: Date, n: number): Date {\n const r = new Date(d);\n r.setSeconds(r.getSeconds() + n);\n return r;\n}\n\n/**\n * A copy of `d` with the given parts of its time of day set and the rest\n * left as they are. A time started from the clock rather than from a value\n * should pass the seconds its picker does not show, and the milliseconds,\n * as `0`, or it keeps the ones the clock had.\n */\nexport function setTimeOfDay(\n d: Date,\n parts: {\n hours?: number;\n minutes?: number;\n seconds?: number;\n milliseconds?: number;\n }\n): Date {\n const r = new Date(d);\n if (parts.hours !== undefined) r.setHours(parts.hours);\n if (parts.minutes !== undefined) r.setMinutes(parts.minutes);\n if (parts.seconds !== undefined) r.setSeconds(parts.seconds);\n if (parts.milliseconds !== undefined) r.setMilliseconds(parts.milliseconds);\n return r;\n}\n\nexport function getTimeOfDay(d: Date): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n return {\n hours: d.getHours(),\n minutes: d.getMinutes(),\n seconds: d.getSeconds(),\n };\n}\n\n/**\n * A copy of `d` moved into `[min, max]`. When `min` is after `max` nothing is\n * in range and `min` wins, so clamping twice gives the same date and a\n * picker's focus stays off the years before 1 under a `max` before then.\n */\nexport function clampDate(d: Date, min?: Date, max?: Date): Date {\n const capped = max && isAfter(d, max) ? max : d;\n return new Date(min && isBefore(capped, min) ? min : capped);\n}\n\n/**\n * Snap a Date's time-of-day to the nearest grid defined by the given\n * increment steps. Used by the \"Now\" button in pickers configured with\n * non-1 hour / minute / second steps so the committed time always lands on\n * a slot that exists on the wheel. Overflows roll up: e.g.\n * 13:58 with step=15 → 14:00. Seconds are zeroed when `enableSeconds` is\n * false, regardless of step.\n */\nexport function snapTimeToIncrement(\n d: Date,\n opts: {\n incrementHours?: number;\n incrementMinutes?: number;\n incrementSeconds?: number;\n enableSeconds?: boolean;\n } = {}\n): Date {\n const {\n incrementHours = 1,\n incrementMinutes = 1,\n incrementSeconds = 1,\n enableSeconds = false,\n } = opts;\n const r = new Date(d);\n let h = r.getHours();\n let m = r.getMinutes();\n let s = enableSeconds ? r.getSeconds() : 0;\n\n if (enableSeconds && incrementSeconds > 1) {\n s = Math.round(s / incrementSeconds) * incrementSeconds;\n if (s >= 60) {\n s -= 60;\n m += 1;\n }\n }\n\n if (incrementMinutes > 1) {\n m = Math.round(m / incrementMinutes) * incrementMinutes;\n if (m >= 60) {\n m -= 60;\n h += 1;\n }\n }\n\n if (incrementHours > 1) {\n h = Math.round(h / incrementHours) * incrementHours;\n // setHours handles 24+ overflow naturally (rolls forward into next day).\n }\n\n r.setHours(h, m, s, 0);\n return r;\n}\n\n/**\n * Build a 6-week × 7-day grid (42 cells) anchored on the month containing\n * `monthAnchor`. The first cell is the start of the week containing the first\n * of the month, where the week starts on `firstDayOfWeek`.\n */\nexport function buildMonthGrid(\n monthAnchor: Date,\n firstDayOfWeek: DayOfWeek = 0\n): CalendarCell[] {\n const monthStart = startOfMonth(monthAnchor);\n const firstWeekday = monthStart.getDay();\n const offset = (firstWeekday - firstDayOfWeek + 7) % 7;\n const gridStart = addDays(monthStart, -offset);\n const today = startOfDay(new Date());\n const cells: CalendarCell[] = [];\n for (let i = 0; i < 42; i++) {\n const date = addDays(gridStart, i);\n cells.push({\n date,\n inCurrentMonth: date.getMonth() === monthAnchor.getMonth(),\n isToday: isSameDay(date, today),\n });\n }\n return cells;\n}\n"],"names":[],"mappings":"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"}
|