@mortenbrudvik/waveui 0.4.0 → 0.8.0
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/README.md +1484 -173
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/components/button/Button.cjs +2 -0
- package/dist/components/button/Button.cjs.map +1 -0
- package/dist/components/button/Button.mjs +51 -0
- package/dist/components/button/Button.mjs.map +1 -0
- package/dist/components/button/Button.semantics.cjs +2 -0
- package/dist/components/button/Button.semantics.cjs.map +1 -0
- package/dist/components/button/Button.semantics.mjs +61 -0
- package/dist/components/button/Button.semantics.mjs.map +1 -0
- package/dist/components/button/Button.slots.cjs +2 -0
- package/dist/components/button/Button.slots.cjs.map +1 -0
- package/dist/components/button/Button.slots.mjs +57 -0
- package/dist/components/button/Button.slots.mjs.map +1 -0
- package/dist/components/button/CompoundButton.cjs +2 -0
- package/dist/components/button/CompoundButton.cjs.map +1 -0
- package/dist/components/button/CompoundButton.mjs +55 -0
- package/dist/components/button/CompoundButton.mjs.map +1 -0
- package/dist/components/button/Link.cjs +2 -0
- package/dist/components/button/Link.cjs.map +1 -0
- package/dist/components/button/Link.mjs +38 -0
- package/dist/components/button/Link.mjs.map +1 -0
- package/dist/components/button/MenuButton.cjs +2 -0
- package/dist/components/button/MenuButton.cjs.map +1 -0
- package/dist/components/button/MenuButton.mjs +46 -0
- package/dist/components/button/MenuButton.mjs.map +1 -0
- package/dist/components/button/SplitButton.cjs +2 -0
- package/dist/components/button/SplitButton.cjs.map +1 -0
- package/dist/components/button/SplitButton.mjs +67 -0
- package/dist/components/button/SplitButton.mjs.map +1 -0
- package/dist/components/button/ToggleButton.cjs +2 -0
- package/dist/components/button/ToggleButton.cjs.map +1 -0
- package/dist/components/button/ToggleButton.mjs +68 -0
- package/dist/components/button/ToggleButton.mjs.map +1 -0
- package/dist/components/button/Toolbar.cjs +2 -0
- package/dist/components/button/Toolbar.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.cjs +2 -0
- package/dist/components/button/Toolbar.context.cjs.map +1 -0
- package/dist/components/button/Toolbar.context.mjs +31 -0
- package/dist/components/button/Toolbar.context.mjs.map +1 -0
- package/dist/components/button/Toolbar.mjs +64 -0
- package/dist/components/button/Toolbar.mjs.map +1 -0
- package/dist/components/button/Toolbar.parts.cjs +2 -0
- package/dist/components/button/Toolbar.parts.cjs.map +1 -0
- package/dist/components/button/Toolbar.parts.mjs +126 -0
- package/dist/components/button/Toolbar.parts.mjs.map +1 -0
- package/dist/components/button/buttonStyles.cjs +2 -0
- package/dist/components/button/buttonStyles.cjs.map +1 -0
- package/dist/components/button/buttonStyles.mjs +39 -0
- package/dist/components/button/buttonStyles.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +2 -0
- package/dist/components/data-display/Avatar.cjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +162 -0
- package/dist/components/data-display/Avatar.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.mjs +135 -0
- package/dist/components/data-display/AvatarGroup.mjs.map +1 -0
- package/dist/components/data-display/Badge.cjs +2 -0
- package/dist/components/data-display/Badge.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.cjs +2 -0
- package/dist/components/data-display/Badge.colors.cjs.map +1 -0
- package/dist/components/data-display/Badge.colors.mjs +58 -0
- package/dist/components/data-display/Badge.colors.mjs.map +1 -0
- package/dist/components/data-display/Badge.mjs +33 -0
- package/dist/components/data-display/Badge.mjs.map +1 -0
- package/dist/components/data-display/CounterBadge.cjs +2 -0
- package/dist/components/data-display/CounterBadge.cjs.map +1 -0
- package/dist/components/data-display/CounterBadge.mjs +29 -0
- package/dist/components/data-display/CounterBadge.mjs.map +1 -0
- package/dist/components/data-display/Divider.cjs +2 -0
- package/dist/components/data-display/Divider.cjs.map +1 -0
- package/dist/components/data-display/Divider.mjs +53 -0
- package/dist/components/data-display/Divider.mjs.map +1 -0
- package/dist/components/data-display/Image.cjs +2 -0
- package/dist/components/data-display/Image.cjs.map +1 -0
- package/dist/components/data-display/Image.mjs +33 -0
- package/dist/components/data-display/Image.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +2 -0
- package/dist/components/data-display/InfoLabel.cjs.map +1 -0
- package/dist/components/data-display/InfoLabel.mjs +105 -0
- package/dist/components/data-display/InfoLabel.mjs.map +1 -0
- package/dist/components/data-display/List.cjs +2 -0
- package/dist/components/data-display/List.cjs.map +1 -0
- package/dist/components/data-display/List.mjs +382 -0
- package/dist/components/data-display/List.mjs.map +1 -0
- package/dist/components/data-display/List.registry.cjs +2 -0
- package/dist/components/data-display/List.registry.cjs.map +1 -0
- package/dist/components/data-display/List.registry.mjs +101 -0
- package/dist/components/data-display/List.registry.mjs.map +1 -0
- package/dist/components/data-display/Persona.cjs +2 -0
- package/dist/components/data-display/Persona.cjs.map +1 -0
- package/dist/components/data-display/Persona.mjs +50 -0
- package/dist/components/data-display/Persona.mjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.cjs +2 -0
- package/dist/components/data-display/PresenceBadge.cjs.map +1 -0
- package/dist/components/data-display/PresenceBadge.mjs +72 -0
- package/dist/components/data-display/PresenceBadge.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +2 -0
- package/dist/components/data-display/Tag.cjs.map +1 -0
- package/dist/components/data-display/Tag.mjs +152 -0
- package/dist/components/data-display/Tag.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.cjs +2 -0
- package/dist/components/feedback/MessageBar.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.mjs +202 -0
- package/dist/components/feedback/MessageBar.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.parts.cjs +2 -0
- package/dist/components/feedback/MessageBar.parts.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.parts.mjs +84 -0
- package/dist/components/feedback/MessageBar.parts.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.reflow.cjs +2 -0
- package/dist/components/feedback/MessageBar.reflow.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.reflow.mjs +74 -0
- package/dist/components/feedback/MessageBar.reflow.mjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.cjs +2 -0
- package/dist/components/feedback/MessageBar.status.cjs.map +1 -0
- package/dist/components/feedback/MessageBar.status.mjs +46 -0
- package/dist/components/feedback/MessageBar.status.mjs.map +1 -0
- package/dist/components/feedback/ProgressBar.cjs +2 -0
- package/dist/components/feedback/ProgressBar.cjs.map +1 -0
- package/dist/components/feedback/ProgressBar.mjs +73 -0
- package/dist/components/feedback/ProgressBar.mjs.map +1 -0
- package/dist/components/feedback/Skeleton.cjs +2 -0
- package/dist/components/feedback/Skeleton.cjs.map +1 -0
- package/dist/components/feedback/Skeleton.mjs +49 -0
- package/dist/components/feedback/Skeleton.mjs.map +1 -0
- package/dist/components/feedback/Spinner.cjs +2 -0
- package/dist/components/feedback/Spinner.cjs.map +1 -0
- package/dist/components/feedback/Spinner.mjs +61 -0
- package/dist/components/feedback/Spinner.mjs.map +1 -0
- package/dist/components/feedback/Toast.cjs +2 -0
- package/dist/components/feedback/Toast.cjs.map +1 -0
- package/dist/components/feedback/Toast.context.cjs +2 -0
- package/dist/components/feedback/Toast.context.cjs.map +1 -0
- package/dist/components/feedback/Toast.context.mjs +23 -0
- package/dist/components/feedback/Toast.context.mjs.map +1 -0
- package/dist/components/feedback/Toast.mjs +15 -0
- package/dist/components/feedback/Toast.mjs.map +1 -0
- package/dist/components/feedback/Toast.parts.cjs +2 -0
- package/dist/components/feedback/Toast.parts.cjs.map +1 -0
- package/dist/components/feedback/Toast.parts.mjs +98 -0
- package/dist/components/feedback/Toast.parts.mjs.map +1 -0
- package/dist/components/feedback/Toast.root.cjs +2 -0
- package/dist/components/feedback/Toast.root.cjs.map +1 -0
- package/dist/components/feedback/Toast.root.mjs +109 -0
- package/dist/components/feedback/Toast.root.mjs.map +1 -0
- package/dist/components/feedback/Toaster.cjs +2 -0
- package/dist/components/feedback/Toaster.cjs.map +1 -0
- package/dist/components/feedback/Toaster.mjs +564 -0
- package/dist/components/feedback/Toaster.mjs.map +1 -0
- package/dist/components/input/AlphaSlider.cjs +2 -0
- package/dist/components/input/AlphaSlider.cjs.map +1 -0
- package/dist/components/input/AlphaSlider.mjs +115 -0
- package/dist/components/input/AlphaSlider.mjs.map +1 -0
- package/dist/components/input/Checkbox.cjs +2 -0
- package/dist/components/input/Checkbox.cjs.map +1 -0
- package/dist/components/input/Checkbox.mjs +97 -0
- package/dist/components/input/Checkbox.mjs.map +1 -0
- package/dist/components/input/ColorArea.cjs +2 -0
- package/dist/components/input/ColorArea.cjs.map +1 -0
- package/dist/components/input/ColorArea.mjs +204 -0
- package/dist/components/input/ColorArea.mjs.map +1 -0
- package/dist/components/input/ColorPicker.cjs +6 -0
- package/dist/components/input/ColorPicker.cjs.map +1 -0
- package/dist/components/input/ColorPicker.mjs +213 -0
- package/dist/components/input/ColorPicker.mjs.map +1 -0
- package/dist/components/input/ColorPicker.parts.cjs +2 -0
- package/dist/components/input/ColorPicker.parts.cjs.map +1 -0
- package/dist/components/input/ColorPicker.parts.mjs +192 -0
- package/dist/components/input/ColorPicker.parts.mjs.map +1 -0
- package/dist/components/input/ColorSlider.cjs +2 -0
- package/dist/components/input/ColorSlider.cjs.map +1 -0
- package/dist/components/input/ColorSlider.mjs +138 -0
- package/dist/components/input/ColorSlider.mjs.map +1 -0
- package/dist/components/input/Combobox.cjs +2 -0
- package/dist/components/input/Combobox.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.cjs +2 -0
- package/dist/components/input/Combobox.expand.cjs.map +1 -0
- package/dist/components/input/Combobox.expand.mjs +38 -0
- package/dist/components/input/Combobox.expand.mjs.map +1 -0
- package/dist/components/input/Combobox.mjs +192 -0
- package/dist/components/input/Combobox.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +2 -0
- package/dist/components/input/DatePicker.cjs.map +1 -0
- package/dist/components/input/DatePicker.mjs +341 -0
- package/dist/components/input/DatePicker.mjs.map +1 -0
- package/dist/components/input/Dropdown.cjs +2 -0
- package/dist/components/input/Dropdown.cjs.map +1 -0
- package/dist/components/input/Dropdown.mjs +131 -0
- package/dist/components/input/Dropdown.mjs.map +1 -0
- package/dist/components/input/Field.cjs +2 -0
- package/dist/components/input/Field.cjs.map +1 -0
- package/dist/components/input/Field.mjs +201 -0
- package/dist/components/input/Field.mjs.map +1 -0
- package/dist/components/input/Input.cjs +2 -0
- package/dist/components/input/Input.cjs.map +1 -0
- package/dist/components/input/Input.mjs +82 -0
- package/dist/components/input/Input.mjs.map +1 -0
- package/dist/components/input/Label.cjs +2 -0
- package/dist/components/input/Label.cjs.map +1 -0
- package/dist/components/input/Label.mjs +29 -0
- package/dist/components/input/Label.mjs.map +1 -0
- package/dist/components/input/Option.cjs +2 -0
- package/dist/components/input/Option.cjs.map +1 -0
- package/dist/components/input/Option.mjs +171 -0
- package/dist/components/input/Option.mjs.map +1 -0
- package/dist/components/input/RadioGroup.cjs +2 -0
- package/dist/components/input/RadioGroup.cjs.map +1 -0
- package/dist/components/input/RadioGroup.mjs +140 -0
- package/dist/components/input/RadioGroup.mjs.map +1 -0
- package/dist/components/input/Rating.cjs +2 -0
- package/dist/components/input/Rating.cjs.map +1 -0
- package/dist/components/input/Rating.mjs +197 -0
- package/dist/components/input/Rating.mjs.map +1 -0
- package/dist/components/input/SearchBox.cjs +2 -0
- package/dist/components/input/SearchBox.cjs.map +1 -0
- package/dist/components/input/SearchBox.mjs +204 -0
- package/dist/components/input/SearchBox.mjs.map +1 -0
- package/dist/components/input/Select.cjs +2 -0
- package/dist/components/input/Select.cjs.map +1 -0
- package/dist/components/input/Select.mjs +34 -0
- package/dist/components/input/Select.mjs.map +1 -0
- package/dist/components/input/Slider.cjs +2 -0
- package/dist/components/input/Slider.cjs.map +1 -0
- package/dist/components/input/Slider.mjs +80 -0
- package/dist/components/input/Slider.mjs.map +1 -0
- package/dist/components/input/SpinButton.cjs +2 -0
- package/dist/components/input/SpinButton.cjs.map +1 -0
- package/dist/components/input/SpinButton.mjs +158 -0
- package/dist/components/input/SpinButton.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.cjs +2 -0
- package/dist/components/input/SwatchPicker.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +114 -0
- package/dist/components/input/SwatchPicker.mjs.map +1 -0
- package/dist/components/input/Switch.cjs +2 -0
- package/dist/components/input/Switch.cjs.map +1 -0
- package/dist/components/input/Switch.mjs +93 -0
- package/dist/components/input/Switch.mjs.map +1 -0
- package/dist/components/input/TagPicker.cjs +2 -0
- package/dist/components/input/TagPicker.cjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +253 -0
- package/dist/components/input/TagPicker.mjs.map +1 -0
- package/dist/components/input/Textarea.cjs +2 -0
- package/dist/components/input/Textarea.cjs.map +1 -0
- package/dist/components/input/Textarea.mjs +33 -0
- package/dist/components/input/Textarea.mjs.map +1 -0
- package/dist/components/input/TimePicker.cjs +2 -0
- package/dist/components/input/TimePicker.cjs.map +1 -0
- package/dist/components/input/TimePicker.mjs +295 -0
- package/dist/components/input/TimePicker.mjs.map +1 -0
- package/dist/components/input/colorName.cjs +2 -0
- package/dist/components/input/colorName.cjs.map +1 -0
- package/dist/components/input/colorName.mjs +30 -0
- package/dist/components/input/colorName.mjs.map +1 -0
- package/dist/components/input/colorUtils.cjs +2 -0
- package/dist/components/input/colorUtils.cjs.map +1 -0
- package/dist/components/input/colorUtils.mjs +194 -0
- package/dist/components/input/colorUtils.mjs.map +1 -0
- package/dist/components/input/dateUtils.cjs +2 -0
- package/dist/components/input/dateUtils.cjs.map +1 -0
- package/dist/components/input/dateUtils.mjs +250 -0
- package/dist/components/input/dateUtils.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +2 -0
- package/dist/components/input/pickerStyles.cjs.map +1 -0
- package/dist/components/input/pickerStyles.mjs +10 -0
- package/dist/components/input/pickerStyles.mjs.map +1 -0
- package/dist/components/internal/HiddenInput.cjs +2 -0
- package/dist/components/internal/HiddenInput.cjs.map +1 -0
- package/dist/components/internal/HiddenInput.mjs +88 -0
- package/dist/components/internal/HiddenInput.mjs.map +1 -0
- package/dist/components/layout/Accordion.cjs +2 -0
- package/dist/components/layout/Accordion.cjs.map +1 -0
- package/dist/components/layout/Accordion.mjs +237 -0
- package/dist/components/layout/Accordion.mjs.map +1 -0
- package/dist/components/layout/Card.cjs +2 -0
- package/dist/components/layout/Card.cjs.map +1 -0
- package/dist/components/layout/Card.mjs +122 -0
- package/dist/components/layout/Card.mjs.map +1 -0
- package/dist/components/layout/Carousel.cjs +2 -0
- package/dist/components/layout/Carousel.cjs.map +1 -0
- package/dist/components/layout/Carousel.mjs +206 -0
- package/dist/components/layout/Carousel.mjs.map +1 -0
- package/dist/components/layout/Flex.cjs +2 -0
- package/dist/components/layout/Flex.cjs.map +1 -0
- package/dist/components/layout/Flex.mjs +55 -0
- package/dist/components/layout/Flex.mjs.map +1 -0
- package/dist/components/layout/Grid.cjs +2 -0
- package/dist/components/layout/Grid.cjs.map +1 -0
- package/dist/components/layout/Grid.mjs +63 -0
- package/dist/components/layout/Grid.mjs.map +1 -0
- package/dist/components/layout/Overflow.cjs +2 -0
- package/dist/components/layout/Overflow.cjs.map +1 -0
- package/dist/components/layout/Overflow.mjs +270 -0
- package/dist/components/layout/Overflow.mjs.map +1 -0
- package/dist/components/layout/Stack.cjs +2 -0
- package/dist/components/layout/Stack.cjs.map +1 -0
- package/dist/components/layout/Stack.mjs +40 -0
- package/dist/components/layout/Stack.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +2 -0
- package/dist/components/layout/TabList.cjs.map +1 -0
- package/dist/components/layout/TabList.mjs +239 -0
- package/dist/components/layout/TabList.mjs.map +1 -0
- package/dist/components/layout/Tree.cjs +2 -0
- package/dist/components/layout/Tree.cjs.map +1 -0
- package/dist/components/layout/Tree.context.cjs +2 -0
- package/dist/components/layout/Tree.context.cjs.map +1 -0
- package/dist/components/layout/Tree.context.mjs +33 -0
- package/dist/components/layout/Tree.context.mjs.map +1 -0
- package/dist/components/layout/Tree.core.cjs +2 -0
- package/dist/components/layout/Tree.core.cjs.map +1 -0
- package/dist/components/layout/Tree.core.mjs +416 -0
- package/dist/components/layout/Tree.core.mjs.map +1 -0
- package/dist/components/layout/Tree.itemPersonaLayout.cjs +2 -0
- package/dist/components/layout/Tree.itemPersonaLayout.cjs.map +1 -0
- package/dist/components/layout/Tree.itemPersonaLayout.mjs +46 -0
- package/dist/components/layout/Tree.itemPersonaLayout.mjs.map +1 -0
- package/dist/components/layout/Tree.mjs +12 -0
- package/dist/components/layout/Tree.mjs.map +1 -0
- package/dist/components/layout/Tree.selection.cjs +2 -0
- package/dist/components/layout/Tree.selection.cjs.map +1 -0
- package/dist/components/layout/Tree.selection.mjs +73 -0
- package/dist/components/layout/Tree.selection.mjs.map +1 -0
- package/dist/components/layout/disclosureIds.cjs +2 -0
- package/dist/components/layout/disclosureIds.cjs.map +1 -0
- package/dist/components/layout/disclosureIds.mjs +12 -0
- package/dist/components/layout/disclosureIds.mjs.map +1 -0
- package/dist/components/motion/Presence.cjs +2 -0
- package/dist/components/motion/Presence.cjs.map +1 -0
- package/dist/components/motion/Presence.mjs +35 -0
- package/dist/components/motion/Presence.mjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.cjs +2 -0
- package/dist/components/navigation/Breadcrumb.cjs.map +1 -0
- package/dist/components/navigation/Breadcrumb.mjs +145 -0
- package/dist/components/navigation/Breadcrumb.mjs.map +1 -0
- package/dist/components/navigation/Menu.cjs +2 -0
- package/dist/components/navigation/Menu.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.cjs +2 -0
- package/dist/components/navigation/Menu.context.cjs.map +1 -0
- package/dist/components/navigation/Menu.context.mjs +82 -0
- package/dist/components/navigation/Menu.context.mjs.map +1 -0
- package/dist/components/navigation/Menu.group.cjs +2 -0
- package/dist/components/navigation/Menu.group.cjs.map +1 -0
- package/dist/components/navigation/Menu.group.mjs +60 -0
- package/dist/components/navigation/Menu.group.mjs.map +1 -0
- package/dist/components/navigation/Menu.items.cjs +2 -0
- package/dist/components/navigation/Menu.items.cjs.map +1 -0
- package/dist/components/navigation/Menu.items.mjs +133 -0
- package/dist/components/navigation/Menu.items.mjs.map +1 -0
- package/dist/components/navigation/Menu.link.cjs +2 -0
- package/dist/components/navigation/Menu.link.cjs.map +1 -0
- package/dist/components/navigation/Menu.link.mjs +47 -0
- package/dist/components/navigation/Menu.link.mjs.map +1 -0
- package/dist/components/navigation/Menu.mjs +27 -0
- package/dist/components/navigation/Menu.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +2 -0
- package/dist/components/navigation/Menu.popover.cjs.map +1 -0
- package/dist/components/navigation/Menu.popover.mjs +232 -0
- package/dist/components/navigation/Menu.popover.mjs.map +1 -0
- package/dist/components/navigation/Menu.root.cjs +2 -0
- package/dist/components/navigation/Menu.root.cjs.map +1 -0
- package/dist/components/navigation/Menu.root.mjs +309 -0
- package/dist/components/navigation/Menu.root.mjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.cjs +2 -0
- package/dist/components/navigation/Menu.selectable.cjs.map +1 -0
- package/dist/components/navigation/Menu.selectable.mjs +111 -0
- package/dist/components/navigation/Menu.selectable.mjs.map +1 -0
- package/dist/components/navigation/Menu.shared.cjs +2 -0
- package/dist/components/navigation/Menu.shared.cjs.map +1 -0
- package/dist/components/navigation/Menu.shared.mjs +23 -0
- package/dist/components/navigation/Menu.shared.mjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.cjs +2 -0
- package/dist/components/navigation/Menu.splitGroup.cjs.map +1 -0
- package/dist/components/navigation/Menu.splitGroup.mjs +52 -0
- package/dist/components/navigation/Menu.splitGroup.mjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.cjs +2 -0
- package/dist/components/navigation/Menu.trigger.cjs.map +1 -0
- package/dist/components/navigation/Menu.trigger.mjs +79 -0
- package/dist/components/navigation/Menu.trigger.mjs.map +1 -0
- package/dist/components/navigation/Nav.cjs +2 -0
- package/dist/components/navigation/Nav.cjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +291 -0
- package/dist/components/navigation/Nav.mjs.map +1 -0
- package/dist/components/navigation/Pagination.cjs +2 -0
- package/dist/components/navigation/Pagination.cjs.map +1 -0
- package/dist/components/navigation/Pagination.mjs +118 -0
- package/dist/components/navigation/Pagination.mjs.map +1 -0
- package/dist/components/navigation/Stepper.cjs +2 -0
- package/dist/components/navigation/Stepper.cjs.map +1 -0
- package/dist/components/navigation/Stepper.mjs +205 -0
- package/dist/components/navigation/Stepper.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +2 -0
- package/dist/components/overlays/Dialog.cjs.map +1 -0
- package/dist/components/overlays/Dialog.mjs +181 -0
- package/dist/components/overlays/Dialog.mjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.cjs +2 -0
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -0
- package/dist/components/overlays/Dialog.shared.mjs +227 -0
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +2 -0
- package/dist/components/overlays/Drawer.cjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +193 -0
- package/dist/components/overlays/Drawer.mjs.map +1 -0
- package/dist/components/overlays/Popover.cjs +2 -0
- package/dist/components/overlays/Popover.cjs.map +1 -0
- package/dist/components/overlays/Popover.mjs +367 -0
- package/dist/components/overlays/Popover.mjs.map +1 -0
- package/dist/components/overlays/Popover.shared.cjs +2 -0
- package/dist/components/overlays/Popover.shared.cjs.map +1 -0
- package/dist/components/overlays/Popover.shared.mjs +182 -0
- package/dist/components/overlays/Popover.shared.mjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.cjs +2 -0
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -0
- package/dist/components/overlays/TeachingPopover.mjs +185 -0
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -0
- package/dist/components/overlays/Tooltip.cjs +2 -0
- package/dist/components/overlays/Tooltip.cjs.map +1 -0
- package/dist/components/overlays/Tooltip.mjs +161 -0
- package/dist/components/overlays/Tooltip.mjs.map +1 -0
- package/dist/components/portal/Portal.cjs +2 -0
- package/dist/components/portal/Portal.cjs.map +1 -0
- package/dist/components/portal/Portal.mjs +46 -0
- package/dist/components/portal/Portal.mjs.map +1 -0
- package/dist/components/provider/WaveProvider.cjs +2 -0
- package/dist/components/provider/WaveProvider.cjs.map +1 -0
- package/dist/components/provider/WaveProvider.mjs +52 -0
- package/dist/components/provider/WaveProvider.mjs.map +1 -0
- package/dist/components/table/DataGrid.cjs +2 -0
- package/dist/components/table/DataGrid.cjs.map +1 -0
- package/dist/components/table/DataGrid.mjs +490 -0
- package/dist/components/table/DataGrid.mjs.map +1 -0
- package/dist/components/table/Table.cjs +2 -0
- package/dist/components/table/Table.cjs.map +1 -0
- package/dist/components/table/Table.mjs +100 -0
- package/dist/components/table/Table.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +2 -0
- package/dist/components/table/useGridNavigation.cjs.map +1 -0
- package/dist/components/table/useGridNavigation.mjs +336 -0
- package/dist/components/table/useGridNavigation.mjs.map +1 -0
- package/dist/components/typography/Text.cjs +2 -0
- package/dist/components/typography/Text.cjs.map +1 -0
- package/dist/components/typography/Text.mjs +39 -0
- package/dist/components/typography/Text.mjs.map +1 -0
- package/dist/hooks/useAnnounce.cjs +2 -0
- package/dist/hooks/useAnnounce.cjs.map +1 -0
- package/dist/hooks/useAnnounce.mjs +88 -0
- package/dist/hooks/useAnnounce.mjs.map +1 -0
- package/dist/hooks/useCheckedValues.cjs +2 -0
- package/dist/hooks/useCheckedValues.cjs.map +1 -0
- package/dist/hooks/useCheckedValues.mjs +102 -0
- package/dist/hooks/useCheckedValues.mjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.cjs +2 -0
- package/dist/hooks/useContextMenuAnchor.cjs.map +1 -0
- package/dist/hooks/useContextMenuAnchor.mjs +132 -0
- package/dist/hooks/useContextMenuAnchor.mjs.map +1 -0
- package/dist/hooks/useControllable.cjs +2 -0
- package/dist/hooks/useControllable.cjs.map +1 -0
- package/dist/hooks/useControllable.mjs +37 -0
- package/dist/hooks/useControllable.mjs.map +1 -0
- package/dist/hooks/useDirection.cjs +2 -0
- package/dist/hooks/useDirection.cjs.map +1 -0
- package/dist/hooks/useDirection.mjs +57 -0
- package/dist/hooks/useDirection.mjs.map +1 -0
- package/dist/hooks/useDismiss.cjs +2 -0
- package/dist/hooks/useDismiss.cjs.map +1 -0
- package/dist/hooks/useDismiss.mjs +57 -0
- package/dist/hooks/useDismiss.mjs.map +1 -0
- package/dist/hooks/useEventCallback.cjs +2 -0
- package/dist/hooks/useEventCallback.cjs.map +1 -0
- package/dist/hooks/useEventCallback.mjs +16 -0
- package/dist/hooks/useEventCallback.mjs.map +1 -0
- package/dist/hooks/useFieldControl.cjs +2 -0
- package/dist/hooks/useFieldControl.cjs.map +1 -0
- package/dist/hooks/useFieldControl.mjs +62 -0
- package/dist/hooks/useFieldControl.mjs.map +1 -0
- package/dist/hooks/useFocusTrap.cjs +2 -0
- package/dist/hooks/useFocusTrap.cjs.map +1 -0
- package/dist/hooks/useFocusTrap.mjs +266 -0
- package/dist/hooks/useFocusTrap.mjs.map +1 -0
- package/dist/hooks/useFormReset.cjs +2 -0
- package/dist/hooks/useFormReset.cjs.map +1 -0
- package/dist/hooks/useFormReset.mjs +33 -0
- package/dist/hooks/useFormReset.mjs.map +1 -0
- package/dist/hooks/useHoverIntent.cjs +2 -0
- package/dist/hooks/useHoverIntent.cjs.map +1 -0
- package/dist/hooks/useHoverIntent.mjs +201 -0
- package/dist/hooks/useHoverIntent.mjs.map +1 -0
- package/dist/hooks/useId.cjs +2 -0
- package/dist/hooks/useId.cjs.map +1 -0
- package/dist/hooks/useId.mjs +11 -0
- package/dist/hooks/useId.mjs.map +1 -0
- package/dist/hooks/useIsClient.cjs +2 -0
- package/dist/hooks/useIsClient.cjs.map +1 -0
- package/dist/hooks/useIsClient.mjs +19 -0
- package/dist/hooks/useIsClient.mjs.map +1 -0
- package/dist/hooks/useListbox.cjs +2 -0
- package/dist/hooks/useListbox.cjs.map +1 -0
- package/dist/hooks/useListbox.mjs +492 -0
- package/dist/hooks/useListbox.mjs.map +1 -0
- package/dist/hooks/useMediaQuery.cjs +2 -0
- package/dist/hooks/useMediaQuery.cjs.map +1 -0
- package/dist/hooks/useMediaQuery.mjs +20 -0
- package/dist/hooks/useMediaQuery.mjs.map +1 -0
- package/dist/hooks/useMergedRefs.cjs +2 -0
- package/dist/hooks/useMergedRefs.cjs.map +1 -0
- package/dist/hooks/useMergedRefs.mjs +57 -0
- package/dist/hooks/useMergedRefs.mjs.map +1 -0
- package/dist/hooks/useModalIsolation.cjs +2 -0
- package/dist/hooks/useModalIsolation.cjs.map +1 -0
- package/dist/hooks/useModalIsolation.mjs +87 -0
- package/dist/hooks/useModalIsolation.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +2 -0
- package/dist/hooks/useModalLayer.cjs.map +1 -0
- package/dist/hooks/useModalLayer.mjs +30 -0
- package/dist/hooks/useModalLayer.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +2 -0
- package/dist/hooks/usePopupPosition.cjs.map +1 -0
- package/dist/hooks/usePopupPosition.mjs +117 -0
- package/dist/hooks/usePopupPosition.mjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.cjs +2 -0
- package/dist/hooks/usePrefersReducedMotion.cjs.map +1 -0
- package/dist/hooks/usePrefersReducedMotion.mjs +10 -0
- package/dist/hooks/usePrefersReducedMotion.mjs.map +1 -0
- package/dist/hooks/usePresence.cjs +2 -0
- package/dist/hooks/usePresence.cjs.map +1 -0
- package/dist/hooks/usePresence.mjs +136 -0
- package/dist/hooks/usePresence.mjs.map +1 -0
- package/dist/hooks/usePreserveFocus.cjs +2 -0
- package/dist/hooks/usePreserveFocus.cjs.map +1 -0
- package/dist/hooks/usePreserveFocus.mjs +50 -0
- package/dist/hooks/usePreserveFocus.mjs.map +1 -0
- package/dist/hooks/useRestoreFocus.cjs +2 -0
- package/dist/hooks/useRestoreFocus.cjs.map +1 -0
- package/dist/hooks/useRestoreFocus.mjs +271 -0
- package/dist/hooks/useRestoreFocus.mjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.cjs +2 -0
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -0
- package/dist/hooks/useRovingTabIndex.mjs +389 -0
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -0
- package/dist/hooks/useScrollLock.cjs +2 -0
- package/dist/hooks/useScrollLock.cjs.map +1 -0
- package/dist/hooks/useScrollLock.mjs +71 -0
- package/dist/hooks/useScrollLock.mjs.map +1 -0
- package/dist/hooks/useTriggerElement.cjs +2 -0
- package/dist/hooks/useTriggerElement.cjs.map +1 -0
- package/dist/hooks/useTriggerElement.mjs +126 -0
- package/dist/hooks/useTriggerElement.mjs.map +1 -0
- package/dist/hooks/useTypeahead.cjs +2 -0
- package/dist/hooks/useTypeahead.cjs.map +1 -0
- package/dist/hooks/useTypeahead.mjs +38 -0
- package/dist/hooks/useTypeahead.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +11086 -0
- package/dist/index.d.ts +10405 -1757
- package/dist/index.mjs +103 -5695
- package/dist/lib/aria.cjs +2 -0
- package/dist/lib/aria.cjs.map +1 -0
- package/dist/lib/aria.mjs +29 -0
- package/dist/lib/aria.mjs.map +1 -0
- package/dist/lib/children.cjs +2 -0
- package/dist/lib/children.cjs.map +1 -0
- package/dist/lib/children.mjs +37 -0
- package/dist/lib/children.mjs.map +1 -0
- package/dist/lib/classNames.cjs +2 -0
- package/dist/lib/classNames.cjs.map +1 -0
- package/dist/lib/classNames.mjs +415 -0
- package/dist/lib/classNames.mjs.map +1 -0
- package/dist/lib/cn.cjs +2 -0
- package/dist/lib/cn.cjs.map +1 -0
- package/dist/lib/cn.mjs +64 -0
- package/dist/lib/cn.mjs.map +1 -0
- package/dist/lib/color.cjs +2 -0
- package/dist/lib/color.cjs.map +1 -0
- package/dist/lib/color.mjs +86 -0
- package/dist/lib/color.mjs.map +1 -0
- package/dist/lib/composeEventHandlers.cjs +2 -0
- package/dist/lib/composeEventHandlers.cjs.map +1 -0
- package/dist/lib/composeEventHandlers.mjs +11 -0
- package/dist/lib/composeEventHandlers.mjs.map +1 -0
- package/dist/lib/dev.cjs +2 -0
- package/dist/lib/dev.cjs.map +1 -0
- package/dist/lib/dev.mjs +42 -0
- package/dist/lib/dev.mjs.map +1 -0
- package/dist/lib/direction.cjs +2 -0
- package/dist/lib/direction.cjs.map +1 -0
- package/dist/lib/direction.mjs +35 -0
- package/dist/lib/direction.mjs.map +1 -0
- package/dist/lib/events.cjs +2 -0
- package/dist/lib/events.cjs.map +1 -0
- package/dist/lib/events.mjs +31 -0
- package/dist/lib/events.mjs.map +1 -0
- package/dist/lib/focus.cjs +2 -0
- package/dist/lib/focus.cjs.map +1 -0
- package/dist/lib/focus.mjs +119 -0
- package/dist/lib/focus.mjs.map +1 -0
- package/dist/lib/globalRegistry.cjs +2 -0
- package/dist/lib/globalRegistry.cjs.map +1 -0
- package/dist/lib/globalRegistry.mjs +13 -0
- package/dist/lib/globalRegistry.mjs.map +1 -0
- package/dist/lib/icons.cjs +2 -0
- package/dist/lib/icons.cjs.map +1 -0
- package/dist/lib/icons.mjs +254 -0
- package/dist/lib/icons.mjs.map +1 -0
- package/dist/lib/labelInName.cjs +2 -0
- package/dist/lib/labelInName.cjs.map +1 -0
- package/dist/lib/labelInName.mjs +54 -0
- package/dist/lib/labelInName.mjs.map +1 -0
- package/dist/lib/layers.cjs +2 -0
- package/dist/lib/layers.cjs.map +1 -0
- package/dist/lib/layers.mjs +224 -0
- package/dist/lib/layers.mjs.map +1 -0
- package/dist/lib/mergeProps.cjs +2 -0
- package/dist/lib/mergeProps.cjs.map +1 -0
- package/dist/lib/mergeProps.mjs +21 -0
- package/dist/lib/mergeProps.mjs.map +1 -0
- package/dist/lib/mergeRefs.cjs +2 -0
- package/dist/lib/mergeRefs.cjs.map +1 -0
- package/dist/lib/mergeRefs.mjs +29 -0
- package/dist/lib/mergeRefs.mjs.map +1 -0
- package/dist/lib/renderTrigger.cjs +2 -0
- package/dist/lib/renderTrigger.cjs.map +1 -0
- package/dist/lib/renderTrigger.mjs +29 -0
- package/dist/lib/renderTrigger.mjs.map +1 -0
- package/dist/lib/slot.cjs +2 -0
- package/dist/lib/slot.cjs.map +1 -0
- package/dist/lib/slot.mjs +122 -0
- package/dist/lib/slot.mjs.map +1 -0
- package/dist/lib/styles.cjs +2 -0
- package/dist/lib/styles.cjs.map +1 -0
- package/dist/lib/styles.mjs +16 -0
- package/dist/lib/styles.mjs.map +1 -0
- package/dist/lib/theme.cjs +2 -0
- package/dist/lib/theme.cjs.map +1 -0
- package/dist/lib/theme.mjs +16 -0
- package/dist/lib/theme.mjs.map +1 -0
- package/dist/lib/toaster.cjs +2 -0
- package/dist/lib/toaster.cjs.map +1 -0
- package/dist/lib/toaster.mjs +77 -0
- package/dist/lib/toaster.mjs.map +1 -0
- package/dist/preflight.css +2 -0
- package/dist/styles.css +2 -0
- package/package.json +149 -100
- package/src/styles/animations.css +7 -39
- package/src/styles/base.css +103 -0
- package/src/styles/globals.css +10 -22
- package/src/styles/legacy-tokens.css +184 -0
- package/src/styles/preflight.css +7 -0
- package/src/styles/styles.css +32 -0
- package/src/styles/tailwind.css +17 -0
- package/src/styles/tokens.css +561 -221
- package/src/styles/variants.css +29 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { warnDeprecated as t, warnOnce as n } from "../../lib/dev.mjs";
|
|
4
|
+
import { composeEventHandlers as r } from "../../lib/composeEventHandlers.mjs";
|
|
5
|
+
import { timePickerClassNames as i } from "../../lib/classNames.mjs";
|
|
6
|
+
import { useControllable as a } from "../../hooks/useControllable.mjs";
|
|
7
|
+
import { useId as ee } from "../../hooks/useId.mjs";
|
|
8
|
+
import { useMergedRefs as o } from "../../hooks/useMergedRefs.mjs";
|
|
9
|
+
import { useIsClient as te } from "../../hooks/useIsClient.mjs";
|
|
10
|
+
import { joinIds as ne } from "../../lib/aria.mjs";
|
|
11
|
+
import { useFieldContext as re, useFieldControl as ie } from "../../hooks/useFieldControl.mjs";
|
|
12
|
+
import { useDismiss as ae } from "../../hooks/useDismiss.mjs";
|
|
13
|
+
import { Portal as oe } from "../portal/Portal.mjs";
|
|
14
|
+
import { disabledStyles as se, forcedColors as s, inputBase as ce, inputFocus as le } from "../../lib/styles.mjs";
|
|
15
|
+
import { CheckIcon as c, DismissIcon as ue } from "../../lib/icons.mjs";
|
|
16
|
+
import { isInvalidLook as de } from "./Input.mjs";
|
|
17
|
+
import { useFormReset as fe } from "../../hooks/useFormReset.mjs";
|
|
18
|
+
import { HiddenInput as pe } from "../internal/HiddenInput.mjs";
|
|
19
|
+
import { ListboxContext as me, useListbox as he, useListboxOption as l } from "../../hooks/useListbox.mjs";
|
|
20
|
+
import { pickerEndPadding as ge } from "./pickerStyles.mjs";
|
|
21
|
+
import { PickerExpandButton as _e, showsExpandButton as ve } from "./Combobox.expand.mjs";
|
|
22
|
+
import { usePopupPosition as ye } from "../../hooks/usePopupPosition.mjs";
|
|
23
|
+
import { generateTimeOptions as be, minutesToTime as xe, minutesToValue as u, normalizeTimeStep as Se, timeToMinutes as d } from "./dateUtils.mjs";
|
|
24
|
+
import * as f from "react";
|
|
25
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
26
|
+
import { flushSync as Ce } from "react-dom";
|
|
27
|
+
//#region src/components/input/TimePicker.tsx
|
|
28
|
+
var h = "flex cursor-pointer items-center gap-2 px-3 py-1.5 text-body-1 text-foreground hover:bg-subtle-hover data-[active]:bg-subtle-hover data-[active]:outline-2 data-[active]:outline-ring data-[active]:-outline-offset-2 data-[selected]:bg-subtle-selected data-[selected]:font-semibold", we = f.memo(function({ value: t, label: n }) {
|
|
29
|
+
let { selected: r, optionProps: a } = l({
|
|
30
|
+
value: t,
|
|
31
|
+
label: n
|
|
32
|
+
});
|
|
33
|
+
return /* @__PURE__ */ m("li", {
|
|
34
|
+
...a,
|
|
35
|
+
className: e(i.option, h, r && s.selectedContainer),
|
|
36
|
+
children: [/* @__PURE__ */ p("span", {
|
|
37
|
+
className: e(i.checkIcon, "flex h-4 w-4 shrink-0 items-center justify-center"),
|
|
38
|
+
children: r ? /* @__PURE__ */ p(c, { size: 12 }) : null
|
|
39
|
+
}), n]
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
we.displayName = "TimePickerOption";
|
|
43
|
+
var Te = (e) => `Enter a time in the format ${e}.`, Ee = (e, t) => e !== void 0 && t !== void 0 ? `Enter a time between ${e} and ${t}.` : e === void 0 ? `Enter a time on or before ${t}.` : `Enter a time on or after ${e}.`;
|
|
44
|
+
function g(e, t) {
|
|
45
|
+
let n = d(e);
|
|
46
|
+
return Number.isNaN(n) ? e : xe(n, t);
|
|
47
|
+
}
|
|
48
|
+
function De(e, t) {
|
|
49
|
+
return e.label.toLowerCase().includes(t) || e.value.includes(t);
|
|
50
|
+
}
|
|
51
|
+
function Oe(e, t) {
|
|
52
|
+
return e.label.toLowerCase().startsWith(t) || e.value.startsWith(t);
|
|
53
|
+
}
|
|
54
|
+
var _ = (s) => {
|
|
55
|
+
let { value: c, defaultValue: l, onValueChange: xe, onChange: h, format: _ = "12h", step: v = 30, minTime: y = "00:00", maxTime: b = "23:59", placeholder: ke = "Select a time", disabled: x = !1, readOnly: S, clearable: Ae = !1, expandIcon: je, open: Me, defaultOpen: Ne, onOpenChange: Pe, onInvalidInput: Fe, labels: C, name: Ie, form: Le, required: Re, autoComplete: ze = "off", autoCapitalize: Be, autoCorrect: Ve, maxLength: He, enterKeyHint: Ue, inputMode: We, spellCheck: Ge, autoFocus: Ke, tabIndex: qe, id: Je, "aria-label": Ye, "aria-labelledby": Xe, "aria-describedby": Ze, "aria-invalid": Qe, "aria-required": $e, "aria-errormessage": et, "aria-details": tt, onFocus: nt, onBlur: rt, onKeyDown: it, onKeyUp: at, controlRef: ot, className: st, ref: ct, ...lt } = s;
|
|
56
|
+
h !== void 0 && t("TimePicker", "onChange", "onValueChange");
|
|
57
|
+
let [w, T] = a(c, l ?? "", (e) => {
|
|
58
|
+
xe?.(e), h?.(e);
|
|
59
|
+
}), ut = Se(v).valid, E = d(y), D = d(b), O = !Number.isNaN(E) && !Number.isNaN(D) && E <= D, k = f.useMemo(() => be(v, y, b, _), [
|
|
60
|
+
v,
|
|
61
|
+
y,
|
|
62
|
+
b,
|
|
63
|
+
_
|
|
64
|
+
]);
|
|
65
|
+
f.useEffect(() => {
|
|
66
|
+
ut || n(`TimePicker:step:${String(v)}`, `TimePicker: \`step\` must be a positive number of minutes (received ${String(v)}); using 30.`);
|
|
67
|
+
}, [v, ut]), f.useEffect(() => {
|
|
68
|
+
O || n(`TimePicker:bounds:${y}|${b}`, `TimePicker: \`minTime\`/\`maxTime\` must be times such as "09:00", "09:00:00" or "9:00 AM" with minTime <= maxTime (received "${y}" / "${b}"); no times are available.`);
|
|
69
|
+
}, [
|
|
70
|
+
y,
|
|
71
|
+
b,
|
|
72
|
+
O
|
|
73
|
+
]);
|
|
74
|
+
let A = !x && !S, [j, M, dt] = a(Me, (Ne ?? !1) && A, Pe), ft = te(), N = j && A && ft;
|
|
75
|
+
f.useEffect(() => {
|
|
76
|
+
!A && j && !dt && M(!1);
|
|
77
|
+
}, [
|
|
78
|
+
A,
|
|
79
|
+
j,
|
|
80
|
+
dt,
|
|
81
|
+
M
|
|
82
|
+
]);
|
|
83
|
+
let [P, F] = f.useState(null), [I, L] = f.useState(null), [pt, mt] = f.useState(A);
|
|
84
|
+
pt !== A && (mt(A), A || (F(null), L(null)));
|
|
85
|
+
let [ht, gt] = f.useState(w);
|
|
86
|
+
ht !== w && (gt(w), I !== null && (F(null), L(null)));
|
|
87
|
+
let _t = P ?? "", vt = () => {
|
|
88
|
+
A && !N && M(!0);
|
|
89
|
+
}, R = () => M(!1), z = f.useMemo(() => {
|
|
90
|
+
let e = _t.trim().toLowerCase();
|
|
91
|
+
if (!e) return;
|
|
92
|
+
let t = d(e), n = Number.isNaN(t) ? null : u(t);
|
|
93
|
+
return (t) => t.value === n || De(t, e);
|
|
94
|
+
}, [_t]), B = (e) => {
|
|
95
|
+
let t = e.trim().toLowerCase();
|
|
96
|
+
if (!t) return null;
|
|
97
|
+
let n = d(e);
|
|
98
|
+
if (!Number.isNaN(n)) {
|
|
99
|
+
let e = u(n);
|
|
100
|
+
return k.some((t) => t.value === e) ? e : null;
|
|
101
|
+
}
|
|
102
|
+
return (k.find((e) => Oe(e, t)) ?? k.find((e) => De(e, t)))?.value ?? null;
|
|
103
|
+
}, yt = w !== "" && k.some((e) => e.value === w), bt = f.useMemo(() => w ? [w] : [], [w]), V = (e) => {
|
|
104
|
+
T(e), F(null), L(null);
|
|
105
|
+
}, H = (e) => {
|
|
106
|
+
if (!e.trim()) return V(""), null;
|
|
107
|
+
let t = d(e);
|
|
108
|
+
return Number.isNaN(t) ? "unparseable" : !O || t < E || t > D ? "out-of-range" : (V(u(t)), null);
|
|
109
|
+
}, xt = (e, t) => {
|
|
110
|
+
L(t), Fe?.(e, t);
|
|
111
|
+
}, U = () => {
|
|
112
|
+
F(null), L(null);
|
|
113
|
+
}, W = f.useMemo(() => z ? k.some(z) : k.length > 0, [k, z]), G = N && W, K = he({
|
|
114
|
+
open: G,
|
|
115
|
+
onOpenChange: (e) => e ? vt() : R(),
|
|
116
|
+
mode: "editable",
|
|
117
|
+
selectedValues: bt,
|
|
118
|
+
onSelect: (e) => V(e),
|
|
119
|
+
items: k,
|
|
120
|
+
filter: z,
|
|
121
|
+
autoHighlight: P === null && yt ? "selected" : !1,
|
|
122
|
+
idPrefix: "timepicker-listbox",
|
|
123
|
+
onClearDraft: P === null ? void 0 : () => {
|
|
124
|
+
U(), R();
|
|
125
|
+
}
|
|
126
|
+
}), St = w ? K.getItem(w)?.label ?? g(w, _) : "", q = Ae && !S && w !== "", Ct = N && !W ? k.length === 0 ? C?.noTimes ?? "No times available" : C?.noMatches ?? "No matching times" : "", wt = f.useRef(null), J = f.useRef(null), Tt = f.useRef(null), Et = o(ct, wt), Dt = o(ot, J), { layerId: Ot } = ae({
|
|
127
|
+
open: N,
|
|
128
|
+
onDismiss: R,
|
|
129
|
+
refs: [Tt, wt],
|
|
130
|
+
anchorRef: J,
|
|
131
|
+
kind: "listbox",
|
|
132
|
+
focusOutside: !0
|
|
133
|
+
}), { setReference: kt, setFloating: At, floatingProps: jt } = ye({
|
|
134
|
+
open: N,
|
|
135
|
+
side: "bottom",
|
|
136
|
+
align: "start",
|
|
137
|
+
matchReferenceWidth: !0,
|
|
138
|
+
fitViewport: !0
|
|
139
|
+
}), Mt = o(Tt, At), Y = re(), Nt = (Re ?? Y?.required ?? !1) && !S, X = ee("timepicker-error"), Z = I !== null && !Y?.hasErrorMessage, Pt = ie({
|
|
140
|
+
id: Je,
|
|
141
|
+
"aria-label": Ye,
|
|
142
|
+
"aria-labelledby": Xe,
|
|
143
|
+
"aria-describedby": ne(Ze, Z ? X : void 0),
|
|
144
|
+
"aria-invalid": I !== null || Qe,
|
|
145
|
+
"aria-required": $e ?? Re
|
|
146
|
+
}), Ft = de(!1, Pt["aria-invalid"]);
|
|
147
|
+
fe(J, () => {
|
|
148
|
+
T(l ?? ""), U(), R();
|
|
149
|
+
}, Le);
|
|
150
|
+
let It = (e) => {
|
|
151
|
+
if (!A) return;
|
|
152
|
+
let t = e.target.value;
|
|
153
|
+
F(t), L(null), N || M(!0), K.setActiveValue(B(t));
|
|
154
|
+
}, Lt = r(it, (e) => {
|
|
155
|
+
if (A && (K.onKeyDown(e), !(e.defaultPrevented || e.nativeEvent.isComposing))) {
|
|
156
|
+
if (e.key === "Escape" && P === "" && St !== "") {
|
|
157
|
+
e.preventDefault(), U(), R();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (e.key === "Enter" && P !== null) {
|
|
161
|
+
e.preventDefault();
|
|
162
|
+
let t = H(P);
|
|
163
|
+
R(), t !== null && xt(P, t);
|
|
164
|
+
}
|
|
165
|
+
e.key === "Tab" && !e.shiftKey && q && P !== null && !P.trim() && Ce(() => H(P)), e.key === "Tab" && N && !G && R();
|
|
166
|
+
}
|
|
167
|
+
}), Rt = r(at, K.onKeyUp), zt = () => {
|
|
168
|
+
A && !N && (vt(), P !== null && K.setActiveValue(B(P)));
|
|
169
|
+
}, Bt = r(rt, () => {
|
|
170
|
+
if (!A || P === null) return;
|
|
171
|
+
let e = I === null ? H(P) : null;
|
|
172
|
+
R(), e !== null && xt(P, e);
|
|
173
|
+
}), Vt = () => {
|
|
174
|
+
A && (N ? R() : zt(), J.current?.focus());
|
|
175
|
+
}, Ht = () => {
|
|
176
|
+
A && (V(""), J.current?.focus());
|
|
177
|
+
}, Ut = ne(Xe, Y?.labelId), Wt = (t) => /* @__PURE__ */ p("ul", {
|
|
178
|
+
...K.getListboxProps(),
|
|
179
|
+
"aria-labelledby": Ut,
|
|
180
|
+
"aria-label": Ut ? void 0 : Ye ?? C?.list ?? "Times",
|
|
181
|
+
hidden: t || void 0,
|
|
182
|
+
className: e(i.listbox, "max-h-60 min-h-0 overflow-auto py-1 focus:outline-hidden"),
|
|
183
|
+
children: K.items.map((e) => /* @__PURE__ */ p(we, {
|
|
184
|
+
value: e.value,
|
|
185
|
+
label: e.label
|
|
186
|
+
}, e.value))
|
|
187
|
+
}), Q = ve(je), $ = "";
|
|
188
|
+
Z && I === "unparseable" ? $ = (C?.invalidTime ?? Te)(_ === "24h" ? "HH:mm" : "h:mm AM") : Z && ($ = (C?.outOfRange ?? Ee)(s.minTime === void 0 ? void 0 : g(y, _), s.maxTime === void 0 ? void 0 : g(b, _)));
|
|
189
|
+
let Gt = N ? W : k.length > 0;
|
|
190
|
+
return /* @__PURE__ */ p(me.Provider, {
|
|
191
|
+
value: K.context,
|
|
192
|
+
children: /* @__PURE__ */ m("div", {
|
|
193
|
+
...lt,
|
|
194
|
+
ref: Et,
|
|
195
|
+
className: e(i.root, "relative inline-flex flex-col", st),
|
|
196
|
+
children: [
|
|
197
|
+
/* @__PURE__ */ m("div", {
|
|
198
|
+
ref: kt,
|
|
199
|
+
className: "relative flex items-center",
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ p("input", {
|
|
202
|
+
ref: Dt,
|
|
203
|
+
type: "text",
|
|
204
|
+
...K.getComboboxProps(),
|
|
205
|
+
"aria-controls": Gt ? K.listboxId : void 0,
|
|
206
|
+
...Pt,
|
|
207
|
+
"aria-errormessage": et,
|
|
208
|
+
"aria-details": tt,
|
|
209
|
+
value: P ?? St,
|
|
210
|
+
onChange: It,
|
|
211
|
+
onClick: zt,
|
|
212
|
+
onFocus: nt,
|
|
213
|
+
onBlur: Bt,
|
|
214
|
+
onKeyDown: Lt,
|
|
215
|
+
onKeyUp: Rt,
|
|
216
|
+
placeholder: ke,
|
|
217
|
+
disabled: x,
|
|
218
|
+
readOnly: S,
|
|
219
|
+
autoComplete: ze,
|
|
220
|
+
autoCapitalize: Be,
|
|
221
|
+
autoCorrect: Ve,
|
|
222
|
+
maxLength: He,
|
|
223
|
+
enterKeyHint: Ue,
|
|
224
|
+
inputMode: We,
|
|
225
|
+
spellCheck: Ge,
|
|
226
|
+
autoFocus: Ke,
|
|
227
|
+
tabIndex: qe,
|
|
228
|
+
className: e(i.input, ce, "border-b-stroke-accessible", le, se, Ft && "border-destructive focus:border-b-destructive", ge(Number(q) + Number(Q)))
|
|
229
|
+
}),
|
|
230
|
+
q && /* @__PURE__ */ p("button", {
|
|
231
|
+
type: "button",
|
|
232
|
+
"aria-label": C?.clear ?? "Clear time",
|
|
233
|
+
disabled: x,
|
|
234
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
235
|
+
onClick: Ht,
|
|
236
|
+
className: e(i.clearButton, "absolute flex h-6 w-6 items-center justify-center rounded bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:bg-subtle-hover not-disabled:not-aria-disabled:hover:text-foreground", Q ? "end-7" : "end-1", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", "disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:focus-visible:opacity-100"),
|
|
237
|
+
children: /* @__PURE__ */ p(ue, {})
|
|
238
|
+
}),
|
|
239
|
+
Q && /* @__PURE__ */ p(_e, {
|
|
240
|
+
component: "TimePicker",
|
|
241
|
+
expandIcon: je,
|
|
242
|
+
label: C?.expand ?? "Show times",
|
|
243
|
+
expanded: G,
|
|
244
|
+
listboxId: K.listboxId,
|
|
245
|
+
disabled: x || !!S,
|
|
246
|
+
onToggle: Vt,
|
|
247
|
+
className: i.expandButton,
|
|
248
|
+
iconClassName: i.expandIcon
|
|
249
|
+
})
|
|
250
|
+
]
|
|
251
|
+
}),
|
|
252
|
+
Z && /* @__PURE__ */ p("p", {
|
|
253
|
+
id: X,
|
|
254
|
+
role: "alert",
|
|
255
|
+
className: e(i.errorMessage, "mt-1 text-caption-1 text-error"),
|
|
256
|
+
children: $
|
|
257
|
+
}),
|
|
258
|
+
!N && k.length > 0 && Wt(!0),
|
|
259
|
+
/* @__PURE__ */ p("span", {
|
|
260
|
+
role: "status",
|
|
261
|
+
className: "sr-only",
|
|
262
|
+
children: Ct
|
|
263
|
+
}),
|
|
264
|
+
/* @__PURE__ */ p(pe, {
|
|
265
|
+
name: Ie,
|
|
266
|
+
form: Le,
|
|
267
|
+
disabled: x,
|
|
268
|
+
value: w,
|
|
269
|
+
type: "text",
|
|
270
|
+
required: Nt,
|
|
271
|
+
onInvalid: () => J.current?.focus()
|
|
272
|
+
}),
|
|
273
|
+
N && /* @__PURE__ */ p(oe, {
|
|
274
|
+
layerId: Ot,
|
|
275
|
+
children: /* @__PURE__ */ p("div", {
|
|
276
|
+
ref: Mt,
|
|
277
|
+
...jt,
|
|
278
|
+
"data-state": "open",
|
|
279
|
+
className: e(i.surface, "flex flex-col overflow-hidden rounded border border-border bg-background shadow-8"),
|
|
280
|
+
children: W ? Wt(!1) : /* @__PURE__ */ p("div", {
|
|
281
|
+
"aria-hidden": "true",
|
|
282
|
+
className: e(i.emptyMessage, "px-3 py-1.5 text-body-1 text-muted-foreground"),
|
|
283
|
+
children: Ct
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
]
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
_.displayName = "TimePicker";
|
|
292
|
+
//#endregion
|
|
293
|
+
export { _ as TimePicker };
|
|
294
|
+
|
|
295
|
+
//# sourceMappingURL=TimePicker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimePicker.mjs","names":["useId","useId$1","React","OPTION_CLASSES","TimePickerOption","useListboxOption","optionProps","cn","timePickerClassNames","selected","forcedColors","CheckIcon","label","defaultInvalidTimeLabel","format","defaultOutOfRangeLabel","min","max","displayTime","minutes","timeToMinutes","value","minutesToTime","matchesQuery","item","text","startsWithQuery","TimePicker","valueProp","openProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","props","onChange","warnDeprecated","selectedValue","setSelectedValue","useControllable","defaultValue","onValueChange","next","stepValid","normalizeTimeStep","step","minMinutes","minTime","maxMinutes","maxTime","boundsValid","allOptions","generateTimeOptions","warnOnce","interactive","disabled","readOnly","openState","setOpen","openControlled","defaultOpen","onOpenChange","isClient","useIsClient","open","draft","setDraft","invalid","setInvalid","wasInteractive","setWasInteractive","seenValue","setSeenValue","query","openList","closeList","filter","exact","minutesToValue","getTypedActiveValue","needle","selectedInList","selectedValues","commitValue","commitDraft","rejectDraft","reason","onInvalidInput","clearDraft","hasMatches","expanded","lb","useListbox","displayLabel","showClear","clearable","statusMessage","labels","rootRef","inputRef","surfaceRef","rootRefs","useMergedRefs","ref","inputRefs","controlRef","useDismiss","usePopupPosition","surfaceRefs","setFloating","field","useFieldContext","validates","required","errorId","showOwnError","fieldProps","useFieldControl","joinIds","invalidLook","isInvalidLook","form","handleInputChange","event","handleKeyDown","composeEventHandlers","onKeyDown","flushSync","handleKeyUp","onKeyUp","handleInputClick","handleBlur","onBlur","handleExpandClick","handleClear","listboxLabelledBy","renderListbox","hidden","showExpand","showsExpandButton","expandIcon","errorMessage","listboxMounted","ListboxContext","className","setReference","inputBase","inputFocus","disabledStyles","pickerEndPadding","DismissIcon","PickerExpandButton","HiddenInput","Portal","floatingProps"],"sources":["../../../src/components/input/TimePicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { flushSync } from 'react-dom';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { timePickerClassNames } from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { CheckIcon, DismissIcon } from '../../lib/icons';\nimport type { Slot } from '../../lib/slot';\nimport {\n disabledStyles,\n focusRing,\n forcedColors,\n inputBase,\n inputFocus,\n inputInvalid,\n} from '../../lib/styles';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useDismiss } from '../../hooks/useDismiss';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useIsClient } from '../../hooks/useIsClient';\nimport { ListboxContext, useListbox, useListboxOption } from '../../hooks/useListbox';\nimport type { ListboxItem } from '../../hooks/useListbox';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { usePopupPosition } from '../../hooks/usePopupPosition';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { Portal } from '../portal/Portal';\nimport { PickerExpandButton, showsExpandButton } from './Combobox.expand';\nimport {\n DEFAULT_TIME_STEP,\n generateTimeOptions,\n minutesToTime,\n minutesToValue,\n normalizeTimeStep,\n timeToMinutes,\n} from './dateUtils';\nimport { isInvalidLook } from './Input';\nimport { PICKER_ICON_BUTTON_CLASSES, pickerEndPadding } from './pickerStyles';\nimport type { RoutedHandlers } from './routedHandlers';\n\n/* ------------------------------------------------------------------ */\n/* Option */\n/* ------------------------------------------------------------------ */\n\nconst OPTION_CLASSES =\n 'flex cursor-pointer items-center gap-2 px-3 py-1.5 text-body-1 text-foreground hover:bg-subtle-hover data-[active]:bg-subtle-hover data-[active]:outline-2 data-[active]:outline-ring data-[active]:-outline-offset-2 data-[selected]:bg-subtle-selected data-[selected]:font-semibold';\n\ninterface TimePickerOptionProps {\n value: string;\n label: string;\n}\n\n/**\n * One time option. Memoized: it re-renders only when its own active/selected state changes (read\n * from the listbox store), so moving the highlight renders two options, not the whole list.\n */\nconst TimePickerOption = React.memo(function TimePickerOption({\n value,\n label,\n}: TimePickerOptionProps) {\n const { selected, optionProps } = useListboxOption<HTMLLIElement>({ value, label });\n return (\n <li\n {...optionProps}\n className={cn(\n timePickerClassNames.option,\n OPTION_CLASSES,\n selected && forcedColors.selectedContainer,\n )}\n >\n <span\n className={cn(\n timePickerClassNames.checkIcon,\n 'flex h-4 w-4 shrink-0 items-center justify-center',\n )}\n >\n {selected ? <CheckIcon size={12} /> : null}\n </span>\n {label}\n </li>\n );\n});\nTimePickerOption.displayName = 'TimePickerOption';\n\n/* ------------------------------------------------------------------ */\n/* TimePicker */\n/* ------------------------------------------------------------------ */\n\n/** Why typed text was not accepted (see {@link TimePickerProps.onInvalidInput}). */\nexport type TimePickerInvalidReason = 'unparseable' | 'out-of-range';\n\n/**\n * The TimePicker's built-in texts, for localization. Each member is optional and falls back to its\n * English default. The times themselves follow `format`.\n */\nexport interface TimePickerLabels {\n /** Name of the clear button.\n * @default 'Clear time'\n */\n clear?: string;\n /** Name of the expand button at the end of the input.\n * @default 'Show times'\n */\n expand?: string;\n /** Name of the list of times when the picker has no `aria-label`, `aria-labelledby` or Field\n * label to lend it.\n * @default 'Times'\n */\n list?: string;\n /** Status text (announced and shown in the open list) when `minTime`/`maxTime` leave no times.\n * @default 'No times available'\n */\n noTimes?: string;\n /** Status text (announced and shown in the open list) when the typed text matches no time.\n * @default 'No matching times'\n */\n noMatches?: string;\n /**\n * Message for text that is not a time. `format` is the display pattern (`'HH:mm'` or\n * `'h:mm AM'`).\n * @default (format) => `Enter a time in the format ${format}.`\n */\n invalidTime?: (format: string) => string;\n /**\n * Message for a time outside `minTime`/`maxTime`. The bounds are passed as the input shows times\n * (`format`); a bound that is not set is `undefined`.\n * @default (min, max) => `Enter a time between ${min} and ${max}.` (only `min`: `Enter a time on\n * or after ${min}.`; only `max`: `Enter a time on or before ${max}.`)\n */\n outOfRange?: (min: string | undefined, max: string | undefined) => string;\n}\n\nconst defaultInvalidTimeLabel = (format: string) => `Enter a time in the format ${format}.`;\n\nconst defaultOutOfRangeLabel = (min: string | undefined, max: string | undefined) => {\n if (min !== undefined && max !== undefined) return `Enter a time between ${min} and ${max}.`;\n if (min !== undefined) return `Enter a time on or after ${min}.`;\n return `Enter a time on or before ${max}.`;\n};\n\n/** Properties for the TimePicker component. */\nexport interface TimePickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | 'placeholder' | RoutedHandlers\n> {\n /** Controlled selected time in `HH:mm` (24-hour) format; `''` for no time. */\n value?: string;\n /**\n * Initial time for uncontrolled usage (`HH:mm`).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new `HH:mm` value (`''` when cleared) whenever the selected time changes. */\n onValueChange?: (value: string) => void;\n /**\n * @deprecated Use `onValueChange`. Still called with the new value (warns once in development).\n */\n onChange?: (value: string) => void;\n /**\n * Time display format of the input and the options.\n * @default '12h'\n */\n format?: '12h' | '24h';\n /**\n * Minutes between options. A non-finite or non-positive value falls back to 30 (development\n * warning); fractions are floored.\n * @default 30\n */\n step?: number;\n /**\n * Earliest time (inclusive): `HH:mm`, `HH:mm:ss` or `h:mm AM`.\n * @default '00:00'\n */\n minTime?: string;\n /**\n * Latest time (inclusive): `HH:mm`, `HH:mm:ss` or `h:mm AM`. Invalid or reversed bounds give no\n * options (development warning, \"No times available\", see `labels`).\n * @default '23:59'\n */\n maxTime?: string;\n /**\n * Placeholder text shown when no time is selected.\n * @default 'Select a time'\n */\n placeholder?: string;\n /**\n * Whether the time picker is disabled and non-interactive.\n * @default false\n */\n disabled?: boolean;\n /**\n * Makes the input read-only: the list does not open and the value cannot change. Turning it (or\n * `disabled`) on while the user is typing drops the typed text.\n */\n readOnly?: boolean;\n /**\n * Whether to show a clear button when a time is selected (not shown while `readOnly`; shown\n * disabled while `disabled`). It is a tab stop after the input. Tab from erased text clears the\n * value before focus moves, so focus goes on past the clear button that disappears with it.\n * @default false\n */\n clearable?: boolean;\n /**\n * The glyph of the expand button at the end of the input (default: a chevron). The button\n * opens and closes the list without moving focus out of the input and is not a tab stop\n * (Alt+ArrowDown opens the list from the keyboard). `null` or `undefined` keep the chevron;\n * `false`, or a value that renders nothing, hides the button. Decorative content rendered\n * inside the built-in button: a `<button>` or `Button` passed here is not nested (its children\n * become the glyph, with a development warning).\n */\n expandIcon?: Slot<'span'>;\n /**\n * Controlled open state of the list (never shown while `disabled` or `readOnly`). The list\n * renders only in the browser: an open picker is closed in the server HTML and opens once it has\n * hydrated.\n */\n open?: boolean;\n /**\n * Initial open state of the list for uncontrolled usage. A picker that starts disabled or\n * read-only starts closed. The list renders only in the browser: it is closed in the server HTML\n * and opens once the picker has hydrated.\n * @default false\n */\n defaultOpen?: boolean;\n /** Called when the list opens or closes (only when the state changes). */\n onOpenChange?: (open: boolean) => void;\n /**\n * Called when edited text is not accepted on Enter or blur (once per edit): it is not a time\n * (`'unparseable'`) or lies outside `minTime`/`maxTime` (`'out-of-range'`). The text stays in the\n * input, which is marked `aria-invalid` and described by an error message (left to the\n * surrounding `Field` when it shows an error); Enter and leaving the input also close the list,\n * so it does not cover the message. Enter reports it again when pressed again.\n */\n onInvalidInput?: (text: string, reason: TimePickerInvalidReason) => void;\n /**\n * Names of the clear and expand buttons and of the list, the status texts of an empty list and\n * the error messages of rejected text, for localization. Unset members keep their English\n * defaults.\n */\n labels?: TimePickerLabels;\n /** Form field name: the `HH:mm` value is submitted under it (hidden input). */\n name?: string;\n /** Id of the `<form>` the value belongs to, when the picker is outside it. */\n form?: string;\n /**\n * Blocks form submission while no time is selected; sets `aria-required` on the input. Like a\n * native readonly input, a `readOnly` TimePicker does not block submission.\n */\n required?: boolean;\n /** Native `autocomplete` of the input. @default 'off' */\n autoComplete?: string;\n /** Native `maxlength` of the input. */\n maxLength?: number;\n /** Focus handler of the text input (the root keeps the other handlers). */\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n /** Blur handler of the text input. */\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n /** Key handler of the text input; `preventDefault()` skips the picker's own keys. */\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Key handler of the text input. */\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Ref to the text input (the `role=\"combobox\"` element); `ref` stays on the root. */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction displayTime(value: string, format: '12h' | '24h'): string {\n const minutes = timeToMinutes(value);\n return Number.isNaN(minutes) ? value : minutesToTime(minutes, format);\n}\n\n/** Whether an option matches the (trimmed, lower-case) typed text: by label or `HH:mm` value. */\nfunction matchesQuery(item: ListboxItem, text: string): boolean {\n return item.label.toLowerCase().includes(text) || item.value.includes(text);\n}\n\n/** Whether an option's label or `HH:mm` value starts with the (trimmed, lower-case) typed text. */\nfunction startsWithQuery(item: ListboxItem, text: string): boolean {\n return item.label.toLowerCase().startsWith(text) || item.value.startsWith(text);\n}\n\n/**\n * A time input with a filterable list of times (APG editable combobox with list autocomplete).\n *\n * - Type to filter (by label or `HH:mm` value). A complete typed time (`2:00 PM`, `14:00`) makes\n * its own option active — not an earlier one that merely contains the text, such as `12:00 PM`\n * — and partial text makes the first option that starts with it active (`2:00 p` -> `2:00 PM`),\n * else the first one that contains it; Enter commits the active option. Enter or leaving the\n * field also commits a complete typed time that is not in the list (`9:15 AM`, `14:45`) when it\n * lies within `minTime`/`maxTime`, and erased text clears the value (as the clear button does);\n * Enter never submits the form with edited text, and both close the list. Other typed text is\n * kept: the input is marked invalid and an error message describes it (`onInvalidInput`,\n * reported once per edit) until the text is edited or replaced (an option, the clear button,\n * Escape, a form reset, a new value from the parent). Escape on a closed list reverts any edit,\n * erased text included, to the selected time.\n * - Click the input or the expand button at its end (a chevron, see `expandIcon`; not a tab stop,\n * and it leaves focus in the input), press ArrowDown/ArrowUp or type to open; the list opens\n * with every option and the selected one (when it is in the list) active and scrolled into\n * view. Without one, no option is active until ArrowDown/ArrowUp or typing, so Enter lets the\n * surrounding form submit. Escape, Tab, an outside press or focus leaving closes it. Typed text\n * kept after Escape closed the list still filters it when it reopens: a click resumes the option\n * typing made active, ArrowDown/ArrowUp start at the first/last match.\n * - `open`/`defaultOpen`/`onOpenChange` control the list. It closes when the picker becomes\n * disabled or read-only (uncontrolled `open`: it stays closed when the picker is enabled again),\n * and the text typed until then is dropped.\n * - Keys of an IME composition (its confirming Enter included) are left to the IME.\n * - `clearable` shows a clear button while a time is selected (not while read-only), a tab stop\n * after the input. Tab from erased text clears the value first, so focus moves on past the\n * picker instead of to the clear button that disappears.\n * - The value is `HH:mm` (24-hour) whatever the display `format`; values off the `step` grid or\n * outside the bounds are still displayed in `format`.\n * - The input (`controlRef`) receives `id`, `aria-label`, `aria-labelledby`, `aria-describedby`,\n * `aria-invalid`, `aria-required`, `aria-errormessage`, `aria-details`, `tabIndex`,\n * `autoFocus`, `onFocus`/`onBlur`/`onKeyDown`/`onKeyUp` and the text input attributes\n * `autoComplete`, `autoCapitalize`, `autoCorrect`, `maxLength`, `inputMode`, `spellCheck` and\n * `enterKeyHint`. `ref`, `className`, `style`, other `aria-*` attributes and the remaining props\n * stay on the root `<div>`. Inside a `Field`, the input is labelled and described by it.\n * - `name`/`required` add a hidden input for native forms (`HH:mm`); the value resets with its form.\n * - The built-in names, status texts and error messages are English; `labels` localizes them.\n * - The open list renders only in the browser: an open list (`defaultOpen`, `open`) is closed in\n * the server HTML and opens once the picker has hydrated.\n */\nexport const TimePicker = (props: TimePickerProps) => {\n const {\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n format = '12h',\n step = DEFAULT_TIME_STEP,\n minTime = '00:00',\n maxTime = '23:59',\n placeholder = 'Select a time',\n disabled = false,\n readOnly,\n clearable = false,\n expandIcon,\n open: openProp,\n defaultOpen,\n onOpenChange,\n onInvalidInput,\n labels,\n name,\n form,\n required,\n autoComplete = 'off',\n autoCapitalize,\n autoCorrect,\n maxLength,\n enterKeyHint,\n inputMode,\n spellCheck,\n autoFocus,\n tabIndex,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n controlRef,\n className,\n ref,\n ...rest\n } = props;\n\n if (onChange !== undefined) warnDeprecated('TimePicker', 'onChange', 'onValueChange');\n\n const [selectedValue, setSelectedValue] = useControllable<string>(\n valueProp,\n defaultValue ?? '',\n (next) => {\n onValueChange?.(next);\n onChange?.(next);\n },\n );\n\n /* ---- options, step and bounds ---------------------------------- */\n\n const stepValid = normalizeTimeStep(step).valid;\n const minMinutes = timeToMinutes(minTime);\n const maxMinutes = timeToMinutes(maxTime);\n const boundsValid =\n !Number.isNaN(minMinutes) && !Number.isNaN(maxMinutes) && minMinutes <= maxMinutes;\n const allOptions = React.useMemo(\n () => generateTimeOptions(step, minTime, maxTime, format),\n [step, minTime, maxTime, format],\n );\n\n // Once per invalid value and page (C-DEV), not once per instance and effect run.\n React.useEffect(() => {\n if (!stepValid) {\n warnOnce(\n `TimePicker:step:${String(step)}`,\n `TimePicker: \\`step\\` must be a positive number of minutes (received ${String(step)}); ` +\n `using ${DEFAULT_TIME_STEP}.`,\n );\n }\n }, [step, stepValid]);\n\n React.useEffect(() => {\n if (!boundsValid) {\n warnOnce(\n `TimePicker:bounds:${minTime}|${maxTime}`,\n `TimePicker: \\`minTime\\`/\\`maxTime\\` must be times such as \"09:00\", \"09:00:00\" or ` +\n `\"9:00 AM\" with minTime <= maxTime (received \"${minTime}\" / \"${maxTime}\"); no times are available.`,\n );\n }\n }, [minTime, maxTime, boundsValid]);\n\n /* ---- open state, draft text and query -------------------------- */\n\n const interactive = !disabled && !readOnly;\n const [openState, setOpen, openControlled] = useControllable<boolean>(\n openProp,\n // A picker that starts disabled or read-only never shows its list, so it starts closed (no\n // close to report later).\n (defaultOpen ?? false) && interactive,\n onOpenChange,\n );\n // The open list lives in a portal, which renders only in the browser: until then (the server\n // HTML, hydration) the picker shows the closed inline list and reports it closed, so\n // aria-controls and aria-activedescendant never name a missing element.\n const isClient = useIsClient();\n const open = openState && interactive && isClient;\n // A list hidden because the picker became disabled or read-only is closed for good\n // (uncontrolled), so enabling the picker again does not bring it back; onOpenChange(false)\n // reports it (a consumer callback, so from an effect). A controlled `open` stays the parent's.\n React.useEffect(() => {\n if (!interactive && openState && !openControlled) setOpen(false);\n }, [interactive, openState, openControlled, setOpen]);\n /** Typed text; `null` shows the selected time's label (draft model). */\n const [draft, setDraft] = React.useState<string | null>(null);\n /** Why the typed text was rejected (it is kept and flagged); `null` while it is not. */\n const [invalid, setInvalid] = React.useState<TimePickerInvalidReason | null>(null);\n // Locking the picker while the user types drops the typed text and its error, so no later blur\n // commits it (adjusted during render, C-HOOKS).\n const [wasInteractive, setWasInteractive] = React.useState(interactive);\n if (wasInteractive !== interactive) {\n setWasInteractive(interactive);\n if (!interactive) {\n setDraft(null);\n setInvalid(null);\n }\n }\n // A new value from the parent replaces rejected text (the picker's own commits clear it\n // themselves), so the input never shows an error next to a valid value. Text the user is still\n // typing stays.\n const [seenValue, setSeenValue] = React.useState(selectedValue);\n if (seenValue !== selectedValue) {\n setSeenValue(selectedValue);\n if (invalid !== null) {\n setDraft(null);\n setInvalid(null);\n }\n }\n /**\n * Filter text: the typed text only, never the selected time's label, so opening without an edit\n * shows every option. Typed text kept while the list is closed (Escape) keeps filtering it, so\n * a reopened list shows what the input says.\n */\n const query = draft ?? '';\n\n const openList = () => {\n if (!interactive || open) return;\n setOpen(true);\n };\n const closeList = () => setOpen(false);\n\n // A complete time in any spelling the commit accepts (`2:00pm`, `09:00 AM`, `14:00:00`) keeps its\n // own option, so it stays listed and active, as Enter and blur commit it.\n const filter = React.useMemo(() => {\n const text = query.trim().toLowerCase();\n if (!text) return undefined;\n const minutes = timeToMinutes(text);\n const exact = Number.isNaN(minutes) ? null : minutesToValue(minutes);\n return (item: ListboxItem) => item.value === exact || matchesQuery(item, text);\n }, [query]);\n\n /**\n * The option that typing `text` makes active. A complete time (`2:00 PM`, `14:00`) activates its\n * own option, never another one that merely contains the text (`12:00 PM`); when it is not in\n * the list (off-grid or out of bounds) nothing is active, so Enter commits the typed time or\n * nothing. Partial text activates the first option whose label or value starts with it (`2:00 p`\n * -> `2:00 PM`, `2` -> `2:00 AM`, not `12:00 AM`), else the first option that contains it.\n */\n const getTypedActiveValue = (text: string): string | null => {\n const needle = text.trim().toLowerCase();\n if (!needle) return null;\n const minutes = timeToMinutes(text);\n if (!Number.isNaN(minutes)) {\n const exact = minutesToValue(minutes);\n return allOptions.some((item) => item.value === exact) ? exact : null;\n }\n const match =\n allOptions.find((item) => startsWithQuery(item, needle)) ??\n allOptions.find((item) => matchesQuery(item, needle));\n return match?.value ?? null;\n };\n\n // Opening without typing activates the selected option only when it is in the list. An empty,\n // off-grid or out-of-range value activates nothing (ArrowDown/ArrowUp start at the first/last\n // option), so Enter on a freshly opened list commits nothing and the surrounding form submits.\n const selectedInList =\n selectedValue !== '' && allOptions.some((item) => item.value === selectedValue);\n\n const selectedValues = React.useMemo(\n () => (selectedValue ? [selectedValue] : []),\n [selectedValue],\n );\n\n const commitValue = (next: string) => {\n setSelectedValue(next);\n setDraft(null);\n setInvalid(null);\n };\n\n /**\n * Commits the typed text: erased text clears the value, a complete time within the bounds selects\n * it. Returns why any other text is not accepted (it is kept), else `null`.\n */\n const commitDraft = (text: string): TimePickerInvalidReason | null => {\n if (!text.trim()) {\n commitValue('');\n return null;\n }\n const minutes = timeToMinutes(text);\n if (Number.isNaN(minutes)) return 'unparseable';\n if (!boundsValid || minutes < minMinutes || minutes > maxMinutes) return 'out-of-range';\n commitValue(minutesToValue(minutes));\n return null;\n };\n\n /** Keeps rejected text, flags it and reports it. */\n const rejectDraft = (text: string, reason: TimePickerInvalidReason) => {\n setInvalid(reason);\n onInvalidInput?.(text, reason);\n };\n\n const clearDraft = () => {\n setDraft(null);\n setInvalid(null);\n };\n\n // The listbox counts as open only while it shows options: with no match nothing is displayed,\n // so `aria-expanded` is false and Escape reverts the typed text instead of closing an empty list.\n const hasMatches = React.useMemo(\n () => (filter ? allOptions.some(filter) : allOptions.length > 0),\n [allOptions, filter],\n );\n const expanded = open && hasMatches;\n\n const lb = useListbox({\n open: expanded,\n onOpenChange: (next) => (next ? openList() : closeList()),\n mode: 'editable',\n selectedValues,\n onSelect: (next) => commitValue(next),\n items: allOptions,\n filter,\n // Typing sets the active option itself (getTypedActiveValue in handleInputChange), so an exact\n // typed time wins over an earlier substring match; highlightOnFilter would force the first one.\n autoHighlight: draft === null && selectedInList ? 'selected' : false,\n idPrefix: 'timepicker-listbox',\n // Escape on a closed list reverts typed text (erased text: handleKeyDown); without a draft it is\n // left to enclosing layers.\n onClearDraft:\n draft !== null\n ? () => {\n clearDraft();\n closeList();\n }\n : undefined,\n });\n\n const displayLabel = selectedValue\n ? (lb.getItem(selectedValue)?.label ?? displayTime(selectedValue, format))\n : '';\n // Read-only pickers offer no clear action (the value cannot change).\n const showClear = clearable && !readOnly && selectedValue !== '';\n const statusMessage =\n open && !hasMatches\n ? allOptions.length === 0\n ? (labels?.noTimes ?? 'No times available')\n : (labels?.noMatches ?? 'No matching times')\n : '';\n\n /* ---- elements, dismissal, positioning --------------------------- */\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const inputRef = React.useRef<HTMLInputElement | null>(null);\n const surfaceRef = React.useRef<HTMLDivElement | null>(null);\n const rootRefs = useMergedRefs<HTMLDivElement>(ref, rootRef);\n const inputRefs = useMergedRefs<HTMLInputElement>(controlRef, inputRef);\n\n const { layerId } = useDismiss({\n open,\n onDismiss: closeList,\n refs: [surfaceRef, rootRef],\n anchorRef: inputRef,\n kind: 'listbox',\n focusOutside: true,\n });\n\n const { setReference, setFloating, floatingProps } = usePopupPosition({\n open,\n side: 'bottom',\n align: 'start',\n matchReferenceWidth: true,\n fitViewport: true,\n });\n const surfaceRefs = useMergedRefs<HTMLDivElement>(surfaceRef, setFloating);\n\n /* ---- forms and Field ------------------------------------------- */\n\n const field = useFieldContext();\n const isRequired = required ?? field?.required ?? false;\n // Like a native readonly input, a read-only picker is barred from constraint validation (the\n // user could not fix it); its value is still submitted.\n const validates = isRequired && !readOnly;\n const errorId = useId('timepicker-error');\n // A Field that shows an error describes the input itself (its message is not repeated).\n const showOwnError = invalid !== null && !field?.hasErrorMessage;\n const fieldProps = useFieldControl({\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, showOwnError ? errorId : undefined),\n 'aria-invalid': invalid !== null ? true : ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n });\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n\n useFormReset(\n inputRef,\n () => {\n setSelectedValue(defaultValue ?? '');\n clearDraft();\n closeList();\n },\n form,\n );\n\n /* ---- handlers --------------------------------------------------- */\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (!interactive) return;\n const text = event.target.value;\n setDraft(text);\n setInvalid(null);\n if (!open) setOpen(true);\n // Every edit re-ranks the highlight (it opens the list in the same update when closed).\n lb.setActiveValue(getTypedActiveValue(text));\n };\n\n const handleKeyDown = composeEventHandlers(\n onKeyDown,\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (!interactive) return;\n // Enter commits the active option: the exact typed time, the first match of partial text,\n // or the option moved to with the arrow keys.\n lb.onKeyDown(event);\n // Keys that belong to an IME composition (its confirming Enter) are left to the IME, as\n // useListbox leaves them.\n if (event.defaultPrevented || event.nativeEvent.isComposing) return;\n if (event.key === 'Escape' && draft === '' && displayLabel !== '') {\n // Erased text: useListbox calls onClearDraft only while the input has text, so Escape on a\n // closed list restores the selected time here (an open list was closed above). With nothing\n // to restore, Escape is left to enclosing layers.\n event.preventDefault();\n clearDraft();\n closeList();\n return;\n }\n if (event.key === 'Enter' && draft !== null) {\n // Edited text is committed (a complete time within the bounds; erased text clears) or kept\n // and flagged (reported on every Enter), never submitted with the form; untouched text\n // lets Enter submit. The list closes either way, so it does not cover the error message.\n event.preventDefault();\n const reason = commitDraft(draft);\n closeList();\n if (reason !== null) rejectDraft(draft, reason);\n }\n if (event.key === 'Tab' && !event.shiftKey && showClear && draft !== null && !draft.trim()) {\n // Erased text clears the value, and with it the clear button, the next tab stop. It is\n // settled before Tab moves focus (the blur would settle it while focus moves to that\n // button), so focus moves on to the tab stop after the picker instead of dropping to\n // <body> with the button (C-DISABLED).\n flushSync(() => commitDraft(draft));\n }\n if (event.key === 'Tab' && open && !expanded) {\n // useListbox closes the list on Tab only while it shows options. The status text shown\n // instead ('No matching times', 'No times available') closes too: the clear button, the\n // next tab stop, is inside the picker, so focus moving there does not dismiss it.\n closeList();\n }\n },\n );\n const handleKeyUp = composeEventHandlers(onKeyUp, lb.onKeyUp);\n\n const handleInputClick = () => {\n if (!interactive || open) return;\n openList();\n // Typed text kept after Escape resumes where typing left it: its matches (the filter) and the\n // option typing made active, so Enter commits the same time as before the list closed.\n if (draft !== null) lb.setActiveValue(getTypedActiveValue(draft));\n };\n\n const handleBlur = composeEventHandlers(onBlur, () => {\n if (!interactive || draft === null) return;\n // Leaving the input settles the edit as Enter does: rejected text is kept (text that was\n // already rejected is not reported again) and the list closes either way, so it does not cover\n // the error message.\n const reason = invalid === null ? commitDraft(draft) : null;\n closeList();\n if (reason !== null) rejectDraft(draft, reason);\n });\n\n // The expand button opens the list as a click in the input does (typed text kept after Escape\n // resumes its matches) and closes it; focus stays in (or returns to) the input.\n const handleExpandClick = () => {\n if (!interactive) return;\n if (open) closeList();\n else handleInputClick();\n inputRef.current?.focus();\n };\n\n const handleClear = () => {\n if (!interactive) return;\n commitValue('');\n inputRef.current?.focus();\n };\n\n /* ---- render ---------------------------------------------------- */\n\n const listboxLabelledBy = joinIds(ariaLabelledBy, field?.labelId);\n const renderListbox = (hidden: boolean) => (\n <ul\n {...lb.getListboxProps()}\n aria-labelledby={listboxLabelledBy}\n aria-label={listboxLabelledBy ? undefined : (ariaLabel ?? labels?.list ?? 'Times')}\n hidden={hidden || undefined}\n className={cn(\n timePickerClassNames.listbox,\n 'max-h-60 min-h-0 overflow-auto py-1 focus:outline-hidden',\n )}\n >\n {lb.items.map((item) => (\n <TimePickerOption key={item.value} value={item.value} label={item.label} />\n ))}\n </ul>\n );\n\n const showExpand = showsExpandButton(expandIcon);\n\n let errorMessage = '';\n if (showOwnError && invalid === 'unparseable') {\n errorMessage = (labels?.invalidTime ?? defaultInvalidTimeLabel)(\n format === '24h' ? 'HH:mm' : 'h:mm AM',\n );\n } else if (showOwnError) {\n // Bounds the consumer did not set are `undefined`, not the defaults.\n errorMessage = (labels?.outOfRange ?? defaultOutOfRangeLabel)(\n props.minTime === undefined ? undefined : displayTime(minTime, format),\n props.maxTime === undefined ? undefined : displayTime(maxTime, format),\n );\n }\n // aria-controls must name a listbox that is actually mounted. The closed list is inline only\n // while options exist; the open list is mounted only while something matches.\n const listboxMounted = open ? hasMatches : allOptions.length > 0;\n\n return (\n <ListboxContext.Provider value={lb.context}>\n <div\n {...rest}\n ref={rootRefs}\n className={cn(timePickerClassNames.root, 'relative inline-flex flex-col', className)}\n >\n <div ref={setReference} className=\"relative flex items-center\">\n <input\n ref={inputRefs}\n type=\"text\"\n {...lb.getComboboxProps()}\n aria-controls={listboxMounted ? lb.listboxId : undefined}\n {...fieldProps}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n value={draft ?? displayLabel}\n onChange={handleInputChange}\n onClick={handleInputClick}\n onFocus={onFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n autoComplete={autoComplete}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n maxLength={maxLength}\n enterKeyHint={enterKeyHint}\n inputMode={inputMode}\n spellCheck={spellCheck}\n autoFocus={autoFocus}\n tabIndex={tabIndex}\n className={cn(\n timePickerClassNames.input,\n inputBase,\n 'border-b-stroke-accessible',\n inputFocus,\n disabledStyles,\n invalidLook && inputInvalid,\n pickerEndPadding(Number(showClear) + Number(showExpand)),\n )}\n />\n {showClear && (\n <button\n type=\"button\"\n aria-label={labels?.clear ?? 'Clear time'}\n disabled={disabled}\n // Keeps focus (and an open list) on the input while the pointer clears it.\n onMouseDown={(event) => event.preventDefault()}\n onClick={handleClear}\n className={cn(\n timePickerClassNames.clearButton,\n PICKER_ICON_BUTTON_CLASSES,\n showExpand ? 'end-7' : 'end-1',\n focusRing,\n disabledStyles,\n )}\n >\n <DismissIcon />\n </button>\n )}\n {showExpand && (\n <PickerExpandButton\n component=\"TimePicker\"\n expandIcon={expandIcon}\n label={labels?.expand ?? 'Show times'}\n expanded={expanded}\n listboxId={lb.listboxId}\n disabled={disabled || !!readOnly}\n onToggle={handleExpandClick}\n className={timePickerClassNames.expandButton}\n iconClassName={timePickerClassNames.expandIcon}\n />\n )}\n </div>\n {showOwnError && (\n <p\n id={errorId}\n role=\"alert\"\n className={cn(timePickerClassNames.errorMessage, 'mt-1 text-caption-1 text-error')}\n >\n {errorMessage}\n </p>\n )}\n {!open && allOptions.length > 0 && renderListbox(true)}\n <span role=\"status\" className=\"sr-only\">\n {statusMessage}\n </span>\n <HiddenInput\n name={name}\n form={form}\n disabled={disabled}\n value={selectedValue}\n type=\"text\"\n required={validates}\n onInvalid={() => inputRef.current?.focus()}\n />\n {open && (\n <Portal layerId={layerId}>\n <div\n ref={surfaceRefs}\n {...floatingProps}\n data-state=\"open\"\n className={cn(\n timePickerClassNames.surface,\n 'flex flex-col overflow-hidden rounded border border-border bg-background shadow-8',\n )}\n >\n {hasMatches ? (\n renderListbox(false)\n ) : (\n <div\n aria-hidden=\"true\"\n className={cn(\n timePickerClassNames.emptyMessage,\n 'px-3 py-1.5 text-body-1 text-muted-foreground',\n )}\n >\n {statusMessage}\n </div>\n )}\n </div>\n </Portal>\n )}\n </div>\n </ListboxContext.Provider>\n );\n};\n\nTimePicker.displayName = 'TimePicker';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../lib/color.cjs");var t=[[15,`red`],[45,`orange`],[70,`yellow`],[165,`green`],[195,`cyan`],[255,`blue`],[290,`purple`],[320,`magenta`],[345,`pink`],[360,`red`]];function n(n){let r=e.wrapHue(n.h),i=e.clampUnit(n.s,0),a=e.clampUnit(n.v,0);if(a<.15)return`black`;if(i<.1)return a>.93?`white`:a<.4?`dark gray`:a>.75?`light gray`:`gray`;let o=t.find(([e])=>r<e)?.[1]??`red`,s=a<.5?`dark`:a>.85&&i<.5?`light`:``;return[s,i<.35&&s!==`light`?`grayish`:i>.85&&a>.85?`vivid`:``,o].filter(Boolean).join(` `)}exports.getColorName=n;
|
|
2
|
+
//# sourceMappingURL=colorName.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorName.cjs","names":["wrapHue","clampUnit","require_color","HUE_FAMILIES","getColorName","h","color","s","v","family","endsBefore","lightness"],"sources":["../../../src/components/input/colorName.ts"],"sourcesContent":["/**\n * The built-in English color namer of the color parts' value texts (spec P3-05, D22): \"blue\",\n * \"dark grayish blue\", \"light pink\", \"vivid red\", \"black\". `labels.colorName` replaces it.\n * Internal (not exported from the package).\n */\nimport { clampUnit, wrapHue } from '../../lib/color';\nimport type { HsvColor } from '../../lib/types';\n\n/** Hue families by the degree they end before (red also covers 345 and above). */\nconst HUE_FAMILIES: ReadonlyArray<readonly [endsBefore: number, family: string]> = [\n [15, 'red'],\n [45, 'orange'],\n [70, 'yellow'],\n [165, 'green'],\n [195, 'cyan'],\n [255, 'blue'],\n [290, 'purple'],\n [320, 'magenta'],\n [345, 'pink'],\n [360, 'red'],\n];\n\n/**\n * An English name of `color` for assistive technology: \"black\" below 15 % brightness; \"white\" or a\n * gray below 10 % saturation; otherwise a hue family, prefixed by \"dark\" (brightness below 50 %)\n * or \"light\" (brightness above 85 % with saturation below 50 %), then by \"grayish\" (saturation\n * below 35 %, never with \"light\") or \"vivid\" (saturation and brightness above 85 %).\n */\nexport function getColorName(color: HsvColor): string {\n const h = wrapHue(color.h);\n const s = clampUnit(color.s, 0);\n const v = clampUnit(color.v, 0);\n if (v < 0.15) return 'black';\n if (s < 0.1) {\n if (v > 0.93) return 'white';\n if (v < 0.4) return 'dark gray';\n if (v > 0.75) return 'light gray';\n return 'gray';\n }\n const family = HUE_FAMILIES.find(([endsBefore]) => h < endsBefore)?.[1] ?? 'red';\n const lightness = v < 0.5 ? 'dark' : v > 0.85 && s < 0.5 ? 'light' : '';\n const saturation =\n s < 0.35 && lightness !== 'light' ? 'grayish' : s > 0.85 && v > 0.85 ? 'vivid' : '';\n return [lightness, saturation, family].filter(Boolean).join(' ');\n}\n"],"mappings":"oDASA,IAAMG,EAA6E,CACjF,CAAC,GAAI,KAAK,EACV,CAAC,GAAI,QAAQ,EACb,CAAC,GAAI,QAAQ,EACb,CAAC,IAAK,OAAO,EACb,CAAC,IAAK,MAAM,EACZ,CAAC,IAAK,MAAM,EACZ,CAAC,IAAK,QAAQ,EACd,CAAC,IAAK,SAAS,EACf,CAAC,IAAK,MAAM,EACZ,CAAC,IAAK,KAAK,CACb,EAQA,SAAgBC,EAAa,EAAyB,CACpD,IAAMC,EAAIL,EAAAA,QAAQM,EAAM,CAAC,EACnBC,EAAIN,EAAAA,UAAUK,EAAM,EAAG,CAAC,EACxBE,EAAIP,EAAAA,UAAUK,EAAM,EAAG,CAAC,EAC9B,GAAIE,EAAI,IAAM,MAAO,QACrB,GAAID,EAAI,GAIN,OAHIC,EAAI,IAAa,QACjBA,EAAI,GAAY,YAChBA,EAAI,IAAa,aACd,OAET,IAAMC,EAASN,EAAa,MAAM,CAACO,KAAgBL,EAAIK,CAAU,CAAC,GAAG,IAAM,MACrEC,EAAYH,EAAI,GAAM,OAASA,EAAI,KAAQD,EAAI,GAAM,QAAU,GAGrE,MAAO,CAACI,EADNJ,EAAI,KAAQI,IAAc,QAAU,UAAYJ,EAAI,KAAQC,EAAI,IAAO,QAAU,GACpDC,CAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,CACjE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { clampUnit as e, wrapHue as t } from "../../lib/color.mjs";
|
|
3
|
+
//#region src/components/input/colorName.ts
|
|
4
|
+
var n = [
|
|
5
|
+
[15, "red"],
|
|
6
|
+
[45, "orange"],
|
|
7
|
+
[70, "yellow"],
|
|
8
|
+
[165, "green"],
|
|
9
|
+
[195, "cyan"],
|
|
10
|
+
[255, "blue"],
|
|
11
|
+
[290, "purple"],
|
|
12
|
+
[320, "magenta"],
|
|
13
|
+
[345, "pink"],
|
|
14
|
+
[360, "red"]
|
|
15
|
+
];
|
|
16
|
+
function r(r) {
|
|
17
|
+
let i = t(r.h), a = e(r.s, 0), o = e(r.v, 0);
|
|
18
|
+
if (o < .15) return "black";
|
|
19
|
+
if (a < .1) return o > .93 ? "white" : o < .4 ? "dark gray" : o > .75 ? "light gray" : "gray";
|
|
20
|
+
let s = n.find(([e]) => i < e)?.[1] ?? "red", c = o < .5 ? "dark" : o > .85 && a < .5 ? "light" : "";
|
|
21
|
+
return [
|
|
22
|
+
c,
|
|
23
|
+
a < .35 && c !== "light" ? "grayish" : a > .85 && o > .85 ? "vivid" : "",
|
|
24
|
+
s
|
|
25
|
+
].filter(Boolean).join(" ");
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { r as getColorName };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=colorName.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorName.mjs","names":["HUE_FAMILIES","getColorName","h","wrapHue","color","s","clampUnit","v","family","endsBefore","lightness"],"sources":["../../../src/components/input/colorName.ts"],"sourcesContent":["/**\n * The built-in English color namer of the color parts' value texts (spec P3-05, D22): \"blue\",\n * \"dark grayish blue\", \"light pink\", \"vivid red\", \"black\". `labels.colorName` replaces it.\n * Internal (not exported from the package).\n */\nimport { clampUnit, wrapHue } from '../../lib/color';\nimport type { HsvColor } from '../../lib/types';\n\n/** Hue families by the degree they end before (red also covers 345 and above). */\nconst HUE_FAMILIES: ReadonlyArray<readonly [endsBefore: number, family: string]> = [\n [15, 'red'],\n [45, 'orange'],\n [70, 'yellow'],\n [165, 'green'],\n [195, 'cyan'],\n [255, 'blue'],\n [290, 'purple'],\n [320, 'magenta'],\n [345, 'pink'],\n [360, 'red'],\n];\n\n/**\n * An English name of `color` for assistive technology: \"black\" below 15 % brightness; \"white\" or a\n * gray below 10 % saturation; otherwise a hue family, prefixed by \"dark\" (brightness below 50 %)\n * or \"light\" (brightness above 85 % with saturation below 50 %), then by \"grayish\" (saturation\n * below 35 %, never with \"light\") or \"vivid\" (saturation and brightness above 85 %).\n */\nexport function getColorName(color: HsvColor): string {\n const h = wrapHue(color.h);\n const s = clampUnit(color.s, 0);\n const v = clampUnit(color.v, 0);\n if (v < 0.15) return 'black';\n if (s < 0.1) {\n if (v > 0.93) return 'white';\n if (v < 0.4) return 'dark gray';\n if (v > 0.75) return 'light gray';\n return 'gray';\n }\n const family = HUE_FAMILIES.find(([endsBefore]) => h < endsBefore)?.[1] ?? 'red';\n const lightness = v < 0.5 ? 'dark' : v > 0.85 && s < 0.5 ? 'light' : '';\n const saturation =\n s < 0.35 && lightness !== 'light' ? 'grayish' : s > 0.85 && v > 0.85 ? 'vivid' : '';\n return [lightness, saturation, family].filter(Boolean).join(' ');\n}\n"],"mappings":";;;AASA,IAAMA,IAA6E;CACjF,CAAC,IAAI,KAAK;CACV,CAAC,IAAI,QAAQ;CACb,CAAC,IAAI,QAAQ;CACb,CAAC,KAAK,OAAO;CACb,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,QAAQ;CACd,CAAC,KAAK,SAAS;CACf,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,KAAK;AACb;AAQA,SAAgBC,EAAa,GAAyB;CACpD,IAAMC,IAAIC,EAAQC,EAAM,CAAC,GACnBC,IAAIC,EAAUF,EAAM,GAAG,CAAC,GACxBG,IAAID,EAAUF,EAAM,GAAG,CAAC;CAC9B,IAAIG,IAAI,KAAM,OAAO;CACrB,IAAIF,IAAI,IAIN,OAHIE,IAAI,MAAa,UACjBA,IAAI,KAAY,cAChBA,IAAI,MAAa,eACd;CAET,IAAMC,IAASR,EAAa,MAAM,CAACS,OAAgBP,IAAIO,CAAU,CAAC,GAAG,MAAM,OACrEC,IAAYH,IAAI,KAAM,SAASA,IAAI,OAAQF,IAAI,KAAM,UAAU;CAGrE,OAAO;EAACK;EADNL,IAAI,OAAQK,MAAc,UAAU,YAAYL,IAAI,OAAQE,IAAI,MAAO,UAAU;EACpDC;CAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AACjE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../lib/color.cjs"),t=require("../../lib/direction.cjs"),n=require("./colorName.cjs");var r=`#000000`,i=`#ffffff`,a=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i,o=/^#?[0-9a-f]{0,8}$/i;function s(e,t,n){return Math.min(n,Math.max(t,e))}function c(e){return Math.round(s(e,0,255)).toString(16).padStart(2,`0`)}function l(t){let n=e.parseHexBytes(t);return n?{rgb:`#${c(n.r)}${c(n.g)}${c(n.b)}`,alpha:n.alpha}:null}function u(e){return a.test(e.trim())?l(e):null}function d(e){return o.test(e.trim())}function f(e,t=255){let n=Math.round(s(t,0,255));return n===255?e:e+c(n)}function p(e){let t=l(e);return t?f(t.rgb,t.alpha):null}function m(e){return Math.round(s(e,0,255)/255*100)}function h(e){let t=e.endsWith(`%`),n=Number(t?e.slice(0,-1):e);return Number.isFinite(n)?s(t?n/100*255:n,0,255):null}function g(e){if(e===void 0)return 1;let t=e.endsWith(`%`),n=Number(t?e.slice(0,-1):e);return Number.isFinite(n)?s(t?n/100:n,0,1):null}var _=/^rgba?\(\s*([^)]*)\)$/i;function v(e){let t=e.trim(),n=l(t);if(n){let e=parseInt(n.rgb.slice(1),16);return{r:e>>16&255,g:e>>8&255,b:e&255,a:n.alpha/255}}let r=_.exec(t);if(!r)return null;let[i,a]=r[1].split(`/`),o=(i??``).split(/[\s,]+/).map(e=>e.trim()).filter(Boolean),s=a?.trim();if(s===void 0&&o.length===4&&(s=o.pop()),o.length!==3)return null;let[c,u,d]=o.map(h),f=g(s);return c===null||u===null||d===null||f===null?null:{r:c,g:u,b:d,a:f}}function y(e){let t=e/255;return t<=.04045?t/12.92:((t+.055)/1.055)**2.4}function b(e){let t=v(e);return t?.2126*y(t.r)+.7152*y(t.g)+.0722*y(t.b):null}function x(e){let t=b(e);return t===null||(t+.05)/.05>=1.05/(t+.05)?{glyph:r,halo:i}:{glyph:i,halo:r}}function S(t){return Number.isFinite(t)&&t>=0&&t<=360?t:e.wrapHue(t)}function C(t){return{h:S(t.h),s:e.clampUnit(t.s,0),v:e.clampUnit(t.v,0),a:e.clampUnit(t.a,1)}}function w(e){return Math.round(e*100)}function T(e){return`${Math.round(e*1e4)/100}%`}function E(e,t){return e.h===t.h&&e.s===t.s&&e.v===t.v&&(e.a??1)===(t.a??1)}function D(e,n,r,i,a){if(n.altKey||n.ctrlKey||n.metaKey)return null;let o=n.shiftKey?10:1,s;switch(e){case`ArrowUp`:s=i+o;break;case`ArrowDown`:s=i-o;break;case`ArrowRight`:case`ArrowLeft`:s=i+(t.getArrowIntent(e,{orientation:`horizontal`,dir:r})===`next`?o:-o);break;case`PageUp`:s=i+10;break;case`PageDown`:s=i-10;break;case`Home`:s=0;break;case`End`:s=a;break;default:return null}return Math.min(a,Math.max(0,s))}var O=e=>e===`vertical`?`to top`:`to right`;function k(t){return`linear-gradient(to top, #000000, transparent), linear-gradient(to right, #ffffff, ${e.hsvToHex({h:t,s:1,v:1})})`}var A=`#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000`;function j(t,n,r){let i=O(r);return t===`hue`?`linear-gradient(${i}, ${A})`:t===`saturation`?`linear-gradient(${i}, ${e.hsvToHex({h:n.h,s:0,v:n.v})}, ${e.hsvToHex({h:n.h,s:1,v:n.v})})`:`linear-gradient(${i}, #000000, ${e.hsvToHex({h:n.h,s:n.s,v:1})})`}function M(t,n,r){let i=e.hsvToHex({h:t.h,s:t.s,v:t.v}),a=O(r);return n?`linear-gradient(${a}, ${i}, transparent)`:`linear-gradient(${a}, transparent, ${i})`}function N(e,t,r){if(r.valueText)return r.valueText(e,t);let i=`${r.saturation} ${w(e.s)}%`,a=`${r.brightness} ${w(e.v)}%`,o=t===`saturation`?`${i}, ${a}`:`${a}, ${i}`,s=(r.colorName??n.getColorName)(e);return s?`${o}, ${s}`:o}function P(e,t,r){if(r.valueText)return r.valueText(e,t);if(t!==`hue`)return`${w(t===`saturation`?e.s:e.v)}%`;let i=`${Math.round(e.h)}°`,a=(r.colorName??n.getColorName)(e);return a?`${i}, ${a}`:i}function F(e,t,n){if(n)return n(e,t);let r=w(e.a);return`${t?100-r:r}%`}var I=`pointer-events-none absolute size-6 rounded-full border-2 border-background bg-(--wave-color-thumb) ring-1 ring-foreground forced-colors:forced-color-adjust-none forced-colors:border-[Canvas] forced-colors:ring-[CanvasText]`,L=`h-6 w-full items-center`,R=`h-40 w-6 flex-col items-center [container-type:size]`,z=`mx-3 h-3 flex-1 wave-rtl:-scale-x-100`,B=`my-3 w-3 flex-1`,V=`bg-(image:--wave-color-slider-gradient)`,H=`absolute m-0 cursor-pointer appearance-none opacity-0 disabled:cursor-not-allowed [&::-webkit-slider-thumb]:size-6 [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:size-6`,U=`inset-0 size-full`,W=`start-1/2 top-1/2 h-6 w-[100cqh] -translate-x-1/2 wave-rtl:translate-x-1/2 -translate-y-1/2 -rotate-90`,G=`pointer-events-none absolute inset-x-3 inset-y-0`,K=`pointer-events-none absolute inset-x-0 inset-y-3`,q=`start-(--wave-color-slider-position) top-1/2 -translate-x-1/2 wave-rtl:translate-x-1/2 -translate-y-1/2`,J=`bottom-(--wave-color-slider-position) start-1/2 -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2`;exports.COLOR_THUMB_CLASSES=I,exports.RAIL_GRADIENT=V,exports.RAIL_INPUT_CLASSES=H,exports.RAIL_INPUT_HORIZONTAL=U,exports.RAIL_INPUT_VERTICAL=W,exports.RAIL_ROOT_HORIZONTAL=L,exports.RAIL_ROOT_VERTICAL=R,exports.RAIL_TRACK_HORIZONTAL=z,exports.RAIL_TRACK_VERTICAL=B,exports.THUMB_POSITION_HORIZONTAL=q,exports.THUMB_POSITION_VERTICAL=J,exports.THUMB_TRACK_HORIZONTAL=G,exports.THUMB_TRACK_VERTICAL=K,exports.alphaSliderGradient=M,exports.alphaToOpacity=m,exports.alphaValueText=F,exports.areaValueText=N,exports.colorAreaGradient=k,exports.colorSliderGradient=j,exports.displayColor=C,exports.displayHue=S,exports.formatHexColor=f,exports.getCheckColors=x,exports.getRelativeLuminance=b,exports.isHexDraft=d,exports.normalizeHexColor=p,exports.parseCssColor=v,exports.parseHexColor=l,exports.parseHexInput=u,exports.railKeyTarget=D,exports.sameColor=E,exports.sliderValueText=P,exports.toPercent=w,exports.toPosition=T;
|
|
2
|
+
//# sourceMappingURL=colorUtils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorUtils.cjs","names":["parseHexBytes","wrapHue","clampUnit","getArrowIntent","hsvToHex","getColorName","require_color","require_direction","require_colorName","BLACK","WHITE","HEX_INPUT","HEX_DRAFT","clamp","max","min","value","toHexByte","parseHexColor","bytes","parseHexInput","text","isHexDraft","formatHexColor","byte","alpha","rgb","normalizeHexColor","parsed","alphaToOpacity","parseChannel","percent","token","parseAlpha","RGB_FUNCTION","parseCssColor","hex","n","match","channelsPart","alphaPart","tokens","t","alphaToken","r","g","b","a","linearize","c","channel","getRelativeLuminance","color","getCheckColors","luminance","displayHue","h","displayColor","toPercent","toPosition","sameColor","railKeyTarget","modifiers","step","next","key","current","toward","orientation","colorAreaGradient","HUE_SPECTRUM","colorSliderGradient","direction","alphaSliderGradient","opaque","transparency","areaValueText","labels","saturation","brightness","channels","name","sliderValueText","degrees","alphaValueText","valueText","opacity","COLOR_THUMB_CLASSES","RAIL_ROOT_HORIZONTAL","RAIL_ROOT_VERTICAL","RAIL_TRACK_HORIZONTAL","RAIL_TRACK_VERTICAL","RAIL_GRADIENT","RAIL_INPUT_CLASSES","RAIL_INPUT_HORIZONTAL","RAIL_INPUT_VERTICAL","THUMB_TRACK_HORIZONTAL","THUMB_TRACK_VERTICAL","THUMB_POSITION_HORIZONTAL","THUMB_POSITION_VERTICAL"],"sources":["../../../src/components/input/colorUtils.ts"],"sourcesContent":["/**\n * Color helpers for ColorPicker, SwatchPicker and the HSV color parts: hex parsing and\n * normalisation (on the grammar of `src/lib/color.ts`), the alpha byte ↔ opacity percentage, and\n * the luminance-picked check glyph drawn on a user-supplied swatch.\n *\n * Internal (not exported from the package). Pure functions, no DOM access, so they run on the\n * server and in tests.\n */\nimport { clampUnit, hsvToHex, parseHexBytes, wrapHue } from '../../lib/color';\nimport { getArrowIntent, type Direction } from '../../lib/direction';\nimport type { HsvColor } from '../../lib/types';\nimport { getColorName } from './colorName';\n\n/** A parsed hex color: the `#rrggbb` part (lowercase) and the alpha byte (0–255). */\nexport interface HexColor {\n /** `#rrggbb`, lowercase. */\n rgb: string;\n /** Alpha byte, 0 (transparent) … 255 (opaque). */\n alpha: number;\n}\n\n/** An sRGB color with 0–255 channels and a 0–1 alpha. */\nexport interface RgbaColor {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n\n/** Colors of the selected-swatch check glyph: the glyph and the halo drawn under it. */\nexport interface CheckColors {\n glyph: string;\n halo: string;\n}\n\n// wave-allow-color: luminance-picked check glyph on a user swatch (C-TOKENS exception, input-pickers#16)\nconst BLACK = '#000000';\n// wave-allow-color: luminance-picked check glyph on a user swatch (C-TOKENS exception, input-pickers#16)\nconst WHITE = '#ffffff';\n\nconst HEX_INPUT = /^#([0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst HEX_DRAFT = /^#?[0-9a-f]{0,8}$/i;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction toHexByte(value: number): string {\n return Math.round(clamp(value, 0, 255))\n .toString(16)\n .padStart(2, '0');\n}\n\n/**\n * Parses a hex color (`#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa`, case-insensitive, surrounding\n * whitespace ignored). Returns `null` for anything else (named colors, `rgb()`, a missing `#`).\n *\n * @example parseHexColor('#0F6CBD80') // { rgb: '#0f6cbd', alpha: 128 }\n */\nexport function parseHexColor(value: string): HexColor | null {\n const bytes = parseHexBytes(value);\n return bytes\n ? {\n rgb: `#${toHexByte(bytes.r)}${toHexByte(bytes.g)}${toHexByte(bytes.b)}`,\n alpha: bytes.alpha,\n }\n : null;\n}\n\n/**\n * Parses text typed into a hex field: only complete `#rrggbb` / `#rrggbbaa` values are accepted,\n * so the short forms a user passes through while typing (`#abc`) are never committed.\n */\nexport function parseHexInput(text: string): HexColor | null {\n return HEX_INPUT.test(text.trim()) ? parseHexColor(text) : null;\n}\n\n/**\n * Whether typed text can still become a hex color by typing more characters (an optional `#`\n * followed by at most 8 hex digits; surrounding whitespace ignored, like the parsers). `false`\n * means the text is invalid whatever follows.\n */\nexport function isHexDraft(text: string): boolean {\n return HEX_DRAFT.test(text.trim());\n}\n\n/**\n * Formats `#rrggbb` plus an alpha byte: `#rrggbb` when opaque (`alpha` 255, the default),\n * `#rrggbbaa` otherwise. The alpha byte is rounded and clamped to 0–255.\n */\nexport function formatHexColor(rgb: string, alpha = 255): string {\n const byte = Math.round(clamp(alpha, 0, 255));\n return byte === 255 ? rgb : rgb + toHexByte(byte);\n}\n\n/**\n * A hex color in the one form ColorPicker reports: `#rrggbb` in lower case, or `#rrggbbaa` when\n * the alpha byte is not 255 (short forms expanded, surrounding whitespace dropped). Returns `null`\n * for anything {@link parseHexColor} rejects.\n *\n * @example normalizeHexColor('#ABC') // '#aabbcc'\n * @example normalizeHexColor('#0f6cbdff') // '#0f6cbd'\n */\nexport function normalizeHexColor(value: string): string | null {\n const parsed = parseHexColor(value);\n return parsed ? formatHexColor(parsed.rgb, parsed.alpha) : null;\n}\n\n/** Alpha byte (0–255) → whole opacity percentage (0–100). */\nexport function alphaToOpacity(alpha: number): number {\n return Math.round((clamp(alpha, 0, 255) / 255) * 100);\n}\n\n/** Opacity percentage (0–100) → alpha byte (0–255). Inverse of {@link alphaToOpacity}. */\nexport function opacityToAlpha(opacity: number): number {\n return Math.round((clamp(opacity, 0, 100) / 100) * 255);\n}\n\nfunction parseChannel(token: string): number | null {\n const percent = token.endsWith('%');\n const n = Number(percent ? token.slice(0, -1) : token);\n if (!Number.isFinite(n)) return null;\n return clamp(percent ? (n / 100) * 255 : n, 0, 255);\n}\n\nfunction parseAlpha(token: string | undefined): number | null {\n if (token === undefined) return 1;\n const percent = token.endsWith('%');\n const n = Number(percent ? token.slice(0, -1) : token);\n if (!Number.isFinite(n)) return null;\n return clamp(percent ? n / 100 : n, 0, 1);\n}\n\nconst RGB_FUNCTION = /^rgba?\\(\\s*([^)]*)\\)$/i;\n\n/**\n * Parses the CSS colors that can be resolved without a browser: hex colors and `rgb()`/`rgba()`\n * (comma or space syntax, numbers or percentages, optional alpha). Returns `null` for named\n * colors, other color spaces and variables.\n */\nexport function parseCssColor(value: string): RgbaColor | null {\n const text = value.trim();\n const hex = parseHexColor(text);\n if (hex) {\n const n = parseInt(hex.rgb.slice(1), 16);\n return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255, a: hex.alpha / 255 };\n }\n const match = RGB_FUNCTION.exec(text);\n if (!match) return null;\n const [channelsPart, alphaPart]: Array<string | undefined> = match[1].split('/');\n const tokens = (channelsPart ?? '')\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter(Boolean);\n let alphaToken: string | undefined = alphaPart?.trim();\n if (alphaToken === undefined && tokens.length === 4) alphaToken = tokens.pop();\n if (tokens.length !== 3) return null;\n const [r, g, b] = tokens.map(parseChannel);\n const a = parseAlpha(alphaToken);\n if (r === null || g === null || b === null || a === null) return null;\n return { r, g, b, a };\n}\n\nfunction linearize(channel: number): number {\n const c = channel / 255;\n return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/**\n * WCAG 2.x relative luminance (0 = black … 1 = white) of a color {@link parseCssColor} understands,\n * or `null`. Alpha is ignored (the swatch is treated as opaque).\n */\nexport function getRelativeLuminance(color: string): number | null {\n const parsed = parseCssColor(color);\n if (!parsed) return null;\n return 0.2126 * linearize(parsed.r) + 0.7152 * linearize(parsed.g) + 0.0722 * linearize(parsed.b);\n}\n\n/**\n * Colors of the check glyph drawn on a selected swatch (`input-pickers#16`): black or white,\n * whichever has the higher WCAG contrast ratio against the swatch color, with the other one as a\n * halo under it so the glyph stays visible on any color. Colors that cannot be parsed without a\n * browser (named colors, `hsl()`, variables) get a black glyph with a white halo.\n *\n * This is the one runtime-computed exception to the token rule (C-TOKENS): the glyph sits on a\n * consumer-supplied color, not on a theme surface.\n */\nexport function getCheckColors(color: string): CheckColors {\n const luminance = getRelativeLuminance(color);\n if (luminance === null) return { glyph: BLACK, halo: WHITE };\n const onBlack = (luminance + 0.05) / 0.05;\n const onWhite = 1.05 / (luminance + 0.05);\n return onBlack >= onWhite ? { glyph: BLACK, halo: WHITE } : { glyph: WHITE, halo: BLACK };\n}\n\n// ---------------------------------------------------------------------------------------------\n// The HSV color parts: ColorArea, ColorSlider and AlphaSlider (spec P3-05)\n// ---------------------------------------------------------------------------------------------\n\n/** The channels of an HSV color that a part edits or names in a value text. */\nexport type ColorChannel = 'hue' | 'saturation' | 'value' | 'alpha';\n\n/** Which way a rail runs: left to right (mirrored in right-to-left layouts), or bottom to top. */\nexport type RailOrientation = 'horizontal' | 'vertical';\n\n/** The modifier keys of a key press. */\nexport interface KeyModifiers {\n shiftKey: boolean;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n}\n\n/**\n * A hue as a part shows it: 0–360 kept as given (360 is the end of a hue rail), any other finite\n * hue wrapped into [0, 360), and a hue that is not finite as 0.\n */\nexport function displayHue(h: number): number {\n return Number.isFinite(h) && h >= 0 && h <= 360 ? h : wrapHue(h);\n}\n\n/**\n * A color as a part shows it: the hue for display, saturation and brightness clamped to [0, 1]\n * (not a number: 0) and alpha clamped to [0, 1] (left out or not a number: 1).\n */\nexport function displayColor(color: HsvColor): Required<HsvColor> {\n return {\n h: displayHue(color.h),\n s: clampUnit(color.s, 0),\n v: clampUnit(color.v, 0),\n a: clampUnit(color.a, 1),\n };\n}\n\n/** A 0–1 channel as the whole percentage the range inputs and value texts use. */\nexport function toPercent(value: number): number {\n return Math.round(value * 100);\n}\n\n/** A 0–1 position as a CSS percentage with at most two decimals, for an inline custom property. */\nexport function toPosition(value: number): string {\n return `${Math.round(value * 10000) / 100}%`;\n}\n\n/** Whether two colors have the same channels (a missing alpha equals 1). */\nexport function sameColor(a: HsvColor, b: HsvColor): boolean {\n return a.h === b.h && a.s === b.s && a.v === b.v && (a.a ?? 1) === (b.a ?? 1);\n}\n\n/**\n * The value a rail (a range from 0 to `max`) moves to for a key press, or `null` for a key it\n * leaves alone: ArrowUp and ArrowDown by 1; ArrowRight and ArrowLeft by 1 toward the reading\n * direction's end and start (so mirrored in right-to-left layouts); Shift with an arrow, Page Up\n * and Page Down by 10; Home and End to 0 and `max`. A key with Alt, Ctrl or Meta belongs to the\n * browser. The result is clamped to the range.\n */\nexport function railKeyTarget(\n key: string,\n modifiers: KeyModifiers,\n dir: Direction,\n current: number,\n max: number,\n): number | null {\n if (modifiers.altKey || modifiers.ctrlKey || modifiers.metaKey) return null;\n const step = modifiers.shiftKey ? 10 : 1;\n let next: number;\n switch (key) {\n case 'ArrowUp':\n next = current + step;\n break;\n case 'ArrowDown':\n next = current - step;\n break;\n case 'ArrowRight':\n case 'ArrowLeft':\n next =\n current +\n (getArrowIntent(key, { orientation: 'horizontal', dir }) === 'next' ? step : -step);\n break;\n case 'PageUp':\n next = current + 10;\n break;\n case 'PageDown':\n next = current - 10;\n break;\n case 'Home':\n next = 0;\n break;\n case 'End':\n next = max;\n break;\n default:\n return null;\n }\n return Math.min(max, Math.max(0, next));\n}\n\nconst toward = (orientation: RailOrientation) =>\n orientation === 'vertical' ? 'to top' : 'to right';\n\n/** The field of a ColorArea at hue `h`: white to the pure hue left to right, black toward the bottom. */\nexport function colorAreaGradient(h: number): string {\n const hue = hsvToHex({ h, s: 1, v: 1 });\n // wave-allow-color: the saturation and brightness field of the user's color (runtime gradient)\n return `linear-gradient(to top, #000000, transparent), linear-gradient(to right, #ffffff, ${hue})`;\n}\n\n// wave-allow-color: the hue spectrum of a hue rail (runtime gradient data, not a theme color)\nconst HUE_SPECTRUM = '#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000';\n\n/**\n * The rail of a ColorSlider: the hue spectrum, gray to the full color at the color's brightness\n * (saturation), or black to the color at full brightness (brightness).\n */\nexport function colorSliderGradient(\n channel: 'hue' | 'saturation' | 'value',\n color: Required<HsvColor>,\n orientation: RailOrientation,\n): string {\n const direction = toward(orientation);\n if (channel === 'hue') return `linear-gradient(${direction}, ${HUE_SPECTRUM})`;\n if (channel === 'saturation') {\n const gray = hsvToHex({ h: color.h, s: 0, v: color.v });\n const full = hsvToHex({ h: color.h, s: 1, v: color.v });\n return `linear-gradient(${direction}, ${gray}, ${full})`;\n }\n const bright = hsvToHex({ h: color.h, s: color.s, v: 1 });\n // wave-allow-color: the brightness rail runs from black to the color (runtime gradient)\n return `linear-gradient(${direction}, #000000, ${bright})`;\n}\n\n/** The rail of an AlphaSlider: transparent to the opaque color, or the reverse with `transparency`. */\nexport function alphaSliderGradient(\n color: Required<HsvColor>,\n transparency: boolean,\n orientation: RailOrientation,\n): string {\n const opaque = hsvToHex({ h: color.h, s: color.s, v: color.v });\n const direction = toward(orientation);\n return transparency\n ? `linear-gradient(${direction}, ${opaque}, transparent)`\n : `linear-gradient(${direction}, transparent, ${opaque})`;\n}\n\n/**\n * The value text of one of ColorArea's inputs: its own channel first, then the other one, then\n * the color's name (\"Saturation 72%, Brightness 40%, dark blue\"). `colorName` replaces the namer\n * (`''` leaves the name out); `valueText` replaces the whole text.\n */\nexport function areaValueText(\n color: Required<HsvColor>,\n channel: 'saturation' | 'value',\n labels: {\n saturation: string;\n brightness: string;\n colorName?: (color: HsvColor) => string;\n valueText?: (color: HsvColor, channel: 'saturation' | 'value') => string;\n },\n): string {\n if (labels.valueText) return labels.valueText(color, channel);\n const saturation = `${labels.saturation} ${toPercent(color.s)}%`;\n const brightness = `${labels.brightness} ${toPercent(color.v)}%`;\n const channels =\n channel === 'saturation' ? `${saturation}, ${brightness}` : `${brightness}, ${saturation}`;\n const name = (labels.colorName ?? getColorName)(color);\n return name ? `${channels}, ${name}` : channels;\n}\n\n/** The value text of a ColorSlider: \"210°, blue\" for hue, \"72%\" for saturation and brightness. */\nexport function sliderValueText(\n color: Required<HsvColor>,\n channel: 'hue' | 'saturation' | 'value',\n labels: {\n colorName?: (color: HsvColor) => string;\n valueText?: (color: HsvColor, channel: 'hue' | 'saturation' | 'value') => string;\n },\n): string {\n if (labels.valueText) return labels.valueText(color, channel);\n if (channel !== 'hue') return `${toPercent(channel === 'saturation' ? color.s : color.v)}%`;\n const degrees = `${Math.round(color.h)}°`;\n const name = (labels.colorName ?? getColorName)(color);\n return name ? `${degrees}, ${name}` : degrees;\n}\n\n/** The value text of an AlphaSlider: the opacity (\"40%\"), or the transparency with `transparency`. */\nexport function alphaValueText(\n color: Required<HsvColor>,\n transparency: boolean,\n valueText?: (color: HsvColor, transparency: boolean) => string,\n): string {\n if (valueText) return valueText(color, transparency);\n const opacity = toPercent(color.a);\n return `${transparency ? 100 - opacity : opacity}%`;\n}\n\n/**\n * The thumb of ColorArea, ColorSlider and AlphaSlider (decorative; the focused input is what\n * assistive technology reads): 24 px, filled from `--wave-color-thumb`, with a two-tone edge (a\n * `background` border inside a `foreground` ring) that shows on any color. Forced colors keep the\n * fill and draw the edge in system colors. Each part adds its own focus classes, keyed on its\n * named group, and its part class.\n */\nexport const COLOR_THUMB_CLASSES =\n 'pointer-events-none absolute size-6 rounded-full border-2 border-background bg-(--wave-color-thumb) ring-1 ring-foreground forced-colors:forced-color-adjust-none forced-colors:border-[Canvas] forced-colors:ring-[CanvasText]';\n\n/** The root of a horizontal ColorSlider or AlphaSlider (24 px, as tall as the thumb). */\nexport const RAIL_ROOT_HORIZONTAL = 'h-6 w-full items-center';\n/** The root of a vertical one: a size container, so the turned input can be as long as it is tall. */\nexport const RAIL_ROOT_VERTICAL = 'h-40 w-6 flex-col items-center [container-type:size]';\n/** The drawn rail, inset by half a thumb at both ends (a horizontal one mirrors in right-to-left layouts). */\nexport const RAIL_TRACK_HORIZONTAL = 'mx-3 h-3 flex-1 wave-rtl:-scale-x-100';\nexport const RAIL_TRACK_VERTICAL = 'my-3 w-3 flex-1';\n/** The rail's gradient, read from the inline `--wave-color-slider-gradient` property. */\nexport const RAIL_GRADIENT = 'bg-(image:--wave-color-slider-gradient)';\n/**\n * The native range input of a rail: over the whole slider and invisible, with its own thumb as\n * wide as the drawn one, so a press lands on the value under the drawn thumb.\n */\nexport const RAIL_INPUT_CLASSES =\n 'absolute m-0 cursor-pointer appearance-none opacity-0 disabled:cursor-not-allowed [&::-webkit-slider-thumb]:size-6 [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:size-6';\nexport const RAIL_INPUT_HORIZONTAL = 'inset-0 size-full';\n/** Turned a quarter, so its start (the minimum) is at the bottom; it carries `dir=\"ltr\"`. */\nexport const RAIL_INPUT_VERTICAL =\n 'start-1/2 top-1/2 h-6 w-[100cqh] -translate-x-1/2 wave-rtl:translate-x-1/2 -translate-y-1/2 -rotate-90';\n/** The box the thumb moves in: the rail's length, so its center meets the native thumb's. */\nexport const THUMB_TRACK_HORIZONTAL = 'pointer-events-none absolute inset-x-3 inset-y-0';\nexport const THUMB_TRACK_VERTICAL = 'pointer-events-none absolute inset-x-0 inset-y-3';\n/** The thumb's place along the rail, read from the inline `--wave-color-slider-position` property. */\nexport const THUMB_POSITION_HORIZONTAL =\n 'start-(--wave-color-slider-position) top-1/2 -translate-x-1/2 wave-rtl:translate-x-1/2 -translate-y-1/2';\nexport const THUMB_POSITION_VERTICAL =\n 'bottom-(--wave-color-slider-position) start-1/2 -translate-x-1/2 wave-rtl:translate-x-1/2 translate-y-1/2';\n"],"mappings":"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"}
|