@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
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { getWindow, isElement, isHTMLElement } from '@floating-ui/utils/dom';
5
4
  import { addEventListener } from '@base-ui/utils/addEventListener';
6
- import { mergeCleanups } from '@base-ui/utils/mergeCleanups';
7
5
  import { isMac, isSafari } from '@base-ui/utils/detectBrowser';
8
- import { useTimeout } from '@base-ui/utils/useTimeout';
6
+ import { mergeCleanups } from '@base-ui/utils/mergeCleanups';
9
7
  import { ownerDocument } from '@base-ui/utils/owner';
8
+ import { useTimeout } from '@base-ui/utils/useTimeout';
9
+ import { getWindow, isElement, isHTMLElement } from '@floating-ui/utils/dom';
10
+ import { createAttribute } from "../utils/createAttribute.js";
10
11
  import { activeElement, contains, getTarget, isTargetInsideEnabledTrigger, isTypeableElement, matchesFocusVisible } from "../utils/element.js";
11
12
  import { createChangeEventDetails } from "../../internals/createBaseUIEventDetails.js";
12
13
  import { REASONS } from "../../internals/reasons.js";
13
- import { createAttribute } from "../utils/createAttribute.js";
14
14
  const isMacSafari = isMac && isSafari;
15
15
  /**
16
16
  * Opens the floating element while the reference element has focus, like CSS
@@ -18,20 +18,20 @@ const isMacSafari = isMac && isSafari;
18
18
  * @see https://floating-ui.com/docs/useFocus
19
19
  */
