@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
@@ -9,340 +9,380 @@ exports.useCollapsiblePanel = useCollapsiblePanel;
9
9
  var React = _interopRequireWildcard(require("react"));
10
10
  var _addEventListener = require("@base-ui/utils/addEventListener");
11
11
  var _useIsoLayoutEffect = require("@base-ui/utils/useIsoLayoutEffect");
12
- var _useStableCallback = require("@base-ui/utils/useStableCallback");
13
12
  var _useMergedRefs = require("@base-ui/utils/useMergedRefs");
14
- var _useOnMount = require("@base-ui/utils/useOnMount");
15
13
  var _useAnimationFrame = require("@base-ui/utils/useAnimationFrame");
14
+ var _useStableCallback = require("@base-ui/utils/useStableCallback");
15
+ var _useValueAsRef = require("@base-ui/utils/useValueAsRef");
16
16
  var _warn = require("@base-ui/utils/warn");
17
+ var _owner = require("@base-ui/utils/owner");
17
18
  var _createBaseUIEventDetails = require("../../internals/createBaseUIEventDetails");
18
19
  var _reasons = require("../../internals/reasons");
20
+ var _useOpenChangeComplete = require("../../internals/useOpenChangeComplete");
21
+ var _useAnimationsFinished = require("../../internals/useAnimationsFinished");
19
22
  var _CollapsiblePanelDataAttributes = require("./CollapsiblePanelDataAttributes");
