@jobber/components 9.9.0 → 9.10.1

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 (155) hide show
  1. package/dist/Autocomplete/index.cjs +0 -2
  2. package/dist/Autocomplete/index.mjs +0 -2
  3. package/dist/Autocomplete-cjs.js +4 -5
  4. package/dist/Autocomplete-es.js +1 -2
  5. package/dist/Card/index.cjs +1 -2
  6. package/dist/Card/index.mjs +1 -2
  7. package/dist/Chip/index.cjs +0 -2
  8. package/dist/Chip/index.mjs +0 -2
  9. package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -2
  10. package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -2
  11. package/dist/Chips/InternalChipDismissible/index.cjs +0 -2
  12. package/dist/Chips/InternalChipDismissible/index.mjs +0 -2
  13. package/dist/Chips/index.cjs +0 -2
  14. package/dist/Chips/index.mjs +0 -2
  15. package/dist/Combobox/index.cjs +2 -4
  16. package/dist/Combobox/index.mjs +2 -4
  17. package/dist/ComboboxPrimitive-cjs.js +29 -30
  18. package/dist/ComboboxPrimitive-es.js +2 -3
  19. package/dist/{ComboboxChipRemove-cjs.js → ComboboxSeparator-cjs.js} +501 -455
  20. package/dist/{ComboboxChipRemove-es.js → ComboboxSeparator-es.js} +500 -456
  21. package/dist/ConfirmationModal/index.cjs +0 -2
  22. package/dist/ConfirmationModal/index.mjs +0 -2
  23. package/dist/DataDump/index.cjs +1 -2
  24. package/dist/DataDump/index.mjs +1 -2
  25. package/dist/DataList/components/DataListActions/index.cjs +0 -2
  26. package/dist/DataList/components/DataListActions/index.mjs +0 -2
  27. package/dist/DataList/components/DataListBulkActions/index.cjs +0 -2
  28. package/dist/DataList/components/DataListBulkActions/index.mjs +0 -2
  29. package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -2
  30. package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -2
  31. package/dist/DataList/components/DataListFilters/index.cjs +0 -2
  32. package/dist/DataList/components/DataListFilters/index.mjs +0 -2
  33. package/dist/DataList/components/DataListHeader/index.cjs +0 -2
  34. package/dist/DataList/components/DataListHeader/index.mjs +0 -2
  35. package/dist/DataList/components/DataListItem/index.cjs +0 -2
  36. package/dist/DataList/components/DataListItem/index.mjs +0 -2
  37. package/dist/DataList/components/DataListItemActions/index.cjs +0 -2
  38. package/dist/DataList/components/DataListItemActions/index.mjs +0 -2
  39. package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -2
  40. package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -2
  41. package/dist/DataList/components/DataListItems/index.cjs +0 -2
  42. package/dist/DataList/components/DataListItems/index.mjs +0 -2
  43. package/dist/DataList/components/DataListLayout/index.cjs +0 -2
  44. package/dist/DataList/components/DataListLayout/index.mjs +0 -2
  45. package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -2
  46. package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -2
  47. package/dist/DataList/index.cjs +0 -2
  48. package/dist/DataList/index.mjs +0 -2
  49. package/dist/DatePicker/index.cjs +0 -2
  50. package/dist/DatePicker/index.mjs +0 -2
  51. package/dist/DatePicker-cjs.js +4 -5
  52. package/dist/DatePicker-es.js +1 -2
  53. package/dist/Dialog/index.cjs +1 -2
  54. package/dist/Dialog/index.mjs +1 -2
  55. package/dist/DrawerDescription-cjs.js +268 -99
  56. package/dist/DrawerDescription-es.js +270 -103
  57. package/dist/DrawerTitle-cjs.js +2 -6
  58. package/dist/DrawerTitle-es.js +3 -7
  59. package/dist/FieldDescription-cjs.js +184 -181
  60. package/dist/FieldDescription-es.js +187 -184
  61. package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -2
  62. package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -2
  63. package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -2
  64. package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -2
  65. package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -2
  66. package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -2
  67. package/dist/FilterPicker/index.cjs +0 -2
  68. package/dist/FilterPicker/index.mjs +0 -2
  69. package/dist/FilterPickerContent-cjs.js +4 -5
  70. package/dist/FilterPickerContent-es.js +1 -2
  71. package/dist/FormatFile/index.cjs +0 -2
  72. package/dist/FormatFile/index.mjs +0 -2
  73. package/dist/Gallery/GalleryTypes.d.ts +2 -1
  74. package/dist/Gallery/index.cjs +19 -2
  75. package/dist/Gallery/index.d.ts +1 -0
  76. package/dist/Gallery/index.mjs +19 -2
  77. package/dist/Gallery-cjs.js +5 -1
  78. package/dist/Gallery-es.js +5 -1
  79. package/dist/InputDate/index.cjs +0 -2
  80. package/dist/InputDate/index.mjs +0 -2
  81. package/dist/InputNumber/index.cjs +1 -2
  82. package/dist/InputNumber/index.mjs +1 -2
  83. package/dist/LightBox/LightBox.d.ts +12 -0
  84. package/dist/LightBox/LightBox.messages.d.ts +4 -0
  85. package/dist/LightBox/LightBox.types.d.ts +18 -0
  86. package/dist/LightBox/index.cjs +19 -2
  87. package/dist/LightBox/index.d.ts +1 -1
  88. package/dist/LightBox/index.mjs +19 -2
  89. package/dist/LightBox-cjs.js +34 -5
  90. package/dist/LightBox-es.js +34 -5
  91. package/dist/Menu/index.cjs +1 -2
  92. package/dist/Menu/index.mjs +1 -2
  93. package/dist/Menu-cjs.js +4 -5
  94. package/dist/Menu-es.js +1 -2
  95. package/dist/MenuSubmenuTrigger-cjs.js +206 -164
  96. package/dist/MenuSubmenuTrigger-es.js +194 -152
  97. package/dist/Modal/index.cjs +0 -2
  98. package/dist/Modal/index.mjs +1 -3
  99. package/dist/NumberFieldInput-cjs.js +187 -308
  100. package/dist/NumberFieldInput-es.js +187 -308
  101. package/dist/Page/index.cjs +1 -2
  102. package/dist/Page/index.mjs +1 -2
  103. package/dist/Popover/index.cjs +0 -2
  104. package/dist/Popover/index.mjs +0 -2
  105. package/dist/Popover-cjs.js +7 -8
  106. package/dist/Popover-es.js +1 -2
  107. package/dist/ScrollAreaViewport-cjs.js +747 -1093
  108. package/dist/ScrollAreaViewport-es.js +734 -1081
  109. package/dist/Select/index.cjs +1 -2
  110. package/dist/Select/index.mjs +1 -2
  111. package/dist/SelectGroupLabel-cjs.js +207 -306
  112. package/dist/SelectGroupLabel-es.js +203 -302
  113. package/dist/Tooltip/index.cjs +0 -2
  114. package/dist/Tooltip/index.mjs +0 -2
  115. package/dist/Tooltip-cjs.js +6 -7
  116. package/dist/Tooltip-es.js +1 -2
  117. package/dist/dialogReturnFocus-cjs.js +1 -1
  118. package/dist/dialogReturnFocus-es.js +2 -2
  119. package/dist/docs/Gallery/Gallery.md +8 -0
  120. package/dist/docs/LightBox/LightBox.md +17 -3
  121. package/dist/floating-ui.react-cjs.js +2557 -185
  122. package/dist/floating-ui.react-es.js +2512 -149
  123. package/dist/index.cjs +3 -4
  124. package/dist/index.mjs +3 -4
  125. package/dist/primitives/BottomSheet/index.cjs +1 -1
  126. package/dist/primitives/BottomSheet/index.mjs +1 -1
  127. package/dist/primitives/ComboboxPrimitive/index.cjs +2 -4
  128. package/dist/primitives/ComboboxPrimitive/index.mjs +2 -4
  129. package/dist/primitives/SelectPrimitive/index.cjs +0 -2
  130. package/dist/primitives/SelectPrimitive/index.mjs +0 -2
  131. package/dist/primitives/index.cjs +2 -3
  132. package/dist/primitives/index.mjs +2 -3
  133. package/dist/scrollEdges-cjs.js +1 -11
  134. package/dist/scrollEdges-es.js +1 -11
  135. package/dist/scrollable-cjs.js +58 -0
  136. package/dist/scrollable-es.js +54 -0
  137. package/dist/styles.css +21 -1
  138. package/dist/unstyledPrimitives/index.cjs +720 -478
  139. package/dist/unstyledPrimitives/index.mjs +663 -421
  140. package/dist/useCompositeListItem-cjs.js +2108 -361
  141. package/dist/useCompositeListItem-es.js +2076 -331
  142. package/dist/useLabel-cjs.js +2 -3
  143. package/dist/useLabel-es.js +2 -3
  144. package/dist/useRenderElement-cjs.js +9 -7
  145. package/dist/useRenderElement-es.js +9 -7
  146. package/dist/useScrollLock-cjs.js +819 -344
  147. package/dist/useScrollLock-es.js +732 -296
  148. package/dist/useScrollToActive-cjs.js +4 -5
  149. package/dist/useScrollToActive-es.js +1 -2
  150. package/dist/utils/meta/meta.json +1 -0
  151. package/package.json +3 -3
  152. package/dist/floating-ui.react-dom-cjs.js +0 -2103
  153. package/dist/floating-ui.react-dom-es.js +0 -2072
  154. package/dist/floating-ui.utils-cjs.js +0 -342
  155. package/dist/floating-ui.utils-es.js +0 -300
@@ -1,7 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { a as isShadowRoot, i as isHTMLElement, b as isElement, h as getComputedStyle, f as floor, g as getNodeName, c as isNode, K as getWindow, d as isLastTraversableNode, e as getParentNode, I as isOverflowElement } from './floating-ui.utils-es.js';
4
- import { a as useRefWithInit, f as formatErrorMessage, i as isReactVersionAtLeast, N as NOOP, E as EMPTY_OBJECT, u as useRenderElement, b as useMergedRefs, m as mergeProps, d as makeEventPreventable } from './useRenderElement-es.js';
3
+ import { a as useRefWithInit, i as isReactVersionAtLeast, N as NOOP, c as EMPTY_ARRAY, E as EMPTY_OBJECT, u as useRenderElement, b as useMergedRefs, f as formatErrorMessage, m as mergeProps, d as makeEventPreventable } from './useRenderElement-es.js';
5
4
  import { jsx, jsxs } from 'react/jsx-runtime';
6
5
  import * as ReactDOM from 'react-dom';
7
6
 