20
20
  export function useFocus(context, props = {}) {
21
+ const {
22
+ enabled = true,
23
+ delay
24
+ } = props;
21
25
  const store = 'rootStore' in context ? context.rootStore : context;
22
26
  const {
23
27
  events,
24
28
  dataRef
25
29
  } = store.context;
26
- const {
27
- enabled = true,
28
- delay
29
- } = props;
30
30
  const blockFocusRef = React.useRef(false);
31
31
  // Track which reference should be blocked from re-opening after Escape/press dismissal.
32
32
  const blockedReferenceRef = React.useRef(null);
33
- const timeout = useTimeout();
34
33
  const keyboardModalityRef = React.useRef(true);
34
+ const timeout = useTimeout();
35
35
  React.useEffect(() => {
36
36
  const domReference = store.select('domReferenceElement');
37
37
  if (!enabled) {
@@ -74,91 +74,94 @@ export function useFocus(context, props = {}) {
74
74
  events.off('openchange', onOpenChangeLocal);
75
75
  };
76
76
  }, [events, enabled, store]);
77
- const reference = React.useMemo(() => ({
78
- onMouseLeave() {
77
+ const reference = React.useMemo(() => {
78
+ function resetBlockedFocus() {
79
79
  blockFocusRef.current = false;
80
80
  blockedReferenceRef.current = null;
81
- },
82
- onFocus(event) {
83
- const focusTarget = event.currentTarget;
84
- if (blockFocusRef.current) {
85
- if (blockedReferenceRef.current === focusTarget) {
86
- return;
81
+ }
82
+ return {
83
+ onMouseLeave() {
84
+ resetBlockedFocus();
85
+ },
86
+ onFocus(event) {
87
+ const focusTarget = event.currentTarget;
88
+ if (blockFocusRef.current) {
89
+ if (blockedReferenceRef.current === focusTarget) {
90
+ return;
91
+ }
92
+ resetBlockedFocus();
87
93
  }
88
- blockFocusRef.current = false;
89
- blockedReferenceRef.current = null;
90
- }
91
- const target = getTarget(event.nativeEvent);
92
- if (isElement(target)) {
93
- // Safari fails to match `:focus-visible` if focus was initially
94
- // outside the document.
95
- if (isMacSafari && !event.relatedTarget) {
96
- if (!keyboardModalityRef.current && !isTypeableElement(target)) {
94
+ const target = getTarget(event.nativeEvent);
95
+ if (isElement(target)) {
96
+ // Safari fails to match `:focus-visible` if focus was initially
97
+ // outside the document.
98
+ if (isMacSafari && !event.relatedTarget) {
99
+ if (!keyboardModalityRef.current && !isTypeableElement(target)) {
100
+ return;
101
+ }
102
+ } else if (!matchesFocusVisible(target)) {
97
103
  return;
98
104
  }
99
- } else if (!matchesFocusVisible(target)) {
100
- return;
101
105
  }
102
- }
103
- const movedFromOtherEnabledTrigger = isTargetInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements);
104
- const {
105
- nativeEvent,
106
- currentTarget
107
- } = event;
108
- const delayValue = typeof delay === 'function' ? delay() : delay;
109
- if (store.select('open') && movedFromOtherEnabledTrigger || delayValue === 0 || delayValue === undefined) {
110
- store.setOpen(true, createChangeEventDetails(REASONS.triggerFocus, nativeEvent, currentTarget));
111
- return;
112
- }
113
- timeout.start(delayValue, () => {
114
- if (blockFocusRef.current) {
106
+ const movedFromOtherEnabledTrigger = isTargetInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements);
107
+ const {
108
+ nativeEvent,
109
+ currentTarget
110
+ } = event;
111
+ const delayValue = typeof delay === 'function' ? delay() : delay;
112
+ if (store.select('open') && movedFromOtherEnabledTrigger || delayValue === 0 || delayValue === undefined) {
113
+ store.setOpen(true, createChangeEventDetails(REASONS.triggerFocus, nativeEvent, currentTarget));
115
114
  return;
116
115
  }
117
- store.setOpen(true, createChangeEventDetails(REASONS.triggerFocus, nativeEvent, currentTarget));
118
- });
119
- },
120
- onBlur(event) {
121
- blockFocusRef.current = false;
122
- blockedReferenceRef.current = null;
123
- const relatedTarget = event.relatedTarget;
124
- const nativeEvent = event.nativeEvent;
116
+ timeout.start(delayValue, () => {
117
+ if (blockFocusRef.current) {
118
+ return;
119
+ }
120
+ store.setOpen(true, createChangeEventDetails(REASONS.triggerFocus, nativeEvent, currentTarget));
121
+ });
122
+ },
123
+ onBlur(event) {
124
+ resetBlockedFocus();
125
+ const relatedTarget = event.relatedTarget;
126
+ const nativeEvent = event.nativeEvent;
125
127
 
126
- // Hit the non-modal focus management portal guard. Focus will be
127
- // moved into the floating element immediately after.
128
- const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
128
+ // Hit the non-modal focus management portal guard. Focus will be
129
+ // moved into the floating element immediately after.
130
+ const movedToFocusGuard = isElement(relatedTarget) && relatedTarget.hasAttribute(createAttribute('focus-guard')) && relatedTarget.getAttribute('data-type') === 'outside';
129
131
 
130
- // Wait for the window blur listener to fire.
131
- timeout.start(0, () => {
132
- const domReference = store.select('domReferenceElement');
133
- const activeEl = activeElement(ownerDocument(domReference));
132
+ // Wait for the window blur listener to fire.
133
+ timeout.start(0, () => {
134
+ const domReference = store.select('domReferenceElement');
135
+ const activeEl = activeElement(ownerDocument(domReference));
134
136
 
135
- // Focus left the page, keep it open.
136
- if (!relatedTarget && activeEl === domReference) {
137
- return;
138
- }
137
+ // Focus left the page, keep it open.
138
+ if (!relatedTarget && activeEl === domReference) {
139
+ return;
140
+ }
139
141
 
140
- // When focusing the reference element (e.g. regular click), then
141
- // clicking into the floating element, prevent it from hiding.
142
- // Note: it must be focusable, e.g. `tabindex="-1"`.
143
- // We can not rely on relatedTarget to point to the correct element
144
- // as it will only point to the shadow host of the newly focused element
145
- // and not the element that actually has received focus if it is located
146
- // inside a shadow root.
147
- if (contains(dataRef.current.floatingContext?.refs.floating.current, activeEl) || contains(domReference, activeEl) || movedToFocusGuard) {
148
- return;
149
- }
142
+ // When focusing the reference element (e.g. regular click), then
143
+ // clicking into the floating element, prevent it from hiding.
144
+ // Note: it must be focusable, e.g. `tabindex="-1"`.
145
+ // We can not rely on relatedTarget to point to the correct element
146
+ // as it will only point to the shadow host of the newly focused element
147
+ // and not the element that actually has received focus if it is located
148
+ // inside a shadow root.
149
+ if (contains(dataRef.current.floatingContext?.refs.floating.current, activeEl) || contains(domReference, activeEl) || movedToFocusGuard) {
150
+ return;
151
+ }
150
152
 
151
- // If the next focused element is one of the triggers, do not close
152
- // the floating element. The focus handler of that trigger will
153
- // handle the open state.
154
- const nextFocusedElement = relatedTarget ?? activeEl;
155
- if (isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
156
- return;
157
- }
158
- store.setOpen(false, createChangeEventDetails(REASONS.triggerFocus, nativeEvent));
159
- });
160
- }
161
- }), [dataRef, store, timeout, delay]);
153
+ // If the next focused element is one of the triggers, do not close
154
+ // the floating element. The focus handler of that trigger will
155
+ // handle the open state.
156
+ const nextFocusedElement = relatedTarget ?? activeEl;
157
+ if (isTargetInsideEnabledTrigger(nextFocusedElement, store.context.triggerElements)) {
158
+ return;
159
+ }
160
+ store.setOpen(false, createChangeEventDetails(REASONS.triggerFocus, nativeEvent));
161
+ });
162
+ }
163
+ };
164
+ }, [dataRef, delay, store, timeout]);
162
165
  return React.useMemo(() => enabled ? {
163
166
  reference,
164
167
  trigger: reference
@@ -1,25 +1,31 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { isElement } from '@floating-ui/utils/dom';
5
4
  import { addEventListener } from '@base-ui/utils/addEventListener';
6
5
  import { mergeCleanups } from '@base-ui/utils/mergeCleanups';
7
- import { useTimeout } from '@base-ui/utils/useTimeout';
8
- import { useValueAsRef } from '@base-ui/utils/useValueAsRef';
9
- import { useStableCallback } from '@base-ui/utils/useStableCallback';
10
6
  import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect';
11
7
  import { ownerDocument } from '@base-ui/utils/owner';
12
- import { contains, getTarget, isInteractiveElement } from "../utils.js";
13
- import { useFloatingParentNodeId, useFloatingTree } from "../components/FloatingTree.js";
8
+ import { useStableCallback } from '@base-ui/utils/useStableCallback';
9
+ import { useTimeout } from '@base-ui/utils/useTimeout';
10
+ import { useValueAsRef } from '@base-ui/utils/useValueAsRef';
11
+ import { isElement } from '@floating-ui/utils/dom';
14
12
  import { createChangeEventDetails } from "../../internals/createBaseUIEventDetails.js";
15
13
  import { REASONS } from "../../internals/reasons.js";
16
- import { getDelay, getRestMs } from "./useHoverShared.js";
14
+ import { useFloatingParentNodeId, useFloatingTree } from "../components/FloatingTree.js";
15
+ import { contains, getTarget, isInteractiveElement } from "../utils/element.js";
16
+ import { getDelay, getRestMs, isClickLikeOpenEvent as isClickLikeOpenEventShared, isHoverOpenEvent } from "./useHoverShared.js";
17
17
  /**
18
18
  * Opens the floating element while hovering over the reference element, like
19
19
  * CSS `:hover`.
20
20
  * @see https://floating-ui.com/docs/useHover
21
21
  */
22
22
  export function useHover(context, props = {}) {
23
+ const {
24
+ delay = 0,
25
+ handleClose = null,
26
+ restMs = 0,
27
+ move = true
28
+ } = props;
23
29
  const store = 'rootStore' in context ? context.rootStore : context;
24
30
  const open = store.useState('open');
25
31
  const floatingElement = store.useState('floatingElement');
@@ -28,12 +34,6 @@ export function useHover(context, props = {}) {
28
34
  dataRef,
29
35
  events
30
36
  } = store.context;
31
- const {
32
- delay = 0,
33
- handleClose = null,
34
- restMs = 0,
35
- move = true
36
- } = props;
37
37
  const tree = useFloatingTree();
38
38
  const parentId = useFloatingParentNodeId();
39
39
  const handleCloseRef = useValueAsRef(handleClose);
@@ -41,22 +41,29 @@ export function useHover(context, props = {}) {
41
41
  const restMsRef = useValueAsRef(restMs);
42
42
  const pointerTypeRef = React.useRef(undefined);
43
43
  const interactedInsideRef = React.useRef(false);
44
- const timeout = useTimeout();
45
44
  const handlerRef = React.useRef(undefined);
46
- const restTimeout = useTimeout();
47
45
  const blockMouseMoveRef = React.useRef(true);
48
46
  const performedPointerEventsMutationRef = React.useRef(false);
49
47
  const unbindMouseMoveRef = React.useRef(() => {});
50
48
  const restTimeoutPendingRef = React.useRef(false);
49
+ const timeout = useTimeout();
50
+ const restTimeout = useTimeout();
51
51
  const isHoverOpen = useStableCallback(() => {
52
- const type = dataRef.current.openEvent?.type;
53
- return type?.includes('mouse') && type !== 'mousedown';
52
+ return isHoverOpenEvent(dataRef.current.openEvent?.type);
54
53
  });
55
54
  const isClickLikeOpenEvent = useStableCallback(() => {
56
- if (interactedInsideRef.current) {
57
- return true;
55
+ return isClickLikeOpenEventShared(dataRef.current.openEvent?.type, interactedInsideRef.current);
56
+ });
57
+ const cleanupMouseMoveHandler = useStableCallback(() => {
58
+ unbindMouseMoveRef.current();
59
+ handlerRef.current = undefined;
60
+ });
61
+ const clearPointerEvents = useStableCallback(() => {
62
+ if (performedPointerEventsMutationRef.current) {
63
+ const body = ownerDocument(floatingElement).body;
64
+ body.style.pointerEvents = '';
65
+ performedPointerEventsMutationRef.current = false;
58
66
  }
59
- return dataRef.current.openEvent ? ['click', 'mousedown'].includes(dataRef.current.openEvent.type) : false;
60
67
  });
61
68
 
62
69
  // When closing before opening, clear the delay timeouts to cancel it
@@ -93,39 +100,40 @@ export function useHover(context, props = {}) {
93
100
  const html = ownerDocument(floatingElement).documentElement;
94
101
  return addEventListener(html, 'mouseleave', onLeave);
95
102
  }, [floatingElement, open, store, handleCloseRef, isHoverOpen, isClickLikeOpenEvent]);
96
- const closeWithDelay = React.useCallback((event, runElseBranch = true) => {
97
- const closeDelay = getDelay(delayRef.current, 'close', pointerTypeRef.current);
98
- if (closeDelay && !handlerRef.current) {
99
- timeout.start(closeDelay, () => store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event)));
100
- } else if (runElseBranch) {
101
- timeout.clear();
102
- store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event));
103
- }
104
- }, [delayRef, store, timeout]);
105
- const cleanupMouseMoveHandler = useStableCallback(() => {
106
- unbindMouseMoveRef.current();
107
- handlerRef.current = undefined;
108
- });
109
- const clearPointerEvents = useStableCallback(() => {
110
- if (performedPointerEventsMutationRef.current) {
111
- const body = ownerDocument(floatingElement).body;
112
- body.style.pointerEvents = '';
113
- performedPointerEventsMutationRef.current = false;
114
- }
115
- });
116
- const handleInteractInside = useStableCallback(event => {
117
- const target = getTarget(event);
118
- if (!isInteractiveElement(target)) {
119
- interactedInsideRef.current = false;
120
- return;
121
- }
122
- interactedInsideRef.current = true;
123
- });
124
103
 
125
104
  // Registering the mouse events on the reference directly to bypass React's
126
105
  // delegation system. If the cursor was on a disabled element and then entered
127
106
  // the reference (no gap), `mouseenter` doesn't fire in the delegation system.
128
107
  React.useEffect(() => {
108
+ function closeWithDelay(event, runElseBranch = true) {
109
+ const closeDelay = getDelay(delayRef.current, 'close', pointerTypeRef.current);
110
+ if (closeDelay && !handlerRef.current) {
111
+ timeout.start(closeDelay, () => store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event)));
112
+ } else if (runElseBranch) {
113
+ timeout.clear();
114
+ store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event));
115
+ }
116
+ }
117
+ function handleInteractInside(event) {
118
+ const target = getTarget(event);
119
+ if (!isInteractiveElement(target)) {
120
+ interactedInsideRef.current = false;
121
+ return;
122
+ }
123
+ interactedInsideRef.current = true;
124
+ }
125
+ function getHandleCloseHandler(event, onClose) {
126
+ if (!handleCloseRef.current || !dataRef.current.floatingContext) {
127
+ return null;
128
+ }
129
+ return handleCloseRef.current({
130
+ ...dataRef.current.floatingContext,
131
+ tree,
132
+ x: event.clientX,
133
+ y: event.clientY,
134
+ onClose
135
+ });
136
+ }
129
137
  function onReferenceMouseEnter(event) {
130
138
  timeout.clear();
131
139
  blockMouseMoveRef.current = false;
@@ -161,25 +169,19 @@ export function useHover(context, props = {}) {
161
169
  // as it will be moved.
162
170
  return;
163
171
  }
164
- if (handleCloseRef.current && dataRef.current.floatingContext) {
172
+ const handler = getHandleCloseHandler(event, () => {
173
+ clearPointerEvents();
174
+ cleanupMouseMoveHandler();
175
+ if (!isClickLikeOpenEvent()) {
176
+ closeWithDelay(event, true);
177
+ }
178
+ });
179
+ if (handler) {
165
180
  // Prevent clearing `onScrollMouseLeave` timeout.
166
181
  if (!open) {
167
182
  timeout.clear();
168
183
  }
169
- handlerRef.current = handleCloseRef.current({
170
- ...dataRef.current.floatingContext,
171
- tree,
172
- x: event.clientX,
173
- y: event.clientY,
174
- onClose() {
175
- clearPointerEvents();
176
- cleanupMouseMoveHandler();
177
- if (!isClickLikeOpenEvent()) {
178
- closeWithDelay(event, true);
179
- }
180
- }
181
- });
182
- const handler = handlerRef.current;
184
+ handlerRef.current = handler;
183
185
  unbindMouseMoveRef.current = addEventListener(doc, 'mousemove', handler);
184
186
  return;
185
187
  }
@@ -206,19 +208,13 @@ export function useHover(context, props = {}) {
206
208
  // as it will be moved.
207
209
  return;
208
210
  }
209
- handleCloseRef.current?.({
210
- ...dataRef.current.floatingContext,
211
- tree,
212
- x: event.clientX,
213
- y: event.clientY,
214
- onClose() {
215
- clearPointerEvents();
216
- cleanupMouseMoveHandler();
217
- if (!isClickLikeOpenEvent()) {
218
- closeWithDelay(event);
219
- }
211
+ getHandleCloseHandler(event, () => {
212
+ clearPointerEvents();
213
+ cleanupMouseMoveHandler();
214
+ if (!isClickLikeOpenEvent()) {
215
+ closeWithDelay(event);
220
216
  }
221
- })(event);
217
+ })?.(event);
222
218
  }
223
219
  function onFloatingMouseEnter() {
224
220
  timeout.clear();
@@ -237,7 +233,7 @@ export function useHover(context, props = {}) {
237
233
  }), addEventListener(trigger, 'mouseenter', onReferenceMouseEnter), addEventListener(trigger, 'mouseleave', onReferenceMouseLeave), floating && addEventListener(floating, 'mouseleave', onScrollMouseLeave), floating && addEventListener(floating, 'mouseenter', onFloatingMouseEnter), floating && addEventListener(floating, 'mouseleave', onFloatingMouseLeave), floating && addEventListener(floating, 'pointerdown', handleInteractInside, true));
238
234
  }
239
235
  return undefined;
240
- }, [move, domReferenceElement, floatingElement, store, closeWithDelay, cleanupMouseMoveHandler, clearPointerEvents, open, tree, delayRef, handleCloseRef, dataRef, isClickLikeOpenEvent, restMsRef, timeout, restTimeout, handleInteractInside]);
236
+ }, [move, domReferenceElement, floatingElement, store, cleanupMouseMoveHandler, clearPointerEvents, open, tree, delayRef, handleCloseRef, dataRef, isClickLikeOpenEvent, restMsRef, timeout, restTimeout]);
241
237
 
