@jobber/components 7.10.0 → 7.11.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/Autocomplete/index.cjs +1 -0
- package/dist/Autocomplete/index.mjs +1 -0
- package/dist/Card/index.cjs +3 -0
- package/dist/Card/index.mjs +3 -0
- package/dist/Chip/index.cjs +1 -0
- package/dist/Chip/index.mjs +1 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.cjs +1 -0
- package/dist/Chips/InternalChipDismissible/hooks/index.mjs +1 -0
- package/dist/Chips/InternalChipDismissible/index.cjs +1 -0
- package/dist/Chips/InternalChipDismissible/index.mjs +1 -0
- package/dist/Chips/index.cjs +1 -0
- package/dist/Chips/index.mjs +1 -0
- package/dist/Combobox/components/ComboboxActivator/index.cjs +1 -0
- package/dist/Combobox/components/ComboboxActivator/index.mjs +1 -0
- package/dist/Combobox/components/ComboboxContent/index.cjs +1 -0
- package/dist/Combobox/components/ComboboxContent/index.mjs +1 -0
- package/dist/Combobox/components/ComboboxTrigger/index.cjs +1 -0
- package/dist/Combobox/components/ComboboxTrigger/index.mjs +1 -0
- package/dist/Combobox/index.cjs +1 -0
- package/dist/Combobox/index.mjs +1 -0
- package/dist/ConfirmationModal/index.cjs +1 -0
- package/dist/ConfirmationModal/index.mjs +1 -0
- package/dist/DataDump/index.cjs +3 -0
- package/dist/DataDump/index.mjs +3 -0
- package/dist/DataList/components/DataListActions/index.cjs +1 -0
- package/dist/DataList/components/DataListActions/index.mjs +1 -0
- package/dist/DataList/components/DataListBulkActions/index.cjs +1 -0
- package/dist/DataList/components/DataListBulkActions/index.mjs +1 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +1 -0
- package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +1 -0
- package/dist/DataList/components/DataListFilters/index.cjs +1 -0
- package/dist/DataList/components/DataListFilters/index.mjs +1 -0
- package/dist/DataList/components/DataListHeader/index.cjs +1 -0
- package/dist/DataList/components/DataListHeader/index.mjs +1 -0
- package/dist/DataList/components/DataListItem/index.cjs +1 -0
- package/dist/DataList/components/DataListItem/index.mjs +1 -0
- package/dist/DataList/components/DataListItemActions/index.cjs +1 -0
- package/dist/DataList/components/DataListItemActions/index.mjs +1 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +1 -0
- package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +1 -0
- package/dist/DataList/components/DataListItems/index.cjs +1 -0
- package/dist/DataList/components/DataListItems/index.mjs +1 -0
- package/dist/DataList/components/DataListLayout/index.cjs +1 -0
- package/dist/DataList/components/DataListLayout/index.mjs +1 -0
- package/dist/DataList/components/DataListLayoutActions/index.cjs +1 -0
- package/dist/DataList/components/DataListLayoutActions/index.mjs +1 -0
- package/dist/DataList/index.cjs +1 -0
- package/dist/DataList/index.mjs +1 -0
- package/dist/DatePicker/index.cjs +1 -0
- package/dist/DatePicker/index.mjs +1 -0
- package/dist/DrawerRoot-cjs.js +181 -968
- package/dist/DrawerRoot-es.js +5 -734
- package/dist/FormatFile/index.cjs +1 -0
- package/dist/FormatFile/index.mjs +1 -0
- package/dist/Gallery/index.cjs +1 -0
- package/dist/Gallery/index.mjs +1 -0
- package/dist/InputDate/index.cjs +1 -0
- package/dist/InputDate/index.mjs +1 -0
- package/dist/InputNumberExperimental-cjs.js +783 -0
- package/dist/InputNumberExperimental-es.js +763 -0
- package/dist/LightBox/index.cjs +1 -0
- package/dist/LightBox/index.mjs +1 -0
- package/dist/Menu/index.cjs +3 -0
- package/dist/Menu/index.mjs +3 -0
- package/dist/MenuSubmenuTrigger-cjs.js +202 -447
- package/dist/MenuSubmenuTrigger-es.js +7 -249
- package/dist/Modal/index.cjs +1 -0
- package/dist/Modal/index.mjs +1 -0
- package/dist/NumberFieldInput-cjs.js +1828 -0
- package/dist/NumberFieldInput-es.js +1788 -0
- package/dist/Page/index.cjs +3 -0
- package/dist/Page/index.mjs +3 -0
- package/dist/Popover/index.cjs +1 -0
- package/dist/Popover/index.mjs +1 -0
- package/dist/Tooltip/index.cjs +1 -0
- package/dist/Tooltip/index.mjs +1 -0
- package/dist/docs/Menu/Menu.md +197 -37
- package/dist/floating-ui.react-cjs.js +35 -34
- package/dist/floating-ui.react-dom-cjs.js +65 -64
- package/dist/floating-ui.react-dom-es.js +2 -1
- package/dist/floating-ui.react-es.js +2 -1
- package/dist/floating-ui.utils.dom-cjs.js +185 -0
- package/dist/floating-ui.utils.dom-es.js +165 -0
- package/dist/index.cjs +3 -0
- package/dist/index.esm-cjs.js +0 -183
- package/dist/index.esm-es.js +1 -165
- package/dist/index.mjs +3 -0
- package/dist/primitives/BottomSheet/index.cjs +3 -1
- package/dist/primitives/BottomSheet/index.mjs +3 -1
- package/dist/primitives/InputNumberExperimental/InputNumberExperimental.d.ts +20 -0
- package/dist/primitives/InputNumberExperimental/index.cjs +22 -0
- package/dist/primitives/InputNumberExperimental/index.d.ts +2 -0
- package/dist/primitives/InputNumberExperimental/index.mjs +16 -0
- package/dist/primitives/InputNumberExperimental/types.d.ts +147 -0
- package/dist/primitives/index.cjs +9 -1
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.mjs +8 -1
- package/dist/styles.css +499 -0
- package/dist/unstyledPrimitives/index.cjs +264 -2039
- package/dist/unstyledPrimitives/index.mjs +72 -1847
- package/dist/useBaseUiId-cjs.js +275 -0
- package/dist/useBaseUiId-es.js +251 -0
- package/dist/useValueChanged-cjs.js +820 -0
- package/dist/useValueChanged-es.js +736 -0
- package/package.json +2 -2
- package/rollup.config.mjs +13 -2
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
import { b as useRefWithInit, E as EMPTY_OBJECT } from './useRenderElement-es.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as ReactDOM from 'react-dom';
|
|
4
|
+
|
|
5
|
+
let TransitionStatusDataAttributes = /*#__PURE__*/function (TransitionStatusDataAttributes) {
|
|
6
|
+
/**
|
|
7
|
+
* Present when the component is animating in.
|
|
8
|
+
*/
|
|
9
|
+
TransitionStatusDataAttributes["startingStyle"] = "data-starting-style";
|
|
10
|
+
/**
|
|
11
|
+
* Present when the component is animating out.
|
|
12
|
+
*/
|
|
13
|
+
TransitionStatusDataAttributes["endingStyle"] = "data-ending-style";
|
|
14
|
+
return TransitionStatusDataAttributes;
|
|
15
|
+
}({});
|
|
16
|
+
const STARTING_HOOK = {
|
|
17
|
+
[TransitionStatusDataAttributes.startingStyle]: ''
|
|
18
|
+
};
|
|
19
|
+
const ENDING_HOOK = {
|
|
20
|
+
[TransitionStatusDataAttributes.endingStyle]: ''
|
|
21
|
+
};
|
|
22
|
+
const transitionStatusMapping = {
|
|
23
|
+
transitionStatus(value) {
|
|
24
|
+
if (value === 'starting') {
|
|
25
|
+
return STARTING_HOOK;
|
|
26
|
+
}
|
|
27
|
+
if (value === 'ending') {
|
|
28
|
+
return ENDING_HOOK;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
35
|
+
const useInsertionEffect = React[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0, -3)];
|
|
36
|
+
const useSafeInsertionEffect =
|
|
37
|
+
// React 17 doesn't have useInsertionEffect.
|
|
38
|
+
useInsertionEffect &&
|
|
39
|
+
// Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
|
|
40
|
+
useInsertionEffect !== React.useLayoutEffect ? useInsertionEffect : fn => fn();
|
|
41
|
+
/**
|
|
42
|
+
* Stabilizes the function passed so it's always the same between renders.
|
|
43
|
+
*
|
|
44
|
+
* The function becomes non-reactive to any values it captures.
|
|
45
|
+
* It can safely be passed as a dependency of `React.useMemo` and `React.useEffect` without re-triggering them if its captured values change.
|
|
46
|
+
*
|
|
47
|
+
* The function must only be called inside effects and event handlers, never during render (which throws an error).
|
|
48
|
+
*
|
|
49
|
+
* 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.
|
|
50
|
+
*/
|
|
51
|
+
function useStableCallback(callback) {
|
|
52
|
+
const stable = useRefWithInit(createStableCallback).current;
|
|
53
|
+
stable.next = callback;
|
|
54
|
+
useSafeInsertionEffect(stable.effect);
|
|
55
|
+
return stable.trampoline;
|
|
56
|
+
}
|
|
57
|
+
function createStableCallback() {
|
|
58
|
+
const stable = {
|
|
59
|
+
next: undefined,
|
|
60
|
+
callback: assertNotCalled,
|
|
61
|
+
trampoline: (...args) => stable.callback?.(...args),
|
|
62
|
+
effect: () => {
|
|
63
|
+
stable.callback = stable.next;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
return stable;
|
|
67
|
+
}
|
|
68
|
+
function assertNotCalled() {
|
|
69
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
70
|
+
throw /* minify-error-disabled */new Error('Base UI: Cannot call an event handler while rendering.');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379
|
|
75
|
+
const SafeReact = {
|
|
76
|
+
...React
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const noop = () => {};
|
|
80
|
+
const useIsoLayoutEffect = typeof document !== 'undefined' ? React.useLayoutEffect : noop;
|
|
81
|
+
|
|
82
|
+
const none = 'none';
|
|
83
|
+
const triggerPress = 'trigger-press';
|
|
84
|
+
const triggerHover = 'trigger-hover';
|
|
85
|
+
const triggerFocus = 'trigger-focus';
|
|
86
|
+
const outsidePress = 'outside-press';
|
|
87
|
+
const itemPress = 'item-press';
|
|
88
|
+
const closePress = 'close-press';
|
|
89
|
+
const clearPress = 'clear-press';
|
|
90
|
+
const chipRemovePress = 'chip-remove-press';
|
|
91
|
+
const incrementPress = 'increment-press';
|
|
92
|
+
const decrementPress = 'decrement-press';
|
|
93
|
+
const inputChange = 'input-change';
|
|
94
|
+
const inputClear = 'input-clear';
|
|
95
|
+
const inputBlur = 'input-blur';
|
|
96
|
+
const inputPaste = 'input-paste';
|
|
97
|
+
const inputPress = 'input-press';
|
|
98
|
+
const focusOut = 'focus-out';
|
|
99
|
+
const escapeKey = 'escape-key';
|
|
100
|
+
const closeWatcher = 'close-watcher';
|
|
101
|
+
const listNavigation = 'list-navigation';
|
|
102
|
+
const keyboard = 'keyboard';
|
|
103
|
+
const scrub = 'scrub';
|
|
104
|
+
const cancelOpen = 'cancel-open';
|
|
105
|
+
const siblingOpen = 'sibling-open';
|
|
106
|
+
const imperativeAction = 'imperative-action';
|
|
107
|
+
const swipe = 'swipe';
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Maps a change `reason` string to the corresponding native event type.
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Details of custom change events emitted by Base UI components.
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Details of custom generic events emitted by Base UI components.
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Creates a Base UI event details object with the given reason and utilities
|
|
123
|
+
* for preventing Base UI's internal event handling.
|
|
124
|
+
*/
|
|
125
|
+
function createChangeEventDetails(reason, event, trigger, customProperties) {
|
|
126
|
+
let canceled = false;
|
|
127
|
+
let allowPropagation = false;
|
|
128
|
+
const custom = customProperties ?? EMPTY_OBJECT;
|
|
129
|
+
const details = {
|
|
130
|
+
reason,
|
|
131
|
+
event: event ?? new Event('base-ui'),
|
|
132
|
+
cancel() {
|
|
133
|
+
canceled = true;
|
|
134
|
+
},
|
|
135
|
+
allowPropagation() {
|
|
136
|
+
allowPropagation = true;
|
|
137
|
+
},
|
|
138
|
+
get isCanceled() {
|
|
139
|
+
return canceled;
|
|
140
|
+
},
|
|
141
|
+
get isPropagationAllowed() {
|
|
142
|
+
return allowPropagation;
|
|
143
|
+
},
|
|
144
|
+
trigger,
|
|
145
|
+
...custom
|
|
146
|
+
};
|
|
147
|
+
return details;
|
|
148
|
+
}
|
|
149
|
+
function createGenericEventDetails(reason, event, customProperties) {
|
|
150
|
+
const custom = customProperties ?? EMPTY_OBJECT;
|
|
151
|
+
const details = {
|
|
152
|
+
reason,
|
|
153
|
+
event: event ?? new Event('base-ui'),
|
|
154
|
+
...custom
|
|
155
|
+
};
|
|
156
|
+
return details;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let globalId = 0;
|
|
160
|
+
|
|
161
|
+
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
162
|
+
function useGlobalId(idOverride, prefix = 'mui') {
|
|
163
|
+
const [defaultId, setDefaultId] = React.useState(idOverride);
|
|
164
|
+
const id = idOverride || defaultId;
|
|
165
|
+
React.useEffect(() => {
|
|
166
|
+
if (defaultId == null) {
|
|
167
|
+
// Fallback to this default id when possible.
|
|
168
|
+
// Use the incrementing value for client-side rendering only.
|
|
169
|
+
// We can't use it server-side.
|
|
170
|
+
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
171
|
+
globalId += 1;
|
|
172
|
+
setDefaultId(`${prefix}-${globalId}`);
|
|
173
|
+
}
|
|
174
|
+
}, [defaultId, prefix]);
|
|
175
|
+
return id;
|
|
176
|
+
}
|
|
177
|
+
const maybeReactUseId = SafeReact.useId;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
*
|
|
181
|
+
* @example <div id={useId()} />
|
|
182
|
+
* @param idOverride
|
|
183
|
+
* @returns {string}
|
|
184
|
+
*/
|
|
185
|
+
function useId(idOverride, prefix) {
|
|
186
|
+
// React.useId() is only available from React 17.0.0.
|
|
187
|
+
if (maybeReactUseId !== undefined) {
|
|
188
|
+
const reactId = maybeReactUseId();
|
|
189
|
+
return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
193
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
194
|
+
return useGlobalId(idOverride, prefix);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const EMPTY$2 = [];
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
201
|
+
*/
|
|
202
|
+
function useOnMount(fn) {
|
|
203
|
+
// 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
|
|
204
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
205
|
+
React.useEffect(fn, EMPTY$2);
|
|
206
|
+
/* eslint-enable react-hooks/exhaustive-deps */
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const EMPTY$1 = 0;
|
|
210
|
+
class Timeout {
|
|
211
|
+
static create() {
|
|
212
|
+
return new Timeout();
|
|
213
|
+
}
|
|
214
|
+
currentId = EMPTY$1;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
218
|
+
*/
|
|
219
|
+
start(delay, fn) {
|
|
220
|
+
this.clear();
|
|
221
|
+
this.currentId = setTimeout(() => {
|
|
222
|
+
this.currentId = EMPTY$1;
|
|
223
|
+
fn();
|
|
224
|
+
}, delay); /* Node.js types are enabled in development */
|
|
225
|
+
}
|
|
226
|
+
isStarted() {
|
|
227
|
+
return this.currentId !== EMPTY$1;
|
|
228
|
+
}
|
|
229
|
+
clear = () => {
|
|
230
|
+
if (this.currentId !== EMPTY$1) {
|
|
231
|
+
clearTimeout(this.currentId);
|
|
232
|
+
this.currentId = EMPTY$1;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
disposeEffect = () => {
|
|
236
|
+
return this.clear;
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* A `setTimeout` with automatic cleanup and guard.
|
|
242
|
+
*/
|
|
243
|
+
function useTimeout() {
|
|
244
|
+
const timeout = useRefWithInit(Timeout.create).current;
|
|
245
|
+
useOnMount(timeout.disposeEffect);
|
|
246
|
+
return timeout;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const hasNavigator = typeof navigator !== 'undefined';
|
|
250
|
+
const nav = getNavigatorData();
|
|
251
|
+
const platform = getPlatform();
|
|
252
|
+
const userAgent = getUserAgent();
|
|
253
|
+
const isWebKit = typeof CSS === 'undefined' || !CSS.supports ? false : CSS.supports('-webkit-backdrop-filter:none');
|
|
254
|
+
const isIOS =
|
|
255
|
+
// iPads can claim to be MacIntel
|
|
256
|
+
nav.platform === 'MacIntel' && nav.maxTouchPoints > 1 ? true : /iP(hone|ad|od)|iOS/.test(nav.platform);
|
|
257
|
+
const isFirefox = hasNavigator && /firefox/i.test(userAgent);
|
|
258
|
+
const isSafari = hasNavigator && /apple/i.test(navigator.vendor);
|
|
259
|
+
const isAndroid = hasNavigator && /android/i.test(platform) || /android/i.test(userAgent);
|
|
260
|
+
const isMac = hasNavigator && platform.toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
|
|
261
|
+
const isJSDOM = userAgent.includes('jsdom/');
|
|
262
|
+
|
|
263
|
+
// Avoid Chrome DevTools blue warning.
|
|
264
|
+
function getNavigatorData() {
|
|
265
|
+
if (!hasNavigator) {
|
|
266
|
+
return {
|
|
267
|
+
platform: '',
|
|
268
|
+
maxTouchPoints: -1
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const uaData = navigator.userAgentData;
|
|
272
|
+
if (uaData?.platform) {
|
|
273
|
+
return {
|
|
274
|
+
platform: uaData.platform,
|
|
275
|
+
maxTouchPoints: navigator.maxTouchPoints
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
platform: navigator.platform ?? '',
|
|
280
|
+
maxTouchPoints: navigator.maxTouchPoints ?? -1
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function getUserAgent() {
|
|
284
|
+
if (!hasNavigator) {
|
|
285
|
+
return '';
|
|
286
|
+
}
|
|
287
|
+
const uaData = navigator.userAgentData;
|
|
288
|
+
if (uaData && Array.isArray(uaData.brands)) {
|
|
289
|
+
return uaData.brands.map(({
|
|
290
|
+
brand,
|
|
291
|
+
version
|
|
292
|
+
}) => `${brand}/${version}`).join(' ');
|
|
293
|
+
}
|
|
294
|
+
return navigator.userAgent;
|
|
295
|
+
}
|
|
296
|
+
function getPlatform() {
|
|
297
|
+
if (!hasNavigator) {
|
|
298
|
+
return '';
|
|
299
|
+
}
|
|
300
|
+
const uaData = navigator.userAgentData;
|
|
301
|
+
if (uaData?.platform) {
|
|
302
|
+
return uaData.platform;
|
|
303
|
+
}
|
|
304
|
+
return navigator.platform ?? '';
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function stopEvent(event) {
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
event.stopPropagation();
|
|
310
|
+
}
|
|
311
|
+
function isReactEvent(event) {
|
|
312
|
+
return 'nativeEvent' in event;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// License: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/utils/src/isVirtualEvent.ts
|
|
316
|
+
function isVirtualClick(event) {
|
|
317
|
+
if (event.pointerType === '' && event.isTrusted) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
if (isAndroid && event.pointerType) {
|
|
321
|
+
return event.type === 'click' && event.buttons === 1;
|
|
322
|
+
}
|
|
323
|
+
return event.detail === 0 && !event.pointerType;
|
|
324
|
+
}
|
|
325
|
+
function isVirtualPointerEvent(event) {
|
|
326
|
+
if (isJSDOM) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
return !isAndroid && event.width === 0 && event.height === 0 || isAndroid && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
|
|
330
|
+
// iOS VoiceOver returns 0.333• for width/height.
|
|
331
|
+
event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
|
|
332
|
+
}
|
|
333
|
+
function isMouseLikePointerType(pointerType, strict) {
|
|
334
|
+
// On some Linux machines with Chromium, mouse inputs return a `pointerType`
|
|
335
|
+
// of "pen": https://github.com/floating-ui/floating-ui/issues/2015
|
|
336
|
+
const values = ['mouse', 'pen'];
|
|
337
|
+
if (!strict) {
|
|
338
|
+
values.push('', undefined);
|
|
339
|
+
}
|
|
340
|
+
return values.includes(pointerType);
|
|
341
|
+
}
|
|
342
|
+
function isClickLikeEvent(event) {
|
|
343
|
+
const type = event.type;
|
|
344
|
+
return type === 'click' || type === 'mousedown' || type === 'keydown' || type === 'keyup';
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function ownerDocument(node) {
|
|
348
|
+
return node?.ownerDocument || document;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Untracks the provided value by turning it into a ref to remove its reactivity.
|
|
353
|
+
*
|
|
354
|
+
* Used to access the passed value inside `React.useEffect` without causing the effect to re-run when the value changes.
|
|
355
|
+
*/
|
|
356
|
+
function useValueAsRef(value) {
|
|
357
|
+
const latest = useRefWithInit(createLatestRef, value).current;
|
|
358
|
+
latest.next = value;
|
|
359
|
+
|
|
360
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
361
|
+
useIsoLayoutEffect(latest.effect);
|
|
362
|
+
return latest;
|
|
363
|
+
}
|
|
364
|
+
function createLatestRef(value) {
|
|
365
|
+
const latest = {
|
|
366
|
+
current: value,
|
|
367
|
+
next: value,
|
|
368
|
+
effect: () => {
|
|
369
|
+
latest.current = latest.next;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
return latest;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Unlike `setTimeout`, rAF doesn't guarantee a positive integer return value, so we can't have
|
|
376
|
+
* a monomorphic `uint` type with `0` meaning empty.
|
|
377
|
+
* See warning note at:
|
|
378
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value */
|
|
379
|
+
const EMPTY = null;
|
|
380
|
+
let LAST_RAF = globalThis.requestAnimationFrame;
|
|
381
|
+
class Scheduler {
|
|
382
|
+
/* This implementation uses an array as a backing data-structure for frame callbacks.
|
|
383
|
+
* It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
|
|
384
|
+
* never calls the native `cancelAnimationFrame` if there are no frames left. This can
|
|
385
|
+
* be much more efficient if there is a call pattern that alterns as
|
|
386
|
+
* "request-cancel-request-cancel-…".
|
|
387
|
+
* But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
|
|
388
|
+
* frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
|
|
389
|
+
|
|
390
|
+
callbacks = [];
|
|
391
|
+
callbacksCount = 0;
|
|
392
|
+
nextId = 1;
|
|
393
|
+
startId = 1;
|
|
394
|
+
isScheduled = false;
|
|
395
|
+
tick = timestamp => {
|
|
396
|
+
this.isScheduled = false;
|
|
397
|
+
const currentCallbacks = this.callbacks;
|
|
398
|
+
const currentCallbacksCount = this.callbacksCount;
|
|
399
|
+
|
|
400
|
+
// Update these before iterating, callbacks could call `requestAnimationFrame` again.
|
|
401
|
+
this.callbacks = [];
|
|
402
|
+
this.callbacksCount = 0;
|
|
403
|
+
this.startId = this.nextId;
|
|
404
|
+
if (currentCallbacksCount > 0) {
|
|
405
|
+
for (let i = 0; i < currentCallbacks.length; i += 1) {
|
|
406
|
+
currentCallbacks[i]?.(timestamp);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
request(fn) {
|
|
411
|
+
const id = this.nextId;
|
|
412
|
+
this.nextId += 1;
|
|
413
|
+
this.callbacks.push(fn);
|
|
414
|
+
this.callbacksCount += 1;
|
|
415
|
+
|
|
416
|
+
/* In a test environment with fake timers, a fake `requestAnimationFrame` can be called
|
|
417
|
+
* but there's no guarantee that the animation frame will actually run before the fake
|
|
418
|
+
* timers are teared, which leaves `isScheduled` set, but won't run our `tick()`. */
|
|
419
|
+
const didRAFChange = process.env.NODE_ENV !== 'production' && LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
|
|
420
|
+
if (!this.isScheduled || didRAFChange) {
|
|
421
|
+
requestAnimationFrame(this.tick);
|
|
422
|
+
this.isScheduled = true;
|
|
423
|
+
}
|
|
424
|
+
return id;
|
|
425
|
+
}
|
|
426
|
+
cancel(id) {
|
|
427
|
+
const index = id - this.startId;
|
|
428
|
+
if (index < 0 || index >= this.callbacks.length) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
this.callbacks[index] = null;
|
|
432
|
+
this.callbacksCount -= 1;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const scheduler = new Scheduler();
|
|
436
|
+
class AnimationFrame {
|
|
437
|
+
static create() {
|
|
438
|
+
return new AnimationFrame();
|
|
439
|
+
}
|
|
440
|
+
static request(fn) {
|
|
441
|
+
return scheduler.request(fn);
|
|
442
|
+
}
|
|
443
|
+
static cancel(id) {
|
|
444
|
+
return scheduler.cancel(id);
|
|
445
|
+
}
|
|
446
|
+
currentId = EMPTY;
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Executes `fn` after `delay`, clearing any previously scheduled call.
|
|
450
|
+
*/
|
|
451
|
+
request(fn) {
|
|
452
|
+
this.cancel();
|
|
453
|
+
this.currentId = scheduler.request(() => {
|
|
454
|
+
this.currentId = EMPTY;
|
|
455
|
+
fn();
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
cancel = () => {
|
|
459
|
+
if (this.currentId !== EMPTY) {
|
|
460
|
+
scheduler.cancel(this.currentId);
|
|
461
|
+
this.currentId = EMPTY;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
disposeEffect = () => {
|
|
465
|
+
return this.cancel;
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* A `requestAnimationFrame` with automatic cleanup and guard.
|
|
471
|
+
*/
|
|
472
|
+
function useAnimationFrame() {
|
|
473
|
+
const timeout = useRefWithInit(AnimationFrame.create).current;
|
|
474
|
+
useOnMount(timeout.disposeEffect);
|
|
475
|
+
return timeout;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const visuallyHiddenBase = {
|
|
479
|
+
clipPath: 'inset(50%)',
|
|
480
|
+
overflow: 'hidden',
|
|
481
|
+
whiteSpace: 'nowrap',
|
|
482
|
+
border: 0,
|
|
483
|
+
padding: 0,
|
|
484
|
+
width: 1,
|
|
485
|
+
height: 1,
|
|
486
|
+
margin: -1
|
|
487
|
+
};
|
|
488
|
+
const visuallyHidden = {
|
|
489
|
+
...visuallyHiddenBase,
|
|
490
|
+
position: 'fixed',
|
|
491
|
+
top: 0,
|
|
492
|
+
left: 0
|
|
493
|
+
};
|
|
494
|
+
const visuallyHiddenInput = {
|
|
495
|
+
...visuallyHiddenBase,
|
|
496
|
+
position: 'absolute'
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* If the provided argument is a ref object, returns its `current` value.
|
|
501
|
+
* Otherwise, returns the argument itself.
|
|
502
|
+
*/
|
|
503
|
+
function resolveRef(maybeRef) {
|
|
504
|
+
if (maybeRef == null) {
|
|
505
|
+
return maybeRef;
|
|
506
|
+
}
|
|
507
|
+
return 'current' in maybeRef ? maybeRef.current : maybeRef;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Provides a status string for CSS animations.
|
|
512
|
+
* @param open - a boolean that determines if the element is open.
|
|
513
|
+
* @param enableIdleState - a boolean that enables the `'idle'` state between `'starting'` and `'ending'`
|
|
514
|
+
*/
|
|
515
|
+
function useTransitionStatus(open, enableIdleState = false, deferEndingState = false) {
|
|
516
|
+
const [transitionStatus, setTransitionStatus] = React.useState(open && enableIdleState ? 'idle' : undefined);
|
|
517
|
+
const [mounted, setMounted] = React.useState(open);
|
|
518
|
+
if (open && !mounted) {
|
|
519
|
+
setMounted(true);
|
|
520
|
+
setTransitionStatus('starting');
|
|
521
|
+
}
|
|
522
|
+
if (!open && mounted && transitionStatus !== 'ending' && !deferEndingState) {
|
|
523
|
+
setTransitionStatus('ending');
|
|
524
|
+
}
|
|
525
|
+
if (!open && !mounted && transitionStatus === 'ending') {
|
|
526
|
+
setTransitionStatus(undefined);
|
|
527
|
+
}
|
|
528
|
+
useIsoLayoutEffect(() => {
|
|
529
|
+
if (!open && mounted && transitionStatus !== 'ending' && deferEndingState) {
|
|
530
|
+
const frame = AnimationFrame.request(() => {
|
|
531
|
+
setTransitionStatus('ending');
|
|
532
|
+
});
|
|
533
|
+
return () => {
|
|
534
|
+
AnimationFrame.cancel(frame);
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
return undefined;
|
|
538
|
+
}, [open, mounted, transitionStatus, deferEndingState]);
|
|
539
|
+
useIsoLayoutEffect(() => {
|
|
540
|
+
if (!open || enableIdleState) {
|
|
541
|
+
return undefined;
|
|
542
|
+
}
|
|
543
|
+
const frame = AnimationFrame.request(() => {
|
|
544
|
+
// Avoid `flushSync` here due to Firefox.
|
|
545
|
+
// See https://github.com/mui/base-ui/pull/3424
|
|
546
|
+
setTransitionStatus(undefined);
|
|
547
|
+
});
|
|
548
|
+
return () => {
|
|
549
|
+
AnimationFrame.cancel(frame);
|
|
550
|
+
};
|
|
551
|
+
}, [enableIdleState, open]);
|
|
552
|
+
useIsoLayoutEffect(() => {
|
|
553
|
+
if (!open || !enableIdleState) {
|
|
554
|
+
return undefined;
|
|
555
|
+
}
|
|
556
|
+
if (open && mounted && transitionStatus !== 'idle') {
|
|
557
|
+
setTransitionStatus('starting');
|
|
558
|
+
}
|
|
559
|
+
const frame = AnimationFrame.request(() => {
|
|
560
|
+
setTransitionStatus('idle');
|
|
561
|
+
});
|
|
562
|
+
return () => {
|
|
563
|
+
AnimationFrame.cancel(frame);
|
|
564
|
+
};
|
|
565
|
+
}, [enableIdleState, open, mounted, setTransitionStatus, transitionStatus]);
|
|
566
|
+
return React.useMemo(() => ({
|
|
567
|
+
mounted,
|
|
568
|
+
setMounted,
|
|
569
|
+
transitionStatus
|
|
570
|
+
}), [mounted, transitionStatus]);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Executes a function once all animations have finished on the provided element.
|
|
575
|
+
* @param elementOrRef - The element to watch for animations.
|
|
576
|
+
* @param waitForStartingStyleRemoved - Whether to wait for [data-starting-style] to be removed before checking for animations.
|
|
577
|
+
* @param treatAbortedAsFinished - Whether to treat aborted animations as finished. If `false`, and there are aborted animations,
|
|
578
|
+
* the function will check again if any new animations have started and wait for them to finish.
|
|
579
|
+
* @returns A function that takes a callback to execute once all animations have finished, and an optional AbortSignal to abort the callback
|
|
580
|
+
*/
|
|
581
|
+
function useAnimationsFinished(elementOrRef, waitForStartingStyleRemoved = false, treatAbortedAsFinished = true) {
|
|
582
|
+
const frame = useAnimationFrame();
|
|
583
|
+
return useStableCallback((fnToExecute,
|
|
584
|
+
/**
|
|
585
|
+
* An optional [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that
|
|
586
|
+
* can be used to abort `fnToExecute` before all the animations have finished.
|
|
587
|
+
* @default null
|
|
588
|
+
*/
|
|
589
|
+
signal = null) => {
|
|
590
|
+
frame.cancel();
|
|
591
|
+
function done() {
|
|
592
|
+
// Synchronously flush the unmounting of the component so that the browser doesn't
|
|
593
|
+
// paint: https://github.com/mui/base-ui/issues/979
|
|
594
|
+
ReactDOM.flushSync(fnToExecute);
|
|
595
|
+
}
|
|
596
|
+
const element = resolveRef(elementOrRef);
|
|
597
|
+
if (element == null) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const resolvedElement = element;
|
|
601
|
+
if (typeof resolvedElement.getAnimations !== 'function' || globalThis.BASE_UI_ANIMATIONS_DISABLED) {
|
|
602
|
+
fnToExecute();
|
|
603
|
+
} else {
|
|
604
|
+
function execWaitForStartingStyleRemoved() {
|
|
605
|
+
const startingStyleAttribute = TransitionStatusDataAttributes.startingStyle;
|
|
606
|
+
|
|
607
|
+
// If `[data-starting-style]` isn't present, fall back to waiting one more frame
|
|
608
|
+
// to give "open" animations a chance to be registered.
|
|
609
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
610
|
+
frame.request(exec);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Wait for `[data-starting-style]` to have been removed.
|
|
615
|
+
const attributeObserver = new MutationObserver(() => {
|
|
616
|
+
if (!resolvedElement.hasAttribute(startingStyleAttribute)) {
|
|
617
|
+
attributeObserver.disconnect();
|
|
618
|
+
exec();
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
attributeObserver.observe(resolvedElement, {
|
|
622
|
+
attributes: true,
|
|
623
|
+
attributeFilter: [startingStyleAttribute]
|
|
624
|
+
});
|
|
625
|
+
signal?.addEventListener('abort', () => attributeObserver.disconnect(), {
|
|
626
|
+
once: true
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
function exec() {
|
|
630
|
+
Promise.all(resolvedElement.getAnimations().map(anim => anim.finished)).then(() => {
|
|
631
|
+
if (signal?.aborted) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
done();
|
|
635
|
+
}).catch(() => {
|
|
636
|
+
const currentAnimations = resolvedElement.getAnimations();
|
|
637
|
+
if (treatAbortedAsFinished) {
|
|
638
|
+
if (signal?.aborted) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
done();
|
|
642
|
+
} else if (currentAnimations.length > 0 && currentAnimations.some(anim => anim.pending || anim.playState !== 'finished')) {
|
|
643
|
+
// Sometimes animations can be aborted because a property they depend on changes while the animation plays.
|
|
644
|
+
// In such cases, we need to re-check if any new animations have started.
|
|
645
|
+
exec();
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
if (waitForStartingStyleRemoved) {
|
|
650
|
+
execWaitForStartingStyleRemoved();
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
frame.request(exec);
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Calls the provided function when the CSS open/close animation or transition completes.
|
|
660
|
+
*/
|
|
661
|
+
function useOpenChangeComplete(parameters) {
|
|
662
|
+
const {
|
|
663
|
+
enabled = true,
|
|
664
|
+
open,
|
|
665
|
+
ref,
|
|
666
|
+
onComplete: onCompleteParam
|
|
667
|
+
} = parameters;
|
|
668
|
+
const onComplete = useStableCallback(onCompleteParam);
|
|
669
|
+
const runOnceAnimationsFinish = useAnimationsFinished(ref, open, false);
|
|
670
|
+
React.useEffect(() => {
|
|
671
|
+
if (!enabled) {
|
|
672
|
+
return undefined;
|
|
673
|
+
}
|
|
674
|
+
const abortController = new AbortController();
|
|
675
|
+
runOnceAnimationsFinish(onComplete, abortController.signal);
|
|
676
|
+
return () => {
|
|
677
|
+
abortController.abort();
|
|
678
|
+
};
|
|
679
|
+
}, [enabled, open, onComplete, runOnceAnimationsFinish]);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
|
|
683
|
+
return Math.max(min, Math.min(val, max));
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function useControlled({
|
|
687
|
+
controlled,
|
|
688
|
+
default: defaultProp,
|
|
689
|
+
name,
|
|
690
|
+
state = 'value'
|
|
691
|
+
}) {
|
|
692
|
+
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
693
|
+
const {
|
|
694
|
+
current: isControlled
|
|
695
|
+
} = React.useRef(controlled !== undefined);
|
|
696
|
+
const [valueState, setValue] = React.useState(defaultProp);
|
|
697
|
+
const value = isControlled ? controlled : valueState;
|
|
698
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
699
|
+
React.useEffect(() => {
|
|
700
|
+
if (isControlled !== (controlled !== undefined)) {
|
|
701
|
+
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'));
|
|
702
|
+
}
|
|
703
|
+
}, [state, name, controlled]);
|
|
704
|
+
const {
|
|
705
|
+
current: defaultValue
|
|
706
|
+
} = React.useRef(defaultProp);
|
|
707
|
+
React.useEffect(() => {
|
|
708
|
+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
709
|
+
if (!isControlled && JSON.stringify(defaultValue) !== JSON.stringify(defaultProp)) {
|
|
710
|
+
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'));
|
|
711
|
+
}
|
|
712
|
+
}, [JSON.stringify(defaultProp)]);
|
|
713
|
+
}
|
|
714
|
+
const setValueIfUncontrolled = React.useCallback(newValue => {
|
|
715
|
+
if (!isControlled) {
|
|
716
|
+
setValue(newValue);
|
|
717
|
+
}
|
|
718
|
+
}, []);
|
|
719
|
+
return [value, setValueIfUncontrolled];
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function useValueChanged(value, onChange) {
|
|
723
|
+
const valueRef = React.useRef(value);
|
|
724
|
+
const onChangeCallback = useStableCallback(onChange);
|
|
725
|
+
useIsoLayoutEffect(() => {
|
|
726
|
+
if (valueRef.current === value) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
onChangeCallback(valueRef.current);
|
|
730
|
+
}, [value, onChangeCallback]);
|
|
731
|
+
useIsoLayoutEffect(() => {
|
|
732
|
+
valueRef.current = value;
|
|
733
|
+
}, [value]);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
export { isReactEvent as $, keyboard as A, closePress as B, isMouseLikePointerType as C, useAnimationFrame as D, isClickLikeEvent as E, triggerPress as F, triggerFocus as G, isMac as H, isSafari as I, escapeKey as J, triggerHover as K, listNavigation as L, focusOut as M, isVirtualClick as N, isVirtualPointerEvent as O, itemPress as P, outsidePress as Q, useAnimationsFinished as R, SafeReact as S, Timeout as T, siblingOpen as U, imperativeAction as V, cancelOpen as W, TransitionStatusDataAttributes as X, isJSDOM as Y, resolveRef as Z, isWebKit as _, useStableCallback as a, AnimationFrame as a0, isAndroid as a1, closeWatcher as a2, swipe as a3, inputPress as a4, isFirefox as a5, clearPress as a6, chipRemovePress as a7, scrub as a8, useId as b, useTimeout as c, useTransitionStatus as d, useOpenChangeComplete as e, useOnMount as f, clamp as g, useControlled as h, useValueAsRef as i, isIOS as j, createChangeEventDetails as k, visuallyHidden as l, inputChange as m, none as n, inputClear as o, inputBlur as p, inputPaste as q, createGenericEventDetails as r, ownerDocument as s, transitionStatusMapping as t, useIsoLayoutEffect as u, visuallyHiddenInput as v, incrementPress as w, decrementPress as x, useValueChanged as y, stopEvent as z };
|