@base-ui/react 1.4.1 → 1.5.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/CHANGELOG.md +125 -8
- package/README.md +1 -1
- package/accordion/item/AccordionItem.d.ts +4 -0
- package/accordion/item/AccordionItem.js +5 -4
- package/accordion/panel/AccordionPanel.js +29 -51
- package/accordion/root/AccordionRoot.js +5 -6
- package/accordion/trigger/AccordionTrigger.js +3 -4
- package/alert-dialog/handle.d.ts +14 -1
- package/alert-dialog/handle.js +22 -5
- package/alert-dialog/index.d.ts +1 -1
- package/alert-dialog/index.parts.d.ts +2 -3
- package/alert-dialog/index.parts.js +4 -5
- package/alert-dialog/root/AlertDialogRoot.d.ts +7 -7
- package/alert-dialog/root/AlertDialogRoot.js +2 -56
- package/alert-dialog/trigger/AlertDialogTrigger.d.ts +25 -0
- package/alert-dialog/trigger/AlertDialogTrigger.js +15 -0
- package/alert-dialog/trigger/AlertDialogTriggerDataAttributes.d.ts +10 -0
- package/alert-dialog/trigger/AlertDialogTriggerDataAttributes.js +18 -0
- package/autocomplete/root/AutocompleteRoot.js +9 -10
- package/avatar/image/AvatarImage.js +4 -4
- package/checkbox/indicator/CheckboxIndicator.js +2 -2
- package/checkbox/root/CheckboxRoot.js +49 -11
- package/checkbox-group/CheckboxGroup.js +1 -5
- package/collapsible/panel/CollapsiblePanel.js +29 -51
- package/collapsible/panel/useCollapsiblePanel.d.ts +9 -23
- package/collapsible/panel/useCollapsiblePanel.js +308 -268
- package/collapsible/root/CollapsibleRoot.d.ts +1 -1
- package/collapsible/root/CollapsibleRootContext.d.ts +0 -2
- package/collapsible/root/useCollapsibleRoot.d.ts +0 -27
- package/collapsible/root/useCollapsibleRoot.js +2 -64
- package/collapsible/trigger/CollapsibleTrigger.js +5 -6
- package/combobox/arrow/ComboboxArrow.js +1 -1
- package/combobox/backdrop/ComboboxBackdrop.js +1 -1
- package/combobox/chip/ComboboxChip.js +7 -2
- package/combobox/clear/ComboboxClear.d.ts +4 -0
- package/combobox/clear/ComboboxClear.js +1 -0
- package/combobox/clear/ComboboxClearDataAttributes.d.ts +4 -0
- package/combobox/clear/ComboboxClearDataAttributes.js +4 -0
- package/combobox/icon/ComboboxIcon.js +1 -1
- package/combobox/input/ComboboxInput.js +15 -6
- package/combobox/item/ComboboxItem.js +8 -14
- package/combobox/item-indicator/ComboboxItemIndicator.js +1 -2
- package/combobox/root/AriaCombobox.js +61 -28
- package/combobox/store.d.ts +4 -8
- package/combobox/store.js +2 -1
- package/combobox/utils/ComboboxInternalDismissButton.js +2 -3
- package/csp-provider/CSPProvider.js +1 -1
- package/dialog/close/DialogClose.js +6 -6
- package/dialog/popup/DialogPopup.js +9 -4
- package/dialog/root/DialogRoot.d.ts +1 -2
- package/dialog/root/DialogRoot.js +3 -73
- package/dialog/root/DialogRootContext.d.ts +1 -0
- package/dialog/root/DialogRootContext.js +3 -1
- package/dialog/root/useDialogRoot.d.ts +12 -4
- package/dialog/root/useDialogRoot.js +27 -25
- package/dialog/root/useRenderDialogRoot.d.ts +4 -0
- package/dialog/root/useRenderDialogRoot.js +96 -0
- package/dialog/store/DialogHandle.d.ts +1 -1
- package/dialog/store/DialogHandle.js +2 -2
- package/dialog/store/DialogStore.d.ts +88 -1
- package/dialog/store/DialogStore.js +12 -17
- package/dialog/trigger/DialogTrigger.d.ts +1 -1
- package/dialog/trigger/DialogTrigger.js +11 -4
- package/dialog/viewport/DialogViewport.js +4 -3
- package/drawer/popup/DrawerPopup.js +13 -9
- package/drawer/root/DrawerRoot.js +11 -11
- package/drawer/root/DrawerRootContext.d.ts +1 -1
- package/drawer/swipe-area/DrawerSwipeArea.js +6 -5
- package/drawer/viewport/DrawerViewport.js +13 -14
- package/esm/accordion/item/AccordionItem.d.ts +4 -0
- package/esm/accordion/item/AccordionItem.js +5 -4
- package/esm/accordion/panel/AccordionPanel.js +29 -51
- package/esm/accordion/root/AccordionRoot.js +5 -6
- package/esm/accordion/trigger/AccordionTrigger.js +4 -5
- package/esm/alert-dialog/handle.d.ts +14 -1
- package/esm/alert-dialog/handle.js +20 -5
- package/esm/alert-dialog/index.d.ts +1 -1
- package/esm/alert-dialog/index.parts.d.ts +2 -3
- package/esm/alert-dialog/index.parts.js +2 -3
- package/esm/alert-dialog/root/AlertDialogRoot.d.ts +7 -7
- package/esm/alert-dialog/root/AlertDialogRoot.js +2 -55
- package/esm/alert-dialog/trigger/AlertDialogTrigger.d.ts +25 -0
- package/esm/alert-dialog/trigger/AlertDialogTrigger.js +10 -0
- package/esm/alert-dialog/trigger/AlertDialogTriggerDataAttributes.d.ts +10 -0
- package/esm/alert-dialog/trigger/AlertDialogTriggerDataAttributes.js +12 -0
- package/esm/autocomplete/root/AutocompleteRoot.js +9 -10
- package/esm/avatar/image/AvatarImage.js +4 -4
- package/esm/checkbox/indicator/CheckboxIndicator.js +2 -2
- package/esm/checkbox/root/CheckboxRoot.js +49 -11
- package/esm/checkbox-group/CheckboxGroup.js +1 -5
- package/esm/collapsible/panel/CollapsiblePanel.js +29 -51
- package/esm/collapsible/panel/useCollapsiblePanel.d.ts +9 -23
- package/esm/collapsible/panel/useCollapsiblePanel.js +309 -269
- package/esm/collapsible/root/CollapsibleRoot.d.ts +1 -1
- package/esm/collapsible/root/CollapsibleRootContext.d.ts +0 -2
- package/esm/collapsible/root/useCollapsibleRoot.d.ts +0 -27
- package/esm/collapsible/root/useCollapsibleRoot.js +2 -64
- package/esm/collapsible/trigger/CollapsibleTrigger.js +5 -6
- package/esm/combobox/arrow/ComboboxArrow.js +1 -1
- package/esm/combobox/backdrop/ComboboxBackdrop.js +1 -1
- package/esm/combobox/chip/ComboboxChip.js +7 -2
- package/esm/combobox/clear/ComboboxClear.d.ts +4 -0
- package/esm/combobox/clear/ComboboxClear.js +1 -0
- package/esm/combobox/clear/ComboboxClearDataAttributes.d.ts +4 -0
- package/esm/combobox/clear/ComboboxClearDataAttributes.js +4 -0
- package/esm/combobox/icon/ComboboxIcon.js +1 -1
- package/esm/combobox/input/ComboboxInput.js +16 -7
- package/esm/combobox/item/ComboboxItem.js +8 -14
- package/esm/combobox/item-indicator/ComboboxItemIndicator.js +1 -2
- package/esm/combobox/root/AriaCombobox.js +62 -29
- package/esm/combobox/store.d.ts +4 -8
- package/esm/combobox/store.js +2 -1
- package/esm/combobox/utils/ComboboxInternalDismissButton.js +2 -3
- package/esm/csp-provider/CSPProvider.js +1 -1
- package/esm/dialog/close/DialogClose.js +6 -6
- package/esm/dialog/popup/DialogPopup.js +9 -4
- package/esm/dialog/root/DialogRoot.d.ts +1 -2
- package/esm/dialog/root/DialogRoot.js +4 -72
- package/esm/dialog/root/DialogRootContext.d.ts +1 -0
- package/esm/dialog/root/DialogRootContext.js +2 -0
- package/esm/dialog/root/useDialogRoot.d.ts +12 -4
- package/esm/dialog/root/useDialogRoot.js +28 -27
- package/esm/dialog/root/useRenderDialogRoot.d.ts +4 -0
- package/esm/dialog/root/useRenderDialogRoot.js +90 -0
- package/esm/dialog/store/DialogHandle.d.ts +1 -1
- package/esm/dialog/store/DialogHandle.js +2 -2
- package/esm/dialog/store/DialogStore.d.ts +88 -1
- package/esm/dialog/store/DialogStore.js +13 -18
- package/esm/dialog/trigger/DialogTrigger.d.ts +1 -1
- package/esm/dialog/trigger/DialogTrigger.js +12 -5
- package/esm/dialog/viewport/DialogViewport.js +4 -3
- package/esm/drawer/popup/DrawerPopup.js +14 -9
- package/esm/drawer/root/DrawerRoot.js +11 -11
- package/esm/drawer/root/DrawerRootContext.d.ts +1 -1
- package/esm/drawer/swipe-area/DrawerSwipeArea.js +6 -5
- package/esm/drawer/viewport/DrawerViewport.js +13 -14
- package/esm/field/control/FieldControl.js +2 -6
- package/esm/field/item/FieldItem.js +1 -4
- package/esm/field/root/FieldRoot.js +11 -3
- package/esm/field/root/useFieldValidation.d.ts +1 -0
- package/esm/field/root/useFieldValidation.js +23 -20
- package/esm/field/utils/getCombinedFieldValidityData.d.ts +1 -1
- package/esm/field/validity/FieldValidity.d.ts +1 -1
- package/esm/floating-ui-react/components/FloatingDelayGroup.js +3 -3
- package/esm/floating-ui-react/components/FloatingFocusManager.d.ts +1 -1
- package/esm/floating-ui-react/components/FloatingFocusManager.js +20 -8
- package/esm/floating-ui-react/components/FloatingPortal.js +3 -3
- package/esm/floating-ui-react/hooks/useClick.js +83 -74
- package/esm/floating-ui-react/hooks/useClientPoint.js +29 -20
- package/esm/floating-ui-react/hooks/useDismiss.d.ts +1 -1
- package/esm/floating-ui-react/hooks/useDismiss.js +82 -93
- package/esm/floating-ui-react/hooks/useFloating.js +37 -32
- package/esm/floating-ui-react/hooks/useFloatingRootContext.d.ts +1 -1
- package/esm/floating-ui-react/hooks/useFloatingRootContext.js +2 -2
- package/esm/floating-ui-react/hooks/useFocus.js +84 -81
- package/esm/floating-ui-react/hooks/useHover.js +72 -76
- package/esm/floating-ui-react/hooks/useHoverFloatingInteraction.js +49 -44
- package/esm/floating-ui-react/hooks/useHoverInteractionSharedState.js +1 -1
- package/esm/floating-ui-react/hooks/useHoverReferenceInteraction.d.ts +7 -2
- package/esm/floating-ui-react/hooks/useHoverReferenceInteraction.js +44 -39
- package/esm/floating-ui-react/hooks/useHoverShared.d.ts +2 -1
- package/esm/floating-ui-react/hooks/useHoverShared.js +4 -0
- package/esm/floating-ui-react/hooks/useListNavigation.d.ts +1 -3
- package/esm/floating-ui-react/hooks/useListNavigation.js +83 -74
- package/esm/floating-ui-react/hooks/useSyncedFloatingRootContext.d.ts +9 -6
- package/esm/floating-ui-react/hooks/useSyncedFloatingRootContext.js +25 -20
- package/esm/floating-ui-react/hooks/useTypeahead.d.ts +2 -2
- package/esm/floating-ui-react/hooks/useTypeahead.js +33 -52
- package/esm/floating-ui-react/index.d.ts +0 -2
- package/esm/floating-ui-react/index.js +0 -2
- package/esm/floating-ui-react/types.d.ts +2 -7
- package/esm/floating-ui-react/utils/composite.js +2 -0
- package/esm/floating-ui-react/utils/enqueueFocus.d.ts +1 -1
- package/esm/floating-ui-react/utils/enqueueFocus.js +10 -7
- package/esm/floating-ui-react/utils/getEmptyRootContext.js +1 -1
- package/esm/form/Form.js +2 -2
- package/esm/index.js +1 -1
- package/esm/internals/composite/composite.d.ts +0 -1
- package/esm/internals/composite/composite.js +1 -2
- package/esm/internals/composite/root/useCompositeRoot.js +2 -2
- package/esm/internals/createBaseUIEventDetails.d.ts +2 -0
- package/esm/internals/csp-context/index.d.ts +2 -0
- package/esm/internals/csp-context/index.js +1 -0
- package/esm/internals/field-register-control/index.d.ts +0 -1
- package/esm/internals/field-register-control/useFieldControlRegistration.d.ts +2 -1
- package/esm/internals/field-register-control/useFieldControlRegistration.js +11 -14
- package/esm/internals/field-register-control/useRegisterFieldControl.d.ts +1 -4
- package/esm/internals/field-register-control/useRegisterFieldControl.js +6 -11
- package/esm/internals/field-root-context/FieldRootContext.d.ts +1 -0
- package/esm/internals/field-root-context/FieldRootContext.js +3 -2
- package/esm/internals/form-context/FormContext.d.ts +5 -1
- package/esm/internals/reason-parts.d.ts +2 -0
- package/esm/internals/reason-parts.js +2 -0
- package/esm/internals/types.d.ts +1 -0
- package/esm/internals/use-button/useButton.js +4 -4
- package/esm/internals/usePressAndHold.js +2 -2
- package/esm/internals/useRenderElement.js +2 -0
- package/esm/menu/arrow/MenuArrow.js +1 -1
- package/esm/menu/backdrop/MenuBackdrop.js +1 -1
- package/esm/menu/checkbox-item/MenuCheckboxItem.js +5 -7
- package/esm/menu/group/MenuGroup.js +1 -4
- package/esm/menu/group/MenuGroupContext.d.ts +1 -3
- package/esm/menu/group/MenuGroupContext.js +1 -1
- package/esm/menu/group-label/MenuGroupLabel.js +4 -6
- package/esm/menu/link-item/MenuLinkItem.js +2 -2
- package/esm/menu/popup/MenuPopup.js +5 -5
- package/esm/menu/radio-group/MenuRadioGroup.js +11 -5
- package/esm/menu/radio-item/MenuRadioItem.js +5 -7
- package/esm/menu/root/MenuRoot.js +63 -68
- package/esm/menu/store/MenuHandle.js +1 -1
- package/esm/menu/store/MenuStore.d.ts +87 -0
- package/esm/menu/submenu-trigger/MenuSubmenuTrigger.js +8 -5
- package/esm/menu/trigger/MenuTrigger.js +13 -10
- package/esm/menu/viewport/MenuViewport.d.ts +2 -2
- package/esm/menu/viewport/MenuViewport.js +2 -2
- package/esm/navigation-menu/arrow/NavigationMenuArrow.js +1 -1
- package/esm/navigation-menu/backdrop/NavigationMenuBackdrop.js +1 -1
- package/esm/navigation-menu/content/NavigationMenuContent.js +8 -5
- package/esm/navigation-menu/icon/NavigationMenuIcon.js +1 -1
- package/esm/navigation-menu/item/NavigationMenuItem.js +2 -2
- package/esm/navigation-menu/list/NavigationMenuList.js +1 -1
- package/esm/navigation-menu/popup/NavigationMenuPopup.js +2 -2
- package/esm/navigation-menu/root/NavigationMenuRoot.js +1 -3
- package/esm/navigation-menu/trigger/NavigationMenuTrigger.js +24 -17
- package/esm/navigation-menu/utils/isOutsideMenuEvent.d.ts +0 -1
- package/esm/navigation-menu/utils/isOutsideMenuEvent.js +1 -5
- package/esm/navigation-menu/viewport/NavigationMenuViewport.js +2 -3
- package/esm/number-field/input/NumberFieldInput.js +3 -5
- package/esm/number-field/root/NumberFieldRoot.js +5 -2
- package/esm/number-field/scrub-area/NumberFieldScrubArea.js +7 -3
- package/esm/otp-field/input/OTPFieldInput.js +43 -29
- package/esm/otp-field/root/OTPFieldRoot.d.ts +17 -8
- package/esm/otp-field/root/OTPFieldRoot.js +33 -33
- package/esm/otp-field/root/OTPFieldRootContext.d.ts +1 -1
- package/esm/otp-field/utils/otp.d.ts +5 -4
- package/esm/otp-field/utils/otp.js +23 -12
- package/esm/popover/arrow/PopoverArrow.js +1 -1
- package/esm/popover/backdrop/PopoverBackdrop.js +1 -1
- package/esm/popover/close/PopoverClose.js +2 -2
- package/esm/popover/description/PopoverDescription.js +1 -7
- package/esm/popover/popup/PopoverPopup.d.ts +1 -1
- package/esm/popover/popup/PopoverPopup.js +16 -10
- package/esm/popover/popup/PopoverPopupDataAttributes.d.ts +1 -1
- package/esm/popover/popup/PopoverPopupDataAttributes.js +1 -1
- package/esm/popover/positioner/PopoverPositioner.js +5 -5
- package/esm/popover/root/PopoverRoot.d.ts +1 -1
- package/esm/popover/root/PopoverRoot.js +42 -47
- package/esm/popover/store/PopoverHandle.js +1 -1
- package/esm/popover/store/PopoverStore.d.ts +91 -4
- package/esm/popover/store/PopoverStore.js +17 -18
- package/esm/popover/title/PopoverTitle.js +1 -7
- package/esm/popover/trigger/PopoverTrigger.js +24 -17
- package/esm/popover/viewport/PopoverViewport.d.ts +3 -3
- package/esm/popover/viewport/PopoverViewport.js +2 -2
- package/esm/popover/viewport/PopoverViewportDataAttributes.d.ts +1 -1
- package/esm/popover/viewport/PopoverViewportDataAttributes.js +1 -1
- package/esm/preview-card/positioner/PreviewCardPositioner.js +11 -1
- package/esm/preview-card/root/PreviewCardRoot.d.ts +1 -1
- package/esm/preview-card/root/PreviewCardRoot.js +32 -22
- package/esm/preview-card/store/PreviewCardHandle.js +1 -1
- package/esm/preview-card/store/PreviewCardStore.d.ts +90 -2
- package/esm/preview-card/store/PreviewCardStore.js +19 -31
- package/esm/preview-card/trigger/PreviewCardTrigger.js +6 -3
- package/esm/preview-card/viewport/PreviewCardViewport.d.ts +2 -2
- package/esm/preview-card/viewport/PreviewCardViewport.js +2 -2
- package/esm/preview-card/viewport/PreviewCardViewportDataAttributes.d.ts +2 -2
- package/esm/preview-card/viewport/PreviewCardViewportDataAttributes.js +2 -2
- package/esm/progress/indicator/ProgressIndicator.js +6 -11
- package/esm/progress/root/ProgressRoot.d.ts +1 -1
- package/esm/radio/root/RadioRoot.js +7 -3
- package/esm/radio-group/RadioGroup.js +4 -11
- package/esm/radio-group/RadioGroupContext.d.ts +0 -1
- package/esm/scroll-area/content/ScrollAreaContent.js +4 -4
- package/esm/scroll-area/root/ScrollAreaRoot.js +1 -1
- package/esm/scroll-area/scrollbar/ScrollAreaScrollbar.js +16 -20
- package/esm/scroll-area/viewport/ScrollAreaViewport.js +6 -10
- package/esm/select/arrow/SelectArrow.js +1 -1
- package/esm/select/backdrop/SelectBackdrop.js +1 -1
- package/esm/select/group/SelectGroup.js +1 -1
- package/esm/select/group-label/SelectGroupLabel.js +2 -2
- package/esm/select/icon/SelectIcon.js +1 -1
- package/esm/select/item/SelectItem.js +46 -32
- package/esm/select/item/SelectItemContext.d.ts +1 -1
- package/esm/select/item-indicator/SelectItemIndicator.js +1 -2
- package/esm/select/item-text/SelectItemText.js +9 -6
- package/esm/select/list/SelectList.js +1 -1
- package/esm/select/popup/SelectPopup.js +8 -3
- package/esm/select/positioner/SelectPositioner.js +3 -0
- package/esm/select/root/SelectRoot.js +46 -40
- package/esm/select/root/SelectRootContext.d.ts +4 -5
- package/esm/select/store.d.ts +3 -0
- package/esm/select/store.js +1 -0
- package/esm/select/trigger/SelectTrigger.d.ts +5 -0
- package/esm/select/trigger/SelectTrigger.js +19 -33
- package/esm/select/trigger/SelectTriggerDataAttributes.d.ts +5 -0
- package/esm/select/trigger/SelectTriggerDataAttributes.js +5 -0
- package/esm/slider/control/SliderControl.js +10 -12
- package/esm/slider/root/SliderRoot.js +1 -4
- package/esm/slider/thumb/SliderThumb.js +32 -30
- package/esm/slider/value/SliderValue.js +7 -15
- package/esm/switch/root/SwitchRoot.js +10 -10
- package/esm/switch/thumb/SwitchThumb.js +1 -9
- package/esm/tabs/indicator/TabsIndicator.js +14 -19
- package/esm/tabs/list/TabsList.js +4 -10
- package/esm/tabs/list/TabsListContext.d.ts +2 -1
- package/esm/tabs/panel/TabsPanel.js +1 -1
- package/esm/tabs/root/TabsRoot.d.ts +16 -1
- package/esm/tabs/root/TabsRoot.js +73 -25
- package/esm/tabs/root/TabsRootContext.d.ts +0 -2
- package/esm/toast/provider/ToastProvider.js +1 -1
- package/esm/toast/root/ToastRoot.d.ts +1 -1
- package/esm/toast/root/ToastRoot.js +108 -131
- package/esm/toast/root/ToastRootDataAttributes.d.ts +1 -1
- package/esm/toast/root/ToastRootDataAttributes.js +1 -1
- package/esm/toast/store.d.ts +9 -1
- package/esm/toast/store.js +19 -13
- package/esm/toast/useToastManager.d.ts +1 -1
- package/esm/toast/viewport/ToastViewport.js +1 -1
- package/esm/toggle/Toggle.js +5 -9
- package/esm/toggle-group/ToggleGroup.d.ts +2 -2
- package/esm/toggle-group/ToggleGroup.js +6 -13
- package/esm/toolbar/link/ToolbarLink.d.ts +1 -1
- package/esm/toolbar/link/ToolbarLink.js +1 -2
- package/esm/tooltip/arrow/TooltipArrow.js +3 -3
- package/esm/tooltip/popup/TooltipPopup.js +5 -4
- package/esm/tooltip/root/TooltipRoot.js +35 -26
- package/esm/tooltip/store/TooltipHandle.js +1 -1
- package/esm/tooltip/store/TooltipStore.d.ts +90 -2
- package/esm/tooltip/store/TooltipStore.js +18 -31
- package/esm/tooltip/trigger/TooltipTrigger.js +151 -20
- package/esm/tooltip/viewport/TooltipViewport.d.ts +2 -2
- package/esm/tooltip/viewport/TooltipViewport.js +2 -2
- package/esm/tooltip/viewport/TooltipViewportDataAttributes.d.ts +1 -1
- package/esm/tooltip/viewport/TooltipViewportDataAttributes.js +1 -1
- package/esm/unstable-use-media-query/index.js +1 -1
- package/esm/utils/popups/index.d.ts +1 -0
- package/esm/utils/popups/index.js +1 -0
- package/esm/utils/popups/inlineRect.d.ts +15 -0
- package/esm/utils/popups/inlineRect.js +191 -0
- package/esm/utils/popups/popupStoreUtils.d.ts +28 -10
- package/esm/utils/popups/popupStoreUtils.js +105 -20
- package/esm/utils/popups/popupTriggerMap.js +2 -0
- package/esm/utils/popups/store.d.ts +15 -2
- package/esm/utils/popups/store.js +38 -2
- package/esm/utils/popups/useTriggerFocusGuards.js +4 -5
- package/esm/utils/useAnchorPositioning.d.ts +5 -0
- package/esm/utils/useAnchorPositioning.js +12 -9
- package/esm/utils/useOpenInteractionType.d.ts +4 -0
- package/esm/utils/useOpenInteractionType.js +23 -18
- package/field/control/FieldControl.js +2 -6
- package/field/item/FieldItem.js +1 -4
- package/field/root/FieldRoot.js +11 -3
- package/field/root/useFieldValidation.d.ts +1 -0
- package/field/root/useFieldValidation.js +23 -20
- package/field/utils/getCombinedFieldValidityData.d.ts +1 -1
- package/field/validity/FieldValidity.d.ts +1 -1
- package/floating-ui-react/components/FloatingDelayGroup.js +3 -3
- package/floating-ui-react/components/FloatingFocusManager.d.ts +1 -1
- package/floating-ui-react/components/FloatingFocusManager.js +20 -8
- package/floating-ui-react/components/FloatingPortal.js +3 -3
- package/floating-ui-react/hooks/useClick.js +82 -73
- package/floating-ui-react/hooks/useClientPoint.js +29 -20
- package/floating-ui-react/hooks/useDismiss.d.ts +1 -1
- package/floating-ui-react/hooks/useDismiss.js +82 -92
- package/floating-ui-react/hooks/useFloating.js +36 -32
- package/floating-ui-react/hooks/useFloatingRootContext.d.ts +1 -1
- package/floating-ui-react/hooks/useFloatingRootContext.js +2 -2
- package/floating-ui-react/hooks/useFocus.js +84 -81
- package/floating-ui-react/hooks/useHover.js +74 -78
- package/floating-ui-react/hooks/useHoverFloatingInteraction.js +48 -43
- package/floating-ui-react/hooks/useHoverInteractionSharedState.js +1 -1
- package/floating-ui-react/hooks/useHoverReferenceInteraction.d.ts +7 -2
- package/floating-ui-react/hooks/useHoverReferenceInteraction.js +43 -38
- package/floating-ui-react/hooks/useHoverShared.d.ts +2 -1
- package/floating-ui-react/hooks/useHoverShared.js +11 -0
- package/floating-ui-react/hooks/useListNavigation.d.ts +1 -3
- package/floating-ui-react/hooks/useListNavigation.js +83 -74
- package/floating-ui-react/hooks/useSyncedFloatingRootContext.d.ts +9 -6
- package/floating-ui-react/hooks/useSyncedFloatingRootContext.js +26 -20
- package/floating-ui-react/hooks/useTypeahead.d.ts +2 -2
- package/floating-ui-react/hooks/useTypeahead.js +33 -52
- package/floating-ui-react/index.d.ts +0 -2
- package/floating-ui-react/index.js +0 -14
- package/floating-ui-react/types.d.ts +2 -7
- package/floating-ui-react/utils/composite.js +2 -0
- package/floating-ui-react/utils/enqueueFocus.d.ts +1 -1
- package/floating-ui-react/utils/enqueueFocus.js +10 -7
- package/floating-ui-react/utils/getEmptyRootContext.js +1 -1
- package/form/Form.js +2 -2
- package/index.js +1 -1
- package/internals/composite/composite.d.ts +0 -1
- package/internals/composite/composite.js +2 -3
- package/internals/composite/root/useCompositeRoot.js +1 -1
- package/internals/createBaseUIEventDetails.d.ts +2 -0
- package/internals/csp-context/index.d.ts +2 -0
- package/internals/csp-context/index.js +18 -0
- package/internals/field-register-control/index.d.ts +0 -1
- package/internals/field-register-control/useFieldControlRegistration.d.ts +2 -1
- package/internals/field-register-control/useFieldControlRegistration.js +11 -14
- package/internals/field-register-control/useRegisterFieldControl.d.ts +1 -4
- package/internals/field-register-control/useRegisterFieldControl.js +6 -11
- package/internals/field-root-context/FieldRootContext.d.ts +1 -0
- package/internals/field-root-context/FieldRootContext.js +4 -3
- package/internals/form-context/FormContext.d.ts +5 -1
- package/internals/reason-parts.d.ts +2 -0
- package/internals/reason-parts.js +3 -1
- package/internals/types.d.ts +1 -0
- package/internals/use-button/useButton.js +4 -4
- package/internals/usePressAndHold.js +2 -2
- package/internals/useRenderElement.js +2 -0
- package/menu/arrow/MenuArrow.js +1 -1
- package/menu/backdrop/MenuBackdrop.js +1 -1
- package/menu/checkbox-item/MenuCheckboxItem.js +5 -7
- package/menu/group/MenuGroup.js +1 -4
- package/menu/group/MenuGroupContext.d.ts +1 -3
- package/menu/group/MenuGroupContext.js +1 -1
- package/menu/group-label/MenuGroupLabel.js +4 -6
- package/menu/link-item/MenuLinkItem.js +2 -2
- package/menu/popup/MenuPopup.js +5 -5
- package/menu/radio-group/MenuRadioGroup.js +11 -5
- package/menu/radio-item/MenuRadioItem.js +5 -7
- package/menu/root/MenuRoot.js +60 -65
- package/menu/store/MenuHandle.js +1 -1
- package/menu/store/MenuStore.d.ts +87 -0
- package/menu/submenu-trigger/MenuSubmenuTrigger.js +7 -4
- package/menu/trigger/MenuTrigger.js +12 -9
- package/menu/viewport/MenuViewport.d.ts +2 -2
- package/menu/viewport/MenuViewport.js +2 -2
- package/navigation-menu/arrow/NavigationMenuArrow.js +1 -1
- package/navigation-menu/backdrop/NavigationMenuBackdrop.js +1 -1
- package/navigation-menu/content/NavigationMenuContent.js +8 -5
- package/navigation-menu/icon/NavigationMenuIcon.js +1 -1
- package/navigation-menu/item/NavigationMenuItem.js +2 -2
- package/navigation-menu/list/NavigationMenuList.js +1 -1
- package/navigation-menu/popup/NavigationMenuPopup.js +2 -2
- package/navigation-menu/root/NavigationMenuRoot.js +1 -3
- package/navigation-menu/trigger/NavigationMenuTrigger.js +23 -16
- package/navigation-menu/utils/isOutsideMenuEvent.d.ts +0 -1
- package/navigation-menu/utils/isOutsideMenuEvent.js +1 -5
- package/navigation-menu/viewport/NavigationMenuViewport.js +2 -3
- package/number-field/input/NumberFieldInput.js +3 -5
- package/number-field/root/NumberFieldRoot.js +5 -2
- package/number-field/scrub-area/NumberFieldScrubArea.js +7 -3
- package/otp-field/input/OTPFieldInput.js +42 -28
- package/otp-field/root/OTPFieldRoot.d.ts +17 -8
- package/otp-field/root/OTPFieldRoot.js +32 -32
- package/otp-field/root/OTPFieldRootContext.d.ts +1 -1
- package/otp-field/utils/otp.d.ts +5 -4
- package/otp-field/utils/otp.js +24 -12
- package/package.json +331 -317
- package/popover/arrow/PopoverArrow.js +1 -1
- package/popover/backdrop/PopoverBackdrop.js +1 -1
- package/popover/close/PopoverClose.js +2 -2
- package/popover/description/PopoverDescription.js +1 -7
- package/popover/popup/PopoverPopup.d.ts +1 -1
- package/popover/popup/PopoverPopup.js +16 -10
- package/popover/popup/PopoverPopupDataAttributes.d.ts +1 -1
- package/popover/popup/PopoverPopupDataAttributes.js +1 -1
- package/popover/positioner/PopoverPositioner.js +5 -5
- package/popover/root/PopoverRoot.d.ts +1 -1
- package/popover/root/PopoverRoot.js +39 -44
- package/popover/store/PopoverHandle.js +1 -1
- package/popover/store/PopoverStore.d.ts +91 -4
- package/popover/store/PopoverStore.js +16 -19
- package/popover/title/PopoverTitle.js +1 -7
- package/popover/trigger/PopoverTrigger.js +23 -16
- package/popover/viewport/PopoverViewport.d.ts +3 -3
- package/popover/viewport/PopoverViewport.js +2 -2
- package/popover/viewport/PopoverViewportDataAttributes.d.ts +1 -1
- package/popover/viewport/PopoverViewportDataAttributes.js +1 -1
- package/preview-card/positioner/PreviewCardPositioner.js +11 -1
- package/preview-card/root/PreviewCardRoot.d.ts +1 -1
- package/preview-card/root/PreviewCardRoot.js +30 -20
- package/preview-card/store/PreviewCardHandle.js +1 -1
- package/preview-card/store/PreviewCardStore.d.ts +90 -2
- package/preview-card/store/PreviewCardStore.js +18 -30
- package/preview-card/trigger/PreviewCardTrigger.js +5 -2
- package/preview-card/viewport/PreviewCardViewport.d.ts +2 -2
- package/preview-card/viewport/PreviewCardViewport.js +2 -2
- package/preview-card/viewport/PreviewCardViewportDataAttributes.d.ts +2 -2
- package/preview-card/viewport/PreviewCardViewportDataAttributes.js +2 -2
- package/progress/indicator/ProgressIndicator.js +6 -11
- package/progress/root/ProgressRoot.d.ts +1 -1
- package/radio/root/RadioRoot.js +7 -3
- package/radio-group/RadioGroup.js +4 -11
- package/radio-group/RadioGroupContext.d.ts +0 -1
- package/scroll-area/content/ScrollAreaContent.js +4 -4
- package/scroll-area/root/ScrollAreaRoot.js +1 -1
- package/scroll-area/scrollbar/ScrollAreaScrollbar.js +16 -20
- package/scroll-area/viewport/ScrollAreaViewport.js +6 -10
- package/select/arrow/SelectArrow.js +1 -1
- package/select/backdrop/SelectBackdrop.js +1 -1
- package/select/group/SelectGroup.js +1 -1
- package/select/group-label/SelectGroupLabel.js +2 -2
- package/select/icon/SelectIcon.js +1 -1
- package/select/item/SelectItem.js +46 -32
- package/select/item/SelectItemContext.d.ts +1 -1
- package/select/item-indicator/SelectItemIndicator.js +1 -2
- package/select/item-text/SelectItemText.js +9 -6
- package/select/list/SelectList.js +1 -1
- package/select/popup/SelectPopup.js +8 -3
- package/select/positioner/SelectPositioner.js +3 -0
- package/select/root/SelectRoot.js +45 -39
- package/select/root/SelectRootContext.d.ts +4 -5
- package/select/store.d.ts +3 -0
- package/select/store.js +1 -0
- package/select/trigger/SelectTrigger.d.ts +5 -0
- package/select/trigger/SelectTrigger.js +19 -33
- package/select/trigger/SelectTriggerDataAttributes.d.ts +5 -0
- package/select/trigger/SelectTriggerDataAttributes.js +5 -0
- package/slider/control/SliderControl.js +9 -11
- package/slider/root/SliderRoot.js +1 -4
- package/slider/thumb/SliderThumb.js +32 -30
- package/slider/value/SliderValue.js +7 -15
- package/switch/root/SwitchRoot.js +10 -10
- package/switch/thumb/SwitchThumb.js +1 -9
- package/tabs/indicator/TabsIndicator.js +14 -19
- package/tabs/list/TabsList.js +4 -10
- package/tabs/list/TabsListContext.d.ts +2 -1
- package/tabs/panel/TabsPanel.js +1 -1
- package/tabs/root/TabsRoot.d.ts +16 -1
- package/tabs/root/TabsRoot.js +71 -24
- package/tabs/root/TabsRootContext.d.ts +0 -2
- package/toast/provider/ToastProvider.js +1 -1
- package/toast/root/ToastRoot.d.ts +1 -1
- package/toast/root/ToastRoot.js +110 -133
- package/toast/root/ToastRootDataAttributes.d.ts +1 -1
- package/toast/root/ToastRootDataAttributes.js +1 -1
- package/toast/store.d.ts +9 -1
- package/toast/store.js +18 -12
- package/toast/useToastManager.d.ts +1 -1
- package/toast/viewport/ToastViewport.js +1 -1
- package/toggle/Toggle.js +5 -9
- package/toggle-group/ToggleGroup.d.ts +2 -2
- package/toggle-group/ToggleGroup.js +6 -13
- package/toolbar/link/ToolbarLink.d.ts +1 -1
- package/toolbar/link/ToolbarLink.js +1 -2
- package/tooltip/arrow/TooltipArrow.js +3 -3
- package/tooltip/popup/TooltipPopup.js +5 -4
- package/tooltip/root/TooltipRoot.js +32 -23
- package/tooltip/store/TooltipHandle.js +1 -1
- package/tooltip/store/TooltipStore.d.ts +90 -2
- package/tooltip/store/TooltipStore.js +17 -30
- package/tooltip/trigger/TooltipTrigger.js +152 -20
- package/tooltip/viewport/TooltipViewport.d.ts +2 -2
- package/tooltip/viewport/TooltipViewport.js +2 -2
- package/tooltip/viewport/TooltipViewportDataAttributes.d.ts +1 -1
- package/tooltip/viewport/TooltipViewportDataAttributes.js +1 -1
- package/unstable-use-media-query/index.js +1 -1
- package/utils/popups/index.d.ts +1 -0
- package/utils/popups/index.js +11 -0
- package/utils/popups/inlineRect.d.ts +15 -0
- package/utils/popups/inlineRect.js +198 -0
- package/utils/popups/popupStoreUtils.d.ts +28 -10
- package/utils/popups/popupStoreUtils.js +110 -20
- package/utils/popups/popupTriggerMap.js +2 -0
- package/utils/popups/store.d.ts +15 -2
- package/utils/popups/store.js +39 -2
- package/utils/popups/useTriggerFocusGuards.js +4 -5
- package/utils/useAnchorPositioning.d.ts +5 -0
- package/utils/useAnchorPositioning.js +12 -9
- package/utils/useOpenInteractionType.d.ts +4 -0
- package/utils/useOpenInteractionType.js +24 -17
- package/checkbox-group/index.parts.d.ts +0 -1
- package/checkbox-group/index.parts.js +0 -12
- package/esm/checkbox-group/index.parts.d.ts +0 -1
- package/esm/checkbox-group/index.parts.js +0 -1
- package/esm/floating-ui-react/hooks/useInteractions.d.ts +0 -20
- package/esm/floating-ui-react/hooks/useInteractions.js +0 -88
- package/esm/floating-ui-react/hooks/useRole.d.ts +0 -17
- package/esm/floating-ui-react/hooks/useRole.js +0 -113
- package/floating-ui-react/hooks/useInteractions.d.ts +0 -20
- package/floating-ui-react/hooks/useInteractions.js +0 -95
- package/floating-ui-react/hooks/useRole.d.ts +0 -17
- package/floating-ui-react/hooks/useRole.js +0 -120
- /package/{csp-provider → esm/internals/csp-context}/CSPContext.d.ts +0 -0
- /package/esm/{csp-provider → internals/csp-context}/CSPContext.js +0 -0
- /package/{esm/csp-provider → internals/csp-context}/CSPContext.d.ts +0 -0
- /package/{csp-provider → internals/csp-context}/CSPContext.js +0 -0
|
@@ -77,10 +77,7 @@ export const NumberFieldInput = /*#__PURE__*/React.forwardRef(function NumberFie
|
|
|
77
77
|
} = useLabelableContext();
|
|
78
78
|
const hasTouchedInputRef = React.useRef(false);
|
|
79
79
|
const blockRevalidationRef = React.useRef(false);
|
|
80
|
-
useRegisterFieldControl(inputRef,
|
|
81
|
-
id,
|
|
82
|
-
value
|
|
83
|
-
});
|
|
80
|
+
useRegisterFieldControl(inputRef, id, value);
|
|
84
81
|
useValueChanged(value, previousValue => {
|
|
85
82
|
const validateOnChange = shouldValidateOnChange();
|
|
86
83
|
clearErrors(name);
|
|
@@ -254,13 +251,14 @@ export const NumberFieldInput = /*#__PURE__*/React.forwardRef(function NumberFie
|
|
|
254
251
|
const isAsciiDigit = event.key >= '0' && event.key <= '9';
|
|
255
252
|
const isArabicNumeral = ARABIC_DETECT_RE.test(event.key);
|
|
256
253
|
const isHanNumeral = HAN_DETECT_RE.test(event.key);
|
|
254
|
+
const isPersianNumeral = PERSIAN_DETECT_RE.test(event.key);
|
|
257
255
|
const isFullwidthNumeral = FULLWIDTH_DETECT_RE.test(event.key);
|
|
258
256
|
const isNavigateKey = NAVIGATE_KEYS.has(event.key);
|
|
259
257
|
if (
|
|
260
258
|
// Allow composition events (e.g., pinyin)
|
|
261
259
|
// event.nativeEvent.isComposing does not work in Safari:
|
|
262
260
|
// https://bugs.webkit.org/show_bug.cgi?id=165004
|
|
263
|
-
event.which === 229 || event.altKey || event.ctrlKey || event.metaKey || isAllowedNonNumericKey || isAsciiDigit || isArabicNumeral || isFullwidthNumeral || isHanNumeral || isNavigateKey) {
|
|
261
|
+
event.which === 229 || event.altKey || event.ctrlKey || event.metaKey || isAllowedNonNumericKey || isAsciiDigit || isArabicNumeral || isFullwidthNumeral || isHanNumeral || isPersianNumeral || isNavigateKey) {
|
|
264
262
|
return;
|
|
265
263
|
}
|
|
266
264
|
|
|
@@ -281,6 +281,7 @@ export const NumberFieldRoot = /*#__PURE__*/React.forwardRef(function NumberFiel
|
|
|
281
281
|
|
|
282
282
|
// Prevent the default behavior to avoid scrolling the page.
|
|
283
283
|
event.preventDefault();
|
|
284
|
+
allowInputSyncRef.current = true;
|
|
284
285
|
const amount = getStepAmount(event) ?? DEFAULT_STEP;
|
|
285
286
|
incrementValue(amount, {
|
|
286
287
|
direction: event.deltaY > 0 ? -1 : 1,
|
|
@@ -289,7 +290,7 @@ export const NumberFieldRoot = /*#__PURE__*/React.forwardRef(function NumberFiel
|
|
|
289
290
|
});
|
|
290
291
|
}
|
|
291
292
|
return addEventListener(element, 'wheel', handleWheel);
|
|
292
|
-
}, [allowWheelScrub, incrementValue, disabled, readOnly,
|
|
293
|
+
}, [allowWheelScrub, incrementValue, disabled, readOnly, getStepAmount]);
|
|
293
294
|
const state = React.useMemo(() => ({
|
|
294
295
|
...fieldState,
|
|
295
296
|
disabled,
|
|
@@ -345,7 +346,9 @@ export const NumberFieldRoot = /*#__PURE__*/React.forwardRef(function NumberFiel
|
|
|
345
346
|
},
|
|
346
347
|
onChange(event) {
|
|
347
348
|
// Workaround for https://github.com/facebook/react/issues/9023
|
|
348
|
-
if (event.nativeEvent.defaultPrevented) {
|
|
349
|
+
if (event.nativeEvent.defaultPrevented || disabled || readOnly) {
|
|
350
|
+
// Outside Field.Root, the event is not wrapped by mergeProps.
|
|
351
|
+
event.preventBaseUIHandler?.();
|
|
349
352
|
return;
|
|
350
353
|
}
|
|
351
354
|
|
|
@@ -43,6 +43,7 @@ export const NumberFieldScrubArea = /*#__PURE__*/React.forwardRef(function Numbe
|
|
|
43
43
|
readOnly,
|
|
44
44
|
inputRef,
|
|
45
45
|
incrementValue,
|
|
46
|
+
allowInputSyncRef,
|
|
46
47
|
getStepAmount,
|
|
47
48
|
onValueCommitted,
|
|
48
49
|
lastChangedValueRef,
|
|
@@ -141,8 +142,10 @@ export const NumberFieldScrubArea = /*#__PURE__*/React.forwardRef(function Numbe
|
|
|
141
142
|
|
|
142
143
|
// Manually dispatch a click event if no movement happened, since
|
|
143
144
|
// preventDefault on pointerdown prevents the browser click event.
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
const pointerDownTarget = pointerDownTargetRef.current;
|
|
146
|
+
const input = inputRef.current;
|
|
147
|
+
if (!didMoveRef.current && pointerDownTarget != null && input) {
|
|
148
|
+
pointerDownTarget.dispatchEvent(new (ownerWindow(input).MouseEvent)('click', {
|
|
146
149
|
bubbles: true,
|
|
147
150
|
cancelable: true
|
|
148
151
|
}));
|
|
@@ -179,6 +182,7 @@ export const NumberFieldScrubArea = /*#__PURE__*/React.forwardRef(function Numbe
|
|
|
179
182
|
const stepAmount = getStepAmount(event) ?? DEFAULT_STEP;
|
|
180
183
|
const rawAmount = dValue * stepAmount;
|
|
181
184
|
if (rawAmount !== 0) {
|
|
185
|
+
allowInputSyncRef.current = true;
|
|
182
186
|
incrementValue(Math.abs(rawAmount), {
|
|
183
187
|
direction: rawAmount >= 0 ? 1 : -1,
|
|
184
188
|
event,
|
|
@@ -193,7 +197,7 @@ export const NumberFieldScrubArea = /*#__PURE__*/React.forwardRef(function Numbe
|
|
|
193
197
|
exitPointerLockTimeout.clear();
|
|
194
198
|
unsubscribe();
|
|
195
199
|
};
|
|
196
|
-
}, [disabled, readOnly, incrementValue, isScrubbing, getStepAmount, inputRef, onScrubbingChange, onScrub, direction, pixelSensitivity, lastChangedValueRef, onValueCommitted, valueRef, exitPointerLockTimeout]);
|
|
200
|
+
}, [disabled, readOnly, allowInputSyncRef, incrementValue, isScrubbing, getStepAmount, inputRef, onScrubbingChange, onScrub, direction, pixelSensitivity, lastChangedValueRef, onValueCommitted, valueRef, exitPointerLockTimeout]);
|
|
197
201
|
|
|
198
202
|
// Prevent scrolling using touch input when scrubbing.
|
|
199
203
|
React.useEffect(function registerScrubberTouchPreventListener() {
|
|
@@ -5,12 +5,13 @@ import { SafeReact } from '@base-ui/utils/safeReact';
|
|
|
5
5
|
import { warn } from '@base-ui/utils/warn';
|
|
6
6
|
import { stopEvent } from "../../floating-ui-react/utils.js";
|
|
7
7
|
import { IndexGuessBehavior, useCompositeListItem } from "../../internals/composite/list/useCompositeListItem.js";
|
|
8
|
+
import { useDirection } from "../../internals/direction-context/DirectionContext.js";
|
|
8
9
|
import { useRenderElement } from "../../internals/useRenderElement.js";
|
|
9
10
|
import { createChangeEventDetails, createGenericEventDetails } from "../../internals/createBaseUIEventDetails.js";
|
|
10
11
|
import { REASONS } from "../../internals/reasons.js";
|
|
11
12
|
import { useOTPFieldRootContext, getOTPFieldInputState } from "../root/OTPFieldRootContext.js";
|
|
12
13
|
import { inputStateAttributesMapping } from "../utils/stateAttributesMapping.js";
|
|
13
|
-
import {
|
|
14
|
+
import { normalizeOTPValueWithDetails, removeOTPCharacter, replaceOTPValue } from "../utils/otp.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* An individual OTP character input.
|
|
@@ -46,7 +47,7 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
46
47
|
reportValueInvalid,
|
|
47
48
|
readOnly,
|
|
48
49
|
required,
|
|
49
|
-
|
|
50
|
+
normalizeValue,
|
|
50
51
|
setValue,
|
|
51
52
|
state,
|
|
52
53
|
validationType,
|
|
@@ -59,6 +60,7 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
59
60
|
indexGuessBehavior: IndexGuessBehavior.GuessFromOrder
|
|
60
61
|
});
|
|
61
62
|
const inputRef = React.useRef(null);
|
|
63
|
+
const direction = useDirection();
|
|
62
64
|
const slotValue = value[index] ?? '';
|
|
63
65
|
const inputState = getOTPFieldInputState(state, slotValue, index);
|
|
64
66
|
const slotAriaLabel = externalAriaLabel;
|
|
@@ -118,9 +120,8 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
118
120
|
return;
|
|
119
121
|
}
|
|
120
122
|
const rawValue = event.currentTarget.value;
|
|
121
|
-
const nextDigits =
|
|
122
|
-
|
|
123
|
-
if (didSanitize) {
|
|
123
|
+
const [nextDigits, didRejectCharacters] = normalizeOTPValueWithDetails(rawValue, length, validationType, normalizeValue);
|
|
124
|
+
if (didRejectCharacters) {
|
|
124
125
|
reportValueInvalid(rawValue, createGenericEventDetails(REASONS.inputChange, event.nativeEvent));
|
|
125
126
|
}
|
|
126
127
|
if (nextDigits === '') {
|
|
@@ -132,7 +133,7 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
132
133
|
}
|
|
133
134
|
return;
|
|
134
135
|
}
|
|
135
|
-
const nextValue = replaceOTPValue(value, index, nextDigits, length, validationType,
|
|
136
|
+
const nextValue = replaceOTPValue(value, index, nextDigits, length, validationType, normalizeValue);
|
|
136
137
|
const committedValue = setValue(nextValue, createChangeEventDetails(REASONS.inputChange, event.nativeEvent));
|
|
137
138
|
if (committedValue != null) {
|
|
138
139
|
const nextInput = Math.min(index + nextDigits.length, length - 1);
|
|
@@ -143,52 +144,66 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
143
144
|
if (event.defaultPrevented || disabled) {
|
|
144
145
|
return;
|
|
145
146
|
}
|
|
146
|
-
|
|
147
|
+
const firstIndex = 0;
|
|
148
|
+
const lastIndex = Math.max(length - 1, firstIndex);
|
|
149
|
+
const endTargetIndex = Math.min(value.length, lastIndex);
|
|
150
|
+
const hasBoundaryModifier = (event.ctrlKey || event.metaKey) && !event.altKey;
|
|
151
|
+
const isRtl = direction === 'rtl';
|
|
152
|
+
const previousKey = isRtl ? 'ArrowRight' : 'ArrowLeft';
|
|
153
|
+
const nextKey = isRtl ? 'ArrowLeft' : 'ArrowRight';
|
|
154
|
+
if (event.key === previousKey) {
|
|
147
155
|
stopEvent(event);
|
|
148
|
-
focusInput(Math.max(
|
|
156
|
+
focusInput(hasBoundaryModifier ? firstIndex : Math.max(firstIndex, index - 1));
|
|
149
157
|
return;
|
|
150
158
|
}
|
|
151
|
-
if (event.key ===
|
|
159
|
+
if (event.key === nextKey) {
|
|
152
160
|
stopEvent(event);
|
|
153
|
-
focusInput(Math.min(
|
|
161
|
+
focusInput(hasBoundaryModifier ? endTargetIndex : Math.min(lastIndex, index + 1));
|
|
154
162
|
return;
|
|
155
163
|
}
|
|
156
|
-
if (event.key === 'Home') {
|
|
164
|
+
if (event.key === 'Home' || event.key === 'ArrowUp') {
|
|
157
165
|
stopEvent(event);
|
|
158
|
-
focusInput(
|
|
166
|
+
focusInput(firstIndex);
|
|
159
167
|
return;
|
|
160
168
|
}
|
|
161
|
-
if (event.key === 'End') {
|
|
169
|
+
if (event.key === 'End' || event.key === 'ArrowDown') {
|
|
162
170
|
stopEvent(event);
|
|
163
|
-
focusInput(
|
|
171
|
+
focusInput(endTargetIndex);
|
|
164
172
|
return;
|
|
165
173
|
}
|
|
166
174
|
if (readOnly) {
|
|
167
175
|
return;
|
|
168
176
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const committedValue = setValue(removeOTPCharacter(value, index), createChangeEventDetails(REASONS.keyboard, event.nativeEvent));
|
|
177
|
+
function setKeyboardValue(nextValue, targetIndex) {
|
|
178
|
+
const committedValue = setValue(nextValue, createChangeEventDetails(REASONS.keyboard, event.nativeEvent));
|
|
172
179
|
if (committedValue != null) {
|
|
173
|
-
queueFocusInput(
|
|
180
|
+
queueFocusInput(targetIndex, committedValue);
|
|
174
181
|
}
|
|
182
|
+
}
|
|
183
|
+
if (event.key === 'Backspace' && hasBoundaryModifier) {
|
|
184
|
+
stopEvent(event);
|
|
185
|
+
setKeyboardValue('', firstIndex);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (event.key === 'Delete') {
|
|
189
|
+
stopEvent(event);
|
|
190
|
+
setKeyboardValue(removeOTPCharacter(value, index), index);
|
|
175
191
|
return;
|
|
176
192
|
}
|
|
177
193
|
const inputValue = event.currentTarget.value;
|
|
178
194
|
const fullSelection = event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === inputValue.length;
|
|
179
195
|
if (event.key.length === 1 && fullSelection && slotValue === event.key) {
|
|
180
196
|
stopEvent(event);
|
|
181
|
-
|
|
197
|
+
if (index < length - 1) {
|
|
198
|
+
focusInput(index + 1);
|
|
199
|
+
}
|
|
182
200
|
return;
|
|
183
201
|
}
|
|
184
202
|
if (event.key === 'Backspace') {
|
|
185
203
|
stopEvent(event);
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
if (committedValue != null) {
|
|
190
|
-
queueFocusInput(targetIndex, committedValue);
|
|
191
|
-
}
|
|
204
|
+
const targetIndex = Math.max(firstIndex, index - 1);
|
|
205
|
+
const deleteIndex = slotValue === '' ? targetIndex : index;
|
|
206
|
+
setKeyboardValue(removeOTPCharacter(value, deleteIndex), targetIndex);
|
|
192
207
|
}
|
|
193
208
|
},
|
|
194
209
|
onPaste(event) {
|
|
@@ -206,15 +221,14 @@ export const OTPFieldInput = /*#__PURE__*/React.forwardRef(function OTPFieldInpu
|
|
|
206
221
|
return;
|
|
207
222
|
}
|
|
208
223
|
event.preventDefault();
|
|
209
|
-
const nextDigits =
|
|
210
|
-
|
|
211
|
-
if (didSanitize) {
|
|
224
|
+
const [nextDigits, didRejectCharacters] = normalizeOTPValueWithDetails(rawValue, length, validationType, normalizeValue);
|
|
225
|
+
if (didRejectCharacters) {
|
|
212
226
|
reportValueInvalid(rawValue, createGenericEventDetails(REASONS.inputPaste, event.nativeEvent));
|
|
213
227
|
}
|
|
214
228
|
if (nextDigits === '') {
|
|
215
229
|
return;
|
|
216
230
|
}
|
|
217
|
-
const committedValue = setValue(replaceOTPValue(value, index, nextDigits, length, validationType,
|
|
231
|
+
const committedValue = setValue(replaceOTPValue(value, index, nextDigits, length, validationType, normalizeValue), createChangeEventDetails(REASONS.inputPaste, event.nativeEvent));
|
|
218
232
|
if (committedValue != null) {
|
|
219
233
|
const nextInput = Math.min(index + nextDigits.length, length - 1);
|
|
220
234
|
queueFocusInput(nextInput, committedValue);
|
|
@@ -57,10 +57,17 @@ export interface OTPFieldRootProps extends Omit<BaseUIComponentProps<'div', OTPF
|
|
|
57
57
|
*/
|
|
58
58
|
validationType?: OTPFieldRoot.ValidationType | undefined;
|
|
59
59
|
/**
|
|
60
|
-
* Function
|
|
61
|
-
*
|
|
60
|
+
* Function that normalizes the OTP value after whitespace and `validationType` filtering.
|
|
61
|
+
* It runs whenever OTP Field normalizes a value, including initial/default values, controlled
|
|
62
|
+
* values, and user edits.
|
|
63
|
+
*
|
|
64
|
+
* The returned value is filtered by `validationType` again, then clamped to `length`.
|
|
65
|
+
* It should be idempotent because OTP Field may normalize the same value more than once while
|
|
66
|
+
* handling edits, storing state, and rendering controlled or uncontrolled values. Non-idempotent
|
|
67
|
+
* normalizers can compound across those normalization passes. Characters rejected while
|
|
68
|
+
* normalizing typed or pasted text are reported through `onValueInvalid`.
|
|
62
69
|
*/
|
|
63
|
-
|
|
70
|
+
normalizeValue?: ((value: string) => string) | undefined;
|
|
64
71
|
/**
|
|
65
72
|
* Whether the user must enter a value before submitting a form.
|
|
66
73
|
* @default false
|
|
@@ -99,16 +106,18 @@ export interface OTPFieldRootProps extends Omit<BaseUIComponentProps<'div', OTPF
|
|
|
99
106
|
*/
|
|
100
107
|
onValueChange?: ((value: string, eventDetails: OTPFieldRoot.ChangeEventDetails) => void) | undefined;
|
|
101
108
|
/**
|
|
102
|
-
* Callback fired when entered text contains characters that are rejected by
|
|
103
|
-
* before the OTP value updates.
|
|
109
|
+
* Callback fired when entered text contains characters that are rejected by validation or
|
|
110
|
+
* normalization before the OTP value updates.
|
|
104
111
|
*
|
|
105
|
-
* The `value` argument is the attempted user-entered string before
|
|
112
|
+
* The `value` argument is the attempted user-entered string before normalization.
|
|
106
113
|
*/
|
|
107
114
|
onValueInvalid?: ((value: string, eventDetails: OTPFieldRoot.InvalidEventDetails) => void) | undefined;
|
|
108
115
|
/**
|
|
109
|
-
* Callback function that is fired when the OTP value becomes complete
|
|
116
|
+
* Callback function that is fired when the OTP value becomes complete, or when a complete value
|
|
117
|
+
* is pasted while the OTP is already complete.
|
|
110
118
|
*
|
|
111
|
-
*
|
|
119
|
+
* When the value changes, it runs later than `onValueChange`, after the internal value update is
|
|
120
|
+
* applied. If a complete pasted value matches the current value, `onValueChange` does not fire.
|
|
112
121
|
*
|
|
113
122
|
* If `autoSubmit` is enabled, it runs immediately before the owning form is submitted.
|
|
114
123
|
*/
|
|
@@ -23,7 +23,7 @@ import { createChangeEventDetails, createGenericEventDetails } from "../../inter
|
|
|
23
23
|
import { REASONS } from "../../internals/reasons.js";
|
|
24
24
|
import { OTPFieldRootContext } from "./OTPFieldRootContext.js";
|
|
25
25
|
import { rootStateAttributesMapping } from "../utils/stateAttributesMapping.js";
|
|
26
|
-
import { getOTPValidationConfig, normalizeOTPValue,
|
|
26
|
+
import { getOTPValidationConfig, normalizeOTPValue, normalizeOTPValueWithDetails } from "../utils/otp.js";
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Groups all OTP field parts and manages their state.
|
|
@@ -48,7 +48,7 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
48
48
|
mask = false,
|
|
49
49
|
inputMode: inputModeProp,
|
|
50
50
|
validationType = 'numeric',
|
|
51
|
-
|
|
51
|
+
normalizeValue,
|
|
52
52
|
disabled: disabledProp = false,
|
|
53
53
|
readOnly = false,
|
|
54
54
|
required = false,
|
|
@@ -109,7 +109,7 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
109
109
|
const hiddenInputPattern = validationConfig?.getRootPattern(length);
|
|
110
110
|
const inputMode = inputModeProp ?? validationConfig?.inputMode;
|
|
111
111
|
const hasValidLength = Number.isInteger(length) && length > 0;
|
|
112
|
-
const value = normalizeOTPValue(valueUnwrapped, length, validationType,
|
|
112
|
+
const value = normalizeOTPValue(valueUnwrapped, length, validationType, normalizeValue);
|
|
113
113
|
const valueRef = useValueAsRef(value);
|
|
114
114
|
const filled = value !== '';
|
|
115
115
|
const [inputCount, setInputCount] = React.useState(0);
|
|
@@ -123,16 +123,10 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
123
123
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
124
124
|
useOTPFieldRootDevWarnings({
|
|
125
125
|
inputCount,
|
|
126
|
-
length
|
|
127
|
-
sanitizeValue,
|
|
128
|
-
validationType
|
|
126
|
+
length
|
|
129
127
|
});
|
|
130
128
|
}
|
|
131
|
-
useRegisterFieldControl(firstInputRef,
|
|
132
|
-
id,
|
|
133
|
-
getValue: () => valueRef.current,
|
|
134
|
-
value
|
|
135
|
-
});
|
|
129
|
+
useRegisterFieldControl(firstInputRef, id, value);
|
|
136
130
|
const focusInput = useStableCallback(index => {
|
|
137
131
|
const targetIndex = Math.min(Math.max(index, 0), Math.max(inputRefs.current.length - 1, 0));
|
|
138
132
|
const target = inputRefs.current[targetIndex];
|
|
@@ -157,6 +151,12 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
157
151
|
formElement.requestSubmit();
|
|
158
152
|
}
|
|
159
153
|
}
|
|
154
|
+
function completeValue(completedValue, eventDetails) {
|
|
155
|
+
onValueCompleteProp?.(completedValue, eventDetails);
|
|
156
|
+
if (autoSubmit) {
|
|
157
|
+
requestSubmit();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
160
|
useValueChanged(value, () => {
|
|
161
161
|
clearErrors(name);
|
|
162
162
|
setDirty(value !== validityData.initialValue);
|
|
@@ -169,10 +169,7 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
169
169
|
if (pendingCompleteValue != null) {
|
|
170
170
|
pendingCompleteValueRef.current = null;
|
|
171
171
|
if (pendingCompleteValue.value === value) {
|
|
172
|
-
|
|
173
|
-
if (autoSubmit) {
|
|
174
|
-
requestSubmit();
|
|
175
|
-
}
|
|
172
|
+
completeValue(value, pendingCompleteValue.eventDetails);
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
const pendingFocus = pendingFocusRef.current;
|
|
@@ -184,8 +181,12 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
184
181
|
}
|
|
185
182
|
});
|
|
186
183
|
const setValue = useStableCallback((nextValue, details) => {
|
|
187
|
-
const normalizedValue = normalizeOTPValue(nextValue, length, validationType,
|
|
184
|
+
const normalizedValue = normalizeOTPValue(nextValue, length, validationType, normalizeValue);
|
|
185
|
+
const completeEventDetails = normalizedValue.length === length && (valueRef.current.length !== length || details.reason === REASONS.inputPaste) ? getCompleteEventDetails(details) : null;
|
|
188
186
|
if (normalizedValue === valueRef.current) {
|
|
187
|
+
if (completeEventDetails != null) {
|
|
188
|
+
completeValue(normalizedValue, completeEventDetails);
|
|
189
|
+
}
|
|
189
190
|
return null;
|
|
190
191
|
}
|
|
191
192
|
onValueChange?.(normalizedValue, details);
|
|
@@ -193,10 +194,10 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
193
194
|
return null;
|
|
194
195
|
}
|
|
195
196
|
setValueUnwrapped(normalizedValue);
|
|
196
|
-
if (
|
|
197
|
+
if (completeEventDetails != null) {
|
|
197
198
|
pendingCompleteValueRef.current = {
|
|
198
199
|
value: normalizedValue,
|
|
199
|
-
eventDetails:
|
|
200
|
+
eventDetails: completeEventDetails
|
|
200
201
|
};
|
|
201
202
|
} else if (normalizedValue.length !== length) {
|
|
202
203
|
pendingCompleteValueRef.current = null;
|
|
@@ -263,12 +264,12 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
263
264
|
reportValueInvalid,
|
|
264
265
|
readOnly,
|
|
265
266
|
required,
|
|
266
|
-
|
|
267
|
+
normalizeValue,
|
|
267
268
|
setValue,
|
|
268
269
|
state,
|
|
269
270
|
validationType,
|
|
270
271
|
value
|
|
271
|
-
}), [activeIndex, autoComplete, disabled, focusInput, form, getInputId, handleInputBlur, handleInputFocus, inputMode, inputAriaLabelledBy, invalid, length, mask, pattern, queueFocusInput, readOnly, reportValueInvalid, required,
|
|
272
|
+
}), [activeIndex, autoComplete, disabled, focusInput, form, getInputId, handleInputBlur, handleInputFocus, inputMode, inputAriaLabelledBy, invalid, length, mask, pattern, queueFocusInput, readOnly, reportValueInvalid, required, normalizeValue, setValue, state, validationType, value]);
|
|
272
273
|
const element = useRenderElement('div', componentProps, {
|
|
273
274
|
ref: [forwardedRef, rootRef],
|
|
274
275
|
state,
|
|
@@ -292,12 +293,14 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
292
293
|
focusInput(0);
|
|
293
294
|
},
|
|
294
295
|
onChange(event) {
|
|
295
|
-
if (event.nativeEvent.defaultPrevented) {
|
|
296
|
+
if (event.nativeEvent.defaultPrevented || disabled || readOnly) {
|
|
297
|
+
// Outside Field.Root, the event is not wrapped by mergeProps.
|
|
298
|
+
event.preventBaseUIHandler?.();
|
|
296
299
|
return;
|
|
297
300
|
}
|
|
298
301
|
const rawValue = event.currentTarget.value;
|
|
299
|
-
const normalizedValue =
|
|
300
|
-
if (
|
|
302
|
+
const [normalizedValue, didRejectCharacters] = normalizeOTPValueWithDetails(rawValue, length, validationType, normalizeValue);
|
|
303
|
+
if (didRejectCharacters) {
|
|
301
304
|
reportValueInvalid(rawValue, createGenericEventDetails(REASONS.inputChange, event.nativeEvent));
|
|
302
305
|
}
|
|
303
306
|
const committedValue = setValue(normalizedValue, createChangeEventDetails(REASONS.inputChange, event.nativeEvent));
|
|
@@ -328,6 +331,12 @@ export const OTPFieldRoot = /*#__PURE__*/React.forwardRef(function OTPFieldRoot(
|
|
|
328
331
|
});
|
|
329
332
|
});
|
|
330
333
|
if (process.env.NODE_ENV !== "production") OTPFieldRoot.displayName = "OTPFieldRoot";
|
|
334
|
+
function getCompleteEventDetails(details) {
|
|
335
|
+
if (details.reason === REASONS.inputChange || details.reason === REASONS.inputPaste) {
|
|
336
|
+
return createGenericEventDetails(details.reason, details.event);
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
331
340
|
function mergeAriaIds(...values) {
|
|
332
341
|
const ids = values.flatMap(value => value?.split(/\s+/).filter(Boolean) ?? []);
|
|
333
342
|
return ids.length > 0 ? Array.from(new Set(ids)).join(' ') : undefined;
|
|
@@ -335,9 +344,7 @@ function mergeAriaIds(...values) {
|
|
|
335
344
|
function useOTPFieldRootDevWarnings(parameters) {
|
|
336
345
|
const {
|
|
337
346
|
inputCount,
|
|
338
|
-
length
|
|
339
|
-
sanitizeValue,
|
|
340
|
-
validationType
|
|
347
|
+
length
|
|
341
348
|
} = parameters;
|
|
342
349
|
React.useEffect(() => {
|
|
343
350
|
if (!Number.isInteger(length) || length <= 0 || inputCount === 0 || inputCount === length) {
|
|
@@ -354,11 +361,4 @@ function useOTPFieldRootDevWarnings(parameters) {
|
|
|
354
361
|
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
355
362
|
warn(`<OTPField.Root> \`length\` must be a positive integer. Received \`length={${String(length)}}\`.`, ownerStackMessage);
|
|
356
363
|
}, [length]);
|
|
357
|
-
React.useEffect(() => {
|
|
358
|
-
if (sanitizeValue == null || validationType === 'none') {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
362
|
-
warn('<OTPField.Root> `sanitizeValue` is only used when `validationType="none"`.', ownerStackMessage);
|
|
363
|
-
}, [sanitizeValue, validationType]);
|
|
364
364
|
}
|
|
@@ -20,7 +20,7 @@ export interface OTPFieldRootContext {
|
|
|
20
20
|
reportValueInvalid: (value: string, details: OTPFieldRoot.InvalidEventDetails) => void;
|
|
21
21
|
readOnly: boolean;
|
|
22
22
|
required: boolean;
|
|
23
|
-
|
|
23
|
+
normalizeValue: ((value: string) => string) | undefined;
|
|
24
24
|
setValue: (value: string, details: OTPFieldRoot.ChangeEventDetails) => string | null;
|
|
25
25
|
state: OTPFieldRootState;
|
|
26
26
|
validationType: OTPFieldRoot.ValidationType;
|
|
@@ -8,14 +8,15 @@ export type OTPValidationType = 'numeric' | 'alpha' | 'alphanumeric' | 'none';
|
|
|
8
8
|
export declare function getOTPValidationConfig(validationType: OTPValidationType): OTPValidationConfig | null;
|
|
9
9
|
export declare function stripOTPWhitespace(value: string | null | undefined): string;
|
|
10
10
|
/**
|
|
11
|
-
* Normalizes user-entered OTP text by stripping whitespace, applying validation
|
|
12
|
-
*
|
|
11
|
+
* Normalizes user-entered OTP text by stripping whitespace, applying validation and custom
|
|
12
|
+
* normalization, and clamping the final value to the configured slot count.
|
|
13
13
|
*/
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function normalizeOTPValueWithDetails(value: string | null | undefined, length: number, validationType: OTPValidationType, normalizeValue?: ((value: string) => string) | undefined): readonly [value: string, didRejectCharacters: boolean];
|
|
15
|
+
export declare function normalizeOTPValue(value: string | null | undefined, length: number, validationType: OTPValidationType, normalizeValue?: ((value: string) => string) | undefined): string;
|
|
15
16
|
/**
|
|
16
17
|
* Replaces characters starting at the provided slot index, then re-normalizes the final OTP value
|
|
17
18
|
* so paste and multi-character edits stay contiguous and length-bounded.
|
|
18
19
|
*/
|
|
19
|
-
export declare function replaceOTPValue(currentValue: string, index: number, nextValue: string, length: number, validationType: OTPValidationType,
|
|
20
|
+
export declare function replaceOTPValue(currentValue: string, index: number, nextValue: string, length: number, validationType: OTPValidationType, normalizeValue?: ((value: string) => string) | undefined): string;
|
|
20
21
|
export declare function removeOTPCharacter(currentValue: string, index: number): string;
|
|
21
22
|
export {};
|
|
@@ -27,33 +27,44 @@ export function getOTPValidationConfig(validationType) {
|
|
|
27
27
|
export function stripOTPWhitespace(value) {
|
|
28
28
|
return (value ?? '').replace(/\s/g, '');
|
|
29
29
|
}
|
|
30
|
+
function applyOTPValidation(value, validation) {
|
|
31
|
+
return validation ? value.replace(validation.regexp, '') : value;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
* Normalizes user-entered OTP text by stripping whitespace, applying validation
|
|
33
|
-
*
|
|
35
|
+
* Normalizes user-entered OTP text by stripping whitespace, applying validation and custom
|
|
36
|
+
* normalization, and clamping the final value to the configured slot count.
|
|
34
37
|
*/
|
|
35
|
-
export function
|
|
36
|
-
|
|
38
|
+
export function normalizeOTPValueWithDetails(value, length, validationType, normalizeValue) {
|
|
39
|
+
const strippedValue = stripOTPWhitespace(value);
|
|
37
40
|
const validation = getOTPValidationConfig(validationType);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
let normalizedValue = applyOTPValidation(strippedValue, validation);
|
|
42
|
+
let didRejectCharacters = strippedValue.length > normalizedValue.length;
|
|
43
|
+
if (normalizeValue) {
|
|
44
|
+
const customNormalizedValue = normalizeValue(normalizedValue);
|
|
45
|
+
didRejectCharacters ||= normalizedValue.length > customNormalizedValue.length;
|
|
46
|
+
normalizedValue = applyOTPValidation(customNormalizedValue, validation);
|
|
47
|
+
didRejectCharacters ||= customNormalizedValue.length > normalizedValue.length;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
// Slice by Unicode code points so multi-byte characters do not split across OTP slots.
|
|
45
|
-
|
|
51
|
+
const maxLength = length < 0 ? 0 : length;
|
|
52
|
+
const normalizedCharacters = Array.from(normalizedValue);
|
|
53
|
+
return [normalizedCharacters.slice(0, maxLength).join(''), didRejectCharacters || normalizedCharacters.length > maxLength];
|
|
54
|
+
}
|
|
55
|
+
export function normalizeOTPValue(value, length, validationType, normalizeValue) {
|
|
56
|
+
return normalizeOTPValueWithDetails(value, length, validationType, normalizeValue)[0];
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
/**
|
|
49
60
|
* Replaces characters starting at the provided slot index, then re-normalizes the final OTP value
|
|
50
61
|
* so paste and multi-character edits stay contiguous and length-bounded.
|
|
51
62
|
*/
|
|
52
|
-
export function replaceOTPValue(currentValue, index, nextValue, length, validationType,
|
|
53
|
-
const normalizedValue = normalizeOTPValue(nextValue, length, validationType,
|
|
63
|
+
export function replaceOTPValue(currentValue, index, nextValue, length, validationType, normalizeValue) {
|
|
64
|
+
const normalizedValue = normalizeOTPValue(nextValue, length, validationType, normalizeValue);
|
|
54
65
|
const prefix = currentValue.slice(0, index);
|
|
55
66
|
const suffix = currentValue.slice(index + normalizedValue.length);
|
|
56
|
-
return normalizeOTPValue(`${prefix}${normalizedValue}${suffix}`, length, validationType,
|
|
67
|
+
return normalizeOTPValue(`${prefix}${normalizedValue}${suffix}`, length, validationType, normalizeValue);
|
|
57
68
|
}
|
|
58
69
|
export function removeOTPCharacter(currentValue, index) {
|
|
59
70
|
if (index < 0 || index >= currentValue.length) {
|
|
@@ -14,8 +14,8 @@ import { useRenderElement } from "../../internals/useRenderElement.js";
|
|
|
14
14
|
*/
|
|
15
15
|
export const PopoverArrow = /*#__PURE__*/React.forwardRef(function PopoverArrow(componentProps, forwardedRef) {
|
|
16
16
|
const {
|
|
17
|
-
className,
|
|
18
17
|
render,
|
|
18
|
+
className,
|
|
19
19
|
style,
|
|
20
20
|
...elementProps
|
|
21
21
|
} = componentProps;
|
|
@@ -18,9 +18,9 @@ export const PopoverClose = /*#__PURE__*/React.forwardRef(function PopoverClose(
|
|
|
18
18
|
const {
|
|
19
19
|
render,
|
|
20
20
|
className,
|
|
21
|
+
style,
|
|
21
22
|
disabled = false,
|
|
22
23
|
nativeButton = true,
|
|
23
|
-
style,
|
|
24
24
|
...elementProps
|
|
25
25
|
} = componentProps;
|
|
26
26
|
const {
|
|
@@ -39,7 +39,7 @@ export const PopoverClose = /*#__PURE__*/React.forwardRef(function PopoverClose(
|
|
|
39
39
|
ref: [forwardedRef, buttonRef],
|
|
40
40
|
props: [{
|
|
41
41
|
onClick(event) {
|
|
42
|
-
store.setOpen(false, createChangeEventDetails(REASONS.closePress, event.nativeEvent
|
|
42
|
+
store.setOpen(false, createChangeEventDetails(REASONS.closePress, event.nativeEvent));
|
|
43
43
|
}
|
|
44
44
|
}, elementProps, getButtonProps]
|
|
45
45
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect';
|
|
5
4
|
import { usePopoverRootContext } from "../root/PopoverRootContext.js";
|
|
6
5
|
import { useBaseUiId } from "../../internals/useBaseUiId.js";
|
|
7
6
|
import { useRenderElement } from "../../internals/useRenderElement.js";
|
|
@@ -23,12 +22,7 @@ export const PopoverDescription = /*#__PURE__*/React.forwardRef(function Popover
|
|
|
23
22
|
store
|
|
24
23
|
} = usePopoverRootContext();
|
|
25
24
|
const id = useBaseUiId(elementProps.id);
|
|
26
|
-
|
|
27
|
-
store.set('descriptionElementId', id);
|
|
28
|
-
return () => {
|
|
29
|
-
store.set('descriptionElementId', undefined);
|
|
30
|
-
};
|
|
31
|
-
}, [store, id]);
|
|
25
|
+
store.useSyncedValueWithCleanup('descriptionElementId', id);
|
|
32
26
|
const element = useRenderElement('p', componentProps, {
|
|
33
27
|
ref: forwardedRef,
|
|
34
28
|
props: [{
|
|
@@ -30,7 +30,7 @@ export interface PopoverPopupState {
|
|
|
30
30
|
/**
|
|
31
31
|
* Whether transitions should be skipped.
|
|
32
32
|
*/
|
|
33
|
-
instant: 'dismiss' | 'click' | undefined;
|
|
33
|
+
instant: 'dismiss' | 'click' | 'focus' | 'trigger-change' | undefined;
|
|
34
34
|
}
|
|
35
35
|
export interface PopoverPopupProps extends BaseUIComponentProps<'div', PopoverPopupState> {
|
|
36
36
|
/**
|