242
238
  // Block pointer-events of every element other than the reference and floating
243
239
  // while the floating element is open and has a `handleClose` handler. Also
@@ -1,24 +1,29 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { isElement } from '@floating-ui/utils/dom';
5
4
  import { addEventListener } from '@base-ui/utils/addEventListener';
6
5
  import { mergeCleanups } from '@base-ui/utils/mergeCleanups';
7
- import { useStableCallback } from '@base-ui/utils/useStableCallback';
8
6
  import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect';
9
- import { useTimeout } from '@base-ui/utils/useTimeout';
10
7
  import { ownerDocument } from '@base-ui/utils/owner';
11
- import { contains, getTarget, isTargetInsideEnabledTrigger } from "../utils/element.js";
12
- import { getNodeChildren } from "../utils/nodes.js";
8
+ import { useStableCallback } from '@base-ui/utils/useStableCallback';
9
+ import { useTimeout } from '@base-ui/utils/useTimeout';
10
+ import { isElement } from '@floating-ui/utils/dom';
13
11
  import { createChangeEventDetails } from "../../internals/createBaseUIEventDetails.js";
14
12
  import { REASONS } from "../../internals/reasons.js";
15
13
  import { useFloatingParentNodeId, useFloatingTree } from "../components/FloatingTree.js";
