@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.
Files changed (579) hide show
  1. package/CHANGELOG.md +125 -8
  2. package/README.md +1 -1
  3. package/accordion/item/AccordionItem.d.ts +4 -0
  4. package/accordion/item/AccordionItem.js +5 -4
  5. package/accordion/panel/AccordionPanel.js +29 -51
  6. package/accordion/root/AccordionRoot.js +5 -6
  7. package/accordion/trigger/AccordionTrigger.js +3 -4
  8. package/alert-dialog/handle.d.ts +14 -1
  9. package/alert-dialog/handle.js +22 -5
  10. package/alert-dialog/index.d.ts +1 -1
  11. package/alert-dialog/index.parts.d.ts +2 -3
  12. package/alert-dialog/index.parts.js +4 -5
  13. package/alert-dialog/root/AlertDialogRoot.d.ts +7 -7
  14. package/alert-dialog/root/AlertDialogRoot.js +2 -56
  15. package/alert-dialog/trigger/AlertDialogTrigger.d.ts +25 -0
  16. package/alert-dialog/trigger/AlertDialogTrigger.js +15 -0
  17. package/alert-dialog/trigger/AlertDialogTriggerDataAttributes.d.ts +10 -0
  18. package/alert-dialog/trigger/AlertDialogTriggerDataAttributes.js +18 -0
  19. package/autocomplete/root/AutocompleteRoot.js +9 -10
  20. package/avatar/image/AvatarImage.js +4 -4
  21. package/checkbox/indicator/CheckboxIndicator.js +2 -2
  22. package/checkbox/root/CheckboxRoot.js +49 -11
  23. package/checkbox-group/CheckboxGroup.js +1 -5
  24. package/collapsible/panel/CollapsiblePanel.js +29 -51
  25. package/collapsible/panel/useCollapsiblePanel.d.ts +9 -23
  26. package/collapsible/panel/useCollapsiblePanel.js +308 -268
  27. package/collapsible/root/CollapsibleRoot.d.ts +1 -1
  28. package/collapsible/root/CollapsibleRootContext.d.ts +0 -2
  29. package/collapsible/root/useCollapsibleRoot.d.ts +0 -27
  30. package/collapsible/root/useCollapsibleRoot.js +2 -64
  31. package/collapsible/trigger/CollapsibleTrigger.js +5 -6
  32. package/combobox/arrow/ComboboxArrow.js +1 -1
  33. package/combobox/backdrop/ComboboxBackdrop.js +1 -1
  34. package/combobox/chip/ComboboxChip.js +7 -2
  35. package/combobox/clear/ComboboxClear.d.ts +4 -0
  36. package/combobox/clear/ComboboxClear.js +1 -0
  37. package/combobox/clear/ComboboxClearDataAttributes.d.ts +4 -0
  38. package/combobox/clear/ComboboxClearDataAttributes.js +4 -0
  39. package/combobox/icon/ComboboxIcon.js +1 -1
  40. package/combobox/input/ComboboxInput.js +15 -6
  41. package/combobox/item/ComboboxItem.js +8 -14
  42. package/combobox/item-indicator/ComboboxItemIndicator.js +1 -2
  43. package/combobox/root/AriaCombobox.js +61 -28
  44. package/combobox/store.d.ts +4 -8
  45. package/combobox/store.js +2 -1
  46. package/combobox/utils/ComboboxInternalDismissButton.js +2 -3
  47. package/csp-provider/CSPProvider.js +1 -1
  48. package/dialog/close/DialogClose.js +6 -6
  49. package/dialog/popup/DialogPopup.js +9 -4
  50. package/dialog/root/DialogRoot.d.ts +1 -2
  51. package/dialog/root/DialogRoot.js +3 -73
  52. package/dialog/root/DialogRootContext.d.ts +1 -0
  53. package/dialog/root/DialogRootContext.js +3 -1
  54. package/dialog/root/useDialogRoot.d.ts +12 -4
  55. package/dialog/root/useDialogRoot.js +27 -25
  56. package/dialog/root/useRenderDialogRoot.d.ts +4 -0
  57. package/dialog/root/useRenderDialogRoot.js +96 -0
  58. package/dialog/store/DialogHandle.d.ts +1 -1
  59. package/dialog/store/DialogHandle.js +2 -2
  60. package/dialog/store/DialogStore.d.ts +88 -1
  61. package/dialog/store/DialogStore.js +12 -17
  62. package/dialog/trigger/DialogTrigger.d.ts +1 -1
  63. package/dialog/trigger/DialogTrigger.js +11 -4
  64. package/dialog/viewport/DialogViewport.js +4 -3
  65. package/drawer/popup/DrawerPopup.js +13 -9
  66. package/drawer/root/DrawerRoot.js +11 -11
  67. package/drawer/root/DrawerRootContext.d.ts +1 -1
  68. package/drawer/swipe-area/DrawerSwipeArea.js +6 -5
  69. package/drawer/viewport/DrawerViewport.js +13 -14
  70. package/esm/accordion/item/AccordionItem.d.ts +4 -0
  71. package/esm/accordion/item/AccordionItem.js +5 -4
  72. package/esm/accordion/panel/AccordionPanel.js +29 -51
  73. package/esm/accordion/root/AccordionRoot.js +5 -6
  74. package/esm/accordion/trigger/AccordionTrigger.js +4 -5
  75. package/esm/alert-dialog/handle.d.ts +14 -1
  76. package/esm/alert-dialog/handle.js +20 -5
  77. package/esm/alert-dialog/index.d.ts +1 -1
  78. package/esm/alert-dialog/index.parts.d.ts +2 -3
  79. package/esm/alert-dialog/index.parts.js +2 -3
  80. package/esm/alert-dialog/root/AlertDialogRoot.d.ts +7 -7
  81. package/esm/alert-dialog/root/AlertDialogRoot.js +2 -55
  82. package/esm/alert-dialog/trigger/AlertDialogTrigger.d.ts +25 -0
  83. package/esm/alert-dialog/trigger/AlertDialogTrigger.js +10 -0
  84. package/esm/alert-dialog/trigger/AlertDialogTriggerDataAttributes.d.ts +10 -0
  85. package/esm/alert-dialog/trigger/AlertDialogTriggerDataAttributes.js +12 -0
  86. package/esm/autocomplete/root/AutocompleteRoot.js +9 -10
  87. package/esm/avatar/image/AvatarImage.js +4 -4
  88. package/esm/checkbox/indicator/CheckboxIndicator.js +2 -2
  89. package/esm/checkbox/root/CheckboxRoot.js +49 -11
  90. package/esm/checkbox-group/CheckboxGroup.js +1 -5
  91. package/esm/collapsible/panel/CollapsiblePanel.js +29 -51
  92. package/esm/collapsible/panel/useCollapsiblePanel.d.ts +9 -23
  93. package/esm/collapsible/panel/useCollapsiblePanel.js +309 -269
  94. package/esm/collapsible/root/CollapsibleRoot.d.ts +1 -1
  95. package/esm/collapsible/root/CollapsibleRootContext.d.ts +0 -2
  96. package/esm/collapsible/root/useCollapsibleRoot.d.ts +0 -27
  97. package/esm/collapsible/root/useCollapsibleRoot.js +2 -64
  98. package/esm/collapsible/trigger/CollapsibleTrigger.js +5 -6
  99. package/esm/combobox/arrow/ComboboxArrow.js +1 -1
  100. package/esm/combobox/backdrop/ComboboxBackdrop.js +1 -1
  101. package/esm/combobox/chip/ComboboxChip.js +7 -2
  102. package/esm/combobox/clear/ComboboxClear.d.ts +4 -0
  103. package/esm/combobox/clear/ComboboxClear.js +1 -0
  104. package/esm/combobox/clear/ComboboxClearDataAttributes.d.ts +4 -0
  105. package/esm/combobox/clear/ComboboxClearDataAttributes.js +4 -0
  106. package/esm/combobox/icon/ComboboxIcon.js +1 -1
  107. package/esm/combobox/input/ComboboxInput.js +16 -7
  108. package/esm/combobox/item/ComboboxItem.js +8 -14
  109. package/esm/combobox/item-indicator/ComboboxItemIndicator.js +1 -2
  110. package/esm/combobox/root/AriaCombobox.js +62 -29
  111. package/esm/combobox/store.d.ts +4 -8
  112. package/esm/combobox/store.js +2 -1
  113. package/esm/combobox/utils/ComboboxInternalDismissButton.js +2 -3
  114. package/esm/csp-provider/CSPProvider.js +1 -1
  115. package/esm/dialog/close/DialogClose.js +6 -6
  116. package/esm/dialog/popup/DialogPopup.js +9 -4
  117. package/esm/dialog/root/DialogRoot.d.ts +1 -2
  118. package/esm/dialog/root/DialogRoot.js +4 -72
  119. package/esm/dialog/root/DialogRootContext.d.ts +1 -0
  120. package/esm/dialog/root/DialogRootContext.js +2 -0
  121. package/esm/dialog/root/useDialogRoot.d.ts +12 -4
  122. package/esm/dialog/root/useDialogRoot.js +28 -27
  123. package/esm/dialog/root/useRenderDialogRoot.d.ts +4 -0
  124. package/esm/dialog/root/useRenderDialogRoot.js +90 -0
  125. package/esm/dialog/store/DialogHandle.d.ts +1 -1
  126. package/esm/dialog/store/DialogHandle.js +2 -2
  127. package/esm/dialog/store/DialogStore.d.ts +88 -1
  128. package/esm/dialog/store/DialogStore.js +13 -18
  129. package/esm/dialog/trigger/DialogTrigger.d.ts +1 -1
  130. package/esm/dialog/trigger/DialogTrigger.js +12 -5
  131. package/esm/dialog/viewport/DialogViewport.js +4 -3
  132. package/esm/drawer/popup/DrawerPopup.js +14 -9
  133. package/esm/drawer/root/DrawerRoot.js +11 -11
  134. package/esm/drawer/root/DrawerRootContext.d.ts +1 -1
  135. package/esm/drawer/swipe-area/DrawerSwipeArea.js +6 -5
  136. package/esm/drawer/viewport/DrawerViewport.js +13 -14
  137. package/esm/field/control/FieldControl.js +2 -6
  138. package/esm/field/item/FieldItem.js +1 -4
  139. package/esm/field/root/FieldRoot.js +11 -3
  140. package/esm/field/root/useFieldValidation.d.ts +1 -0
  141. package/esm/field/root/useFieldValidation.js +23 -20
  142. package/esm/field/utils/getCombinedFieldValidityData.d.ts +1 -1
  143. package/esm/field/validity/FieldValidity.d.ts +1 -1
  144. package/esm/floating-ui-react/components/FloatingDelayGroup.js +3 -3
  145. package/esm/floating-ui-react/components/FloatingFocusManager.d.ts +1 -1
  146. package/esm/floating-ui-react/components/FloatingFocusManager.js +20 -8
  147. package/esm/floating-ui-react/components/FloatingPortal.js +3 -3
  148. package/esm/floating-ui-react/hooks/useClick.js +83 -74
  149. package/esm/floating-ui-react/hooks/useClientPoint.js +29 -20
  150. package/esm/floating-ui-react/hooks/useDismiss.d.ts +1 -1
  151. package/esm/floating-ui-react/hooks/useDismiss.js +82 -93
  152. package/esm/floating-ui-react/hooks/useFloating.js +37 -32
  153. package/esm/floating-ui-react/hooks/useFloatingRootContext.d.ts +1 -1
  154. package/esm/floating-ui-react/hooks/useFloatingRootContext.js +2 -2
  155. package/esm/floating-ui-react/hooks/useFocus.js +84 -81
  156. package/esm/floating-ui-react/hooks/useHover.js +72 -76
  157. package/esm/floating-ui-react/hooks/useHoverFloatingInteraction.js +49 -44
  158. package/esm/floating-ui-react/hooks/useHoverInteractionSharedState.js +1 -1
  159. package/esm/floating-ui-react/hooks/useHoverReferenceInteraction.d.ts +7 -2
  160. package/esm/floating-ui-react/hooks/useHoverReferenceInteraction.js +44 -39
  161. package/esm/floating-ui-react/hooks/useHoverShared.d.ts +2 -1
  162. package/esm/floating-ui-react/hooks/useHoverShared.js +4 -0
  163. package/esm/floating-ui-react/hooks/useListNavigation.d.ts +1 -3
  164. package/esm/floating-ui-react/hooks/useListNavigation.js +83 -74
  165. package/esm/floating-ui-react/hooks/useSyncedFloatingRootContext.d.ts +9 -6
  166. package/esm/floating-ui-react/hooks/useSyncedFloatingRootContext.js +25 -20
  167. package/esm/floating-ui-react/hooks/useTypeahead.d.ts +2 -2
  168. package/esm/floating-ui-react/hooks/useTypeahead.js +33 -52
  169. package/esm/floating-ui-react/index.d.ts +0 -2
  170. package/esm/floating-ui-react/index.js +0 -2
  171. package/esm/floating-ui-react/types.d.ts +2 -7
  172. package/esm/floating-ui-react/utils/composite.js +2 -0
  173. package/esm/floating-ui-react/utils/enqueueFocus.d.ts +1 -1
  174. package/esm/floating-ui-react/utils/enqueueFocus.js +10 -7
  175. package/esm/floating-ui-react/utils/getEmptyRootContext.js +1 -1
  176. package/esm/form/Form.js +2 -2
  177. package/esm/index.js +1 -1
  178. package/esm/internals/composite/composite.d.ts +0 -1
  179. package/esm/internals/composite/composite.js +1 -2
  180. package/esm/internals/composite/root/useCompositeRoot.js +2 -2
  181. package/esm/internals/createBaseUIEventDetails.d.ts +2 -0
  182. package/esm/internals/csp-context/index.d.ts +2 -0
  183. package/esm/internals/csp-context/index.js +1 -0
  184. package/esm/internals/field-register-control/index.d.ts +0 -1
  185. package/esm/internals/field-register-control/useFieldControlRegistration.d.ts +2 -1
  186. package/esm/internals/field-register-control/useFieldControlRegistration.js +11 -14
  187. package/esm/internals/field-register-control/useRegisterFieldControl.d.ts +1 -4
  188. package/esm/internals/field-register-control/useRegisterFieldControl.js +6 -11
  189. package/esm/internals/field-root-context/FieldRootContext.d.ts +1 -0
  190. package/esm/internals/field-root-context/FieldRootContext.js +3 -2
  191. package/esm/internals/form-context/FormContext.d.ts +5 -1
  192. package/esm/internals/reason-parts.d.ts +2 -0
  193. package/esm/internals/reason-parts.js +2 -0
  194. package/esm/internals/types.d.ts +1 -0
  195. package/esm/internals/use-button/useButton.js +4 -4
  196. package/esm/internals/usePressAndHold.js +2 -2
  197. package/esm/internals/useRenderElement.js +2 -0
  198. package/esm/menu/arrow/MenuArrow.js +1 -1
  199. package/esm/menu/backdrop/MenuBackdrop.js +1 -1
  200. package/esm/menu/checkbox-item/MenuCheckboxItem.js +5 -7
  201. package/esm/menu/group/MenuGroup.js +1 -4
  202. package/esm/menu/group/MenuGroupContext.d.ts +1 -3
  203. package/esm/menu/group/MenuGroupContext.js +1 -1
  204. package/esm/menu/group-label/MenuGroupLabel.js +4 -6
  205. package/esm/menu/link-item/MenuLinkItem.js +2 -2
  206. package/esm/menu/popup/MenuPopup.js +5 -5
  207. package/esm/menu/radio-group/MenuRadioGroup.js +11 -5
  208. package/esm/menu/radio-item/MenuRadioItem.js +5 -7
  209. package/esm/menu/root/MenuRoot.js +63 -68
  210. package/esm/menu/store/MenuHandle.js +1 -1
  211. package/esm/menu/store/MenuStore.d.ts +87 -0
  212. package/esm/menu/submenu-trigger/MenuSubmenuTrigger.js +8 -5
  213. package/esm/menu/trigger/MenuTrigger.js +13 -10
  214. package/esm/menu/viewport/MenuViewport.d.ts +2 -2
  215. package/esm/menu/viewport/MenuViewport.js +2 -2
  216. package/esm/navigation-menu/arrow/NavigationMenuArrow.js +1 -1
  217. package/esm/navigation-menu/backdrop/NavigationMenuBackdrop.js +1 -1
  218. package/esm/navigation-menu/content/NavigationMenuContent.js +8 -5
  219. package/esm/navigation-menu/icon/NavigationMenuIcon.js +1 -1
  220. package/esm/navigation-menu/item/NavigationMenuItem.js +2 -2
  221. package/esm/navigation-menu/list/NavigationMenuList.js +1 -1
  222. package/esm/navigation-menu/popup/NavigationMenuPopup.js +2 -2
  223. package/esm/navigation-menu/root/NavigationMenuRoot.js +1 -3
  224. package/esm/navigation-menu/trigger/NavigationMenuTrigger.js +24 -17
  225. package/esm/navigation-menu/utils/isOutsideMenuEvent.d.ts +0 -1
  226. package/esm/navigation-menu/utils/isOutsideMenuEvent.js +1 -5
  227. package/esm/navigation-menu/viewport/NavigationMenuViewport.js +2 -3
  228. package/esm/number-field/input/NumberFieldInput.js +3 -5
  229. package/esm/number-field/root/NumberFieldRoot.js +5 -2
  230. package/esm/number-field/scrub-area/NumberFieldScrubArea.js +7 -3
  231. package/esm/otp-field/input/OTPFieldInput.js +43 -29
  232. package/esm/otp-field/root/OTPFieldRoot.d.ts +17 -8
  233. package/esm/otp-field/root/OTPFieldRoot.js +33 -33
  234. package/esm/otp-field/root/OTPFieldRootContext.d.ts +1 -1
  235. package/esm/otp-field/utils/otp.d.ts +5 -4
  236. package/esm/otp-field/utils/otp.js +23 -12
  237. package/esm/popover/arrow/PopoverArrow.js +1 -1
  238. package/esm/popover/backdrop/PopoverBackdrop.js +1 -1
  239. package/esm/popover/close/PopoverClose.js +2 -2
  240. package/esm/popover/description/PopoverDescription.js +1 -7
  241. package/esm/popover/popup/PopoverPopup.d.ts +1 -1
  242. package/esm/popover/popup/PopoverPopup.js +16 -10
  243. package/esm/popover/popup/PopoverPopupDataAttributes.d.ts +1 -1
  244. package/esm/popover/popup/PopoverPopupDataAttributes.js +1 -1
  245. package/esm/popover/positioner/PopoverPositioner.js +5 -5
  246. package/esm/popover/root/PopoverRoot.d.ts +1 -1
  247. package/esm/popover/root/PopoverRoot.js +42 -47
  248. package/esm/popover/store/PopoverHandle.js +1 -1
  249. package/esm/popover/store/PopoverStore.d.ts +91 -4
  250. package/esm/popover/store/PopoverStore.js +17 -18
  251. package/esm/popover/title/PopoverTitle.js +1 -7
  252. package/esm/popover/trigger/PopoverTrigger.js +24 -17
  253. package/esm/popover/viewport/PopoverViewport.d.ts +3 -3
  254. package/esm/popover/viewport/PopoverViewport.js +2 -2
  255. package/esm/popover/viewport/PopoverViewportDataAttributes.d.ts +1 -1
  256. package/esm/popover/viewport/PopoverViewportDataAttributes.js +1 -1
  257. package/esm/preview-card/positioner/PreviewCardPositioner.js +11 -1
  258. package/esm/preview-card/root/PreviewCardRoot.d.ts +1 -1
  259. package/esm/preview-card/root/PreviewCardRoot.js +32 -22
  260. package/esm/preview-card/store/PreviewCardHandle.js +1 -1
  261. package/esm/preview-card/store/PreviewCardStore.d.ts +90 -2
  262. package/esm/preview-card/store/PreviewCardStore.js +19 -31
  263. package/esm/preview-card/trigger/PreviewCardTrigger.js +6 -3
  264. package/esm/preview-card/viewport/PreviewCardViewport.d.ts +2 -2
  265. package/esm/preview-card/viewport/PreviewCardViewport.js +2 -2
  266. package/esm/preview-card/viewport/PreviewCardViewportDataAttributes.d.ts +2 -2
  267. package/esm/preview-card/viewport/PreviewCardViewportDataAttributes.js +2 -2
  268. package/esm/progress/indicator/ProgressIndicator.js +6 -11
  269. package/esm/progress/root/ProgressRoot.d.ts +1 -1
  270. package/esm/radio/root/RadioRoot.js +7 -3
  271. package/esm/radio-group/RadioGroup.js +4 -11
  272. package/esm/radio-group/RadioGroupContext.d.ts +0 -1
  273. package/esm/scroll-area/content/ScrollAreaContent.js +4 -4
  274. package/esm/scroll-area/root/ScrollAreaRoot.js +1 -1
  275. package/esm/scroll-area/scrollbar/ScrollAreaScrollbar.js +16 -20
  276. package/esm/scroll-area/viewport/ScrollAreaViewport.js +6 -10
  277. package/esm/select/arrow/SelectArrow.js +1 -1
  278. package/esm/select/backdrop/SelectBackdrop.js +1 -1
  279. package/esm/select/group/SelectGroup.js +1 -1
  280. package/esm/select/group-label/SelectGroupLabel.js +2 -2
  281. package/esm/select/icon/SelectIcon.js +1 -1
  282. package/esm/select/item/SelectItem.js +46 -32
  283. package/esm/select/item/SelectItemContext.d.ts +1 -1
  284. package/esm/select/item-indicator/SelectItemIndicator.js +1 -2
  285. package/esm/select/item-text/SelectItemText.js +9 -6
  286. package/esm/select/list/SelectList.js +1 -1
  287. package/esm/select/popup/SelectPopup.js +8 -3
  288. package/esm/select/positioner/SelectPositioner.js +3 -0
  289. package/esm/select/root/SelectRoot.js +46 -40
  290. package/esm/select/root/SelectRootContext.d.ts +4 -5
  291. package/esm/select/store.d.ts +3 -0
  292. package/esm/select/store.js +1 -0
  293. package/esm/select/trigger/SelectTrigger.d.ts +5 -0
  294. package/esm/select/trigger/SelectTrigger.js +19 -33
  295. package/esm/select/trigger/SelectTriggerDataAttributes.d.ts +5 -0
  296. package/esm/select/trigger/SelectTriggerDataAttributes.js +5 -0
  297. package/esm/slider/control/SliderControl.js +10 -12
  298. package/esm/slider/root/SliderRoot.js +1 -4
  299. package/esm/slider/thumb/SliderThumb.js +32 -30
  300. package/esm/slider/value/SliderValue.js +7 -15
  301. package/esm/switch/root/SwitchRoot.js +10 -10
  302. package/esm/switch/thumb/SwitchThumb.js +1 -9
  303. package/esm/tabs/indicator/TabsIndicator.js +14 -19
  304. package/esm/tabs/list/TabsList.js +4 -10
  305. package/esm/tabs/list/TabsListContext.d.ts +2 -1
  306. package/esm/tabs/panel/TabsPanel.js +1 -1
  307. package/esm/tabs/root/TabsRoot.d.ts +16 -1
  308. package/esm/tabs/root/TabsRoot.js +73 -25
  309. package/esm/tabs/root/TabsRootContext.d.ts +0 -2
  310. package/esm/toast/provider/ToastProvider.js +1 -1
  311. package/esm/toast/root/ToastRoot.d.ts +1 -1
  312. package/esm/toast/root/ToastRoot.js +108 -131
  313. package/esm/toast/root/ToastRootDataAttributes.d.ts +1 -1
  314. package/esm/toast/root/ToastRootDataAttributes.js +1 -1
  315. package/esm/toast/store.d.ts +9 -1
  316. package/esm/toast/store.js +19 -13
  317. package/esm/toast/useToastManager.d.ts +1 -1
  318. package/esm/toast/viewport/ToastViewport.js +1 -1
  319. package/esm/toggle/Toggle.js +5 -9
  320. package/esm/toggle-group/ToggleGroup.d.ts +2 -2
  321. package/esm/toggle-group/ToggleGroup.js +6 -13
  322. package/esm/toolbar/link/ToolbarLink.d.ts +1 -1
  323. package/esm/toolbar/link/ToolbarLink.js +1 -2
  324. package/esm/tooltip/arrow/TooltipArrow.js +3 -3
  325. package/esm/tooltip/popup/TooltipPopup.js +5 -4
  326. package/esm/tooltip/root/TooltipRoot.js +35 -26
  327. package/esm/tooltip/store/TooltipHandle.js +1 -1
  328. package/esm/tooltip/store/TooltipStore.d.ts +90 -2
  329. package/esm/tooltip/store/TooltipStore.js +18 -31
  330. package/esm/tooltip/trigger/TooltipTrigger.js +151 -20
  331. package/esm/tooltip/viewport/TooltipViewport.d.ts +2 -2
  332. package/esm/tooltip/viewport/TooltipViewport.js +2 -2
  333. package/esm/tooltip/viewport/TooltipViewportDataAttributes.d.ts +1 -1
  334. package/esm/tooltip/viewport/TooltipViewportDataAttributes.js +1 -1
  335. package/esm/unstable-use-media-query/index.js +1 -1
  336. package/esm/utils/popups/index.d.ts +1 -0
  337. package/esm/utils/popups/index.js +1 -0
  338. package/esm/utils/popups/inlineRect.d.ts +15 -0
  339. package/esm/utils/popups/inlineRect.js +191 -0
  340. package/esm/utils/popups/popupStoreUtils.d.ts +28 -10
  341. package/esm/utils/popups/popupStoreUtils.js +105 -20
  342. package/esm/utils/popups/popupTriggerMap.js +2 -0
  343. package/esm/utils/popups/store.d.ts +15 -2
  344. package/esm/utils/popups/store.js +38 -2
  345. package/esm/utils/popups/useTriggerFocusGuards.js +4 -5
  346. package/esm/utils/useAnchorPositioning.d.ts +5 -0
  347. package/esm/utils/useAnchorPositioning.js +12 -9
  348. package/esm/utils/useOpenInteractionType.d.ts +4 -0
  349. package/esm/utils/useOpenInteractionType.js +23 -18
  350. package/field/control/FieldControl.js +2 -6
  351. package/field/item/FieldItem.js +1 -4
  352. package/field/root/FieldRoot.js +11 -3
  353. package/field/root/useFieldValidation.d.ts +1 -0
  354. package/field/root/useFieldValidation.js +23 -20
  355. package/field/utils/getCombinedFieldValidityData.d.ts +1 -1
  356. package/field/validity/FieldValidity.d.ts +1 -1
  357. package/floating-ui-react/components/FloatingDelayGroup.js +3 -3
  358. package/floating-ui-react/components/FloatingFocusManager.d.ts +1 -1
  359. package/floating-ui-react/components/FloatingFocusManager.js +20 -8
  360. package/floating-ui-react/components/FloatingPortal.js +3 -3
  361. package/floating-ui-react/hooks/useClick.js +82 -73
  362. package/floating-ui-react/hooks/useClientPoint.js +29 -20
  363. package/floating-ui-react/hooks/useDismiss.d.ts +1 -1
  364. package/floating-ui-react/hooks/useDismiss.js +82 -92
  365. package/floating-ui-react/hooks/useFloating.js +36 -32
  366. package/floating-ui-react/hooks/useFloatingRootContext.d.ts +1 -1
  367. package/floating-ui-react/hooks/useFloatingRootContext.js +2 -2
  368. package/floating-ui-react/hooks/useFocus.js +84 -81
  369. package/floating-ui-react/hooks/useHover.js +74 -78
  370. package/floating-ui-react/hooks/useHoverFloatingInteraction.js +48 -43
  371. package/floating-ui-react/hooks/useHoverInteractionSharedState.js +1 -1
  372. package/floating-ui-react/hooks/useHoverReferenceInteraction.d.ts +7 -2
  373. package/floating-ui-react/hooks/useHoverReferenceInteraction.js +43 -38
  374. package/floating-ui-react/hooks/useHoverShared.d.ts +2 -1
  375. package/floating-ui-react/hooks/useHoverShared.js +11 -0
  376. package/floating-ui-react/hooks/useListNavigation.d.ts +1 -3
  377. package/floating-ui-react/hooks/useListNavigation.js +83 -74
  378. package/floating-ui-react/hooks/useSyncedFloatingRootContext.d.ts +9 -6
  379. package/floating-ui-react/hooks/useSyncedFloatingRootContext.js +26 -20
  380. package/floating-ui-react/hooks/useTypeahead.d.ts +2 -2
  381. package/floating-ui-react/hooks/useTypeahead.js +33 -52
  382. package/floating-ui-react/index.d.ts +0 -2
  383. package/floating-ui-react/index.js +0 -14
  384. package/floating-ui-react/types.d.ts +2 -7
  385. package/floating-ui-react/utils/composite.js +2 -0
  386. package/floating-ui-react/utils/enqueueFocus.d.ts +1 -1
  387. package/floating-ui-react/utils/enqueueFocus.js +10 -7
  388. package/floating-ui-react/utils/getEmptyRootContext.js +1 -1
  389. package/form/Form.js +2 -2
  390. package/index.js +1 -1
  391. package/internals/composite/composite.d.ts +0 -1
  392. package/internals/composite/composite.js +2 -3
  393. package/internals/composite/root/useCompositeRoot.js +1 -1
  394. package/internals/createBaseUIEventDetails.d.ts +2 -0
  395. package/internals/csp-context/index.d.ts +2 -0
  396. package/internals/csp-context/index.js +18 -0
  397. package/internals/field-register-control/index.d.ts +0 -1
  398. package/internals/field-register-control/useFieldControlRegistration.d.ts +2 -1
  399. package/internals/field-register-control/useFieldControlRegistration.js +11 -14
  400. package/internals/field-register-control/useRegisterFieldControl.d.ts +1 -4
  401. package/internals/field-register-control/useRegisterFieldControl.js +6 -11
  402. package/internals/field-root-context/FieldRootContext.d.ts +1 -0
  403. package/internals/field-root-context/FieldRootContext.js +4 -3
  404. package/internals/form-context/FormContext.d.ts +5 -1
  405. package/internals/reason-parts.d.ts +2 -0
  406. package/internals/reason-parts.js +3 -1
  407. package/internals/types.d.ts +1 -0
  408. package/internals/use-button/useButton.js +4 -4
  409. package/internals/usePressAndHold.js +2 -2
  410. package/internals/useRenderElement.js +2 -0
  411. package/menu/arrow/MenuArrow.js +1 -1
  412. package/menu/backdrop/MenuBackdrop.js +1 -1
  413. package/menu/checkbox-item/MenuCheckboxItem.js +5 -7
  414. package/menu/group/MenuGroup.js +1 -4
  415. package/menu/group/MenuGroupContext.d.ts +1 -3
  416. package/menu/group/MenuGroupContext.js +1 -1
  417. package/menu/group-label/MenuGroupLabel.js +4 -6
  418. package/menu/link-item/MenuLinkItem.js +2 -2
  419. package/menu/popup/MenuPopup.js +5 -5
  420. package/menu/radio-group/MenuRadioGroup.js +11 -5
  421. package/menu/radio-item/MenuRadioItem.js +5 -7
  422. package/menu/root/MenuRoot.js +60 -65
  423. package/menu/store/MenuHandle.js +1 -1
  424. package/menu/store/MenuStore.d.ts +87 -0
  425. package/menu/submenu-trigger/MenuSubmenuTrigger.js +7 -4
  426. package/menu/trigger/MenuTrigger.js +12 -9
  427. package/menu/viewport/MenuViewport.d.ts +2 -2
  428. package/menu/viewport/MenuViewport.js +2 -2
  429. package/navigation-menu/arrow/NavigationMenuArrow.js +1 -1
  430. package/navigation-menu/backdrop/NavigationMenuBackdrop.js +1 -1
  431. package/navigation-menu/content/NavigationMenuContent.js +8 -5
  432. package/navigation-menu/icon/NavigationMenuIcon.js +1 -1
  433. package/navigation-menu/item/NavigationMenuItem.js +2 -2
  434. package/navigation-menu/list/NavigationMenuList.js +1 -1
  435. package/navigation-menu/popup/NavigationMenuPopup.js +2 -2
  436. package/navigation-menu/root/NavigationMenuRoot.js +1 -3
  437. package/navigation-menu/trigger/NavigationMenuTrigger.js +23 -16
  438. package/navigation-menu/utils/isOutsideMenuEvent.d.ts +0 -1
  439. package/navigation-menu/utils/isOutsideMenuEvent.js +1 -5
  440. package/navigation-menu/viewport/NavigationMenuViewport.js +2 -3
  441. package/number-field/input/NumberFieldInput.js +3 -5
  442. package/number-field/root/NumberFieldRoot.js +5 -2
  443. package/number-field/scrub-area/NumberFieldScrubArea.js +7 -3
  444. package/otp-field/input/OTPFieldInput.js +42 -28
  445. package/otp-field/root/OTPFieldRoot.d.ts +17 -8
  446. package/otp-field/root/OTPFieldRoot.js +32 -32
  447. package/otp-field/root/OTPFieldRootContext.d.ts +1 -1
  448. package/otp-field/utils/otp.d.ts +5 -4
  449. package/otp-field/utils/otp.js +24 -12
  450. package/package.json +331 -317
  451. package/popover/arrow/PopoverArrow.js +1 -1
  452. package/popover/backdrop/PopoverBackdrop.js +1 -1
  453. package/popover/close/PopoverClose.js +2 -2
  454. package/popover/description/PopoverDescription.js +1 -7
  455. package/popover/popup/PopoverPopup.d.ts +1 -1
  456. package/popover/popup/PopoverPopup.js +16 -10
  457. package/popover/popup/PopoverPopupDataAttributes.d.ts +1 -1
  458. package/popover/popup/PopoverPopupDataAttributes.js +1 -1
  459. package/popover/positioner/PopoverPositioner.js +5 -5
  460. package/popover/root/PopoverRoot.d.ts +1 -1
  461. package/popover/root/PopoverRoot.js +39 -44
  462. package/popover/store/PopoverHandle.js +1 -1
  463. package/popover/store/PopoverStore.d.ts +91 -4
  464. package/popover/store/PopoverStore.js +16 -19
  465. package/popover/title/PopoverTitle.js +1 -7
  466. package/popover/trigger/PopoverTrigger.js +23 -16
  467. package/popover/viewport/PopoverViewport.d.ts +3 -3
  468. package/popover/viewport/PopoverViewport.js +2 -2
  469. package/popover/viewport/PopoverViewportDataAttributes.d.ts +1 -1
  470. package/popover/viewport/PopoverViewportDataAttributes.js +1 -1
  471. package/preview-card/positioner/PreviewCardPositioner.js +11 -1
  472. package/preview-card/root/PreviewCardRoot.d.ts +1 -1
  473. package/preview-card/root/PreviewCardRoot.js +30 -20
  474. package/preview-card/store/PreviewCardHandle.js +1 -1
  475. package/preview-card/store/PreviewCardStore.d.ts +90 -2
  476. package/preview-card/store/PreviewCardStore.js +18 -30
  477. package/preview-card/trigger/PreviewCardTrigger.js +5 -2
  478. package/preview-card/viewport/PreviewCardViewport.d.ts +2 -2
  479. package/preview-card/viewport/PreviewCardViewport.js +2 -2
  480. package/preview-card/viewport/PreviewCardViewportDataAttributes.d.ts +2 -2
  481. package/preview-card/viewport/PreviewCardViewportDataAttributes.js +2 -2
  482. package/progress/indicator/ProgressIndicator.js +6 -11
  483. package/progress/root/ProgressRoot.d.ts +1 -1
  484. package/radio/root/RadioRoot.js +7 -3
  485. package/radio-group/RadioGroup.js +4 -11
  486. package/radio-group/RadioGroupContext.d.ts +0 -1
  487. package/scroll-area/content/ScrollAreaContent.js +4 -4
  488. package/scroll-area/root/ScrollAreaRoot.js +1 -1
  489. package/scroll-area/scrollbar/ScrollAreaScrollbar.js +16 -20
  490. package/scroll-area/viewport/ScrollAreaViewport.js +6 -10
  491. package/select/arrow/SelectArrow.js +1 -1
  492. package/select/backdrop/SelectBackdrop.js +1 -1
  493. package/select/group/SelectGroup.js +1 -1
  494. package/select/group-label/SelectGroupLabel.js +2 -2
  495. package/select/icon/SelectIcon.js +1 -1
  496. package/select/item/SelectItem.js +46 -32
  497. package/select/item/SelectItemContext.d.ts +1 -1
  498. package/select/item-indicator/SelectItemIndicator.js +1 -2
  499. package/select/item-text/SelectItemText.js +9 -6
  500. package/select/list/SelectList.js +1 -1
  501. package/select/popup/SelectPopup.js +8 -3
  502. package/select/positioner/SelectPositioner.js +3 -0
  503. package/select/root/SelectRoot.js +45 -39
  504. package/select/root/SelectRootContext.d.ts +4 -5
  505. package/select/store.d.ts +3 -0
  506. package/select/store.js +1 -0
  507. package/select/trigger/SelectTrigger.d.ts +5 -0
  508. package/select/trigger/SelectTrigger.js +19 -33
  509. package/select/trigger/SelectTriggerDataAttributes.d.ts +5 -0
  510. package/select/trigger/SelectTriggerDataAttributes.js +5 -0
  511. package/slider/control/SliderControl.js +9 -11
  512. package/slider/root/SliderRoot.js +1 -4
  513. package/slider/thumb/SliderThumb.js +32 -30
  514. package/slider/value/SliderValue.js +7 -15
  515. package/switch/root/SwitchRoot.js +10 -10
  516. package/switch/thumb/SwitchThumb.js +1 -9
  517. package/tabs/indicator/TabsIndicator.js +14 -19
  518. package/tabs/list/TabsList.js +4 -10
  519. package/tabs/list/TabsListContext.d.ts +2 -1
  520. package/tabs/panel/TabsPanel.js +1 -1
  521. package/tabs/root/TabsRoot.d.ts +16 -1
  522. package/tabs/root/TabsRoot.js +71 -24
  523. package/tabs/root/TabsRootContext.d.ts +0 -2
  524. package/toast/provider/ToastProvider.js +1 -1
  525. package/toast/root/ToastRoot.d.ts +1 -1
  526. package/toast/root/ToastRoot.js +110 -133
  527. package/toast/root/ToastRootDataAttributes.d.ts +1 -1
  528. package/toast/root/ToastRootDataAttributes.js +1 -1
  529. package/toast/store.d.ts +9 -1
  530. package/toast/store.js +18 -12
  531. package/toast/useToastManager.d.ts +1 -1
  532. package/toast/viewport/ToastViewport.js +1 -1
  533. package/toggle/Toggle.js +5 -9
  534. package/toggle-group/ToggleGroup.d.ts +2 -2
  535. package/toggle-group/ToggleGroup.js +6 -13
  536. package/toolbar/link/ToolbarLink.d.ts +1 -1
  537. package/toolbar/link/ToolbarLink.js +1 -2
  538. package/tooltip/arrow/TooltipArrow.js +3 -3
  539. package/tooltip/popup/TooltipPopup.js +5 -4
  540. package/tooltip/root/TooltipRoot.js +32 -23
  541. package/tooltip/store/TooltipHandle.js +1 -1
  542. package/tooltip/store/TooltipStore.d.ts +90 -2
  543. package/tooltip/store/TooltipStore.js +17 -30
  544. package/tooltip/trigger/TooltipTrigger.js +152 -20
  545. package/tooltip/viewport/TooltipViewport.d.ts +2 -2
  546. package/tooltip/viewport/TooltipViewport.js +2 -2
  547. package/tooltip/viewport/TooltipViewportDataAttributes.d.ts +1 -1
  548. package/tooltip/viewport/TooltipViewportDataAttributes.js +1 -1
  549. package/unstable-use-media-query/index.js +1 -1
  550. package/utils/popups/index.d.ts +1 -0
  551. package/utils/popups/index.js +11 -0
  552. package/utils/popups/inlineRect.d.ts +15 -0
  553. package/utils/popups/inlineRect.js +198 -0
  554. package/utils/popups/popupStoreUtils.d.ts +28 -10
  555. package/utils/popups/popupStoreUtils.js +110 -20
  556. package/utils/popups/popupTriggerMap.js +2 -0
  557. package/utils/popups/store.d.ts +15 -2
  558. package/utils/popups/store.js +39 -2
  559. package/utils/popups/useTriggerFocusGuards.js +4 -5
  560. package/utils/useAnchorPositioning.d.ts +5 -0
  561. package/utils/useAnchorPositioning.js +12 -9
  562. package/utils/useOpenInteractionType.d.ts +4 -0
  563. package/utils/useOpenInteractionType.js +24 -17
  564. package/checkbox-group/index.parts.d.ts +0 -1
  565. package/checkbox-group/index.parts.js +0 -12
  566. package/esm/checkbox-group/index.parts.d.ts +0 -1
  567. package/esm/checkbox-group/index.parts.js +0 -1
  568. package/esm/floating-ui-react/hooks/useInteractions.d.ts +0 -20
  569. package/esm/floating-ui-react/hooks/useInteractions.js +0 -88
  570. package/esm/floating-ui-react/hooks/useRole.d.ts +0 -17
  571. package/esm/floating-ui-react/hooks/useRole.js +0 -113
  572. package/floating-ui-react/hooks/useInteractions.d.ts +0 -20
  573. package/floating-ui-react/hooks/useInteractions.js +0 -95
  574. package/floating-ui-react/hooks/useRole.d.ts +0 -17
  575. package/floating-ui-react/hooks/useRole.js +0 -120
  576. /package/{csp-provider → esm/internals/csp-context}/CSPContext.d.ts +0 -0
  577. /package/esm/{csp-provider → internals/csp-context}/CSPContext.js +0 -0
  578. /package/{esm/csp-provider → internals/csp-context}/CSPContext.d.ts +0 -0
  579. /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, largeStep, step, getStepAmount]);
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
- if (!didMoveRef.current && pointerDownTargetRef.current != null) {
145
- pointerDownTargetRef.current.dispatchEvent(new MouseEvent('click', {
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 { normalizeOTPValue, removeOTPCharacter, replaceOTPValue, stripOTPWhitespace } from "../utils/otp.js";
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
- sanitizeValue,
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 = normalizeOTPValue(event.currentTarget.value, length, validationType, sanitizeValue);
122
- const didSanitize = stripOTPWhitespace(rawValue).length > nextDigits.length;
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, sanitizeValue);
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
- if (event.key === 'ArrowLeft') {
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(0, index - 1));
156
+ focusInput(hasBoundaryModifier ? firstIndex : Math.max(firstIndex, index - 1));
149
157
  return;
150
158
  }
151
- if (event.key === 'ArrowRight') {
159
+ if (event.key === nextKey) {
152
160
  stopEvent(event);
153
- focusInput(Math.min(length - 1, index + 1));
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(0);
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(Math.max(value.length - 1, 0));
171
+ focusInput(endTargetIndex);
164
172
  return;
165
173
  }
166
174
  if (readOnly) {
167
175
  return;
168
176
  }
169
- if (event.key === 'Delete') {
170
- stopEvent(event);
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(index, committedValue);
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
- focusInput(Math.min(length - 1, index + 1));
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 deleteIndex = slotValue === '' ? Math.max(0, index - 1) : index;
187
- const targetIndex = Math.max(0, index - 1);
188
- const committedValue = setValue(removeOTPCharacter(value, deleteIndex), createChangeEventDetails(REASONS.keyboard, event.nativeEvent));
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 = normalizeOTPValue(rawValue, length, validationType, sanitizeValue);
210
- const didSanitize = stripOTPWhitespace(rawValue).length > nextDigits.length;
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, sanitizeValue), createChangeEventDetails(REASONS.inputPaste, event.nativeEvent));
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 for custom sanitization when `validationType` is set to `'none'`.
61
- * This function runs before updating the OTP value from user interactions.
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
- sanitizeValue?: ((value: string) => string) | undefined;
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 sanitization,
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 sanitization.
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
- * It runs later than `onValueChange`, after the internal value update is applied.
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, stripOTPWhitespace } from "../utils/otp.js";
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
- sanitizeValue,
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, sanitizeValue);
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
- onValueCompleteProp?.(value, pendingCompleteValue.eventDetails);
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, sanitizeValue);
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 (normalizedValue.length === length && valueRef.current.length !== length) {
197
+ if (completeEventDetails != null) {
197
198
  pendingCompleteValueRef.current = {
198
199
  value: normalizedValue,
199
- eventDetails: createGenericEventDetails(details.reason, details.event)
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
- sanitizeValue,
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, sanitizeValue, setValue, state, validationType, value]);
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 = normalizeOTPValue(rawValue, length, validationType, sanitizeValue);
300
- if (stripOTPWhitespace(rawValue).length > normalizedValue.length) {
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
- sanitizeValue: ((value: string) => string) | undefined;
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 or custom
12
- * sanitization, and clamping the final value to the configured slot count.
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 normalizeOTPValue(value: string | null | undefined, length: number, validationType: OTPValidationType, sanitizeValue?: ((value: string) => string) | undefined): string;
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, sanitizeValue?: ((value: string) => string) | undefined): string;
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 or custom
33
- * sanitization, and clamping the final value to the configured slot count.
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 normalizeOTPValue(value, length, validationType, sanitizeValue) {
36
- let sanitizedValue = stripOTPWhitespace(value);
38
+ export function normalizeOTPValueWithDetails(value, length, validationType, normalizeValue) {
39
+ const strippedValue = stripOTPWhitespace(value);
37
40
  const validation = getOTPValidationConfig(validationType);
38
- if (validation) {
39
- sanitizedValue = sanitizedValue.replace(validation.regexp, '');
40
- } else if (sanitizeValue) {
41
- sanitizedValue = sanitizeValue(sanitizedValue);
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
- return Array.from(sanitizedValue).slice(0, Math.max(length, 0)).join('');
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, sanitizeValue) {
53
- const normalizedValue = normalizeOTPValue(nextValue, length, validationType, sanitizeValue);
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, sanitizeValue);
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;
@@ -19,8 +19,8 @@ const stateAttributesMapping = {
19
19
  */
20
20
  export const PopoverBackdrop = /*#__PURE__*/React.forwardRef(function PopoverBackdrop(props, forwardedRef) {
21
21
  const {
22
- className,
23
22
  render,
23
+ className,
24
24
  style,
25
25
  ...elementProps
26
26
  } = props;
@@ -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, event.currentTarget));
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
- useIsoLayoutEffect(() => {
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
  /**