@jobber/components 8.15.0 → 8.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Card/index.cjs +1 -1
- package/dist/Card/index.mjs +1 -1
- package/dist/DataDump/index.cjs +1 -1
- package/dist/DataDump/index.mjs +1 -1
- package/dist/InputNumberExperimental-cjs.js +16 -16
- package/dist/InputNumberExperimental-es.js +1 -1
- package/dist/Menu/index.cjs +1 -1
- package/dist/Menu/index.mjs +1 -1
- package/dist/MenuSubmenuTrigger-cjs.js +1060 -1060
- package/dist/MenuSubmenuTrigger-es.js +928 -928
- package/dist/NumberFieldInput-cjs.js +53 -53
- package/dist/NumberFieldInput-es.js +1 -1
- package/dist/Page/index.cjs +1 -1
- package/dist/Page/index.mjs +1 -1
- package/dist/ScrollAreaViewport-cjs.js +4436 -4436
- package/dist/ScrollAreaViewport-es.js +4372 -4372
- package/dist/{useValueChanged-cjs.js → clamp-cjs.js} +594 -592
- package/dist/{useValueChanged-es.js → clamp-es.js} +595 -594
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/primitives/BottomSheet/index.cjs +2 -2
- package/dist/primitives/BottomSheet/index.mjs +2 -2
- package/dist/primitives/InputNumberExperimental/index.cjs +2 -2
- package/dist/primitives/InputNumberExperimental/index.mjs +2 -2
- package/dist/primitives/index.cjs +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/unstyledPrimitives/index.cjs +6271 -6134
- package/dist/unstyledPrimitives/index.d.ts +1 -0
- package/dist/unstyledPrimitives/index.mjs +6318 -6182
- package/dist/useRenderElement-cjs.js +30 -30
- package/dist/useRenderElement-es.js +30 -30
- package/package.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
|
|
5
4
|
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
6
5
|
var ReactDOM = require('react-dom');
|
|
6
|
+
var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
|
|
7
7
|
|
|
8
8
|
function _interopNamespaceDefault(e) {
|
|
9
9
|
var n = Object.create(null);
|
|
@@ -25,35 +25,6 @@ function _interopNamespaceDefault(e) {
|
|
|
25
25
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
26
26
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
27
27
|
|
|
28
|
-
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
29
|
-
/**
|
|
30
|
-
* Present when the component is animating in.
|
|
31
|
-
*/
|
|
32
|
-
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
33
|
-
/**
|
|
34
|
-
* Present when the component is animating out.
|
|
35
|
-
*/
|
|
36
|
-
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
37
|
-
return TransitionStatusDataAttributes;
|
|
38
|
-
}({});
|
|
39
|
-
const STARTING_HOOK = {
|
|
40
|
-
[TransitionStatusDataAttributes.startingStyle]: ''
|
|
41
|
-
};
|
|
42
|
-
const ENDING_HOOK = {
|
|
43
|
-
[TransitionStatusDataAttributes.endingStyle]: ''
|
|
44
|
-
};
|
|
45
|
-
const transitionStatusMapping = {
|
|
46
|
-
transitionStatus(value) {
|
|
47
|
-
if (value === 'starting') {
|
|
48
|
-
return STARTING_HOOK;
|
|
49
|
-
}
|
|
50
|
-
if (value === 'ending') {
|
|
51
|
-
return ENDING_HOOK;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
28
|
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
58
29
|
const useInsertionEffect = React__namespace[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0, -3)];
|
|
59
30
|
const useSafeInsertionEffect =
|
|
@@ -94,392 +65,187 @@ function assertNotCalled() {
|
|
|
94
65
|
}
|
|
95
66
|
}
|
|
96
67
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
68
|
+
function useControlled({
|
|
69
|
+
controlled,
|
|
70
|
+
default: defaultProp,
|
|
71
|
+
name,
|
|
72
|
+
state = 'value'
|
|
73
|
+
}) {
|
|
74
|
+
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
75
|
+
const {
|
|
76
|
+
current: isControlled
|
|
77
|
+
} = React__namespace.useRef(controlled !== undefined);
|
|
78
|
+
const [valueState, setValue] = React__namespace.useState(defaultProp);
|
|
79
|
+
const value = isControlled ? controlled : valueState;
|
|
102
80
|
if (process.env.NODE_ENV !== 'production') {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
81
|
+
React__namespace.useEffect(() => {
|
|
82
|
+
if (isControlled !== (controlled !== undefined)) {
|
|
83
|
+
console.error([`Base UI: 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'));
|
|
84
|
+
}
|
|
85
|
+
}, [state, name, controlled]);
|
|
86
|
+
const {
|
|
87
|
+
current: defaultValue
|
|
88
|
+
} = React__namespace.useRef(defaultProp);
|
|
89
|
+
React__namespace.useEffect(() => {
|
|
90
|
+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
91
|
+
if (!isControlled && JSON.stringify(defaultValue) !== JSON.stringify(defaultProp)) {
|
|
92
|
+
console.error([`Base UI: 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'));
|
|
93
|
+
}
|
|
94
|
+
}, [JSON.stringify(defaultProp)]);
|
|
108
95
|
}
|
|
96
|
+
const setValueIfUncontrolled = React__namespace.useCallback(newValue => {
|
|
97
|
+
if (!isControlled) {
|
|
98
|
+
setValue(newValue);
|
|
99
|
+
}
|
|
100
|
+
}, []);
|
|
101
|
+
return [value, setValueIfUncontrolled];
|
|
109
102
|
}
|
|
110
103
|
|
|
111
|
-
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
112
|
-
const SafeReact = {
|
|
113
|
-
...React__namespace
|
|
114
|
-
};
|
|
115
|
-
|
|
116
104
|
const noop = () => {};
|
|
117
105
|
const useIsoLayoutEffect = typeof document !== 'undefined' ? React__namespace.useLayoutEffect : noop;
|
|
118
106
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
107
|
+
const visuallyHiddenBase = {
|
|
108
|
+
clipPath: 'inset(50%)',
|
|
109
|
+
overflow: 'hidden',
|
|
110
|
+
whiteSpace: 'nowrap',
|
|
111
|
+
border: 0,
|
|
112
|
+
padding: 0,
|
|
113
|
+
width: 1,
|
|
114
|
+
height: 1,
|
|
115
|
+
margin: -1
|
|
116
|
+
};
|
|
117
|
+
const visuallyHidden = {
|
|
118
|
+
...visuallyHiddenBase,
|
|
119
|
+
position: 'fixed',
|
|
120
|
+
top: 0,
|
|
121
|
+
left: 0
|
|
122
|
+
};
|
|
123
|
+
const visuallyHiddenInput = {
|
|
124
|
+
...visuallyHiddenBase,
|
|
125
|
+
position: 'absolute'
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const EMPTY$2 = [];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
132
|
+
*/
|
|
133
|
+
function useOnMount(fn) {
|
|
134
|
+
// 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
|
|
135
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
136
|
+
React__namespace.useEffect(fn, EMPTY$2);
|
|
137
|
+
/* eslint-enable react-hooks/exhaustive-deps */
|
|
127
138
|
}
|
|
128
139
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
141
|
+
* a monomorphic `uint` type with `0` meaning empty.
|
|
142
|
+
* See warning note at:
|
|
143
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
144
|
+
const EMPTY$1 = null;
|
|
145
|
+
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
146
|
+
class Scheduler {
|
|
147
|
+
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
148
|
+
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
149
|
+
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
150
|
+
* be much more efficient if there is a call pattern that alterns as
|
|
151
|
+
* "request-cancel-request-cancel-…".
|
|
152
|
+
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
153
|
+
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
139
154
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
callbacks = [];
|
|
156
|
+
callbacksCount = 0;
|
|
157
|
+
nextId = 1;
|
|
158
|
+
startId = 1;
|
|
159
|
+
isScheduled = false;
|
|
160
|
+
tick = timestamp => {
|
|
161
|
+
this.isScheduled = false;
|
|
162
|
+
const currentCallbacks = this.callbacks;
|
|
163
|
+
const currentCallbacksCount = this.callbacksCount;
|
|
164
|
+
|
|
165
|
+
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
166
|
+
this.callbacks = [];
|
|
167
|
+
this.callbacksCount = 0;
|
|
168
|
+
this.startId = this.nextId;
|
|
169
|
+
if (currentCallbacksCount > 0) {
|
|
170
|
+
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
171
|
+
currentCallbacks[i]?.(timestamp);
|
|
155
172
|
}
|
|
156
173
|
}
|
|
157
|
-
if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
|
|
158
|
-
additionalProps['aria-disabled'] = disabled;
|
|
159
|
-
}
|
|
160
|
-
if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
|
|
161
|
-
additionalProps.disabled = disabled;
|
|
162
|
-
}
|
|
163
|
-
return additionalProps;
|
|
164
|
-
}, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
|
|
165
|
-
return {
|
|
166
|
-
props
|
|
167
174
|
};
|
|
168
|
-
|
|
175
|
+
request(fn) {
|
|
176
|
+
const id = this.nextId;
|
|
177
|
+
this.nextId += 1;
|
|
178
|
+
this.callbacks.push(fn);
|
|
179
|
+
this.callbacksCount += 1;
|
|
169
180
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const compositeRootContext = useCompositeRootContext(true);
|
|
180
|
-
const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
|
|
181
|
-
const {
|
|
182
|
-
props: focusableWhenDisabledProps
|
|
183
|
-
} = useFocusableWhenDisabled({
|
|
184
|
-
focusableWhenDisabled,
|
|
185
|
-
disabled,
|
|
186
|
-
composite: isCompositeItem,
|
|
187
|
-
tabIndex,
|
|
188
|
-
isNativeButton
|
|
189
|
-
});
|
|
190
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
191
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
192
|
-
React__namespace.useEffect(() => {
|
|
193
|
-
if (!elementRef.current) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const isButtonTag = isButtonElement(elementRef.current);
|
|
197
|
-
if (isNativeButton) {
|
|
198
|
-
if (!isButtonTag) {
|
|
199
|
-
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
200
|
-
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`.';
|
|
201
|
-
error(`${message}${ownerStackMessage}`);
|
|
202
|
-
}
|
|
203
|
-
} else if (isButtonTag) {
|
|
204
|
-
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
205
|
-
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`.';
|
|
206
|
-
error(`${message}${ownerStackMessage}`);
|
|
207
|
-
}
|
|
208
|
-
}, [isNativeButton]);
|
|
181
|
+
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
182
|
+
* but there's no guarantee that the animation frame will actually run before the fake
|
|
183
|
+
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
184
|
+
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
185
|
+
if (!this.isScheduled || didRAFChange) {
|
|
186
|
+
requestAnimationFrame(this.tick);
|
|
187
|
+
this.isScheduled = true;
|
|
188
|
+
}
|
|
189
|
+
return id;
|
|
209
190
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// the `disabled` prop needs to pass through 2 `useButton`s then finally
|
|
214
|
-
// delete the `disabled` attribute from DOM
|
|
215
|
-
const updateDisabled = React__namespace.useCallback(() => {
|
|
216
|
-
const element = elementRef.current;
|
|
217
|
-
if (!isButtonElement(element)) {
|
|
191
|
+
cancel(id) {
|
|
192
|
+
const index = id - this.startId;
|
|
193
|
+
if (index < 0 || index >= this.callbacks.length) {
|
|
218
194
|
return;
|
|
219
195
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
|
|
224
|
-
useIsoLayoutEffect(updateDisabled, [updateDisabled]);
|
|
225
|
-
const getButtonProps = React__namespace.useCallback((externalProps = {}) => {
|
|
226
|
-
const {
|
|
227
|
-
onClick: externalOnClick,
|
|
228
|
-
onMouseDown: externalOnMouseDown,
|
|
229
|
-
onKeyUp: externalOnKeyUp,
|
|
230
|
-
onKeyDown: externalOnKeyDown,
|
|
231
|
-
onPointerDown: externalOnPointerDown,
|
|
232
|
-
...otherExternalProps
|
|
233
|
-
} = externalProps;
|
|
234
|
-
const type = isNativeButton ? 'button' : undefined;
|
|
235
|
-
return useRenderElement.mergeProps({
|
|
236
|
-
type,
|
|
237
|
-
onClick(event) {
|
|
238
|
-
if (disabled) {
|
|
239
|
-
event.preventDefault();
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
externalOnClick?.(event);
|
|
243
|
-
},
|
|
244
|
-
onMouseDown(event) {
|
|
245
|
-
if (!disabled) {
|
|
246
|
-
externalOnMouseDown?.(event);
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
onKeyDown(event) {
|
|
250
|
-
if (disabled) {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
useRenderElement.makeEventPreventable(event);
|
|
254
|
-
externalOnKeyDown?.(event);
|
|
255
|
-
if (event.baseUIHandlerPrevented) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
const isCurrentTarget = event.target === event.currentTarget;
|
|
259
|
-
const currentTarget = event.currentTarget;
|
|
260
|
-
const isButton = isButtonElement(currentTarget);
|
|
261
|
-
const isLink = !isNativeButton && isValidLinkElement(currentTarget);
|
|
262
|
-
const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
|
|
263
|
-
const isEnterKey = event.key === 'Enter';
|
|
264
|
-
const isSpaceKey = event.key === ' ';
|
|
265
|
-
const role = currentTarget.getAttribute('role');
|
|
266
|
-
const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
|
|
267
|
-
if (isCurrentTarget && isCompositeItem && isSpaceKey) {
|
|
268
|
-
if (event.defaultPrevented && isTextNavigationRole) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
event.preventDefault();
|
|
272
|
-
if (isLink || isNativeButton && isButton) {
|
|
273
|
-
currentTarget.click();
|
|
274
|
-
event.preventBaseUIHandler();
|
|
275
|
-
} else if (shouldClick) {
|
|
276
|
-
externalOnClick?.(event);
|
|
277
|
-
event.preventBaseUIHandler();
|
|
278
|
-
}
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Keyboard accessibility for native and non-native elements.
|
|
283
|
-
if (shouldClick) {
|
|
284
|
-
if (!isNativeButton && (isSpaceKey || isEnterKey)) {
|
|
285
|
-
event.preventDefault();
|
|
286
|
-
}
|
|
287
|
-
if (!isNativeButton && isEnterKey) {
|
|
288
|
-
externalOnClick?.(event);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
onKeyUp(event) {
|
|
293
|
-
if (disabled) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
|
|
298
|
-
// https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
|
|
299
|
-
useRenderElement.makeEventPreventable(event);
|
|
300
|
-
externalOnKeyUp?.(event);
|
|
301
|
-
if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
|
|
302
|
-
event.preventDefault();
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
if (event.baseUIHandlerPrevented) {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Keyboard accessibility for non interactive elements
|
|
310
|
-
if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
|
|
311
|
-
externalOnClick?.(event);
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
onPointerDown(event) {
|
|
315
|
-
if (disabled) {
|
|
316
|
-
event.preventDefault();
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
externalOnPointerDown?.(event);
|
|
320
|
-
}
|
|
321
|
-
}, !isNativeButton ? {
|
|
322
|
-
role: 'button'
|
|
323
|
-
} : undefined, focusableWhenDisabledProps, otherExternalProps);
|
|
324
|
-
}, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
|
|
325
|
-
const buttonRef = useStableCallback(element => {
|
|
326
|
-
elementRef.current = element;
|
|
327
|
-
updateDisabled();
|
|
328
|
-
});
|
|
329
|
-
return {
|
|
330
|
-
getButtonProps,
|
|
331
|
-
buttonRef
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function isButtonElement(elem) {
|
|
335
|
-
return floatingUi_utils_dom.isHTMLElement(elem) && elem.tagName === 'BUTTON';
|
|
336
|
-
}
|
|
337
|
-
function isValidLinkElement(elem) {
|
|
338
|
-
return Boolean(elem?.tagName === 'A' && elem?.href);
|
|
196
|
+
this.callbacks[index] = null;
|
|
197
|
+
this.callbacksCount -= 1;
|
|
198
|
+
}
|
|
339
199
|
}
|
|
200
|
+
const scheduler = new Scheduler();
|
|
201
|
+
class AnimationFrame {
|
|
202
|
+
static create() {
|
|
203
|
+
return new AnimationFrame();
|
|
204
|
+
}
|
|
205
|
+
static request(fn) {
|
|
206
|
+
return scheduler.request(fn);
|
|
207
|
+
}
|
|
208
|
+
static cancel(id) {
|
|
209
|
+
return scheduler.cancel(id);
|
|
210
|
+
}
|
|
211
|
+
currentId = EMPTY$1;
|
|
340
212
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const inputPress = 'input-press';
|
|
357
|
-
const focusOut = 'focus-out';
|
|
358
|
-
const escapeKey = 'escape-key';
|
|
359
|
-
const closeWatcher = 'close-watcher';
|
|
360
|
-
const listNavigation = 'list-navigation';
|
|
361
|
-
const keyboard = 'keyboard';
|
|
362
|
-
const scrub = 'scrub';
|
|
363
|
-
const cancelOpen = 'cancel-open';
|
|
364
|
-
const siblingOpen = 'sibling-open';
|
|
365
|
-
const imperativeAction = 'imperative-action';
|
|
366
|
-
const swipe = 'swipe';
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Maps a change `reason` string to the corresponding native event type.
|
|
370
|
-
*/
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Details of custom change events emitted by Base UI components.
|
|
374
|
-
*/
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Details of custom generic events emitted by Base UI components.
|
|
378
|
-
*/
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Creates a Base UI event details object with the given reason and utilities
|
|
382
|
-
* for preventing Base UI's internal event handling.
|
|
383
|
-
*/
|
|
384
|
-
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
385
|
-
let canceled = false;
|
|
386
|
-
let allowPropagation = false;
|
|
387
|
-
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
388
|
-
const details = {
|
|
389
|
-
reason,
|
|
390
|
-
event: event ?? new Event('base-ui'),
|
|
391
|
-
cancel() {
|
|
392
|
-
canceled = true;
|
|
393
|
-
},
|
|
394
|
-
allowPropagation() {
|
|
395
|
-
allowPropagation = true;
|
|
396
|
-
},
|
|
397
|
-
get isCanceled() {
|
|
398
|
-
return canceled;
|
|
399
|
-
},
|
|
400
|
-
get isPropagationAllowed() {
|
|
401
|
-
return allowPropagation;
|
|
402
|
-
},
|
|
403
|
-
trigger,
|
|
404
|
-
...custom
|
|
213
|
+
/**
|
|
214
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
215
|
+
*/
|
|
216
|
+
request(fn) {
|
|
217
|
+
this.cancel();
|
|
218
|
+
this.currentId = scheduler.request(() => {
|
|
219
|
+
this.currentId = EMPTY$1;
|
|
220
|
+
fn();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
cancel = () => {
|
|
224
|
+
if (this.currentId !== EMPTY$1) {
|
|
225
|
+
scheduler.cancel(this.currentId);
|
|
226
|
+
this.currentId = EMPTY$1;
|
|
227
|
+
}
|
|
405
228
|
};
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
function createGenericEventDetails(reason, event, customProperties) {
|
|
409
|
-
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
410
|
-
const details = {
|
|
411
|
-
reason,
|
|
412
|
-
event: event ?? new Event('base-ui'),
|
|
413
|
-
...custom
|
|
229
|
+
disposeEffect = () => {
|
|
230
|
+
return this.cancel;
|
|
414
231
|
};
|
|
415
|
-
return details;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
let globalId = 0;
|
|
419
|
-
|
|
420
|
-
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
421
|
-
function useGlobalId(idOverride, prefix = 'mui') {
|
|
422
|
-
const [defaultId, setDefaultId] = React__namespace.useState(idOverride);
|
|
423
|
-
const id = idOverride || defaultId;
|
|
424
|
-
React__namespace.useEffect(() => {
|
|
425
|
-
if (defaultId == null) {
|
|
426
|
-
// Fallback to this default id when possible.
|
|
427
|
-
// Use the incrementing value for client-side rendering only.
|
|
428
|
-
// We can't use it server-side.
|
|
429
|
-
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
430
|
-
globalId += 1;
|
|
431
|
-
setDefaultId(`${prefix}-${globalId}`);
|
|
432
|
-
}
|
|
433
|
-
}, [defaultId, prefix]);
|
|
434
|
-
return id;
|
|
435
|
-
}
|
|
436
|
-
const maybeReactUseId = SafeReact.useId;
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
*
|
|
440
|
-
* @example <div id={useId()} />
|
|
441
|
-
* @param idOverride
|
|
442
|
-
* @returns {string}
|
|
443
|
-
*/
|
|
444
|
-
function useId(idOverride, prefix) {
|
|
445
|
-
// React.useId() is only available from React 17.0.0.
|
|
446
|
-
if (maybeReactUseId !== undefined) {
|
|
447
|
-
const reactId = maybeReactUseId();
|
|
448
|
-
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
452
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
453
|
-
return useGlobalId(idOverride, prefix);
|
|
454
232
|
}
|
|
455
233
|
|
|
456
234
|
/**
|
|
457
|
-
*
|
|
458
|
-
* @param {string | undefined} idOverride overrides the generated id when provided
|
|
459
|
-
* @returns {string | undefined}
|
|
460
|
-
*/
|
|
461
|
-
function useBaseUiId(idOverride) {
|
|
462
|
-
return useId(idOverride, 'base-ui');
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const EMPTY$2 = [];
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
235
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
469
236
|
*/
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
/* eslint-enable react-hooks/exhaustive-deps */
|
|
237
|
+
function useAnimationFrame() {
|
|
238
|
+
const timeout = useRenderElement.useRefWithInit(AnimationFrame.create).current;
|
|
239
|
+
useOnMount(timeout.disposeEffect);
|
|
240
|
+
return timeout;
|
|
475
241
|
}
|
|
476
242
|
|
|
477
|
-
const EMPTY
|
|
243
|
+
const EMPTY = 0;
|
|
478
244
|
class Timeout {
|
|
479
245
|
static create() {
|
|
480
246
|
return new Timeout();
|
|
481
247
|
}
|
|
482
|
-
currentId = EMPTY
|
|
248
|
+
currentId = EMPTY;
|
|
483
249
|
|
|
484
250
|
/**
|
|
485
251
|
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
@@ -487,17 +253,17 @@ class Timeout {
|
|
|
487
253
|
start(delay, fn) {
|
|
488
254
|
this.clear();
|
|
489
255
|
this.currentId = setTimeout(() => {
|
|
490
|
-
this.currentId = EMPTY
|
|
256
|
+
this.currentId = EMPTY;
|
|
491
257
|
fn();
|
|
492
258
|
}, delay); /* Node.js types are enabled in development */
|
|
493
259
|
}
|
|
494
260
|
isStarted() {
|
|
495
|
-
return this.currentId !== EMPTY
|
|
261
|
+
return this.currentId !== EMPTY;
|
|
496
262
|
}
|
|
497
263
|
clear = () => {
|
|
498
|
-
if (this.currentId !== EMPTY
|
|
264
|
+
if (this.currentId !== EMPTY) {
|
|
499
265
|
clearTimeout(this.currentId);
|
|
500
|
-
this.currentId = EMPTY
|
|
266
|
+
this.currentId = EMPTY;
|
|
501
267
|
}
|
|
502
268
|
};
|
|
503
269
|
disposeEffect = () => {
|
|
@@ -514,6 +280,30 @@ function useTimeout() {
|
|
|
514
280
|
return timeout;
|
|
515
281
|
}
|
|
516
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Untracks the provided value by turning it into a ref to remove its reactivity.
|
|
285
|
+
*
|
|
286
|
+
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
287
|
+
*/
|
|
288
|
+
function useValueAsRef(value) {
|
|
289
|
+
const latest = useRenderElement.useRefWithInit(createLatestRef, value).current;
|
|
290
|
+
latest.next = value;
|
|
291
|
+
|
|
292
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
293
|
+
useIsoLayoutEffect(latest.effect);
|
|
294
|
+
return latest;
|
|
295
|
+
}
|
|
296
|
+
function createLatestRef(value) {
|
|
297
|
+
const latest = {
|
|
298
|
+
current: value,
|
|
299
|
+
next: value,
|
|
300
|
+
effect: () => {
|
|
301
|
+
latest.current = latest.next;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
return latest;
|
|
305
|
+
}
|
|
306
|
+
|
|
517
307
|
const hasNavigator = typeof navigator !== 'undefined';
|
|
518
308
|
const nav = getNavigatorData();
|
|
519
309
|
const platform = getPlatform();
|
|
@@ -616,153 +406,126 @@ function ownerDocument(node) {
|
|
|
616
406
|
return node?.ownerDocument || document;
|
|
617
407
|
}
|
|
618
408
|
|
|
409
|
+
const none = 'none';
|
|
410
|
+
const triggerPress = 'trigger-press';
|
|
411
|
+
const triggerHover = 'trigger-hover';
|
|
412
|
+
const triggerFocus = 'trigger-focus';
|
|
413
|
+
const outsidePress = 'outside-press';
|
|
414
|
+
const itemPress = 'item-press';
|
|
415
|
+
const closePress = 'close-press';
|
|
416
|
+
const clearPress = 'clear-press';
|
|
417
|
+
const chipRemovePress = 'chip-remove-press';
|
|
418
|
+
const incrementPress = 'increment-press';
|
|
419
|
+
const decrementPress = 'decrement-press';
|
|
420
|
+
const inputChange = 'input-change';
|
|
421
|
+
const inputClear = 'input-clear';
|
|
422
|
+
const inputBlur = 'input-blur';
|
|
423
|
+
const inputPaste = 'input-paste';
|
|
424
|
+
const inputPress = 'input-press';
|
|
425
|
+
const focusOut = 'focus-out';
|
|
426
|
+
const escapeKey = 'escape-key';
|
|
427
|
+
const closeWatcher = 'close-watcher';
|
|
428
|
+
const listNavigation = 'list-navigation';
|
|
429
|
+
const keyboard = 'keyboard';
|
|
430
|
+
const pointer = 'pointer';
|
|
431
|
+
const scrub = 'scrub';
|
|
432
|
+
const cancelOpen = 'cancel-open';
|
|
433
|
+
const siblingOpen = 'sibling-open';
|
|
434
|
+
const imperativeAction = 'imperative-action';
|
|
435
|
+
const swipe = 'swipe';
|
|
436
|
+
|
|
619
437
|
/**
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
438
|
+
* Maps a change `reason` string to the corresponding native event type.
|
|
623
439
|
*/
|
|
624
|
-
function useValueAsRef(value) {
|
|
625
|
-
const latest = useRenderElement.useRefWithInit(createLatestRef, value).current;
|
|
626
|
-
latest.next = value;
|
|
627
440
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
632
|
-
function createLatestRef(value) {
|
|
633
|
-
const latest = {
|
|
634
|
-
current: value,
|
|
635
|
-
next: value,
|
|
636
|
-
effect: () => {
|
|
637
|
-
latest.current = latest.next;
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
return latest;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
644
|
-
* a monomorphic `uint` type with `0` meaning empty.
|
|
645
|
-
* See warning note at:
|
|
646
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
647
|
-
const EMPTY = null;
|
|
648
|
-
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
649
|
-
class Scheduler {
|
|
650
|
-
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
651
|
-
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
652
|
-
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
653
|
-
* be much more efficient if there is a call pattern that alterns as
|
|
654
|
-
* "request-cancel-request-cancel-…".
|
|
655
|
-
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
656
|
-
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
441
|
+
/**
|
|
442
|
+
* Details of custom change events emitted by Base UI components.
|
|
443
|
+
*/
|
|
657
444
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
startId = 1;
|
|
662
|
-
isScheduled = false;
|
|
663
|
-
tick = timestamp => {
|
|
664
|
-
this.isScheduled = false;
|
|
665
|
-
const currentCallbacks = this.callbacks;
|
|
666
|
-
const currentCallbacksCount = this.callbacksCount;
|
|
445
|
+
/**
|
|
446
|
+
* Details of custom generic events emitted by Base UI components.
|
|
447
|
+
*/
|
|
667
448
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
449
|
+
/**
|
|
450
|
+
* Creates a Base UI event details object with the given reason and utilities
|
|
451
|
+
* for preventing Base UI's internal event handling.
|
|
452
|
+
*/
|
|
453
|
+
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
454
|
+
let canceled = false;
|
|
455
|
+
let allowPropagation = false;
|
|
456
|
+
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
457
|
+
const details = {
|
|
458
|
+
reason,
|
|
459
|
+
event: event ?? new Event('base-ui'),
|
|
460
|
+
cancel() {
|
|
461
|
+
canceled = true;
|
|
462
|
+
},
|
|
463
|
+
allowPropagation() {
|
|
464
|
+
allowPropagation = true;
|
|
465
|
+
},
|
|
466
|
+
get isCanceled() {
|
|
467
|
+
return canceled;
|
|
468
|
+
},
|
|
469
|
+
get isPropagationAllowed() {
|
|
470
|
+
return allowPropagation;
|
|
471
|
+
},
|
|
472
|
+
trigger,
|
|
473
|
+
...custom
|
|
677
474
|
};
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (!this.isScheduled || didRAFChange) {
|
|
689
|
-
requestAnimationFrame(this.tick);
|
|
690
|
-
this.isScheduled = true;
|
|
691
|
-
}
|
|
692
|
-
return id;
|
|
693
|
-
}
|
|
694
|
-
cancel(id) {
|
|
695
|
-
const index = id - this.startId;
|
|
696
|
-
if (index < 0 || index >= this.callbacks.length) {
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
this.callbacks[index] = null;
|
|
700
|
-
this.callbacksCount -= 1;
|
|
701
|
-
}
|
|
475
|
+
return details;
|
|
476
|
+
}
|
|
477
|
+
function createGenericEventDetails(reason, event, customProperties) {
|
|
478
|
+
const custom = customProperties ?? useRenderElement.EMPTY_OBJECT;
|
|
479
|
+
const details = {
|
|
480
|
+
reason,
|
|
481
|
+
event: event ?? new Event('base-ui'),
|
|
482
|
+
...custom
|
|
483
|
+
};
|
|
484
|
+
return details;
|
|
702
485
|
}
|
|
703
|
-
const scheduler = new Scheduler();
|
|
704
|
-
class AnimationFrame {
|
|
705
|
-
static create() {
|
|
706
|
-
return new AnimationFrame();
|
|
707
|
-
}
|
|
708
|
-
static request(fn) {
|
|
709
|
-
return scheduler.request(fn);
|
|
710
|
-
}
|
|
711
|
-
static cancel(id) {
|
|
712
|
-
return scheduler.cancel(id);
|
|
713
|
-
}
|
|
714
|
-
currentId = EMPTY;
|
|
715
486
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
this
|
|
487
|
+
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
488
|
+
const SafeReact = {
|
|
489
|
+
...React__namespace
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
let globalId = 0;
|
|
493
|
+
|
|
494
|
+
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
495
|
+
function useGlobalId(idOverride, prefix = 'mui') {
|
|
496
|
+
const [defaultId, setDefaultId] = React__namespace.useState(idOverride);
|
|
497
|
+
const id = idOverride || defaultId;
|
|
498
|
+
React__namespace.useEffect(() => {
|
|
499
|
+
if (defaultId == null) {
|
|
500
|
+
// Fallback to this default id when possible.
|
|
501
|
+
// Use the incrementing value for client-side rendering only.
|
|
502
|
+
// We can't use it server-side.
|
|
503
|
+
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
504
|
+
globalId += 1;
|
|
505
|
+
setDefaultId(`${prefix}-${globalId}`);
|
|
730
506
|
}
|
|
731
|
-
};
|
|
732
|
-
|
|
733
|
-
return this.cancel;
|
|
734
|
-
};
|
|
507
|
+
}, [defaultId, prefix]);
|
|
508
|
+
return id;
|
|
735
509
|
}
|
|
510
|
+
const maybeReactUseId = SafeReact.useId;
|
|
736
511
|
|
|
737
512
|
/**
|
|
738
|
-
*
|
|
513
|
+
*
|
|
514
|
+
* @example <div id={useId()} />
|
|
515
|
+
* @param idOverride
|
|
516
|
+
* @returns {string}
|
|
739
517
|
*/
|
|
740
|
-
function
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
518
|
+
function useId(idOverride, prefix) {
|
|
519
|
+
// React.useId() is only available from React 17.0.0.
|
|
520
|
+
if (maybeReactUseId !== undefined) {
|
|
521
|
+
const reactId = maybeReactUseId();
|
|
522
|
+
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
523
|
+
}
|
|
745
524
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
border: 0,
|
|
751
|
-
padding: 0,
|
|
752
|
-
width: 1,
|
|
753
|
-
height: 1,
|
|
754
|
-
margin: -1
|
|
755
|
-
};
|
|
756
|
-
const visuallyHidden = {
|
|
757
|
-
...visuallyHiddenBase,
|
|
758
|
-
position: 'fixed',
|
|
759
|
-
top: 0,
|
|
760
|
-
left: 0
|
|
761
|
-
};
|
|
762
|
-
const visuallyHiddenInput = {
|
|
763
|
-
...visuallyHiddenBase,
|
|
764
|
-
position: 'absolute'
|
|
765
|
-
};
|
|
525
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
526
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
527
|
+
return useGlobalId(idOverride, prefix);
|
|
528
|
+
}
|
|
766
529
|
|
|
767
530
|
/**
|
|
768
531
|
* If the provided argument is a ref object, returns its `current` value.
|
|
@@ -838,6 +601,35 @@ function useTransitionStatus(open, enableIdleState = false, deferEndingState = f
|
|
|
838
601
|
}), [mounted, transitionStatus]);
|
|
839
602
|
}
|
|
840
603
|
|
|
604
|
+
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
605
|
+
/**
|
|
606
|
+
* Present when the component is animating in.
|
|
607
|
+
*/
|
|
608
|
+
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
609
|
+
/**
|
|
610
|
+
* Present when the component is animating out.
|
|
611
|
+
*/
|
|
612
|
+
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
613
|
+
return TransitionStatusDataAttributes;
|
|
614
|
+
}({});
|
|
615
|
+
const STARTING_HOOK = {
|
|
616
|
+
[TransitionStatusDataAttributes.startingStyle]: ''
|
|
617
|
+
};
|
|
618
|
+
const ENDING_HOOK = {
|
|
619
|
+
[TransitionStatusDataAttributes.endingStyle]: ''
|
|
620
|
+
};
|
|
621
|
+
const transitionStatusMapping = {
|
|
622
|
+
transitionStatus(value) {
|
|
623
|
+
if (value === 'starting') {
|
|
624
|
+
return STARTING_HOOK;
|
|
625
|
+
}
|
|
626
|
+
if (value === 'ending') {
|
|
627
|
+
return ENDING_HOOK;
|
|
628
|
+
}
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
|
|
841
633
|
/**
|
|
842
634
|
* Executes a function once all animations have finished on the provided element.
|
|
843
635
|
* @param elementOrRef - The element to watch for animations.
|
|
@@ -914,91 +706,300 @@ function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false
|
|
|
914
706
|
}
|
|
915
707
|
});
|
|
916
708
|
}
|
|
917
|
-
if (waitForStartingStyleRemoved) {
|
|
918
|
-
execWaitForStartingStyleRemoved();
|
|
919
|
-
return;
|
|
709
|
+
if (waitForStartingStyleRemoved) {
|
|
710
|
+
execWaitForStartingStyleRemoved();
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
frame.request(exec);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Calls the provided function when the CSS open/close animation or transition completes.
|
|
720
|
+
*/
|
|
721
|
+
function useOpenChangeComplete(parameters) {
|
|
722
|
+
const {
|
|
723
|
+
enabled = true,
|
|
724
|
+
open,
|
|
725
|
+
ref,
|
|
726
|
+
onComplete: onCompleteParam
|
|
727
|
+
} = parameters;
|
|
728
|
+
const onComplete = useStableCallback(onCompleteParam);
|
|
729
|
+
const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
|
|
730
|
+
React__namespace.useEffect(() => {
|
|
731
|
+
if (!enabled) {
|
|
732
|
+
return undefined;
|
|
733
|
+
}
|
|
734
|
+
const abortController = new AbortController();
|
|
735
|
+
runOnceAnimationsFinish(onComplete, abortController.signal);
|
|
736
|
+
return () => {
|
|
737
|
+
abortController.abort();
|
|
738
|
+
};
|
|
739
|
+
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Wraps `useId` and prefixes generated `id`s with `base-ui-`
|
|
744
|
+
* @param {string | undefined} idOverride overrides the generated id when provided
|
|
745
|
+
* @returns {string | undefined}
|
|
746
|
+
*/
|
|
747
|
+
function useBaseUiId(idOverride) {
|
|
748
|
+
return useId(idOverride, 'base-ui');
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function useValueChanged(value, onChange) {
|
|
752
|
+
const valueRef = React__namespace.useRef(value);
|
|
753
|
+
const onChangeCallback = useStableCallback(onChange);
|
|
754
|
+
useIsoLayoutEffect(() => {
|
|
755
|
+
if (valueRef.current === value) {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
onChangeCallback(valueRef.current);
|
|
759
|
+
}, [value, onChangeCallback]);
|
|
760
|
+
useIsoLayoutEffect(() => {
|
|
761
|
+
valueRef.current = value;
|
|
762
|
+
}, [value]);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
let set;
|
|
766
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
767
|
+
set = new Set();
|
|
768
|
+
}
|
|
769
|
+
function error(...messages) {
|
|
770
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
771
|
+
const messageKey = messages.join(' ');
|
|
772
|
+
if (!set.has(messageKey)) {
|
|
773
|
+
set.add(messageKey);
|
|
774
|
+
console.error(`Base UI: ${messageKey}`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const CompositeRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
780
|
+
if (process.env.NODE_ENV !== "production") CompositeRootContext.displayName = "CompositeRootContext";
|
|
781
|
+
function useCompositeRootContext(optional = false) {
|
|
782
|
+
const context = React__namespace.useContext(CompositeRootContext);
|
|
783
|
+
if (context === undefined && !optional) {
|
|
784
|
+
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.' : useRenderElement.formatErrorMessage(16));
|
|
785
|
+
}
|
|
786
|
+
return context;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function useFocusableWhenDisabled(parameters) {
|
|
790
|
+
const {
|
|
791
|
+
focusableWhenDisabled,
|
|
792
|
+
disabled,
|
|
793
|
+
composite = false,
|
|
794
|
+
tabIndex: tabIndexProp = 0,
|
|
795
|
+
isNativeButton
|
|
796
|
+
} = parameters;
|
|
797
|
+
const isFocusableComposite = composite && focusableWhenDisabled !== false;
|
|
798
|
+
const isNonFocusableComposite = composite && focusableWhenDisabled === false;
|
|
799
|
+
|
|
800
|
+
// we can't explicitly assign `undefined` to any of these props because it
|
|
801
|
+
// would otherwise prevent subsequently merged props from setting them
|
|
802
|
+
const props = React__namespace.useMemo(() => {
|
|
803
|
+
const additionalProps = {
|
|
804
|
+
// allow Tabbing away from focusableWhenDisabled elements
|
|
805
|
+
onKeyDown(event) {
|
|
806
|
+
if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
|
|
807
|
+
event.preventDefault();
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
if (!composite) {
|
|
812
|
+
additionalProps.tabIndex = tabIndexProp;
|
|
813
|
+
if (!isNativeButton && disabled) {
|
|
814
|
+
additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1;
|
|
920
815
|
}
|
|
921
|
-
frame.request(exec);
|
|
922
816
|
}
|
|
923
|
-
|
|
817
|
+
if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
|
|
818
|
+
additionalProps['aria-disabled'] = disabled;
|
|
819
|
+
}
|
|
820
|
+
if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
|
|
821
|
+
additionalProps.disabled = disabled;
|
|
822
|
+
}
|
|
823
|
+
return additionalProps;
|
|
824
|
+
}, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
|
|
825
|
+
return {
|
|
826
|
+
props
|
|
827
|
+
};
|
|
924
828
|
}
|
|
925
829
|
|
|
926
|
-
|
|
927
|
-
* Calls the provided function when the CSS open/close animation or transition completes.
|
|
928
|
-
*/
|
|
929
|
-
function useOpenChangeComplete(parameters) {
|
|
830
|
+
function useButton(parameters = {}) {
|
|
930
831
|
const {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
832
|
+
disabled = false,
|
|
833
|
+
focusableWhenDisabled,
|
|
834
|
+
tabIndex = 0,
|
|
835
|
+
native: isNativeButton = true,
|
|
836
|
+
composite: compositeProp
|
|
935
837
|
} = parameters;
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
if (!enabled) {
|
|
940
|
-
return undefined;
|
|
941
|
-
}
|
|
942
|
-
const abortController = new AbortController();
|
|
943
|
-
runOnceAnimationsFinish(onComplete, abortController.signal);
|
|
944
|
-
return () => {
|
|
945
|
-
abortController.abort();
|
|
946
|
-
};
|
|
947
|
-
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
951
|
-
return Math.max(min, Math.min(val, max));
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
function useControlled({
|
|
955
|
-
controlled,
|
|
956
|
-
default: defaultProp,
|
|
957
|
-
name,
|
|
958
|
-
state = 'value'
|
|
959
|
-
}) {
|
|
960
|
-
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
838
|
+
const elementRef = React__namespace.useRef(null);
|
|
839
|
+
const compositeRootContext = useCompositeRootContext(true);
|
|
840
|
+
const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
|
|
961
841
|
const {
|
|
962
|
-
|
|
963
|
-
} =
|
|
964
|
-
|
|
965
|
-
|
|
842
|
+
props: focusableWhenDisabledProps
|
|
843
|
+
} = useFocusableWhenDisabled({
|
|
844
|
+
focusableWhenDisabled,
|
|
845
|
+
disabled,
|
|
846
|
+
composite: isCompositeItem,
|
|
847
|
+
tabIndex,
|
|
848
|
+
isNativeButton
|
|
849
|
+
});
|
|
966
850
|
if (process.env.NODE_ENV !== 'production') {
|
|
851
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
967
852
|
React__namespace.useEffect(() => {
|
|
968
|
-
if (
|
|
969
|
-
|
|
853
|
+
if (!elementRef.current) {
|
|
854
|
+
return;
|
|
970
855
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
856
|
+
const isButtonTag = isButtonElement(elementRef.current);
|
|
857
|
+
if (isNativeButton) {
|
|
858
|
+
if (!isButtonTag) {
|
|
859
|
+
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
860
|
+
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`.';
|
|
861
|
+
error(`${message}${ownerStackMessage}`);
|
|
862
|
+
}
|
|
863
|
+
} else if (isButtonTag) {
|
|
864
|
+
const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
|
|
865
|
+
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`.';
|
|
866
|
+
error(`${message}${ownerStackMessage}`);
|
|
979
867
|
}
|
|
980
|
-
}, [
|
|
868
|
+
}, [isNativeButton]);
|
|
981
869
|
}
|
|
982
|
-
const setValueIfUncontrolled = React__namespace.useCallback(newValue => {
|
|
983
|
-
if (!isControlled) {
|
|
984
|
-
setValue(newValue);
|
|
985
|
-
}
|
|
986
|
-
}, []);
|
|
987
|
-
return [value, setValueIfUncontrolled];
|
|
988
|
-
}
|
|
989
870
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
871
|
+
// handles a disabled composite button rendering another button, e.g.
|
|
872
|
+
// <Toolbar.Button disabled render={<Menu.Trigger />} />
|
|
873
|
+
// the `disabled` prop needs to pass through 2 `useButton`s then finally
|
|
874
|
+
// delete the `disabled` attribute from DOM
|
|
875
|
+
const updateDisabled = React__namespace.useCallback(() => {
|
|
876
|
+
const element = elementRef.current;
|
|
877
|
+
if (!isButtonElement(element)) {
|
|
995
878
|
return;
|
|
996
879
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
880
|
+
if (isCompositeItem && disabled && focusableWhenDisabledProps.disabled === undefined && element.disabled) {
|
|
881
|
+
element.disabled = false;
|
|
882
|
+
}
|
|
883
|
+
}, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
|
|
884
|
+
useIsoLayoutEffect(updateDisabled, [updateDisabled]);
|
|
885
|
+
const getButtonProps = React__namespace.useCallback((externalProps = {}) => {
|
|
886
|
+
const {
|
|
887
|
+
onClick: externalOnClick,
|
|
888
|
+
onMouseDown: externalOnMouseDown,
|
|
889
|
+
onKeyUp: externalOnKeyUp,
|
|
890
|
+
onKeyDown: externalOnKeyDown,
|
|
891
|
+
onPointerDown: externalOnPointerDown,
|
|
892
|
+
...otherExternalProps
|
|
893
|
+
} = externalProps;
|
|
894
|
+
const type = isNativeButton ? 'button' : undefined;
|
|
895
|
+
return useRenderElement.mergeProps({
|
|
896
|
+
type,
|
|
897
|
+
onClick(event) {
|
|
898
|
+
if (disabled) {
|
|
899
|
+
event.preventDefault();
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
externalOnClick?.(event);
|
|
903
|
+
},
|
|
904
|
+
onMouseDown(event) {
|
|
905
|
+
if (!disabled) {
|
|
906
|
+
externalOnMouseDown?.(event);
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
onKeyDown(event) {
|
|
910
|
+
if (disabled) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
useRenderElement.makeEventPreventable(event);
|
|
914
|
+
externalOnKeyDown?.(event);
|
|
915
|
+
if (event.baseUIHandlerPrevented) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const isCurrentTarget = event.target === event.currentTarget;
|
|
919
|
+
const currentTarget = event.currentTarget;
|
|
920
|
+
const isButton = isButtonElement(currentTarget);
|
|
921
|
+
const isLink = !isNativeButton && isValidLinkElement(currentTarget);
|
|
922
|
+
const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
|
|
923
|
+
const isEnterKey = event.key === 'Enter';
|
|
924
|
+
const isSpaceKey = event.key === ' ';
|
|
925
|
+
const role = currentTarget.getAttribute('role');
|
|
926
|
+
const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
|
|
927
|
+
if (isCurrentTarget && isCompositeItem && isSpaceKey) {
|
|
928
|
+
if (event.defaultPrevented && isTextNavigationRole) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
event.preventDefault();
|
|
932
|
+
if (isLink || isNativeButton && isButton) {
|
|
933
|
+
currentTarget.click();
|
|
934
|
+
event.preventBaseUIHandler();
|
|
935
|
+
} else if (shouldClick) {
|
|
936
|
+
externalOnClick?.(event);
|
|
937
|
+
event.preventBaseUIHandler();
|
|
938
|
+
}
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// Keyboard accessibility for native and non-native elements.
|
|
943
|
+
if (shouldClick) {
|
|
944
|
+
if (!isNativeButton && (isSpaceKey || isEnterKey)) {
|
|
945
|
+
event.preventDefault();
|
|
946
|
+
}
|
|
947
|
+
if (!isNativeButton && isEnterKey) {
|
|
948
|
+
externalOnClick?.(event);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
},
|
|
952
|
+
onKeyUp(event) {
|
|
953
|
+
if (disabled) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
|
|
958
|
+
// https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
|
|
959
|
+
useRenderElement.makeEventPreventable(event);
|
|
960
|
+
externalOnKeyUp?.(event);
|
|
961
|
+
if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
|
|
962
|
+
event.preventDefault();
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
if (event.baseUIHandlerPrevented) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Keyboard accessibility for non interactive elements
|
|
970
|
+
if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
|
|
971
|
+
externalOnClick?.(event);
|
|
972
|
+
}
|
|
973
|
+
},
|
|
974
|
+
onPointerDown(event) {
|
|
975
|
+
if (disabled) {
|
|
976
|
+
event.preventDefault();
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
externalOnPointerDown?.(event);
|
|
980
|
+
}
|
|
981
|
+
}, !isNativeButton ? {
|
|
982
|
+
role: 'button'
|
|
983
|
+
} : undefined, focusableWhenDisabledProps, otherExternalProps);
|
|
984
|
+
}, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
|
|
985
|
+
const buttonRef = useStableCallback(element => {
|
|
986
|
+
elementRef.current = element;
|
|
987
|
+
updateDisabled();
|
|
988
|
+
});
|
|
989
|
+
return {
|
|
990
|
+
getButtonProps,
|
|
991
|
+
buttonRef
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
function isButtonElement(elem) {
|
|
995
|
+
return floatingUi_utils_dom.isHTMLElement(elem) && elem.tagName === 'BUTTON';
|
|
996
|
+
}
|
|
997
|
+
function isValidLinkElement(elem) {
|
|
998
|
+
return Boolean(elem?.tagName === 'A' && elem?.href);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
1002
|
+
return Math.max(min, Math.min(val, max));
|
|
1002
1003
|
}
|
|
1003
1004
|
|
|
1004
1005
|
exports.AnimationFrame = AnimationFrame;
|
|
@@ -1042,6 +1043,7 @@ exports.listNavigation = listNavigation;
|
|
|
1042
1043
|
exports.none = none;
|
|
1043
1044
|
exports.outsidePress = outsidePress;
|
|
1044
1045
|
exports.ownerDocument = ownerDocument;
|
|
1046
|
+
exports.pointer = pointer;
|
|
1045
1047
|
exports.resolveRef = resolveRef;
|
|
1046
1048
|
exports.scrub = scrub;
|
|
1047
1049
|
exports.siblingOpen = siblingOpen;
|