@@ -83,14 +82,6 @@ function serializeToDevModeString(input) {
83
82
  const noop = () => {};
84
83
  const useIsoLayoutEffect = typeof document !== 'undefined' ? React.useLayoutEffect : noop;
85
84
 
86
- function useOnFirstRender(fn) {
87
- const ref = React.useRef(true);
88
- if (ref.current) {
89
- ref.current = false;
90
- fn();
91
- }
92
- }
93
-
94
85
  /**
95
86
  * A clone of the React namespace for reading APIs that may be missing in older
96
87
  * supported React versions. Bundlers can rewrite direct `React.someNewApi`
@@ -189,87 +180,6 @@ const visuallyHiddenInput = {
189
180
  position: 'absolute'
190
181
  };
191
182
 
192
- /**
193
- * The NoOptionalParams type is a utility type that checks if a function has optional or default parameters.
194
- * If the function has optional or default parameters, it returns a string literal type with an error message.
195
- * Otherwise, it returns the original function type.
196
- *
197
- * This is used to enforce that the combiner function passed to createSelector does not have optional or default parameters,
198
- * as memoization relies on the Function.length property, which does not account for optional or default parameters.
199
- */
200
-
201
- /**
202
- * Creates a selector function that can be used to derive values from the store's state.
203
- *
204
- * The combiner function can have up to three additional parameters, but it **cannot have optional or default parameters**.
205
- *
206
- * This function accepts up to six functions and combines them into a single selector function.
207
- * The resulting selector will take the state from the combined selectors and any additional parameters required by the combiner.
208
- *
209
- * The return type of the resulting selector is determined by the return type of the combiner function.
210
- *
211
- * @example
212
- * const selector = createSelector(
213
- * (state) => state.disabled
214
- * );
215
- *
216
- * @example
217
- * const selector = createSelector(
218
- * (state) => state.disabled,
219
- * (state) => state.open,
220
- * (disabled, open) => ({ disabled, open })
221
- * );
222
- */
223
- /* eslint-disable id-denylist */
224
- const createSelector = (a, b, c, d, e, f, ...other) => {
225
- if (other.length > 0) {
226
- throw new Error(process.env.NODE_ENV !== "production" ? 'Unsupported number of selectors' : formatErrorMessage(1));
227
- }
228
- let selector;
229
- if (a && b && c && d && e && f) {
230
- selector = (state, a1, a2, a3) => {
231
- const va = a(state, a1, a2, a3);
232
- const vb = b(state, a1, a2, a3);
233
- const vc = c(state, a1, a2, a3);
234
- const vd = d(state, a1, a2, a3);
235
- const ve = e(state, a1, a2, a3);
236
- return f(va, vb, vc, vd, ve, a1, a2, a3);
237
- };
238
- } else if (a && b && c && d && e) {
239
- selector = (state, a1, a2, a3) => {
240
- const va = a(state, a1, a2, a3);
241
- const vb = b(state, a1, a2, a3);
242
- const vc = c(state, a1, a2, a3);
243
- const vd = d(state, a1, a2, a3);
244
- return e(va, vb, vc, vd, a1, a2, a3);
245
- };
246
- } else if (a && b && c && d) {
247
- selector = (state, a1, a2, a3) => {
248
- const va = a(state, a1, a2, a3);
249
- const vb = b(state, a1, a2, a3);
250
- const vc = c(state, a1, a2, a3);
251
- return d(va, vb, vc, a1, a2, a3);
252
- };
253
- } else if (a && b && c) {
254
- selector = (state, a1, a2, a3) => {
255
- const va = a(state, a1, a2, a3);
256
- const vb = b(state, a1, a2, a3);
257
- return c(va, vb, a1, a2, a3);
258
- };
259
- } else if (a && b) {
260
- selector = (state, a1, a2, a3) => {
261
- const va = a(state, a1, a2, a3);
262
- return b(va, a1, a2, a3);
263
- };
264
- } else if (a) {
265
- selector = a;
266
- } else {
267
- throw /* minify-error-disabled */new Error('Missing arguments');
268
- }
269
- return selector;
270
- };
271
- /* eslint-enable id-denylist */
272
-
273
183
  var shim = {exports: {}};
274
184
 
275
185
  var useSyncExternalStoreShim_production = {};
@@ -677,6 +587,41 @@ function getInstance() {
677
587
  function register(hook) {
678
588
  hooks.push(hook);
679
589
  }
590
+
591
+ /**
592
+ * Wraps a component function to enable performance optimizations for internal hooks.
593
+ *
594
+ * **Performance Optimization:**
595
+ * Components wrapped with `fastComponent` have access to a shared "instance" context that enables
596
+ * specialized hook implementations to batch operations and reduce overhead. The wrapper creates a
597
+ * stable instance object that persists across renders, sets it as the current context, calls
598
+ * registered hooks before and after rendering, then clears the context. The primary benefit is
599
+ * with `useStore`, where multiple store subscriptions within the same component are collapsed into
600
+ * a single `useSyncExternalStore` subscription per store, significantly reducing re-render overhead.
601
+ * This optimization is only active on React 19+; on earlier versions `useStore` falls back to a
602
+ * separate subscription per call.
603
+ *
604
+ * **Requirements:**
605
+ * - The component function should follow standard React component patterns
606
+ * - `useStore` calls must keep a stable order and count across renders, as batched hooks are
607
+ * matched by call index
608
+ * - Do not rely on the instance context outside of specialized hooks
609
+ *
610
+ * @param fn - The component function to wrap
611
+ * @returns A wrapped component with the same signature as the input function
612
+ *
613
+ * @example
614
+ * ```tsx
615
+ * // Wrapping a component to enable optimized useStore batching
616
+ * export const TooltipRoot = fastComponent(function TooltipRoot(props) {
617
+ * // These useStore calls share a single subscription
618
+ * const open = useStore(store, (state) => state.open);
619
+ * const disabled = useStore(store, (state) => state.disabled);
620
+ * const value = useStore(store, (state) => state.value);
621
+ * // ...
622
+ * });
623
+ * ```
624
+ */
680
625
  function fastComponent(fn) {
681
626
  const FastComponent = (props, forwardedRef) => {
682
627
  const instance = useRefWithInit(createInstance).current;
@@ -699,6 +644,31 @@ function fastComponent(fn) {
699
644
  FastComponent.displayName = fn.displayName || fn.name;
700
645
  return FastComponent;
701
646
  }
647
+
648
+ /**
649
+ * Wraps a component function with ref forwarding to enable performance optimizations for internal hooks.
650
+ *
651
+ * This is a convenience wrapper that combines `fastComponent` with `React.forwardRef`, enabling
652
+ * both performance optimizations and proper ref forwarding. See `fastComponent` for details on
653
+ * the performance benefits.
654
+ *
655
+ * @param fn - The component function that accepts props and a forwarded ref
656
+ * @returns A wrapped component with ref forwarding enabled
657
+ *
658
+ * @example
659
+ * ```tsx
660
+ * // Wrapping a component with ref forwarding and optimized hooks
661
+ * export const TooltipTrigger = fastComponentRef(function TooltipTrigger(
662
+ * props,
663
+ * forwardedRef
664
+ * ) {
665
+ * const store = useContext(TooltipContext);
666
+ * const open = useStore(store, (state) => state.open);
667
+ * // ... component logic with ref
668
+ * return <button ref={forwardedRef} {...props} />;
669
+ * });
670
+ * ```
671
+ */
702
672
  function fastComponentRef(fn) {
703
673
  return /*#__PURE__*/React.forwardRef(fastComponent(fn));
704
674
  }
@@ -1114,6 +1084,170 @@ class ReactStore extends Store {
1114
1084
  }
1115
1085
  }
1116
1086
 
1087
+ function hasWindow() {
1088
+ return typeof window !== 'undefined';
1089
+ }
1090
+ function getNodeName(node) {
1091
+ if (isNode(node)) {
1092
+ return (node.nodeName || '').toLowerCase();
1093
+ }
1094
+ // Mocked nodes in testing environments may not be instances of Node. By
1095
+ // returning `#document` an infinite loop won't occur.
1096
+ // https://github.com/floating-ui/floating-ui/issues/2317
1097
+ return '#document';
1098
+ }
1099
+ function getWindow(node) {
1100
+ var _node$ownerDocument;
1101
+ return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
1102
+ }
1103
+ function getDocumentElement(node) {
1104
+ var _ref;
1105
+ return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
1106
+ }
1107
+ function isNode(value) {
1108
+ if (!hasWindow()) {
1109
+ return false;
1110
+ }
1111
+ return value instanceof Node || value instanceof getWindow(value).Node;
1112
+ }
1113
+ function isElement(value) {
1114
+ if (!hasWindow()) {
1115
+ return false;
1116
+ }
1117
+ return value instanceof Element || value instanceof getWindow(value).Element;
1118
+ }
1119
+ function isHTMLElement(value) {
1120
+ if (!hasWindow()) {
1121
+ return false;
1122
+ }
1123
+ return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
1124
+ }
1125
+ function isShadowRoot(value) {
1126
+ if (!hasWindow() || typeof ShadowRoot === 'undefined') {
1127
+ return false;
1128
+ }
1129
+ return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
1130
+ }
1131
+ function isOverflowElement(element) {
1132
+ const {
1133
+ overflow,
1134
+ overflowX,
1135
+ overflowY,
1136
+ display
1137
+ } = getComputedStyle(element);
1138
+ return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';
1139
+ }
1140
+ function isTableElement(element) {
1141
+ return /^(table|td|th)$/.test(getNodeName(element));
1142
+ }
1143
+ function isTopLayer(element) {
1144
+ try {
1145
+ if (element.matches(':popover-open')) {
1146
+ return true;
1147
+ }
1148
+ } catch (_e) {
1149
+ // no-op
1150
+ }
1151
+ try {
1152
+ return element.matches(':modal');
1153
+ } catch (_e) {
1154
+ return false;
1155
+ }
1156
+ }
1157
+ const willChangeRe = /transform|translate|scale|rotate|perspective|filter/;
1158
+ const containRe = /paint|layout|strict|content/;
1159
+ const isNotNone = value => !!value && value !== 'none';
1160
+ let isWebKitValue;
1161
+ function isContainingBlock(elementOrCss) {
1162
+ const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;
1163
+
1164
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
1165
+ // https://drafts.csswg.org/css-transforms-2/#individual-transforms
1166
+ return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');
1167
+ }
1168
+ function getContainingBlock(element) {
1169
+ let currentNode = getParentNode(element);
1170
+ while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
1171
+ if (isContainingBlock(currentNode)) {
1172
+ return currentNode;
1173
+ } else if (isTopLayer(currentNode)) {
1174
+ return null;
1175
+ }
1176
+ currentNode = getParentNode(currentNode);
1177
+ }
1178
+ return null;
1179
+ }
1180
+ function isWebKit() {
1181
+ if (isWebKitValue == null) {
1182
+ isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');
1183
+ }
1184
+ return isWebKitValue;
1185
+ }
1186
+ function isLastTraversableNode(node) {
1187
+ return /^(html|body|#document)$/.test(getNodeName(node));
1188
+ }
1189
+ function getComputedStyle(element) {
1190
+ return getWindow(element).getComputedStyle(element);
1191
+ }
1192
+ function getNodeScroll(element) {
1193
+ if (isElement(element)) {
1194
+ return {
1195
+ scrollLeft: element.scrollLeft,
1196
+ scrollTop: element.scrollTop
1197
+ };
1198
+ }
1199
+ return {
1200
+ scrollLeft: element.scrollX,
1201
+ scrollTop: element.scrollY
1202
+ };
1203
+ }
1204
+ function getParentNode(node) {
1205
+ if (getNodeName(node) === 'html') {
1206
+ return node;
1207
+ }
1208
+ const result =
1209
+ // Step into the shadow DOM of the parent of a slotted node.
1210
+ node.assignedSlot ||
1211
+ // DOM Element detected.
1212
+ node.parentNode ||
1213
+ // ShadowRoot detected.
1214
+ isShadowRoot(node) && node.host ||
1215
+ // Fallback.
1216
+ getDocumentElement(node);
1217
+ return isShadowRoot(result) ? result.host : result;
1218
+ }
1219
+ function getNearestOverflowAncestor(node) {
1220
+ const parentNode = getParentNode(node);
1221
+ if (isLastTraversableNode(parentNode)) {
1222
+ return (node.ownerDocument || node).body;
1223
+ }
1224
+ if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
1225
+ return parentNode;
1226
+ }
1227
+ return getNearestOverflowAncestor(parentNode);
1228
+ }
1229
+ function getOverflowAncestors(node, list, traverseIframes) {
1230
+ var _node$ownerDocument2;
1231
+ if (list === void 0) {
1232
+ list = [];
1233
+ }
1234
+ if (traverseIframes === void 0) {
1235
+ traverseIframes = true;
1236
+ }
1237
+ const scrollableAncestor = getNearestOverflowAncestor(node);
1238
+ const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
1239
+ const win = getWindow(scrollableAncestor);
1240
+ if (isBody) {
1241
+ const frameElement = getFrameElement(win);
1242
+ return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
1243
+ } else {
1244
+ return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
1245
+ }
1246
+ }
1247
+ function getFrameElement(win) {
1248
+ return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
1249
+ }
1250
+
1117
1251
  /**
1118
1252
  * Combines multiple cleanup functions into a single cleanup function.
1119
1253
  */
@@ -1143,15 +1277,13 @@ function addEventListener(target, type, listener, options) {
1143
1277
  };
1144
1278
  }
1145
1279
 
1146
- const EMPTY$2 = [];
1147
-
1148
1280
  /**
1149
1281
  * A React.useEffect equivalent that runs once, when the component is mounted.
1150
1282
  */
1151
1283
  function useOnMount(fn) {
1152
1284
  // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- no need to put `fn` in the dependency array
1153
1285
  /* eslint-disable react-hooks/exhaustive-deps */
1154
- React.useEffect(fn, EMPTY$2);
1286
+ React.useEffect(fn, EMPTY_ARRAY);
1155
1287
  /* eslint-enable react-hooks/exhaustive-deps */
1156
1288
  }
1157
1289
 
@@ -1215,7 +1347,7 @@ class Scheduler {
1215
1347
  this.callbacksCount -= 1;
1216
1348
  }
1217
1349
  }