20
- var _AccordionRootDataAttributes = require("../../accordion/root/AccordionRootDataAttributes");
23
+ const EMPTY_DIMENSIONS = {
24
+ height: undefined,
25
+ width: undefined
26
+ };
21
27
  function useCollapsiblePanel(parameters) {
22
28
  const {
23
- abortControllerRef,
24
- animationTypeRef,
25
29
  externalRef,
26
- height,
27
30
  hiddenUntilFound,
28
- keepMounted,
29
31
  id: idParam,
32
+ keepMounted,
30
33
  mounted,
31
34
  onOpenChange,
32
35
  open,
33
- panelRef,
34
- runOnceAnimationsFinish,
35
- setDimensions,
36
36
  setMounted,
37
37
  setOpen,
38
- setVisible,
39
- transitionDimensionRef,
40
- visible,
41
- width
38
+ transitionStatus
42
39
  } = parameters;
43
- const isBeforeMatchRef = React.useRef(false);
44
- const latestAnimationNameRef = React.useRef(null);
45
- const shouldCancelInitialOpenAnimationRef = React.useRef(open);
46
- const shouldCancelInitialOpenTransitionRef = React.useRef(open);
47
- const endingStyleFrame = (0, _useAnimationFrame.useAnimationFrame)();
48
-
49
- /**
50
- * When opening, the `hidden` attribute is removed immediately.
51
- * When closing, the `hidden` attribute is set after any exit animations runs.
52
- */
53
- const hidden = React.useMemo(() => {
54
- if (animationTypeRef.current === 'css-animation') {
55
- return !visible;
56
- }
57
- return !open && !mounted;
58
- }, [open, mounted, visible, animationTypeRef]);
40
+ const panelRef = React.useRef(null);
41
+ const animationTypeRef = React.useRef(null);
42
+ const [dimensions, setDimensionsUnwrapped] = React.useState(EMPTY_DIMENSIONS);
43
+ const lastMeasuredDimensionsRef = React.useRef(EMPTY_DIMENSIONS);
44
+ // `beforematch` should reveal the matched content immediately, so the next
45
+ // open cycle skips author-defined motion once and then returns to normal.
46
+ const shouldSkipNextOpenRef = React.useRef(false);
47
+ // Keyframe mount animations on initially open panels cause a visible layout
48
+ // shift during the server-rendered first paint, so suppress that first open
49
+ // lifecycle until the panel has been closed once.
50
+ const shouldPreventMountAnimationRef = React.useRef(open);
51
+ // React.Activity tears down Effects while preserving state, so revealing an
52
+ // already-open panel would otherwise replay its CSS keyframe open animation.
53
+ const shouldPreventActivityResumeAnimationRef = React.useRef(false);
54
+ // Some open paths intentionally bypass motion, but the shared root transition
55
+ // status still advances asynchronously. Override the panel to idle so its data
56
+ // attributes and dimension cleanup reflect the immediate open state.
57
+ const [forcePanelIdle, setForcePanelIdle] = React.useState(false);
58
+ const pendingTemporaryStyleRestoreRef = React.useRef(null);
59
+ const mergedPanelRef = (0, _useMergedRefs.useMergedRefs)(externalRef, panelRef);
60
+ const latestStateRef = (0, _useValueAsRef.useValueAsRef)({
61
+ mounted,
62
+ open
63
+ });
64
+ // Only used to handle panel close
65
+ const runOnceCloseAnimationsFinish = (0, _useAnimationsFinished.useAnimationsFinished)(panelRef, false, false);
66
+ const hidden = !open && !mounted;
67
+ const panelTransitionStatus = forcePanelIdle ? 'idle' : transitionStatus;
68
+ const shouldPreventOpenAnimation = open && (
69
+ // These 2 refs are safe to read in render, they are only written from committed
70
+ // layout/effect paths and gate one-shot motion suppression for the next open
71
+ // lifecycle. They intentionally expose the last committed motion snapshot.
72
+ shouldPreventMountAnimationRef.current || shouldPreventActivityResumeAnimationRef.current);
73
+ const renderedDimensions = !open && mounted &&
74
+ // These 2 refs are also safe to read in render, both hold the last committed
75
+ // animation mode and measurement. This fallback only restores a previously
76
+ // measured pixel size after the live dimensions state has been reset back to `auto`.
77
+ animationTypeRef.current === 'css-animation' && dimensions.height === undefined && dimensions.width === undefined ? lastMeasuredDimensionsRef.current : dimensions;
78
+ const shouldPersistHiddenTransitionStyles = hiddenUntilFound && hidden && animationTypeRef.current !== 'css-animation';
59
79
 
60
- /**
61
- * When `keepMounted` is `true` this runs once as soon as it exists in the DOM
62
- * regardless of initial open state.
63
- *
64
- * When `keepMounted` is `false` this runs on every mount, typically every
65
- * time it opens. If the panel is in the middle of a close transition that is
66
- * interrupted and re-opens, this won't run as the panel was not unmounted.
67
- */
68
- const handlePanelRef = (0, _useStableCallback.useStableCallback)(element => {
69
- if (!element) {
70
- return undefined;
80
+ // Most measured dimensions are reused later when CSS keyframe closes need a
81
+ // pixel size after the rendered dimensions have been reset back to `auto`.
82
+ // Passing `false` is only for clearing the current dimensions state.
83
+ const setDimensions = (0, _useStableCallback.useStableCallback)((nextDimensions, shouldCacheMeasurement = true) => {
84
+ if (shouldCacheMeasurement) {
85
+ lastMeasuredDimensionsRef.current = nextDimensions;
71
86
  }
72
- if (animationTypeRef.current == null || transitionDimensionRef.current == null) {
73
- const panelStyles = getComputedStyle(element);
74
- const hasAnimation = panelStyles.animationName !== 'none' && panelStyles.animationName !== '';
75
- const hasTransition = panelStyles.transitionDuration !== '0s' && panelStyles.transitionDuration !== '';
76
-
77
- /**
78
- * animationTypeRef is safe to read in render because it's only ever set
79
- * once here during the first render and never again.
80
- * https://react.dev/learn/referencing-values-with-refs#best-practices-for-refs
81
- */
82
- if (hasAnimation && hasTransition) {
83
- if (process.env.NODE_ENV !== 'production') {
84
- (0, _warn.warn)('CSS transitions and CSS animations both detected on Collapsible or Accordion panel.', 'Only one of either animation type should be used.');
85
- }
86
- } else if (panelStyles.animationName === 'none' && panelStyles.transitionDuration !== '0s') {
87
- animationTypeRef.current = 'css-transition';
88
- } else if (panelStyles.animationName !== 'none' && panelStyles.transitionDuration === '0s') {
89
- animationTypeRef.current = 'css-animation';
90
- } else {
91
- animationTypeRef.current = 'none';
92
- }
87
+ setDimensionsUnwrapped(nextDimensions);
88
+ });
89
+ const restorePendingTemporaryStyle = (0, _useStableCallback.useStableCallback)(() => {
90
+ pendingTemporaryStyleRestoreRef.current?.();
91
+ pendingTemporaryStyleRestoreRef.current = null;
92
+ });
93
+ const setPendingTemporaryStyleRestore = (0, _useStableCallback.useStableCallback)(restore => {
94
+ restorePendingTemporaryStyle();
95
+ pendingTemporaryStyleRestoreRef.current = () => {
96
+ pendingTemporaryStyleRestoreRef.current = null;
97
+ restore();
98
+ };
99
+ });
93
100
 
94
- /**
95
- * We need to know in advance which side is being collapsed when using CSS
96
- * transitions in order to set the value of width/height to `0px` momentarily.
97
- * Setting both to `0px` will break layout.
98
- */
99
- if (element.getAttribute(_AccordionRootDataAttributes.AccordionRootDataAttributes.orientation) === 'horizontal' || panelStyles.transitionProperty.indexOf('width') > -1) {
100
- transitionDimensionRef.current = 'width';
101
- } else {
102
- transitionDimensionRef.current = 'height';
103
- }
104
- }
105
- if (animationTypeRef.current !== 'css-transition') {
106
- return undefined;
101
+ // React.Activity unmounts Effects while preserving component state. If that
102
+ // teardown happens while an already-open keyframe panel is visible, remember
103
+ // to suppress the replayed open animation on the next committed reveal.
104
+ const markActivityResumeAnimationSuppressed = (0, _useStableCallback.useStableCallback)(() => {
105
+ if (open && mounted && animationTypeRef.current === 'css-animation') {
106
+ shouldPreventActivityResumeAnimationRef.current = true;
107
107
  }
108
- if (height === undefined || width === undefined) {
109
- setDimensions({
110
- height: element.scrollHeight,
111
- width: element.scrollWidth
112
- });
113
- if (shouldCancelInitialOpenTransitionRef.current) {
114
- element.style.setProperty('transition-duration', '0s');
115
- }
108
+ });
109
+ (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
110
+ // `forcePanelIdle` is only a temporary override for open paths that skip
111
+ // motion. Keep it active while the shared root still reports `starting`,
112
+ // then drop it once the root transition state catches up.
113
+ if (!forcePanelIdle || transitionStatus === 'starting') {
114
+ return;
116
115
  }
117
- let frame = -1;
118
- let nextFrame = -1;
119
- frame = _useAnimationFrame.AnimationFrame.request(() => {
120
- shouldCancelInitialOpenTransitionRef.current = false;
121
- nextFrame = _useAnimationFrame.AnimationFrame.request(() => {
122
- /**
123
- * This is slightly faster than another RAF and is the earliest
124
- * opportunity to remove the temporary `transition-duration: 0s` that
125
- * was applied to cancel opening transitions of initially open panels.
126
- * https://nolanlawson.com/2018/09/25/accurately-measuring-layout-on-the-web/
127
- */
128
- setTimeout(() => {
129
- element.style.removeProperty('transition-duration');
130
- });
131
- });
132
- });
116
+ setForcePanelIdle(false);
117
+ }, [forcePanelIdle, transitionStatus]);
118
+ React.useEffect(() => {
133
119
  return () => {
134
- _useAnimationFrame.AnimationFrame.cancel(frame);
135
- _useAnimationFrame.AnimationFrame.cancel(nextFrame);
120
+ markActivityResumeAnimationSuppressed();
121
+ restorePendingTemporaryStyle();
136
122
  };
137
- });
138
- const mergedPanelRef = (0, _useMergedRefs.useMergedRefs)(externalRef, panelRef, handlePanelRef);
123
+ }, [markActivityResumeAnimationSuppressed, restorePendingTemporaryStyle]);
139
124
  (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
140
- if (animationTypeRef.current !== 'css-transition') {
141
- return undefined;
142
- }
143
125
  const panel = panelRef.current;
144
126
  if (!panel) {
145
127
  return undefined;
146
128
  }
147
- let resizeFrame = -1;
148
- if (abortControllerRef.current != null) {
149
- abortControllerRef.current.abort();
150
- abortControllerRef.current = null;
129
+
130
+ // `beforematch` can temporarily force a `0s` motion duration so the matched
131
+ // content reveals immediately. Restore the authored duration before detecting
132
+ // the next close animation type, otherwise that first close is misread as
133
+ // "no motion" and the close transition or keyframe gets skipped.
134
+ if (!open && pendingTemporaryStyleRestoreRef.current) {
135
+ restorePendingTemporaryStyle();
151
136
  }
152
- if (open) {
153
- const originalLayoutStyles = {
154
- 'justify-content': panel.style.justifyContent,
155
- 'align-items': panel.style.alignItems,
156
- 'align-content': panel.style.alignContent,
157
- 'justify-items': panel.style.justifyItems
158
- };
137
+ const animationType = getAnimationType(panel, shouldPreventOpenAnimation);
138
+ animationTypeRef.current = animationType;
159
139
 
160
- /* opening */
161
- Object.keys(originalLayoutStyles).forEach(key => {
162
- panel.style.setProperty(key, 'initial', 'important');
163
- });
140
+ // Initially open keyframe panels skip their first paint animation to avoid
141
+ // layout shift, but we still need to cache the expanded size so the first
142
+ // close animation can start from pixels instead of `auto`.
143
+ if (open && transitionStatus === 'idle' && shouldPreventMountAnimationRef.current && animationType === 'css-animation') {
144
+ lastMeasuredDimensionsRef.current = getDimensions(panel);
145
+ return undefined;
146
+ }
164
147
 
165
- /**
166
- * When `keepMounted={false}` and the panel is initially closed, the very
167
- * first time it opens (not any subsequent opens) `data-starting-style` is
168
- * off or missing by a frame so we need to set it manually. Otherwise any
169
- * CSS properties expected to transition using [data-starting-style] may
170
- * be mis-timed and appear to be complete skipped.
171
- */
172
- if (!shouldCancelInitialOpenTransitionRef.current && !keepMounted) {
173
- panel.setAttribute(_CollapsiblePanelDataAttributes.CollapsiblePanelDataAttributes.startingStyle, '');
174
- }
175
- setDimensions({
176
- height: panel.scrollHeight,
177
- width: panel.scrollWidth
178
- });
179
- resizeFrame = _useAnimationFrame.AnimationFrame.request(() => {
180
- Object.entries(originalLayoutStyles).forEach(([key, value]) => {
181
- if (value === '') {
182
- panel.style.removeProperty(key);
183
- } else {
184
- panel.style.setProperty(key, value);
185
- }
186
- });
187
- });
188
- } else {
189
- if (panel.scrollHeight === 0 && panel.scrollWidth === 0) {
148
+ // Handle the opening pass: measure the expanded size and, when necessary,
149
+ // neutralize author-defined motion so the panel can open immediately.
150
+ if (open && transitionStatus === 'starting') {
151
+ // `beforematch` opens should reveal the panel immediately so find-in-page
152
+ // does not wait for the author-defined transition or animation to finish.
153
+ const skipNextOpen = shouldSkipNextOpenRef.current;
154
+ shouldSkipNextOpenRef.current = false;
155
+ if (animationType === 'none') {
156
+ setDimensions(getDimensions(panel));
157
+ setForcePanelIdle(true);
190
158
  return undefined;
191
159
  }
192
-
193
- /* closing */
194
- setDimensions({
195
- height: panel.scrollHeight,
196
- width: panel.scrollWidth
197
- });
198
- const abortController = new AbortController();
199
- abortControllerRef.current = abortController;
200
- const signal = abortController.signal;
201
- let attributeObserver = null;
202
- const endingStyleAttribute = _CollapsiblePanelDataAttributes.CollapsiblePanelDataAttributes.endingStyle;
203
-
204
- // Wait for `[data-ending-style]` to be applied.
205
- attributeObserver = new MutationObserver(mutationList => {
206
- const hasEndingStyle = mutationList.some(mutation => mutation.type === 'attributes' && mutation.attributeName === endingStyleAttribute);
207
- if (hasEndingStyle) {
208
- attributeObserver?.disconnect();
209
- attributeObserver = null;
210
- runOnceAnimationsFinish(() => {
211
- setDimensions({
212
- height: 0,
213
- width: 0
214
- });
215
- panel.style.removeProperty('content-visibility');
216
- setMounted(false);
217
- if (abortControllerRef.current === abortController) {
218
- abortControllerRef.current = null;
219
- }
220
- }, signal);
160
+ if (animationType === 'css-transition') {
161
+ const restoreLayoutStyles = resetLayoutStyles(panel);
162
+ setDimensions(getDimensions(panel));
163
+ if (!skipNextOpen) {
164
+ return restoreLayoutStyles;
221
165
  }
222
- });
223
- attributeObserver.observe(panel, {
224
- attributes: true,
225
- attributeFilter: [endingStyleAttribute]
226
- });
227
- return () => {
228
- attributeObserver?.disconnect();
229
- endingStyleFrame.cancel();
230
- if (abortControllerRef.current === abortController) {
231
- abortController.abort();
232
- abortControllerRef.current = null;
166
+ const restoreTransitionDuration = setTemporaryStyle(panel, 'transition-duration', '0s');
167
+ setPendingTemporaryStyleRestore(restoreTransitionDuration);
168
+ setForcePanelIdle(true);
169
+ return restoreLayoutStyles;
170
+ }
171
+ if (animationType === 'css-animation') {
172
+ setDimensions(getDimensions(panel));
173
+ if (!skipNextOpen) {
174
+ const restoreAnimationName = setTemporaryStyle(panel, 'animation-name', 'none');
175
+ restoreAnimationName();
176
+ return undefined;
233
177
  }
234
- };
178
+ const restoreAnimationName = setTemporaryStyle(panel, 'animation-name', 'none');
179
+ const restoreAnimationDuration = setTemporaryStyle(panel, 'animation-duration', '0s');
180
+ restoreAnimationName();
181
+ setPendingTemporaryStyleRestore(restoreAnimationDuration);
182
+ setForcePanelIdle(true);
183
+ return undefined;
184
+ }
235
185
  }
236
- return () => {
237
- _useAnimationFrame.AnimationFrame.cancel(resizeFrame);
238
- };
239
- }, [abortControllerRef, animationTypeRef, endingStyleFrame, hiddenUntilFound, keepMounted, mounted, open, panelRef, runOnceAnimationsFinish, setDimensions, setMounted]);
240
- (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
241
- if (animationTypeRef.current !== 'css-animation') {
242
- return;
186
+
187
+ // Capture the current size as soon as close is requested, before the
188
+ // deferred ending phase applies closed styles. This keeps close transitions
189
+ // starting from a measured pixel value, including interrupted opens.
190
+ if (!open && mounted && (transitionStatus === 'idle' || transitionStatus === 'starting')) {
191
+ if (animationType === 'none') {
192
+ setDimensions(EMPTY_DIMENSIONS, false);
193
+ setMounted(false);
194
+ return undefined;
195
+ }
196
+ if (animationType === 'css-animation') {
197
+ shouldPreventMountAnimationRef.current = false;
198
+ shouldPreventActivityResumeAnimationRef.current = false;
199
+ }
200
+ setDimensions(getDimensions(panel));
201
+ return undefined;
243
202
  }
244
- const panel = panelRef.current;
245
- if (!panel) {
246
- return;
203
+ if (transitionStatus !== 'ending') {
204
+ return undefined;
247
205
  }
248
- latestAnimationNameRef.current = panel.style.animationName || latestAnimationNameRef.current;
249
- panel.style.setProperty('animation-name', 'none');
250
- setDimensions({
251
- height: panel.scrollHeight,
252
- width: panel.scrollWidth
253
- });
254
- if (!shouldCancelInitialOpenAnimationRef.current && !isBeforeMatchRef.current) {
255
- panel.style.removeProperty('animation-name');
206
+ if (animationType === 'none') {
207
+ setMounted(false);
208
+ return undefined;
209
+ }
210
+ const nextDimensions = getDimensions(panel);
211
+ const hasMeasuredSize = (nextDimensions.height ?? 0) > 0 || (nextDimensions.width ?? 0) > 0;
212
+ if (!hasMeasuredSize) {
213
+ setMounted(false);
214
+ return undefined;
256
215
  }
257
- if (open) {
258
- if (abortControllerRef.current != null) {
259
- abortControllerRef.current.abort();
260
- abortControllerRef.current = null;
216
+ setDimensions(nextDimensions);
217
+ if (animationType === 'css-animation') {
218
+ const restoreAnimationName = setTemporaryStyle(panel, 'animation-name', 'none');
219
+ restoreAnimationName();
220
+ }
221
+ return undefined;
222
+ }, [mounted, open, restorePendingTemporaryStyle, setDimensions, setMounted, setPendingTemporaryStyleRestore, shouldPreventOpenAnimation, transitionStatus]);
223
+ (0, _useOpenChangeComplete.useOpenChangeComplete)({
224
+ enabled: open && mounted && panelTransitionStatus === 'idle',
225
+ open: true,
226
+ ref: panelRef,
227
+ onComplete() {
228
+ if (!open) {
229
+ return;
261
230
  }
262
- setMounted(true);
263
- setVisible(true);
264
- } else {
265
- abortControllerRef.current = new AbortController();
266
- runOnceAnimationsFinish(() => {
267
- setMounted(false);
268
- setVisible(false);
269
- abortControllerRef.current = null;
270
- }, abortControllerRef.current.signal);
231
+ setDimensions(EMPTY_DIMENSIONS, false);
271
232
  }
272
- }, [abortControllerRef, animationTypeRef, open, panelRef, runOnceAnimationsFinish, setDimensions, setMounted, setVisible, visible]);
273
- (0, _useOnMount.useOnMount)(() => {
274
- const frame = _useAnimationFrame.AnimationFrame.request(() => {
275
- shouldCancelInitialOpenAnimationRef.current = false;
276
- });
277
- return () => _useAnimationFrame.AnimationFrame.cancel(frame);
278
233
  });
279
- (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
280
- if (!hiddenUntilFound) {
234
+
235
+ // Closing panels need extra sequencing beyond `useOpenChangeComplete`.
236
+ // This passive effect runs after the `ending` render has committed, so
237
+ // `[data-ending-style]` is already present. Chrome can still register the
238
+ // exit transition one frame later when an Accordion closes one item while
239
+ // opening another, so wait one frame before watching animations.
240
+ // See https://github.com/mui/base-ui/issues/3099
241
+ React.useEffect(() => {
242
+ if (open || !mounted || panelTransitionStatus !== 'ending') {
281
243
  return undefined;
282
244
  }
283
245
  const panel = panelRef.current;
284
246
  if (!panel) {
285
247
  return undefined;
286
248
  }
287
- let frame = -1;
288
- let nextFrame = -1;
289
- if (open && isBeforeMatchRef.current) {
290
- panel.style.transitionDuration = '0s';
291
- setDimensions({
292
- height: panel.scrollHeight,
293
- width: panel.scrollWidth
294
- });
295
- frame = _useAnimationFrame.AnimationFrame.request(() => {
296
- isBeforeMatchRef.current = false;
297
- nextFrame = _useAnimationFrame.AnimationFrame.request(() => {
298
- setTimeout(() => {
299
- panel.style.removeProperty('transition-duration');
300
- });
301
- });
302
- });
249
+ const abortController = new AbortController();
250
+ let endingStyleFrame = -1;
251
+ function handleComplete() {
252
+ if (latestStateRef.current.open) {
253
+ return;
254
+ }
255
+ setMounted(false);
256
+ setDimensions(EMPTY_DIMENSIONS, false);
303
257
  }
258
+ endingStyleFrame = _useAnimationFrame.AnimationFrame.request(() => {
259
+ if (!abortController.signal.aborted) {
260
+ runOnceCloseAnimationsFinish(handleComplete, abortController.signal);
261
+ }
262
+ });
304
263
  return () => {
305
- _useAnimationFrame.AnimationFrame.cancel(frame);
306
- _useAnimationFrame.AnimationFrame.cancel(nextFrame);
264
+ _useAnimationFrame.AnimationFrame.cancel(endingStyleFrame);
265
+ abortController.abort();
307
266
  };
308
- }, [hiddenUntilFound, open, panelRef, setDimensions]);
267
+ }, [latestStateRef, mounted, open, panelTransitionStatus, runOnceCloseAnimationsFinish, setDimensions, setMounted]);
309
268
  (0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
310
269
  const panel = panelRef.current;
311
- if (panel && hiddenUntilFound && hidden) {
312
- /**
313
- * React only supports a boolean for the `hidden` attribute and forces
314
- * legit string values to booleans so we have to force it back in the DOM
315
- * when necessary: https://github.com/facebook/react/issues/24740
316
- */
317
- panel.setAttribute('hidden', 'until-found');
318
- /**
319
- * Set data-starting-style here to persist the closed styles, this is to
320
- * prevent transitions from starting when the `hidden` attribute changes
321
- * to `'until-found'` as they could have different `display` properties:
322
- * https://github.com/tailwindlabs/tailwindcss/pull/14625
323
- */
324
- if (animationTypeRef.current === 'css-transition') {
325
- panel.setAttribute(_CollapsiblePanelDataAttributes.CollapsiblePanelDataAttributes.startingStyle, '');
326
- }
270
+ if (!panel || !hiddenUntilFound || !hidden) {
271
+ return;
327
272
  }
328
- }, [hiddenUntilFound, hidden, animationTypeRef, panelRef]);
273
+
274
+ // React only supports a boolean for the `hidden` attribute and forces
275
+ // legit string values to booleans so we have to force it back in the DOM
276
+ // when necessary: https://github.com/facebook/react/issues/24740
277
+ panel.setAttribute('hidden', 'until-found');
278
+ }, [hidden, hiddenUntilFound]);
329
279
  React.useEffect(function registerBeforeMatchListener() {
330
280
  const panel = panelRef.current;
331
281
  if (!panel) {
332
282
  return undefined;
333
283
  }
334
284
  function handleBeforeMatch(event) {
335
- isBeforeMatchRef.current = true;
285
+ shouldSkipNextOpenRef.current = true;
336
286
  setOpen(true);
337
287
  onOpenChange(true, (0, _createBaseUIEventDetails.createChangeEventDetails)(_reasons.REASONS.none, event));
338
288
  }
339
289
  return (0, _addEventListener.addEventListener)(panel, 'beforematch', handleBeforeMatch);
340
- }, [onOpenChange, panelRef, setOpen]);
341
- return React.useMemo(() => ({
290
+ }, [onOpenChange, setOpen]);
291
+ const shouldRender = keepMounted || hiddenUntilFound || mounted || open;
292
+ return {
293
+ height: renderedDimensions.height,
342
294
  props: {
295
+ ...(shouldPersistHiddenTransitionStyles ? {
296
+ [_CollapsiblePanelDataAttributes.CollapsiblePanelDataAttributes.startingStyle]: ''
297
+ } : undefined),
343
298
  hidden,
344
- id: idParam,
345
- ref: mergedPanelRef
299
+ id: idParam
300
+ },
301
+ ref: mergedPanelRef,
302
+ shouldPreventOpenAnimation,
303
+ shouldRender,
304
+ transitionStatus: panelTransitionStatus,
305
+ width: renderedDimensions.width
306
+ };
307
+ }
308
+ function getDimensions(element) {
309
+ return {
310
+ height: element.scrollHeight,
311
+ width: element.scrollWidth
312
+ };
313
+ }
314
+ function getAnimationType(element, hasSuppressedMountAnimation = false) {
315
+ const panelStyles = (0, _owner.ownerWindow)(element).getComputedStyle(element);
316
+ const hasAnimation = (panelStyles.animationName.split(',').map(name => name.trim()).some(name => name !== '' && name !== 'none') || hasSuppressedMountAnimation) && hasNonZeroDuration(panelStyles.animationDuration);
317
+ const hasTransition = hasNonZeroDuration(panelStyles.transitionDuration);
318
+ if (hasAnimation && hasTransition) {
319
+ if (process.env.NODE_ENV !== 'production') {
320
+ (0, _warn.warn)('CSS transitions and CSS animations both detected on Collapsible or Accordion panel.', 'Only one of either animation type should be used.');
321
+ }
322
+ return 'css-transition';
323
+ }
324
+ if (hasTransition) {
325
+ return 'css-transition';
326
+ }
327
+ if (hasAnimation) {
328
+ return 'css-animation';
329
+ }
330
+ return 'none';
331
+ }
332
+ function hasNonZeroDuration(value) {
333
+ return value.split(',').map(part => part.trim()).some(part => part !== '' && Number.parseFloat(part) > 0);
334
+ }
335
+
336
+ /**
337
+ * Temporarily overrides an inline style property and returns a cleanup that
338
+ * restores the previous inline value and priority.
339
+ * @param element - The element whose inline style should be updated.
340
+ * @param property - The CSS property name to override.
341
+ * @param value - The temporary value to assign.
342
+ * @returns A cleanup function that restores the original inline style state.
343
+ */
344
+ function setTemporaryStyle(element, property, value) {
345
+ const previousValue = element.style.getPropertyValue(property);
346
+ const previousPriority = element.style.getPropertyPriority(property);
347
+ element.style.setProperty(property, value);
348
+ return () => {
349
+ if (previousValue === '') {
350
+ element.style.removeProperty(property);
351
+ return;
346
352
  }
347
- }), [hidden, idParam, mergedPanelRef]);
353
+ element.style.setProperty(property, previousValue, previousPriority);
354
+ };
355
+ }
356
+
357
+ /**
358
+ * Temporarily resets inline alignment styles that can distort scroll-based
359
+ * size measurements, then restores them on the next animation frame.
360
+ * @param element - The panel element being measured.
361
+ * @returns A cleanup function that cancels the scheduled restore and reapplies
362
+ * the original inline layout styles immediately.
363
+ */
364
+ function resetLayoutStyles(element) {
365
+ const originalLayoutStyles = {
366
+ 'justify-content': element.style.justifyContent,
367
+ 'align-items': element.style.alignItems,
368
+ 'align-content': element.style.alignContent,
369
+ 'justify-items': element.style.justifyItems
370
+ };
371
+ Object.keys(originalLayoutStyles).forEach(key => {
372
+ element.style.setProperty(key, 'initial', 'important');
373
+ });
374
+ function restoreLayoutStyles() {
375
+ Object.entries(originalLayoutStyles).forEach(([key, value]) => {
376
+ if (value === '') {
377
+ element.style.removeProperty(key);
378
+ return;
379
+ }
380
+ element.style.setProperty(key, value);
381
+ });
382
+ }
383
+ const frame = _useAnimationFrame.AnimationFrame.request(restoreLayoutStyles);
384
+ return () => {
385
+ _useAnimationFrame.AnimationFrame.cancel(frame);
386
+ restoreLayoutStyles();
387
+ };
348
388
  }