@limonify/zest-ui 0.3.2 → 0.4.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 +3 -0
- package/lib/alert-dialog/index.parts.d.ts +1 -1
- package/lib/alert-dialog/index.parts.d.ts.map +1 -1
- package/lib/alert-dialog/index.parts.js.map +1 -1
- package/lib/autocomplete/handle.d.ts +15 -0
- package/lib/autocomplete/handle.d.ts.map +1 -0
- package/lib/autocomplete/handle.js +12 -0
- package/lib/autocomplete/handle.js.map +1 -0
- package/lib/autocomplete/index.d.ts +1 -0
- package/lib/autocomplete/index.d.ts.map +1 -1
- package/lib/autocomplete/index.parts.d.ts +1 -0
- package/lib/autocomplete/index.parts.d.ts.map +1 -1
- package/lib/autocomplete/index.parts.js +3 -1
- package/lib/autocomplete/index.parts.js.map +1 -1
- package/lib/autocomplete/root/AutocompleteRoot.d.ts +55 -16
- package/lib/autocomplete/root/AutocompleteRoot.d.ts.map +1 -1
- package/lib/autocomplete/root/AutocompleteRoot.js +2 -18
- package/lib/autocomplete/root/AutocompleteRoot.js.map +1 -1
- package/lib/avatar/fallback/AvatarFallback.d.ts.map +1 -1
- package/lib/avatar/fallback/AvatarFallback.js +3 -1
- package/lib/avatar/fallback/AvatarFallback.js.map +1 -1
- package/lib/avatar/image/AvatarImage.d.ts.map +1 -1
- package/lib/avatar/image/AvatarImage.js +5 -0
- package/lib/avatar/image/AvatarImage.js.map +1 -1
- package/lib/checkbox/root/CheckboxRoot.d.ts.map +1 -1
- package/lib/checkbox/root/CheckboxRoot.js +9 -4
- package/lib/checkbox/root/CheckboxRoot.js.map +1 -1
- package/lib/combobox/backdrop/ComboboxBackdrop.d.ts.map +1 -1
- package/lib/combobox/backdrop/ComboboxBackdrop.js +10 -4
- package/lib/combobox/backdrop/ComboboxBackdrop.js.map +1 -1
- package/lib/combobox/empty/ComboboxEmpty.d.ts.map +1 -1
- package/lib/combobox/empty/ComboboxEmpty.js +4 -1
- package/lib/combobox/empty/ComboboxEmpty.js.map +1 -1
- package/lib/combobox/index.d.ts +2 -0
- package/lib/combobox/index.d.ts.map +1 -1
- package/lib/combobox/index.js +3 -1
- package/lib/combobox/index.js.map +1 -1
- package/lib/combobox/index.parts.d.ts +1 -0
- package/lib/combobox/index.parts.d.ts.map +1 -1
- package/lib/combobox/index.parts.js +4 -1
- package/lib/combobox/index.parts.js.map +1 -1
- package/lib/combobox/input/ComboboxInput.d.ts +24 -3
- package/lib/combobox/input/ComboboxInput.d.ts.map +1 -1
- package/lib/combobox/input/ComboboxInput.js +65 -11
- package/lib/combobox/input/ComboboxInput.js.map +1 -1
- package/lib/combobox/item/ComboboxItem.d.ts +11 -1
- package/lib/combobox/item/ComboboxItem.d.ts.map +1 -1
- package/lib/combobox/item/ComboboxItem.js +9 -6
- package/lib/combobox/item/ComboboxItem.js.map +1 -1
- package/lib/combobox/list/ComboboxList.d.ts +1 -1
- package/lib/combobox/list/ComboboxList.d.ts.map +1 -1
- package/lib/combobox/list/ComboboxList.js +4 -1
- package/lib/combobox/list/ComboboxList.js.map +1 -1
- package/lib/combobox/popup/ComboboxPopup.d.ts +26 -0
- package/lib/combobox/popup/ComboboxPopup.d.ts.map +1 -1
- package/lib/combobox/popup/ComboboxPopup.js +18 -2
- package/lib/combobox/popup/ComboboxPopup.js.map +1 -1
- package/lib/combobox/portal/ComboboxPortal.d.ts.map +1 -1
- package/lib/combobox/portal/ComboboxPortal.js +8 -4
- package/lib/combobox/portal/ComboboxPortal.js.map +1 -1
- package/lib/combobox/portal/ComboboxPortalContext.d.ts +4 -0
- package/lib/combobox/portal/ComboboxPortalContext.d.ts.map +1 -0
- package/lib/combobox/portal/ComboboxPortalContext.js +48 -0
- package/lib/combobox/portal/ComboboxPortalContext.js.map +1 -0
- package/lib/combobox/positioner/ComboboxPositioner.d.ts +7 -2
- package/lib/combobox/positioner/ComboboxPositioner.d.ts.map +1 -1
- package/lib/combobox/positioner/ComboboxPositioner.js +61 -6
- package/lib/combobox/positioner/ComboboxPositioner.js.map +1 -1
- package/lib/combobox/positioner/ComboboxPositionerContext.d.ts +9 -0
- package/lib/combobox/positioner/ComboboxPositionerContext.d.ts.map +1 -0
- package/lib/combobox/positioner/ComboboxPositionerContext.js +48 -0
- package/lib/combobox/positioner/ComboboxPositionerContext.js.map +1 -0
- package/lib/combobox/root/ComboboxItemsContext.d.ts +18 -0
- package/lib/combobox/root/ComboboxItemsContext.d.ts.map +1 -0
- package/lib/combobox/root/ComboboxItemsContext.js +55 -0
- package/lib/combobox/root/ComboboxItemsContext.js.map +1 -0
- package/lib/combobox/root/ComboboxRoot.d.ts +77 -21
- package/lib/combobox/root/ComboboxRoot.d.ts.map +1 -1
- package/lib/combobox/root/ComboboxRoot.js +4 -23
- package/lib/combobox/root/ComboboxRoot.js.map +1 -1
- package/lib/combobox/root/ComboboxRootContext.d.ts +4 -54
- package/lib/combobox/root/ComboboxRootContext.d.ts.map +1 -1
- package/lib/combobox/root/ComboboxRootContext.js.map +1 -1
- package/lib/combobox/root/ComboboxTransitionContext.d.ts +8 -0
- package/lib/combobox/root/ComboboxTransitionContext.d.ts.map +1 -0
- package/lib/combobox/root/ComboboxTransitionContext.js +44 -0
- package/lib/combobox/root/ComboboxTransitionContext.js.map +1 -0
- package/lib/combobox/root/useRenderComboboxRoot.d.ts +39 -0
- package/lib/combobox/root/useRenderComboboxRoot.d.ts.map +1 -0
- package/lib/combobox/root/useRenderComboboxRoot.js +136 -0
- package/lib/combobox/root/useRenderComboboxRoot.js.map +1 -0
- package/lib/combobox/store/ComboboxHandle.d.ts +42 -0
- package/lib/combobox/store/ComboboxHandle.d.ts.map +1 -0
- package/lib/combobox/store/ComboboxHandle.js +65 -0
- package/lib/combobox/store/ComboboxHandle.js.map +1 -0
- package/lib/combobox/store/ComboboxStore.d.ts +147 -0
- package/lib/combobox/store/ComboboxStore.d.ts.map +1 -0
- package/lib/combobox/store/ComboboxStore.js +127 -0
- package/lib/combobox/store/ComboboxStore.js.map +1 -0
- package/lib/combobox/value/ComboboxValue.d.ts.map +1 -1
- package/lib/combobox/value/ComboboxValue.js +2 -1
- package/lib/combobox/value/ComboboxValue.js.map +1 -1
- package/lib/context-menu/positioner/ContextMenuPositioner.d.ts +19 -3
- package/lib/context-menu/positioner/ContextMenuPositioner.d.ts.map +1 -1
- package/lib/context-menu/positioner/ContextMenuPositioner.js +56 -7
- package/lib/context-menu/positioner/ContextMenuPositioner.js.map +1 -1
- package/lib/context-menu/root/ContextMenuRoot.d.ts +8 -0
- package/lib/context-menu/root/ContextMenuRoot.d.ts.map +1 -1
- package/lib/dialog/backdrop/DialogBackdrop.d.ts +9 -0
- package/lib/dialog/backdrop/DialogBackdrop.d.ts.map +1 -1
- package/lib/dialog/backdrop/DialogBackdrop.js +3 -1
- package/lib/dialog/backdrop/DialogBackdrop.js.map +1 -1
- package/lib/dialog/popup/DialogPopup.d.ts +9 -0
- package/lib/dialog/popup/DialogPopup.d.ts.map +1 -1
- package/lib/dialog/popup/DialogPopup.js +2 -2
- package/lib/dialog/popup/DialogPopup.js.map +1 -1
- package/lib/dialog/popup/useDialogPopupProps.d.ts +2 -0
- package/lib/dialog/popup/useDialogPopupProps.d.ts.map +1 -1
- package/lib/dialog/popup/useDialogPopupProps.js +4 -0
- package/lib/dialog/popup/useDialogPopupProps.js.map +1 -1
- package/lib/dialog/root/DialogNestingContext.d.ts +20 -0
- package/lib/dialog/root/DialogNestingContext.d.ts.map +1 -0
- package/lib/dialog/root/DialogNestingContext.js +53 -0
- package/lib/dialog/root/DialogNestingContext.js.map +1 -0
- package/lib/dialog/root/useRenderDialogRoot.d.ts.map +1 -1
- package/lib/dialog/root/useRenderDialogRoot.js +26 -2
- package/lib/dialog/root/useRenderDialogRoot.js.map +1 -1
- package/lib/dialog/store/DialogStore.d.ts +19 -2
- package/lib/dialog/store/DialogStore.d.ts.map +1 -1
- package/lib/dialog/store/DialogStore.js +14 -2
- package/lib/dialog/store/DialogStore.js.map +1 -1
- package/lib/drawer/index.parts.d.ts +1 -1
- package/lib/drawer/index.parts.d.ts.map +1 -1
- package/lib/drawer/index.parts.js.map +1 -1
- package/lib/drawer/popup/DrawerPopup.d.ts +9 -0
- package/lib/drawer/popup/DrawerPopup.d.ts.map +1 -1
- package/lib/drawer/popup/DrawerPopup.js +3 -1
- package/lib/drawer/popup/DrawerPopup.js.map +1 -1
- package/lib/filter/index.d.ts +2 -0
- package/lib/filter/index.d.ts.map +1 -0
- package/lib/filter/index.js +6 -0
- package/lib/filter/index.js.map +1 -0
- package/lib/filter/useFilter.d.ts +45 -0
- package/lib/filter/useFilter.d.ts.map +1 -0
- package/lib/filter/useFilter.js +96 -0
- package/lib/filter/useFilter.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/internals/field/useFieldControlRegistration.d.ts +25 -6
- package/lib/internals/field/useFieldControlRegistration.d.ts.map +1 -1
- package/lib/internals/field/useFieldControlRegistration.js +93 -6
- package/lib/internals/field/useFieldControlRegistration.js.map +1 -1
- package/lib/menu/popup/MenuPopup.d.ts +10 -0
- package/lib/menu/popup/MenuPopup.d.ts.map +1 -1
- package/lib/menu/popup/MenuPopup.js +10 -1
- package/lib/menu/popup/MenuPopup.js.map +1 -1
- package/lib/menu/positioner/MenuPositioner.d.ts +10 -0
- package/lib/menu/positioner/MenuPositioner.d.ts.map +1 -1
- package/lib/menu/positioner/MenuPositioner.js +9 -1
- package/lib/menu/positioner/MenuPositioner.js.map +1 -1
- package/lib/menu/store/MenuStore.d.ts +11 -0
- package/lib/menu/store/MenuStore.d.ts.map +1 -1
- package/lib/menu/store/MenuStore.js +4 -0
- package/lib/menu/store/MenuStore.js.map +1 -1
- package/lib/menu/submenu-trigger/MenuSubmenuTrigger.d.ts.map +1 -1
- package/lib/menu/submenu-trigger/MenuSubmenuTrigger.js +3 -0
- package/lib/menu/submenu-trigger/MenuSubmenuTrigger.js.map +1 -1
- package/lib/menu/trigger/MenuTrigger.d.ts.map +1 -1
- package/lib/menu/trigger/MenuTrigger.js +4 -1
- package/lib/menu/trigger/MenuTrigger.js.map +1 -1
- package/lib/meter/indicator/MeterIndicator.d.ts +2 -1
- package/lib/meter/indicator/MeterIndicator.d.ts.map +1 -1
- package/lib/meter/indicator/MeterIndicator.js +1 -2
- package/lib/meter/indicator/MeterIndicator.js.map +1 -1
- package/lib/meter/label/MeterLabel.d.ts +2 -1
- package/lib/meter/label/MeterLabel.d.ts.map +1 -1
- package/lib/meter/label/MeterLabel.js +1 -2
- package/lib/meter/label/MeterLabel.js.map +1 -1
- package/lib/meter/root/MeterRoot.d.ts +21 -0
- package/lib/meter/root/MeterRoot.d.ts.map +1 -1
- package/lib/meter/root/MeterRoot.js +2 -2
- package/lib/meter/root/MeterRoot.js.map +1 -1
- package/lib/meter/root/MeterRootContext.d.ts +5 -0
- package/lib/meter/root/MeterRootContext.d.ts.map +1 -1
- package/lib/meter/root/MeterRootContext.js.map +1 -1
- package/lib/meter/track/MeterTrack.d.ts +2 -1
- package/lib/meter/track/MeterTrack.d.ts.map +1 -1
- package/lib/meter/track/MeterTrack.js +1 -2
- package/lib/meter/track/MeterTrack.js.map +1 -1
- package/lib/meter/value/MeterValue.d.ts +2 -1
- package/lib/meter/value/MeterValue.d.ts.map +1 -1
- package/lib/meter/value/MeterValue.js +1 -2
- package/lib/meter/value/MeterValue.js.map +1 -1
- package/lib/number-field/input/NumberFieldInput.d.ts.map +1 -1
- package/lib/number-field/input/NumberFieldInput.js +11 -2
- package/lib/number-field/input/NumberFieldInput.js.map +1 -1
- package/lib/number-field/root/NumberFieldRoot.d.ts.map +1 -1
- package/lib/number-field/root/NumberFieldRoot.js +5 -2
- package/lib/number-field/root/NumberFieldRoot.js.map +1 -1
- package/lib/otp-field/input/OTPFieldInput.d.ts.map +1 -1
- package/lib/otp-field/input/OTPFieldInput.js +4 -0
- package/lib/otp-field/input/OTPFieldInput.js.map +1 -1
- package/lib/otp-field/root/OTPFieldRoot.d.ts.map +1 -1
- package/lib/otp-field/root/OTPFieldRoot.js +20 -2
- package/lib/otp-field/root/OTPFieldRoot.js.map +1 -1
- package/lib/popover/popup/PopoverPopup.d.ts +10 -0
- package/lib/popover/popup/PopoverPopup.d.ts.map +1 -1
- package/lib/popover/popup/PopoverPopup.js +10 -1
- package/lib/popover/popup/PopoverPopup.js.map +1 -1
- package/lib/popover/positioner/PopoverPositioner.d.ts +10 -0
- package/lib/popover/positioner/PopoverPositioner.d.ts.map +1 -1
- package/lib/popover/positioner/PopoverPositioner.js +4 -0
- package/lib/popover/positioner/PopoverPositioner.js.map +1 -1
- package/lib/popover/store/PopoverStore.d.ts +11 -0
- package/lib/popover/store/PopoverStore.d.ts.map +1 -1
- package/lib/popover/store/PopoverStore.js +4 -0
- package/lib/popover/store/PopoverStore.js.map +1 -1
- package/lib/popover/trigger/PopoverTrigger.d.ts.map +1 -1
- package/lib/popover/trigger/PopoverTrigger.js +4 -1
- package/lib/popover/trigger/PopoverTrigger.js.map +1 -1
- package/lib/progress/root/ProgressRoot.d.ts +21 -0
- package/lib/progress/root/ProgressRoot.d.ts.map +1 -1
- package/lib/progress/root/ProgressRoot.js +1 -1
- package/lib/progress/root/ProgressRoot.js.map +1 -1
- package/lib/radio-group/RadioGroup.d.ts.map +1 -1
- package/lib/radio-group/RadioGroup.js +5 -2
- package/lib/radio-group/RadioGroup.js.map +1 -1
- package/lib/select/backdrop/SelectBackdrop.d.ts.map +1 -1
- package/lib/select/backdrop/SelectBackdrop.js +3 -0
- package/lib/select/backdrop/SelectBackdrop.js.map +1 -1
- package/lib/select/index.parts.d.ts +1 -0
- package/lib/select/index.parts.d.ts.map +1 -1
- package/lib/select/index.parts.js +4 -1
- package/lib/select/index.parts.js.map +1 -1
- package/lib/select/popup/SelectPopup.d.ts +8 -0
- package/lib/select/popup/SelectPopup.d.ts.map +1 -1
- package/lib/select/popup/SelectPopup.js +10 -1
- package/lib/select/popup/SelectPopup.js.map +1 -1
- package/lib/select/positioner/SelectPositioner.d.ts +4 -0
- package/lib/select/positioner/SelectPositioner.d.ts.map +1 -1
- package/lib/select/positioner/SelectPositioner.js +2 -0
- package/lib/select/positioner/SelectPositioner.js.map +1 -1
- package/lib/select/root/SelectRoot.d.ts +45 -4
- package/lib/select/root/SelectRoot.d.ts.map +1 -1
- package/lib/select/root/SelectRoot.js +43 -5
- package/lib/select/root/SelectRoot.js.map +1 -1
- package/lib/select/store/SelectHandle.d.ts +42 -0
- package/lib/select/store/SelectHandle.d.ts.map +1 -0
- package/lib/select/store/SelectHandle.js +69 -0
- package/lib/select/store/SelectHandle.js.map +1 -0
- package/lib/select/store/SelectStore.d.ts +28 -0
- package/lib/select/store/SelectStore.d.ts.map +1 -1
- package/lib/select/store/SelectStore.js +15 -1
- package/lib/select/store/SelectStore.js.map +1 -1
- package/lib/select/trigger/SelectTrigger.d.ts +18 -3
- package/lib/select/trigger/SelectTrigger.d.ts.map +1 -1
- package/lib/select/trigger/SelectTrigger.js +49 -4
- package/lib/select/trigger/SelectTrigger.js.map +1 -1
- package/lib/slider/root/SliderRoot.d.ts.map +1 -1
- package/lib/slider/root/SliderRoot.js +9 -1
- package/lib/slider/root/SliderRoot.js.map +1 -1
- package/lib/slider/thumb/SliderThumb.d.ts.map +1 -1
- package/lib/slider/thumb/SliderThumb.js +10 -2
- package/lib/slider/thumb/SliderThumb.js.map +1 -1
- package/lib/switch/root/SwitchRoot.d.ts.map +1 -1
- package/lib/switch/root/SwitchRoot.js +6 -2
- package/lib/switch/root/SwitchRoot.js.map +1 -1
- package/lib/tabs/tab/TabsTab.d.ts +2 -10
- package/lib/tabs/tab/TabsTab.d.ts.map +1 -1
- package/lib/tooltip/popup/TooltipPopup.d.ts +10 -0
- package/lib/tooltip/popup/TooltipPopup.d.ts.map +1 -1
- package/lib/tooltip/popup/TooltipPopup.js +10 -1
- package/lib/tooltip/popup/TooltipPopup.js.map +1 -1
- package/lib/tooltip/positioner/TooltipPositioner.d.ts +10 -0
- package/lib/tooltip/positioner/TooltipPositioner.d.ts.map +1 -1
- package/lib/tooltip/positioner/TooltipPositioner.js +4 -0
- package/lib/tooltip/positioner/TooltipPositioner.js.map +1 -1
- package/lib/tooltip/store/TooltipStore.d.ts +11 -0
- package/lib/tooltip/store/TooltipStore.d.ts.map +1 -1
- package/lib/tooltip/store/TooltipStore.js +11 -1
- package/lib/tooltip/store/TooltipStore.js.map +1 -1
- package/lib/tooltip/trigger/TooltipTrigger.d.ts.map +1 -1
- package/lib/tooltip/trigger/TooltipTrigger.js +4 -1
- package/lib/tooltip/trigger/TooltipTrigger.js.map +1 -1
- package/package.json +1 -1
- package/src/alert-dialog/index.parts.ts +1 -1
- package/src/autocomplete/handle.ts +18 -0
- package/src/autocomplete/index.parts.ts +1 -0
- package/src/autocomplete/index.ts +1 -0
- package/src/autocomplete/root/AutocompleteRoot.tsx +65 -50
- package/src/avatar/fallback/AvatarFallback.tsx +3 -1
- package/src/avatar/image/AvatarImage.tsx +5 -0
- package/src/checkbox/root/CheckboxRoot.tsx +7 -2
- package/src/combobox/backdrop/ComboboxBackdrop.tsx +10 -3
- package/src/combobox/empty/ComboboxEmpty.tsx +5 -1
- package/src/combobox/index.parts.ts +1 -0
- package/src/combobox/index.ts +2 -0
- package/src/combobox/input/ComboboxInput.tsx +112 -27
- package/src/combobox/item/ComboboxItem.tsx +24 -6
- package/src/combobox/list/ComboboxList.tsx +7 -2
- package/src/combobox/popup/ComboboxPopup.tsx +44 -2
- package/src/combobox/portal/ComboboxPortal.tsx +19 -13
- package/src/combobox/portal/ComboboxPortalContext.ts +15 -0
- package/src/combobox/positioner/ComboboxPositioner.tsx +45 -10
- package/src/combobox/positioner/ComboboxPositionerContext.ts +23 -0
- package/src/combobox/root/ComboboxItemsContext.ts +32 -0
- package/src/combobox/root/ComboboxRoot.tsx +94 -56
- package/src/combobox/root/ComboboxRootContext.ts +3 -54
- package/src/combobox/root/ComboboxTransitionContext.ts +15 -0
- package/src/combobox/root/useRenderComboboxRoot.tsx +189 -0
- package/src/combobox/store/ComboboxHandle.ts +64 -0
- package/src/combobox/store/ComboboxStore.ts +249 -0
- package/src/combobox/value/ComboboxValue.tsx +2 -1
- package/src/context-menu/positioner/ContextMenuPositioner.tsx +90 -10
- package/src/context-menu/root/ContextMenuRoot.tsx +8 -0
- package/src/dialog/backdrop/DialogBackdrop.tsx +12 -1
- package/src/dialog/popup/DialogPopup.tsx +11 -2
- package/src/dialog/popup/useDialogPopupProps.ts +4 -0
- package/src/dialog/root/DialogNestingContext.ts +27 -0
- package/src/dialog/root/useRenderDialogRoot.tsx +37 -2
- package/src/dialog/store/DialogStore.ts +24 -2
- package/src/drawer/index.parts.ts +1 -1
- package/src/drawer/popup/DrawerPopup.tsx +12 -1
- package/src/filter/index.ts +5 -0
- package/src/filter/useFilter.ts +95 -0
- package/src/index.ts +1 -0
- package/src/internals/field/useFieldControlRegistration.ts +86 -6
- package/src/menu/popup/MenuPopup.tsx +20 -1
- package/src/menu/positioner/MenuPositioner.tsx +19 -1
- package/src/menu/store/MenuStore.ts +13 -0
- package/src/menu/submenu-trigger/MenuSubmenuTrigger.tsx +3 -0
- package/src/menu/trigger/MenuTrigger.tsx +5 -2
- package/src/meter/indicator/MeterIndicator.tsx +3 -4
- package/src/meter/label/MeterLabel.tsx +3 -4
- package/src/meter/root/MeterRoot.tsx +29 -4
- package/src/meter/root/MeterRootContext.ts +5 -0
- package/src/meter/track/MeterTrack.tsx +3 -4
- package/src/meter/value/MeterValue.tsx +3 -4
- package/src/number-field/input/NumberFieldInput.tsx +11 -2
- package/src/number-field/root/NumberFieldRoot.tsx +4 -2
- package/src/otp-field/input/OTPFieldInput.tsx +4 -0
- package/src/otp-field/root/OTPFieldRoot.tsx +22 -2
- package/src/popover/popup/PopoverPopup.tsx +20 -1
- package/src/popover/positioner/PopoverPositioner.tsx +14 -0
- package/src/popover/store/PopoverStore.ts +13 -0
- package/src/popover/trigger/PopoverTrigger.tsx +5 -2
- package/src/progress/root/ProgressRoot.tsx +25 -1
- package/src/radio-group/RadioGroup.tsx +5 -2
- package/src/select/backdrop/SelectBackdrop.tsx +4 -0
- package/src/select/index.parts.ts +1 -0
- package/src/select/popup/SelectPopup.tsx +18 -1
- package/src/select/positioner/SelectPositioner.tsx +9 -3
- package/src/select/root/SelectRoot.tsx +109 -9
- package/src/select/store/SelectHandle.ts +68 -0
- package/src/select/store/SelectStore.ts +38 -1
- package/src/select/trigger/SelectTrigger.tsx +78 -7
- package/src/slider/root/SliderRoot.tsx +11 -1
- package/src/slider/thumb/SliderThumb.tsx +10 -1
- package/src/switch/root/SwitchRoot.tsx +5 -2
- package/src/tabs/tab/TabsTab.tsx +2 -10
- package/src/tooltip/popup/TooltipPopup.tsx +20 -1
- package/src/tooltip/positioner/TooltipPositioner.tsx +14 -0
- package/src/tooltip/store/TooltipStore.ts +20 -1
- package/src/tooltip/trigger/TooltipTrigger.tsx +5 -2
- package/lib/combobox/root/useComboboxRoot.d.ts +0 -29
- package/lib/combobox/root/useComboboxRoot.d.ts.map +0 -1
- package/lib/combobox/root/useComboboxRoot.js +0 -176
- package/lib/combobox/root/useComboboxRoot.js.map +0 -1
- package/lib/utils/fastObjectShallowCompare.d.ts +0 -2
- package/lib/utils/fastObjectShallowCompare.d.ts.map +0 -1
- package/lib/utils/fastObjectShallowCompare.js +0 -29
- package/lib/utils/fastObjectShallowCompare.js.map +0 -1
- package/lib/utils/mergeObjects.d.ts +0 -2
- package/lib/utils/mergeObjects.d.ts.map +0 -1
- package/lib/utils/mergeObjects.js +0 -16
- package/lib/utils/mergeObjects.js.map +0 -1
- package/src/combobox/root/useComboboxRoot.ts +0 -199
- package/src/utils/fastObjectShallowCompare.ts +0 -30
- package/src/utils/mergeObjects.ts +0 -15
|
@@ -60,7 +60,7 @@ export function DrawerPopup(componentProps: DrawerPopup.Props) {
|
|
|
60
60
|
setActiveSnapPoint,
|
|
61
61
|
snapToSequentialPoints,
|
|
62
62
|
} = useDrawerSnapPoints();
|
|
63
|
-
const { store, open, transitionStatus, props } = useDialogPopupProps();
|
|
63
|
+
const { store, open, transitionStatus, nested, nestedDialogOpen, props } = useDialogPopupProps();
|
|
64
64
|
|
|
65
65
|
const [swiping, setSwiping] = React.useState(false);
|
|
66
66
|
const [swipeMovement, setSwipeMovement] = React.useState(0);
|
|
@@ -159,6 +159,8 @@ export function DrawerPopup(componentProps: DrawerPopup.Props) {
|
|
|
159
159
|
const state: DrawerPopupState = {
|
|
160
160
|
open,
|
|
161
161
|
transitionStatus,
|
|
162
|
+
nested,
|
|
163
|
+
nestedDialogOpen,
|
|
162
164
|
swiping,
|
|
163
165
|
swipeMovement,
|
|
164
166
|
swipeDirection,
|
|
@@ -199,6 +201,15 @@ export interface DrawerPopupState {
|
|
|
199
201
|
* to `undefined` after one frame), `'ending'` once it is closing.
|
|
200
202
|
*/
|
|
201
203
|
transitionStatus: TransitionStatus;
|
|
204
|
+
/**
|
|
205
|
+
* Whether this drawer is rendered inside another dialog's tree.
|
|
206
|
+
*/
|
|
207
|
+
nested: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Whether a dialog nested inside this one is open — the cue to scale or dim
|
|
210
|
+
* this popup, which the web version drives with a CSS variable.
|
|
211
|
+
*/
|
|
212
|
+
nestedDialogOpen: boolean;
|
|
202
213
|
/**
|
|
203
214
|
* Whether a swipe is currently in progress.
|
|
204
215
|
*/
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface UseFilterParameters extends Intl.CollatorOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The locale to compare in, as a BCP 47 language tag. Defaults to the
|
|
7
|
+
* runtime's.
|
|
8
|
+
*/
|
|
9
|
+
locale?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseFilterReturnValue {
|
|
13
|
+
/**
|
|
14
|
+
* Whether `string` starts with `substring`.
|
|
15
|
+
*/
|
|
16
|
+
startsWith: (string: string, substring: string) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether `string` ends with `substring`.
|
|
19
|
+
*/
|
|
20
|
+
endsWith: (string: string, substring: string) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether `string` contains `substring` anywhere.
|
|
23
|
+
*/
|
|
24
|
+
contains: (string: string, substring: string) => boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Locale-aware string matching for filtering a list.
|
|
29
|
+
*
|
|
30
|
+
* `Intl.Collator` is what makes this better than `toLowerCase().includes()`: at
|
|
31
|
+
* the default `'base'` sensitivity, "resume" matches "Résumé" and "PENO" matches
|
|
32
|
+
* "Jalapeño" — which a lowercase comparison never will. Pass
|
|
33
|
+
* `sensitivity: 'case'` (or any other `Intl.CollatorOptions`) to tighten it.
|
|
34
|
+
*
|
|
35
|
+
* All three compare a **fixed-width** window, so a query only matches a run of
|
|
36
|
+
* the same length. Characters that fold to a different number of characters are
|
|
37
|
+
* therefore not matched across that boundary: "straße" (6) does not find
|
|
38
|
+
* "STRASSE" (7), even though the collator considers the two equal. Scanning
|
|
39
|
+
* every width instead would make every keystroke quadratic.
|
|
40
|
+
*
|
|
41
|
+
* ```tsx
|
|
42
|
+
* const { contains } = useFilter({ sensitivity: 'base' });
|
|
43
|
+
* const matches = items.filter((item) => contains(item.label, query));
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* This is the default filter behind `Combobox.Root` and `Autocomplete.Root`;
|
|
47
|
+
* use it directly when you filter the items yourself.
|
|
48
|
+
*/
|
|
49
|
+
export function useFilter(options?: UseFilterParameters): UseFilterReturnValue {
|
|
50
|
+
const { locale, ...collatorOptions } = options ?? {};
|
|
51
|
+
|
|
52
|
+
// `usage: 'search'` is what makes a collator answer "are these equal for
|
|
53
|
+
// matching purposes" rather than "how do these sort".
|
|
54
|
+
const collator = React.useMemo(
|
|
55
|
+
() =>
|
|
56
|
+
new Intl.Collator(locale, { usage: 'search', sensitivity: 'base', ...collatorOptions }),
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
[locale, JSON.stringify(collatorOptions)],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return React.useMemo(
|
|
62
|
+
() => ({
|
|
63
|
+
startsWith(string: string, substring: string) {
|
|
64
|
+
if (substring.length === 0) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return collator.compare(string.slice(0, substring.length), substring) === 0;
|
|
69
|
+
},
|
|
70
|
+
endsWith(string: string, substring: string) {
|
|
71
|
+
if (substring.length === 0) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return collator.compare(string.slice(-substring.length), substring) === 0;
|
|
76
|
+
},
|
|
77
|
+
contains(string: string, substring: string) {
|
|
78
|
+
if (substring.length === 0) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// A collator compares whole strings, so a scan is the only way to ask
|
|
83
|
+
// about a substring.
|
|
84
|
+
for (let index = 0; index <= string.length - substring.length; index += 1) {
|
|
85
|
+
if (collator.compare(string.slice(index, index + substring.length), substring) === 0) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
[collator],
|
|
94
|
+
);
|
|
95
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,23 +1,59 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
2
3
|
import { useFieldRootContext } from '../../field/root/FieldRootContext';
|
|
3
4
|
import { useStableCallback } from '../../hooks/useStableCallback';
|
|
4
5
|
|
|
6
|
+
/** Whether a value counts as "the user has put something in this control". */
|
|
7
|
+
function defaultIsFilled(value: unknown): boolean {
|
|
8
|
+
if (value == null || value === false || value === '') {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value.length > 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UseFieldControlRegistrationParameters {
|
|
20
|
+
/**
|
|
21
|
+
* The control's value at mount. `dirty` is whether the current value still
|
|
22
|
+
* equals this one.
|
|
23
|
+
*/
|
|
24
|
+
initialValue?: unknown;
|
|
25
|
+
/**
|
|
26
|
+
* Whether a value counts as filled. Defaults to "not null, empty, or false".
|
|
27
|
+
*/
|
|
28
|
+
isFilled?: ((value: unknown) => boolean) | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
5
31
|
/**
|
|
6
|
-
* Wires a non-text form control (Checkbox, Switch, RadioGroup, NumberField
|
|
7
|
-
* a surrounding `Field.Root`, when there is one.
|
|
32
|
+
* Wires a non-text form control (Checkbox, Switch, RadioGroup, NumberField,
|
|
33
|
+
* Slider, Select, OTPField) into a surrounding `Field.Root`, when there is one.
|
|
8
34
|
*
|
|
9
35
|
* A field-aware control:
|
|
10
36
|
* - is labelled by `Field.Label` and described by `Field.Description`/`Error`
|
|
11
37
|
* (through `accessibilityLabelledBy`/`accessibilityDescribedBy`);
|
|
12
38
|
* - inherits the field's (and its fieldset's) `disabled`;
|
|
13
|
-
* - runs the field's `validate` when its value changes
|
|
39
|
+
* - runs the field's `validate` when its value changes;
|
|
40
|
+
* - reports `dirty`/`filled`/`touched`/`focused` back to the field, which is
|
|
41
|
+
* what `Field.Validity` and `Field.Error` branch on.
|
|
14
42
|
*
|
|
15
43
|
* Outside a `Field.Root` everything is `undefined`/no-op, so a standalone
|
|
16
44
|
* control is unaffected.
|
|
17
45
|
*/
|
|
18
|
-
export function useFieldControlRegistration(
|
|
46
|
+
export function useFieldControlRegistration(
|
|
47
|
+
parameters: UseFieldControlRegistrationParameters = {},
|
|
48
|
+
) {
|
|
49
|
+
const { initialValue, isFilled = defaultIsFilled } = parameters;
|
|
50
|
+
|
|
19
51
|
const field = useFieldRootContext(false);
|
|
20
52
|
|
|
53
|
+
// Only the value the control mounted with decides `dirty`; a later prop change
|
|
54
|
+
// from the consumer is a new baseline they set themselves, not user input.
|
|
55
|
+
const initialValueRef = React.useRef(initialValue);
|
|
56
|
+
|
|
21
57
|
const validate = useStableCallback((value: unknown) => {
|
|
22
58
|
if (!field) {
|
|
23
59
|
return;
|
|
@@ -26,6 +62,44 @@ export function useFieldControlRegistration() {
|
|
|
26
62
|
field.setValidityData({ valid: errors.length === 0, errors });
|
|
27
63
|
});
|
|
28
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Records a user-driven value change: the field becomes dirty (unless the
|
|
67
|
+
* value is back to where it started), filled tracks the new value, and
|
|
68
|
+
* `onChange` validation runs.
|
|
69
|
+
*/
|
|
70
|
+
const markChanged = useStableCallback((value: unknown) => {
|
|
71
|
+
if (!field) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
field.setDirty(!Object.is(value, initialValueRef.current));
|
|
76
|
+
field.setFilled(isFilled(value));
|
|
77
|
+
|
|
78
|
+
if (field.validationMode === 'onChange') {
|
|
79
|
+
validate(value);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Records that the user is done with the control — the counterpart of a blur
|
|
85
|
+
* on a text input, which is when `onBlur` validation runs.
|
|
86
|
+
*/
|
|
87
|
+
const markTouched = useStableCallback((value: unknown) => {
|
|
88
|
+
if (!field) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
field.setTouched(true);
|
|
93
|
+
|
|
94
|
+
if (field.validationMode === 'onBlur') {
|
|
95
|
+
validate(value);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const markFocused = useStableCallback((focused: boolean) => {
|
|
100
|
+
field?.setFocused(focused);
|
|
101
|
+
});
|
|
102
|
+
|
|
29
103
|
const describedBy =
|
|
30
104
|
field && field.messageIds.length > 0 ? field.messageIds.join(' ') : undefined;
|
|
31
105
|
|
|
@@ -36,18 +110,24 @@ export function useFieldControlRegistration() {
|
|
|
36
110
|
fieldDisabled: field?.disabled ?? false,
|
|
37
111
|
/**
|
|
38
112
|
* Accessibility props associating the control with the field's label and
|
|
39
|
-
* messages. Spread into the control's props
|
|
113
|
+
* messages, and reporting its validity. Spread into the control's props
|
|
114
|
+
* before `elementProps`.
|
|
40
115
|
*/
|
|
41
116
|
fieldProps: {
|
|
42
117
|
accessibilityLabelledBy: field?.labelId,
|
|
43
118
|
accessibilityDescribedBy: describedBy,
|
|
44
119
|
'aria-labelledby': field?.labelId,
|
|
45
120
|
'aria-describedby': describedBy,
|
|
121
|
+
'aria-invalid': field?.validityData.valid === false || undefined,
|
|
46
122
|
},
|
|
47
123
|
/**
|
|
48
|
-
* Runs the field's validation for a new control value
|
|
124
|
+
* Runs the field's validation for a new control value, regardless of
|
|
125
|
+
* `validationMode`. No-op without a field.
|
|
49
126
|
*/
|
|
50
127
|
validateField: validate,
|
|
128
|
+
markChanged,
|
|
129
|
+
markTouched,
|
|
130
|
+
markFocused,
|
|
51
131
|
/**
|
|
52
132
|
* Whether a surrounding field is present at all.
|
|
53
133
|
*/
|
|
@@ -21,8 +21,17 @@ export function MenuPopup(componentProps: MenuPopup.Props) {
|
|
|
21
21
|
const { transitionStatus } = useMenuTransitionContext() ?? { transitionStatus: undefined };
|
|
22
22
|
|
|
23
23
|
const open = store.useState('open');
|
|
24
|
+
const triggerWidth = store.useState('triggerWidth');
|
|
25
|
+
const triggerHeight = store.useState('triggerHeight');
|
|
24
26
|
|
|
25
|
-
const state: MenuPopupState = {
|
|
27
|
+
const state: MenuPopupState = {
|
|
28
|
+
open,
|
|
29
|
+
transitionStatus,
|
|
30
|
+
side,
|
|
31
|
+
align,
|
|
32
|
+
triggerWidth,
|
|
33
|
+
triggerHeight,
|
|
34
|
+
};
|
|
26
35
|
|
|
27
36
|
const element = useRenderElement(View, componentProps, {
|
|
28
37
|
state,
|
|
@@ -60,6 +69,16 @@ export interface MenuPopupState {
|
|
|
60
69
|
* The alignment the popup was actually placed with.
|
|
61
70
|
*/
|
|
62
71
|
align: Align;
|
|
72
|
+
/**
|
|
73
|
+
* The trigger's measured width, available for consumers to size the popup
|
|
74
|
+
* against its anchor. This is the React Native equivalent of the web's
|
|
75
|
+
* `--anchor-width` CSS variable.
|
|
76
|
+
*/
|
|
77
|
+
triggerWidth: number | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The trigger's measured height.
|
|
80
|
+
*/
|
|
81
|
+
triggerHeight: number | undefined;
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
export interface MenuPopupProps extends ZestUIComponentProps<typeof View, MenuPopupState> {}
|
|
@@ -38,6 +38,8 @@ export function MenuPositioner(componentProps: MenuPositioner.Props) {
|
|
|
38
38
|
useMenuPortalContext();
|
|
39
39
|
const store = useMenuRootContext();
|
|
40
40
|
const open = store.useState('open');
|
|
41
|
+
const triggerWidth = store.useState('triggerWidth');
|
|
42
|
+
const triggerHeight = store.useState('triggerHeight');
|
|
41
43
|
const triggerNode = store.useState('triggerNode');
|
|
42
44
|
|
|
43
45
|
const positioning = useAnchorPositioning({
|
|
@@ -65,7 +67,13 @@ export function MenuPositioner(componentProps: MenuPositioner.Props) {
|
|
|
65
67
|
|
|
66
68
|
const mergedRef = useMergedRefs(ref, refs.setFloating);
|
|
67
69
|
|
|
68
|
-
const state: MenuPositionerState = {
|
|
70
|
+
const state: MenuPositionerState = {
|
|
71
|
+
open,
|
|
72
|
+
side: positioning.side,
|
|
73
|
+
align: positioning.align,
|
|
74
|
+
triggerWidth,
|
|
75
|
+
triggerHeight,
|
|
76
|
+
};
|
|
69
77
|
|
|
70
78
|
const contextValue: MenuPositionerContext = React.useMemo(
|
|
71
79
|
() => ({ side: positioning.side, align: positioning.align, arrowRef, arrowStyles }),
|
|
@@ -95,6 +103,16 @@ export interface MenuPositionerState {
|
|
|
95
103
|
open: boolean;
|
|
96
104
|
side: Side;
|
|
97
105
|
align: Align;
|
|
106
|
+
/**
|
|
107
|
+
* The trigger's measured width, available for consumers to size the popup
|
|
108
|
+
* against its anchor. This is the React Native equivalent of the web's
|
|
109
|
+
* `--anchor-width` CSS variable.
|
|
110
|
+
*/
|
|
111
|
+
triggerWidth: number | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* The trigger's measured height.
|
|
114
|
+
*/
|
|
115
|
+
triggerHeight: number | undefined;
|
|
98
116
|
}
|
|
99
117
|
|
|
100
118
|
export interface MenuPositionerProps
|
|
@@ -11,6 +11,15 @@ export type State = {
|
|
|
11
11
|
* The anchor's native node, carried across the portal boundary.
|
|
12
12
|
*/
|
|
13
13
|
triggerNode: unknown;
|
|
14
|
+
/**
|
|
15
|
+
* The trigger's measured width, the React Native counterpart of the web's
|
|
16
|
+
* `--anchor-width` CSS variable.
|
|
17
|
+
*/
|
|
18
|
+
triggerWidth: number | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The trigger's measured height.
|
|
21
|
+
*/
|
|
22
|
+
triggerHeight: number | undefined;
|
|
14
23
|
update: (() => void) | undefined;
|
|
15
24
|
/**
|
|
16
25
|
* The payload of the trigger the popup was opened by, handed to the root's
|
|
@@ -40,6 +49,8 @@ const selectors = {
|
|
|
40
49
|
open: createSelector((state: State) => state.openProp ?? state.open),
|
|
41
50
|
disablePointerDismissal: createSelector((state: State) => state.disablePointerDismissal),
|
|
42
51
|
triggerNode: createSelector((state: State) => state.triggerNode),
|
|
52
|
+
triggerWidth: createSelector((state: State) => state.triggerWidth),
|
|
53
|
+
triggerHeight: createSelector((state: State) => state.triggerHeight),
|
|
43
54
|
update: createSelector((state: State) => state.update),
|
|
44
55
|
payload: createSelector((state: State) => state.payload),
|
|
45
56
|
triggerId: createSelector((state: State) => state.triggerIdProp ?? state.triggerId),
|
|
@@ -53,6 +64,8 @@ export class MenuStore extends ReactStore<Readonly<State>, Context, typeof selec
|
|
|
53
64
|
openProp: undefined,
|
|
54
65
|
disablePointerDismissal: false,
|
|
55
66
|
triggerNode: null,
|
|
67
|
+
triggerWidth: undefined,
|
|
68
|
+
triggerHeight: undefined,
|
|
56
69
|
update: undefined,
|
|
57
70
|
payload: undefined,
|
|
58
71
|
triggerId: null,
|
|
@@ -62,6 +62,9 @@ export function MenuSubmenuTrigger(componentProps: MenuSubmenuTrigger.Props) {
|
|
|
62
62
|
{
|
|
63
63
|
onLayout(event: LayoutChangeEvent) {
|
|
64
64
|
onLayout(event);
|
|
65
|
+
const { width, height } = event.nativeEvent.layout;
|
|
66
|
+
store.set('triggerWidth', width);
|
|
67
|
+
store.set('triggerHeight', height);
|
|
65
68
|
store.state.update?.();
|
|
66
69
|
},
|
|
67
70
|
accessibilityRole: 'menuitem' as const,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { Pressable, type GestureResponderEvent } from 'react-native';
|
|
3
|
+
import { Pressable, type GestureResponderEvent, type LayoutChangeEvent } from 'react-native';
|
|
4
4
|
import { MenuRootContext } from '../root/MenuRootContext';
|
|
5
5
|
import { useRenderElement } from '../../use-render/useRenderElement';
|
|
6
6
|
import { useButton } from '../../internals/use-button/useButton';
|
|
@@ -98,7 +98,10 @@ export function MenuTrigger<Payload = unknown>(componentProps: MenuTrigger.Props
|
|
|
98
98
|
onPressOut() {
|
|
99
99
|
setPressed(false);
|
|
100
100
|
},
|
|
101
|
-
onLayout() {
|
|
101
|
+
onLayout(event: LayoutChangeEvent) {
|
|
102
|
+
const { width, height } = event.nativeEvent.layout;
|
|
103
|
+
store.set('triggerWidth', width);
|
|
104
|
+
store.set('triggerHeight', height);
|
|
102
105
|
store.state.update?.();
|
|
103
106
|
},
|
|
104
107
|
accessibilityState: { expanded: open, disabled: disabled || undefined },
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { useMeterRootContext } from '../root/MeterRootContext';
|
|
4
4
|
import { useRenderElement } from '../../use-render/useRenderElement';
|
|
5
|
+
import type { MeterRootState } from '../root/MeterRoot';
|
|
5
6
|
import type { ZestUIComponentProps } from '../../types';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -11,9 +12,7 @@ import type { ZestUIComponentProps } from '../../types';
|
|
|
11
12
|
export function MeterIndicator(componentProps: MeterIndicator.Props) {
|
|
12
13
|
const { render, className, style, ref, ...elementProps } = componentProps;
|
|
13
14
|
|
|
14
|
-
const { percentageValue } = useMeterRootContext();
|
|
15
|
-
|
|
16
|
-
const state: MeterIndicatorState = {};
|
|
15
|
+
const { percentageValue, state } = useMeterRootContext();
|
|
17
16
|
|
|
18
17
|
return useRenderElement(View, componentProps, {
|
|
19
18
|
state,
|
|
@@ -22,7 +21,7 @@ export function MeterIndicator(componentProps: MeterIndicator.Props) {
|
|
|
22
21
|
});
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
export interface MeterIndicatorState {}
|
|
24
|
+
export interface MeterIndicatorState extends MeterRootState {}
|
|
26
25
|
|
|
27
26
|
export interface MeterIndicatorProps
|
|
28
27
|
extends ZestUIComponentProps<typeof View, MeterIndicatorState> {}
|
|
@@ -4,6 +4,7 @@ import { useMeterRootContext } from '../root/MeterRootContext';
|
|
|
4
4
|
import { useRenderElement } from '../../use-render/useRenderElement';
|
|
5
5
|
import { useId } from '../../hooks/useId';
|
|
6
6
|
import { useIsoLayoutEffect } from '../../hooks/useIsoLayoutEffect';
|
|
7
|
+
import type { MeterRootState } from '../root/MeterRoot';
|
|
7
8
|
import type { ZestUIComponentProps } from '../../types';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -13,7 +14,7 @@ import type { ZestUIComponentProps } from '../../types';
|
|
|
13
14
|
export function MeterLabel(componentProps: MeterLabel.Props) {
|
|
14
15
|
const { render, className, style, nativeID: idProp, ref, ...elementProps } = componentProps;
|
|
15
16
|
|
|
16
|
-
const { setLabelId } = useMeterRootContext();
|
|
17
|
+
const { setLabelId, state } = useMeterRootContext();
|
|
17
18
|
|
|
18
19
|
const id = useId(idProp ?? undefined);
|
|
19
20
|
|
|
@@ -22,8 +23,6 @@ export function MeterLabel(componentProps: MeterLabel.Props) {
|
|
|
22
23
|
return () => setLabelId(undefined);
|
|
23
24
|
}, [id, setLabelId]);
|
|
24
25
|
|
|
25
|
-
const state: MeterLabelState = {};
|
|
26
|
-
|
|
27
26
|
return useRenderElement(Text, componentProps, {
|
|
28
27
|
state,
|
|
29
28
|
ref,
|
|
@@ -31,7 +30,7 @@ export function MeterLabel(componentProps: MeterLabel.Props) {
|
|
|
31
30
|
});
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
export interface MeterLabelState {}
|
|
33
|
+
export interface MeterLabelState extends MeterRootState {}
|
|
35
34
|
|
|
36
35
|
export interface MeterLabelProps extends ZestUIComponentProps<typeof Text, MeterLabelState> {}
|
|
37
36
|
|
|
@@ -45,11 +45,14 @@ export function MeterRoot(componentProps: MeterRoot.Props) {
|
|
|
45
45
|
? formatNumber(value, locale, format)
|
|
46
46
|
: formatNumber(percentageValue / 100, locale, { style: 'percent' });
|
|
47
47
|
|
|
48
|
-
const state: MeterRootState = React.useMemo(
|
|
48
|
+
const state: MeterRootState = React.useMemo(
|
|
49
|
+
() => ({ value: clampedValue, min, max, percent: percentageValue, formattedValue }),
|
|
50
|
+
[clampedValue, min, max, percentageValue, formattedValue],
|
|
51
|
+
);
|
|
49
52
|
|
|
50
53
|
const contextValue: MeterRootContext = React.useMemo(
|
|
51
|
-
() => ({ formattedValue, percentageValue, setLabelId, value }),
|
|
52
|
-
[formattedValue, percentageValue, value],
|
|
54
|
+
() => ({ formattedValue, percentageValue, setLabelId, state, value }),
|
|
55
|
+
[formattedValue, percentageValue, state, value],
|
|
53
56
|
);
|
|
54
57
|
|
|
55
58
|
const element = useRenderElement(View, componentProps, {
|
|
@@ -83,7 +86,29 @@ function valueToPercent(value: number, min: number, max: number) {
|
|
|
83
86
|
return ((value - min) * 100) / (max - min);
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
export interface MeterRootState {
|
|
89
|
+
export interface MeterRootState {
|
|
90
|
+
/**
|
|
91
|
+
* The current value, clamped into `[min, max]`.
|
|
92
|
+
*/
|
|
93
|
+
value: number;
|
|
94
|
+
/**
|
|
95
|
+
* The minimum value.
|
|
96
|
+
*/
|
|
97
|
+
min: number;
|
|
98
|
+
/**
|
|
99
|
+
* The maximum value.
|
|
100
|
+
*/
|
|
101
|
+
max: number;
|
|
102
|
+
/**
|
|
103
|
+
* How far the value sits through the range, `0`–`100`. This is what an
|
|
104
|
+
* indicator's width comes from.
|
|
105
|
+
*/
|
|
106
|
+
percent: number;
|
|
107
|
+
/**
|
|
108
|
+
* The value as text, through `format`/`locale`.
|
|
109
|
+
*/
|
|
110
|
+
formattedValue: string;
|
|
111
|
+
}
|
|
87
112
|
|
|
88
113
|
export interface MeterRootProps extends ZestUIComponentProps<typeof View, MeterRootState> {
|
|
89
114
|
/**
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
+
import type { MeterRootState } from './MeterRoot';
|
|
3
4
|
|
|
4
5
|
export interface MeterRootContext {
|
|
6
|
+
/**
|
|
7
|
+
* The state every part publishes to its style and render functions.
|
|
8
|
+
*/
|
|
9
|
+
state: MeterRootState;
|
|
5
10
|
/**
|
|
6
11
|
* The current value.
|
|
7
12
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { useMeterRootContext } from '../root/MeterRootContext';
|
|
4
4
|
import { useRenderElement } from '../../use-render/useRenderElement';
|
|
5
|
+
import type { MeterRootState } from '../root/MeterRoot';
|
|
5
6
|
import type { ZestUIComponentProps } from '../../types';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -11,9 +12,7 @@ import type { ZestUIComponentProps } from '../../types';
|
|
|
11
12
|
export function MeterTrack(componentProps: MeterTrack.Props) {
|
|
12
13
|
const { render, className, style, ref, ...elementProps } = componentProps;
|
|
13
14
|
|
|
14
|
-
useMeterRootContext();
|
|
15
|
-
|
|
16
|
-
const state: MeterTrackState = {};
|
|
15
|
+
const { state } = useMeterRootContext();
|
|
17
16
|
|
|
18
17
|
return useRenderElement(View, componentProps, {
|
|
19
18
|
state,
|
|
@@ -22,7 +21,7 @@ export function MeterTrack(componentProps: MeterTrack.Props) {
|
|
|
22
21
|
});
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
export interface MeterTrackState {}
|
|
24
|
+
export interface MeterTrackState extends MeterRootState {}
|
|
26
25
|
|
|
27
26
|
export interface MeterTrackProps extends ZestUIComponentProps<typeof View, MeterTrackState> {}
|
|
28
27
|
|
|
@@ -3,6 +3,7 @@ import type * as React from 'react';
|
|
|
3
3
|
import { Text } from 'react-native';
|
|
4
4
|
import { useMeterRootContext } from '../root/MeterRootContext';
|
|
5
5
|
import { useRenderElement } from '../../use-render/useRenderElement';
|
|
6
|
+
import type { MeterRootState } from '../root/MeterRoot';
|
|
6
7
|
import type { ZestUIComponentProps } from '../../types';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -15,9 +16,7 @@ import type { ZestUIComponentProps } from '../../types';
|
|
|
15
16
|
export function MeterValue(componentProps: MeterValue.Props) {
|
|
16
17
|
const { render, className, style, children, ref, ...elementProps } = componentProps;
|
|
17
18
|
|
|
18
|
-
const { value, formattedValue } = useMeterRootContext();
|
|
19
|
-
|
|
20
|
-
const state: MeterValueState = {};
|
|
19
|
+
const { value, formattedValue, state } = useMeterRootContext();
|
|
21
20
|
|
|
22
21
|
return useRenderElement(Text, componentProps, {
|
|
23
22
|
state,
|
|
@@ -35,7 +34,7 @@ export function MeterValue(componentProps: MeterValue.Props) {
|
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
export interface MeterValueState {}
|
|
37
|
+
export interface MeterValueState extends MeterRootState {}
|
|
39
38
|
|
|
40
39
|
export interface MeterValueProps
|
|
41
40
|
extends Omit<ZestUIComponentProps<typeof Text, MeterValueState>, 'children'> {
|
|
@@ -43,7 +43,7 @@ export function NumberFieldInput(componentProps: NumberFieldInput.Props) {
|
|
|
43
43
|
|
|
44
44
|
const { disabled, readOnly, value, inputValue } = state;
|
|
45
45
|
|
|
46
|
-
const { fieldProps } = useFieldControlRegistration();
|
|
46
|
+
const { fieldProps, markTouched, markFocused } = useFieldControlRegistration();
|
|
47
47
|
|
|
48
48
|
const handleChangeText = useStableCallback((text: string) => {
|
|
49
49
|
if (disabled || readOnly) {
|
|
@@ -147,7 +147,16 @@ export function NumberFieldInput(componentProps: NumberFieldInput.Props) {
|
|
|
147
147
|
nativeID: id,
|
|
148
148
|
value: inputValue,
|
|
149
149
|
onChangeText: handleChangeText,
|
|
150
|
-
|
|
150
|
+
onFocus() {
|
|
151
|
+
markFocused(true);
|
|
152
|
+
},
|
|
153
|
+
onBlur(event: NativeSyntheticEvent<TextInputFocusEventData>) {
|
|
154
|
+
markFocused(false);
|
|
155
|
+
// Leaving the input is what ends the interaction, the same way it does
|
|
156
|
+
// for a text control — so this is where `onBlur` validation runs.
|
|
157
|
+
markTouched(valueRef.current);
|
|
158
|
+
handleBlur(event);
|
|
159
|
+
},
|
|
151
160
|
editable: !disabled && !readOnly,
|
|
152
161
|
// `numeric` rather than `decimal-pad`: a locale's format may include a
|
|
153
162
|
// decimal separator, a minus sign or a currency symbol, and the numeric
|
|
@@ -52,7 +52,9 @@ export function NumberFieldRoot(componentProps: NumberFieldRoot.Props) {
|
|
|
52
52
|
...elementProps
|
|
53
53
|
} = componentProps;
|
|
54
54
|
|
|
55
|
-
const { fieldDisabled,
|
|
55
|
+
const { fieldDisabled, markChanged } = useFieldControlRegistration({
|
|
56
|
+
initialValue: defaultValue ?? valueProp ?? null,
|
|
57
|
+
});
|
|
56
58
|
|
|
57
59
|
const disabled = disabledProp || fieldDisabled;
|
|
58
60
|
|
|
@@ -135,7 +137,7 @@ export function NumberFieldRoot(componentProps: NumberFieldRoot.Props) {
|
|
|
135
137
|
|
|
136
138
|
valueRef.current = validatedValue;
|
|
137
139
|
setValueState(validatedValue);
|
|
138
|
-
|
|
140
|
+
markChanged(validatedValue);
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
lastChangedValueRef.current = validatedValue;
|
|
@@ -163,6 +163,10 @@ export function OTPFieldInput(componentProps: OTPFieldInput.Props) {
|
|
|
163
163
|
autoComplete: (index === 0 ? autoComplete : 'off') as 'one-time-code' | 'off',
|
|
164
164
|
textContentType: index === 0 ? ('oneTimeCode' as const) : ('none' as const),
|
|
165
165
|
enterKeyHint: index === length - 1 ? ('done' as const) : ('next' as const),
|
|
166
|
+
// Every slot is an identical one-character box, so position is the only
|
|
167
|
+
// thing that tells them apart out loud. A consumer-supplied
|
|
168
|
+
// `accessibilityLabel` in `elementProps` still wins.
|
|
169
|
+
accessibilityLabel: `Digit ${index + 1} of ${length}`,
|
|
166
170
|
accessibilityState: { disabled: disabled || undefined },
|
|
167
171
|
},
|
|
168
172
|
elementProps,
|