1218
- const scheduler = new Scheduler();
1350
+ let scheduler = new Scheduler();
1219
1351
  class AnimationFrame {
1220
1352
  static create() {
1221
1353
  return new AnimationFrame();
@@ -1655,6 +1787,138 @@ const FocusGuard = /*#__PURE__*/React.forwardRef(function FocusGuard(props, ref)
1655
1787
  });
1656
1788
  if (process.env.NODE_ENV !== "production") FocusGuard.displayName = "FocusGuard";
1657
1789
 
1790
+ /**
1791
+ * Custom positioning reference element.
1792
+ * @see https://floating-ui.com/docs/virtual-elements
1793
+ */
1794
+
1795
+ const min = Math.min;
1796
+ const max = Math.max;
1797
+ const round = Math.round;
1798
+ const floor = Math.floor;
1799
+ const createCoords = v => ({
1800
+ x: v,
1801
+ y: v
1802
+ });
1803
+ const oppositeSideMap = {
1804
+ left: 'right',
1805
+ right: 'left',
1806
+ bottom: 'top',
1807
+ top: 'bottom'
1808
+ };
1809
+ function clamp(start, value, end) {
1810
+ return max(start, min(value, end));
1811
+ }
1812
+ function evaluate(value, param) {
1813
+ return typeof value === 'function' ? value(param) : value;
1814
+ }
1815
+ function getSide(placement) {
1816
+ return placement.split('-')[0];
1817
+ }
1818
+ function getAlignment(placement) {
1819
+ return placement.split('-')[1];
1820
+ }
1821
+ function getOppositeAxis(axis) {
1822
+ return axis === 'x' ? 'y' : 'x';
1823
+ }
1824
+ function getAxisLength(axis) {
1825
+ return axis === 'y' ? 'height' : 'width';
1826
+ }
1827
+ function getSideAxis(placement) {
1828
+ const firstChar = placement[0];
1829
+ return firstChar === 't' || firstChar === 'b' ? 'y' : 'x';
1830
+ }
1831
+ function getAlignmentAxis(placement) {
1832
+ return getOppositeAxis(getSideAxis(placement));
1833
+ }
1834
+ function getAlignmentSides(placement, rects, rtl) {
1835
+ if (rtl === void 0) {
1836
+ rtl = false;
1837
+ }
1838
+ const alignment = getAlignment(placement);
1839
+ const alignmentAxis = getAlignmentAxis(placement);
1840
+ const length = getAxisLength(alignmentAxis);
1841
+ let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';
1842
+ if (rects.reference[length] > rects.floating[length]) {
1843
+ mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
1844
+ }
1845
+ return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
1846
+ }
1847
+ function getExpandedPlacements(placement) {
1848
+ const oppositePlacement = getOppositePlacement(placement);
1849
+ return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
1850
+ }
1851
+ function getOppositeAlignmentPlacement(placement) {
1852
+ return placement.includes('start') ? placement.replace('start', 'end') : placement.replace('end', 'start');
1853
+ }
1854
+ const lrPlacement = ['left', 'right'];
1855
+ const rlPlacement = ['right', 'left'];
1856
+ const tbPlacement = ['top', 'bottom'];
1857
+ const btPlacement = ['bottom', 'top'];
1858
+ function getSideList(side, isStart, rtl) {
1859
+ switch (side) {
1860
+ case 'top':
1861
+ case 'bottom':
1862
+ if (rtl) return isStart ? rlPlacement : lrPlacement;
1863
+ return isStart ? lrPlacement : rlPlacement;
1864
+ case 'left':
1865
+ case 'right':
1866
+ return isStart ? tbPlacement : btPlacement;
1867
+ default:
1868
+ return [];
1869
+ }
1870
+ }
1871
+ function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
1872
+ const alignment = getAlignment(placement);
1873
+ let list = getSideList(getSide(placement), direction === 'start', rtl);
1874
+ if (alignment) {
1875
+ list = list.map(side => side + "-" + alignment);
1876
+ if (flipAlignment) {
1877
+ list = list.concat(list.map(getOppositeAlignmentPlacement));
1878
+ }
1879
+ }
1880
+ return list;
1881
+ }
1882
+ function getOppositePlacement(placement) {
1883
+ const side = getSide(placement);
1884
+ return oppositeSideMap[side] + placement.slice(side.length);
1885
+ }
1886
+ function expandPaddingObject(padding) {
1887
+ var _padding$top, _padding$right, _padding$bottom, _padding$left;
1888
+ return {
1889
+ top: (_padding$top = padding.top) != null ? _padding$top : 0,
1890
+ right: (_padding$right = padding.right) != null ? _padding$right : 0,
1891
+ bottom: (_padding$bottom = padding.bottom) != null ? _padding$bottom : 0,
1892
+ left: (_padding$left = padding.left) != null ? _padding$left : 0
1893
+ };
1894
+ }
1895
+ function getPaddingObject(padding) {
1896
+ return typeof padding !== 'number' ? expandPaddingObject(padding) : {
1897
+ top: padding,
1898
+ right: padding,
1899
+ bottom: padding,
1900
+ left: padding
1901
+ };
1902
+ }
1903
+ function rectToClientRect(rect) {
1904
+ const {
1905
+ x,
1906
+ y,
1907
+ width,
1908
+ height
1909
+ } = rect;
1910
+ return {
1911
+ width,
1912
+ height,
1913
+ top: y,
1914
+ left: x,
1915
+ right: x + width,
1916
+ bottom: y + height,
1917
+ x,
1918
+ y
1919
+ };
1920
+ }
1921
+
1658
1922
  function isDifferentGridRow(index, cols, prevRow) {
1659
1923
  return Math.floor(index / cols) !== prevRow;
1660
1924
  }
