@jobber/components 9.4.0 → 9.5.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 (161) hide show
  1. package/dist/Autocomplete/index.cjs +0 -1
  2. package/dist/Autocomplete/index.mjs +0 -1
  3. package/dist/Card/index.cjs +7 -7
  4. package/dist/Card/index.mjs +7 -7
  5. package/dist/Chip/index.cjs +0 -1
  6. package/dist/Chip/index.mjs +0 -1
  7. package/dist/Chips/InternalChipDismissible/hooks/index.cjs +0 -1
  8. package/dist/Chips/InternalChipDismissible/hooks/index.mjs +0 -1
  9. package/dist/Chips/InternalChipDismissible/index.cjs +0 -1
  10. package/dist/Chips/InternalChipDismissible/index.mjs +0 -1
  11. package/dist/Chips/index.cjs +0 -1
  12. package/dist/Chips/index.mjs +0 -1
  13. package/dist/ComboboxChipRemove-cjs.js +181 -184
  14. package/dist/ComboboxChipRemove-es.js +4 -7
  15. package/dist/ConfirmationModal/index.cjs +0 -1
  16. package/dist/ConfirmationModal/index.mjs +0 -1
  17. package/dist/DataDump/index.cjs +7 -7
  18. package/dist/DataDump/index.mjs +7 -7
  19. package/dist/DataList/components/DataListActions/index.cjs +0 -1
  20. package/dist/DataList/components/DataListActions/index.mjs +0 -1
  21. package/dist/DataList/components/DataListBulkActions/index.cjs +0 -1
  22. package/dist/DataList/components/DataListBulkActions/index.mjs +0 -1
  23. package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +0 -1
  24. package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +0 -1
  25. package/dist/DataList/components/DataListFilters/index.cjs +0 -1
  26. package/dist/DataList/components/DataListFilters/index.mjs +0 -1
  27. package/dist/DataList/components/DataListHeader/index.cjs +0 -1
  28. package/dist/DataList/components/DataListHeader/index.mjs +0 -1
  29. package/dist/DataList/components/DataListItem/index.cjs +0 -1
  30. package/dist/DataList/components/DataListItem/index.mjs +0 -1
  31. package/dist/DataList/components/DataListItemActions/index.cjs +0 -1
  32. package/dist/DataList/components/DataListItemActions/index.mjs +0 -1
  33. package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +0 -1
  34. package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +0 -1
  35. package/dist/DataList/components/DataListItems/index.cjs +0 -1
  36. package/dist/DataList/components/DataListItems/index.mjs +0 -1
  37. package/dist/DataList/components/DataListLayout/index.cjs +0 -1
  38. package/dist/DataList/components/DataListLayout/index.mjs +0 -1
  39. package/dist/DataList/components/DataListLayoutActions/index.cjs +0 -1
  40. package/dist/DataList/components/DataListLayoutActions/index.mjs +0 -1
  41. package/dist/DataList/index.cjs +0 -1
  42. package/dist/DataList/index.mjs +0 -1
  43. package/dist/DatePicker/index.cjs +0 -2
  44. package/dist/DatePicker/index.mjs +0 -2
  45. package/dist/DatePicker-cjs.js +19 -18
  46. package/dist/DatePicker-es.js +2 -1
  47. package/dist/Dialog/index.cjs +11 -6
  48. package/dist/Dialog/index.mjs +11 -6
  49. package/dist/DrawerDescription-cjs.js +7 -8
  50. package/dist/DrawerDescription-es.js +1 -2
  51. package/dist/DrawerTitle-cjs.js +4 -4
  52. package/dist/DrawerTitle-es.js +1 -1
  53. package/dist/FieldDescription-cjs.js +49 -49
  54. package/dist/FieldDescription-es.js +2 -2
  55. package/dist/FilterPicker/components/FilterPickerActivator/index.cjs +0 -1
  56. package/dist/FilterPicker/components/FilterPickerActivator/index.mjs +0 -1
  57. package/dist/FilterPicker/components/FilterPickerContent/index.cjs +0 -1
  58. package/dist/FilterPicker/components/FilterPickerContent/index.mjs +0 -1
  59. package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +0 -1
  60. package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +0 -1
  61. package/dist/FilterPicker/index.cjs +0 -1
  62. package/dist/FilterPicker/index.mjs +0 -1
  63. package/dist/FormatFile/index.cjs +0 -1
  64. package/dist/FormatFile/index.mjs +0 -1
  65. package/dist/Gallery/index.cjs +0 -1
  66. package/dist/Gallery/index.mjs +0 -1
  67. package/dist/HelperText-cjs.js +3 -2
  68. package/dist/HelperText-es.js +3 -2
  69. package/dist/InputDate/index.cjs +0 -2
  70. package/dist/InputDate/index.mjs +0 -2
  71. package/dist/InputNumber/InputNumber.d.ts +75 -5
  72. package/dist/InputNumber/index.cjs +27 -3
  73. package/dist/InputNumber/index.d.ts +2 -2
  74. package/dist/InputNumber/index.mjs +27 -3
  75. package/dist/{primitives/InputNumberExperimental → InputNumber}/types.d.ts +48 -35
  76. package/dist/InputNumber-cjs.js +267 -4986
  77. package/dist/InputNumber-es.js +268 -4987
  78. package/dist/LightBox/index.cjs +0 -1
  79. package/dist/LightBox/index.mjs +0 -1
  80. package/dist/Menu/index.cjs +7 -7
  81. package/dist/Menu/index.mjs +7 -7
  82. package/dist/Menu-cjs.js +8 -5
  83. package/dist/Menu-es.js +8 -5
  84. package/dist/MenuSubmenuTrigger-cjs.js +142 -143
  85. package/dist/MenuSubmenuTrigger-es.js +5 -6
  86. package/dist/Modal/index.cjs +0 -1
  87. package/dist/Modal/index.mjs +0 -1
  88. package/dist/NumberFieldInput-cjs.js +63 -63
  89. package/dist/NumberFieldInput-es.js +5 -5
  90. package/dist/Page/index.cjs +7 -8
  91. package/dist/Page/index.mjs +7 -8
  92. package/dist/Popover/index.cjs +0 -1
  93. package/dist/Popover/index.mjs +0 -1
  94. package/dist/ScrollAreaViewport-cjs.js +119 -121
  95. package/dist/ScrollAreaViewport-es.js +3 -5
  96. package/dist/Select/index.cjs +3 -9
  97. package/dist/Select/index.mjs +3 -9
  98. package/dist/SelectGroupLabel-cjs.js +117 -107
  99. package/dist/SelectGroupLabel-es.js +20 -12
  100. package/dist/Tooltip/index.cjs +0 -1
  101. package/dist/Tooltip/index.mjs +0 -1
  102. package/dist/dialogReturnFocus-cjs.js +4 -1
  103. package/dist/dialogReturnFocus-es.js +4 -1
  104. package/dist/docs/InputNumber/InputNumber.md +564 -56
  105. package/dist/docs/index.md +0 -1
  106. package/dist/floating-ui.react-cjs.js +34 -35
  107. package/dist/floating-ui.react-dom-cjs.js +64 -65
  108. package/dist/floating-ui.react-dom-es.js +1 -2
  109. package/dist/floating-ui.react-es.js +1 -2
  110. package/dist/floating-ui.utils-cjs.js +183 -0
  111. package/dist/floating-ui.utils-es.js +165 -1
  112. package/dist/index.cjs +10 -15
  113. package/dist/index.mjs +10 -15
  114. package/dist/primitives/BottomSheet/index.cjs +2 -5
  115. package/dist/primitives/BottomSheet/index.mjs +2 -5
  116. package/dist/primitives/ComboboxPrimitive/index.cjs +3 -7
  117. package/dist/primitives/ComboboxPrimitive/index.mjs +3 -7
  118. package/dist/primitives/HelperText/HelperText.d.ts +4 -1
  119. package/dist/primitives/HelperText/index.cjs +1 -1
  120. package/dist/primitives/HelperText/index.mjs +1 -1
  121. package/dist/primitives/SelectPrimitive/index.cjs +3 -9
  122. package/dist/primitives/SelectPrimitive/index.mjs +3 -9
  123. package/dist/primitives/index.cjs +2 -16
  124. package/dist/primitives/index.d.ts +0 -2
  125. package/dist/primitives/index.mjs +2 -15
  126. package/dist/scrollEdges-cjs.js +6 -2
  127. package/dist/scrollEdges-es.js +5 -2
  128. package/dist/styles.css +573 -902
  129. package/dist/unstyledPrimitives/index.cjs +105 -111
  130. package/dist/unstyledPrimitives/index.mjs +5 -11
  131. package/dist/useCompositeListItem-cjs.js +516 -90
  132. package/dist/useCompositeListItem-es.js +407 -6
  133. package/dist/useLabel-cjs.js +10 -10
  134. package/dist/useLabel-es.js +3 -3
  135. package/dist/useRenderElement-es.js +1 -1
  136. package/dist/useScrollLock-cjs.js +1332 -203
  137. package/dist/useScrollLock-es.js +1068 -5
  138. package/dist/utils/meta/meta.json +12 -0
  139. package/package.json +2 -3
  140. package/dist/InputNumber/InputNumber.types.d.ts +0 -20
  141. package/dist/InputNumberExperimental-cjs.js +0 -277
  142. package/dist/InputNumberExperimental-es.js +0 -275
  143. package/dist/clamp-cjs.js +0 -7
  144. package/dist/clamp-es.js +0 -5
  145. package/dist/clsx-cjs.js +0 -5
  146. package/dist/clsx-es.js +0 -3
  147. package/dist/docs/InputNumberExperimental/InputNumberExperimental.md +0 -578
  148. package/dist/floating-ui.utils.dom-cjs.js +0 -185
  149. package/dist/floating-ui.utils.dom-es.js +0 -165
  150. package/dist/isElementDisabled-cjs.js +0 -40
  151. package/dist/isElementDisabled-es.js +0 -18
  152. package/dist/primitives/InputNumberExperimental/InputNumberExperimental.d.ts +0 -77
  153. package/dist/primitives/InputNumberExperimental/index.cjs +0 -30
  154. package/dist/primitives/InputNumberExperimental/index.d.ts +0 -2
  155. package/dist/primitives/InputNumberExperimental/index.mjs +0 -24
  156. package/dist/resolveAriaLabelledBy-cjs.js +0 -200
  157. package/dist/resolveAriaLabelledBy-es.js +0 -166
  158. package/dist/useButton-cjs.js +0 -1164
  159. package/dist/useButton-es.js +0 -1071
  160. package/dist/useLabelableId-cjs.js +0 -278
  161. package/dist/useLabelableId-es.js +0 -247
