@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
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { TextInput } from 'react-native';
|
|
2
|
+
import { createSelector } from '../../store/createSelector';
|
|
3
|
+
import { ReactStore } from '../../store/ReactStore';
|
|
4
|
+
import { PopupTriggerMap } from '../../utils/popups/PopupTriggerMap';
|
|
5
|
+
import type { ComboboxRoot } from '../root/ComboboxRoot';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The items to filter and choose from: strings, or `{ value, label }` records
|
|
9
|
+
* for non-string values.
|
|
10
|
+
*/
|
|
11
|
+
export type ComboboxItems = ReadonlyArray<string | { value: unknown; label: string }>;
|
|
12
|
+
|
|
13
|
+
export interface ComboboxItem {
|
|
14
|
+
value: unknown;
|
|
15
|
+
label: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Normalizes the `items` prop into `{ value, label }` records. */
|
|
19
|
+
export function normalizeComboboxItems(items: ComboboxItems | undefined): ComboboxItem[] {
|
|
20
|
+
if (!items) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return items.map((item) =>
|
|
25
|
+
typeof item === 'string' ? { value: item, label: item } : { value: item.value, label: item.label },
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type State = {
|
|
30
|
+
/**
|
|
31
|
+
* The uncontrolled open state. Read through the `open` selector, which
|
|
32
|
+
* resolves the controlled prop first.
|
|
33
|
+
*/
|
|
34
|
+
open: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The controlled `open` prop, when provided.
|
|
37
|
+
*/
|
|
38
|
+
openProp: boolean | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* The uncontrolled selected value. Read through the `value` selector.
|
|
41
|
+
*/
|
|
42
|
+
value: unknown;
|
|
43
|
+
/**
|
|
44
|
+
* The controlled `value` prop, when provided.
|
|
45
|
+
*/
|
|
46
|
+
valueProp: unknown;
|
|
47
|
+
/**
|
|
48
|
+
* The uncontrolled input text. Read through the `inputValue` selector.
|
|
49
|
+
*/
|
|
50
|
+
inputValue: string;
|
|
51
|
+
/**
|
|
52
|
+
* The controlled `inputValue` prop, when provided.
|
|
53
|
+
*/
|
|
54
|
+
inputValueProp: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Every item, normalized.
|
|
57
|
+
*/
|
|
58
|
+
items: ComboboxItem[];
|
|
59
|
+
/**
|
|
60
|
+
* `'combobox'` selects a value and shows its label; `'autocomplete'` is free
|
|
61
|
+
* text with suggestions, where the typed string is the value.
|
|
62
|
+
*/
|
|
63
|
+
mode: 'combobox' | 'autocomplete';
|
|
64
|
+
disabled: boolean;
|
|
65
|
+
disablePointerDismissal: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Whether focusing the input opens the list.
|
|
68
|
+
*/
|
|
69
|
+
openOnFocus: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* The anchor's native node, carried across the portal boundary.
|
|
72
|
+
*/
|
|
73
|
+
triggerNode: unknown;
|
|
74
|
+
/**
|
|
75
|
+
* The input's measured width, used to size the popup.
|
|
76
|
+
*/
|
|
77
|
+
triggerWidth: number | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The input's measured height.
|
|
80
|
+
*/
|
|
81
|
+
triggerHeight: number | undefined;
|
|
82
|
+
update: (() => void) | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Ref to the input element, for programmatic blur.
|
|
85
|
+
*/
|
|
86
|
+
inputRef: React.RefObject<TextInput | null> | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* The payload of the trigger the popup was opened by, handed to the root's
|
|
89
|
+
* children when they are a function.
|
|
90
|
+
*/
|
|
91
|
+
payload: unknown;
|
|
92
|
+
/**
|
|
93
|
+
* The id of the trigger the popup is associated with, or `null` for none.
|
|
94
|
+
*/
|
|
95
|
+
triggerId: string | null;
|
|
96
|
+
/**
|
|
97
|
+
* The controlled `triggerId` prop, when provided.
|
|
98
|
+
*/
|
|
99
|
+
triggerIdProp: string | null | undefined;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
type Context = {
|
|
103
|
+
onOpenChange:
|
|
104
|
+
| ((open: boolean, eventDetails: ComboboxRoot.ChangeEventDetails) => void)
|
|
105
|
+
| undefined;
|
|
106
|
+
onValueChange:
|
|
107
|
+
| ((value: any, eventDetails: ComboboxRoot.ChangeEventDetails) => void)
|
|
108
|
+
| undefined;
|
|
109
|
+
onInputValueChange:
|
|
110
|
+
| ((value: string, eventDetails: ComboboxRoot.ChangeEventDetails) => void)
|
|
111
|
+
| undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Every trigger bound to this root, by id. A handle resolves `open(id)`
|
|
114
|
+
* through this, which is what lets an input rendered outside the root open it.
|
|
115
|
+
*/
|
|
116
|
+
triggerNodes: PopupTriggerMap;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const selectors = {
|
|
120
|
+
open: createSelector((state: State) => state.openProp ?? state.open),
|
|
121
|
+
value: createSelector((state: State) =>
|
|
122
|
+
state.valueProp !== undefined ? state.valueProp : state.value,
|
|
123
|
+
),
|
|
124
|
+
inputValue: createSelector((state: State) => state.inputValueProp ?? state.inputValue),
|
|
125
|
+
items: createSelector((state: State) => state.items),
|
|
126
|
+
mode: createSelector((state: State) => state.mode),
|
|
127
|
+
disabled: createSelector((state: State) => state.disabled),
|
|
128
|
+
disablePointerDismissal: createSelector((state: State) => state.disablePointerDismissal),
|
|
129
|
+
openOnFocus: createSelector((state: State) => state.openOnFocus),
|
|
130
|
+
triggerNode: createSelector((state: State) => state.triggerNode),
|
|
131
|
+
triggerWidth: createSelector((state: State) => state.triggerWidth),
|
|
132
|
+
triggerHeight: createSelector((state: State) => state.triggerHeight),
|
|
133
|
+
update: createSelector((state: State) => state.update),
|
|
134
|
+
inputRef: createSelector((state: State) => state.inputRef),
|
|
135
|
+
payload: createSelector((state: State) => state.payload),
|
|
136
|
+
triggerId: createSelector((state: State) => state.triggerIdProp ?? state.triggerId),
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The store behind `Combobox.Root` and `Autocomplete.Root`.
|
|
141
|
+
*
|
|
142
|
+
* It follows the same controlled-prop and cancelable-event contract as the other
|
|
143
|
+
* popup families: every change fires its callback first and only commits the
|
|
144
|
+
* uncontrolled key when the consumer has not called `eventDetails.cancel()`.
|
|
145
|
+
*/
|
|
146
|
+
export class ComboboxStore extends ReactStore<Readonly<State>, Context, typeof selectors> {
|
|
147
|
+
constructor(initialState?: Partial<State>) {
|
|
148
|
+
super(
|
|
149
|
+
{
|
|
150
|
+
open: false,
|
|
151
|
+
openProp: undefined,
|
|
152
|
+
value: null,
|
|
153
|
+
valueProp: undefined,
|
|
154
|
+
inputValue: '',
|
|
155
|
+
inputValueProp: undefined,
|
|
156
|
+
items: [],
|
|
157
|
+
mode: 'combobox',
|
|
158
|
+
disabled: false,
|
|
159
|
+
disablePointerDismissal: false,
|
|
160
|
+
openOnFocus: true,
|
|
161
|
+
triggerNode: null,
|
|
162
|
+
triggerWidth: undefined,
|
|
163
|
+
triggerHeight: undefined,
|
|
164
|
+
update: undefined,
|
|
165
|
+
inputRef: undefined,
|
|
166
|
+
payload: undefined,
|
|
167
|
+
triggerId: null,
|
|
168
|
+
triggerIdProp: undefined,
|
|
169
|
+
...initialState,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
onOpenChange: undefined,
|
|
173
|
+
onValueChange: undefined,
|
|
174
|
+
onInputValueChange: undefined,
|
|
175
|
+
triggerNodes: new PopupTriggerMap(),
|
|
176
|
+
},
|
|
177
|
+
selectors,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public setOpen = (nextOpen: boolean, eventDetails: ComboboxRoot.ChangeEventDetails) => {
|
|
182
|
+
if (nextOpen === this.select('open')) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.context.onOpenChange?.(nextOpen, eventDetails);
|
|
187
|
+
|
|
188
|
+
if (eventDetails.isCanceled) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.set('open', nextOpen);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
public setValue = (nextValue: unknown, eventDetails: ComboboxRoot.ChangeEventDetails) => {
|
|
196
|
+
this.context.onValueChange?.(nextValue, eventDetails);
|
|
197
|
+
|
|
198
|
+
if (eventDetails.isCanceled) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this.set('value', nextValue);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
public setInputValue = (nextValue: string, eventDetails: ComboboxRoot.ChangeEventDetails) => {
|
|
206
|
+
this.context.onInputValueChange?.(nextValue, eventDetails);
|
|
207
|
+
|
|
208
|
+
if (eventDetails.isCanceled) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.set('inputValue', nextValue);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Reflects a value the consumer changed from outside into the input text.
|
|
217
|
+
*
|
|
218
|
+
* This is not a change the consumer made through the combobox, so it fires no
|
|
219
|
+
* callback — it writes the uncontrolled key directly.
|
|
220
|
+
*/
|
|
221
|
+
public reflectInputValue = (nextValue: string) => {
|
|
222
|
+
this.set('inputValue', nextValue);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Selects an item: records the value, fills the input with its label, and
|
|
227
|
+
* closes the popup.
|
|
228
|
+
*
|
|
229
|
+
* One `eventDetails` object is shared by all three, so canceling in any
|
|
230
|
+
* handler stops the rest — the same contract the group components use.
|
|
231
|
+
*/
|
|
232
|
+
public selectItem = (item: ComboboxItem, eventDetails: ComboboxRoot.ChangeEventDetails) => {
|
|
233
|
+
if (this.select('mode') === 'combobox') {
|
|
234
|
+
this.setValue(item.value, eventDetails);
|
|
235
|
+
|
|
236
|
+
if (eventDetails.isCanceled) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
this.setInputValue(item.label, eventDetails);
|
|
242
|
+
|
|
243
|
+
if (eventDetails.isCanceled) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
this.setOpen(false, eventDetails);
|
|
248
|
+
};
|
|
249
|
+
}
|
|
@@ -13,7 +13,8 @@ import type { ZestUIComponentProps } from '../../types';
|
|
|
13
13
|
export function ComboboxValue(componentProps: ComboboxValue.Props) {
|
|
14
14
|
const { render, className, style, children, ref, ...elementProps } = componentProps;
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const store = useComboboxRootContext();
|
|
17
|
+
const inputValue = store.useState('inputValue');
|
|
17
18
|
|
|
18
19
|
const state: ComboboxValueState = { value: inputValue };
|
|
19
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { View } from 'react-native';
|
|
3
|
+
import { View, useWindowDimensions, type LayoutChangeEvent } from 'react-native';
|
|
4
4
|
import { useMenuRootContext } from '../../menu/root/MenuRootContext';
|
|
5
5
|
import { useMenuPortalContext } from '../../menu/portal/MenuPortalContext';
|
|
6
6
|
import { MenuPositionerContext } from '../../menu/positioner/MenuPositionerContext';
|
|
@@ -15,31 +15,97 @@ const NO_ARROW = { current: null };
|
|
|
15
15
|
* Positions the context menu popup at the point the long press landed.
|
|
16
16
|
* Renders a `<View>`.
|
|
17
17
|
*
|
|
18
|
-
* Unlike `Menu.Positioner
|
|
19
|
-
* element, so
|
|
20
|
-
*
|
|
18
|
+
* Unlike `Menu.Positioner` it anchors to a screen point rather than a trigger
|
|
19
|
+
* element, so it does not go through `useAnchorPositioning`: floating-ui
|
|
20
|
+
* measures a real node, and there is no node here. Collision handling is
|
|
21
|
+
* therefore its own — the popup flips to the other side of the press point when
|
|
22
|
+
* it would otherwise run off the screen, and is kept `collisionPadding` inside
|
|
23
|
+
* the edges. `side` and `align` on state report where it actually landed.
|
|
21
24
|
*/
|
|
22
25
|
export function ContextMenuPositioner(componentProps: ContextMenuPositioner.Props) {
|
|
23
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
render,
|
|
28
|
+
className,
|
|
29
|
+
collisionPadding = 5,
|
|
30
|
+
style,
|
|
31
|
+
ref,
|
|
32
|
+
...elementProps
|
|
33
|
+
} = componentProps;
|
|
24
34
|
|
|
25
35
|
useMenuPortalContext();
|
|
26
36
|
const store = useMenuRootContext();
|
|
27
37
|
const { anchor } = useContextMenuRootContext();
|
|
28
38
|
|
|
29
39
|
const open = store.useState('open');
|
|
40
|
+
const { width: screenWidth, height: screenHeight } = useWindowDimensions();
|
|
41
|
+
|
|
42
|
+
// The popup's own size, which only exists after it has been laid out. Until
|
|
43
|
+
// then it is placed at the press point unflipped, exactly as before.
|
|
44
|
+
const [size, setSize] = React.useState<{ width: number; height: number } | undefined>(undefined);
|
|
45
|
+
|
|
46
|
+
const onLayout = React.useCallback((event: LayoutChangeEvent) => {
|
|
47
|
+
const { width, height } = event.nativeEvent.layout;
|
|
48
|
+
setSize((previous) =>
|
|
49
|
+
previous?.width === width && previous?.height === height ? previous : { width, height },
|
|
50
|
+
);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
// A closed menu remeasures when it reopens somewhere else, so stale geometry
|
|
54
|
+
// never decides the first frame of the next open.
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
if (!open) {
|
|
57
|
+
setSize(undefined);
|
|
58
|
+
}
|
|
59
|
+
}, [open]);
|
|
60
|
+
|
|
61
|
+
const placement = React.useMemo(() => {
|
|
62
|
+
if (size === undefined) {
|
|
63
|
+
return { left: anchor.x, top: anchor.y, side: 'bottom' as Side, align: 'start' as Align };
|
|
64
|
+
}
|
|
30
65
|
|
|
31
|
-
|
|
66
|
+
const flipHorizontally = anchor.x + size.width > screenWidth - collisionPadding;
|
|
67
|
+
const flipVertically = anchor.y + size.height > screenHeight - collisionPadding;
|
|
68
|
+
|
|
69
|
+
const rawLeft = flipHorizontally ? anchor.x - size.width : anchor.x;
|
|
70
|
+
const rawTop = flipVertically ? anchor.y - size.height : anchor.y;
|
|
71
|
+
|
|
72
|
+
// Clamping matters when the popup is larger than the space on either side:
|
|
73
|
+
// flipping alone would just move the overflow to the opposite edge.
|
|
74
|
+
const maxLeft = Math.max(collisionPadding, screenWidth - size.width - collisionPadding);
|
|
75
|
+
const maxTop = Math.max(collisionPadding, screenHeight - size.height - collisionPadding);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
left: Math.min(Math.max(rawLeft, collisionPadding), maxLeft),
|
|
79
|
+
top: Math.min(Math.max(rawTop, collisionPadding), maxTop),
|
|
80
|
+
side: (flipVertically ? 'top' : 'bottom') as Side,
|
|
81
|
+
align: (flipHorizontally ? 'end' : 'start') as Align,
|
|
82
|
+
};
|
|
83
|
+
}, [anchor.x, anchor.y, size, screenWidth, screenHeight, collisionPadding]);
|
|
84
|
+
|
|
85
|
+
const state: ContextMenuPositionerState = {
|
|
86
|
+
open,
|
|
87
|
+
side: placement.side,
|
|
88
|
+
align: placement.align,
|
|
89
|
+
};
|
|
32
90
|
|
|
33
91
|
const contextValue: MenuPositionerContext = React.useMemo(
|
|
34
|
-
() => ({
|
|
35
|
-
|
|
92
|
+
() => ({
|
|
93
|
+
side: placement.side,
|
|
94
|
+
align: placement.align,
|
|
95
|
+
arrowRef: NO_ARROW,
|
|
96
|
+
arrowStyles: {},
|
|
97
|
+
}),
|
|
98
|
+
[placement.side, placement.align],
|
|
36
99
|
);
|
|
37
100
|
|
|
38
101
|
const element = useRenderElement(View, componentProps, {
|
|
39
102
|
state,
|
|
40
103
|
ref,
|
|
41
104
|
props: [
|
|
42
|
-
{
|
|
105
|
+
{
|
|
106
|
+
style: { position: 'absolute' as const, left: placement.left, top: placement.top },
|
|
107
|
+
onLayout,
|
|
108
|
+
},
|
|
43
109
|
elementProps,
|
|
44
110
|
],
|
|
45
111
|
});
|
|
@@ -53,12 +119,26 @@ export function ContextMenuPositioner(componentProps: ContextMenuPositioner.Prop
|
|
|
53
119
|
|
|
54
120
|
export interface ContextMenuPositionerState {
|
|
55
121
|
open: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* `'bottom'` when the popup hangs below the press point, `'top'` when it was
|
|
124
|
+
* flipped above it to stay on screen.
|
|
125
|
+
*/
|
|
56
126
|
side: Side;
|
|
127
|
+
/**
|
|
128
|
+
* `'start'` when the popup extends right of the press point, `'end'` when it
|
|
129
|
+
* was flipped to its left.
|
|
130
|
+
*/
|
|
57
131
|
align: Align;
|
|
58
132
|
}
|
|
59
133
|
|
|
60
134
|
export interface ContextMenuPositionerProps
|
|
61
|
-
extends ZestUIComponentProps<typeof View, ContextMenuPositionerState> {
|
|
135
|
+
extends ZestUIComponentProps<typeof View, ContextMenuPositionerState> {
|
|
136
|
+
/**
|
|
137
|
+
* How much space to keep between the popup and the edges of the screen.
|
|
138
|
+
* @default 5
|
|
139
|
+
*/
|
|
140
|
+
collisionPadding?: number | undefined;
|
|
141
|
+
}
|
|
62
142
|
|
|
63
143
|
export namespace ContextMenuPositioner {
|
|
64
144
|
export type State = ContextMenuPositionerState;
|
|
@@ -43,4 +43,12 @@ export interface ContextMenuRootProps
|
|
|
43
43
|
export namespace ContextMenuRoot {
|
|
44
44
|
export type State = ContextMenuRootState;
|
|
45
45
|
export type Props = ContextMenuRootProps;
|
|
46
|
+
/**
|
|
47
|
+
* A context menu is a menu, so it reuses the menu's action and event
|
|
48
|
+
* contracts — a consumer should not have to reach for `Menu.Root`'s types to
|
|
49
|
+
* type a `ContextMenu.Root` handler.
|
|
50
|
+
*/
|
|
51
|
+
export type Actions = MenuRoot.Actions;
|
|
52
|
+
export type ChangeEventReason = MenuRoot.ChangeEventReason;
|
|
53
|
+
export type ChangeEventDetails = MenuRoot.ChangeEventDetails;
|
|
46
54
|
}
|
|
@@ -16,8 +16,10 @@ export function DialogBackdrop(componentProps: DialogBackdrop.Props) {
|
|
|
16
16
|
|
|
17
17
|
const store = useDialogRootContext();
|
|
18
18
|
const open = store.useState('open');
|
|
19
|
+
const nested = store.useState('nested');
|
|
20
|
+
const nestedDialogOpen = store.useState('nestedDialogOpen');
|
|
19
21
|
|
|
20
|
-
const state: DialogBackdropState = { open };
|
|
22
|
+
const state: DialogBackdropState = { open, nested, nestedDialogOpen };
|
|
21
23
|
|
|
22
24
|
return useRenderElement(View, componentProps, {
|
|
23
25
|
state,
|
|
@@ -39,6 +41,15 @@ export interface DialogBackdropState {
|
|
|
39
41
|
* Whether the dialog is currently open.
|
|
40
42
|
*/
|
|
41
43
|
open: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Whether this dialog is rendered inside another dialog's tree.
|
|
46
|
+
*/
|
|
47
|
+
nested: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a dialog nested inside this one is open — a backdrop usually wants
|
|
50
|
+
* to darken further while it is.
|
|
51
|
+
*/
|
|
52
|
+
nestedDialogOpen: boolean;
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
export interface DialogBackdropProps
|
|
@@ -12,9 +12,9 @@ import { useDialogPopupProps } from './useDialogPopupProps';
|
|
|
12
12
|
export function DialogPopup(componentProps: DialogPopup.Props) {
|
|
13
13
|
const { render, className, style, ref, ...elementProps } = componentProps;
|
|
14
14
|
|
|
15
|
-
const { open, transitionStatus, props } = useDialogPopupProps();
|
|
15
|
+
const { open, transitionStatus, nested, nestedDialogOpen, props } = useDialogPopupProps();
|
|
16
16
|
|
|
17
|
-
const state: DialogPopupState = { open, transitionStatus };
|
|
17
|
+
const state: DialogPopupState = { open, transitionStatus, nested, nestedDialogOpen };
|
|
18
18
|
|
|
19
19
|
return useRenderElement(View, componentProps, {
|
|
20
20
|
state,
|
|
@@ -33,6 +33,15 @@ export interface DialogPopupState {
|
|
|
33
33
|
* to `undefined` after one frame), `'ending'` once it is closing.
|
|
34
34
|
*/
|
|
35
35
|
transitionStatus: TransitionStatus;
|
|
36
|
+
/**
|
|
37
|
+
* Whether this dialog is rendered inside another dialog's tree.
|
|
38
|
+
*/
|
|
39
|
+
nested: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a dialog nested inside this one is open — the cue to scale or dim
|
|
42
|
+
* this popup, which the web version drives with a CSS variable.
|
|
43
|
+
*/
|
|
44
|
+
nestedDialogOpen: boolean;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
export interface DialogPopupProps extends ZestUIComponentProps<typeof View, DialogPopupState> {}
|
|
@@ -16,10 +16,14 @@ export function useDialogPopupProps() {
|
|
|
16
16
|
const titleElementId = store.useState('titleElementId');
|
|
17
17
|
const descriptionElementId = store.useState('descriptionElementId');
|
|
18
18
|
const role = store.useState('role');
|
|
19
|
+
const nested = store.useState('nested');
|
|
20
|
+
const nestedDialogOpen = store.useState('nestedDialogOpen');
|
|
19
21
|
|
|
20
22
|
return {
|
|
21
23
|
store,
|
|
22
24
|
open,
|
|
25
|
+
nested,
|
|
26
|
+
nestedDialogOpen,
|
|
23
27
|
transitionStatus: transitionContext?.transitionStatus,
|
|
24
28
|
props: {
|
|
25
29
|
role,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface DialogNestingContext {
|
|
5
|
+
/**
|
|
6
|
+
* Called by a nested root as it opens and closes, so the parent can keep a
|
|
7
|
+
* count of how many of its descendants are open.
|
|
8
|
+
*/
|
|
9
|
+
onNestedOpenChange: (open: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Lets a dialog know it has a dialog above it, and lets a parent know one of its
|
|
14
|
+
* descendants is open.
|
|
15
|
+
*
|
|
16
|
+
* On the web Base UI counts nested dialogs so the one underneath can be scaled
|
|
17
|
+
* back or dimmed. React Native has no CSS to express that, so the count reaches
|
|
18
|
+
* the consumer the way everything else does: as `nested` and `nestedDialogOpen`
|
|
19
|
+
* on the popup and backdrop state.
|
|
20
|
+
*/
|
|
21
|
+
export const DialogNestingContext = React.createContext<DialogNestingContext | undefined>(
|
|
22
|
+
undefined,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export function useDialogNestingContext() {
|
|
26
|
+
return React.useContext(DialogNestingContext);
|
|
27
|
+
}
|
|
@@ -3,8 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import { useRefWithInit } from '../../hooks/useRefWithInit';
|
|
4
4
|
import { useTransitionStatus } from '../../internals/useTransitionStatus';
|
|
5
5
|
import { usePopupRootHandle } from '../../utils/popups/usePopupRootHandle';
|
|
6
|
+
import { useStableCallback } from '../../hooks/useStableCallback';
|
|
6
7
|
import { DialogStore } from '../store/DialogStore';
|
|
7
8
|
import type { DialogRootProps } from './DialogRoot';
|
|
9
|
+
import { DialogNestingContext, useDialogNestingContext } from './DialogNestingContext';
|
|
8
10
|
import { DialogRootContext } from './DialogRootContext';
|
|
9
11
|
import { DialogTransitionContext } from './DialogTransitionContext';
|
|
10
12
|
|
|
@@ -36,6 +38,9 @@ export function useRenderDialogRoot<Payload = unknown>(
|
|
|
36
38
|
const disablePointerDismissal = isAlertDialog || disablePointerDismissalProp;
|
|
37
39
|
const role: 'dialog' | 'alertdialog' = isAlertDialog ? 'alertdialog' : 'dialog';
|
|
38
40
|
|
|
41
|
+
const parent = useDialogNestingContext();
|
|
42
|
+
const nested = parent !== undefined;
|
|
43
|
+
|
|
39
44
|
const store = useRefWithInit(
|
|
40
45
|
() =>
|
|
41
46
|
new DialogStore({
|
|
@@ -45,19 +50,42 @@ export function useRenderDialogRoot<Payload = unknown>(
|
|
|
45
50
|
role,
|
|
46
51
|
triggerId: defaultTriggerId,
|
|
47
52
|
triggerIdProp: triggerId,
|
|
53
|
+
nested,
|
|
48
54
|
}),
|
|
49
55
|
).current;
|
|
50
56
|
|
|
51
57
|
store.useControlledProp('openProp', open);
|
|
52
58
|
store.useControlledProp('triggerIdProp', triggerId);
|
|
53
59
|
store.useContextCallback('onOpenChange', onOpenChange);
|
|
54
|
-
store.useSyncedValues({ disablePointerDismissal, role });
|
|
60
|
+
store.useSyncedValues({ disablePointerDismissal, role, nested });
|
|
55
61
|
|
|
56
62
|
usePopupRootHandle({ store, handle, actionsRef });
|
|
57
63
|
|
|
58
64
|
const resolvedOpen = store.useState('open');
|
|
59
65
|
const { transitionStatus } = useTransitionStatus(resolvedOpen, false, true);
|
|
60
66
|
|
|
67
|
+
// Tell the dialog above this one whether it now has an open descendant. The
|
|
68
|
+
// cleanup is what keeps the parent's count right when this root unmounts
|
|
69
|
+
// while still open.
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
if (parent === undefined || !resolvedOpen) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
parent.onNestedOpenChange(true);
|
|
76
|
+
|
|
77
|
+
return () => {
|
|
78
|
+
parent.onNestedOpenChange(false);
|
|
79
|
+
};
|
|
80
|
+
}, [parent, resolvedOpen]);
|
|
81
|
+
|
|
82
|
+
const onNestedOpenChange = useStableCallback((open: boolean) => {
|
|
83
|
+
store.setNestedOpen(open);
|
|
84
|
+
// A dialog two levels down is still nested inside this one's parent, so the
|
|
85
|
+
// count propagates all the way up.
|
|
86
|
+
parent?.onNestedOpenChange(open);
|
|
87
|
+
});
|
|
88
|
+
|
|
61
89
|
const payload = store.useState('payload') as Payload;
|
|
62
90
|
|
|
63
91
|
const transitionContextValue = React.useMemo(
|
|
@@ -65,10 +93,17 @@ export function useRenderDialogRoot<Payload = unknown>(
|
|
|
65
93
|
[transitionStatus],
|
|
66
94
|
);
|
|
67
95
|
|
|
96
|
+
const nestingContextValue = React.useMemo(
|
|
97
|
+
() => ({ onNestedOpenChange }),
|
|
98
|
+
[onNestedOpenChange],
|
|
99
|
+
);
|
|
100
|
+
|
|
68
101
|
return (
|
|
69
102
|
<DialogRootContext.Provider value={store}>
|
|
70
103
|
<DialogTransitionContext.Provider value={transitionContextValue}>
|
|
71
|
-
{
|
|
104
|
+
<DialogNestingContext.Provider value={nestingContextValue}>
|
|
105
|
+
{typeof children === 'function' ? children(payload) : children}
|
|
106
|
+
</DialogNestingContext.Provider>
|
|
72
107
|
</DialogTransitionContext.Provider>
|
|
73
108
|
</DialogRootContext.Provider>
|
|
74
109
|
);
|
|
@@ -35,6 +35,15 @@ export type State = {
|
|
|
35
35
|
* The controlled `triggerId` prop, when provided.
|
|
36
36
|
*/
|
|
37
37
|
triggerIdProp: string | null | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Whether this dialog is itself rendered inside another dialog's tree.
|
|
40
|
+
*/
|
|
41
|
+
nested: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* How many dialogs nested inside this one are currently open. A count rather
|
|
44
|
+
* than a flag because siblings can overlap while one animates out.
|
|
45
|
+
*/
|
|
46
|
+
nestedOpenCount: number;
|
|
38
47
|
};
|
|
39
48
|
|
|
40
49
|
type Context<Reason extends string> = {
|
|
@@ -56,6 +65,8 @@ const selectors = {
|
|
|
56
65
|
descriptionElementId: createSelector((state: State) => state.descriptionElementId),
|
|
57
66
|
disablePointerDismissal: createSelector((state: State) => state.disablePointerDismissal),
|
|
58
67
|
role: createSelector((state: State) => state.role),
|
|
68
|
+
nested: createSelector((state: State) => state.nested),
|
|
69
|
+
nestedDialogOpen: createSelector((state: State) => state.nestedOpenCount > 0),
|
|
59
70
|
};
|
|
60
71
|
|
|
61
72
|
/**
|
|
@@ -67,8 +78,7 @@ const selectors = {
|
|
|
67
78
|
* `DialogRootContext` erases it to `any` (the same trick the group components
|
|
68
79
|
* use) so the parts stay non-generic.
|
|
69
80
|
*
|
|
70
|
-
* TODO(later):
|
|
71
|
-
* transitions (`mounted`/`transitionStatus`), handles/payloads.
|
|
81
|
+
* TODO(later): openMethod interaction typing.
|
|
72
82
|
*/
|
|
73
83
|
export class DialogStore<Reason extends string = DialogRootChangeEventReason> extends ReactStore<
|
|
74
84
|
Readonly<State>,
|
|
@@ -87,6 +97,8 @@ export class DialogStore<Reason extends string = DialogRootChangeEventReason> ex
|
|
|
87
97
|
payload: undefined,
|
|
88
98
|
triggerId: null,
|
|
89
99
|
triggerIdProp: undefined,
|
|
100
|
+
nested: false,
|
|
101
|
+
nestedOpenCount: 0,
|
|
90
102
|
...initialState,
|
|
91
103
|
},
|
|
92
104
|
{ onOpenChange: undefined, triggerNodes: new PopupTriggerMap() },
|
|
@@ -107,4 +119,14 @@ export class DialogStore<Reason extends string = DialogRootChangeEventReason> ex
|
|
|
107
119
|
|
|
108
120
|
this.set('open', nextOpen);
|
|
109
121
|
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Records that a dialog nested inside this one opened or closed.
|
|
125
|
+
*
|
|
126
|
+
* Increments rather than assigns, so two descendants closing out of order
|
|
127
|
+
* cannot leave the count stuck above zero.
|
|
128
|
+
*/
|
|
129
|
+
public setNestedOpen = (open: boolean) => {
|
|
130
|
+
this.set('nestedOpenCount', Math.max(0, this.state.nestedOpenCount + (open ? 1 : -1)));
|
|
131
|
+
};
|
|
110
132
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { DrawerRoot as Root } from './root/DrawerRoot';
|
|
2
|
-
export { createDrawerHandle as createHandle } from './handle';
|
|
2
|
+
export { createDrawerHandle as createHandle, type DrawerHandle as Handle } from './handle';
|
|
3
3
|
export { DrawerPopup as Popup } from './popup/DrawerPopup';
|
|
4
4
|
export { DrawerSwipeArea as SwipeArea } from './swipe-area/DrawerSwipeArea';
|
|
5
5
|
|