14
+ import { contains, getTarget } from "../utils/element.js";
15
+ import { getNodeChildren } from "../utils/nodes.js";
16
16
  import { applySafePolygonPointerEventsMutation, clearSafePolygonPointerEventsMutation, isInteractiveElement, useHoverInteractionSharedState } from "./useHoverInteractionSharedState.js";
17
- import { getDelay, isClickLikeOpenEvent as isClickLikeOpenEventShared } from "./useHoverShared.js";
17
+ import { getDelay, isClickLikeOpenEvent as isClickLikeOpenEventShared, isHoverOpenEvent, isInsideEnabledTrigger } from "./useHoverShared.js";
18
18
  /**
19
19
  * Provides hover interactions that should be attached to the floating element.
20
20
  */
21
21
  export function useHoverFloatingInteraction(context, parameters = {}) {
22
+ const {
23
+ enabled = true,
24
+ closeDelay: closeDelayProp = 0,
25
+ nodeId: nodeIdProp
26
+ } = parameters;
22
27
  const store = 'rootStore' in context ? context.rootStore : context;
23
28
  const open = store.useState('open');
24
29
  const floatingElement = store.useState('floatingElement');
@@ -26,48 +31,19 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
26
31
  const {
27
32
  dataRef
28
33
  } = store.context;
29
- const {
30
- enabled = true,
31
- closeDelay: closeDelayProp = 0,
32
- nodeId: nodeIdProp
33
- } = parameters;
34
- const instance = useHoverInteractionSharedState(store);
35
34
  const tree = useFloatingTree();
36
35
  const parentId = useFloatingParentNodeId();
36
+ const instance = useHoverInteractionSharedState(store);
37
+ const childClosedTimeout = useTimeout();
37
38
  const isClickLikeOpenEvent = useStableCallback(() => {
38
39
  return isClickLikeOpenEventShared(dataRef.current.openEvent?.type, instance.interactedInside);
39
40
  });
40
41
  const isHoverOpen = useStableCallback(() => {
41
- const type = dataRef.current.openEvent?.type;
42
- return type?.includes('mouse') && type !== 'mousedown';
43
- });
44
- const isRelatedTargetInsideEnabledTrigger = useStableCallback(target => {
45
- return isTargetInsideEnabledTrigger(target, store.context.triggerElements);
42
+ return isHoverOpenEvent(dataRef.current.openEvent?.type);
46
43
  });
47
- const closeWithDelay = React.useCallback(event => {
48
- const closeDelay = getDelay(closeDelayProp, 'close', instance.pointerType);
49
- const close = () => {
50
- store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event));
51
- tree?.events.emit('floating.closed', event);
52
- };
53
- if (closeDelay) {
54
- instance.openChangeTimeout.start(closeDelay, close);
55
- } else {
56
- instance.openChangeTimeout.clear();
57
- close();
58
- }
59
- }, [closeDelayProp, store, instance, tree]);
60
44
  const clearPointerEvents = useStableCallback(() => {
61
45
  clearSafePolygonPointerEventsMutation(instance);
62
46
  });