@@ -1,1164 +0,0 @@
1
- 'use strict';
2
-
3
- var React = require('react');
4
- var useRenderElement = require('./useRenderElement-cjs.js');
5
- var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
6
- var ReactDOM = require('react-dom');
7
-
8
- function _interopNamespaceDefault(e) {
9
- var n = Object.create(null);
10
- if (e) {
11
- Object.keys(e).forEach(function (k) {
12
- if (k !== 'default') {
13
- var d = Object.getOwnPropertyDescriptor(e, k);
14
- Object.defineProperty(n, k, d.get ? d : {
15
- enumerable: true,
16
- get: function () { return e[k]; }
17
- });
18
- }
19
- });
20
- }
21
- n.default = e;
22
- return Object.freeze(n);
23
- }
24
-
25
- var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
- var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
27
-
28
- let set;
29
- if (process.env.NODE_ENV !== 'production') {
30
- set = new Set();
31
- }
32
- function error(...messages) {
33
- if (process.env.NODE_ENV !== 'production') {
34
- const messageKey = messages.join(' ');
35
- if (!set.has(messageKey)) {
36
- set.add(messageKey);
37
- console.error(`Base UI: ${messageKey}`);
38
- }
39
- }
40
- }
41
-
42
- function useControlled({
43
- controlled,
44
- default: defaultProp,
45
- name,
46
- state = 'value'
47
- }) {
48
- // isControlled is ignored in the hook dependency lists as it should never change.
49
- const {
50
- current: isControlled
51
- } = React__namespace.useRef(controlled !== undefined);
52
- const [valueState, setValue] = React__namespace.useState(defaultProp);
53
- const value = isControlled ? controlled : valueState;
54
- if (process.env.NODE_ENV !== 'production') {
55
- React__namespace.useEffect(() => {
56
- if (isControlled !== (controlled !== undefined)) {
57
- error([`A component is changing the ${isControlled ? '' : 'un'}controlled ${state} state of ${name} to be ${isControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled ${name} ` + 'element for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
58
- }
59
- }, [state, name, controlled]);
60
- const {
61
- current: defaultValue
62
- } = React__namespace.useRef(defaultProp);
63
- React__namespace.useEffect(() => {
64
- if (!isControlled && serializeToDevModeString(defaultValue) !== serializeToDevModeString(defaultProp)) {
65
- error([`A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. ` + `To suppress this warning opt to use a controlled ${name}.`].join('\n'));
66
- }
67
- }, [defaultProp]);
68
- }
69
- const setValueIfUncontrolled = React__namespace.useCallback(newValue => {
70
- if (!isControlled) {
71
- setValue(newValue);
72
- }
73
- }, []);
74
- return [value, setValueIfUncontrolled];
75
- }
76
- function serializeToDevModeString(input) {
77
- let nextId = 0;
78
- const seen = new WeakMap();
79
- try {
80
- const result = JSON.stringify(input, function replacer(key, value) {
81
- if (key === '_owner' && this != null && typeof this === 'object' && '$$typeof' in this) {
82
- return undefined;
83
- }
84
- if (typeof value === 'bigint') {
85
- return `__bigint__:${value}`;
86
- }
87
- if (value !== null && typeof value === 'object') {
88
- const id = seen.get(value);
89
- if (id !== undefined) {
90
- return `__object__:${id}`;
91
- }
92
- seen.set(value, nextId);
93
- nextId += 1;
94
- }
95
- return value;
96
- });
97
- return result ?? `__top__:${typeof input}`;
98
- } catch {
99
- return '__unserializable__';
100
- }
101
- }
102
-
103
- const noop = () => {};
104
- const useIsoLayoutEffect = typeof document !== 'undefined' ? React__namespace.useLayoutEffect : noop;
105
-
106
- /**
107
- * A clone of the React namespace for reading APIs that may be missing in older
108
- * supported React versions. Bundlers can rewrite direct `React.someNewApi`
109
- * reads into named imports, which breaks React 17. Reading from this cloned
110
- * object keeps those lookups optional.
111
- *
112
- * @see https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
113
- */
114
- const SafeReact = {
115
- ...React__namespace
116
- };
117
-
118
- const useInsertionEffect = SafeReact.useInsertionEffect;
119
- const useSafeInsertionEffect =
120
- // React 17 doesn't have useInsertionEffect.
121
- useInsertionEffect &&
122
- // Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
123
- useInsertionEffect !== SafeReact.useLayoutEffect ? useInsertionEffect : fn => fn();
124
- /**
125
- * Stabilizes the function passed so it's always the same between renders.
126
- *
127
- * The function becomes non-reactive to any values it captures.
128
- * It can safely be passed as a dependency of `React.useMemo` and `React.useEffect` without re-triggering them if its captured values change.
129
- *
130
- * The function must only be called inside effects and event handlers, never during render (which throws an error).
131
- *
132
- * This hook is a more permissive version of React 19.2's `React.useEffectEvent` in that it can be passed through contexts and called in event handler props, not just effects.
133
- */
134
- function useStableCallback(callback) {
135
- const stable = useRenderElement.useRefWithInit(createStableCallback).current;
136
- stable.next = callback;
137
- useSafeInsertionEffect(stable.effect);
138
- return stable.trampoline;
139
- }
140
- function createStableCallback() {
141
- const stable = {
142
- next: undefined,
143
- callback: assertNotCalled,
144
- trampoline: (...args) => stable.callback?.(...args),
145
- effect: () => {
146
- stable.callback = stable.next;
147
- }
148
- };
149
- return stable;
150
- }
151
- function assertNotCalled() {
152
- if (process.env.NODE_ENV !== 'production') {
153
- // TODO: fix mui/no-guarded-throw
154
- // eslint-disable-next-line mui/no-guarded-throw
155
- throw /* minify-error-disabled */new Error('Base UI: Cannot call an event handler while rendering.');
156
- }
157
- }
158
-
159
- /**
160
- * Untracks the provided value by turning it into a ref to remove its reactivity.
161
- *
162
- * Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
163
- */
164
- function useValueAsRef(value) {
165
- const latest = useRenderElement.useRefWithInit(createLatestRef, value).current;
166
- latest.next = value;
167
-
168
- // eslint-disable-next-line react-hooks/exhaustive-deps
169
- useIsoLayoutEffect(latest.effect);
170
- return latest;
171
- }
172
- function createLatestRef(value) {
173
- const latest = {
174
- current: value,
175
- next: value,
176
- effect: () => {
177
- latest.current = latest.next;
178
- }
179
- };
180
- return latest;
181
- }
182
-
183
- const visuallyHiddenBase = {
184
- clipPath: 'inset(50%)',
185
- overflow: 'hidden',
186
- whiteSpace: 'nowrap',
187
- border: 0,
188
- padding: 0,
189
- width: 1,
190
- height: 1,
191
- margin: -1
192
- };
193
- const visuallyHidden = {
194
- ...visuallyHiddenBase,
195
- position: 'fixed',
196
- top: 0,
197
- left: 0
198
- };
199
- const visuallyHiddenInput = {
200
- ...visuallyHiddenBase,
201
- position: 'absolute'
202
- };
203
-
204
- function ownerDocument(node) {
205
- return node?.ownerDocument || document;
206
- }
207
-
208
- /**
209
- * Adds an event listener and returns a cleanup function to remove it.
210
- */
211
-
212
- function addEventListener(target, type, listener, options) {
213
- target.addEventListener(type, listener, options);
214
- return () => {
215
- target.removeEventListener(type, listener, options);
216
- };
217
- }
218
-
219
- const EMPTY$2 = [];
220
-
221
- /**
222
- * A React.useEffect equivalent that runs once, when the component is mounted.
223
- */
224
- function useOnMount(fn) {
225
- // 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
226
- /* eslint-disable react-hooks/exhaustive-deps */
227
- React__namespace.useEffect(fn, EMPTY$2);
228
- /* eslint-enable react-hooks/exhaustive-deps */
229
- }
230
-
231
- /** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
232
- * a monomorphic `uint` type with `0` meaning empty.
233
- * See warning note at:
234
- * https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
235
- const EMPTY$1 = null;
236
- let LAST_RAF = globalThis.requestAnimationFrame;
237
- class Scheduler {
238
- /* This implementation uses an array as a backing data-structure for frame callbacks.
239
- * It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
240
- * never calls the native `cancelAnimationFrame` if there are no frames left. This can
241
- * be much more efficient if there is a call pattern that alterns as
242
- * "request-cancel-request-cancel-…".
243
- * But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
244
- * frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
245
-
246
- callbacks = [];
247
- callbacksCount = 0;
248
- nextId = 1;
249
- startId = 1;
250
- isScheduled = false;
251
- tick = timestamp => {
252
- this.isScheduled = false;
253
- const currentCallbacks = this.callbacks;
254
- const currentCallbacksCount = this.callbacksCount;
255
-
256
- // Update these before iterating, callbacks could call `requestAnimationFrame` again.
257
- this.callbacks = [];
258
- this.callbacksCount = 0;
259
- this.startId = this.nextId;
260
- if (currentCallbacksCount > 0) {
261
- for (let i = 0; i < currentCallbacks.length; i += 1) {
262
- currentCallbacks[i]?.(timestamp);
263
- }
264
- }
265
- };
266
- request(fn) {
267
- const id = this.nextId;
268
- this.nextId += 1;
269
- this.callbacks.push(fn);
270
- this.callbacksCount += 1;
271
-
272
- /* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
273
- * but there's no guarantee that the animation frame will actually run before the fake
274
- * timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
275
- const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
276
- if (!this.isScheduled || didRAFChange) {
277
- requestAnimationFrame(this.tick);
278
- this.isScheduled = true;
279
- }
280
- return id;
281
- }
282
- cancel(id) {
283
- const index = id - this.startId;
284
- if (index < 0 || index >= this.callbacks.length) {
285
- return;
286
- }
287
- this.callbacks[index] = null;
288
- this.callbacksCount -= 1;
289
- }
290
- }
291
- const scheduler = new Scheduler();
292
- class AnimationFrame {
293
- static create() {
294
- return new AnimationFrame();
295
- }
296
- static request(fn) {
297
- return scheduler.request(fn);
298
- }
299
- static cancel(id) {
300
- return scheduler.cancel(id);
301
- }
302
- currentId = EMPTY$1;
303
-
304
- /**
305
- * Executes `fn` after `delay`, clearing any previously scheduled call.
306
- */
307
- request(fn) {
308
- this.cancel();
309
- this.currentId = scheduler.request(() => {
310
- this.currentId = EMPTY$1;
311
- fn();
312
- });
313
- }
314
- cancel = () => {
315
- if (this.currentId !== EMPTY$1) {
316
- scheduler.cancel(this.currentId);
317
- this.currentId = EMPTY$1;
318
- }
319
- };
320
- disposeEffect = () => {
321
- return this.cancel;
322
- };
323
- }
324
-
325
- /**
326
- * A `requestAnimationFrame` with automatic cleanup and guard.
327
- */
328
- function useAnimationFrame() {
329
- const timeout = useRenderElement.useRefWithInit(AnimationFrame.create).current;
330
- useOnMount(timeout.disposeEffect);
331
- return timeout;
332
- }
333
-
334
- const EMPTY = 0;
335
- class Timeout {
336
- static create() {
337
- return new Timeout();
338
- }
339
- currentId = EMPTY;
340
-
341
- /**
342
- * Executes `fn` after `delay`, clearing any previously scheduled call.
343
- */
344
- start(delay, fn) {
345
- this.clear();
346
- this.currentId = setTimeout(() => {
347
- this.currentId = EMPTY;
348
- fn();
349
- }, delay); /* Node.js types are enabled in development */
350
- }
351
- isStarted() {
352
- return this.currentId !== EMPTY;
353
- }
354
- clear = () => {
355
- if (this.currentId !== EMPTY) {
356
- clearTimeout(this.currentId);
357
- this.currentId = EMPTY;
358
- }
359
- };
360
- disposeEffect = () => {
361
- return this.clear;
362
- };
363
- }
364
-
365
- /**
366
- * A `setTimeout` with automatic cleanup and guard.
367
- */
368
- function useTimeout() {
369
- const timeout = useRenderElement.useRefWithInit(Timeout.create).current;
370
- useOnMount(timeout.disposeEffect);
371
- return timeout;
372
- }
373
-
374
- /**
375
- * Reads `navigator.userAgent` / `navigator.platform` (legacy but universally
376
- * supported) into a normalized shape. In development, prefers the modern
377
- * `navigator.userAgentData` API on Chromium to avoid DevTools warnings about
378
- * the deprecated reads; that branch is dead-code-eliminated in production
379
- * builds to keep the bundle small.
380
- *
381
- * Returns empty/zero values when `navigator` is undefined (SSR), so every
382
- * derived flag safely evaluates to `false`.
383
- */
384
- function readRawData() {
385
- if (typeof navigator === 'undefined') {
386
- return {
387
- userAgent: '',
388
- platform: '',
389
- maxTouchPoints: 0
390
- };
391
- }
392
- if (process.env.NODE_ENV !== 'production') {
393
- const uaData = navigator.userAgentData;
394
- if (uaData && Array.isArray(uaData.brands)) {
395
- return {
396
- userAgent: uaData.brands.map(({
397
- brand,
398
- version
399
- }) => `${brand}/${version}`).join(' '),
400
- platform: uaData.platform ?? navigator.platform ?? '',
401
- maxTouchPoints: navigator.maxTouchPoints ?? 0
402
- };
403
- }
404
- }
405
- return {
406
- userAgent: navigator.userAgent,
407
- platform: navigator.platform ?? '',
408
- maxTouchPoints: navigator.maxTouchPoints ?? 0
409
- };
410
- }
411
- const {
412
- userAgent,
413
- platform,
414
- maxTouchPoints
415
- } = readRawData();
416
- const lowerUserAgent = userAgent.toLowerCase();
417
- const lowerPlatform = platform.toLowerCase();
418
-
419
- // iPadOS 13+ reports `MacIntel` for `navigator.platform`; disambiguated via
420
- // `maxTouchPoints` so iPad is classified as iOS, not macOS.
421
- // https://github.com/mui/base-ui/issues/1309
422
- /** iPhone, iPad (including iPadOS 13+ reporting as macOS), iPod. */
423
- const ios = /^i(os$|p)/.test(lowerPlatform) || lowerPlatform === 'macintel' && maxTouchPoints > 1;
424
-
425
- /** Android phones, tablets, and embedded Android browsers. */
426
- const ANDROID_STRING = 'android';
427
- const android = lowerPlatform === ANDROID_STRING || lowerUserAgent.includes(ANDROID_STRING);
428
-
429
- /** macOS desktop. Excludes iPadOS, which reports as `MacIntel`. */
430
- const mac = !ios && lowerPlatform.startsWith('mac');
431
-
432
- /** Windows desktop. */
433
- lowerPlatform.startsWith('win');
434
-
435
- /** Any Apple OS (`mac || ios`). */
436
- const apple = mac || ios;
437
-
438
- /** Running in jsdom or HappyDOM (used by unit tests). */
439
- const jsdom = /jsdom|happydom/.test(lowerUserAgent);
440
-
441
- function stopEvent(event) {
442
- event.preventDefault();
443
- event.stopPropagation();
444
- }
445
- function isReactEvent(event) {
446
- return 'nativeEvent' in event;
447
- }
448
-
449
- // License: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/utils/src/isVirtualEvent.ts
450
- function isVirtualClick(event) {
451
- if (event.pointerType === '' && event.isTrusted) {
452
- return true;
453
- }
454
- if (android && event.pointerType) {
455
- return event.type === 'click' && event.buttons === 1;
456
- }
457
- return event.detail === 0 && !event.pointerType;
458
- }
459
- function isVirtualPointerEvent(event) {
460
- if (jsdom) {
461
- return false;
462
- }
463
- return !android && event.width === 0 && event.height === 0 || android && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
464
- // iOS VoiceOver returns 0.333• for width/height.
465
- event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
466
- }
467
- function isMouseLikePointerType(pointerType, strict) {
468
- // On some Linux machines with Chromium, mouse inputs return a `pointerType`
469
- // of "pen": https://github.com/floating-ui/floating-ui/issues/2015
470
- const values = ['mouse', 'pen'];
471
- if (!strict) {
472
- values.push('', undefined);
473
- }
474
- return values.includes(pointerType);
475
- }
476
- function isClickLikeEvent(event) {
477
- const type = event.type;
478
- return type === 'click' || type === 'mousedown' || type === 'keydown' || type === 'keyup';
479
- }
480
-
481
- function activeElement(doc) {
482
- let element = doc.activeElement;
483
- while (element?.shadowRoot?.activeElement != null) {
484
- element = element.shadowRoot.activeElement;
485
- }
486
- return element;
487
- }
488
- function contains(parent, child) {
489
- if (!parent || !child) {
490
- return false;
491
- }
492
- const rootNode = child.getRootNode?.();
493
-
494
- // First, attempt with the faster native method.
495
- if (parent.contains(child)) {
496
- return true;
497
- }
498
-
499
- // Then fall back to traversing out of shadow roots when needed.
500
- if (rootNode && floatingUi_utils_dom.isShadowRoot(rootNode)) {
501
- let next = child;
502
- while (next) {
503
- if (parent === next) {
504
- return true;
505
- }
506
- next = next.parentNode || next.host;
507
- }
508
- }
509
- return false;
510
- }
511
- function getTarget(event) {
512
- if ('composedPath' in event) {
513
- return event.composedPath()[0];
514
- }
515
-
516
- // TS assumes `composedPath()` always exists, but older browsers without
517
- // shadow DOM support still fall back to `target`.
518
- return event.target;
519
- }
520
-
521
- const none = 'none';
522
- const triggerPress = 'trigger-press';
523
- const triggerHover = 'trigger-hover';
524
- const triggerFocus = 'trigger-focus';
525
- const outsidePress = 'outside-press';
526
- const itemPress = 'item-press';
527
- const closePress = 'close-press';
528
- const clearPress = 'clear-press';
529
- const chipRemovePress = 'chip-remove-press';
530
- const incrementPress = 'increment-press';
531
- const decrementPress = 'decrement-press';
532
- const inputChange = 'input-change';
533
- const inputClear = 'input-clear';
534
- const inputBlur = 'input-blur';
535
- const inputPaste = 'input-paste';
536
- const inputPress = 'input-press';
537
- const focusOut = 'focus-out';
538
- const escapeKey = 'escape-key';
539
- const closeWatcher = 'close-watcher';
540
- const listNavigation = 'list-navigation';
541
- const keyboard = 'keyboard';
542
- const pointer = 'pointer';
543
- const wheel = 'wheel';
544
- const scrub = 'scrub';
545
- const cancelOpen = 'cancel-open';
546
- const siblingOpen = 'sibling-open';
547
- const imperativeAction = 'imperative-action';
548
- const swipe = 'swipe';
549
- const windowResize = 'window-resize';
550
-
551
- /**
552
- * Maps a change `reason` string to the corresponding native event type.
553
- */
554
-
555
- /**
556
- * Details of custom change events emitted by Base UI components.
557
- */
558
-
559
- /**
560
- * Details of custom generic events emitted by Base UI components.
561
- */
562
-
563
- /**
564
- * Creates a Base UI event details object with the given reason and utilities
565
- * for preventing Base UI's internal event handling.
566
- */
567
- function createChangeEventDetails(reason, event, trigger, customProperties) {
568
- let canceled = false;
569
- let allowPropagation = false;
570
- const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
571
- const details = {
572
- reason,
573
- event: event ?? new Event('base-ui'),
574
- cancel() {
575
- canceled = true;
576
- },
577
- allowPropagation() {
578
- allowPropagation = true;
579
- },
580
- get isCanceled() {
581
- return canceled;
582
- },
583
- get isPropagationAllowed() {
584
- return allowPropagation;
585
- },
586
- trigger,
587
- ...custom
588
- };
589
- return details;
590
- }
591
- function createGenericEventDetails(reason, event, customProperties) {
592
- const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
593
- const details = {
594
- reason,
595
- event: event ?? new Event('base-ui'),
596
- ...custom
597
- };
598
- return details;
599
- }
600
-
601
- let globalId = 0;
602
-
603
- // TODO React 17: Remove `useGlobalId` once React 17 support is removed
604
- function useGlobalId(idOverride, prefix = 'mui') {
605
- const [defaultId, setDefaultId] = React__namespace.useState(idOverride);
606
- const id = idOverride || defaultId;
607
- React__namespace.useEffect(() => {
608
- if (defaultId == null) {
609
- // Fallback to this default id when possible.
610
- // Use the incrementing value for client-side rendering only.
611
- // We can't use it server-side.
612
- // If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
613
- globalId += 1;
614
- setDefaultId(`${prefix}-${globalId}`);
615
- }
616
- }, [defaultId, prefix]);
617
- return id;
618
- }
619
- const maybeReactUseId = SafeReact.useId;
620
-
621
- /**
622
- *
623
- * @example <div id={useId()} />
624
- * @param idOverride
625
- * @returns {string}
626
- */
627
- function useId(idOverride, prefix) {
628
- // React.useId() is only available from React 17.0.0.
629
- if (maybeReactUseId !== undefined) {
630
- const reactId = maybeReactUseId();
631
- return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
632
- }
633
-
634
- // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
635
- // eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
636
- return useGlobalId(idOverride, prefix);
637
- }
638
-
639
- /**
640
- * If the provided argument is a ref object, returns its `current` value.
641
- * Otherwise, returns the argument itself.
642
- */
643
- function resolveRef(maybeRef) {
644
- if (maybeRef == null) {
645
- return maybeRef;
646
- }
647
- return 'current' in maybeRef ? maybeRef.current : maybeRef;
648
- }
649
-
650
- /**
651
- * Provides a status string for CSS animations.
652
- * @param open - a boolean that determines if the element is open.
653
- * @param enableIdleState - a boolean that enables the `'idle'` state between `'starting'` and `'ending'`
654
- */
655
- function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) {
656
- const [transitionStatus, setTransitionStatus] = React__namespace.useState(open && enableIdleState ? 'idle' : undefined);
657
- const [mounted, setMounted] = React__namespace.useState(open);
658
- if (open && !mounted) {
659
- setMounted(true);
660
- setTransitionStatus('starting');
661
- }
662
- if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) {
663
- setTransitionStatus('ending');
664
- }
665
- if (!open && !mounted && transitionStatus === 'ending') {
666
- setTransitionStatus(undefined);
667
- }
668
- useIsoLayoutEffect(() => {
669
- if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) {
670
- const frame = AnimationFrame.request(() => {
671
- setTransitionStatus('ending');
672
- });
673
- return () => {
674
- AnimationFrame.cancel(frame);
675
- };
676
- }
677
- return undefined;
678
- }, [open, mounted, transitionStatus, deferEndingState]);
679
- useIsoLayoutEffect(() => {
680
- if (!open || enableIdleState) {
681
- return undefined;
682
- }
683
- const frame = AnimationFrame.request(() => {
684
- // Avoid `flushSync` here due to Firefox.
685
- // See https://github.com/mui/base-ui/pull/3424
686
- setTransitionStatus(undefined);
687
- });
688
- return () => {
689
- AnimationFrame.cancel(frame);
690
- };
691
- }, [enableIdleState, open]);
692
- useIsoLayoutEffect(() => {
693
- if (!open || !enableIdleState) {
694
- return undefined;
695
- }
696
- if (open && mounted && transitionStatus !== 'idle') {
697
- setTransitionStatus('starting');
698
- }
699
- const frame = AnimationFrame.request(() => {
700
- setTransitionStatus('idle');
701
- });
702
- return () => {
703
- AnimationFrame.cancel(frame);
704
- };
705
- }, [enableIdleState, open, mounted, transitionStatus]);
706
- return {
707
- mounted,
708
- setMounted,
709
- transitionStatus
710
- };
711
- }
712
-
713
- let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
714
- /**
715
- * Present when the component is animating in.
716
- */
717
- TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
718
- /**
719
- * Present when the component is animating out.
720
- */
721
- TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
722
- return TransitionStatusDataAttributes;
723
- }({});
724
- const STARTING_HOOK = {
725
- [TransitionStatusDataAttributes.startingStyle]: ''
726
- };
727
- const ENDING_HOOK = {
728
- [TransitionStatusDataAttributes.endingStyle]: ''
729
- };
730
- const transitionStatusMapping = {
731
- transitionStatus(value) {
732
- if (value === 'starting') {
733
- return STARTING_HOOK;
734
- }
735
- if (value === 'ending') {
736
- return ENDING_HOOK;
737
- }
738
- return null;
739
- }
740
- };
741
-
742
- /**
743
- * Executes a function once all animations have finished on the provided element.
744
- * @param elementOrRef - The element to watch for animations.
745
- * @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
746
- * @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
747
- * the function will check again if any new animations have started and wait for them to finish.
748
- * @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
749
- */
750
- function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
751
- const frame = useAnimationFrame();
752
- return useStableCallback((fnToExecute,
753
- /**
754
- * An optional [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that
755
- * can be used to abort `fnToExecute` before all the animations have finished.
756
- * @default null
757
- */
758
- signal = null) => {
759
- frame.cancel();
760
- const element = resolveRef(elementOrRef);
761
- if (element == null) {
762
- return;
763
- }
764
- const resolvedElement = element;
765
- const done = () => {
766
- // Synchronously flush the unmounting of the component so that the browser doesn't
767
- // paint: https://github.com/mui/base-ui/issues/979
768
- ReactDOM__namespace.flushSync(fnToExecute);
769
- };
770
- if (typeof resolvedElement.getAnimations !== 'function' || globalThis.BASE_UI_ANIMATIONS_DISABLED) {
771
- fnToExecute();
772
- return;
773
- }
774
- function exec() {
775
- Promise.all(resolvedElement.getAnimations().map(animation => animation.finished)).then(() => {
776
- if (!signal?.aborted) {
777
- done();
778
- }
779
- }).catch(() => {
780
- if (treatAbortedAsFinished) {
781
- if (!signal?.aborted) {
782
- done();
783
- }
784
- return;
785
- }
786
- const currentAnimations = resolvedElement.getAnimations();
787
- if (!signal?.aborted && currentAnimations.length > 0 && currentAnimations.some(animation => animation.pending || animation.playState !== 'finished')) {
788
- // Sometimes animations can be aborted because a property they depend on changes while the animation plays.
789
- // In such cases, we need to re-check if any new animations have started.
790
- exec();
791
- }
792
- });
793
- }
794
- if (waitForStartingStyleRemoved) {
795
- const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle;
796
-
797
- // If `[data-starting-style]` isn't present, fall back to waiting one more frame
798
- // to give "open" animations a chance to be registered.
799
- if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
800
- frame.request(exec);
801
- return;
802
- }
803
-
804
- // Wait for `[data-starting-style]` to have been removed.
805
- const attributeObserver = new MutationObserver(() => {
806
- if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
807
- attributeObserver.disconnect();
808
- exec();
809
- }
810
- });
811
- attributeObserver.observe(resolvedElement, {
812
- attributes: true,
813
- attributeFilter: [startingStyleAttribute]
814
- });
815
- signal?.addEventListener('abort', () => attributeObserver.disconnect(), {
816
- once: true
817
- });
818
- return;
819
- }
820
- frame.request(exec);
821
- });
822
- }
823
-
824
- /**
825
- * Calls the provided function when the CSS open/close animation or transition completes.
826
- */
827
- function useOpenChangeComplete(parameters) {
828
- const {
829
- enabled = true,
830
- open,
831
- ref,
832
- onComplete: onCompleteParam
833
- } = parameters;
834
- const onComplete = useStableCallback(onCompleteParam);
835
- const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
836
- React__namespace.useEffect(() => {
837
- if (!enabled) {
838
- return undefined;
839
- }
840
- const abortController = new AbortController();
841
- runOnceAnimationsFinish(onComplete, abortController.signal);
842
- return () => {
843
- abortController.abort();
844
- };
845
- }, [enabled, open, onComplete, runOnceAnimationsFinish]);
846
- }
847
-
848
- /**
849
- * Wraps `useId` and prefixes generated `id`s with `base-ui-`
850
- * @param {string | undefined} idOverride overrides the generated id when provided
851
- * @returns {string | undefined}
852
- */
853
- function useBaseUiId(idOverride) {
854
- return useId(idOverride, 'base-ui');
855
- }
856
-
857
- function useValueChanged(value, onChange) {
858
- const valueRef = React__namespace.useRef(value);
859
- const onChangeCallback = useStableCallback(onChange);
860
- useIsoLayoutEffect(() => {
861
- if (valueRef.current === value) {
862
- return;
863
- }
864
- onChangeCallback(valueRef.current);
865
- }, [value, onChangeCallback]);
866
- useIsoLayoutEffect(() => {
867
- valueRef.current = value;
868
- }, [value]);
869
- }
870
-
871
- const CompositeRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
872
- if (process.env.NODE_ENV !== "production") CompositeRootContext.displayName = "CompositeRootContext";
873
- function useCompositeRootContext(optional = false) {
874
- const context = React__namespace.useContext(CompositeRootContext);
875
- if (context === undefined && !optional) {
876
- throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.' : useRenderElement.formatErrorMessage(16));
877
- }
878
- return context;
879
- }
880
-
881
- function useFocusableWhenDisabled(parameters) {
882
- const {
883
- focusableWhenDisabled,
884
- disabled,
885
- composite = false,
886
- tabIndex: tabIndexProp = 0,
887
- isNativeButton
888
- } = parameters;
889
- const isFocusableComposite = composite && focusableWhenDisabled !== false;
890
- const isNonFocusableComposite = composite && focusableWhenDisabled === false;
891
-
892
- // we can't explicitly assign `undefined` to any of these props because it
893
- // would otherwise prevent subsequently merged props from setting them
894
- const props = React__namespace.useMemo(() => {
895
- const additionalProps = {
896
- // allow Tabbing away from focusableWhenDisabled elements
897
- onKeyDown(event) {
898
- if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
899
- event.preventDefault();
900
- }
901
- }
902
- };
903
- if (!composite) {
904
- additionalProps.tabIndex = tabIndexProp;
905
- if (!isNativeButton && disabled) {
906
- additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1;
907
- }
908
- }
909
- if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
910
- additionalProps['aria-disabled'] = disabled;
911
- }
912
- if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
913
- additionalProps.disabled = disabled;
914
- }
915
- return additionalProps;
916
- }, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
917
- return {
918
- props
919
- };
920
- }
921
-
922
- function useButton(parameters = {}) {
923
- const {
924
- disabled = false,
925
- focusableWhenDisabled,
926
- tabIndex = 0,
927
- native: isNativeButton = true,
928
- composite: compositeProp
929
- } = parameters;
930
- const elementRef = React__namespace.useRef(null);
931
- const compositeRootContext = useCompositeRootContext(true);
932
- const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
933
- const {
934
- props: focusableWhenDisabledProps
935
- } = useFocusableWhenDisabled({
936
- focusableWhenDisabled,
937
- disabled,
938
- composite: isCompositeItem,
939
- tabIndex,
940
- isNativeButton
941
- });
942
- if (process.env.NODE_ENV !== 'production') {
943
- // eslint-disable-next-line react-hooks/rules-of-hooks
944
- React__namespace.useEffect(() => {
945
- if (!elementRef.current) {
946
- return;
947
- }
948
- const isButtonTag = isButtonElement(elementRef.current);
949
- if (isNativeButton) {
950
- if (!isButtonTag) {
951
- const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
952
- const message = 'A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Use a real <button> in the ' + '`render` prop, or set `nativeButton` to `false`.';
953
- error(`${message}${ownerStackMessage}`);
954
- }
955
- } else if (isButtonTag) {
956
- const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
957
- const message = 'A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while Base UI applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Use a non-<button> in the `render` prop, or set ' + '`nativeButton` to `true`.';
958
- error(`${message}${ownerStackMessage}`);
959
- }
960
- }, [isNativeButton]);
961
- }
962
-
963
- // handles a disabled composite button rendering another button, e.g.
964
- // <Toolbar.Button disabled render={<Menu.Trigger />} />
965
- // the `disabled` prop needs to pass through 2 `useButton`s then finally
966
- // delete the `disabled` attribute from DOM
967
- const updateDisabled = React__namespace.useCallback(() => {
968
- const element = elementRef.current;
969
- if (!isButtonElement(element)) {
970
- return;
971
- }
972
- if (isCompositeItem && disabled && focusableWhenDisabledProps.disabled === undefined && element.disabled) {
973
- element.disabled = false;
974
- }
975
- }, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
976
- useIsoLayoutEffect(updateDisabled, [updateDisabled]);
977
- const getButtonProps = React__namespace.useCallback((externalProps = {}) => {
978
- const {
979
- onClick: externalOnClick,
980
- onMouseDown: externalOnMouseDown,
981
- onKeyUp: externalOnKeyUp,
982
- onKeyDown: externalOnKeyDown,
983
- onPointerDown: externalOnPointerDown,
984
- ...otherExternalProps
985
- } = externalProps;
986
- return useRenderElement.mergeProps({
987
- onClick(event) {
988
- if (disabled) {
989
- event.preventDefault();
990
- return;
991
- }
992
- externalOnClick?.(event);
993
- },
994
- onMouseDown(event) {
995
- if (!disabled) {
996
- externalOnMouseDown?.(event);
997
- }
998
- },
999
- onKeyDown(event) {
1000
- if (disabled) {
1001
- return;
1002
- }
1003
- useRenderElement.makeEventPreventable(event);
1004
- externalOnKeyDown?.(event);
1005
- if (event.baseUIHandlerPrevented) {
1006
- return;
1007
- }
1008
- const isCurrentTarget = event.target === event.currentTarget;
1009
- const currentTarget = event.currentTarget;
1010
- const isButton = isButtonElement(currentTarget);
1011
- const isLink = !isNativeButton && isValidLinkElement(currentTarget);
1012
- const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
1013
- const isEnterKey = event.key === 'Enter';
1014
- const isSpaceKey = event.key === ' ';
1015
- const role = currentTarget.getAttribute('role');
1016
- const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
1017
- if (isCurrentTarget && isCompositeItem && isSpaceKey) {
1018
- if (event.defaultPrevented && isTextNavigationRole) {
1019
- return;
1020
- }
1021
- event.preventDefault();
1022
- if (isLink || isNativeButton && isButton) {
1023
- currentTarget.click();
1024
- event.preventBaseUIHandler();
1025
- } else if (shouldClick) {
1026
- externalOnClick?.(event);
1027
- event.preventBaseUIHandler();
1028
- }
1029
- return;
1030
- }
1031
-
1032
- // Keyboard accessibility for native and non-native elements.
1033
- if (shouldClick) {
1034
- if (!isNativeButton && (isSpaceKey || isEnterKey)) {
1035
- event.preventDefault();
1036
- }
1037
- if (!isNativeButton && isEnterKey) {
1038
- externalOnClick?.(event);
1039
- }
1040
- }
1041
- },
1042
- onKeyUp(event) {
1043
- if (disabled) {
1044
- return;
1045
- }
1046
-
1047
- // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
1048
- // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
1049
- useRenderElement.makeEventPreventable(event);
1050
- externalOnKeyUp?.(event);
1051
- if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
1052
- event.preventDefault();
1053
- return;
1054
- }
1055
- if (event.baseUIHandlerPrevented) {
1056
- return;
1057
- }
1058
-
1059
- // Keyboard accessibility for non interactive elements
1060
- if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
1061
- externalOnClick?.(event);
1062
- }
1063
- },
1064
- onPointerDown(event) {
1065
- if (disabled) {
1066
- event.preventDefault();
1067
- return;
1068
- }
1069
- externalOnPointerDown?.(event);
1070
- }
1071
- }, isNativeButton ? {
1072
- type: 'button'
1073
- } : {
1074
- role: 'button'
1075
- }, focusableWhenDisabledProps, otherExternalProps);
1076
- }, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
1077
- const buttonRef = useStableCallback(element => {
1078
- elementRef.current = element;
1079
- updateDisabled();
1080
- });
1081
- return {
1082
- getButtonProps,
1083
- buttonRef
1084
- };
1085
- }
1086
- function isButtonElement(elem) {
1087
- return floatingUi_utils_dom.isHTMLElement(elem) && elem.tagName === 'BUTTON';
1088
- }
1089
- function isValidLinkElement(elem) {
1090
- return Boolean(elem?.tagName === 'A' && elem?.href);
1091
- }
1092
-
1093
- exports.AnimationFrame = AnimationFrame;
1094
- exports.SafeReact = SafeReact;
1095
- exports.Timeout = Timeout;
1096
- exports.TransitionStatusDataAttributes = TransitionStatusDataAttributes;
1097
- exports.activeElement = activeElement;
1098
- exports.addEventListener = addEventListener;
1099
- exports.android = android;
1100
- exports.apple = apple;
1101
- exports.cancelOpen = cancelOpen;
1102
- exports.chipRemovePress = chipRemovePress;
1103
- exports.clearPress = clearPress;
1104
- exports.closePress = closePress;
1105
- exports.closeWatcher = closeWatcher;
1106
- exports.contains = contains;
1107
- exports.createChangeEventDetails = createChangeEventDetails;
1108
- exports.createGenericEventDetails = createGenericEventDetails;
1109
- exports.decrementPress = decrementPress;
1110
- exports.error = error;
1111
- exports.escapeKey = escapeKey;
1112
- exports.focusOut = focusOut;
1113
- exports.getTarget = getTarget;
1114
- exports.imperativeAction = imperativeAction;
1115
- exports.incrementPress = incrementPress;
1116
- exports.inputBlur = inputBlur;
1117
- exports.inputChange = inputChange;
1118
- exports.inputClear = inputClear;
1119
- exports.inputPaste = inputPaste;
1120
- exports.inputPress = inputPress;
1121
- exports.ios = ios;
1122
- exports.isClickLikeEvent = isClickLikeEvent;
1123
- exports.isMouseLikePointerType = isMouseLikePointerType;
1124
- exports.isReactEvent = isReactEvent;
1125
- exports.isVirtualClick = isVirtualClick;
1126
- exports.isVirtualPointerEvent = isVirtualPointerEvent;
1127
- exports.itemPress = itemPress;
1128
- exports.jsdom = jsdom;
1129
- exports.keyboard = keyboard;
1130
- exports.listNavigation = listNavigation;
1131
- exports.lowerUserAgent = lowerUserAgent;
1132
- exports.mac = mac;
1133
- exports.none = none;
1134
- exports.outsidePress = outsidePress;
1135
- exports.ownerDocument = ownerDocument;
1136
- exports.pointer = pointer;
1137
- exports.resolveRef = resolveRef;
1138
- exports.scrub = scrub;
1139
- exports.siblingOpen = siblingOpen;
1140
- exports.stopEvent = stopEvent;
1141
- exports.swipe = swipe;
1142
- exports.transitionStatusMapping = transitionStatusMapping;
1143
- exports.triggerFocus = triggerFocus;
1144
- exports.triggerHover = triggerHover;
1145
- exports.triggerPress = triggerPress;
1146
- exports.useAnimationFrame = useAnimationFrame;
1147
- exports.useAnimationsFinished = useAnimationsFinished;
1148
- exports.useBaseUiId = useBaseUiId;
1149
- exports.useButton = useButton;
1150
- exports.useCompositeRootContext = useCompositeRootContext;
1151
- exports.useControlled = useControlled;
1152
- exports.useId = useId;
1153
- exports.useIsoLayoutEffect = useIsoLayoutEffect;
1154
- exports.useOnMount = useOnMount;
1155
- exports.useOpenChangeComplete = useOpenChangeComplete;
1156
- exports.useStableCallback = useStableCallback;
1157
- exports.useTimeout = useTimeout;
1158
- exports.useTransitionStatus = useTransitionStatus;
1159
- exports.useValueAsRef = useValueAsRef;
1160
- exports.useValueChanged = useValueChanged;
1161
- exports.visuallyHidden = visuallyHidden;
1162
- exports.visuallyHiddenInput = visuallyHiddenInput;
1163
- exports.wheel = wheel;
1164
- exports.windowResize = windowResize;