@@ -1950,6 +2214,13 @@ function isListIndexDisabled(list, index, disabledIndices) {
1950
2214
  if (!isElementVisible(element)) {
1951
2215
  return true;
1952
2216
  }
2217
+
2218
+ // A natively disabled element can never receive focus, so it must always be
2219
+ // skipped, even when `disabledIndices` marks it as enabled. Only
2220
+ // `aria-disabled` items can be focusable-while-disabled.
2221
+ if (element.matches(':disabled')) {
2222
+ return true;
2223
+ }
1953
2224
  return !disabledIndices && (element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true');
1954
2225
  }
1955
2226
  function isHiddenByStyles(styles) {
@@ -2480,11 +2751,6 @@ function useFloatingPortalNode(props = {}) {
2480
2751
  }
2481
2752
  return;
2482
2753
  }
2483
-
2484
- // React 17 does not use React.useId().
2485
- if (uniqueId == null) {
2486
- return;
2487
- }
2488
2754
  const resolvedContainer = (containerProp && (isNode(containerProp) ? containerProp : containerProp.current)) ?? parentPortalNode ?? document.body;
2489
2755
  if (resolvedContainer == null) {
2490
2756
  if (containerRef.current) {
@@ -2499,7 +2765,7 @@ function useFloatingPortalNode(props = {}) {
2499
2765
  setPortalNode(null);
2500
2766
  setContainerElement(resolvedContainer);
2501
2767
  }
2502
- }, [containerProp, parentPortalNode, uniqueId]);
2768
+ }, [containerProp, parentPortalNode]);
2503
2769
  const portalElement = useRenderElement('div', componentProps, {
2504
2770
  ref: [ref, setPortalNodeRef],
2505
2771
  props: [{
@@ -2512,8 +2778,11 @@ function useFloatingPortalNode(props = {}) {
2512
2778
  // Another call inside `FloatingPortal`/`FloatingPortalLite` then injects the children into `portalElement`.
2513
2779
  const portalSubtree = containerElement && portalElement ? /*#__PURE__*/ReactDOM.createPortal(portalElement, containerElement) : null;
2514
2780
  return {
2515
- portalNode,
2516
- portalSubtree
2781
+ node: portalNode,
2782
+ // `id` and `render` props can override or remove the generated ID. Use the exact
2783
+ // rendered value so `aria-owns` never points at an ID absent from the DOM.
2784
+ nodeId: /*#__PURE__*/React.isValidElement(portalElement) ? portalElement.props.id : undefined,
2785
+ subtree: portalSubtree
2517
2786
  };
2518
2787
  }
2519
2788
 
@@ -2533,12 +2802,12 @@ const FloatingPortal = /*#__PURE__*/React.forwardRef(function FloatingPortal(com
2533
2802
  style,
2534
2803
  children,
2535
2804
  container,
2536
- renderGuards,
2537
2805
  ...elementProps
2538
2806
  } = componentProps;
2539
2807
  const {
2540
- portalNode,
2541
- portalSubtree
2808
+ node: portalNode,
2809
+ nodeId: portalNodeId,
2810
+ subtree: portalSubtree
2542
2811
  } = useFloatingPortalNode({
2543
2812
  container,
2544
2813
  ref: forwardedRef,
@@ -2553,7 +2822,7 @@ const FloatingPortal = /*#__PURE__*/React.forwardRef(function FloatingPortal(com
2553
2822
  const focusInsideDisabledRef = React.useRef(false);
2554
2823
  const modal = focusManagerState?.modal;
2555
2824
  const open = focusManagerState?.open;
2556
- const shouldRenderGuards = typeof renderGuards === 'boolean' ? renderGuards : !!focusManagerState && !focusManagerState.modal && focusManagerState.open && !!portalNode;
2825
+ const shouldRenderGuards = !!focusManagerState && !focusManagerState.modal && focusManagerState.open && !!portalNode;
2557
2826
 
2558
2827
  // https://codesandbox.io/s/tabbable-portal-f4tng?file=/src/TabbablePortal.tsx
2559
2828
  React.useEffect(() => {
@@ -2615,7 +2884,7 @@ const FloatingPortal = /*#__PURE__*/React.forwardRef(function FloatingPortal(com
2615
2884
  }
2616
2885
  }
2617
2886
  }), shouldRenderGuards && portalNode && /*#__PURE__*/jsx("span", {
2618
- "aria-owns": portalNode.id,
2887
+ "aria-owns": portalNodeId,
2619
2888
  style: ownerVisuallyHidden
2620
2889
  }), portalNode && /*#__PURE__*/ReactDOM.createPortal(children, portalNode), shouldRenderGuards && portalNode && /*#__PURE__*/jsx(FocusGuard, {
2621
2890
  "data-type": "outside",
@@ -2879,11 +3148,10 @@ function FloatingFocusManager(props) {
2879
3148
  } = store.context;
2880
3149
  const getNodeId = useStableCallback(() => dataRef.current.floatingContext?.nodeId);
2881
3150
  const ignoreInitialFocus = initialFocus === false;
2882
- // If the reference is a combobox and is typeable (e.g. input/textarea),
2883
- // there are different focus semantics. The guards should not be rendered, but
2884
- // aria-hidden should be applied to all nodes still. Further, the visually
2885
- // hidden dismiss button should only appear at the end of the list, not the
2886
- // start.
3151
+ // A typeable combobox reference (e.g. input/textarea) with `initialFocus={false}`
3152
+ // has different focus semantics: focus is not trapped inside the floating element,
3153
+ // so in the modal case the guards are not rendered, but `aria-hidden` is still
3154
+ // applied to the outside nodes.
2887
3155
  const isUntrappedTypeableCombobox = isTypeableCombobox(domReference) && ignoreInitialFocus;
2888
3156
  const initialFocusRef = useValueAsRef(initialFocus);
2889
3157
  const returnFocusRef = useValueAsRef(returnFocus);
@@ -2997,12 +3265,12 @@ function FloatingFocusManager(props) {
2997
3265
  const triggers = store.context.triggerElements;
2998
3266
  const insideElements = getResolvedInsideElements();
2999
3267
  const isRelatedFocusGuard = relatedTarget?.hasAttribute(createAttribute('focus-guard')) && [beforeGuardRef.current, afterGuardRef.current, portalContext?.beforeInsideRef.current, portalContext?.afterInsideRef.current, portalContext?.beforeOutsideRef.current, portalContext?.afterOutsideRef.current, resolveRef(previousFocusableElement), resolveRef(nextFocusableElement)].includes(relatedTarget);
3000
- const movedToUnrelatedNode = !(contains(domReference, relatedTarget) || contains(floating, relatedTarget) || contains(relatedTarget, floating) || contains(portalContext?.portalNode, relatedTarget) || insideElements.some(element => element === relatedTarget || contains(element, relatedTarget)) || relatedTarget != null && triggers.hasElement(relatedTarget) || triggers.hasMatchingElement(trigger => contains(trigger, relatedTarget)) || isRelatedFocusGuard || tree && (getNodeChildren(tree.nodesRef.current, nodeId).find(node => contains(node.context?.elements.floating, relatedTarget) || contains(node.context?.elements.domReference, relatedTarget)) || getNodeAncestors(tree.nodesRef.current, nodeId).find(node => [node.context?.elements.floating, getFloatingFocusElement(node.context?.elements.floating)].includes(relatedTarget) || node.context?.elements.domReference === relatedTarget)));
3268
+ const movedToUnrelatedNode = !(contains(domReference, relatedTarget) || contains(floating, relatedTarget) || contains(relatedTarget, floating) || contains(portalContext?.portalNode, relatedTarget) || insideElements.some(element => element === relatedTarget || contains(element, relatedTarget)) || triggers.hasMatchingElement(trigger => contains(trigger, relatedTarget)) || isRelatedFocusGuard || tree && (getNodeChildren(tree.nodesRef.current, nodeId).find(node => contains(node.context?.elements.floating, relatedTarget) || contains(node.context?.elements.domReference, relatedTarget)) || getNodeAncestors(tree.nodesRef.current, nodeId).find(node => [node.context?.elements.floating, getFloatingFocusElement(node.context?.elements.floating)].includes(relatedTarget) || node.context?.elements.domReference === relatedTarget)));
3001
3269
  if (currentTarget === domReference && floatingFocusElement) {
3002
3270
  handleTabIndex(floatingFocusElement);
3003
3271
  }
3004
3272
 
3005
- // Restore focus to the previous tabbable element index to prevent
3273
+ // Restore focus to the previously focused tabbable element to prevent
3006
3274
  // focus from being lost outside the floating tree.
3007
3275
  if (restoreFocus && currentTarget !== domReference && !isElementVisible(target) && activeElement(doc) === doc.body) {
3008
3276
  // Let `FloatingPortal` effect knows that focus is still inside the
@@ -3012,10 +3280,10 @@ function FloatingFocusManager(props) {
3012
3280
  // If explicitly requested to restore focus to the popup container, do not search
3013
3281
  // for the next/previous tabbable element.
3014
3282
  if (restoreFocus === 'popup') {
3015
- // If the element is removed on pointerdown, focus tries to move it,
3016
- // but since it's removed at the same time, focus gets lost as it
3017
- // happens after the .focus() call above.
3018
- // In this case, focus needs to be moved asynchronously.
3283
+ // If the focused element is removed on pointerdown, the browser
3284
+ // tries to move focus to it right after the `.focus()` call above,
3285
+ // but because it's removed in the same tick, focus is lost instead.
3286
+ // Re-focusing asynchronously (next frame) wins that race.
3019
3287
  restoreFocusFrame.request(() => {
3020
3288
  floatingFocusElement.focus();
3021
3289
  });
@@ -3097,6 +3365,8 @@ function FloatingFocusManager(props) {
3097
3365
  if (!open || disabled || !isHTMLElement(floatingFocusElement)) {
3098
3366
  return;
3099
3367
  }
3368
+ closeTypeRef.current = '';
3369
+ lastInteractionTypeRef.current = '';
3100
3370
  const doc = ownerDocument(floatingFocusElement);
3101
3371
  const previouslyFocusedElement = activeElement(doc);
3102
3372
 
@@ -3128,7 +3398,9 @@ function FloatingFocusManager(props) {
3128
3398
  }
3129
3399
  elToFocus = elToFocus || getDefaultFocusElement();
3130
3400
  const hadFocusInside = contains(floatingFocusElement, activeElement(doc));
3131
- enqueueFocus(elToFocus, {
3401
+
3402
+ // enqueueFocus returns a rAF-cancel function; we intentionally don't cancel this focus.
3403
+ void enqueueFocus(elToFocus, {
3132
3404
  preventScroll: elToFocus === floatingFocusElement,
3133
3405
  shouldFocus() {
3134
3406
  // This focus is queued on the next animation frame. If the floating element has closed
@@ -3155,13 +3427,11 @@ function FloatingFocusManager(props) {
3155
3427
  }
3156
3428
  const doc = ownerDocument(floatingFocusElement);
3157
3429
  const elementFocusedBeforeOpen = activeElement(doc);
3158
- // Only nullish interaction types represent programmatic opens. The empty
3159
- // string default is intentionally not treated as programmatic.
3430
+ // Only an explicit `null` interaction type represents a programmatic open.
3431
+ // `undefined` is normalized to `''` by the prop default, so it never reaches
3432
+ // here as nullish and is intentionally not treated as programmatic.
3160
3433
  const preferPreviousFocus = openInteractionTypeRef.current == null;
3161
3434
  addPreviouslyFocusedElement(elementFocusedBeforeOpen);
3162
-
3163
- // Dismissing via outside press should always ignore `returnFocus` to
3164
- // prevent unwanted scrolling.
3165
3435
  function onOpenChangeLocal(details) {
3166
3436
  if (!details.open) {
3167
3437
  closeTypeRef.current = getEventType(details.nativeEvent, lastInteractionTypeRef.current);
@@ -3177,6 +3447,11 @@ function FloatingFocusManager(props) {
3177
3447
  } else if (isVirtualClick(details.nativeEvent) || isVirtualPointerEvent(details.nativeEvent)) {
3178
3448
  preventReturnFocusRef.current = false;
3179
3449
  } else {
3450
+ // On outside press, only return focus to the reference when the browser supports the
3451
+ // `focus({ preventScroll })` option; without it, restoring focus scrolls the page.
3452
+ // Chrome on Android and Samsung Internet still don't support `preventScroll`
3453
+ // (https://issues.chromium.org/issues/41453122), so the runtime check keeps return
3454
+ // focus disabled there to avoid the scroll jump.
3180
3455
  let isPreventScrollSupported = false;
3181
3456
  ownerDocument(floatingFocusElement).createElement('div').focus({
3182
3457
  get preventScroll() {
@@ -3192,9 +3467,9 @@ function FloatingFocusManager(props) {
3192
3467
  }
3193
3468
  }
3194
3469
  events.on('openchange', onOpenChangeLocal);
3195
- function getReturnElement() {
3470
+ function getReturnElement(closeType) {
3196
3471
  const returnFocusValueOrFn = returnFocusRef.current;
3197
- let resolvedReturnFocusValue = typeof returnFocusValueOrFn === 'function' ? returnFocusValueOrFn(closeTypeRef.current) : returnFocusValueOrFn;
3472
+ let resolvedReturnFocusValue = typeof returnFocusValueOrFn === 'function' ? returnFocusValueOrFn(closeType) : returnFocusValueOrFn;
3198
3473
 
3199
3474
  // `null` should fallback to default behavior in case of an empty ref.
3200
3475
  if (resolvedReturnFocusValue === undefined || resolvedReturnFocusValue === false) {
@@ -3222,9 +3497,11 @@ function FloatingFocusManager(props) {
3222
3497
 
3223
3498
  // eslint-disable-next-line react-hooks/exhaustive-deps
3224
3499
  const returnFocusValueOrFn = returnFocusRef.current;
3225
- const returnElement = getReturnElement();
3500
+ const closeType = closeTypeRef.current;
3501
+ const returnElement = getReturnElement(closeType);
3226
3502
  queueMicrotask(() => {
3227
- // This is `returnElement`, if it's tabbable, or its first tabbable child.
3503
+ // `returnElement` if it is tabbable, otherwise its first tabbable child,
3504
+ // otherwise `returnElement` itself (which may not be tabbable at all).
3228
3505
  const tabbableReturnElement = getFirstTabbableElement(returnElement);
3229
3506
  const hasExplicitReturnFocus = typeof returnFocusValueOrFn !== 'boolean';
3230
3507
  if (returnFocusValueOrFn && !preventReturnFocusRef.current && isHTMLElement(tabbableReturnElement) && (
@@ -3232,9 +3509,13 @@ function FloatingFocusManager(props) {
3232
3509
  // since it likely entered a different element which should be
3233
3510
  // respected: https://github.com/floating-ui/floating-ui/issues/2607
3234
3511
  !hasExplicitReturnFocus && tabbableReturnElement !== activeEl && activeEl !== doc.body ? isFocusInsideFloatingTree : true)) {
3235
- tabbableReturnElement.focus({
3512
+ const focusOptions = {
3236
3513
  preventScroll: true
3237
- });
3514
+ };
3515
+ if (closeType === 'keyboard') {
3516
+ focusOptions.focusVisible = true;
3517
+ }
3518
+ tabbableReturnElement.focus(focusOptions);
3238
3519
  }
3239
3520
  preventReturnFocusRef.current = false;
3240
3521
  });
@@ -3257,8 +3538,8 @@ function FloatingFocusManager(props) {
3257
3538
  }
3258
3539
  }, [open, floating]);
3259
3540
 
3260
- // Synchronize the `context` & `modal` value to the FloatingPortal context.
3261
- // It will decide whether or not it needs to render its own guards.
3541
+ // Synchronize the focus manager state (modal, closeOnFocusOut, open, etc.) to the
3542
+ // FloatingPortal context, which uses it to decide whether to render its own guards.
3262
3543
  useIsoLayoutEffect(() => {
3263
3544
  if (disabled || !portalContext) {
3264
3545
  return undefined;
@@ -3293,7 +3574,8 @@ function FloatingFocusManager(props) {
3293
3574
  onFocus: event => {
3294
3575
  if (modal) {
3295
3576
  const els = getTabbableContent();
3296
- enqueueFocus(els[els.length - 1]);
3577
+ // enqueueFocus returns a rAF-cancel function we don't need here.
3578
+ void enqueueFocus(els[els.length - 1]);
3297
3579
  } else if (portalContext?.portalNode) {
3298
3580
  preventReturnFocusRef.current = false;
3299
3581
  if (isOutsideEvent(event, portalContext.portalNode)) {
@@ -3309,7 +3591,8 @@ function FloatingFocusManager(props) {
3309
3591
  ref: mergedAfterGuardRef,
3310
3592
  onFocus: event => {
3311
3593
  if (modal) {
3312
- enqueueFocus(getTabbableContent()[0]);
3594
+ // enqueueFocus returns a rAF-cancel function we don't need here.
3595
+ void enqueueFocus(getTabbableContent()[0]);
3313
3596
  } else if (portalContext?.portalNode) {
3314
3597
  if (closeOnFocusOut) {
3315
3598
  preventReturnFocusRef.current = true;
@@ -3381,7 +3664,11 @@ function useClick(context, props = {}) {
3381
3664
  }
3382
3665
  return {
3383
3666
  onPointerDown(event) {
3384
- pointerTypeRef.current = event.pointerType;
3667
+ // Screen reader activations (Android TalkBack, desktop screen readers) report a
3668
+ // mouse-like `pointerType`, but `ignoreMouse` must not drop them: hover logic cannot
3669
+ // open for a virtual press since there is no real pointer movement to wait for.
3670
+ // Virtual `touch` presses (iOS VoiceOver) keep their type so `touchOpenDelay` applies.
3671
+ pointerTypeRef.current = isMouseLikePointerType(event.pointerType, true) && isVirtualPointerEvent(event.nativeEvent) ? 'virtual' : event.pointerType;
3385
3672
  },
3386
3673
  onMouseDown(event) {
3387
3674
  const pointerType = pointerTypeRef.current;
@@ -3561,7 +3848,7 @@ function useDismiss(context, props = {}) {
3561
3848
  });
3562
3849
  React.useEffect(() => {
3563
3850
  if (!open || !enabled) {
3564
- return undefined;
3851
+ return clearInsideReactTree;
3565
3852
  }
3566
3853
  dataRef.current.__escapeKeyBubbles = escapeKeyBubbles;
3567
3854
  dataRef.current.__outsidePressBubbles = outsidePressBubbles;
@@ -3839,9 +4126,9 @@ function useDismiss(context, props = {}) {
3839
4126
  preventedPressSuppressionTimeout.clear();
3840
4127
  resetPressStartState();
3841
4128
  suppressNextOutsideClickRef.current = false;
4129
+ clearInsideReactTree();
3842
4130
  };
3843
4131
  }, [dataRef, floatingElement, escapeKey$1, outsidePressEnabled, outsidePress$1, open, enabled, escapeKeyBubbles, outsidePressBubbles, closeOnEscapeKeyDown, clearInsideReactTree, getOutsidePressEventProp, hasBlockingChild, isEventWithinOwnElements, tree, store, cancelDismissOnEndTimeout]);
3844
- React.useEffect(clearInsideReactTree, [outsidePress$1, clearInsideReactTree]);
3845
4132
  const reference = React.useMemo(() => ({
3846
4133
  onKeyDown: closeOnEscapeKeyDown,
3847
4134
  onPointerDown: closeOnReferencePress,
@@ -3875,12 +4162,12 @@ function useDismiss(context, props = {}) {
3875
4162
  }
3876
4163
 
3877
4164
  const selectors = {
3878
- open: createSelector(state => state.open),
3879
- transitionStatus: createSelector(state => state.transitionStatus),
3880
- domReferenceElement: createSelector(state => state.domReferenceElement),
3881
- referenceElement: createSelector(state => state.positionReference ?? state.referenceElement),
3882
- floatingElement: createSelector(state => state.floatingElement),
3883
- floatingId: createSelector(state => state.floatingId)
4165
+ open: state => state.open,
4166
+ transitionStatus: state => state.transitionStatus,
4167
+ domReferenceElement: state => state.domReferenceElement,
4168
+ referenceElement: state => state.positionReference ?? state.referenceElement,
4169
+ floatingElement: state => state.floatingElement,
4170
+ floatingId: state => state.floatingId
3884
4171
  };
3885
4172
  class FloatingRootStore extends ReactStore {
3886
4173
  constructor(options) {
@@ -4069,44 +4356,14 @@ function useTransitionStatus(open, enableIdleState = false, deferEndingState = f
4069
4356
  };
4070
4357
  }
4071
4358
 
4072
- let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
4073
- /**
4074
- * Present when the component is animating in.
4075
- */
4076
- TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
4077
- /**
4078
- * Present when the component is animating out.
4079
- */
4080
- TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
4081
- return TransitionStatusDataAttributes;
4082
- }({});
4083
- const STARTING_HOOK = {
4084
- [TransitionStatusDataAttributes.startingStyle]: ''
4085
- };
4086
- const ENDING_HOOK = {
4087
- [TransitionStatusDataAttributes.endingStyle]: ''
4088
- };
4089
- const transitionStatusMapping = {
4090
- transitionStatus(value) {
4091
- if (value === 'starting') {
4092
- return STARTING_HOOK;
4093
- }
4094
- if (value === 'ending') {
4095
- return ENDING_HOOK;
4096
- }
4097
- return null;
4098
- }
4099
- };
4100
-
4101
4359
  /**
4102
4360
  * Executes a function once all animations have finished on the provided element.
4361
+ * If an animation is canceled, waits for any replacement animations before executing.
4103
4362
  * @param elementOrRef - The element to watch for animations.
4104
4363
  * @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
4105
- * @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
4106
- * the function will check again if any new animations have started and wait for them to finish.
4107
4364
  * @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
4108
4365
  */
4109
- function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
4366
+ function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false) {
4110
4367
  const frame = useAnimationFrame();
4111
4368
  return useStableCallback((fnToExecute,
4112
4369
  /**
@@ -4135,23 +4392,22 @@ function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false
4135
4392
  if (!signal?.aborted) {
4136
4393
  done();
4137
4394
  }
4138
- }).catch(() => {
4139
- if (treatAbortedAsFinished) {
4140
- if (!signal?.aborted) {
4141
- done();
4142
- }
4395
+ }, () => {
4396
+ if (signal?.aborted) {
4143
4397
  return;
4144
4398
  }
4145
4399
  const currentAnimations = resolvedElement.getAnimations();
4146
- if (!signal?.aborted && currentAnimations.length > 0 && currentAnimations.some(animation => animation.pending || animation.playState !== 'finished')) {
4400
+ if (currentAnimations.some(animation => animation.pending || animation.playState !== 'finished')) {
4147
4401
  // Sometimes animations can be aborted because a property they depend on changes while the animation plays.
4148
4402
  // In such cases, we need to re-check if any new animations have started.
4149
4403
  exec();
4404
+ return;
4150
4405
  }
4406
+ done();
4151
4407
  });
4152
4408
  }
4153
4409
  if (waitForStartingStyleRemoved) {
4154
- const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle;
4410
+ const startingStyleAttribute = 'data-starting-style';
4155
4411
 
4156
4412
  // If `[data-starting-style]` isn't present, fall back to waiting one more frame
4157
4413
  // to give "open" animations a chance to be registered.
@@ -4191,7 +4447,7 @@ function useOpenChangeComplete(parameters) {
4191
4447
  onComplete: onCompleteParam
4192
4448
  } = parameters;
4193
4449
  const onComplete = useStableCallback(onCompleteParam);
4194
- const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
4450
+ const runOnceAnimationsFinish = useAnimationsFinished(ref, open);
4195
4451
  React.useEffect(() => {
4196
4452
  if (!enabled) {
4197
4453
  return undefined;
@@ -4217,14 +4473,26 @@ const FOCUSABLE_POPUP_PROPS = {
4217
4473
  function createDefaultInitialFocus(popupRef) {
4218
4474
  return interactionType => interactionType === 'touch' ? popupRef.current : true;
4219
4475
  }
4220
- function usePopupStore(externalStore, createStore, treatPopupAsFloatingElement = false) {
4476
+
4477
+ /**
4478
+ * The subset of a popup handle that a Root needs to bind its store to. Both the real handle classes
4479
+ * and any test double satisfy it.
4480
+ */
4481
+
4482
+ /**
4483
+ * Creates and owns a popup store on behalf of a Root part. The store is created exactly once, with
4484
+ * controlled props and root state synced separately after creation. Sets up the synced floating
4485
+ * root context and returns the store.
4486
+ *
4487
+ * @param createStore Factory that builds the store. Called exactly once, receiving the floating id
4488
+ * and whether the popup is nested inside another floating element, both resolved on the first render.
4489
+ * @param treatPopupAsFloatingElement Whether the popup element is passed to Floating UI as the
4490
+ * floating element instead of the default positioner.
4491
+ */
4492
+ function usePopupRootStore(createStore, treatPopupAsFloatingElement = false) {
4221
4493
  const floatingId = useId();
4222
4494
  const nested = useFloatingParentNodeId() != null;
4223
- const internalStoreRef = React.useRef(null);
4224
- if (externalStore === undefined && internalStoreRef.current === null) {
4225
- internalStoreRef.current = createStore(floatingId, nested);
4226
- }
4227
- const store = externalStore ?? internalStoreRef.current;
4495
+ const store = useRefWithInit(() => createStore(floatingId, nested)).current;
4228
4496
  useSyncedFloatingRootContext({
4229
4497
  popupStore: store,
4230
4498
  treatPopupAsFloatingElement,
@@ -4233,10 +4501,27 @@ function usePopupStore(externalStore, createStore, treatPopupAsFloatingElement =
4233
4501
  nested,
4234
4502
  onOpenChange: store.setOpen
4235
4503
  });
4236
- return {
4237
- store,
4238
- internalStore: internalStoreRef.current
4239
- };
4504
+ return store;
4505
+ }
4506
+
4507
+ /**
4508
+ * Attaches a Root's store to a handle for this component's committed lifetime. Popup Roots render
4509
+ * it before their interactions and user children so its layout effect runs before descendant layout
4510
+ * effects. This lets descendants call the handle during the Root's initial commit without attaching
4511
+ * during render, which would leak suspended or abandoned stores. Store subscribers are notified by
4512
+ * `attachStore` in this ordinary layout phase, where React permits synchronous updates.
4513
+ *
4514
+ * Popup Roots must render this component only when a handle is present so handle-less Roots avoid
4515
+ * mounting an extra fiber and layout effect.
4516
+ */
4517
+ function PopupHandleAttachment({
4518
+ handle,
4519
+ store
4520
+ }) {
4521
+ useIsoLayoutEffect(() => {
4522
+ return handle.attachStore(store);
4523
+ }, [handle, store]);
4524
+ return null;
4240
4525
  }
4241
4526
 
4242
4527
  /**
@@ -4301,19 +4586,6 @@ function attachPreventUnmountOnClose(eventDetails) {
4301
4586
  };
4302
4587
  return () => preventUnmountOnClose;
4303
4588
  }
4304
- function useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerId) {
4305
- useOnFirstRender(() => {
4306
- if (openProp === undefined && store.state.open === false && defaultOpen) {
4307
- // Avoid notifying detached trigger subscribers while the Root is rendering.
4308
- store.state = {
4309
- ...store.state,
4310
- open: true,
4311
- activeTriggerId: defaultTriggerId,
4312
- preventUnmountingOnClose: false
4313
- };
4314
- }
4315
- });
4316
- }
4317
4589
 
4318
4590
  /**
4319
4591
  * Sets up trigger data forwarding to the store.
@@ -4326,11 +4598,11 @@ function useInitialOpenSync(store, openProp, defaultOpen, defaultTriggerId) {
4326
4598
  function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpdates) {
4327
4599
  const isMountedByThisTrigger = store.useState('isMountedByTrigger', triggerId);
4328
4600
  const baseRegisterTrigger = useTriggerRegistration(triggerId, store);
4329
- const registerTrigger = useStableCallback(element => {
4330
- baseRegisterTrigger(element);
4331
- if (!element) {
4332
- return;
4333
- }
4601
+
4602
+ // Applies trigger-owned state (active-trigger ownership and payload) when the trigger registers.
4603
+ // Stable so payload/`stateUpdates` changes do not change the ref identity (which would needlessly
4604
+ // churn registration); it reads the latest closure values when invoked.
4605
+ const applyTriggerData = useStableCallback(element => {
4334
4606
  const open = store.select('open');
4335
4607
  const activeTriggerId = store.select('activeTriggerId');
4336
4608
  if (activeTriggerId === triggerId) {
@@ -4351,6 +4623,18 @@ function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpda
4351
4623
  });
4352
4624
  }
4353
4625
  });
4626
+
4627
+ // Intentionally NOT stable. Its identity is derived from `baseRegisterTrigger`, which is keyed on
4628
+ // `[store, id]`, so when a handle-backed trigger's store pointer swaps the merged ref re-fires —
4629
+ // unregistering from the previous store and registering into the new one. This lets a detached
4630
+ // trigger follow its handle's currently-attached store across attach/detach/remount. (A stable
4631
+ // callback would keep its identity and never re-fire on a store swap.)
4632
+ const registerTrigger = React.useCallback(element => {
4633
+ baseRegisterTrigger(element);
4634
+ if (element) {
4635
+ applyTriggerData(element);
4636
+ }
4637
+ }, [baseRegisterTrigger, applyTriggerData]);
4354
4638
  useIsoLayoutEffect(() => {
4355
4639
  if (isMountedByThisTrigger) {
4356
4640
  store.update({
@@ -4370,12 +4654,17 @@ function useTriggerDataForwarding(triggerId, triggerElementRef, store, stateUpda
4370
4654
  *
4371
4655
  * When a popup opens without an explicit trigger id and exactly one trigger is registered, that
4372
4656
  * trigger is claimed as the active trigger. When the active trigger id is still registered but its
4373
- * element changed, the active element is refreshed. When the active trigger unregisters, the
4374
- * default path preserves existing ownership so non-closing popup families do not silently claim a
4375
- * different trigger while staying open.
4657
+ * element changed, the active element is refreshed. When the active trigger id is missing from the
4658
+ * registry but the same element is still registered under a different id (e.g. the rendered trigger
4659
+ * carries its own DOM `id` that differs from Base UI's internal trigger id), the active id is
4660
+ * reassociated to the registered id instead of being treated as lost. When the active trigger
4661
+ * unregisters, the default path preserves existing ownership so non-closing popup families do not
4662
+ * silently claim a different trigger while staying open.
4376
4663
  *
4377
- * If `closeOnActiveTriggerUnmount` is enabled, unregistering the active trigger requests a close
4378
- * after a microtask so a same-tick replacement trigger with the same id can register first.
4664
+ * If `closeOnActiveTriggerUnmount` is enabled, unregistering a previously resolved active trigger
4665
+ * requests a close after a microtask so a same-tick replacement trigger with the same id can
4666
+ * register first. An active trigger id that has not matched a registered trigger yet is treated as
4667
+ * pending and does not request a close.
4379
4668
  *
4380
4669
  * This should be called on the Root part.
4381
4670
  *
@@ -4386,10 +4675,22 @@ function useImplicitActiveTrigger(store, options = {}) {
4386
4675
  const {
4387
4676
  closeOnActiveTriggerUnmount = false
4388
4677
  } = options;
4678
+ // Distinguishes a trigger that unmounted from a new active trigger that has not hydrated yet.
4679
+ const resolvedActiveTriggerIdRef = React.useRef(null);
4389
4680
  const open = store.useState('open');
4390
4681
  const reactiveTriggerCount = store.useState('triggerCount');
4682
+ // Subscribe to the active trigger id so the reconciliation below reruns when ownership moves to
4683
+ // another trigger while the popup stays open (e.g. a focus/hover handoff between triggers).
4684
+ const activeTriggerId = store.useState('activeTriggerId');
4685
+ // Subscribe to the active trigger element so the reconciliation reruns when a pending active
4686
+ // trigger registers in a commit where the trigger count nets out unchanged (registration
4687
+ // forwards the element to the store when the registering trigger matches the active id).
4688
+ // Without this, the id would never be marked resolved and a later genuine unmount would be
4689
+ // misclassified as pending, disabling `closeOnActiveTriggerUnmount`.
4690
+ const reactiveActiveTriggerElement = store.useState('activeTriggerElement');
4391
4691
  useIsoLayoutEffect(() => {
4392
4692
  if (!open) {
4693
+ resolvedActiveTriggerIdRef.current = null;
4393
4694
  if (store.state.triggerCount !== 0) {
4394
4695
  store.set('triggerCount', 0);
4395
4696
  }
@@ -4400,22 +4701,42 @@ function useImplicitActiveTrigger(store, options = {}) {
4400
4701
  if (store.state.triggerCount !== triggerCount) {
4401
4702
  stateUpdates.triggerCount = triggerCount;
4402
4703
  }
4403
- const activeTriggerId = store.select('activeTriggerId');
4704
+ const currentActiveTriggerId = store.select('activeTriggerId');
4404
4705
  let lostActiveTriggerId = null;
4405
- if (activeTriggerId) {
4406
- const activeTriggerElement = store.context.triggerElements.getById(activeTriggerId);
4706
+ if (currentActiveTriggerId) {
4707
+ const activeTriggerElement = store.context.triggerElements.getById(currentActiveTriggerId);
4407
4708
  if (!activeTriggerElement) {
4408
- lostActiveTriggerId = activeTriggerId;
4409
- } else if (activeTriggerElement !== store.state.activeTriggerElement) {
4410
- stateUpdates.activeTriggerElement = activeTriggerElement;
4709
+ for (const [triggerId, triggerElement] of store.context.triggerElements.entries()) {
4710
+ if (triggerElement === store.state.activeTriggerElement) {
4711
+ stateUpdates.activeTriggerId = triggerId;
4712
+ stateUpdates.activeTriggerElement = triggerElement;
4713
+ resolvedActiveTriggerIdRef.current = triggerId;
4714
+ break;
4715
+ }
4716
+ }
4717
+ if (stateUpdates.activeTriggerId === undefined) {
4718
+ if (resolvedActiveTriggerIdRef.current === currentActiveTriggerId) {
4719
+ lostActiveTriggerId = currentActiveTriggerId;
4720
+ } else {
4721
+ resolvedActiveTriggerIdRef.current = null;
4722
+ }
4723
+ }
4724
+ } else {
4725
+ resolvedActiveTriggerIdRef.current = currentActiveTriggerId;
4726
+ if (activeTriggerElement !== store.state.activeTriggerElement) {
4727
+ stateUpdates.activeTriggerElement = activeTriggerElement;
4728
+ }
4411
4729
  }
4730
+ } else {
4731
+ resolvedActiveTriggerIdRef.current = null;
4412
4732
  }
4413
- if (!lostActiveTriggerId && !activeTriggerId && triggerCount === 1) {
4733
+ if (!lostActiveTriggerId && !currentActiveTriggerId && triggerCount === 1) {
4414
4734
  const iteratorResult = store.context.triggerElements.entries().next();
4415
4735
  if (!iteratorResult.done) {
4416
4736
  const [implicitTriggerId, implicitTriggerElement] = iteratorResult.value;
4417
4737
  stateUpdates.activeTriggerId = implicitTriggerId;
4418
4738
  stateUpdates.activeTriggerElement = implicitTriggerElement;
4739
+ resolvedActiveTriggerIdRef.current = implicitTriggerId;
4419
4740
  }
4420
4741
  }
4421
4742
  if (stateUpdates.triggerCount !== undefined || stateUpdates.activeTriggerId !== undefined || stateUpdates.activeTriggerElement !== undefined) {
@@ -4440,7 +4761,7 @@ function useImplicitActiveTrigger(store, options = {}) {
4440
4761
  });
4441
4762
  }
4442
4763
  }
4443
- }, [open, store, reactiveTriggerCount, closeOnActiveTriggerUnmount]);
4764
+ }, [open, store, reactiveTriggerCount, activeTriggerId, reactiveActiveTriggerElement, closeOnActiveTriggerUnmount]);
4444
4765
  }
4445
4766
 
4446
4767
  /**
@@ -4518,13 +4839,33 @@ function usePopupRootSync(store, open) {
4518
4839
  }, [store]);
4519
4840
  }
4520
4841
 
4842
+ /**
4843
+ * Development-only reverse index of element to registered id, keyed by the owning map.
4844
+ *
4845
+ * Registration would otherwise have to scan every entry to detect an element claimed by two ids,
4846
+ * making the mount of many triggers sharing one handle quadratic. Kept module-scoped, lazily
4847
+ * initialized, and read only from `process.env.NODE_ENV` guards so production builds drop it along
4848
+ * with the checks.
4849
+ */
4850
+ let devElementIdsByMap;
4851
+ function getDevElementIds(map) {
4852
+ devElementIdsByMap ??= new WeakMap();
4853
+ let elementIds = devElementIdsByMap.get(map);
4854
+ if (!elementIds) {
4855
+ elementIds = new WeakMap();
4856
+ devElementIdsByMap.set(map, elementIds);
4857
+ }
4858
+ return elementIds;
4859
+ }
4860
+
4521
4861
  /**
4522
4862
  * Data structure to keep track of popup trigger elements by their IDs.
4523
- * Uses both a set of Elements and a map of IDs to Elements for efficient lookups.
4863
+ *
4864
+ * Element lookups iterate the id map rather than maintaining a parallel Set. Registration is O(1),
4865
+ * while `hasElement` and `hasMatchingElement` are linear in the number of triggers.
4524
4866
  */
4525
4867
  class PopupTriggerMap {
4526
4868
  constructor() {
4527
- this.elementsSet = new Set();
4528
4869
  this.idMap = new Map();
4529
4870
  }
4530
4871
 
@@ -4534,49 +4875,56 @@ class PopupTriggerMap {
4534
4875
  * Note: The provided element is assumed to not be registered under multiple IDs.
4535
4876
  */
4536
4877
  add(id, element) {
4537
- const existingElement = this.idMap.get(id);
4538
- if (existingElement === element) {
4539
- return;
4540
- }
4541
- if (existingElement !== undefined) {
4542
- // We assume that the same element won't be registered under multiple ids.
4543
- // This is safe considering how useTriggerRegistration is implemented.
4544
- this.elementsSet.delete(existingElement);
4545
- }
4546
- this.elementsSet.add(element);
4547
- this.idMap.set(id, element);
4548
4878
  if (process.env.NODE_ENV !== 'production') {
4549
- if (this.elementsSet.size !== this.idMap.size) {
4879
+ const elementIds = getDevElementIds(this);
4880
+ const existingId = elementIds.get(element);
4881
+ if (existingId !== undefined && existingId !== id) {
4550
4882
  // TODO: fix mui/no-guarded-throw
4551
4883
  // eslint-disable-next-line mui/no-guarded-throw
4552
4884
  throw new Error('Base UI: A trigger element cannot be registered under multiple IDs in PopupTriggerMap.');
4553
4885
  }
4886
+
4887
+ // Reusing an id for a different element evicts the previous one, so it must lose its claim
4888
+ // on the id or a later registration under a different id would be reported as a duplicate.
4889
+ const previousElement = this.idMap.get(id);
4890
+ if (previousElement !== undefined && previousElement !== element) {
4891
+ elementIds.delete(previousElement);
4892
+ }
4893
+ elementIds.set(element, id);
4554
4894
  }
4895
+ this.idMap.set(id, element);
4555
4896
  }
4556
4897
 
4557
4898
  /**
4558
4899
  * Removes the trigger element with the given ID.
4559
4900
  */
4560
4901
  delete(id) {
4561
- const element = this.idMap.get(id);
4562
- if (element) {
4563
- this.elementsSet.delete(element);
4564
- this.idMap.delete(id);
4902
+ if (process.env.NODE_ENV !== 'production') {
4903
+ const element = this.idMap.get(id);
4904
+ if (element !== undefined) {
4905
+ devElementIdsByMap?.get(this)?.delete(element);
4906
+ }
4565
4907
  }
4908
+ this.idMap.delete(id);
4566
4909
  }
4567
4910
 
4568
4911
  /**
4569
4912
  * Whether the given element is registered as a trigger.
4570
4913
  */
4571
4914
  hasElement(element) {
4572
- return this.elementsSet.has(element);
4915
+ for (const registered of this.idMap.values()) {
4916
+ if (registered === element) {
4917
+ return true;
4918
+ }
4919
+ }
4920
+ return false;
4573
4921
  }
4574
4922
 
4575
4923
  /**
4576
4924
  * Whether there is a registered trigger element matching the given predicate.
4577
4925
  */
4578
4926
  hasMatchingElement(predicate) {
4579
- for (const element of this.elementsSet) {
4927
+ for (const element of this.idMap.values()) {
4580
4928
  if (predicate(element)) {
4581
4929
  return true;
4582
4930
  }
@@ -4602,7 +4950,7 @@ class PopupTriggerMap {
4602
4950
  * Returns an iterable of all registered trigger elements.
4603
4951
  */
4604
4952
  elements() {
4605
- return this.elementsSet.values();
4953
+ return this.idMap.values();
4606
4954
  }
4607
4955
 
4608
4956
  /**
@@ -4662,14 +5010,11 @@ function useValueChanged(value, onChange) {
4662
5010
  const valueRef = React.useRef(value);
4663
5011
  const onChangeCallback = useStableCallback(onChange);
4664
5012
  useIsoLayoutEffect(() => {
4665
- if (valueRef.current === value) {
4666
- return;
5013
+ if (valueRef.current !== value) {
5014
+ onChangeCallback(valueRef.current);
4667
5015
  }
4668
- onChangeCallback(valueRef.current);
4669
- }, [value, onChangeCallback]);
4670
- useIsoLayoutEffect(() => {
4671
5016
  valueRef.current = value;
4672
- }, [value]);
5017
+ }, [value, onChangeCallback]);
4673
5018
  }
4674
5019
 
4675
5020
  function useOpenMethodTriggerProps(open, setOpenMethod) {
@@ -4712,9 +5057,6 @@ function useOpenInteractionType(open) {
4712
5057
  }), [openMethod, triggerProps]);
4713
5058
  }
4714
5059
 
4715
- /**
4716
- * @internal
4717
- */
4718
5060
  const DirectionContext = /*#__PURE__*/React.createContext(undefined);
4719
5061
  if (process.env.NODE_ENV !== "production") DirectionContext.displayName = "DirectionContext";
4720
5062
  function useDirection() {
@@ -4773,6 +5115,30 @@ function useFocusableWhenDisabled(parameters) {
4773
5115
  };
4774
5116
  }
4775
5117
 
5118
+ /**
5119
+ * Dispatches a constructed click on the target so it carries the source event's
5120
+ * modifier state, which `click()` always reports as unpressed. Like `click()`,
5121
+ * the untrusted click still runs native activation behavior (form submission,
5122
+ * link navigation).
5123
+ * `detail` defaults to 0 (the native convention for keyboard-generated clicks);
5124
+ * pass `detail: 1` when the click represents a mouse gesture so consumers keying
5125
+ * off `detail === 0` don't classify it as a keyboard activation.
5126
+ */
5127
+ function dispatchClickWithModifiers(target, sourceEvent, {
5128
+ detail = 0
5129
+ } = {}) {
5130
+ target.dispatchEvent(new (getWindow(target).PointerEvent)('click', {
5131
+ bubbles: true,
5132
+ cancelable: true,
5133
+ composed: true,
5134
+ detail,
5135
+ shiftKey: sourceEvent.shiftKey,
5136
+ ctrlKey: sourceEvent.ctrlKey,
5137
+ altKey: sourceEvent.altKey,
5138
+ metaKey: sourceEvent.metaKey
5139
+ }));
5140
+ }
5141
+
4776
5142
  function useButton(parameters = {}) {
4777
5143
  const {
4778
5144
  disabled = false,
@@ -4873,24 +5239,34 @@ function useButton(parameters = {}) {
4873
5239
  return;
4874
5240
  }
4875
5241
  event.preventDefault();
4876
- if (isLink || isNativeButton && isButton) {
4877
- currentTarget.click();
4878
- event.preventBaseUIHandler();
4879
- } else if (shouldClick) {
4880
- externalOnClick?.(event);
5242
+
5243
+ // Only a native-mode item that isn't a real <button> is excluded.
5244
+ if (!isNativeButton || isButton) {
4881
5245
  event.preventBaseUIHandler();
5246
+ dispatchClickWithModifiers(currentTarget, event);
4882
5247
  }
4883
5248
  return;
4884
5249
  }
4885
5250
 
4886
5251
  // Keyboard accessibility for native and non-native elements.
4887
- if (shouldClick) {
4888
- if (!isNativeButton && (isSpaceKey || isEnterKey)) {
5252
+ if (!shouldClick || isNativeButton || !isSpaceKey && !isEnterKey) {
5253
+ // Space activates links on keyup (`role="button"` semantics, matching the
5254
+ // composite path); prevent the page scroll Space would otherwise trigger.
5255
+ // Enter is left to the browser's native link activation.
5256
+ if (isCurrentTarget && isLink && isSpaceKey) {
4889
5257
  event.preventDefault();
4890
5258
  }
4891
- if (!isNativeButton && isEnterKey) {
4892
- externalOnClick?.(event);
4893
- }
5259
+ return;
5260
+ }
5261
+
5262
+ // Match native buttons: preventing the keydown's default cancels activation.
5263
+ if (event.defaultPrevented) {
5264
+ return;
5265
+ }
5266
+ event.preventDefault();
5267
+ if (isEnterKey) {
5268
+ event.preventBaseUIHandler();
5269
+ dispatchClickWithModifiers(currentTarget, event);
4894
5270
  }
4895
5271
  },
4896
5272
  onKeyUp(event) {
@@ -4910,9 +5286,14 @@ function useButton(parameters = {}) {
4910
5286
  return;
4911
5287
  }
4912
5288
 
4913
- // Keyboard accessibility for non interactive elements
4914
- if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
4915
- externalOnClick?.(event);
5289
+ // Keyboard accessibility for non interactive elements.
5290
+ // Match native buttons: preventing the keyup's default cancels Space activation.
5291
+ // Limitation: unlike a native <button>, a prevented *keydown* cannot cancel the
5292
+ // activation — no state is kept between keydown and keyup, so we can't tell
5293
+ // whether the keydown was prevented or even happened on this element.
5294
+ if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && !event.defaultPrevented && event.key === ' ') {
5295
+ event.preventBaseUIHandler();
5296
+ dispatchClickWithModifiers(event.currentTarget, event);
4916
5297
  }
4917
5298
  },
4918
5299
  onPointerDown(event) {
@@ -4941,9 +5322,38 @@ function isButtonElement(elem) {
4941
5322
  return isHTMLElement(elem) && elem.tagName === 'BUTTON';
4942
5323
  }
4943
5324
  function isValidLinkElement(elem) {
4944
- return Boolean(elem?.tagName === 'A' && elem?.href);
5325
+ return isHTMLElement(elem) && elem.tagName === 'A' && Boolean(elem.href);
4945
5326
  }
4946
5327
 
5328
+ let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
5329
+ /**
5330
+ * Present when the component begins animating in.
5331
+ */
5332
+ TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
5333
+ /**
5334
+ * Present when the component is animating out.
5335
+ */
5336
+ TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
5337
+ return TransitionStatusDataAttributes;
5338
+ }({});
5339
+ const STARTING_HOOK = {
5340
+ 'data-starting-style': ''
5341
+ };
5342
+ const ENDING_HOOK = {
5343
+ 'data-ending-style': ''
5344
+ };
5345
+ const transitionStatusMapping = {
5346
+ transitionStatus(value) {
5347
+ if (value === 'starting') {
5348
+ return STARTING_HOOK;
5349
+ }
5350
+ if (value === 'ending') {
5351
+ return ENDING_HOOK;
5352
+ }
5353
+ return null;
5354
+ }
5355
+ };
5356
+
4947
5357
  let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
4948
5358
  /**
4949
5359
  * Present when the popup is open.
@@ -4954,7 +5364,7 @@ let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
4954
5364
  */
4955
5365
  CommonPopupDataAttributes["closed"] = "data-closed";
4956
5366
  /**
4957
- * Present when the popup is animating in.
5367
+ * Present when the popup begins animating in.
4958
5368
  */
4959
5369
  CommonPopupDataAttributes[CommonPopupDataAttributes["startingStyle"] = TransitionStatusDataAttributes.startingStyle] = "startingStyle";
4960
5370
  /**
@@ -4977,32 +5387,24 @@ let CommonPopupDataAttributes = function (CommonPopupDataAttributes) {
4977
5387
  CommonPopupDataAttributes["align"] = "data-align";
4978
5388
  return CommonPopupDataAttributes;
4979
5389
  }({});
4980
- let CommonTriggerDataAttributes = /*#__PURE__*/function (CommonTriggerDataAttributes) {
4981
- /**
4982
- * Present when the popup is open.
4983
- */
4984
- CommonTriggerDataAttributes["popupOpen"] = "data-popup-open";
4985
- /**
4986
- * Present when a pressable trigger is pressed.
4987
- */
4988
- CommonTriggerDataAttributes["pressed"] = "data-pressed";
4989
- return CommonTriggerDataAttributes;
4990
- }({});
5390
+
5391
+ // Literal keys (instead of enum member references) keep the docs-only enums above
5392
+ // tree-shakeable: a runtime reference would retain the whole enum IIFE in every bundle.
4991
5393
  const TRIGGER_HOOK = {
4992
- [CommonTriggerDataAttributes.popupOpen]: ''
5394
+ 'data-popup-open': ''
4993
5395
  };
4994
5396
  const PRESSABLE_TRIGGER_HOOK = {
4995
- [CommonTriggerDataAttributes.popupOpen]: '',
4996
- [CommonTriggerDataAttributes.pressed]: ''
5397
+ 'data-popup-open': '',
5398
+ 'data-pressed': ''
4997
5399
  };
4998
5400
  const POPUP_OPEN_HOOK = {
4999
- [CommonPopupDataAttributes.open]: ''
5401
+ 'data-open': ''
5000
5402
  };
5001
5403
  const POPUP_CLOSED_HOOK = {
5002
- [CommonPopupDataAttributes.closed]: ''
5404
+ 'data-closed': ''
5003
5405
  };
5004
5406
  const ANCHOR_HIDDEN_HOOK = {
5005
- [CommonPopupDataAttributes.anchorHidden]: ''
5407
+ 'data-anchor-hidden': ''
5006
5408
  };
5007
5409
  const triggerOpenStateMapping = {
5008
5410
  open(value) {
@@ -5034,6 +5436,10 @@ const popupStateMapping = {
5034
5436
  return null;
5035
5437
  }
5036
5438
  };
5439
+ const popupTransitionStateMapping = {
5440
+ ...popupStateMapping,
5441
+ ...transitionStatusMapping
5442
+ };
5037
5443
 
5038
5444
  function inertValue(value) {
5039
5445
  if (isReactVersionAtLeast(19)) {
@@ -5075,6 +5481,15 @@ if (process.env.NODE_ENV !== "production") InternalBackdrop.displayName = "Inter
5075
5481
  let originalHtmlStyles = {};
5076
5482
  let originalBodyStyles = {};
5077
5483
  let originalHtmlScrollBehavior = '';
5484
+
5485
+ // The viewport's overflow comes from <html> when it establishes its own scroll container, and
5486
+ // propagates from <body> otherwise. An `overflow` style on the other element doesn't lock the page.
5487
+ function getViewportScroller(html, body) {
5488
+ return isOverflowElement(html) ? html : body;
5489
+ }
5490
+ function isPageScrollLocked(win, html, body) {
5491
+ return /hidden|clip/.test(win.getComputedStyle(getViewportScroller(html, body)).overflowY);
5492
+ }
5078
5493
  function hasInsetScrollbars(referenceElement) {
5079
5494
  if (typeof document === 'undefined') {
5080
5495
  return false;
@@ -5091,7 +5506,7 @@ function supportsStableScrollbarGutter(referenceElement) {
5091
5506
  const doc = ownerDocument(referenceElement);
5092
5507
  const html = doc.documentElement;
5093
5508
  const body = doc.body;
5094
- const scrollContainer = isOverflowElement(html) ? html : body;
5509
+ const scrollContainer = getViewportScroller(html, body);
5095
5510
  const originalScrollContainerOverflowY = scrollContainer.style.overflowY;
5096
5511
  const originalHtmlStyleGutter = html.style.scrollbarGutter;
5097
5512
  html.style.scrollbarGutter = 'stable';
@@ -5112,7 +5527,7 @@ function preventScrollOverlayScrollbars(referenceElement) {
5112
5527
  // won't have any effect.
5113
5528
  // But if <body> has an `overflow` style (like `overflow-x: hidden`), we need to lock it
5114
5529
  // instead, as sticky elements shift otherwise.
5115
- const elementToLock = isOverflowElement(html) ? html : body;
5530
+ const elementToLock = getViewportScroller(html, body);
5116
5531
  const originalElementToLockStyles = {
5117
5532
  overflowY: elementToLock.style.overflowY,
5118
5533
  overflowX: elementToLock.style.overflowX
@@ -5177,7 +5592,7 @@ function preventScrollInsetScrollbars(referenceElement) {
5177
5592
  // with whitespace. Warn if <body> has margins?
5178
5593
  const marginY = parseFloat(bodyStyles.marginTop) + parseFloat(bodyStyles.marginBottom);
5179
5594
  const marginX = parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight);
5180
- const elementToLock = isOverflowElement(html) ? html : body;
5595
+ const elementToLock = getViewportScroller(html, body);
5181
5596
  updateGutterOnly = supportsStableScrollbarGutter(referenceElement);
5182
5597
 
5183
5598
  /*
@@ -5207,7 +5622,9 @@ function preventScrollInsetScrollbars(referenceElement) {
5207
5622
  height: marginY || scrollbarHeight ? `calc(100dvh - ${marginY + scrollbarHeight}px)` : '100dvh',
5208
5623
  width: marginX || scrollbarWidth ? `calc(100vw - ${marginX + scrollbarWidth}px)` : '100vw',
5209
5624
  boxSizing: 'border-box',
5210
- overflow: 'hidden',
5625
+ // Assign the longhands that `cleanup` restores, so nothing is left behind.
5626
+ overflowY: 'hidden',
5627
+ overflowX: 'hidden',
5211
5628
  scrollBehavior: 'unset'
5212
5629
  });
5213
5630
  body.scrollTop = scrollTop;
@@ -5272,11 +5689,30 @@ class ScrollLocker {
5272
5689
  }
5273
5690
  const doc = ownerDocument(referenceElement);
5274
5691
  const html = doc.documentElement;
5275
- const htmlOverflowY = getWindow(html).getComputedStyle(html).overflowY;
5692
+ const body = doc.body;
5693
+ const win = getWindow(html);
5694
+
5695
+ // The page is already locked, either by the site author or by a non-Base UI overlay that
5696
+ // hasn't cleaned up yet. Leave it alone and wait for the lock to clear before taking over,
5697
+ // otherwise we'd snapshot the locked state and restore it after our own lock is released.
5698
+ if (isPageScrollLocked(win, html, body)) {
5699
+ const observer = new win.MutationObserver(() => {
5700
+ if (isPageScrollLocked(win, html, body)) {
5701
+ return;
5702
+ }
5703
+ observer.disconnect();
5704
+ this.restore = null;
5705
+ this.lock(referenceElement);
5706
+ });
5276
5707
 
5277
- // If the site author already hid overflow on <html>, respect it and bail out.
5278
- if (htmlOverflowY === 'hidden' || htmlOverflowY === 'clip') {
5279
- this.restore = NOOP;
5708
+ // Watch every attribute: locks are applied through inline styles, classes, or attributes
5709
+ // paired with a stylesheet (`data-scroll-locked` in react-remove-scroll, for example).
5710
+ const options = {
5711
+ attributes: true
5712
+ };
5713
+ observer.observe(html, options);
5714
+ observer.observe(body, options);
5715
+ this.restore = () => observer.disconnect();
5280
5716
  return;
5281
5717
  }
5282
5718
  const hasOverlayScrollbars = ios || !hasInsetScrollbars(referenceElement);
@@ -5307,4 +5743,4 @@ function useScrollLock(enabled = true, referenceElement = null) {
5307
5743
  }, [enabled, referenceElement]);
5308
5744
  }
5309
5745
 
5310
- export { cancelOpen as $, inputBlur as A, inputPaste as B, CommonPopupDataAttributes as C, activeElement as D, createGenericEventDetails as E, FOCUSABLE_POPUP_PROPS as F, wheel as G, useOnMount as H, incrementPress as I, decrementPress as J, useValueChanged as K, stopEvent as L, keyboard as M, createSelector as N, useOpenInteractionType as O, useStore as P, useClick as Q, useDismiss as R, SafeReact as S, Timeout as T, useOnFirstRender as U, Store as V, focusOut as W, outsidePress as X, pressableTriggerOpenStateMapping as Y, getFloatingFocusElement as Z, contains as _, useIsoLayoutEffect as a, getTabbableBeforeElement as a$, FloatingPortal as a0, InternalBackdrop as a1, inertValue as a2, DROPDOWN_COLLISION_AVOIDANCE as a3, useDirection as a4, useAnimationFrame as a5, webkit as a6, windowResize as a7, isVirtualClick as a8, itemPress as a9, isTargetInsideEnabledTrigger as aA, triggerFocus as aB, createAttribute as aC, mac as aD, triggerPress as aE, escapeKey as aF, isInteractiveElement as aG, getNodeChildren as aH, triggerHover as aI, useAnimationsFinished as aJ, POPUP_COLLISION_AVOIDANCE as aK, FloatingNode as aL, siblingOpen as aM, ReactStore as aN, FloatingTreeStore as aO, fastComponent as aP, useInitialOpenSync as aQ, useFloatingNodeId as aR, useImplicitActiveTrigger as aS, useOpenStateTransitions as aT, attachPreventUnmountOnClose as aU, setPopupOpenState as aV, useSyncedFloatingRootContext as aW, TYPEAHEAD_RESET_MS as aX, usePopupInteractionProps as aY, FloatingTree as aZ, useCompositeRootContext as a_, useId as aa, useFloatingParentNodeId as ab, FloatingRootStore as ac, PopupTriggerMap as ad, useFloatingTree as ae, isTypeableCombobox as af, isIndexOutOfListBounds as ag, getMinListIndex as ah, getMaxListIndex as ai, listNavigation as aj, findNonDisabledListIndex as ak, enqueueFocus as al, isVirtualPointerEvent as am, ARROW_UP as an, ARROW_DOWN as ao, ARROW_LEFT as ap, ARROW_RIGHT as aq, isListIndexDisabled as ar, isElementVisible as as, jsdom as at, DISABLED_TRANSITIONS_STYLE as au, useScrollLock as av, isMouseLikePointerType as aw, mergeCleanups as ax, isTypeableElement as ay, matchesFocusVisible as az, useStableCallback as b, isOutsideEvent as b0, getTabbableAfterElement as b1, getNextTabbable as b2, fastComponentRef as b3, useTriggerDataForwarding as b4, FocusGuard as b5, PATIENT_CLICK_THRESHOLD as b6, useTriggerRegistration as b7, triggerOpenStateMapping as b8, usePopupRootSync as b9, usePopupStore as ba, useOpenMethodTriggerProps as bb, CLICK_TRIGGER_IDENTIFIER as bc, android as bd, closeWatcher as be, BASE_UI_SWIPE_IGNORE_SELECTOR as bf, TransitionStatusDataAttributes as bg, swipe as bh, getGridNavigatedIndex as bi, inputPress as bj, gecko as bk, clearPress as bl, chipRemovePress as bm, pointer as bn, scrub as bo, useButton as c, createChangeEventDetails as d, closePress as e, useOpenChangeComplete as f, getTarget as g, createDefaultInitialFocus as h, FloatingFocusManager as i, imperativeAction as j, useTimeout as k, error as l, useTransitionStatus as m, useControlled as n, ownerDocument as o, popupStateMapping as p, useValueAsRef as q, ios as r, addEventListener as s, transitionStatusMapping as t, useBaseUiId as u, none as v, visuallyHiddenInput as w, visuallyHidden as x, inputChange as y, inputClear as z };
5746
+ export { getFloatingFocusElement as $, AnimationFrame as A, visuallyHiddenInput as B, visuallyHidden as C, activeElement as D, wheel as E, FOCUSABLE_POPUP_PROPS as F, createGenericEventDetails as G, useOnMount as H, getWindow as I, incrementPress as J, decrementPress as K, useValueChanged as L, inputClear as M, inputBlur as N, inputChange as O, keyboard as P, inputPaste as Q, useOpenInteractionType as R, SafeReact as S, Timeout as T, useStore as U, useClick as V, useDismiss as W, ReactStore as X, focusOut as Y, outsidePress as Z, pressableTriggerOpenStateMapping as _, isLastTraversableNode as a, isListIndexDisabled as a$, contains as a0, cancelOpen as a1, FloatingPortal as a2, InternalBackdrop as a3, inertValue as a4, DROPDOWN_COLLISION_AVOIDANCE as a5, popupStateMapping as a6, useDirection as a7, useAnimationFrame as a8, webkit as a9, getNodeScroll as aA, isTableElement as aB, isContainingBlock as aC, getContainingBlock as aD, getOverflowAncestors as aE, getFrameElement as aF, isWebKit as aG, floor as aH, useId as aI, useFloatingParentNodeId as aJ, FloatingRootStore as aK, PopupTriggerMap as aL, useFloatingTree as aM, isTypeableCombobox as aN, isIndexOutOfListBounds as aO, getMinListIndex as aP, getMaxListIndex as aQ, stopEvent as aR, listNavigation as aS, findNonDisabledListIndex as aT, enqueueFocus as aU, isVirtualPointerEvent as aV, ARROW_UP as aW, ARROW_DOWN as aX, ARROW_LEFT as aY, ARROW_RIGHT as aZ, isElementVisible as a_, rectToClientRect as aa, windowResize as ab, isVirtualClick as ac, itemPress as ad, evaluate as ae, getSide as af, getSideAxis as ag, getOppositePlacement as ah, getExpandedPlacements as ai, getOppositeAxisPlacements as aj, getAlignmentSides as ak, getAlignment as al, min as am, max as an, getAlignmentAxis as ao, getPaddingObject as ap, getOppositeAxis as aq, clamp as ar, getAxisLength as as, getDocumentElement as at, isElement as au, createCoords as av, round as aw, isTopLayer as ax, getNodeName as ay, isOverflowElement as az, getParentNode as b, scrub as b$, jsdom as b0, DISABLED_TRANSITIONS_STYLE as b1, useScrollLock as b2, shimExports as b3, usePopupInteractionProps as b4, setPopupOpenState as b5, usePopupRootStore as b6, usePopupRootSync as b7, useImplicitActiveTrigger as b8, useOpenStateTransitions as b9, POPUP_COLLISION_AVOIDANCE as bA, FloatingNode as bB, siblingOpen as bC, FloatingTreeStore as bD, fastComponent as bE, useFloatingNodeId as bF, attachPreventUnmountOnClose as bG, useSyncedFloatingRootContext as bH, TYPEAHEAD_RESET_MS as bI, FloatingTree as bJ, useCompositeRootContext as bK, getTabbableBeforeElement as bL, isOutsideEvent as bM, getTabbableAfterElement as bN, getNextTabbable as bO, fastComponentRef as bP, FocusGuard as bQ, PATIENT_CLICK_THRESHOLD as bR, useTriggerRegistration as bS, voiceOver as bT, getGridNavigatedIndex as bU, Store as bV, inputPress as bW, pointer as bX, gecko as bY, clearPress as bZ, chipRemovePress as b_, PopupHandleAttachment as ba, useTriggerDataForwarding as bb, useOpenMethodTriggerProps as bc, CLICK_TRIGGER_IDENTIFIER as bd, triggerOpenStateMapping as be, CommonPopupDataAttributes as bf, android as bg, closeWatcher as bh, TransitionStatusDataAttributes as bi, swipe as bj, BASE_UI_SWIPE_IGNORE_SELECTOR as bk, isMouseLikePointerType as bl, mergeCleanups as bm, isTypeableElement as bn, matchesFocusVisible as bo, isTargetInsideEnabledTrigger as bp, triggerFocus as bq, createAttribute as br, mac as bs, triggerPress as bt, escapeKey as bu, isInteractiveElement as bv, getNodeChildren as bw, triggerHover as bx, dispatchClickWithModifiers as by, useAnimationsFinished as bz, useIsoLayoutEffect as c, useStableCallback as d, getTarget as e, useButton as f, getComputedStyle as g, createChangeEventDetails as h, isHTMLElement as i, closePress as j, imperativeAction as k, useOpenChangeComplete as l, createDefaultInitialFocus as m, FloatingFocusManager as n, ownerDocument as o, popupTransitionStateMapping as p, useTimeout as q, error as r, useTransitionStatus as s, transitionStatusMapping as t, useBaseUiId as u, useControlled as v, useValueAsRef as w, ios as x, addEventListener as y, none as z };