63
- const handleInteractInside = useStableCallback(event => {
64
- const target = getTarget(event);
65
- if (!isInteractiveElement(target)) {
66
- instance.interactedInside = false;
67
- return;
68
- }
69
- instance.interactedInside = target?.closest('[aria-haspopup]') != null;
70
- });
71
47
  useIsoLayoutEffect(() => {
72
48
  if (!open) {
73
49
  instance.pointerType = undefined;
@@ -91,7 +67,13 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
91
67
  if (parentFloating) {
92
68
  parentFloating.style.pointerEvents = '';
93
69
  }
94
- const scopeElement = instance.handleCloseOptions?.getScope?.() ?? instance.pointerEventsScopeElement ?? parentFloating ?? ref.closest('[data-rootownerid]') ?? doc.body;
70
+
71
+ // A keep-mounted submenu can appear in the tree before it opens, so a
72
+ // cached scope or parent lookup may resolve to the submenu itself. That
73
+ // would not shield sibling items in the parent menu.
74
+ const cachedScopeElement = instance.pointerEventsScopeElement !== floatingEl ? instance.pointerEventsScopeElement : null;
75
+ const parentScopeElement = parentFloating !== floatingEl ? parentFloating : null;
76
+ const scopeElement = instance.handleCloseOptions?.getScope?.() ?? cachedScopeElement ?? parentScopeElement ?? ref.closest('[data-rootownerid]') ?? doc.body;
95
77
  applySafePolygonPointerEventsMutation(instance, {
96
78
  scopeElement,
97
79
  referenceElement: ref,
@@ -103,11 +85,34 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
103
85
  }
104
86
  return undefined;
105
87
  }, [enabled, open, domReferenceElement, floatingElement, instance, isHoverOpen, tree, parentId, clearPointerEvents]);
106
- const childClosedTimeout = useTimeout();
107
88
  React.useEffect(() => {
108
89
  if (!enabled) {
109
90
  return undefined;
110
91
  }
92
+ function hasParentChildren() {
93
+ return !!(tree && parentId && getNodeChildren(tree.nodesRef.current, parentId).length > 0);
94
+ }
95
+ function closeWithDelay(event) {
96
+ const closeDelay = getDelay(closeDelayProp, 'close', instance.pointerType);
97
+ const close = () => {
98
+ store.setOpen(false, createChangeEventDetails(REASONS.triggerHover, event));
99
+ tree?.events.emit('floating.closed', event);
100
+ };
101
+ if (closeDelay) {
102
+ instance.openChangeTimeout.start(closeDelay, close);
103
+ } else {
104
+ instance.openChangeTimeout.clear();
105
+ close();
106
+ }
107
+ }
108
+ function handleInteractInside(event) {
109
+ const target = getTarget(event);
110
+ if (!isInteractiveElement(target)) {
111
+ instance.interactedInside = false;
112
+ return;
113
+ }
114
+ instance.interactedInside = target?.closest('[aria-haspopup]') != null;
115
+ }
111
116
  function onFloatingMouseEnter() {
112
117
  instance.openChangeTimeout.clear();
113
118
  childClosedTimeout.clear();
@@ -115,11 +120,11 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
115
120
  clearPointerEvents();
116
121
  }
117
122
  function onFloatingMouseLeave(event) {
118
- if (tree && parentId && getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
123
+ if (hasParentChildren() && tree) {
119
124
  tree.events.on('floating.closed', onNodeClosed);
120
125
  return;
121
126
  }
122
- if (isRelatedTargetInsideEnabledTrigger(event.relatedTarget)) {
127
+ if (isInsideEnabledTrigger(event.relatedTarget, store.context.triggerElements)) {
123
128
  // If the mouse is leaving the reference element to another trigger, don't explicitly close the popup
124
129
  // as it will be moved.
125
130
  return;
@@ -142,7 +147,7 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
142
147
  }
143
148
  }
144
149
  function onNodeClosed(event) {
145
- if (!tree || !parentId || getNodeChildren(tree.nodesRef.current, parentId).length > 0) {
150
+ if (!tree || !parentId || hasParentChildren()) {
146
151
  return;
147
152
  }
148
153
  // Allow the mouseenter event to fire in case child was closed because mouse moved into parent.
@@ -156,5 +161,5 @@ export function useHoverFloatingInteraction(context, parameters = {}) {
156
161
  return mergeCleanups(floating && addEventListener(floating, 'mouseenter', onFloatingMouseEnter), floating && addEventListener(floating, 'mouseleave', onFloatingMouseLeave), floating && addEventListener(floating, 'pointerdown', handleInteractInside, true), () => {
157
162
  tree?.events.off('floating.closed', onNodeClosed);
158
163
  });
159
- }, [enabled, floatingElement, store, dataRef, nodeIdProp, isClickLikeOpenEvent, isRelatedTargetInsideEnabledTrigger, closeWithDelay, clearPointerEvents, handleInteractInside, instance, tree, parentId, childClosedTimeout]);
164
+ }, [enabled, floatingElement, store, dataRef, closeDelayProp, nodeIdProp, isClickLikeOpenEvent, clearPointerEvents, instance, tree, parentId, childClosedTimeout]);
160
165
  }
@@ -69,8 +69,8 @@ export function applySafePolygonPointerEventsMutation(instance, options) {
69
69
  floatingElement.style.pointerEvents = 'auto';
70
70
  }
71
71
  export function useHoverInteractionSharedState(store) {
72
- const instance = useRefWithInit(HoverInteraction.create).current;
73
72
  const data = store.context.dataRef.current;
73
+ const instance = useRefWithInit(() => data.hoverInteractionState ?? HoverInteraction.create()).current;
74
74
  if (!data.hoverInteractionState) {
75
75
  data.hoverInteractionState = instance;
76
76
  }
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
- import type { Delay, FloatingContext, FloatingRootContext } from "../types.js";
2
+ import { HTMLProps } from "../../internals/types.js";
3
3
  import type { FloatingTreeStore } from "../components/FloatingTreeStore.js";
4
+ import type { Delay, FloatingContext, FloatingRootContext } from "../types.js";
4
5
  import type { HandleClose, HandleCloseContextBase } from "./useHoverShared.js";
5
- import { HTMLProps } from "../../internals/types.js";
6
6
  export interface UseHoverReferenceInteractionProps {
7
7
  enabled?: boolean | undefined;
8
8
  handleClose?: HandleClose | null | undefined;
@@ -21,6 +21,11 @@ export interface UseHoverReferenceInteractionProps {
21
21
  triggerElementRef?: Readonly<React.RefObject<Element | null>> | undefined;
22
22
  getHandleCloseContext?: (() => HandleCloseContextBase | null) | undefined;
23
23
  isClosing?: (() => boolean) | undefined;
24
+ /**
25
+ * Called before each hover-driven open attempt (immediate, delayed, and rest-ms
26
+ * paths). Return `false` to veto; any other return value permits the open.
27
+ */
28
+ shouldOpen?: (() => boolean) | undefined;
24
29
  }
25
30
  /**
26
31
  * Provides hover interactions that should be attached to reference or trigger