@basic-ui/core 0.0.61 → 0.0.63
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/build/esm/index.js +1 -1
- package/build/esm/index.js.map +1 -1
- package/build/tsconfig-build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/build/cjs/index.js +0 -3938
- package/build/cjs/index.js.map +0 -1
- package/build/tsconfig.tsbuildinfo +0 -1
- /package/build/esm/{toggle → Toggle}/Toggle.d.ts +0 -0
- /package/build/esm/{toggle → Toggle}/Toggle.d.ts.map +0 -0
- /package/build/esm/{toggle → Toggle}/Toggle.js +0 -0
- /package/build/esm/{toggle → Toggle}/Toggle.js.map +0 -0
- /package/build/esm/{toggle → Toggle}/index.d.ts +0 -0
- /package/build/esm/{toggle → Toggle}/index.d.ts.map +0 -0
- /package/build/esm/{toggle → Toggle}/index.js +0 -0
- /package/build/esm/{toggle → Toggle}/index.js.map +0 -0
package/build/cjs/index.js
DELETED
|
@@ -1,3938 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var react = require('react');
|
|
6
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
-
var core = require('@popperjs/core');
|
|
8
|
-
var reactDom = require('react-dom');
|
|
9
|
-
|
|
10
|
-
// AccordionGroup Component
|
|
11
|
-
|
|
12
|
-
const accordionContext = /*#__PURE__*/react.createContext(null);
|
|
13
|
-
const {
|
|
14
|
-
Provider: AccordionProvider
|
|
15
|
-
} = accordionContext;
|
|
16
|
-
const useAccordionContext = () => react.useContext(accordionContext);
|
|
17
|
-
|
|
18
|
-
// Accordion Component
|
|
19
|
-
|
|
20
|
-
const accordionItemContext = /*#__PURE__*/react.createContext(null);
|
|
21
|
-
const {
|
|
22
|
-
Provider: AccordionItemProvider
|
|
23
|
-
} = accordionItemContext;
|
|
24
|
-
const useAccordionItemContext = () => react.useContext(accordionItemContext);
|
|
25
|
-
|
|
26
|
-
const tabblable = ['button:enabled:not([readonly])', 'select:enabled:not([readonly])', 'textarea:enabled:not([readonly])', 'input:enabled:not([readonly])', 'a[href]', 'area[href]', 'iframe', 'object', 'embed', '[tabindex]', '[contenteditable]', '[autofocus]'].join(',');
|
|
27
|
-
|
|
28
|
-
/* This is naive and will not consider tabIndex */
|
|
29
|
-
const getTabblableNodes = parentNode => {
|
|
30
|
-
if (!parentNode) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
return Array.from(parentNode.querySelectorAll(tabblable));
|
|
34
|
-
};
|
|
35
|
-
function focusOnChildNode(parentNode, itemIndex) {
|
|
36
|
-
const elements = getTabblableNodes(parentNode);
|
|
37
|
-
if (elements.length > 0) {
|
|
38
|
-
elements[itemIndex === -1 ? elements.length - 1 : 0].focus();
|
|
39
|
-
} else {
|
|
40
|
-
const currentTabIndex = parentNode.tabIndex;
|
|
41
|
-
parentNode.tabIndex = 0;
|
|
42
|
-
parentNode.focus();
|
|
43
|
-
parentNode.tabIndex = currentTabIndex;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function useAutoFocus(open, elementRef) {
|
|
48
|
-
react.useEffect(() => {
|
|
49
|
-
if (open) {
|
|
50
|
-
// We will only autoFocus on the first child if the currently active element isn't already trapped inside the modal
|
|
51
|
-
if (elementRef.current && !elementRef.current.contains(document.activeElement)) {
|
|
52
|
-
focusOnChildNode(elementRef.current, 0);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
56
|
-
}, [open]);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function assignRef(ref, value) {
|
|
60
|
-
if (ref == null) return;
|
|
61
|
-
if (typeof ref === 'function') {
|
|
62
|
-
ref(value);
|
|
63
|
-
} else {
|
|
64
|
-
try {
|
|
65
|
-
ref.current = value;
|
|
66
|
-
} catch (error) {
|
|
67
|
-
throw new Error(`Cannot assign value "${value}" to ref "${ref}"`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function assignMultipleRefs(...refs) {
|
|
72
|
-
return node => {
|
|
73
|
-
refs.forEach(ref => {
|
|
74
|
-
assignRef(ref, node);
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function canUseDOM() {
|
|
80
|
-
return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function createContext(rootName, defaultContext) {
|
|
84
|
-
const Ctx = /*#__PURE__*/react.createContext(defaultContext);
|
|
85
|
-
function Provider(props) {
|
|
86
|
-
const {
|
|
87
|
-
children,
|
|
88
|
-
...context
|
|
89
|
-
} = props;
|
|
90
|
-
const value = react.useMemo(() => context,
|
|
91
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
92
|
-
Object.values(context));
|
|
93
|
-
return /*#__PURE__*/jsxRuntime.jsx(Ctx.Provider, {
|
|
94
|
-
value: value,
|
|
95
|
-
children: children
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function useContext(childName) {
|
|
99
|
-
const context = react.useContext(Ctx);
|
|
100
|
-
if (context) {
|
|
101
|
-
return context;
|
|
102
|
-
}
|
|
103
|
-
if (defaultContext) {
|
|
104
|
-
return defaultContext;
|
|
105
|
-
}
|
|
106
|
-
throw Error(`${childName} must be rendered inside of a ${rootName} component.`);
|
|
107
|
-
}
|
|
108
|
-
Ctx.displayName = `${rootName}Context`;
|
|
109
|
-
Provider.displayName = `${rootName}Provider`;
|
|
110
|
-
return [Provider, useContext];
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function getCircularIndex(index, maxLength) {
|
|
114
|
-
if (maxLength < 0) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return (index % maxLength + maxLength) % maxLength;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Detects right clicks
|
|
122
|
-
*
|
|
123
|
-
* @param nativeEvent
|
|
124
|
-
*/
|
|
125
|
-
function isRightClick(nativeEvent) {
|
|
126
|
-
return 'which' in nativeEvent ? nativeEvent.which === 3 : 'button' in nativeEvent ? nativeEvent.button === 2 : false;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Get an element's owner document. Useful when components are used in iframes
|
|
131
|
-
* or other environments like dev tools.
|
|
132
|
-
*
|
|
133
|
-
* @param element
|
|
134
|
-
*/
|
|
135
|
-
function getOwnerDocument(element) {
|
|
136
|
-
return canUseDOM() ? element ? element.ownerDocument : document : null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// https://twitter.com/chpwn/status/285540192096497664
|
|
140
|
-
// iOS constant = 0.55
|
|
141
|
-
function rubberBand(distance, dimension, constant = 0.15) {
|
|
142
|
-
return distance * dimension * constant / (dimension + constant * distance);
|
|
143
|
-
}
|
|
144
|
-
function rubberBandClamp(min, max, delta, constant = 0.15) {
|
|
145
|
-
if (delta < min) {
|
|
146
|
-
return -rubberBand(min - delta, max - min, constant) + min;
|
|
147
|
-
}
|
|
148
|
-
if (delta > max) {
|
|
149
|
-
return rubberBand(delta - max, max - min, constant) + max;
|
|
150
|
-
}
|
|
151
|
-
return delta;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/* eslint-disable react-hooks/rules-of-hooks */
|
|
155
|
-
const useEnhancedEffect$2 = typeof window !== 'undefined' ? react.useLayoutEffect : react.useEffect;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Converts a callback to a ref to avoid triggering re-renders when passed as a
|
|
159
|
-
* prop and exposed as a stable function to avoid executing effects when
|
|
160
|
-
* passed as a dependency.
|
|
161
|
-
*/
|
|
162
|
-
function createStableCallbackHook(useEffectHook, callback) {
|
|
163
|
-
const callbackRef = react.useRef(callback);
|
|
164
|
-
useEffectHook(() => {
|
|
165
|
-
callbackRef.current = callback;
|
|
166
|
-
});
|
|
167
|
-
return react.useCallback((...args) => {
|
|
168
|
-
callbackRef.current && callbackRef.current(...args);
|
|
169
|
-
}, []);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Converts a callback to a ref to avoid triggering re-renders when passed as a
|
|
174
|
-
* prop and exposed as a stable function to avoid executing effects when passed
|
|
175
|
-
* as a dependency.
|
|
176
|
-
*/
|
|
177
|
-
function useStableCallback(callback) {
|
|
178
|
-
return createStableCallbackHook(react.useEffect, callback);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Converts a callback to a ref to avoid triggering re-renders when passed as a
|
|
183
|
-
* prop and exposed as a stable function to avoid executing effects when passed
|
|
184
|
-
* as a dependency.
|
|
185
|
-
*
|
|
186
|
-
* Use this over `useStableCallback` when you want the callback to be cached in
|
|
187
|
-
* `useLayoutEffect` instead of `useEffect` to deal with timing issues only when
|
|
188
|
-
* needed.
|
|
189
|
-
*/
|
|
190
|
-
function useStableLayoutCallback(callback) {
|
|
191
|
-
return createStableCallbackHook(useEnhancedEffect$2, callback);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function wrapEvent(theirHandler, ourHandler) {
|
|
195
|
-
return (event, ...otherArgs) => {
|
|
196
|
-
const ret = theirHandler && theirHandler(event, ...otherArgs);
|
|
197
|
-
if (!event || !event.defaultPrevented) {
|
|
198
|
-
return ourHandler(event, ...otherArgs);
|
|
199
|
-
}
|
|
200
|
-
return ret;
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function useControlledState(valueProp, onChangeProp, defaultValue, defaultOnChange) {
|
|
205
|
-
const isControlled = valueProp !== undefined;
|
|
206
|
-
const wasControlled = react.useRef(isControlled);
|
|
207
|
-
const hasWarned = react.useRef(false);
|
|
208
|
-
const [valueState, setValueState] = react.useState(defaultValue);
|
|
209
|
-
if (isControlled) {
|
|
210
|
-
if (!wasControlled.current && !hasWarned.current && process.env.NODE_ENV !== 'production') {
|
|
211
|
-
console.warn('Trying to change from controlled to uncontrolled.');
|
|
212
|
-
hasWarned.current = true;
|
|
213
|
-
}
|
|
214
|
-
return [valueProp, wrapEvent(onChangeProp, defaultOnChange(setValueState))];
|
|
215
|
-
}
|
|
216
|
-
return [valueState, wrapEvent(onChangeProp, defaultOnChange(setValueState))];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function useChildrenCounterParent(itemsRef) {
|
|
220
|
-
// Reset the options ref every render so that they are always
|
|
221
|
-
// accurate and ready for keyboard navigation handlers. Using layout
|
|
222
|
-
// effect to schedule this effect before the ComboboxOptions push into
|
|
223
|
-
// the array
|
|
224
|
-
itemsRef.current = [];
|
|
225
|
-
itemsRef.current.isNewRender = true;
|
|
226
|
-
react.useEffect(() => {
|
|
227
|
-
// Rendering is finished. Meaning any children can now rerender,
|
|
228
|
-
// and they should not push any new items to our array, because
|
|
229
|
-
// it is not a new render
|
|
230
|
-
itemsRef.current.isNewRender = false;
|
|
231
|
-
});
|
|
232
|
-
react.useEffect(() => {
|
|
233
|
-
// When we are unmounting, it means there are no children anymore.
|
|
234
|
-
// Clear out our items array
|
|
235
|
-
return () => {
|
|
236
|
-
itemsRef.current = [];
|
|
237
|
-
};
|
|
238
|
-
}, [itemsRef]);
|
|
239
|
-
}
|
|
240
|
-
function useChildrenCounterChild(itemsRef, itemIndexRef, obj, disabled = false) {
|
|
241
|
-
if (itemsRef && itemsRef.current.isNewRender) {
|
|
242
|
-
if (disabled) {
|
|
243
|
-
itemIndexRef.current = -1;
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// push this option to the optionsRef array
|
|
248
|
-
itemIndexRef.current = itemsRef.current.length;
|
|
249
|
-
if (obj instanceof Function) {
|
|
250
|
-
itemsRef.current.push(obj(itemIndexRef.current));
|
|
251
|
-
} else {
|
|
252
|
-
itemsRef.current.push(obj);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function useFocusReturn(open, rootEl) {
|
|
258
|
-
const previousFocusRef = react.useRef((() => {
|
|
259
|
-
if (open && typeof document !== 'undefined' && document.activeElement instanceof HTMLElement) {
|
|
260
|
-
return document.activeElement;
|
|
261
|
-
}
|
|
262
|
-
return null;
|
|
263
|
-
})());
|
|
264
|
-
react.useEffect(() => {
|
|
265
|
-
if (open) {
|
|
266
|
-
// once opened, keep track of the element that triggered
|
|
267
|
-
// the Modal opening
|
|
268
|
-
if (!previousFocusRef.current && document.activeElement instanceof HTMLElement && !rootEl.current?.contains(document.activeElement)) {
|
|
269
|
-
previousFocusRef.current = document.activeElement;
|
|
270
|
-
}
|
|
271
|
-
const rootElement = rootEl.current;
|
|
272
|
-
const previousElement = previousFocusRef.current;
|
|
273
|
-
return () => {
|
|
274
|
-
// on unmount, return focus to that element
|
|
275
|
-
if (previousElement && !rootElement?.contains(document.activeElement)) {
|
|
276
|
-
previousElement.focus({
|
|
277
|
-
preventScroll: true
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}, [open, rootEl]);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function useFocusState(props = {}) {
|
|
286
|
-
const {
|
|
287
|
-
onFocus,
|
|
288
|
-
onBlur
|
|
289
|
-
} = props;
|
|
290
|
-
const [hasFocus, setHasFocus] = react.useState(false);
|
|
291
|
-
const handleFocus = () => {
|
|
292
|
-
setHasFocus(true);
|
|
293
|
-
};
|
|
294
|
-
const handleBlur = () => {
|
|
295
|
-
setHasFocus(false);
|
|
296
|
-
};
|
|
297
|
-
return {
|
|
298
|
-
bind: {
|
|
299
|
-
onFocus: wrapEvent(onFocus, handleFocus),
|
|
300
|
-
onBlur: wrapEvent(onBlur, handleBlur)
|
|
301
|
-
},
|
|
302
|
-
hasFocus
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function useOnClickOutside(ref, handler, active = true) {
|
|
307
|
-
const listener = react.useCallback(event => {
|
|
308
|
-
// Do nothing if clicking ref's element or descendent elements
|
|
309
|
-
if (!ref.current || ref.current.contains(event.target)) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
handler && handler(event);
|
|
313
|
-
}, [ref, handler]);
|
|
314
|
-
react.useEffect(() => {
|
|
315
|
-
if (active) {
|
|
316
|
-
document.addEventListener('pointerup', listener);
|
|
317
|
-
return () => {
|
|
318
|
-
document.removeEventListener('pointerup', listener);
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
return;
|
|
322
|
-
}, [listener, active]);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function useOnKeyDown(ownerWindow, handler, active = true) {
|
|
326
|
-
react.useEffect(() => {
|
|
327
|
-
if (active) {
|
|
328
|
-
ownerWindow.addEventListener('keydown', handler);
|
|
329
|
-
return () => {
|
|
330
|
-
ownerWindow.removeEventListener('keydown', handler);
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
return;
|
|
334
|
-
}, [ownerWindow, active, handler]);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// This manages transitions between states with a built in reducer to manage
|
|
338
|
-
// the data that goes with those transitions.
|
|
339
|
-
function useReducerMachine(chart, reducer, initialData) {
|
|
340
|
-
const [reducerState, dispatch] = react.useReducer(reducer, initialData);
|
|
341
|
-
const {
|
|
342
|
-
state,
|
|
343
|
-
...data
|
|
344
|
-
} = reducerState;
|
|
345
|
-
const transition = (action, payload = {}) => {
|
|
346
|
-
const currentState = chart.states[state];
|
|
347
|
-
if (!currentState) {
|
|
348
|
-
throw new Error(`Unknown currentState "${state}"`);
|
|
349
|
-
}
|
|
350
|
-
const nextState = currentState.on[action];
|
|
351
|
-
if (!nextState) {
|
|
352
|
-
throw new Error(`Unknown action "${action}" for state "${state}"`);
|
|
353
|
-
}
|
|
354
|
-
dispatch({
|
|
355
|
-
type: action,
|
|
356
|
-
nextState,
|
|
357
|
-
...payload
|
|
358
|
-
});
|
|
359
|
-
};
|
|
360
|
-
return [state, data, transition];
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
let scrollBodyCount = 0;
|
|
364
|
-
function useRemoveBodyScroll(open, elementRef) {
|
|
365
|
-
react.useEffect(() => {
|
|
366
|
-
if (open && elementRef.current) {
|
|
367
|
-
const ownerDocument = getOwnerDocument(elementRef.current);
|
|
368
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
369
|
-
scrollBodyCount += 1;
|
|
370
|
-
|
|
371
|
-
// calculate scrollbar width if mounting the first scroll lock
|
|
372
|
-
let scrollBarWidth = 0;
|
|
373
|
-
if (scrollBodyCount === 1) {
|
|
374
|
-
scrollBarWidth = ownerWindow.innerWidth - ownerDocument.body.clientWidth;
|
|
375
|
-
}
|
|
376
|
-
ownerDocument.body.style.overflow = 'hidden';
|
|
377
|
-
if (scrollBarWidth > 0) {
|
|
378
|
-
ownerDocument.body.style.marginRight = `${scrollBarWidth}px`;
|
|
379
|
-
}
|
|
380
|
-
return () => {
|
|
381
|
-
scrollBodyCount -= 1;
|
|
382
|
-
if (scrollBodyCount === 0) {
|
|
383
|
-
ownerDocument.body.style.overflow = '';
|
|
384
|
-
ownerDocument.body.style.marginRight = '';
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
}, [elementRef, open]);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function useThrottle(value, limit) {
|
|
392
|
-
const [throttledValue, setThrottledValue] = react.useState(value);
|
|
393
|
-
const lastRan = react.useRef(Date.now());
|
|
394
|
-
react.useEffect(() => {
|
|
395
|
-
const handler = setTimeout(() => {
|
|
396
|
-
setThrottledValue(value);
|
|
397
|
-
lastRan.current = Date.now();
|
|
398
|
-
}, limit - (Date.now() - lastRan.current));
|
|
399
|
-
return () => {
|
|
400
|
-
clearTimeout(handler);
|
|
401
|
-
};
|
|
402
|
-
}, [value, limit]);
|
|
403
|
-
return throttledValue;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function useMeasure(ref) {
|
|
407
|
-
const ro = react.useRef(null);
|
|
408
|
-
const [bounds, setBounds] = react.useState({
|
|
409
|
-
left: 0,
|
|
410
|
-
top: 0,
|
|
411
|
-
width: 0,
|
|
412
|
-
height: 0
|
|
413
|
-
});
|
|
414
|
-
react.useEffect(() => {
|
|
415
|
-
if (ro.current === null) {
|
|
416
|
-
ro.current = new ResizeObserver(entries => {
|
|
417
|
-
const entry = entries[0];
|
|
418
|
-
setBounds(entry.contentRect);
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
if (ref.current) {
|
|
422
|
-
ro.current.observe(ref.current);
|
|
423
|
-
}
|
|
424
|
-
return () => {
|
|
425
|
-
if (ro.current) {
|
|
426
|
-
ro.current.disconnect();
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
}, [ref]);
|
|
430
|
-
return bounds;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const initialGestureHandlersState = {
|
|
434
|
-
target: null,
|
|
435
|
-
x: 0,
|
|
436
|
-
xDelta: 0,
|
|
437
|
-
xDeltaPercent: 0,
|
|
438
|
-
xInitial: 0,
|
|
439
|
-
xPrev: 0,
|
|
440
|
-
xVelocity: 0,
|
|
441
|
-
y: 0,
|
|
442
|
-
yDelta: 0,
|
|
443
|
-
yDeltaPercent: 0,
|
|
444
|
-
yInitial: 0,
|
|
445
|
-
yPrev: 0,
|
|
446
|
-
yVelocity: 0,
|
|
447
|
-
startTime: 0,
|
|
448
|
-
down: false,
|
|
449
|
-
scrollLocked: false
|
|
450
|
-
};
|
|
451
|
-
const FRAMERATE_CONST = 1000 / 60; // 60 fps
|
|
452
|
-
const VELOCITY_DEPR_FACTOR = FRAMERATE_CONST * 2;
|
|
453
|
-
function gestureHandlers(set, containerRef, options = {}) {
|
|
454
|
-
const {
|
|
455
|
-
ensureTargetIsContainer = false,
|
|
456
|
-
minTouchDelta = 0
|
|
457
|
-
} = options;
|
|
458
|
-
|
|
459
|
-
// Common handlers
|
|
460
|
-
const handleUp = () => {
|
|
461
|
-
set(state => {
|
|
462
|
-
const deltaTime = Date.now() - state.startTime;
|
|
463
|
-
const xDelta = state.x - state.xInitial;
|
|
464
|
-
const yDelta = state.y - state.yInitial;
|
|
465
|
-
const xVelocity = calcVelocity(xDelta, deltaTime, state.xVelocity);
|
|
466
|
-
const yVelocity = calcVelocity(yDelta, deltaTime, state.yVelocity);
|
|
467
|
-
const newState = {
|
|
468
|
-
...state,
|
|
469
|
-
xVelocity,
|
|
470
|
-
yVelocity,
|
|
471
|
-
target: null,
|
|
472
|
-
down: false
|
|
473
|
-
};
|
|
474
|
-
return newState;
|
|
475
|
-
});
|
|
476
|
-
};
|
|
477
|
-
const handleDown = e => {
|
|
478
|
-
const {
|
|
479
|
-
target,
|
|
480
|
-
pageX,
|
|
481
|
-
pageY
|
|
482
|
-
} = e;
|
|
483
|
-
set(state => {
|
|
484
|
-
const newState = {
|
|
485
|
-
...state,
|
|
486
|
-
target,
|
|
487
|
-
x: pageX,
|
|
488
|
-
xDelta: 0,
|
|
489
|
-
xDeltaPercent: 0,
|
|
490
|
-
xVelocity: 0,
|
|
491
|
-
xInitial: pageX,
|
|
492
|
-
xPrev: pageX,
|
|
493
|
-
y: pageY,
|
|
494
|
-
yDelta: 0,
|
|
495
|
-
yDeltaPercent: 0,
|
|
496
|
-
yVelocity: 0,
|
|
497
|
-
yInitial: pageY,
|
|
498
|
-
yPrev: pageY,
|
|
499
|
-
startTime: Date.now(),
|
|
500
|
-
down: true,
|
|
501
|
-
scrollLocked: false
|
|
502
|
-
};
|
|
503
|
-
return newState;
|
|
504
|
-
});
|
|
505
|
-
};
|
|
506
|
-
function calcVelocity(deltaSpace, deltaTime, prevVelocity) {
|
|
507
|
-
if (deltaTime < 1) {
|
|
508
|
-
deltaTime = 1;
|
|
509
|
-
}
|
|
510
|
-
const speed = deltaSpace / deltaTime;
|
|
511
|
-
const depr = 0.5 + Math.min(deltaTime / VELOCITY_DEPR_FACTOR, 0.5);
|
|
512
|
-
return speed * depr + prevVelocity * (1 - depr);
|
|
513
|
-
}
|
|
514
|
-
function handleMove(e) {
|
|
515
|
-
const {
|
|
516
|
-
pageX,
|
|
517
|
-
pageY
|
|
518
|
-
} = e;
|
|
519
|
-
if (e.cancelable) {
|
|
520
|
-
// prevent drag & drop behaviour from browser
|
|
521
|
-
e.preventDefault && e.preventDefault();
|
|
522
|
-
}
|
|
523
|
-
set(state => {
|
|
524
|
-
function getDeltaSum(currentPos, initialPos, prevPos) {
|
|
525
|
-
if (state.scrollLocked || Math.abs(currentPos - initialPos) >= minTouchDelta) {
|
|
526
|
-
state.scrollLocked = true;
|
|
527
|
-
return currentPos - prevPos;
|
|
528
|
-
}
|
|
529
|
-
return 0;
|
|
530
|
-
}
|
|
531
|
-
const target = containerRef && containerRef.current || e.target;
|
|
532
|
-
const deltaTime = Date.now() - state.startTime;
|
|
533
|
-
const width = target ? target.offsetWidth : NaN;
|
|
534
|
-
const xDelta = state.xDelta + getDeltaSum(pageX, state.xInitial, state.x);
|
|
535
|
-
const xDeltaPercent = xDelta * 100 / width;
|
|
536
|
-
const xVelocity = calcVelocity(xDelta, deltaTime, state.xVelocity);
|
|
537
|
-
const height = target ? target.offsetHeight : NaN;
|
|
538
|
-
const yDelta = state.yDelta + getDeltaSum(pageY, state.yInitial, state.y);
|
|
539
|
-
const yDeltaPercent = yDelta * 100 / height;
|
|
540
|
-
const yVelocity = calcVelocity(yDelta, deltaTime, state.yVelocity);
|
|
541
|
-
const newState = {
|
|
542
|
-
...state,
|
|
543
|
-
xDelta,
|
|
544
|
-
xDeltaPercent,
|
|
545
|
-
x: pageX,
|
|
546
|
-
xPrev: state.x,
|
|
547
|
-
xVelocity,
|
|
548
|
-
yDelta,
|
|
549
|
-
yDeltaPercent,
|
|
550
|
-
y: pageY,
|
|
551
|
-
yPrev: state.y,
|
|
552
|
-
yVelocity
|
|
553
|
-
};
|
|
554
|
-
return newState;
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Touch handlers
|
|
559
|
-
|
|
560
|
-
function handleTouchMove(e) {
|
|
561
|
-
if (e.cancelable) {
|
|
562
|
-
// prevent drag & drop behaviour from browser
|
|
563
|
-
e.preventDefault();
|
|
564
|
-
}
|
|
565
|
-
handleMove(e.touches.item(0));
|
|
566
|
-
}
|
|
567
|
-
function handleTouchStart(e) {
|
|
568
|
-
// making sure we're not dragging the element when more than one finger press the screen
|
|
569
|
-
const {
|
|
570
|
-
touches
|
|
571
|
-
} = e;
|
|
572
|
-
if (touches.length > 1) {
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
if (ensureTargetIsContainer && containerRef && e.target !== containerRef.current) {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
const ownerDocument = getOwnerDocument(e.currentTarget);
|
|
579
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
580
|
-
ownerWindow.addEventListener('touchmove', handleTouchMove, {
|
|
581
|
-
passive: false
|
|
582
|
-
});
|
|
583
|
-
ownerWindow.addEventListener('touchend', handleTouchEnd);
|
|
584
|
-
ownerWindow.addEventListener('touchcancel', handleTouchEnd);
|
|
585
|
-
handleDown(e.touches.item(0));
|
|
586
|
-
}
|
|
587
|
-
function handleTouchEnd() {
|
|
588
|
-
this.removeEventListener('touchmove', handleTouchMove);
|
|
589
|
-
this.removeEventListener('touchend', handleTouchEnd);
|
|
590
|
-
this.removeEventListener('touchcancel', handleTouchEnd);
|
|
591
|
-
handleUp();
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// Mouse handlers
|
|
595
|
-
function handleMouseDown(e) {
|
|
596
|
-
if (ensureTargetIsContainer && containerRef && e.target !== containerRef.current) {
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
const ownerDocument = getOwnerDocument(e.currentTarget);
|
|
600
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
601
|
-
if (e.button === 0) {
|
|
602
|
-
ownerWindow.addEventListener('mousemove', handleMove);
|
|
603
|
-
ownerWindow.addEventListener('mouseup', handleMouseUp);
|
|
604
|
-
handleDown(e);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
function handleMouseUp() {
|
|
608
|
-
this.removeEventListener('mousemove', handleMove);
|
|
609
|
-
this.removeEventListener('mouseup', handleMouseUp);
|
|
610
|
-
handleUp();
|
|
611
|
-
}
|
|
612
|
-
return {
|
|
613
|
-
onMouseDown: handleMouseDown,
|
|
614
|
-
onTouchStart: handleTouchStart
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
const useGestureHandlers = (containerRef, onGesture, options = {}) => {
|
|
618
|
-
const state = react.useRef({
|
|
619
|
-
...initialGestureHandlersState
|
|
620
|
-
});
|
|
621
|
-
const set = cb => {
|
|
622
|
-
state.current = cb(state.current);
|
|
623
|
-
onGesture && onGesture(state.current);
|
|
624
|
-
return state.current;
|
|
625
|
-
};
|
|
626
|
-
const handlers = gestureHandlers(set, containerRef, options);
|
|
627
|
-
return {
|
|
628
|
-
state: state.current,
|
|
629
|
-
handlers
|
|
630
|
-
};
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
function getScope(rootRef) {
|
|
634
|
-
const queryAllNodes = matcherFn => {
|
|
635
|
-
if (!rootRef.current) {
|
|
636
|
-
return [];
|
|
637
|
-
}
|
|
638
|
-
const allNodes = rootRef.current.querySelectorAll('*');
|
|
639
|
-
const filtered = [];
|
|
640
|
-
allNodes.forEach(node => {
|
|
641
|
-
const props = {};
|
|
642
|
-
const {
|
|
643
|
-
attributes
|
|
644
|
-
} = node;
|
|
645
|
-
for (let i = 0; i < attributes.length; i++) {
|
|
646
|
-
const attr = attributes[i];
|
|
647
|
-
props[attr.name] = attr.value;
|
|
648
|
-
}
|
|
649
|
-
if (matcherFn(node.tagName.toLowerCase(), props, node)) {
|
|
650
|
-
filtered.push(node);
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
return filtered;
|
|
654
|
-
};
|
|
655
|
-
return {
|
|
656
|
-
queryAllNodes
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
function useScope(rootRef) {
|
|
660
|
-
const scope = react.useRef(getScope(rootRef));
|
|
661
|
-
return scope;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
const Accordion = /*#__PURE__*/react.forwardRef(function Accordion(props, forwardedRef) {
|
|
665
|
-
const {
|
|
666
|
-
as: Comp = 'div',
|
|
667
|
-
expandedIndex = -1,
|
|
668
|
-
onChange,
|
|
669
|
-
...otherProps
|
|
670
|
-
} = props;
|
|
671
|
-
const [childrenHeaderHasFocus, setChildrenHeaderHasFocus] = react.useState(false);
|
|
672
|
-
const ref = react.useRef(null);
|
|
673
|
-
const scope = useScope(ref);
|
|
674
|
-
const contextValue = {
|
|
675
|
-
childrenHeaderHasFocus,
|
|
676
|
-
setChildrenHeaderHasFocus,
|
|
677
|
-
scope,
|
|
678
|
-
expandedIndex,
|
|
679
|
-
onChange
|
|
680
|
-
};
|
|
681
|
-
return /*#__PURE__*/jsxRuntime.jsx(AccordionProvider, {
|
|
682
|
-
value: contextValue,
|
|
683
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
684
|
-
ref: assignMultipleRefs(forwardedRef, ref),
|
|
685
|
-
...otherProps,
|
|
686
|
-
"data-accordion-root": "",
|
|
687
|
-
"data-children-has-focus": childrenHeaderHasFocus
|
|
688
|
-
})
|
|
689
|
-
});
|
|
690
|
-
});
|
|
691
|
-
|
|
692
|
-
const AccordionItem = /*#__PURE__*/react.forwardRef(function AccordionItem(props, forwardedRef) {
|
|
693
|
-
const {
|
|
694
|
-
as: Comp = react.Fragment,
|
|
695
|
-
expanded = false,
|
|
696
|
-
onChange,
|
|
697
|
-
...otherProps
|
|
698
|
-
} = props;
|
|
699
|
-
const id = react.useId();
|
|
700
|
-
const headerId = id ? `accordion-header-${id}` : undefined;
|
|
701
|
-
const bodyId = id ? `accordion-body-${id}` : undefined;
|
|
702
|
-
const contextValue = {
|
|
703
|
-
headerId,
|
|
704
|
-
bodyId,
|
|
705
|
-
expanded,
|
|
706
|
-
onChange
|
|
707
|
-
};
|
|
708
|
-
return /*#__PURE__*/jsxRuntime.jsx(AccordionItemProvider, {
|
|
709
|
-
value: contextValue,
|
|
710
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
711
|
-
ref: forwardedRef,
|
|
712
|
-
...otherProps
|
|
713
|
-
})
|
|
714
|
-
});
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
function headerScopeQuery(type, props) {
|
|
718
|
-
return props['data-accordion-header'] === '';
|
|
719
|
-
}
|
|
720
|
-
function bodyScopeQuery(type, props) {
|
|
721
|
-
return props['data-accordion-body'] === '';
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
const AccordionHeader = /*#__PURE__*/react.forwardRef(function AccordionHeader(props, forwardedRef) {
|
|
725
|
-
const {
|
|
726
|
-
as: Comp = 'div',
|
|
727
|
-
onKeyDown,
|
|
728
|
-
onClick: onClickProp,
|
|
729
|
-
onFocus,
|
|
730
|
-
onBlur,
|
|
731
|
-
...otherProps
|
|
732
|
-
} = props;
|
|
733
|
-
const accordionContext = useAccordionContext();
|
|
734
|
-
const accordionItemContext = useAccordionItemContext();
|
|
735
|
-
const ref = react.useRef(null);
|
|
736
|
-
const [index, setIndex] = react.useState();
|
|
737
|
-
if (!accordionItemContext) {
|
|
738
|
-
throw new Error('Missing parent <Accordion /> component');
|
|
739
|
-
}
|
|
740
|
-
react.useEffect(() => {
|
|
741
|
-
if (accordionContext) {
|
|
742
|
-
const allHeaders = accordionContext.scope.current.queryAllNodes(headerScopeQuery) || [];
|
|
743
|
-
const index = allHeaders.findIndex(e => e === ref.current);
|
|
744
|
-
setIndex(index);
|
|
745
|
-
}
|
|
746
|
-
}, [accordionContext]);
|
|
747
|
-
const onClick = wrapEvent(onClickProp, e => {
|
|
748
|
-
let index = 0;
|
|
749
|
-
if (accordionItemContext.expanded) {
|
|
750
|
-
index = -1;
|
|
751
|
-
} else if (accordionContext) {
|
|
752
|
-
const allHeaders = accordionContext.scope.current.queryAllNodes(headerScopeQuery) || [];
|
|
753
|
-
index = allHeaders.findIndex(e => e === ref.current);
|
|
754
|
-
if (index === accordionContext.expandedIndex) {
|
|
755
|
-
index = -1;
|
|
756
|
-
}
|
|
757
|
-
accordionContext.onChange && accordionContext.onChange(e, index);
|
|
758
|
-
}
|
|
759
|
-
accordionItemContext.onChange && accordionItemContext.onChange(e, index >= 0);
|
|
760
|
-
});
|
|
761
|
-
const handleKeyDown = e => {
|
|
762
|
-
switch (e.key) {
|
|
763
|
-
case 'Enter':
|
|
764
|
-
case ' ':
|
|
765
|
-
{
|
|
766
|
-
onClick(e);
|
|
767
|
-
e.preventDefault();
|
|
768
|
-
break;
|
|
769
|
-
}
|
|
770
|
-
case 'ArrowUp':
|
|
771
|
-
case 'ArrowDown':
|
|
772
|
-
case 'Home':
|
|
773
|
-
case 'End':
|
|
774
|
-
{
|
|
775
|
-
if (!accordionContext) {
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
const allHeaders = accordionContext.scope.current.queryAllNodes(headerScopeQuery);
|
|
779
|
-
e.preventDefault();
|
|
780
|
-
if (allHeaders.length === 0) {
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
let nextIndex = allHeaders.findIndex(e => e === ref.current);
|
|
784
|
-
switch (e.key) {
|
|
785
|
-
case 'ArrowUp':
|
|
786
|
-
nextIndex += -1;
|
|
787
|
-
break;
|
|
788
|
-
case 'ArrowDown':
|
|
789
|
-
nextIndex += +1;
|
|
790
|
-
break;
|
|
791
|
-
case 'Home':
|
|
792
|
-
nextIndex = 0;
|
|
793
|
-
break;
|
|
794
|
-
case 'End':
|
|
795
|
-
nextIndex = -1;
|
|
796
|
-
break;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// We're sure it will not be null, because we already checked for allHeaders.length > 0 above
|
|
800
|
-
nextIndex = getCircularIndex(nextIndex, allHeaders.length);
|
|
801
|
-
allHeaders[nextIndex] && allHeaders[nextIndex].focus();
|
|
802
|
-
break;
|
|
803
|
-
}
|
|
804
|
-
default:
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
const handleFocus = () => {
|
|
809
|
-
if (accordionContext) {
|
|
810
|
-
if (!accordionContext.childrenHeaderHasFocus) {
|
|
811
|
-
// this is needed to avoid rerendering the parent and
|
|
812
|
-
// messing up with the internal count for children/parent count
|
|
813
|
-
accordionContext.setChildrenHeaderHasFocus(true);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
};
|
|
817
|
-
const handleBlur = e => {
|
|
818
|
-
if (accordionContext) {
|
|
819
|
-
const allHeaders = accordionContext.scope.current.queryAllNodes(headerScopeQuery);
|
|
820
|
-
const newFocusIsHeader = allHeaders.findIndex(header => header === e.relatedTarget) >= 0;
|
|
821
|
-
|
|
822
|
-
// only remove focus flag if the focus went to some element
|
|
823
|
-
// that is not an accordion header
|
|
824
|
-
if (!newFocusIsHeader) {
|
|
825
|
-
accordionContext.setChildrenHeaderHasFocus(false);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
const expanded = Boolean(accordionItemContext.expanded || accordionContext && accordionContext.expandedIndex === index);
|
|
830
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
831
|
-
ref: assignMultipleRefs(ref, forwardedRef),
|
|
832
|
-
...otherProps,
|
|
833
|
-
id: accordionItemContext.headerId,
|
|
834
|
-
"aria-controls": accordionItemContext.bodyId,
|
|
835
|
-
role: "button",
|
|
836
|
-
"data-accordion-header": "",
|
|
837
|
-
tabIndex: "0",
|
|
838
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
839
|
-
onFocus: wrapEvent(onFocus, handleFocus),
|
|
840
|
-
onBlur: wrapEvent(onBlur, handleBlur),
|
|
841
|
-
onClick: onClick,
|
|
842
|
-
"aria-expanded": String(expanded)
|
|
843
|
-
});
|
|
844
|
-
});
|
|
845
|
-
|
|
846
|
-
const AccordionBody = /*#__PURE__*/react.forwardRef(function AccordionBody(props, forwardedRef) {
|
|
847
|
-
const {
|
|
848
|
-
as: Comp = 'div',
|
|
849
|
-
...otherProps
|
|
850
|
-
} = props;
|
|
851
|
-
const accordionItemContext = useAccordionItemContext();
|
|
852
|
-
const accordionContext = useAccordionContext();
|
|
853
|
-
const ref = react.useRef(null);
|
|
854
|
-
const [index, setIndex] = react.useState();
|
|
855
|
-
if (!accordionItemContext) {
|
|
856
|
-
throw new Error('Missing parent <Accordion /> component');
|
|
857
|
-
}
|
|
858
|
-
react.useEffect(() => {
|
|
859
|
-
if (accordionContext) {
|
|
860
|
-
const allHeaders = accordionContext.scope.current.queryAllNodes(bodyScopeQuery);
|
|
861
|
-
const index = allHeaders.findIndex(e => e === ref.current);
|
|
862
|
-
setIndex(index);
|
|
863
|
-
}
|
|
864
|
-
}, [accordionContext]);
|
|
865
|
-
const expanded = Boolean(accordionItemContext.expanded || accordionContext && accordionContext.expandedIndex === index);
|
|
866
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
867
|
-
ref: assignMultipleRefs(forwardedRef, ref),
|
|
868
|
-
...otherProps,
|
|
869
|
-
"aria-labelledby": accordionItemContext.headerId,
|
|
870
|
-
id: accordionItemContext.bodyId,
|
|
871
|
-
role: "region",
|
|
872
|
-
"data-accordion-body": "",
|
|
873
|
-
hidden: expanded ? undefined : 'hidden'
|
|
874
|
-
});
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
const CheckBox = /*#__PURE__*/react.forwardRef(function CheckBox(props, forwardedRef) {
|
|
878
|
-
const {
|
|
879
|
-
as: Comp = 'input',
|
|
880
|
-
checked: checkedProp,
|
|
881
|
-
defaultChecked = false,
|
|
882
|
-
onChange: onChangeProp,
|
|
883
|
-
...otherProps
|
|
884
|
-
} = props;
|
|
885
|
-
const [checked, onChange] = useControlledState(checkedProp, onChangeProp, defaultChecked, setValue => e => {
|
|
886
|
-
setValue(e.target.checked);
|
|
887
|
-
});
|
|
888
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
889
|
-
ref: forwardedRef,
|
|
890
|
-
type: "checkbox",
|
|
891
|
-
checked: checked,
|
|
892
|
-
"aria-checked": checked,
|
|
893
|
-
onChange: onChange,
|
|
894
|
-
...otherProps
|
|
895
|
-
});
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
const comboboxContext = /*#__PURE__*/react.createContext(null);
|
|
899
|
-
const {
|
|
900
|
-
Provider: ComboBoxProvider
|
|
901
|
-
} = comboboxContext;
|
|
902
|
-
const useComboBoxContext = () => react.useContext(comboboxContext);
|
|
903
|
-
|
|
904
|
-
function scopeQuery$1(nodeType, props) {
|
|
905
|
-
return props['data-reach-combobox-option'] === '';
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
909
|
-
// States
|
|
910
|
-
|
|
911
|
-
// Nothing going on, waiting for the user to type or use the arrow keys
|
|
912
|
-
const IDLE = 'IDLE';
|
|
913
|
-
|
|
914
|
-
// The component is suggesting options as the user types
|
|
915
|
-
const SUGGESTING = 'SUGGESTING';
|
|
916
|
-
|
|
917
|
-
// The user is using the keyboard to navigate the list, not typing
|
|
918
|
-
const NAVIGATING = 'NAVIGATING';
|
|
919
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
920
|
-
// Actions:
|
|
921
|
-
|
|
922
|
-
// Used to sync the state with controlled state, right after mounting
|
|
923
|
-
const INIT = 'INIT';
|
|
924
|
-
|
|
925
|
-
// User cleared the value w/ backspace, but input still has focus
|
|
926
|
-
const CLEAR = 'CLEAR';
|
|
927
|
-
|
|
928
|
-
// User cleared the value w/ backspace, but input still has focus
|
|
929
|
-
const CLEAR_SELECTION = 'CLEAR_SELECTION';
|
|
930
|
-
|
|
931
|
-
// User is typing
|
|
932
|
-
const CHANGE = 'CHANGE';
|
|
933
|
-
|
|
934
|
-
// User is navigating w/ the keyboard
|
|
935
|
-
const NAVIGATE = 'NAVIGATE';
|
|
936
|
-
|
|
937
|
-
// User can be navigating with keyboard and then click instead, we want the
|
|
938
|
-
// value from the click, not the current nav item
|
|
939
|
-
const SELECT_WITH_KEYBOARD = 'SELECT_WITH_KEYBOARD';
|
|
940
|
-
const SELECT_WITH_CLICK = 'SELECT_WITH_CLICK';
|
|
941
|
-
|
|
942
|
-
// Pretty self-explanatory, user can hit escape or blur to close the popover
|
|
943
|
-
const ESCAPE = 'ESCAPE';
|
|
944
|
-
const BLUR = 'BLUR';
|
|
945
|
-
const FOCUS = 'FOCUS';
|
|
946
|
-
const OPEN_WITH_BUTTON = 'OPEN_WITH_BUTTON';
|
|
947
|
-
const CLOSE_WITH_BUTTON = 'CLOSE_WITH_BUTTON';
|
|
948
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
949
|
-
const stateChart = {
|
|
950
|
-
initial: IDLE,
|
|
951
|
-
states: {
|
|
952
|
-
[IDLE]: {
|
|
953
|
-
on: {
|
|
954
|
-
[BLUR]: IDLE,
|
|
955
|
-
[CLEAR]: IDLE,
|
|
956
|
-
[INIT]: IDLE,
|
|
957
|
-
[CLEAR_SELECTION]: IDLE,
|
|
958
|
-
[CHANGE]: SUGGESTING,
|
|
959
|
-
[FOCUS]: SUGGESTING,
|
|
960
|
-
[NAVIGATE]: NAVIGATING,
|
|
961
|
-
[OPEN_WITH_BUTTON]: SUGGESTING
|
|
962
|
-
}
|
|
963
|
-
},
|
|
964
|
-
[SUGGESTING]: {
|
|
965
|
-
on: {
|
|
966
|
-
[CHANGE]: SUGGESTING,
|
|
967
|
-
[FOCUS]: SUGGESTING,
|
|
968
|
-
[INIT]: SUGGESTING,
|
|
969
|
-
[NAVIGATE]: NAVIGATING,
|
|
970
|
-
[CLEAR]: IDLE,
|
|
971
|
-
[CLEAR_SELECTION]: SUGGESTING,
|
|
972
|
-
[ESCAPE]: IDLE,
|
|
973
|
-
[BLUR]: IDLE,
|
|
974
|
-
[SELECT_WITH_CLICK]: IDLE,
|
|
975
|
-
[CLOSE_WITH_BUTTON]: IDLE
|
|
976
|
-
}
|
|
977
|
-
},
|
|
978
|
-
[NAVIGATING]: {
|
|
979
|
-
on: {
|
|
980
|
-
[CHANGE]: SUGGESTING,
|
|
981
|
-
[FOCUS]: SUGGESTING,
|
|
982
|
-
[INIT]: NAVIGATING,
|
|
983
|
-
[CLEAR]: IDLE,
|
|
984
|
-
[CLEAR_SELECTION]: NAVIGATING,
|
|
985
|
-
[BLUR]: IDLE,
|
|
986
|
-
[ESCAPE]: IDLE,
|
|
987
|
-
[NAVIGATE]: NAVIGATING,
|
|
988
|
-
[SELECT_WITH_KEYBOARD]: IDLE,
|
|
989
|
-
[SELECT_WITH_CLICK]: IDLE,
|
|
990
|
-
[CLOSE_WITH_BUTTON]: IDLE
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
function comboboxReducer(data, action) {
|
|
996
|
-
const nextState = {
|
|
997
|
-
...data,
|
|
998
|
-
state: action.nextState,
|
|
999
|
-
lastActionType: action.type
|
|
1000
|
-
};
|
|
1001
|
-
switch (action.type) {
|
|
1002
|
-
case INIT:
|
|
1003
|
-
case CHANGE:
|
|
1004
|
-
return {
|
|
1005
|
-
...nextState,
|
|
1006
|
-
text: action.text,
|
|
1007
|
-
navigationItem: '',
|
|
1008
|
-
item: ''
|
|
1009
|
-
};
|
|
1010
|
-
case NAVIGATE:
|
|
1011
|
-
case OPEN_WITH_BUTTON:
|
|
1012
|
-
if (action.persistSelection) {
|
|
1013
|
-
return {
|
|
1014
|
-
...nextState,
|
|
1015
|
-
navigationItem: data.item
|
|
1016
|
-
};
|
|
1017
|
-
}
|
|
1018
|
-
return {
|
|
1019
|
-
...nextState,
|
|
1020
|
-
navigationItem: action.item
|
|
1021
|
-
};
|
|
1022
|
-
case CLEAR_SELECTION:
|
|
1023
|
-
return {
|
|
1024
|
-
...nextState,
|
|
1025
|
-
navigationItem: ''
|
|
1026
|
-
};
|
|
1027
|
-
case CLEAR:
|
|
1028
|
-
return {
|
|
1029
|
-
...nextState,
|
|
1030
|
-
text: '',
|
|
1031
|
-
navigationItem: '',
|
|
1032
|
-
item: ''
|
|
1033
|
-
};
|
|
1034
|
-
case BLUR:
|
|
1035
|
-
return {
|
|
1036
|
-
...nextState,
|
|
1037
|
-
text: action.text,
|
|
1038
|
-
navigationItem: '',
|
|
1039
|
-
item: action.item
|
|
1040
|
-
};
|
|
1041
|
-
case CLOSE_WITH_BUTTON:
|
|
1042
|
-
case ESCAPE:
|
|
1043
|
-
return {
|
|
1044
|
-
...nextState,
|
|
1045
|
-
navigationItem: '',
|
|
1046
|
-
item: ''
|
|
1047
|
-
};
|
|
1048
|
-
case SELECT_WITH_CLICK:
|
|
1049
|
-
case SELECT_WITH_KEYBOARD:
|
|
1050
|
-
return {
|
|
1051
|
-
...nextState,
|
|
1052
|
-
text: action.text,
|
|
1053
|
-
item: action.item,
|
|
1054
|
-
navigationItem: ''
|
|
1055
|
-
};
|
|
1056
|
-
case FOCUS:
|
|
1057
|
-
return {
|
|
1058
|
-
...nextState,
|
|
1059
|
-
navigationItem: action.item
|
|
1060
|
-
};
|
|
1061
|
-
default:
|
|
1062
|
-
throw new Error(`Unknown action ${action.type}`);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
const visibleStates = [SUGGESTING, NAVIGATING];
|
|
1066
|
-
const isVisible = state => visibleStates.indexOf(state) >= 0;
|
|
1067
|
-
|
|
1068
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
1069
|
-
// The rest is all implementation details
|
|
1070
|
-
|
|
1071
|
-
// Move focus back to the input if we start navigating w/ the
|
|
1072
|
-
// keyboard after focus has moved to any focusable content in
|
|
1073
|
-
// the popup.
|
|
1074
|
-
function useFocusManagement(lastActionType, inputRef) {
|
|
1075
|
-
// useEffect so that the cursor goes to the end of the input instead
|
|
1076
|
-
// of awkwardly at the beginning, unclear to me why ...
|
|
1077
|
-
react.useEffect(() => {
|
|
1078
|
-
if (lastActionType === NAVIGATE || lastActionType === ESCAPE || lastActionType === SELECT_WITH_CLICK || lastActionType === OPEN_WITH_BUTTON) {
|
|
1079
|
-
inputRef.current && inputRef.current.focus();
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
function getNextItem(currentItem, key, optionsItems, autocomplete) {
|
|
1084
|
-
const jumpToStartOrEnd = key === 'Home' || key === 'End';
|
|
1085
|
-
let incr = 1;
|
|
1086
|
-
switch (key) {
|
|
1087
|
-
case 'PageUp':
|
|
1088
|
-
incr = -10;
|
|
1089
|
-
break;
|
|
1090
|
-
case 'PageDown':
|
|
1091
|
-
incr = 10;
|
|
1092
|
-
break;
|
|
1093
|
-
case 'End':
|
|
1094
|
-
case 'ArrowUp':
|
|
1095
|
-
incr = -1;
|
|
1096
|
-
break;
|
|
1097
|
-
case 'Home':
|
|
1098
|
-
case 'ArrowDown':
|
|
1099
|
-
incr = 1;
|
|
1100
|
-
break;
|
|
1101
|
-
}
|
|
1102
|
-
const index = currentItem === '' ? -1 : optionsItems.findIndex(n => String(n.id) === currentItem);
|
|
1103
|
-
const optionsLen = optionsItems.length;
|
|
1104
|
-
|
|
1105
|
-
// Nothing selected, either go to start, or end
|
|
1106
|
-
if (index < 0 || jumpToStartOrEnd) {
|
|
1107
|
-
if (incr > 0) {
|
|
1108
|
-
// Go to start
|
|
1109
|
-
return optionsItems[0];
|
|
1110
|
-
} else {
|
|
1111
|
-
// Go to end
|
|
1112
|
-
return optionsItems[optionsLen - 1];
|
|
1113
|
-
}
|
|
1114
|
-
} else if (autocomplete) {
|
|
1115
|
-
const nextIndex = index + incr;
|
|
1116
|
-
if (nextIndex < 0 || nextIndex >= optionsLen) {
|
|
1117
|
-
// Next is outside the bounds of list, return nothing selected
|
|
1118
|
-
return null;
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
// I'm sure it won't be null, we already check optionsLen above
|
|
1123
|
-
return optionsItems[getCircularIndex(index + incr, optionsLen)];
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
// We want the same events when the input or the popup have focus (HOW COOL ARE
|
|
1127
|
-
// HOOKS BTW?) This is probably the hairiest piece but it's not bad.
|
|
1128
|
-
function useKeyDown() {
|
|
1129
|
-
const {
|
|
1130
|
-
data: {
|
|
1131
|
-
text,
|
|
1132
|
-
navigationItem
|
|
1133
|
-
},
|
|
1134
|
-
onSelect,
|
|
1135
|
-
optionsRef,
|
|
1136
|
-
inputRef,
|
|
1137
|
-
state,
|
|
1138
|
-
transition,
|
|
1139
|
-
autocompletePropRef,
|
|
1140
|
-
clearOnEscapeRef,
|
|
1141
|
-
persistSelectionRef,
|
|
1142
|
-
listScope
|
|
1143
|
-
} = useComboBoxContext();
|
|
1144
|
-
return function handleKeyDown(event) {
|
|
1145
|
-
const optionNodes = listScope.current.queryAllNodes(scopeQuery$1);
|
|
1146
|
-
switch (event.key) {
|
|
1147
|
-
case 'Home':
|
|
1148
|
-
case 'End':
|
|
1149
|
-
case 'PageUp':
|
|
1150
|
-
case 'PageDown':
|
|
1151
|
-
case 'ArrowUp':
|
|
1152
|
-
case 'ArrowDown':
|
|
1153
|
-
{
|
|
1154
|
-
// Don't scroll the page
|
|
1155
|
-
event.preventDefault();
|
|
1156
|
-
const optionsLen = optionNodes.length;
|
|
1157
|
-
|
|
1158
|
-
// If the developer didn't render any options, there's no point in
|
|
1159
|
-
// trying to navigate--but seriously what the heck? Give us some
|
|
1160
|
-
// options fam.
|
|
1161
|
-
if (optionsLen === 0) {
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
if (state === IDLE) {
|
|
1165
|
-
// Opening a closed list
|
|
1166
|
-
transition(NAVIGATE, {
|
|
1167
|
-
persistSelection: persistSelectionRef.current
|
|
1168
|
-
});
|
|
1169
|
-
} else {
|
|
1170
|
-
// When autocompletting, we'll not cycle through the list directly
|
|
1171
|
-
const autocomplete = autocompletePropRef.current;
|
|
1172
|
-
|
|
1173
|
-
// Get next selected item
|
|
1174
|
-
const nextItem = getNextItem(navigationItem, event.key, optionNodes, autocomplete);
|
|
1175
|
-
if (nextItem !== null) {
|
|
1176
|
-
nextItem.scrollIntoView({
|
|
1177
|
-
behavior: 'auto',
|
|
1178
|
-
block: 'nearest'
|
|
1179
|
-
});
|
|
1180
|
-
transition(NAVIGATE, {
|
|
1181
|
-
value: optionsRef.current[nextItem.id].text,
|
|
1182
|
-
item: nextItem.id
|
|
1183
|
-
});
|
|
1184
|
-
} else {
|
|
1185
|
-
transition(NAVIGATE, {
|
|
1186
|
-
value: null,
|
|
1187
|
-
item: ''
|
|
1188
|
-
});
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
break;
|
|
1192
|
-
}
|
|
1193
|
-
case 'Escape':
|
|
1194
|
-
{
|
|
1195
|
-
if (state !== IDLE) {
|
|
1196
|
-
transition(ESCAPE);
|
|
1197
|
-
} else if (state === IDLE && text !== '') {
|
|
1198
|
-
if (!inputRef.current || !clearOnEscapeRef.current) {
|
|
1199
|
-
break;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
// emulate a inputRef change event, might not work in future versions of React
|
|
1203
|
-
const lastValue = inputRef.current.value;
|
|
1204
|
-
inputRef.current.value = '';
|
|
1205
|
-
const tracker = inputRef.current._valueTracker;
|
|
1206
|
-
if (tracker) {
|
|
1207
|
-
tracker.setValue(lastValue);
|
|
1208
|
-
}
|
|
1209
|
-
const event = new Event('change', {
|
|
1210
|
-
bubbles: true
|
|
1211
|
-
});
|
|
1212
|
-
inputRef.current.dispatchEvent(event);
|
|
1213
|
-
}
|
|
1214
|
-
break;
|
|
1215
|
-
}
|
|
1216
|
-
case 'Enter':
|
|
1217
|
-
{
|
|
1218
|
-
if (state === NAVIGATING && navigationItem !== '') {
|
|
1219
|
-
const {
|
|
1220
|
-
value: navigationValue,
|
|
1221
|
-
text: navigationText
|
|
1222
|
-
} = optionsRef.current[navigationItem];
|
|
1223
|
-
|
|
1224
|
-
// don't want to submit forms
|
|
1225
|
-
event.preventDefault();
|
|
1226
|
-
onSelect && onSelect(navigationText, navigationItem, navigationValue);
|
|
1227
|
-
transition(SELECT_WITH_KEYBOARD, {
|
|
1228
|
-
text: navigationText,
|
|
1229
|
-
item: navigationItem
|
|
1230
|
-
});
|
|
1231
|
-
}
|
|
1232
|
-
break;
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
function useBlur() {
|
|
1238
|
-
const {
|
|
1239
|
-
data: {
|
|
1240
|
-
navigationItem,
|
|
1241
|
-
text: stateText
|
|
1242
|
-
},
|
|
1243
|
-
transition,
|
|
1244
|
-
optionsRef,
|
|
1245
|
-
popoverRef,
|
|
1246
|
-
inputRef,
|
|
1247
|
-
buttonRef,
|
|
1248
|
-
onSelect,
|
|
1249
|
-
selectOnBlur // not implemented yet
|
|
1250
|
-
} = useComboBoxContext();
|
|
1251
|
-
return function handleBlur() {
|
|
1252
|
-
requestAnimationFrame(() => {
|
|
1253
|
-
// we on want to close only if focus rests outside the combobox
|
|
1254
|
-
if (document.activeElement !== inputRef.current && document.activeElement !== buttonRef.current && popoverRef.current) {
|
|
1255
|
-
if (popoverRef.current.contains(document.activeElement)) ; else {
|
|
1256
|
-
// focus landed outside the combobox, close it.
|
|
1257
|
-
if (!selectOnBlur || navigationItem === '') {
|
|
1258
|
-
// we don't wanna select on blur, or navigationIndex is invalid
|
|
1259
|
-
transition(BLUR, {
|
|
1260
|
-
text: stateText,
|
|
1261
|
-
item: ''
|
|
1262
|
-
});
|
|
1263
|
-
} else {
|
|
1264
|
-
// select the currently selected item
|
|
1265
|
-
const {
|
|
1266
|
-
value: navigationValue,
|
|
1267
|
-
text: navigationText
|
|
1268
|
-
} = optionsRef.current[navigationItem];
|
|
1269
|
-
onSelect && onSelect(navigationText, navigationItem, navigationValue);
|
|
1270
|
-
transition(BLUR, {
|
|
1271
|
-
text: navigationText,
|
|
1272
|
-
item: navigationItem
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
});
|
|
1278
|
-
};
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
const Combobox = /*#__PURE__*/react.forwardRef(function Combobox({
|
|
1282
|
-
// Called whenever the user selects an item from the list
|
|
1283
|
-
onSelect,
|
|
1284
|
-
// opens the list when the input receives focused (but only if there are
|
|
1285
|
-
// items in the list)
|
|
1286
|
-
openOnFocus = false,
|
|
1287
|
-
// if set to true, it will select an item after blurring
|
|
1288
|
-
selectOnBlur = false,
|
|
1289
|
-
children,
|
|
1290
|
-
as: Comp = 'div',
|
|
1291
|
-
innerAs,
|
|
1292
|
-
...rest
|
|
1293
|
-
}, ref) {
|
|
1294
|
-
// We store the values of all the ComboboxOptions on this ref. This makes it
|
|
1295
|
-
// possible to perform the keyboard navigation from the input on the list. We
|
|
1296
|
-
// manipulate this array through context so that we don't have to enforce a
|
|
1297
|
-
// parent/child relationship between ComboboxList and ComboboxOption.
|
|
1298
|
-
const optionsRef = react.useRef({});
|
|
1299
|
-
const listScope = react.useRef(getScope({
|
|
1300
|
-
current: null
|
|
1301
|
-
}));
|
|
1302
|
-
|
|
1303
|
-
// Need this to focus it
|
|
1304
|
-
const inputRef = react.useRef(null);
|
|
1305
|
-
const popoverRef = react.useRef(null);
|
|
1306
|
-
const buttonRef = react.useRef(null);
|
|
1307
|
-
|
|
1308
|
-
// When <ComboboxInput autocomplete={false} /> we don't want cycle back to
|
|
1309
|
-
// the user's value while navigating (because it's always the user's value),
|
|
1310
|
-
// but we need to know this in useKeyDown which is far away from the prop
|
|
1311
|
-
// here, so we do something sneaky and write it to this ref on context so we
|
|
1312
|
-
// can use it anywhere else 😛. Another new trick for me and I'm excited
|
|
1313
|
-
// about this one too!
|
|
1314
|
-
const autocompletePropRef = react.useRef(false);
|
|
1315
|
-
const persistSelectionRef = react.useRef(false);
|
|
1316
|
-
const clearOnEscapeRef = react.useRef(false);
|
|
1317
|
-
const listboxIdRef = react.useRef(undefined);
|
|
1318
|
-
const labelIdRef = react.useRef(undefined);
|
|
1319
|
-
const defaultData = {
|
|
1320
|
-
// initial state
|
|
1321
|
-
state: stateChart.initial,
|
|
1322
|
-
// the value the user has typed, we derived this also when the developer is
|
|
1323
|
-
// controlling the value of ComboboxInput
|
|
1324
|
-
text: '',
|
|
1325
|
-
// the index the user has typed, we derived this also when the developer is
|
|
1326
|
-
// controlling the value of ComboboxInput
|
|
1327
|
-
item: '',
|
|
1328
|
-
// the hash of the currently navigated item
|
|
1329
|
-
navigationItem: '',
|
|
1330
|
-
// the last submitted action
|
|
1331
|
-
lastActionType: INIT
|
|
1332
|
-
};
|
|
1333
|
-
const [state, data, transition] = useReducerMachine(stateChart, comboboxReducer, defaultData);
|
|
1334
|
-
listboxIdRef.current = react.useId();
|
|
1335
|
-
labelIdRef.current = react.useId();
|
|
1336
|
-
const context = react.useMemo(() => ({
|
|
1337
|
-
data,
|
|
1338
|
-
inputRef,
|
|
1339
|
-
popoverRef,
|
|
1340
|
-
buttonRef,
|
|
1341
|
-
onSelect,
|
|
1342
|
-
optionsRef,
|
|
1343
|
-
listScope,
|
|
1344
|
-
state,
|
|
1345
|
-
transition,
|
|
1346
|
-
listboxIdRef,
|
|
1347
|
-
labelIdRef,
|
|
1348
|
-
autocompletePropRef,
|
|
1349
|
-
persistSelectionRef,
|
|
1350
|
-
clearOnEscapeRef,
|
|
1351
|
-
isVisible: isVisible(state),
|
|
1352
|
-
openOnFocus,
|
|
1353
|
-
selectOnBlur
|
|
1354
|
-
}), [data, onSelect, listScope, state, transition, openOnFocus, selectOnBlur]);
|
|
1355
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboBoxProvider, {
|
|
1356
|
-
value: context,
|
|
1357
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1358
|
-
...rest,
|
|
1359
|
-
as: innerAs,
|
|
1360
|
-
"data-reach-combobox": "",
|
|
1361
|
-
ref: ref,
|
|
1362
|
-
role: "combobox",
|
|
1363
|
-
"aria-haspopup": "listbox",
|
|
1364
|
-
"aria-owns": listboxIdRef.current,
|
|
1365
|
-
"aria-expanded": context.isVisible,
|
|
1366
|
-
children: children
|
|
1367
|
-
})
|
|
1368
|
-
});
|
|
1369
|
-
});
|
|
1370
|
-
|
|
1371
|
-
const ComboboxButton = /*#__PURE__*/react.forwardRef(function ComboboxButton({
|
|
1372
|
-
as: Comp = 'button',
|
|
1373
|
-
innerAs,
|
|
1374
|
-
onClick,
|
|
1375
|
-
onKeyDown,
|
|
1376
|
-
...props
|
|
1377
|
-
}, ref) {
|
|
1378
|
-
const {
|
|
1379
|
-
transition,
|
|
1380
|
-
data,
|
|
1381
|
-
state,
|
|
1382
|
-
buttonRef,
|
|
1383
|
-
listboxIdRef,
|
|
1384
|
-
isVisible
|
|
1385
|
-
} = useComboBoxContext();
|
|
1386
|
-
const handleKeyDown = useKeyDown();
|
|
1387
|
-
const handleClick = () => {
|
|
1388
|
-
const payload = {
|
|
1389
|
-
item: data.navigationItem
|
|
1390
|
-
};
|
|
1391
|
-
if (state === IDLE) {
|
|
1392
|
-
transition(OPEN_WITH_BUTTON, payload);
|
|
1393
|
-
} else {
|
|
1394
|
-
transition(CLOSE_WITH_BUTTON, payload);
|
|
1395
|
-
}
|
|
1396
|
-
};
|
|
1397
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1398
|
-
as: innerAs,
|
|
1399
|
-
"data-reach-combobox-button": "",
|
|
1400
|
-
"aria-controls": listboxIdRef.current,
|
|
1401
|
-
"aria-haspopup": "listbox",
|
|
1402
|
-
"aria-expanded": isVisible,
|
|
1403
|
-
ref: assignMultipleRefs(ref, buttonRef),
|
|
1404
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
1405
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
1406
|
-
...props
|
|
1407
|
-
});
|
|
1408
|
-
});
|
|
1409
|
-
|
|
1410
|
-
const ComboboxInput = /*#__PURE__*/react.forwardRef(function ComboboxInput({
|
|
1411
|
-
as: Comp = 'input',
|
|
1412
|
-
innerAs,
|
|
1413
|
-
selectOnClick = false,
|
|
1414
|
-
autocomplete = true,
|
|
1415
|
-
clearOnEscape = false,
|
|
1416
|
-
// wrapped events
|
|
1417
|
-
onClick,
|
|
1418
|
-
onChange,
|
|
1419
|
-
onKeyDown,
|
|
1420
|
-
onBlur,
|
|
1421
|
-
onFocus,
|
|
1422
|
-
id: preferredId,
|
|
1423
|
-
defaultValue = '',
|
|
1424
|
-
// might be controlled
|
|
1425
|
-
value: controlledValue,
|
|
1426
|
-
...props
|
|
1427
|
-
}, forwardedRef) {
|
|
1428
|
-
const {
|
|
1429
|
-
data: {
|
|
1430
|
-
navigationItem,
|
|
1431
|
-
text,
|
|
1432
|
-
lastActionType
|
|
1433
|
-
},
|
|
1434
|
-
inputRef,
|
|
1435
|
-
state,
|
|
1436
|
-
transition,
|
|
1437
|
-
listboxIdRef,
|
|
1438
|
-
autocompletePropRef,
|
|
1439
|
-
clearOnEscapeRef,
|
|
1440
|
-
openOnFocus,
|
|
1441
|
-
optionsRef,
|
|
1442
|
-
labelIdRef
|
|
1443
|
-
} = useComboBoxContext();
|
|
1444
|
-
|
|
1445
|
-
// Keep focus on the input component
|
|
1446
|
-
useFocusManagement(lastActionType, inputRef);
|
|
1447
|
-
|
|
1448
|
-
// Keep using the defaultValue until the user started interacting
|
|
1449
|
-
const hasStartedInteracting = react.useRef(false);
|
|
1450
|
-
|
|
1451
|
-
// Because we close the List on blur, we need to track if the blur is
|
|
1452
|
-
// caused by clicking inside the list, and if so, don't close the List.
|
|
1453
|
-
const selectOnClickRef = react.useRef(false);
|
|
1454
|
-
const handleBlur = useBlur();
|
|
1455
|
-
|
|
1456
|
-
// Update ref props
|
|
1457
|
-
autocompletePropRef.current = autocomplete;
|
|
1458
|
-
clearOnEscapeRef.current = clearOnEscape;
|
|
1459
|
-
listboxIdRef.current = preferredId || listboxIdRef.current;
|
|
1460
|
-
|
|
1461
|
-
// [*]... and when controlled, we don't trigger handleValueChange as the user
|
|
1462
|
-
// types, instead the developer controls it with the normal input onChange
|
|
1463
|
-
// prop
|
|
1464
|
-
const handleChange = e => {
|
|
1465
|
-
// After the user started typing, lets forget the defaultValue
|
|
1466
|
-
hasStartedInteracting.current = true;
|
|
1467
|
-
const text = e.target.value;
|
|
1468
|
-
if (text.trim() === '') {
|
|
1469
|
-
transition(CLEAR);
|
|
1470
|
-
} else {
|
|
1471
|
-
transition(CHANGE, {
|
|
1472
|
-
text
|
|
1473
|
-
});
|
|
1474
|
-
}
|
|
1475
|
-
};
|
|
1476
|
-
const handleKeyDown = useKeyDown();
|
|
1477
|
-
const handleFocus = () => {
|
|
1478
|
-
if (selectOnClick) {
|
|
1479
|
-
selectOnClickRef.current = true;
|
|
1480
|
-
}
|
|
1481
|
-
// If we select an option with click, useFocusManagement will focus the
|
|
1482
|
-
// input, in those cases we don't want to cause the menu to open back up,
|
|
1483
|
-
// so we guard behind these states
|
|
1484
|
-
if (openOnFocus && lastActionType !== SELECT_WITH_CLICK) {
|
|
1485
|
-
transition(FOCUS, {
|
|
1486
|
-
item: navigationItem
|
|
1487
|
-
});
|
|
1488
|
-
}
|
|
1489
|
-
};
|
|
1490
|
-
const handleClick = () => {
|
|
1491
|
-
if (selectOnClickRef.current) {
|
|
1492
|
-
selectOnClickRef.current = false;
|
|
1493
|
-
inputRef.current && inputRef.current.select();
|
|
1494
|
-
}
|
|
1495
|
-
};
|
|
1496
|
-
const navigationText = navigationItem !== '' ? optionsRef.current[navigationItem].text : undefined;
|
|
1497
|
-
const fallbackValue = hasStartedInteracting.current ? '' : defaultValue;
|
|
1498
|
-
const inputStrings =
|
|
1499
|
-
// When idle, we don't have a navigationText on ArrowUp/Down
|
|
1500
|
-
autocomplete && state === NAVIGATING ? [navigationText, controlledValue, text, fallbackValue] : [controlledValue, text, fallbackValue];
|
|
1501
|
-
const inputValue = inputStrings.find(str => str !== undefined);
|
|
1502
|
-
|
|
1503
|
-
// If they are controlling the value we still need to do our transitions, so
|
|
1504
|
-
// we have this derived state to emulate onChange of the input as we receive
|
|
1505
|
-
// new `value`s ...[*]
|
|
1506
|
-
react.useEffect(() => {
|
|
1507
|
-
transition(INIT, {
|
|
1508
|
-
text: inputValue,
|
|
1509
|
-
item: ''
|
|
1510
|
-
});
|
|
1511
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1512
|
-
}, []);
|
|
1513
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1514
|
-
...props,
|
|
1515
|
-
as: innerAs,
|
|
1516
|
-
"data-reach-combobox-input": "",
|
|
1517
|
-
ref: assignMultipleRefs(inputRef, forwardedRef),
|
|
1518
|
-
value: inputValue,
|
|
1519
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
1520
|
-
onBlur: wrapEvent(onBlur, handleBlur),
|
|
1521
|
-
onFocus: wrapEvent(onFocus, handleFocus),
|
|
1522
|
-
onChange: wrapEvent(onChange, handleChange),
|
|
1523
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
1524
|
-
"aria-labelledby": labelIdRef.current,
|
|
1525
|
-
id: listboxIdRef.current,
|
|
1526
|
-
"aria-autocomplete": "both",
|
|
1527
|
-
"aria-activedescendant": navigationItem !== '' ? navigationItem : undefined,
|
|
1528
|
-
autoComplete: "off"
|
|
1529
|
-
});
|
|
1530
|
-
});
|
|
1531
|
-
|
|
1532
|
-
const ComboboxLabel = /*#__PURE__*/react.forwardRef(function ComboboxButton({
|
|
1533
|
-
as: Comp = 'label',
|
|
1534
|
-
innerAs,
|
|
1535
|
-
id: preferredId,
|
|
1536
|
-
...props
|
|
1537
|
-
}, ref) {
|
|
1538
|
-
const {
|
|
1539
|
-
listboxIdRef,
|
|
1540
|
-
labelIdRef
|
|
1541
|
-
} = useComboBoxContext();
|
|
1542
|
-
labelIdRef.current = preferredId || labelIdRef.current;
|
|
1543
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1544
|
-
as: innerAs,
|
|
1545
|
-
"data-reach-combobox-label": "",
|
|
1546
|
-
htmlFor: listboxIdRef.current,
|
|
1547
|
-
id: labelIdRef.current,
|
|
1548
|
-
ref: ref,
|
|
1549
|
-
...props
|
|
1550
|
-
});
|
|
1551
|
-
});
|
|
1552
|
-
|
|
1553
|
-
const ComboboxList = /*#__PURE__*/react.forwardRef(function ComboboxList({
|
|
1554
|
-
// when true, and the list opens again, the option with a matching value will be
|
|
1555
|
-
// automatically highleted.
|
|
1556
|
-
persistSelection = false,
|
|
1557
|
-
as: Comp = 'ul',
|
|
1558
|
-
innerAs,
|
|
1559
|
-
...props
|
|
1560
|
-
}, ref) {
|
|
1561
|
-
const {
|
|
1562
|
-
persistSelectionRef,
|
|
1563
|
-
labelIdRef,
|
|
1564
|
-
listScope
|
|
1565
|
-
} = useComboBoxContext();
|
|
1566
|
-
const listRef = react.useRef(null);
|
|
1567
|
-
react.useEffect(() => {
|
|
1568
|
-
listScope.current = getScope(listRef);
|
|
1569
|
-
}, [listScope]);
|
|
1570
|
-
persistSelectionRef.current = persistSelection;
|
|
1571
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1572
|
-
...props,
|
|
1573
|
-
as: innerAs,
|
|
1574
|
-
ref: assignMultipleRefs(ref, listRef),
|
|
1575
|
-
"data-reach-combobox-list": "",
|
|
1576
|
-
role: "listbox",
|
|
1577
|
-
"aria-labelledby": labelIdRef.current
|
|
1578
|
-
});
|
|
1579
|
-
});
|
|
1580
|
-
|
|
1581
|
-
// We don't want to track the active descendant with indexes because nothing is
|
|
1582
|
-
// more annoying in a combobox than having it change values RIGHT AS YOU HIT
|
|
1583
|
-
// ENTER. That only happens if you use the index as your data, rather than
|
|
1584
|
-
// *your data as your data*. We use this to generate a unique ID based on the
|
|
1585
|
-
// value of each item. This function is short, sweet, and good enough™ (I also
|
|
1586
|
-
// don't know how it works, tbqh)
|
|
1587
|
-
// https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript
|
|
1588
|
-
function makeHash(str) {
|
|
1589
|
-
let hash = 0;
|
|
1590
|
-
if (str.length === 0) {
|
|
1591
|
-
return hash;
|
|
1592
|
-
}
|
|
1593
|
-
for (let i = 0; i < str.length; i++) {
|
|
1594
|
-
const char = str.charCodeAt(i);
|
|
1595
|
-
hash = (hash << 5) - hash + char;
|
|
1596
|
-
hash = hash & hash;
|
|
1597
|
-
}
|
|
1598
|
-
return hash;
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
const ComboboxOption = /*#__PURE__*/react.forwardRef(function ComboboxOption({
|
|
1602
|
-
children,
|
|
1603
|
-
id: idProp,
|
|
1604
|
-
value: valueProp,
|
|
1605
|
-
text: textProp,
|
|
1606
|
-
onClick,
|
|
1607
|
-
as: Comp = 'li',
|
|
1608
|
-
innerAs,
|
|
1609
|
-
...props
|
|
1610
|
-
}, ref) {
|
|
1611
|
-
const {
|
|
1612
|
-
onSelect,
|
|
1613
|
-
data: {
|
|
1614
|
-
navigationItem
|
|
1615
|
-
},
|
|
1616
|
-
transition,
|
|
1617
|
-
optionsRef
|
|
1618
|
-
} = useComboBoxContext();
|
|
1619
|
-
const transitionCleanupRef = react.useRef(transition);
|
|
1620
|
-
const isActiveRef = react.useRef(false);
|
|
1621
|
-
const value = valueProp;
|
|
1622
|
-
let text = textProp ? textProp : '';
|
|
1623
|
-
if (text.length === 0) {
|
|
1624
|
-
if (typeof valueProp === 'string' && valueProp.length > 0) {
|
|
1625
|
-
text = valueProp;
|
|
1626
|
-
} else {
|
|
1627
|
-
throw new Error('Missing text for <ComboboxOption />');
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
const id = String(makeHash(idProp));
|
|
1631
|
-
react.useEffect(() => {
|
|
1632
|
-
const opts = optionsRef.current;
|
|
1633
|
-
opts[id] = {
|
|
1634
|
-
value,
|
|
1635
|
-
text
|
|
1636
|
-
};
|
|
1637
|
-
return () => {
|
|
1638
|
-
delete opts[id];
|
|
1639
|
-
};
|
|
1640
|
-
}, [optionsRef, id, text, value]);
|
|
1641
|
-
|
|
1642
|
-
// Keep updating this ref with the current
|
|
1643
|
-
// function pointer for transition, so it can
|
|
1644
|
-
// be used by the unmount effect below.
|
|
1645
|
-
transitionCleanupRef.current = transition;
|
|
1646
|
-
isActiveRef.current = navigationItem === id;
|
|
1647
|
-
react.useEffect(() => {
|
|
1648
|
-
return () => {
|
|
1649
|
-
if (isActiveRef.current === true) {
|
|
1650
|
-
// clean up selections if this option is getting
|
|
1651
|
-
// unmounted and it was the currently selected item
|
|
1652
|
-
transitionCleanupRef.current(CLEAR_SELECTION);
|
|
1653
|
-
}
|
|
1654
|
-
};
|
|
1655
|
-
}, []);
|
|
1656
|
-
const handleClick = () => {
|
|
1657
|
-
onSelect && onSelect(text, id, value);
|
|
1658
|
-
transition(SELECT_WITH_CLICK, {
|
|
1659
|
-
text,
|
|
1660
|
-
item: id
|
|
1661
|
-
});
|
|
1662
|
-
};
|
|
1663
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1664
|
-
...props,
|
|
1665
|
-
as: innerAs,
|
|
1666
|
-
"data-reach-combobox-option": "",
|
|
1667
|
-
ref: ref,
|
|
1668
|
-
id: id,
|
|
1669
|
-
role: "option",
|
|
1670
|
-
"aria-selected": isActiveRef.current,
|
|
1671
|
-
"data-highlighted": isActiveRef.current ? '' : undefined
|
|
1672
|
-
// without this the menu will close from `onBlur`, but with it the
|
|
1673
|
-
// element can be `document.activeElement` and then our focus checks in
|
|
1674
|
-
// onBlur will work as intended
|
|
1675
|
-
,
|
|
1676
|
-
tabIndex: "-1",
|
|
1677
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
1678
|
-
children: children || text
|
|
1679
|
-
});
|
|
1680
|
-
});
|
|
1681
|
-
|
|
1682
|
-
const ComboboxPopover = /*#__PURE__*/react.forwardRef(function ComboboxPopover({
|
|
1683
|
-
// wrapped events
|
|
1684
|
-
onKeyDown,
|
|
1685
|
-
onBlur,
|
|
1686
|
-
as: Comp = 'div',
|
|
1687
|
-
innerAs,
|
|
1688
|
-
...props
|
|
1689
|
-
}, forwardedRef) {
|
|
1690
|
-
const {
|
|
1691
|
-
popoverRef,
|
|
1692
|
-
isVisible
|
|
1693
|
-
} = useComboBoxContext();
|
|
1694
|
-
const handleKeyDown = useKeyDown();
|
|
1695
|
-
const handleBlur = useBlur();
|
|
1696
|
-
|
|
1697
|
-
// Instead of conditionally rendering the popover we use the `hidden` prop
|
|
1698
|
-
// because we don't want to unmount on close (from escape or onSelect). If
|
|
1699
|
-
// we unmounted, then we'd lose the optionsRef and the user wouldn't be able
|
|
1700
|
-
// to use the arrow keys to pop the list back open. However, the developer
|
|
1701
|
-
// can conditionally render the ComboboxPopover if they do want to cause
|
|
1702
|
-
// mount/unmount based on the app's own data (like results.length or
|
|
1703
|
-
// whatever).
|
|
1704
|
-
const hidden = !isVisible;
|
|
1705
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1706
|
-
...props,
|
|
1707
|
-
as: innerAs,
|
|
1708
|
-
"data-reach-combobox-popover": "",
|
|
1709
|
-
ref: assignMultipleRefs(popoverRef, forwardedRef),
|
|
1710
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
1711
|
-
onBlur: wrapEvent(onBlur, handleBlur),
|
|
1712
|
-
hidden: hidden
|
|
1713
|
-
// Allow the user to click empty space inside the popover without causing
|
|
1714
|
-
// to close from useBlur
|
|
1715
|
-
,
|
|
1716
|
-
tabIndex: "-1"
|
|
1717
|
-
});
|
|
1718
|
-
});
|
|
1719
|
-
|
|
1720
|
-
const focusLockStack = [];
|
|
1721
|
-
function useFocusLock(ref, opts) {
|
|
1722
|
-
const {
|
|
1723
|
-
enabled = true,
|
|
1724
|
-
lockStartRef,
|
|
1725
|
-
lockEndRef
|
|
1726
|
-
} = opts;
|
|
1727
|
-
react.useEffect(() => {
|
|
1728
|
-
const rootEl = ref.current;
|
|
1729
|
-
if (enabled && rootEl) {
|
|
1730
|
-
focusLockStack.push(rootEl);
|
|
1731
|
-
const listener = event => {
|
|
1732
|
-
const isActiveFocusLock = focusLockStack[focusLockStack.length - 1] === rootEl;
|
|
1733
|
-
if (!isActiveFocusLock) {
|
|
1734
|
-
// Not the currently focused lock. Forget about it.
|
|
1735
|
-
return;
|
|
1736
|
-
}
|
|
1737
|
-
if (event.target === lockEndRef.current) {
|
|
1738
|
-
focusOnChildNode(rootEl, 0);
|
|
1739
|
-
} else if (event.target === lockStartRef.current) {
|
|
1740
|
-
focusOnChildNode(rootEl, -1);
|
|
1741
|
-
} else if (document !== event.target && rootEl !== event.target && !rootEl.contains(event.target)) {
|
|
1742
|
-
event.preventDefault();
|
|
1743
|
-
focusOnChildNode(rootEl, 0);
|
|
1744
|
-
}
|
|
1745
|
-
};
|
|
1746
|
-
document.addEventListener('focusin', listener);
|
|
1747
|
-
return () => {
|
|
1748
|
-
document.removeEventListener('focusin', listener);
|
|
1749
|
-
focusLockStack.pop();
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1753
|
-
}, [enabled]);
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
const FocusLock = function FocusLock(props) {
|
|
1757
|
-
const {
|
|
1758
|
-
as: Comp = 'div',
|
|
1759
|
-
childRef,
|
|
1760
|
-
enabled = false,
|
|
1761
|
-
style = {},
|
|
1762
|
-
children,
|
|
1763
|
-
...otherProps
|
|
1764
|
-
} = props;
|
|
1765
|
-
const lockStartRef = react.useRef(null);
|
|
1766
|
-
const lockEndRef = react.useRef(null);
|
|
1767
|
-
useFocusLock(childRef, {
|
|
1768
|
-
enabled,
|
|
1769
|
-
lockStartRef,
|
|
1770
|
-
lockEndRef
|
|
1771
|
-
});
|
|
1772
|
-
const lockStyle = {
|
|
1773
|
-
width: 1,
|
|
1774
|
-
height: 0,
|
|
1775
|
-
padding: 0,
|
|
1776
|
-
overflow: 'hidden',
|
|
1777
|
-
position: 'fixed',
|
|
1778
|
-
top: 1,
|
|
1779
|
-
left: 1,
|
|
1780
|
-
...style
|
|
1781
|
-
};
|
|
1782
|
-
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
1783
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1784
|
-
ref: lockStartRef,
|
|
1785
|
-
"data-focus-lock-start": "",
|
|
1786
|
-
"aria-hidden": true,
|
|
1787
|
-
tabIndex: 0,
|
|
1788
|
-
style: lockStyle,
|
|
1789
|
-
...otherProps
|
|
1790
|
-
}), children, /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1791
|
-
ref: lockEndRef,
|
|
1792
|
-
"data-focus-lock-end": "",
|
|
1793
|
-
"aria-hidden": true,
|
|
1794
|
-
tabIndex: 0,
|
|
1795
|
-
style: lockStyle,
|
|
1796
|
-
...otherProps
|
|
1797
|
-
})]
|
|
1798
|
-
});
|
|
1799
|
-
};
|
|
1800
|
-
|
|
1801
|
-
// MenuRoot
|
|
1802
|
-
|
|
1803
|
-
const menuContext = /*#__PURE__*/react.createContext(null);
|
|
1804
|
-
const {
|
|
1805
|
-
Provider: MenuProvider
|
|
1806
|
-
} = menuContext;
|
|
1807
|
-
const useMenuContext = () => react.useContext(menuContext);
|
|
1808
|
-
|
|
1809
|
-
// MenuList
|
|
1810
|
-
|
|
1811
|
-
const menuListContext = /*#__PURE__*/react.createContext(null);
|
|
1812
|
-
const MenuListProvider = menuListContext.Provider;
|
|
1813
|
-
const useMenuListContext = () => react.useContext(menuListContext);
|
|
1814
|
-
|
|
1815
|
-
const Menu = /*#__PURE__*/react.forwardRef(function Menu(props, forwardedRef) {
|
|
1816
|
-
const {
|
|
1817
|
-
as: Comp = react.Fragment,
|
|
1818
|
-
innerAs,
|
|
1819
|
-
open: openProp,
|
|
1820
|
-
defaultOpen = false,
|
|
1821
|
-
onChange: onChangeProp,
|
|
1822
|
-
...otherProps
|
|
1823
|
-
} = props;
|
|
1824
|
-
const menuListIdRef = react.useRef(undefined);
|
|
1825
|
-
const openWithArrowKeyRef = react.useRef(null);
|
|
1826
|
-
const buttonRef = react.useRef(null);
|
|
1827
|
-
const [open, onChange] = useControlledState(openProp, onChangeProp, defaultOpen, setState => (e, isOpen) => {
|
|
1828
|
-
setState(isOpen);
|
|
1829
|
-
});
|
|
1830
|
-
const [offsetFn, setOffsetFn] = react.useState(undefined);
|
|
1831
|
-
menuListIdRef.current = react.useId();
|
|
1832
|
-
const isContextMenu = react.useRef(false);
|
|
1833
|
-
if (!open && offsetFn) {
|
|
1834
|
-
setOffsetFn(undefined);
|
|
1835
|
-
}
|
|
1836
|
-
const value = {
|
|
1837
|
-
menuListIdRef,
|
|
1838
|
-
openWithArrowKeyRef,
|
|
1839
|
-
open,
|
|
1840
|
-
onChange,
|
|
1841
|
-
buttonRef,
|
|
1842
|
-
offsetFn,
|
|
1843
|
-
setOffsetFn,
|
|
1844
|
-
isContextMenu
|
|
1845
|
-
};
|
|
1846
|
-
return /*#__PURE__*/jsxRuntime.jsx(MenuProvider, {
|
|
1847
|
-
value: value,
|
|
1848
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1849
|
-
...(Comp !== react.Fragment ? {
|
|
1850
|
-
as: innerAs,
|
|
1851
|
-
ref: forwardedRef
|
|
1852
|
-
} : {}),
|
|
1853
|
-
...otherProps
|
|
1854
|
-
})
|
|
1855
|
-
});
|
|
1856
|
-
});
|
|
1857
|
-
|
|
1858
|
-
const MenuButton = /*#__PURE__*/react.forwardRef(function MenuButton(props, forwardedRef) {
|
|
1859
|
-
const {
|
|
1860
|
-
as: Comp = 'button',
|
|
1861
|
-
innerAs,
|
|
1862
|
-
id: preferredId,
|
|
1863
|
-
onClick,
|
|
1864
|
-
onKeyDown,
|
|
1865
|
-
disabled,
|
|
1866
|
-
...otherProps
|
|
1867
|
-
} = props;
|
|
1868
|
-
const {
|
|
1869
|
-
menuListIdRef,
|
|
1870
|
-
openWithArrowKeyRef,
|
|
1871
|
-
open,
|
|
1872
|
-
buttonRef,
|
|
1873
|
-
onChange
|
|
1874
|
-
} = useMenuContext();
|
|
1875
|
-
const buttonIdGenerated = react.useId();
|
|
1876
|
-
const buttonId = preferredId || buttonIdGenerated;
|
|
1877
|
-
const handleKeyDown = e => {
|
|
1878
|
-
if (disabled) {
|
|
1879
|
-
return;
|
|
1880
|
-
}
|
|
1881
|
-
buttonRef.current = e.currentTarget;
|
|
1882
|
-
const isArrowKey = () => ['ArrowUp', 'ArrowDown'].includes(e.key);
|
|
1883
|
-
const isEnterKey = () => [' ', 'Enter'].includes(e.key);
|
|
1884
|
-
const openedWithArrow = isArrowKey();
|
|
1885
|
-
if (openedWithArrow || isEnterKey()) {
|
|
1886
|
-
if (openedWithArrow) {
|
|
1887
|
-
// Used to make it open at the end or begining of the list
|
|
1888
|
-
openWithArrowKeyRef.current = e.key;
|
|
1889
|
-
}
|
|
1890
|
-
onChange(e, true);
|
|
1891
|
-
e.preventDefault();
|
|
1892
|
-
}
|
|
1893
|
-
};
|
|
1894
|
-
const handleClick = e => {
|
|
1895
|
-
if (disabled) {
|
|
1896
|
-
return;
|
|
1897
|
-
}
|
|
1898
|
-
buttonRef.current = e.currentTarget;
|
|
1899
|
-
onChange(e, !open);
|
|
1900
|
-
};
|
|
1901
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1902
|
-
ref: forwardedRef,
|
|
1903
|
-
as: innerAs,
|
|
1904
|
-
id: buttonId,
|
|
1905
|
-
role: "button",
|
|
1906
|
-
type: "button",
|
|
1907
|
-
"aria-haspopup": true,
|
|
1908
|
-
"aria-controls": menuListIdRef.current,
|
|
1909
|
-
"aria-expanded": open ? true : undefined,
|
|
1910
|
-
"data-menu-button": "",
|
|
1911
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
1912
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
1913
|
-
disabled: disabled,
|
|
1914
|
-
...otherProps
|
|
1915
|
-
});
|
|
1916
|
-
});
|
|
1917
|
-
|
|
1918
|
-
const ContextMenuTrigger = /*#__PURE__*/react.forwardRef(function ContextMenuTrigger(props, forwardedRef) {
|
|
1919
|
-
const {
|
|
1920
|
-
as: Comp = 'div',
|
|
1921
|
-
innerAs,
|
|
1922
|
-
id: preferredId,
|
|
1923
|
-
onContextMenu,
|
|
1924
|
-
disabled,
|
|
1925
|
-
...otherProps
|
|
1926
|
-
} = props;
|
|
1927
|
-
const {
|
|
1928
|
-
menuListIdRef,
|
|
1929
|
-
open,
|
|
1930
|
-
buttonRef,
|
|
1931
|
-
onChange,
|
|
1932
|
-
setOffsetFn,
|
|
1933
|
-
isContextMenu
|
|
1934
|
-
} = useMenuContext();
|
|
1935
|
-
const idGenerated = react.useId();
|
|
1936
|
-
const id = preferredId || idGenerated;
|
|
1937
|
-
const handleContextMenu = e => {
|
|
1938
|
-
if (disabled) {
|
|
1939
|
-
return;
|
|
1940
|
-
}
|
|
1941
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
1942
|
-
isContextMenu.current = true;
|
|
1943
|
-
buttonRef.current = e.currentTarget;
|
|
1944
|
-
onChange(e, true);
|
|
1945
|
-
const mouseX = e.nativeEvent.x;
|
|
1946
|
-
const mouseY = e.nativeEvent.y;
|
|
1947
|
-
setOffsetFn(() => ({
|
|
1948
|
-
reference
|
|
1949
|
-
}) => [mouseX - rect.x, mouseY - rect.y - reference.height]);
|
|
1950
|
-
e.preventDefault();
|
|
1951
|
-
};
|
|
1952
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
1953
|
-
ref: forwardedRef,
|
|
1954
|
-
as: innerAs,
|
|
1955
|
-
id: id,
|
|
1956
|
-
"aria-haspopup": true,
|
|
1957
|
-
"aria-controls": menuListIdRef.current,
|
|
1958
|
-
"aria-expanded": open ? true : undefined,
|
|
1959
|
-
"data-menu-trigger": "",
|
|
1960
|
-
onContextMenu: wrapEvent(onContextMenu, handleContextMenu),
|
|
1961
|
-
disabled: disabled,
|
|
1962
|
-
...otherProps
|
|
1963
|
-
});
|
|
1964
|
-
});
|
|
1965
|
-
|
|
1966
|
-
const MenuItem = /*#__PURE__*/react.forwardRef(function MenuItem(props, forwardedRef) {
|
|
1967
|
-
const {
|
|
1968
|
-
as: Comp = 'li',
|
|
1969
|
-
innerAs,
|
|
1970
|
-
disabled,
|
|
1971
|
-
onSelect,
|
|
1972
|
-
onClick,
|
|
1973
|
-
onKeyDown,
|
|
1974
|
-
...otherProps
|
|
1975
|
-
} = props;
|
|
1976
|
-
const {
|
|
1977
|
-
onChange,
|
|
1978
|
-
buttonRef
|
|
1979
|
-
} = useMenuContext();
|
|
1980
|
-
const {
|
|
1981
|
-
navigationItem,
|
|
1982
|
-
onNavigate
|
|
1983
|
-
} = useMenuListContext();
|
|
1984
|
-
const ref = react.useRef(null);
|
|
1985
|
-
const itemId = react.useId();
|
|
1986
|
-
const isActive = ref.current && ref.current === navigationItem;
|
|
1987
|
-
const handleSelect = wrapEvent(onSelect, e => {
|
|
1988
|
-
onChange(e, false);
|
|
1989
|
-
buttonRef.current?.focus();
|
|
1990
|
-
e.preventDefault();
|
|
1991
|
-
});
|
|
1992
|
-
const handleClick = e => {
|
|
1993
|
-
if (!disabled) {
|
|
1994
|
-
onNavigate && onNavigate(ref.current);
|
|
1995
|
-
handleSelect(e);
|
|
1996
|
-
}
|
|
1997
|
-
};
|
|
1998
|
-
const handleKeyDown = e => {
|
|
1999
|
-
switch (e.key) {
|
|
2000
|
-
case ' ':
|
|
2001
|
-
case 'Enter':
|
|
2002
|
-
if (!disabled) {
|
|
2003
|
-
handleSelect(e);
|
|
2004
|
-
}
|
|
2005
|
-
break;
|
|
2006
|
-
}
|
|
2007
|
-
};
|
|
2008
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2009
|
-
ref: assignMultipleRefs(ref, forwardedRef),
|
|
2010
|
-
as: innerAs,
|
|
2011
|
-
id: disabled ? undefined : itemId,
|
|
2012
|
-
"data-menu-item": "",
|
|
2013
|
-
"data-highlighted": isActive ? '' : undefined,
|
|
2014
|
-
role: "menuitem",
|
|
2015
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
2016
|
-
tabIndex: disabled ? -1 : 0,
|
|
2017
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
2018
|
-
"data-disabled": disabled ? '' : undefined,
|
|
2019
|
-
"aria-disabled": disabled ? '' : undefined,
|
|
2020
|
-
disabled: disabled,
|
|
2021
|
-
...otherProps
|
|
2022
|
-
});
|
|
2023
|
-
});
|
|
2024
|
-
|
|
2025
|
-
function queryScope(type, props) {
|
|
2026
|
-
return props['data-menu-item'] === '' && props['data-disabled'] !== '' && props['data-disabled'] !== true;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
const useEnhancedEffect$1 = typeof window !== 'undefined' ? react.useLayoutEffect : react.useEffect;
|
|
2030
|
-
const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwardedRef) {
|
|
2031
|
-
const {
|
|
2032
|
-
as: Comp = 'ul',
|
|
2033
|
-
innerAs,
|
|
2034
|
-
onKeyDown,
|
|
2035
|
-
id: preferredId,
|
|
2036
|
-
defaultActiveItemValue,
|
|
2037
|
-
...otherProps
|
|
2038
|
-
} = props;
|
|
2039
|
-
const interactedOutside = react.useRef(false);
|
|
2040
|
-
const itemSearchStr = react.useRef('');
|
|
2041
|
-
const itemSearchClearTimeout = react.useRef(undefined);
|
|
2042
|
-
const {
|
|
2043
|
-
menuListIdRef,
|
|
2044
|
-
buttonRef,
|
|
2045
|
-
onChange,
|
|
2046
|
-
openWithArrowKeyRef,
|
|
2047
|
-
open,
|
|
2048
|
-
isContextMenu
|
|
2049
|
-
} = useMenuContext();
|
|
2050
|
-
const [navigationItem, setNavigationItem] = react.useState();
|
|
2051
|
-
const [mounted, setMounted] = react.useState(false);
|
|
2052
|
-
const menuListRef = react.useRef(null);
|
|
2053
|
-
const scope = useScope(menuListRef);
|
|
2054
|
-
const onNavigate = el => {
|
|
2055
|
-
el.focus({
|
|
2056
|
-
preventScroll: true
|
|
2057
|
-
});
|
|
2058
|
-
setNavigationItem(el);
|
|
2059
|
-
};
|
|
2060
|
-
menuListIdRef.current = preferredId || menuListIdRef.current;
|
|
2061
|
-
useEnhancedEffect$1(() => {
|
|
2062
|
-
if (!mounted) {
|
|
2063
|
-
const allItems = scope.current.queryAllNodes(queryScope);
|
|
2064
|
-
let index = getCircularIndex(openWithArrowKeyRef.current === 'ArrowUp' ? -1 : 0, allItems.length);
|
|
2065
|
-
if (defaultActiveItemValue) {
|
|
2066
|
-
if (typeof defaultActiveItemValue === 'string') {
|
|
2067
|
-
for (let i = 0; i < allItems.length; i++) {
|
|
2068
|
-
if (allItems[i].dataset.value === defaultActiveItemValue) {
|
|
2069
|
-
index = i;
|
|
2070
|
-
break;
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
} else if (Array.isArray(defaultActiveItemValue)) {
|
|
2074
|
-
const set = new Set(defaultActiveItemValue);
|
|
2075
|
-
for (let i = 0; i < allItems.length; i++) {
|
|
2076
|
-
const val = allItems[i].dataset.value;
|
|
2077
|
-
if (val && set.has(val)) {
|
|
2078
|
-
index = i;
|
|
2079
|
-
break;
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
if (index !== null) {
|
|
2085
|
-
onNavigate && onNavigate(allItems[index]);
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
openWithArrowKeyRef.current = null;
|
|
2089
|
-
setMounted(true);
|
|
2090
|
-
}, [mounted, navigationItem, onNavigate, openWithArrowKeyRef, scope, defaultActiveItemValue]);
|
|
2091
|
-
const handleClickOutside = react.useCallback(e => {
|
|
2092
|
-
if (isContextMenu.current) {
|
|
2093
|
-
if (!interactedOutside.current && e.pointerType === 'touch') {
|
|
2094
|
-
// First interaction should be ignored, because
|
|
2095
|
-
// this is what triggered the context menu to open
|
|
2096
|
-
interactedOutside.current = true;
|
|
2097
|
-
return;
|
|
2098
|
-
}
|
|
2099
|
-
if (e.button === 0) {
|
|
2100
|
-
onChange(e, false);
|
|
2101
|
-
}
|
|
2102
|
-
} else {
|
|
2103
|
-
if (e.target instanceof HTMLElement && e.target !== buttonRef.current && !buttonRef.current?.contains(e.target)) {
|
|
2104
|
-
onChange(e, false);
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
e.preventDefault();
|
|
2108
|
-
}, [buttonRef, isContextMenu, onChange]);
|
|
2109
|
-
useOnClickOutside(menuListRef, handleClickOutside, open);
|
|
2110
|
-
function handleKeyDown(e) {
|
|
2111
|
-
switch (e.key) {
|
|
2112
|
-
case 'Escape':
|
|
2113
|
-
case 'Tab':
|
|
2114
|
-
{
|
|
2115
|
-
onChange(e, false);
|
|
2116
|
-
e.preventDefault(); // prevents focusing on next element, because we will be handling it
|
|
2117
|
-
itemSearchStr.current = '';
|
|
2118
|
-
buttonRef.current?.focus();
|
|
2119
|
-
break;
|
|
2120
|
-
}
|
|
2121
|
-
case 'Home':
|
|
2122
|
-
case 'End':
|
|
2123
|
-
case 'ArrowDown':
|
|
2124
|
-
case 'ArrowUp':
|
|
2125
|
-
e.preventDefault();
|
|
2126
|
-
itemSearchStr.current = '';
|
|
2127
|
-
const allItems = scope ? scope.current.queryAllNodes(queryScope) : [];
|
|
2128
|
-
const currentIndex = allItems.findIndex(e => e === navigationItem);
|
|
2129
|
-
if (allItems.length === 0) {
|
|
2130
|
-
return;
|
|
2131
|
-
}
|
|
2132
|
-
let nextIndex = currentIndex;
|
|
2133
|
-
switch (e.key) {
|
|
2134
|
-
case 'ArrowUp':
|
|
2135
|
-
nextIndex += -1;
|
|
2136
|
-
break;
|
|
2137
|
-
case 'ArrowDown':
|
|
2138
|
-
nextIndex += 1;
|
|
2139
|
-
break;
|
|
2140
|
-
case 'Home':
|
|
2141
|
-
nextIndex = 0;
|
|
2142
|
-
break;
|
|
2143
|
-
case 'End':
|
|
2144
|
-
nextIndex = -1;
|
|
2145
|
-
break;
|
|
2146
|
-
}
|
|
2147
|
-
// We already checked if allItems.length = 0 above
|
|
2148
|
-
nextIndex = getCircularIndex(nextIndex, allItems.length);
|
|
2149
|
-
onNavigate && onNavigate(allItems[nextIndex]);
|
|
2150
|
-
break;
|
|
2151
|
-
default:
|
|
2152
|
-
{
|
|
2153
|
-
if (e.key.length === 1 && !e.ctrlKey && !e.altKey) {
|
|
2154
|
-
// A-Z
|
|
2155
|
-
e.preventDefault();
|
|
2156
|
-
if (itemSearchStr.current.length === 0 || itemSearchStr.current.slice(-1) !== e.key) {
|
|
2157
|
-
itemSearchStr.current = itemSearchStr.current + e.key;
|
|
2158
|
-
}
|
|
2159
|
-
clearTimeout(itemSearchClearTimeout.current);
|
|
2160
|
-
itemSearchClearTimeout.current = setTimeout(() => {
|
|
2161
|
-
itemSearchStr.current = '';
|
|
2162
|
-
}, 500);
|
|
2163
|
-
const allItems = scope ? scope.current.queryAllNodes(queryScope) : [];
|
|
2164
|
-
const currentIndex = allItems.findIndex(e => e === navigationItem);
|
|
2165
|
-
const searchStr = itemSearchStr.current;
|
|
2166
|
-
let nextIndex = -1;
|
|
2167
|
-
for (let i = searchStr.length === 1 ? 1 : 0; i < allItems.length; i++) {
|
|
2168
|
-
const idx = getCircularIndex(currentIndex + i, allItems.length);
|
|
2169
|
-
const dom = allItems[idx];
|
|
2170
|
-
const domText = dom.innerText.toLowerCase();
|
|
2171
|
-
if (domText.length > 0 && domText.startsWith(searchStr)) {
|
|
2172
|
-
nextIndex = idx;
|
|
2173
|
-
break;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
if (nextIndex >= 0 && nextIndex < allItems.length) {
|
|
2177
|
-
onNavigate && onNavigate(allItems[nextIndex]);
|
|
2178
|
-
}
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
if (!open) {
|
|
2184
|
-
interactedOutside.current = false;
|
|
2185
|
-
return null;
|
|
2186
|
-
}
|
|
2187
|
-
return /*#__PURE__*/jsxRuntime.jsx(MenuListProvider, {
|
|
2188
|
-
value: {
|
|
2189
|
-
navigationItem,
|
|
2190
|
-
onNavigate
|
|
2191
|
-
},
|
|
2192
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2193
|
-
ref: assignMultipleRefs(forwardedRef, menuListRef),
|
|
2194
|
-
as: innerAs,
|
|
2195
|
-
id: menuListIdRef.current,
|
|
2196
|
-
role: "menu",
|
|
2197
|
-
"aria-labelledby": buttonRef.current?.id,
|
|
2198
|
-
"data-menu-list": "",
|
|
2199
|
-
tabIndex: "-1",
|
|
2200
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
2201
|
-
...otherProps
|
|
2202
|
-
})
|
|
2203
|
-
});
|
|
2204
|
-
});
|
|
2205
|
-
|
|
2206
|
-
const context = /*#__PURE__*/react.createContext(null);
|
|
2207
|
-
const PopperProvider = context.Provider;
|
|
2208
|
-
const usePopperContext = () => react.useContext(context);
|
|
2209
|
-
|
|
2210
|
-
const PortalSelectorContext = /*#__PURE__*/react.createContext(null);
|
|
2211
|
-
PortalSelectorContext.displayName = 'PortalSelectorContext';
|
|
2212
|
-
const PortalSelectorProvider = ({
|
|
2213
|
-
selector,
|
|
2214
|
-
children
|
|
2215
|
-
}) => {
|
|
2216
|
-
return /*#__PURE__*/jsxRuntime.jsx(PortalSelectorContext.Provider, {
|
|
2217
|
-
value: selector,
|
|
2218
|
-
children: children
|
|
2219
|
-
});
|
|
2220
|
-
};
|
|
2221
|
-
|
|
2222
|
-
const Portal = ({
|
|
2223
|
-
children,
|
|
2224
|
-
selector: selectorProp
|
|
2225
|
-
}) => {
|
|
2226
|
-
const selectorCtx = react.useContext(PortalSelectorContext);
|
|
2227
|
-
if (typeof window === 'undefined') {
|
|
2228
|
-
return null;
|
|
2229
|
-
}
|
|
2230
|
-
const selector = selectorProp || selectorCtx || 'body';
|
|
2231
|
-
const dom = typeof selector === 'string' ? document.querySelector(selector) : selector();
|
|
2232
|
-
if (dom) {
|
|
2233
|
-
return /*#__PURE__*/reactDom.createPortal(/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
2234
|
-
"data-portal": "",
|
|
2235
|
-
children: children
|
|
2236
|
-
}), dom);
|
|
2237
|
-
}
|
|
2238
|
-
return null;
|
|
2239
|
-
};
|
|
2240
|
-
|
|
2241
|
-
const useEnhancedEffect = typeof window !== 'undefined' ? react.useLayoutEffect : react.useEffect;
|
|
2242
|
-
const emptyModifiers = [];
|
|
2243
|
-
const Popper = /*#__PURE__*/react.memo(/*#__PURE__*/react.forwardRef(function Popper({
|
|
2244
|
-
placement = 'bottom',
|
|
2245
|
-
strategy = 'absolute',
|
|
2246
|
-
as: Comp = 'div',
|
|
2247
|
-
innerAs,
|
|
2248
|
-
anchorEl,
|
|
2249
|
-
children,
|
|
2250
|
-
modifiers = emptyModifiers,
|
|
2251
|
-
usePortal = false,
|
|
2252
|
-
style = {},
|
|
2253
|
-
portalSelector,
|
|
2254
|
-
distance = 0,
|
|
2255
|
-
skidding = 0,
|
|
2256
|
-
arrowPadding = 5,
|
|
2257
|
-
offsetFn,
|
|
2258
|
-
...props
|
|
2259
|
-
}, forwardedRef) {
|
|
2260
|
-
const arrowRef = react.useRef(null);
|
|
2261
|
-
const popperRef = react.useRef(null);
|
|
2262
|
-
const popperEngineInstance = react.useRef(null);
|
|
2263
|
-
const defaultModifiers = react.useMemo(() => {
|
|
2264
|
-
const arrowModifier = {
|
|
2265
|
-
name: 'arrow',
|
|
2266
|
-
options: {
|
|
2267
|
-
element: '[data-popper-arrow]',
|
|
2268
|
-
padding: arrowPadding
|
|
2269
|
-
}
|
|
2270
|
-
};
|
|
2271
|
-
const offsetModifier = {
|
|
2272
|
-
name: 'offset',
|
|
2273
|
-
options: {
|
|
2274
|
-
offset: offsetFn ?? [skidding, distance]
|
|
2275
|
-
}
|
|
2276
|
-
};
|
|
2277
|
-
return [arrowModifier, offsetModifier];
|
|
2278
|
-
}, [arrowPadding, distance, skidding, offsetFn]);
|
|
2279
|
-
useEnhancedEffect(() => {
|
|
2280
|
-
if (anchorEl && anchorEl.current && popperRef.current) {
|
|
2281
|
-
popperEngineInstance.current = core.createPopper(anchorEl.current, popperRef.current, {
|
|
2282
|
-
placement,
|
|
2283
|
-
strategy,
|
|
2284
|
-
modifiers: [...defaultModifiers, ...modifiers]
|
|
2285
|
-
});
|
|
2286
|
-
}
|
|
2287
|
-
return () => {
|
|
2288
|
-
popperEngineInstance.current && popperEngineInstance.current.destroy();
|
|
2289
|
-
popperEngineInstance.current = null;
|
|
2290
|
-
};
|
|
2291
|
-
}, [anchorEl, modifiers, placement, strategy, defaultModifiers]);
|
|
2292
|
-
useEnhancedEffect(() => {
|
|
2293
|
-
popperEngineInstance.current?.forceUpdate();
|
|
2294
|
-
}, [props.hidden || props['aria-hidden']]);
|
|
2295
|
-
const contextValue = {
|
|
2296
|
-
arrowRef
|
|
2297
|
-
};
|
|
2298
|
-
const ret = /*#__PURE__*/jsxRuntime.jsx(PopperProvider, {
|
|
2299
|
-
value: contextValue,
|
|
2300
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2301
|
-
...props,
|
|
2302
|
-
as: innerAs,
|
|
2303
|
-
ref: assignMultipleRefs(popperRef, forwardedRef),
|
|
2304
|
-
style: {
|
|
2305
|
-
position: 'fixed',
|
|
2306
|
-
left: -5000,
|
|
2307
|
-
top: -5000,
|
|
2308
|
-
...style
|
|
2309
|
-
},
|
|
2310
|
-
children: children
|
|
2311
|
-
})
|
|
2312
|
-
});
|
|
2313
|
-
if (usePortal) {
|
|
2314
|
-
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
2315
|
-
selector: portalSelector,
|
|
2316
|
-
children: ret
|
|
2317
|
-
});
|
|
2318
|
-
}
|
|
2319
|
-
return ret;
|
|
2320
|
-
}));
|
|
2321
|
-
|
|
2322
|
-
const PopperArrow = /*#__PURE__*/react.forwardRef(function PopperArrow({
|
|
2323
|
-
as: Comp = 'div',
|
|
2324
|
-
...props
|
|
2325
|
-
}, ref) {
|
|
2326
|
-
const ctx = usePopperContext();
|
|
2327
|
-
if (ctx === null) {
|
|
2328
|
-
return null;
|
|
2329
|
-
}
|
|
2330
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2331
|
-
...props,
|
|
2332
|
-
ref: node => {
|
|
2333
|
-
if (node && ctx.arrowRef.current && ctx.arrowRef.current !== node) {
|
|
2334
|
-
throw new Error('You can only render one <PopperArrow /> per <Popper> component');
|
|
2335
|
-
}
|
|
2336
|
-
assignMultipleRefs(ref, ctx.arrowRef)(node);
|
|
2337
|
-
},
|
|
2338
|
-
"data-popper-arrow": ""
|
|
2339
|
-
});
|
|
2340
|
-
});
|
|
2341
|
-
|
|
2342
|
-
const MenuPopover = /*#__PURE__*/react.forwardRef(function MenuPopover(props, forwardedRef) {
|
|
2343
|
-
const {
|
|
2344
|
-
as = 'div',
|
|
2345
|
-
innerAs,
|
|
2346
|
-
...otherProps
|
|
2347
|
-
} = props;
|
|
2348
|
-
const {
|
|
2349
|
-
buttonRef,
|
|
2350
|
-
open,
|
|
2351
|
-
offsetFn,
|
|
2352
|
-
isContextMenu
|
|
2353
|
-
} = useMenuContext();
|
|
2354
|
-
if (!open) {
|
|
2355
|
-
return null;
|
|
2356
|
-
}
|
|
2357
|
-
return /*#__PURE__*/jsxRuntime.jsx(Popper, {
|
|
2358
|
-
as: as,
|
|
2359
|
-
innerAs: innerAs,
|
|
2360
|
-
ref: forwardedRef,
|
|
2361
|
-
anchorEl: buttonRef,
|
|
2362
|
-
offsetFn: offsetFn,
|
|
2363
|
-
placement: isContextMenu.current ? 'bottom-start' : undefined,
|
|
2364
|
-
...otherProps
|
|
2365
|
-
});
|
|
2366
|
-
});
|
|
2367
|
-
|
|
2368
|
-
const Modal = /*#__PURE__*/react.forwardRef(({
|
|
2369
|
-
as: Comp = 'div',
|
|
2370
|
-
children,
|
|
2371
|
-
trapFocus = true,
|
|
2372
|
-
style = {},
|
|
2373
|
-
...otherProps
|
|
2374
|
-
}, ref) => {
|
|
2375
|
-
const modalRef = react.useRef(null);
|
|
2376
|
-
useFocusReturn(trapFocus, modalRef);
|
|
2377
|
-
useRemoveBodyScroll(trapFocus, modalRef);
|
|
2378
|
-
useAutoFocus(trapFocus, modalRef);
|
|
2379
|
-
return /*#__PURE__*/jsxRuntime.jsx(FocusLock, {
|
|
2380
|
-
childRef: modalRef,
|
|
2381
|
-
enabled: trapFocus,
|
|
2382
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2383
|
-
ref: assignMultipleRefs(ref, modalRef),
|
|
2384
|
-
"data-modal-container": "",
|
|
2385
|
-
role: "dialog",
|
|
2386
|
-
"aria-modal": "true",
|
|
2387
|
-
style: style,
|
|
2388
|
-
tabIndex: -1,
|
|
2389
|
-
...otherProps,
|
|
2390
|
-
children: children
|
|
2391
|
-
})
|
|
2392
|
-
});
|
|
2393
|
-
});
|
|
2394
|
-
|
|
2395
|
-
const ModalBackdrop = /*#__PURE__*/react.forwardRef(({
|
|
2396
|
-
as: Comp = 'div',
|
|
2397
|
-
onClose,
|
|
2398
|
-
onClick,
|
|
2399
|
-
onMouseDown,
|
|
2400
|
-
onKeyDown,
|
|
2401
|
-
disableCloseOnClick = false,
|
|
2402
|
-
disableEscapeKeyDown = false,
|
|
2403
|
-
...otherProps
|
|
2404
|
-
}, forwardedRef) => {
|
|
2405
|
-
const ref = react.useRef(null);
|
|
2406
|
-
const mouseDownTargetRef = react.useRef(null);
|
|
2407
|
-
const handleClick = e => {
|
|
2408
|
-
// Ignore the events not coming from the "backdrop"
|
|
2409
|
-
// We don't want to close the dialog when clicking the dialog content.
|
|
2410
|
-
if (e.target !== e.currentTarget) {
|
|
2411
|
-
return;
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
// Make sure the event starts and ends on the same DOM element.
|
|
2415
|
-
if (e.target !== mouseDownTargetRef.current) {
|
|
2416
|
-
return;
|
|
2417
|
-
}
|
|
2418
|
-
mouseDownTargetRef.current = null;
|
|
2419
|
-
!disableCloseOnClick && onClose?.();
|
|
2420
|
-
e.stopPropagation();
|
|
2421
|
-
};
|
|
2422
|
-
const handleMouseDown = e => {
|
|
2423
|
-
mouseDownTargetRef.current = e.target;
|
|
2424
|
-
};
|
|
2425
|
-
const handleKeyDown = e => {
|
|
2426
|
-
if (e.key === 'Escape') {
|
|
2427
|
-
!disableEscapeKeyDown && onClose?.();
|
|
2428
|
-
e.stopPropagation();
|
|
2429
|
-
}
|
|
2430
|
-
};
|
|
2431
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2432
|
-
ref: assignMultipleRefs(ref, forwardedRef),
|
|
2433
|
-
"data-modal-root": "",
|
|
2434
|
-
onClick: wrapEvent(onClick, handleClick),
|
|
2435
|
-
onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
|
|
2436
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
2437
|
-
...otherProps
|
|
2438
|
-
});
|
|
2439
|
-
});
|
|
2440
|
-
|
|
2441
|
-
// RadioGroup Component
|
|
2442
|
-
|
|
2443
|
-
const RadioGroupContext = /*#__PURE__*/react.createContext(undefined);
|
|
2444
|
-
const {
|
|
2445
|
-
Provider: RadioGroupProvider
|
|
2446
|
-
} = RadioGroupContext;
|
|
2447
|
-
const useRadioGroupContext = () => react.useContext(RadioGroupContext);
|
|
2448
|
-
|
|
2449
|
-
const RadioButton = /*#__PURE__*/react.forwardRef(function RadioButton(props, forwardedRef) {
|
|
2450
|
-
const {
|
|
2451
|
-
as: Comp = 'input',
|
|
2452
|
-
value: valueProp,
|
|
2453
|
-
onChange: onChangeProp,
|
|
2454
|
-
checked: checkedProp,
|
|
2455
|
-
name: nameProp,
|
|
2456
|
-
...otherProps
|
|
2457
|
-
} = props;
|
|
2458
|
-
const radioGroupContext = useRadioGroupContext();
|
|
2459
|
-
const handleChange = e => {
|
|
2460
|
-
radioGroupContext?.onChange?.(e, valueProp);
|
|
2461
|
-
};
|
|
2462
|
-
const checked = radioGroupContext ? radioGroupContext.value === valueProp : checkedProp;
|
|
2463
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2464
|
-
ref: forwardedRef,
|
|
2465
|
-
type: "radio",
|
|
2466
|
-
checked: checked,
|
|
2467
|
-
"aria-checked": String(checked),
|
|
2468
|
-
name: radioGroupContext ? radioGroupContext.name : nameProp,
|
|
2469
|
-
onChange: wrapEvent(onChangeProp, handleChange),
|
|
2470
|
-
value: valueProp,
|
|
2471
|
-
...otherProps
|
|
2472
|
-
});
|
|
2473
|
-
});
|
|
2474
|
-
|
|
2475
|
-
const RadioGroup = /*#__PURE__*/react.forwardRef(function RadioGroup(props, forwardedRef) {
|
|
2476
|
-
const {
|
|
2477
|
-
as: Comp = 'div',
|
|
2478
|
-
onChange: onChangeProp,
|
|
2479
|
-
value: valueProp,
|
|
2480
|
-
name: nameProp,
|
|
2481
|
-
defaultValue,
|
|
2482
|
-
...otherProps
|
|
2483
|
-
} = props;
|
|
2484
|
-
const [value, onChange] = useControlledState(valueProp, onChangeProp, defaultValue, setValue => (e, value) => {
|
|
2485
|
-
setValue(value);
|
|
2486
|
-
});
|
|
2487
|
-
const fallbackId = react.useId();
|
|
2488
|
-
return /*#__PURE__*/jsxRuntime.jsx(RadioGroupProvider, {
|
|
2489
|
-
value: {
|
|
2490
|
-
value,
|
|
2491
|
-
onChange,
|
|
2492
|
-
name: nameProp || fallbackId
|
|
2493
|
-
},
|
|
2494
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2495
|
-
ref: forwardedRef,
|
|
2496
|
-
role: "radiogroup",
|
|
2497
|
-
...otherProps
|
|
2498
|
-
})
|
|
2499
|
-
});
|
|
2500
|
-
});
|
|
2501
|
-
|
|
2502
|
-
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2503
|
-
const noop = () => {
|
|
2504
|
-
/* noop */
|
|
2505
|
-
};
|
|
2506
|
-
const [SliderProvider, useSliderContext] = createContext('Slider');
|
|
2507
|
-
|
|
2508
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
2509
|
-
|
|
2510
|
-
/**
|
|
2511
|
-
* Slider
|
|
2512
|
-
*
|
|
2513
|
-
* @see Docs https://reach.tech/slider#slider
|
|
2514
|
-
*/
|
|
2515
|
-
const Slider = /*#__PURE__*/react.forwardRef(function Slider({
|
|
2516
|
-
children,
|
|
2517
|
-
...props
|
|
2518
|
-
}, forwardedRef) {
|
|
2519
|
-
return /*#__PURE__*/jsxRuntime.jsx(SliderInput, {
|
|
2520
|
-
...props,
|
|
2521
|
-
ref: forwardedRef,
|
|
2522
|
-
"data-reach-slider": "",
|
|
2523
|
-
children: /*#__PURE__*/jsxRuntime.jsxs(SliderTrack, {
|
|
2524
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(SliderRange, {}), /*#__PURE__*/jsxRuntime.jsx(SliderHandle, {}), children]
|
|
2525
|
-
})
|
|
2526
|
-
});
|
|
2527
|
-
});
|
|
2528
|
-
|
|
2529
|
-
/**
|
|
2530
|
-
* @see Docs https://reach.tech/slider#slider-props
|
|
2531
|
-
*/
|
|
2532
|
-
|
|
2533
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
2534
|
-
|
|
2535
|
-
/**
|
|
2536
|
-
* SliderInput
|
|
2537
|
-
*
|
|
2538
|
-
* The parent component of the slider interface. This is a lower level component
|
|
2539
|
-
* if you need more control over styles or rendering the slider's inner
|
|
2540
|
-
* components.
|
|
2541
|
-
*
|
|
2542
|
-
* @see Docs https://reach.tech/slider#sliderinput
|
|
2543
|
-
*/
|
|
2544
|
-
const SliderInput = /*#__PURE__*/react.forwardRef(function SliderInput({
|
|
2545
|
-
'aria-label': ariaLabel,
|
|
2546
|
-
'aria-labelledby': ariaLabelledBy,
|
|
2547
|
-
'aria-valuetext': ariaValueTextProp,
|
|
2548
|
-
as: Comp = 'div',
|
|
2549
|
-
innerAs,
|
|
2550
|
-
defaultValue,
|
|
2551
|
-
disabled = false,
|
|
2552
|
-
value: controlledValue,
|
|
2553
|
-
getAriaLabel,
|
|
2554
|
-
getAriaValueText,
|
|
2555
|
-
handleAlignment = 'center',
|
|
2556
|
-
max = 100,
|
|
2557
|
-
min = 0,
|
|
2558
|
-
name,
|
|
2559
|
-
onChange: onChangeProp,
|
|
2560
|
-
onKeyDown,
|
|
2561
|
-
onMouseDown,
|
|
2562
|
-
onMouseMove,
|
|
2563
|
-
onMouseUp,
|
|
2564
|
-
onPointerDown,
|
|
2565
|
-
onPointerUp,
|
|
2566
|
-
onTouchEnd,
|
|
2567
|
-
onTouchMove,
|
|
2568
|
-
onTouchStart,
|
|
2569
|
-
orientation = 'horizontal',
|
|
2570
|
-
step = 1,
|
|
2571
|
-
children,
|
|
2572
|
-
...rest
|
|
2573
|
-
}, forwardedRef) {
|
|
2574
|
-
const touchId = react.useRef(undefined);
|
|
2575
|
-
const fallbackId = react.useId();
|
|
2576
|
-
const id = rest.id || fallbackId;
|
|
2577
|
-
|
|
2578
|
-
// Track whether or not the pointer is down without updating the component
|
|
2579
|
-
const pointerDownRef = react.useRef(false);
|
|
2580
|
-
const trackRef = react.useRef(null);
|
|
2581
|
-
const handleRef = react.useRef(null);
|
|
2582
|
-
const sliderRef = react.useRef(null);
|
|
2583
|
-
const [hasFocus, setHasFocus] = react.useState(false);
|
|
2584
|
-
const {
|
|
2585
|
-
ref: x,
|
|
2586
|
-
...handleDimensions
|
|
2587
|
-
} = useDimensions(handleRef);
|
|
2588
|
-
const [_value, onChange] = useControlledState(controlledValue, onChangeProp, defaultValue || min, setValue => (e, v) => setValue(v));
|
|
2589
|
-
const value = clamp$1(_value, min, max);
|
|
2590
|
-
const trackPercent = valueToPercent(value, min, max);
|
|
2591
|
-
const isVertical = orientation === 'vertical';
|
|
2592
|
-
const handleSize = isVertical ? handleDimensions.height : handleDimensions.width;
|
|
2593
|
-
|
|
2594
|
-
// TODO: Consider removing the `handleAlignment` prop
|
|
2595
|
-
// We may want to use accept a `handlePosition` prop instead and let apps
|
|
2596
|
-
// define their own positioning logic, similar to how we do for popovers.
|
|
2597
|
-
const handlePosition = `calc(${trackPercent}% - ${handleAlignment === 'center' ? `${handleSize}px / 2` : `${handleSize}px * ${trackPercent * 0.01}`})`;
|
|
2598
|
-
const handlePositionRef = react.useRef(handlePosition);
|
|
2599
|
-
react.useLayoutEffect(() => {
|
|
2600
|
-
handlePositionRef.current = handlePosition;
|
|
2601
|
-
}, [handlePosition]);
|
|
2602
|
-
const getNewValueFromEvent = react.useCallback(event => {
|
|
2603
|
-
return getNewValue(getPointerPosition(event, touchId), trackRef.current, {
|
|
2604
|
-
step,
|
|
2605
|
-
orientation,
|
|
2606
|
-
min,
|
|
2607
|
-
max
|
|
2608
|
-
});
|
|
2609
|
-
}, [max, min, orientation, step]);
|
|
2610
|
-
|
|
2611
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_kbd_interaction
|
|
2612
|
-
const handleKeyDown = useStableLayoutCallback(event => {
|
|
2613
|
-
if (disabled) {
|
|
2614
|
-
return;
|
|
2615
|
-
}
|
|
2616
|
-
let newValue;
|
|
2617
|
-
const tenSteps = (max - min) / 10;
|
|
2618
|
-
const keyStep = step || (max - min) / 100;
|
|
2619
|
-
switch (event.key) {
|
|
2620
|
-
// Decrease the value of the slider by one step.
|
|
2621
|
-
case 'ArrowLeft':
|
|
2622
|
-
case 'ArrowDown':
|
|
2623
|
-
newValue = value - keyStep;
|
|
2624
|
-
break;
|
|
2625
|
-
// Increase the value of the slider by one step
|
|
2626
|
-
case 'ArrowRight':
|
|
2627
|
-
case 'ArrowUp':
|
|
2628
|
-
newValue = value + keyStep;
|
|
2629
|
-
break;
|
|
2630
|
-
// Decrement the slider by an amount larger than the step change made by
|
|
2631
|
-
// `ArrowDown`.
|
|
2632
|
-
case 'PageDown':
|
|
2633
|
-
newValue = value - tenSteps;
|
|
2634
|
-
break;
|
|
2635
|
-
// Increment the slider by an amount larger than the step change made by
|
|
2636
|
-
// `ArrowUp`.
|
|
2637
|
-
case 'PageUp':
|
|
2638
|
-
newValue = value + tenSteps;
|
|
2639
|
-
break;
|
|
2640
|
-
// Set the slider to the first allowed value in its range.
|
|
2641
|
-
case 'Home':
|
|
2642
|
-
newValue = min;
|
|
2643
|
-
break;
|
|
2644
|
-
// Set the slider to the last allowed value in its range.
|
|
2645
|
-
case 'End':
|
|
2646
|
-
newValue = max;
|
|
2647
|
-
break;
|
|
2648
|
-
default:
|
|
2649
|
-
return;
|
|
2650
|
-
}
|
|
2651
|
-
newValue = clamp$1(step ? roundValueToStep(newValue, step, min) : newValue, min, max);
|
|
2652
|
-
onChange(event, newValue);
|
|
2653
|
-
});
|
|
2654
|
-
const ariaValueText = getAriaValueText ? getAriaValueText(value) : ariaValueTextProp;
|
|
2655
|
-
const rangeStyle = {
|
|
2656
|
-
[isVertical ? 'height' : 'width']: `${trackPercent}%`
|
|
2657
|
-
};
|
|
2658
|
-
|
|
2659
|
-
// Slide events!
|
|
2660
|
-
// We will try to use pointer events if they are supported to leverage
|
|
2661
|
-
// setPointerCapture and releasePointerCapture. We'll fall back to separate
|
|
2662
|
-
// mouse and touch events.
|
|
2663
|
-
// TODO: This could be more concise
|
|
2664
|
-
const removeMoveEvents = react.useRef(noop);
|
|
2665
|
-
const removeStartEvents = react.useRef(noop);
|
|
2666
|
-
const removeEndEvents = react.useRef(noop);
|
|
2667
|
-
|
|
2668
|
-
// Store our event handlers in refs so we aren't attaching/detaching events
|
|
2669
|
-
// on every render if the user doesn't useCallback
|
|
2670
|
-
const appEvents = react.useRef({
|
|
2671
|
-
onMouseMove,
|
|
2672
|
-
onMouseDown,
|
|
2673
|
-
onMouseUp,
|
|
2674
|
-
onTouchStart,
|
|
2675
|
-
onTouchEnd,
|
|
2676
|
-
onTouchMove,
|
|
2677
|
-
onPointerDown,
|
|
2678
|
-
onPointerUp
|
|
2679
|
-
});
|
|
2680
|
-
react.useLayoutEffect(() => {
|
|
2681
|
-
appEvents.current.onMouseMove = onMouseMove;
|
|
2682
|
-
appEvents.current.onMouseDown = onMouseDown;
|
|
2683
|
-
appEvents.current.onMouseUp = onMouseUp;
|
|
2684
|
-
appEvents.current.onTouchStart = onTouchStart;
|
|
2685
|
-
appEvents.current.onTouchEnd = onTouchEnd;
|
|
2686
|
-
appEvents.current.onTouchMove = onTouchMove;
|
|
2687
|
-
appEvents.current.onPointerDown = onPointerDown;
|
|
2688
|
-
appEvents.current.onPointerUp = onPointerUp;
|
|
2689
|
-
}, [onMouseMove, onMouseDown, onMouseUp, onTouchStart, onTouchEnd, onTouchMove, onPointerDown, onPointerUp]);
|
|
2690
|
-
const handleSlideStart = useStableLayoutCallback(event => {
|
|
2691
|
-
if (isRightClick(event)) return;
|
|
2692
|
-
if (disabled) {
|
|
2693
|
-
pointerDownRef.current = false;
|
|
2694
|
-
return;
|
|
2695
|
-
}
|
|
2696
|
-
const ownerDocument = getOwnerDocument(sliderRef.current);
|
|
2697
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
2698
|
-
pointerDownRef.current = true;
|
|
2699
|
-
if (event.changedTouches) {
|
|
2700
|
-
// Prevent scrolling for touch events
|
|
2701
|
-
event.preventDefault();
|
|
2702
|
-
const touch = event.changedTouches?.[0];
|
|
2703
|
-
if (touch != null) {
|
|
2704
|
-
touchId.current = touch.identifier;
|
|
2705
|
-
}
|
|
2706
|
-
}
|
|
2707
|
-
const newValue = getNewValueFromEvent(event);
|
|
2708
|
-
if (newValue == null) {
|
|
2709
|
-
return;
|
|
2710
|
-
}
|
|
2711
|
-
ownerWindow.requestAnimationFrame(() => handleRef.current?.focus());
|
|
2712
|
-
onChange(event, newValue);
|
|
2713
|
-
removeMoveEvents.current = addMoveListener();
|
|
2714
|
-
removeEndEvents.current = addEndListener();
|
|
2715
|
-
});
|
|
2716
|
-
const setPointerCapture = useStableLayoutCallback(event => {
|
|
2717
|
-
if (isRightClick(event)) return;
|
|
2718
|
-
if (disabled) {
|
|
2719
|
-
pointerDownRef.current = false;
|
|
2720
|
-
return;
|
|
2721
|
-
}
|
|
2722
|
-
pointerDownRef.current = true;
|
|
2723
|
-
sliderRef.current?.setPointerCapture(event.pointerId);
|
|
2724
|
-
});
|
|
2725
|
-
const releasePointerCapture = useStableLayoutCallback(event => {
|
|
2726
|
-
if (isRightClick(event)) return;
|
|
2727
|
-
sliderRef.current?.releasePointerCapture(event.pointerId);
|
|
2728
|
-
pointerDownRef.current = false;
|
|
2729
|
-
});
|
|
2730
|
-
const handlePointerMove = useStableLayoutCallback(event => {
|
|
2731
|
-
if (disabled || !pointerDownRef.current) {
|
|
2732
|
-
pointerDownRef.current = false;
|
|
2733
|
-
return;
|
|
2734
|
-
}
|
|
2735
|
-
const newValue = getNewValueFromEvent(event);
|
|
2736
|
-
if (newValue == null) {
|
|
2737
|
-
return;
|
|
2738
|
-
}
|
|
2739
|
-
onChange?.(event, newValue);
|
|
2740
|
-
});
|
|
2741
|
-
const handleSlideStop = useStableLayoutCallback(event => {
|
|
2742
|
-
if (isRightClick(event)) return;
|
|
2743
|
-
pointerDownRef.current = false;
|
|
2744
|
-
const newValue = getNewValueFromEvent(event);
|
|
2745
|
-
if (newValue == null) {
|
|
2746
|
-
return;
|
|
2747
|
-
}
|
|
2748
|
-
touchId.current = undefined;
|
|
2749
|
-
removeMoveEvents.current();
|
|
2750
|
-
removeEndEvents.current();
|
|
2751
|
-
});
|
|
2752
|
-
const addMoveListener = react.useCallback(() => {
|
|
2753
|
-
const ownerDocument = getOwnerDocument(sliderRef.current);
|
|
2754
|
-
const touchListener = wrapEvent(appEvents.current.onTouchMove, handlePointerMove);
|
|
2755
|
-
const mouseListener = wrapEvent(appEvents.current.onMouseMove, handlePointerMove);
|
|
2756
|
-
ownerDocument.addEventListener('touchmove', touchListener);
|
|
2757
|
-
ownerDocument.addEventListener('mousemove', mouseListener);
|
|
2758
|
-
return () => {
|
|
2759
|
-
ownerDocument.removeEventListener('touchmove', touchListener);
|
|
2760
|
-
ownerDocument.removeEventListener('mousemove', mouseListener);
|
|
2761
|
-
};
|
|
2762
|
-
}, [handlePointerMove]);
|
|
2763
|
-
const addEndListener = react.useCallback(() => {
|
|
2764
|
-
const ownerDocument = getOwnerDocument(sliderRef.current);
|
|
2765
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
2766
|
-
const pointerListener = wrapEvent(appEvents.current.onPointerUp, releasePointerCapture);
|
|
2767
|
-
const touchListener = wrapEvent(appEvents.current.onTouchEnd, handleSlideStop);
|
|
2768
|
-
const mouseListener = wrapEvent(appEvents.current.onMouseUp, handleSlideStop);
|
|
2769
|
-
if ('PointerEvent' in ownerWindow) {
|
|
2770
|
-
ownerDocument.addEventListener('pointerup', pointerListener);
|
|
2771
|
-
}
|
|
2772
|
-
ownerDocument.addEventListener('touchend', touchListener);
|
|
2773
|
-
ownerDocument.addEventListener('mouseup', mouseListener);
|
|
2774
|
-
return () => {
|
|
2775
|
-
if ('PointerEvent' in ownerWindow) {
|
|
2776
|
-
ownerDocument.removeEventListener('pointerup', pointerListener);
|
|
2777
|
-
}
|
|
2778
|
-
ownerDocument.removeEventListener('touchend', touchListener);
|
|
2779
|
-
ownerDocument.removeEventListener('mouseup', mouseListener);
|
|
2780
|
-
};
|
|
2781
|
-
}, [handleSlideStop, releasePointerCapture]);
|
|
2782
|
-
const addStartListener = react.useCallback(() => {
|
|
2783
|
-
// e.preventDefault is ignored by React's synthetic touchStart event, so
|
|
2784
|
-
// we attach the listener directly to the DOM node
|
|
2785
|
-
// https://github.com/facebook/react/issues/9809#issuecomment-413978405
|
|
2786
|
-
|
|
2787
|
-
const sliderElement = sliderRef.current;
|
|
2788
|
-
if (!sliderElement) {
|
|
2789
|
-
return noop;
|
|
2790
|
-
}
|
|
2791
|
-
const ownerDocument = getOwnerDocument(sliderElement);
|
|
2792
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
2793
|
-
const touchListener = wrapEvent(appEvents.current.onTouchStart, handleSlideStart);
|
|
2794
|
-
const mouseListener = wrapEvent(appEvents.current.onMouseDown, handleSlideStart);
|
|
2795
|
-
const pointerListener = wrapEvent(appEvents.current.onPointerDown, setPointerCapture);
|
|
2796
|
-
sliderElement.addEventListener('touchstart', touchListener);
|
|
2797
|
-
sliderElement.addEventListener('mousedown', mouseListener);
|
|
2798
|
-
if ('PointerEvent' in ownerWindow) {
|
|
2799
|
-
sliderElement.addEventListener('pointerdown', pointerListener);
|
|
2800
|
-
}
|
|
2801
|
-
return () => {
|
|
2802
|
-
sliderElement.removeEventListener('touchstart', touchListener);
|
|
2803
|
-
sliderElement.removeEventListener('mousedown', mouseListener);
|
|
2804
|
-
if ('PointerEvent' in ownerWindow) {
|
|
2805
|
-
sliderElement.removeEventListener('pointerdown', pointerListener);
|
|
2806
|
-
}
|
|
2807
|
-
};
|
|
2808
|
-
}, [setPointerCapture, handleSlideStart]);
|
|
2809
|
-
react.useEffect(() => {
|
|
2810
|
-
removeStartEvents.current = addStartListener();
|
|
2811
|
-
return () => {
|
|
2812
|
-
removeStartEvents.current();
|
|
2813
|
-
removeEndEvents.current();
|
|
2814
|
-
removeMoveEvents.current();
|
|
2815
|
-
};
|
|
2816
|
-
}, [addStartListener]);
|
|
2817
|
-
const inputFallbackId = react.useId();
|
|
2818
|
-
const inputId = id || inputFallbackId;
|
|
2819
|
-
return /*#__PURE__*/jsxRuntime.jsx(SliderProvider, {
|
|
2820
|
-
ariaLabel: getAriaLabel ? getAriaLabel(value) : ariaLabel,
|
|
2821
|
-
ariaLabelledBy: ariaLabelledBy,
|
|
2822
|
-
ariaValueText: ariaValueText,
|
|
2823
|
-
handleDimensions: handleDimensions,
|
|
2824
|
-
handleKeyDown: handleKeyDown,
|
|
2825
|
-
handlePosition: handlePosition,
|
|
2826
|
-
handleRef: handleRef,
|
|
2827
|
-
hasFocus: hasFocus,
|
|
2828
|
-
onKeyDown: onKeyDown,
|
|
2829
|
-
setHasFocus: setHasFocus,
|
|
2830
|
-
sliderId: id,
|
|
2831
|
-
sliderMax: max,
|
|
2832
|
-
sliderMin: min,
|
|
2833
|
-
value: value,
|
|
2834
|
-
disabled: !!disabled,
|
|
2835
|
-
isVertical: isVertical,
|
|
2836
|
-
orientation: orientation,
|
|
2837
|
-
trackPercent: trackPercent,
|
|
2838
|
-
trackRef: trackRef,
|
|
2839
|
-
rangeStyle: rangeStyle,
|
|
2840
|
-
updateValue: onChange,
|
|
2841
|
-
children: /*#__PURE__*/jsxRuntime.jsxs(Comp, {
|
|
2842
|
-
...rest,
|
|
2843
|
-
// @ts-ignore
|
|
2844
|
-
as: innerAs,
|
|
2845
|
-
ref: assignMultipleRefs(sliderRef, forwardedRef),
|
|
2846
|
-
"data-reach-slider-input": "",
|
|
2847
|
-
"data-disabled": disabled ? '' : undefined,
|
|
2848
|
-
"data-orientation": orientation,
|
|
2849
|
-
tabIndex: -1,
|
|
2850
|
-
children: [typeof children === 'function' ? children({
|
|
2851
|
-
hasFocus,
|
|
2852
|
-
id,
|
|
2853
|
-
max,
|
|
2854
|
-
min,
|
|
2855
|
-
value,
|
|
2856
|
-
ariaValueText
|
|
2857
|
-
}) : children, name &&
|
|
2858
|
-
/*#__PURE__*/
|
|
2859
|
-
// If the slider is used in a form we'll need an input field to
|
|
2860
|
-
// capture the value. We'll assume this when the component is given a
|
|
2861
|
-
// form field name (A `name` prop doesn't really make sense in any
|
|
2862
|
-
// other context).
|
|
2863
|
-
jsxRuntime.jsx("input", {
|
|
2864
|
-
type: "hidden",
|
|
2865
|
-
value: value,
|
|
2866
|
-
name: name,
|
|
2867
|
-
id: inputId
|
|
2868
|
-
})]
|
|
2869
|
-
})
|
|
2870
|
-
});
|
|
2871
|
-
});
|
|
2872
|
-
|
|
2873
|
-
/**
|
|
2874
|
-
* @see Docs https://reach.tech/slider#sliderinput-props
|
|
2875
|
-
*/
|
|
2876
|
-
|
|
2877
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
2878
|
-
|
|
2879
|
-
/**
|
|
2880
|
-
* SliderTrack
|
|
2881
|
-
*
|
|
2882
|
-
* @see Docs https://reach.tech/slider#slidertrack
|
|
2883
|
-
*/
|
|
2884
|
-
const SliderTrackImpl = /*#__PURE__*/react.forwardRef(function SliderTrack({
|
|
2885
|
-
as: Comp = 'div',
|
|
2886
|
-
innerAs,
|
|
2887
|
-
children,
|
|
2888
|
-
style = {},
|
|
2889
|
-
...props
|
|
2890
|
-
}, forwardedRef) {
|
|
2891
|
-
const {
|
|
2892
|
-
disabled,
|
|
2893
|
-
orientation,
|
|
2894
|
-
trackRef
|
|
2895
|
-
} = useSliderContext('SliderTrack');
|
|
2896
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2897
|
-
ref: assignMultipleRefs(trackRef, forwardedRef)
|
|
2898
|
-
// @ts-ignore
|
|
2899
|
-
,
|
|
2900
|
-
as: innerAs,
|
|
2901
|
-
style: {
|
|
2902
|
-
...style,
|
|
2903
|
-
position: 'relative'
|
|
2904
|
-
},
|
|
2905
|
-
...props,
|
|
2906
|
-
"data-reach-slider-track": "",
|
|
2907
|
-
"data-disabled": disabled ? '' : undefined,
|
|
2908
|
-
"data-orientation": orientation,
|
|
2909
|
-
children: children
|
|
2910
|
-
});
|
|
2911
|
-
});
|
|
2912
|
-
const SliderTrack = /*#__PURE__*/react.memo(SliderTrackImpl);
|
|
2913
|
-
|
|
2914
|
-
/**
|
|
2915
|
-
* @see Docs https://reach.tech/slider#slidertrack-props
|
|
2916
|
-
*/
|
|
2917
|
-
|
|
2918
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
2919
|
-
|
|
2920
|
-
/**
|
|
2921
|
-
* SliderRange
|
|
2922
|
-
*
|
|
2923
|
-
* The (typically) highlighted portion of the track that represents the space
|
|
2924
|
-
* between the slider's `min` value and its current value.
|
|
2925
|
-
*
|
|
2926
|
-
* @see Docs https://reach.tech/slider#sliderrange
|
|
2927
|
-
*/
|
|
2928
|
-
const SliderRangeImpl = /*#__PURE__*/react.forwardRef(function SliderRange({
|
|
2929
|
-
as: Comp = 'div',
|
|
2930
|
-
innerAs,
|
|
2931
|
-
children,
|
|
2932
|
-
style = {},
|
|
2933
|
-
...props
|
|
2934
|
-
}, forwardedRef) {
|
|
2935
|
-
const {
|
|
2936
|
-
disabled,
|
|
2937
|
-
orientation,
|
|
2938
|
-
rangeStyle
|
|
2939
|
-
} = useSliderContext('SliderRange');
|
|
2940
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
2941
|
-
ref: forwardedRef
|
|
2942
|
-
// @ts-ignore
|
|
2943
|
-
,
|
|
2944
|
-
as: innerAs,
|
|
2945
|
-
style: {
|
|
2946
|
-
position: 'absolute',
|
|
2947
|
-
...rangeStyle,
|
|
2948
|
-
...style
|
|
2949
|
-
},
|
|
2950
|
-
...props,
|
|
2951
|
-
"data-reach-slider-range": "",
|
|
2952
|
-
"data-disabled": disabled ? '' : undefined,
|
|
2953
|
-
"data-orientation": orientation
|
|
2954
|
-
});
|
|
2955
|
-
});
|
|
2956
|
-
const SliderRange = /*#__PURE__*/react.memo(SliderRangeImpl);
|
|
2957
|
-
|
|
2958
|
-
/**
|
|
2959
|
-
* `SliderRange` accepts any props that a HTML div component accepts.
|
|
2960
|
-
* `SliderRange` will not accept or render any children.
|
|
2961
|
-
*
|
|
2962
|
-
* @see Docs https://reach.tech/slider#sliderrange-props
|
|
2963
|
-
*/
|
|
2964
|
-
|
|
2965
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
2966
|
-
|
|
2967
|
-
/**
|
|
2968
|
-
* SliderHandle
|
|
2969
|
-
*
|
|
2970
|
-
* The handle that the user drags along the track to set the slider value.
|
|
2971
|
-
*
|
|
2972
|
-
* @see Docs https://reach.tech/slider#sliderhandle
|
|
2973
|
-
*/
|
|
2974
|
-
const SliderHandleImpl = /*#__PURE__*/react.forwardRef(function SliderHandle({
|
|
2975
|
-
// min,
|
|
2976
|
-
// max,
|
|
2977
|
-
as: Comp = 'div',
|
|
2978
|
-
innerAs,
|
|
2979
|
-
onBlur,
|
|
2980
|
-
onFocus,
|
|
2981
|
-
style = {},
|
|
2982
|
-
onKeyDown,
|
|
2983
|
-
...props
|
|
2984
|
-
}, forwardedRef) {
|
|
2985
|
-
const {
|
|
2986
|
-
ariaLabel,
|
|
2987
|
-
ariaLabelledBy,
|
|
2988
|
-
ariaValueText,
|
|
2989
|
-
disabled,
|
|
2990
|
-
handlePosition,
|
|
2991
|
-
handleRef,
|
|
2992
|
-
isVertical,
|
|
2993
|
-
handleKeyDown,
|
|
2994
|
-
orientation,
|
|
2995
|
-
setHasFocus,
|
|
2996
|
-
sliderMin,
|
|
2997
|
-
sliderMax,
|
|
2998
|
-
value
|
|
2999
|
-
} = useSliderContext('SliderHandle');
|
|
3000
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp
|
|
3001
|
-
// @ts-ignore
|
|
3002
|
-
, {
|
|
3003
|
-
as: innerAs,
|
|
3004
|
-
"aria-disabled": disabled || undefined
|
|
3005
|
-
// If the slider has a visible label, it is referenced by
|
|
3006
|
-
// `aria-labelledby` on the slider element. Otherwise, the slider
|
|
3007
|
-
// element has a label provided by `aria-label`.
|
|
3008
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3009
|
-
,
|
|
3010
|
-
"aria-label": ariaLabel,
|
|
3011
|
-
"aria-labelledby": ariaLabel ? undefined : ariaLabelledBy
|
|
3012
|
-
// If the slider is vertically oriented, it has `aria-orientation` set
|
|
3013
|
-
// to vertical. The default value of `aria-orientation` for a slider is
|
|
3014
|
-
// horizontal.
|
|
3015
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3016
|
-
,
|
|
3017
|
-
"aria-orientation": orientation
|
|
3018
|
-
// The slider element has the `aria-valuemax` property set to a decimal
|
|
3019
|
-
// value representing the maximum allowed value of the slider.
|
|
3020
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3021
|
-
,
|
|
3022
|
-
"aria-valuemax": sliderMax
|
|
3023
|
-
// The slider element has the `aria-valuemin` property set to a decimal
|
|
3024
|
-
// value representing the minimum allowed value of the slider.
|
|
3025
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3026
|
-
,
|
|
3027
|
-
"aria-valuemin": sliderMin
|
|
3028
|
-
// The slider element has the `aria-valuenow` property set to a decimal
|
|
3029
|
-
// value representing the current value of the slider.
|
|
3030
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3031
|
-
,
|
|
3032
|
-
"aria-valuenow": value
|
|
3033
|
-
// If the value of `aria-valuenow` is not user-friendly, e.g., the day
|
|
3034
|
-
// of the week is represented by a number, the `aria-valuetext` property
|
|
3035
|
-
// is set to a string that makes the slider value understandable, e.g.,
|
|
3036
|
-
// "Monday".
|
|
3037
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3038
|
-
,
|
|
3039
|
-
"aria-valuetext": ariaValueText
|
|
3040
|
-
// The element serving as the focusable slider control has role
|
|
3041
|
-
// `slider`.
|
|
3042
|
-
// https://www.w3.org/TR/wai-aria-practices-1.2/#slider_roles_states_props
|
|
3043
|
-
,
|
|
3044
|
-
role: "slider",
|
|
3045
|
-
tabIndex: disabled ? -1 : 0,
|
|
3046
|
-
...props,
|
|
3047
|
-
"data-reach-slider-handle": "",
|
|
3048
|
-
ref: assignMultipleRefs(handleRef, forwardedRef),
|
|
3049
|
-
onBlur: wrapEvent(onBlur, () => {
|
|
3050
|
-
setHasFocus(false);
|
|
3051
|
-
}),
|
|
3052
|
-
onFocus: wrapEvent(onFocus, () => {
|
|
3053
|
-
setHasFocus(true);
|
|
3054
|
-
}),
|
|
3055
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
3056
|
-
style: {
|
|
3057
|
-
position: 'absolute',
|
|
3058
|
-
...(isVertical ? {
|
|
3059
|
-
bottom: handlePosition
|
|
3060
|
-
} : {
|
|
3061
|
-
left: handlePosition
|
|
3062
|
-
}),
|
|
3063
|
-
...style
|
|
3064
|
-
}
|
|
3065
|
-
});
|
|
3066
|
-
});
|
|
3067
|
-
const SliderHandle = /*#__PURE__*/react.memo(SliderHandleImpl);
|
|
3068
|
-
|
|
3069
|
-
/**
|
|
3070
|
-
* `SliderRange` accepts any props that a HTML div component accepts.
|
|
3071
|
-
*
|
|
3072
|
-
* @see Docs https://reach.tech/slider#sliderhandle-props
|
|
3073
|
-
*/
|
|
3074
|
-
|
|
3075
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
3076
|
-
|
|
3077
|
-
/**
|
|
3078
|
-
* SliderMarker
|
|
3079
|
-
*
|
|
3080
|
-
* A fixed value marker. These can be used to illustrate a range of steps or
|
|
3081
|
-
* highlight important points along the slider track.
|
|
3082
|
-
*
|
|
3083
|
-
* @see Docs https://reach.tech/slider#slidermarker
|
|
3084
|
-
*/
|
|
3085
|
-
const SliderMarkerImpl = /*#__PURE__*/react.forwardRef(function SliderMarker({
|
|
3086
|
-
as: Comp = 'div',
|
|
3087
|
-
innerAs,
|
|
3088
|
-
children,
|
|
3089
|
-
style = {},
|
|
3090
|
-
value,
|
|
3091
|
-
...props
|
|
3092
|
-
}, forwardedRef) {
|
|
3093
|
-
const {
|
|
3094
|
-
disabled,
|
|
3095
|
-
isVertical,
|
|
3096
|
-
orientation,
|
|
3097
|
-
sliderMin,
|
|
3098
|
-
sliderMax,
|
|
3099
|
-
value: sliderValue
|
|
3100
|
-
} = useSliderContext('SliderMarker');
|
|
3101
|
-
const inRange = value >= sliderMin && value <= sliderMax;
|
|
3102
|
-
const absoluteStartPosition = `${valueToPercent(value, sliderMin, sliderMax)}%`;
|
|
3103
|
-
const state = value < sliderValue ? 'under-value' : value === sliderValue ? 'at-value' : 'over-value';
|
|
3104
|
-
return inRange ? /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3105
|
-
ref: forwardedRef
|
|
3106
|
-
// @ts-ignore
|
|
3107
|
-
,
|
|
3108
|
-
as: innerAs,
|
|
3109
|
-
style: {
|
|
3110
|
-
position: 'absolute',
|
|
3111
|
-
...(isVertical ? {
|
|
3112
|
-
bottom: absoluteStartPosition
|
|
3113
|
-
} : {
|
|
3114
|
-
left: absoluteStartPosition
|
|
3115
|
-
}),
|
|
3116
|
-
...style
|
|
3117
|
-
},
|
|
3118
|
-
...props,
|
|
3119
|
-
"data-reach-slider-marker": "",
|
|
3120
|
-
"data-disabled": disabled ? '' : undefined,
|
|
3121
|
-
"data-orientation": orientation,
|
|
3122
|
-
"data-state": state,
|
|
3123
|
-
"data-value": value,
|
|
3124
|
-
children: children
|
|
3125
|
-
}) : null;
|
|
3126
|
-
});
|
|
3127
|
-
const SliderMarker = /*#__PURE__*/react.memo(SliderMarkerImpl);
|
|
3128
|
-
|
|
3129
|
-
/**
|
|
3130
|
-
* @see Docs https://reach.tech/slider#slidermarker-props
|
|
3131
|
-
*/
|
|
3132
|
-
|
|
3133
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
3134
|
-
|
|
3135
|
-
function clamp$1(val, min, max) {
|
|
3136
|
-
return val > max ? max : val < min ? min : val;
|
|
3137
|
-
}
|
|
3138
|
-
|
|
3139
|
-
/**
|
|
3140
|
-
* This handles the case when num is very small (0.00000001), js will turn
|
|
3141
|
-
* this into 1e-8. When num is bigger than 1 or less than -1 it won't get
|
|
3142
|
-
* converted to this notation so it's fine.
|
|
3143
|
-
*
|
|
3144
|
-
* @param num
|
|
3145
|
-
* @see https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Slider/Slider.js#L69
|
|
3146
|
-
*/
|
|
3147
|
-
function getDecimalPrecision(num) {
|
|
3148
|
-
if (Math.abs(num) < 1) {
|
|
3149
|
-
const parts = num.toExponential().split('e-');
|
|
3150
|
-
const matissaDecimalPart = parts[0].split('.')[1];
|
|
3151
|
-
return (matissaDecimalPart ? matissaDecimalPart.length : 0) + parseInt(parts[1], 10);
|
|
3152
|
-
}
|
|
3153
|
-
const decimalPart = num.toString().split('.')[1];
|
|
3154
|
-
return decimalPart ? decimalPart.length : 0;
|
|
3155
|
-
}
|
|
3156
|
-
function percentToValue(percent, min, max) {
|
|
3157
|
-
return (max - min) * percent + min;
|
|
3158
|
-
}
|
|
3159
|
-
function roundValueToStep(value, step, min) {
|
|
3160
|
-
const nearest = Math.round((value - min) / step) * step + min;
|
|
3161
|
-
return Number(nearest.toFixed(getDecimalPrecision(step)));
|
|
3162
|
-
}
|
|
3163
|
-
function getPointerPosition(event, touchId) {
|
|
3164
|
-
if (touchId.current !== undefined && event.changedTouches) {
|
|
3165
|
-
for (let i = 0; i < event.changedTouches.length; i += 1) {
|
|
3166
|
-
const touch = event.changedTouches[i];
|
|
3167
|
-
if (touch.identifier === touchId.current) {
|
|
3168
|
-
return {
|
|
3169
|
-
x: touch.clientX,
|
|
3170
|
-
y: touch.clientY
|
|
3171
|
-
};
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
return false;
|
|
3175
|
-
}
|
|
3176
|
-
return {
|
|
3177
|
-
x: event.clientX,
|
|
3178
|
-
y: event.clientY
|
|
3179
|
-
};
|
|
3180
|
-
}
|
|
3181
|
-
function getNewValue(handlePosition, track, props) {
|
|
3182
|
-
const {
|
|
3183
|
-
orientation,
|
|
3184
|
-
min,
|
|
3185
|
-
max,
|
|
3186
|
-
step
|
|
3187
|
-
} = props;
|
|
3188
|
-
if (!track || !handlePosition) {
|
|
3189
|
-
return null;
|
|
3190
|
-
}
|
|
3191
|
-
const {
|
|
3192
|
-
left,
|
|
3193
|
-
width,
|
|
3194
|
-
bottom,
|
|
3195
|
-
height
|
|
3196
|
-
} = track.getBoundingClientRect();
|
|
3197
|
-
const isVertical = orientation === 'vertical';
|
|
3198
|
-
const diff = isVertical ? bottom - handlePosition.y : handlePosition.x - left;
|
|
3199
|
-
const percent = diff / (isVertical ? height : width);
|
|
3200
|
-
const newValue = percentToValue(percent, min, max);
|
|
3201
|
-
return clamp$1(step ? roundValueToStep(newValue, step, min) : newValue, min, max);
|
|
3202
|
-
}
|
|
3203
|
-
function useDimensions(ref) {
|
|
3204
|
-
const [{
|
|
3205
|
-
width,
|
|
3206
|
-
height
|
|
3207
|
-
}, setDimensions] = react.useState({
|
|
3208
|
-
width: 0,
|
|
3209
|
-
height: 0
|
|
3210
|
-
});
|
|
3211
|
-
// Many existing `useDimensions` type hooks will use `getBoundingClientRect`
|
|
3212
|
-
// getBoundingClientRect does not work here when borders are applied.
|
|
3213
|
-
// getComputedStyle is not as performant so we may want to create a utility to
|
|
3214
|
-
// check for any conflicts with box sizing first and only use
|
|
3215
|
-
// `getComputedStyle` if neccessary.
|
|
3216
|
-
/* const { width, height } = ref.current
|
|
3217
|
-
? ref.current.getBoundingClientRect()
|
|
3218
|
-
: 0; */
|
|
3219
|
-
|
|
3220
|
-
react.useLayoutEffect(() => {
|
|
3221
|
-
const ownerDocument = getOwnerDocument(ref.current);
|
|
3222
|
-
const ownerWindow = ownerDocument.defaultView || window;
|
|
3223
|
-
if (ref.current) {
|
|
3224
|
-
const {
|
|
3225
|
-
height: _newHeight,
|
|
3226
|
-
width: _newWidth
|
|
3227
|
-
} = ownerWindow.getComputedStyle(ref.current);
|
|
3228
|
-
const newHeight = parseFloat(_newHeight);
|
|
3229
|
-
const newWidth = parseFloat(_newWidth);
|
|
3230
|
-
if (newHeight !== height || newWidth !== width) {
|
|
3231
|
-
setDimensions({
|
|
3232
|
-
height: newHeight,
|
|
3233
|
-
width: newWidth
|
|
3234
|
-
});
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
}, [ref, width, height]);
|
|
3238
|
-
return {
|
|
3239
|
-
ref,
|
|
3240
|
-
width,
|
|
3241
|
-
height
|
|
3242
|
-
};
|
|
3243
|
-
}
|
|
3244
|
-
function valueToPercent(value, min, max) {
|
|
3245
|
-
return (value - min) * 100 / (max - min);
|
|
3246
|
-
}
|
|
3247
|
-
|
|
3248
|
-
// Spinner Component
|
|
3249
|
-
|
|
3250
|
-
const spinbuttonContext = /*#__PURE__*/react.createContext(null);
|
|
3251
|
-
const {
|
|
3252
|
-
Provider: SpinnerProvider
|
|
3253
|
-
} = spinbuttonContext;
|
|
3254
|
-
const useSpinnerContext = () => react.useContext(spinbuttonContext);
|
|
3255
|
-
|
|
3256
|
-
function clamp(value, min, max) {
|
|
3257
|
-
return Math.min(Math.max(value, min), max);
|
|
3258
|
-
}
|
|
3259
|
-
|
|
3260
|
-
const Spinner = /*#__PURE__*/react.forwardRef(function Spinner(props, forwardedRef) {
|
|
3261
|
-
const {
|
|
3262
|
-
as: Comp = 'div',
|
|
3263
|
-
minValue = -1000,
|
|
3264
|
-
maxValue = 1000,
|
|
3265
|
-
stepSize = 10,
|
|
3266
|
-
value = 0,
|
|
3267
|
-
onChange,
|
|
3268
|
-
onKeyDown,
|
|
3269
|
-
onBlur,
|
|
3270
|
-
onFocus,
|
|
3271
|
-
...otherProps
|
|
3272
|
-
} = props;
|
|
3273
|
-
const [spinnerHasFocus, setSpinnerHasFocus] = react.useState(false);
|
|
3274
|
-
const ref = react.useRef(null);
|
|
3275
|
-
const clamp$1 = value => clamp(value, minValue, maxValue);
|
|
3276
|
-
const handleKeyDown = e => {
|
|
3277
|
-
let nextValue = value;
|
|
3278
|
-
switch (e.key) {
|
|
3279
|
-
case 'ArrowUp':
|
|
3280
|
-
nextValue += 1;
|
|
3281
|
-
break;
|
|
3282
|
-
case 'ArrowDown':
|
|
3283
|
-
nextValue -= 1;
|
|
3284
|
-
break;
|
|
3285
|
-
case 'Home':
|
|
3286
|
-
nextValue = minValue;
|
|
3287
|
-
break;
|
|
3288
|
-
case 'End':
|
|
3289
|
-
nextValue = maxValue;
|
|
3290
|
-
break;
|
|
3291
|
-
case 'PageUp':
|
|
3292
|
-
nextValue += stepSize;
|
|
3293
|
-
break;
|
|
3294
|
-
case 'PageDown':
|
|
3295
|
-
nextValue -= stepSize;
|
|
3296
|
-
break;
|
|
3297
|
-
default:
|
|
3298
|
-
return;
|
|
3299
|
-
}
|
|
3300
|
-
ref.current && ref.current.focus();
|
|
3301
|
-
nextValue = clamp$1(nextValue);
|
|
3302
|
-
if (nextValue !== value) {
|
|
3303
|
-
e.preventDefault(); // prevent scrolling
|
|
3304
|
-
onChange && onChange(e, nextValue);
|
|
3305
|
-
}
|
|
3306
|
-
};
|
|
3307
|
-
const handleFocus = () => {
|
|
3308
|
-
setSpinnerHasFocus(true);
|
|
3309
|
-
};
|
|
3310
|
-
const handleBlur = () => {
|
|
3311
|
-
setSpinnerHasFocus(false);
|
|
3312
|
-
};
|
|
3313
|
-
return /*#__PURE__*/jsxRuntime.jsx(SpinnerProvider, {
|
|
3314
|
-
value: {
|
|
3315
|
-
minValue,
|
|
3316
|
-
value,
|
|
3317
|
-
maxValue,
|
|
3318
|
-
stepSize,
|
|
3319
|
-
onChange,
|
|
3320
|
-
clamp: clamp$1,
|
|
3321
|
-
spinnerHasFocus
|
|
3322
|
-
},
|
|
3323
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3324
|
-
ref: assignMultipleRefs(forwardedRef, ref),
|
|
3325
|
-
"data-spinner-root": "",
|
|
3326
|
-
role: "spinbutton",
|
|
3327
|
-
"aria-valuenow": value,
|
|
3328
|
-
"aria-valuemin": minValue,
|
|
3329
|
-
"aria-valuemax": maxValue,
|
|
3330
|
-
tabIndex: 0,
|
|
3331
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
3332
|
-
onFocus: wrapEvent(onFocus, handleFocus),
|
|
3333
|
-
onBlur: wrapEvent(onBlur, handleBlur),
|
|
3334
|
-
...otherProps
|
|
3335
|
-
})
|
|
3336
|
-
});
|
|
3337
|
-
});
|
|
3338
|
-
|
|
3339
|
-
const SpinnerButton = /*#__PURE__*/react.forwardRef(function SpinnerButton(props, forwardedRef) {
|
|
3340
|
-
const {
|
|
3341
|
-
as: Comp = 'button',
|
|
3342
|
-
type,
|
|
3343
|
-
onClick,
|
|
3344
|
-
...otherProps
|
|
3345
|
-
} = props;
|
|
3346
|
-
const spinnerContext = useSpinnerContext();
|
|
3347
|
-
if (!spinnerContext) {
|
|
3348
|
-
throw new Error('Missing <Spinner /> in component tree');
|
|
3349
|
-
}
|
|
3350
|
-
const handleClick = e => {
|
|
3351
|
-
const delta = type === 'next' ? 1 : -1;
|
|
3352
|
-
spinnerContext.onChange && spinnerContext.onChange(e, spinnerContext.value + delta);
|
|
3353
|
-
};
|
|
3354
|
-
const disabled = type === 'next' ? spinnerContext.value + 1 > spinnerContext.maxValue : spinnerContext.value - 1 < spinnerContext.minValue;
|
|
3355
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3356
|
-
...otherProps,
|
|
3357
|
-
type: "button",
|
|
3358
|
-
ref: forwardedRef,
|
|
3359
|
-
tabIndex: -1,
|
|
3360
|
-
"data-spinner-button": "",
|
|
3361
|
-
"data-spinner-has-focus": spinnerContext.spinnerHasFocus ? '' : undefined,
|
|
3362
|
-
disabled: disabled,
|
|
3363
|
-
onClick: wrapEvent(onClick, handleClick)
|
|
3364
|
-
});
|
|
3365
|
-
});
|
|
3366
|
-
|
|
3367
|
-
// Tabs Component
|
|
3368
|
-
|
|
3369
|
-
const tabsContext = /*#__PURE__*/react.createContext(null);
|
|
3370
|
-
const {
|
|
3371
|
-
Provider: TabsProvider
|
|
3372
|
-
} = tabsContext;
|
|
3373
|
-
const useTabsContext = () => react.useContext(tabsContext);
|
|
3374
|
-
|
|
3375
|
-
// TabList Component
|
|
3376
|
-
|
|
3377
|
-
const tablistContext = /*#__PURE__*/react.createContext(null);
|
|
3378
|
-
const {
|
|
3379
|
-
Provider: TabListProvider
|
|
3380
|
-
} = tablistContext;
|
|
3381
|
-
const useTabListContext = () => react.useContext(tablistContext);
|
|
3382
|
-
|
|
3383
|
-
const Tabs = /*#__PURE__*/react.forwardRef(function Tabs(props, forwardedRef) {
|
|
3384
|
-
const {
|
|
3385
|
-
as: Comp = react.Fragment,
|
|
3386
|
-
index: indexProp,
|
|
3387
|
-
onChange: onChangeProp,
|
|
3388
|
-
defaultIndex = 0,
|
|
3389
|
-
...otherProps
|
|
3390
|
-
} = props;
|
|
3391
|
-
const [index, onChange] = useControlledState(indexProp, onChangeProp, defaultIndex, setState => (e, idx) => setState(idx));
|
|
3392
|
-
const [tabListId, setTabListId] = react.useState(null);
|
|
3393
|
-
return /*#__PURE__*/jsxRuntime.jsx(TabsProvider, {
|
|
3394
|
-
value: {
|
|
3395
|
-
currentIndex: index || 0,
|
|
3396
|
-
onChange,
|
|
3397
|
-
tabListId,
|
|
3398
|
-
setTabListId
|
|
3399
|
-
},
|
|
3400
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3401
|
-
ref: forwardedRef,
|
|
3402
|
-
...otherProps
|
|
3403
|
-
})
|
|
3404
|
-
});
|
|
3405
|
-
});
|
|
3406
|
-
|
|
3407
|
-
function scopeQuery(nodeType, props) {
|
|
3408
|
-
return props['data-tab'] === '';
|
|
3409
|
-
}
|
|
3410
|
-
|
|
3411
|
-
function getNextIndex(desiredIndex, delta, allTabs) {
|
|
3412
|
-
for (let i = 0; i < allTabs.length; i++) {
|
|
3413
|
-
const nextIndex = getCircularIndex(desiredIndex + delta * i, allTabs.length);
|
|
3414
|
-
if (nextIndex !== null && !allTabs[nextIndex].disabled) {
|
|
3415
|
-
return nextIndex;
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
return null;
|
|
3419
|
-
}
|
|
3420
|
-
const Tab = /*#__PURE__*/react.forwardRef(function Tab(props, forwardedRef) {
|
|
3421
|
-
const {
|
|
3422
|
-
as: Comp = 'button',
|
|
3423
|
-
onKeyDown,
|
|
3424
|
-
onClick,
|
|
3425
|
-
index: tabIndex = -1,
|
|
3426
|
-
...otherProps
|
|
3427
|
-
} = props;
|
|
3428
|
-
const tabContext = useTabsContext();
|
|
3429
|
-
const tabListContext = useTabListContext();
|
|
3430
|
-
const ref = react.useRef(undefined);
|
|
3431
|
-
if (!tabContext || !tabListContext) {
|
|
3432
|
-
throw new Error('Missing <Tabs /> or <TabList /> in the component tree');
|
|
3433
|
-
}
|
|
3434
|
-
const handleKeyDown = e => {
|
|
3435
|
-
const right = tabListContext.vertical ? 'ArrowDown' : 'ArrowRight';
|
|
3436
|
-
const left = tabListContext.vertical ? 'ArrowUp' : 'ArrowLeft';
|
|
3437
|
-
const first = 'Home';
|
|
3438
|
-
const last = 'End';
|
|
3439
|
-
const navigateIndex = (desiredIndex, isLast) => {
|
|
3440
|
-
const delta = e.key === right || e.key === first ? 1 : -1;
|
|
3441
|
-
const allTabs = tabListContext.tabsScope.current.queryAllNodes(scopeQuery);
|
|
3442
|
-
const currentIndex = ref.current ? allTabs.indexOf(ref.current) : -1;
|
|
3443
|
-
const nextIndex = getNextIndex(isLast ? desiredIndex : currentIndex + desiredIndex, delta, allTabs);
|
|
3444
|
-
if (nextIndex !== null && nextIndex !== currentIndex && tabContext.onChange) {
|
|
3445
|
-
allTabs[nextIndex].focus();
|
|
3446
|
-
!tabListContext.manualActivation && tabContext.onChange(e, nextIndex);
|
|
3447
|
-
}
|
|
3448
|
-
};
|
|
3449
|
-
switch (e.key) {
|
|
3450
|
-
case right:
|
|
3451
|
-
case left:
|
|
3452
|
-
{
|
|
3453
|
-
navigateIndex(e.key === right ? 1 : -1, false);
|
|
3454
|
-
break;
|
|
3455
|
-
}
|
|
3456
|
-
case first: // Home / End
|
|
3457
|
-
case last:
|
|
3458
|
-
{
|
|
3459
|
-
navigateIndex(e.key === first ? 0 : -1, true);
|
|
3460
|
-
break;
|
|
3461
|
-
}
|
|
3462
|
-
}
|
|
3463
|
-
};
|
|
3464
|
-
const handleClick = e => {
|
|
3465
|
-
const allTabs = tabListContext.tabsScope.current.queryAllNodes(scopeQuery);
|
|
3466
|
-
const currentIndex = ref.current ? allTabs.indexOf(ref.current) : -1;
|
|
3467
|
-
if (currentIndex >= 0) {
|
|
3468
|
-
tabContext.onChange && tabContext.onChange(e, currentIndex);
|
|
3469
|
-
}
|
|
3470
|
-
};
|
|
3471
|
-
const isSelected = tabIndex === tabContext.currentIndex;
|
|
3472
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3473
|
-
...otherProps,
|
|
3474
|
-
ref: assignMultipleRefs(ref, forwardedRef),
|
|
3475
|
-
"data-tab": "",
|
|
3476
|
-
id: tabContext.tabListId !== null && tabIndex >= 0 ? `tab-${tabContext.tabListId}-${tabIndex}` : undefined,
|
|
3477
|
-
"aria-controls": tabContext.tabListId !== null && tabIndex >= 0 ? `tabpanel-${tabContext.tabListId}-${tabIndex}` : undefined,
|
|
3478
|
-
role: "tab",
|
|
3479
|
-
tabIndex: isSelected ? 0 : -1,
|
|
3480
|
-
"aria-selected": isSelected,
|
|
3481
|
-
selected: isSelected,
|
|
3482
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
|
3483
|
-
onClick: wrapEvent(onClick, handleClick)
|
|
3484
|
-
});
|
|
3485
|
-
});
|
|
3486
|
-
|
|
3487
|
-
const TabList = /*#__PURE__*/react.forwardRef(function TabList(props, forwardedRef) {
|
|
3488
|
-
const {
|
|
3489
|
-
as: Comp = 'div',
|
|
3490
|
-
manualActivation = false,
|
|
3491
|
-
vertical = false,
|
|
3492
|
-
children: childrenProps,
|
|
3493
|
-
...otherProps
|
|
3494
|
-
} = props;
|
|
3495
|
-
const ref = react.useRef(null);
|
|
3496
|
-
const tabsScope = useScope(ref);
|
|
3497
|
-
const tabsContext = useTabsContext();
|
|
3498
|
-
const id = react.useId();
|
|
3499
|
-
if (!tabsContext) {
|
|
3500
|
-
throw new Error('Missing <Tabs /> in the component tree');
|
|
3501
|
-
}
|
|
3502
|
-
react.useEffect(() => {
|
|
3503
|
-
if (id !== undefined) {
|
|
3504
|
-
tabsContext.setTabListId(id);
|
|
3505
|
-
return () => {
|
|
3506
|
-
tabsContext.setTabListId(null);
|
|
3507
|
-
};
|
|
3508
|
-
}
|
|
3509
|
-
return;
|
|
3510
|
-
}, [id, tabsContext, tabsContext.setTabListId]);
|
|
3511
|
-
const children = react.Children.map(childrenProps, (node, index) => /*#__PURE__*/react.cloneElement(node, {
|
|
3512
|
-
index
|
|
3513
|
-
}));
|
|
3514
|
-
return /*#__PURE__*/jsxRuntime.jsx(TabListProvider, {
|
|
3515
|
-
value: {
|
|
3516
|
-
tabsScope,
|
|
3517
|
-
manualActivation,
|
|
3518
|
-
vertical
|
|
3519
|
-
},
|
|
3520
|
-
children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3521
|
-
ref: assignMultipleRefs(forwardedRef, ref),
|
|
3522
|
-
"data-tab-list": "",
|
|
3523
|
-
role: "tablist",
|
|
3524
|
-
...otherProps,
|
|
3525
|
-
children: children
|
|
3526
|
-
})
|
|
3527
|
-
});
|
|
3528
|
-
});
|
|
3529
|
-
|
|
3530
|
-
const TabPanels = /*#__PURE__*/react.forwardRef(function TabPanels(props, forwardedRef) {
|
|
3531
|
-
const {
|
|
3532
|
-
as: Comp = react.Fragment,
|
|
3533
|
-
children: childrenProps,
|
|
3534
|
-
lazy,
|
|
3535
|
-
...otherProps
|
|
3536
|
-
} = props;
|
|
3537
|
-
const children = react.Children.map(childrenProps, (node, index) => /*#__PURE__*/react.cloneElement(node, {
|
|
3538
|
-
index,
|
|
3539
|
-
lazy
|
|
3540
|
-
}));
|
|
3541
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3542
|
-
ref: forwardedRef,
|
|
3543
|
-
...otherProps,
|
|
3544
|
-
children: children
|
|
3545
|
-
});
|
|
3546
|
-
});
|
|
3547
|
-
|
|
3548
|
-
const TabPanel = /*#__PURE__*/react.forwardRef(function TabPanel(props, forwardedRef) {
|
|
3549
|
-
const {
|
|
3550
|
-
as: Comp = 'div',
|
|
3551
|
-
index,
|
|
3552
|
-
lazy = false,
|
|
3553
|
-
children,
|
|
3554
|
-
...otherProps
|
|
3555
|
-
} = props;
|
|
3556
|
-
const tabsContext = useTabsContext();
|
|
3557
|
-
if (!tabsContext) {
|
|
3558
|
-
throw new Error('Missing <Tabs /> in the component tree.');
|
|
3559
|
-
}
|
|
3560
|
-
const isSelected = tabsContext.currentIndex === index;
|
|
3561
|
-
return /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3562
|
-
ref: forwardedRef,
|
|
3563
|
-
"data-tab-panel": "",
|
|
3564
|
-
role: "tabpanel",
|
|
3565
|
-
id: tabsContext.tabListId !== null ? `tabpanel-${tabsContext.tabListId}-${index}` : undefined,
|
|
3566
|
-
"aria-labelledby": tabsContext.tabListId !== null ? `tab-${tabsContext.tabListId}-${index}` : undefined,
|
|
3567
|
-
hidden: isSelected ? undefined : 'hidden',
|
|
3568
|
-
tabIndex: 0,
|
|
3569
|
-
...otherProps,
|
|
3570
|
-
children: (isSelected || !lazy) && children
|
|
3571
|
-
});
|
|
3572
|
-
});
|
|
3573
|
-
|
|
3574
|
-
function createSubscription() {
|
|
3575
|
-
const subscriptions = [];
|
|
3576
|
-
function subscribe(fn) {
|
|
3577
|
-
subscriptions.push(fn);
|
|
3578
|
-
return () => {
|
|
3579
|
-
subscriptions.splice(subscriptions.indexOf(fn), 1);
|
|
3580
|
-
};
|
|
3581
|
-
}
|
|
3582
|
-
function notify() {
|
|
3583
|
-
subscriptions.forEach(fn => fn());
|
|
3584
|
-
}
|
|
3585
|
-
return {
|
|
3586
|
-
subscribe,
|
|
3587
|
-
notify
|
|
3588
|
-
};
|
|
3589
|
-
}
|
|
3590
|
-
|
|
3591
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
3592
|
-
// Timeouts:
|
|
3593
|
-
|
|
3594
|
-
// Manages when the user "rests" on an element. Keeps the interface from being
|
|
3595
|
-
// flashing tooltips all the time as the user moves the mouse around the screen.
|
|
3596
|
-
let restTimeout;
|
|
3597
|
-
function startRestTimer() {
|
|
3598
|
-
clearTimeout(restTimeout);
|
|
3599
|
-
restTimeout = setTimeout(() => {
|
|
3600
|
-
send(Rest, undefined);
|
|
3601
|
-
}, 200);
|
|
3602
|
-
}
|
|
3603
|
-
function clearRestTimer() {
|
|
3604
|
-
clearTimeout(restTimeout);
|
|
3605
|
-
}
|
|
3606
|
-
|
|
3607
|
-
// Manages the delay to hide the tooltip after rest leaves.
|
|
3608
|
-
let leavingVisibleTimer;
|
|
3609
|
-
function startLeavingVisibleTimer() {
|
|
3610
|
-
clearTimeout(leavingVisibleTimer);
|
|
3611
|
-
leavingVisibleTimer = setTimeout(() => send(TimeComplete, undefined), 100);
|
|
3612
|
-
}
|
|
3613
|
-
function clearLeavingVisibleTimer() {
|
|
3614
|
-
clearTimeout(leavingVisibleTimer);
|
|
3615
|
-
}
|
|
3616
|
-
|
|
3617
|
-
////////////////////////////////////////////////////////////////////////////////
|
|
3618
|
-
// State machine
|
|
3619
|
-
|
|
3620
|
-
// Nothing goin' on
|
|
3621
|
-
const Idle = 'IDLE';
|
|
3622
|
-
// We're considering showing the tooltip, but we're gonna wait a sec
|
|
3623
|
-
const Focused = 'FOCUSED';
|
|
3624
|
-
// It's on!
|
|
3625
|
-
const Visible = 'VISIBLE';
|
|
3626
|
-
// Focus has left, but we want to keep it visible for a sec
|
|
3627
|
-
const LeavingVisible = 'LEAVING_VISIBLE';
|
|
3628
|
-
// The user clicked the tool, so we want to hide the thing, we can't just use
|
|
3629
|
-
// IDLE because we need to ignore mousemove, etc.
|
|
3630
|
-
const Dismissed = 'DISMISSED';
|
|
3631
|
-
const Blur = 'BLUR';
|
|
3632
|
-
const Focus = 'FOCUS';
|
|
3633
|
-
const GlobalMouseMove = 'GLOBAL_MOUSE_MOVE';
|
|
3634
|
-
const MouseDown = 'MOUSE_DOWN';
|
|
3635
|
-
const MouseEnter = 'MOUSE_ENTER';
|
|
3636
|
-
const MouseLeave = 'MOUSE_LEAVE';
|
|
3637
|
-
const MouseMove = 'MOUSE_MOVE';
|
|
3638
|
-
const Rest = 'REST';
|
|
3639
|
-
const SelectWithKeyboard = 'SELECT_WITH_KEYBOARD';
|
|
3640
|
-
const TimeComplete = 'TIME_COMPLETE';
|
|
3641
|
-
const subscription = createSubscription();
|
|
3642
|
-
const state = {
|
|
3643
|
-
current: {
|
|
3644
|
-
state: Idle,
|
|
3645
|
-
id: ''
|
|
3646
|
-
}
|
|
3647
|
-
};
|
|
3648
|
-
function clearContextId() {
|
|
3649
|
-
state.current.id = '';
|
|
3650
|
-
}
|
|
3651
|
-
const chart = {
|
|
3652
|
-
initial: Idle,
|
|
3653
|
-
states: {
|
|
3654
|
-
[Idle]: {
|
|
3655
|
-
enter: () => {
|
|
3656
|
-
clearContextId();
|
|
3657
|
-
},
|
|
3658
|
-
on: {
|
|
3659
|
-
[MouseEnter]: Focused,
|
|
3660
|
-
[Focus]: Visible
|
|
3661
|
-
}
|
|
3662
|
-
},
|
|
3663
|
-
[Focused]: {
|
|
3664
|
-
enter: startRestTimer,
|
|
3665
|
-
leave: clearRestTimer,
|
|
3666
|
-
on: {
|
|
3667
|
-
[MouseMove]: Focused,
|
|
3668
|
-
[MouseLeave]: Idle,
|
|
3669
|
-
[MouseDown]: Dismissed,
|
|
3670
|
-
[Blur]: Idle,
|
|
3671
|
-
[Rest]: Visible
|
|
3672
|
-
}
|
|
3673
|
-
},
|
|
3674
|
-
[Visible]: {
|
|
3675
|
-
on: {
|
|
3676
|
-
[Focus]: Focused,
|
|
3677
|
-
[MouseEnter]: Focused,
|
|
3678
|
-
[MouseLeave]: LeavingVisible,
|
|
3679
|
-
[Blur]: LeavingVisible,
|
|
3680
|
-
[MouseDown]: Dismissed,
|
|
3681
|
-
[SelectWithKeyboard]: Dismissed,
|
|
3682
|
-
[GlobalMouseMove]: LeavingVisible
|
|
3683
|
-
}
|
|
3684
|
-
},
|
|
3685
|
-
[LeavingVisible]: {
|
|
3686
|
-
enter: () => {
|
|
3687
|
-
startLeavingVisibleTimer();
|
|
3688
|
-
},
|
|
3689
|
-
leave: () => {
|
|
3690
|
-
clearLeavingVisibleTimer();
|
|
3691
|
-
clearContextId();
|
|
3692
|
-
},
|
|
3693
|
-
on: {
|
|
3694
|
-
[MouseEnter]: Visible,
|
|
3695
|
-
[Focus]: Visible,
|
|
3696
|
-
[TimeComplete]: Idle
|
|
3697
|
-
}
|
|
3698
|
-
},
|
|
3699
|
-
[Dismissed]: {
|
|
3700
|
-
leave: () => {
|
|
3701
|
-
clearContextId();
|
|
3702
|
-
},
|
|
3703
|
-
on: {
|
|
3704
|
-
[MouseLeave]: Idle,
|
|
3705
|
-
[Blur]: Idle
|
|
3706
|
-
}
|
|
3707
|
-
}
|
|
3708
|
-
}
|
|
3709
|
-
};
|
|
3710
|
-
function transition(currentState, event, payload) {
|
|
3711
|
-
const currentStateValue = currentState.state;
|
|
3712
|
-
const stateDef = chart.states[currentState.state];
|
|
3713
|
-
const nextState = stateDef?.on?.[event];
|
|
3714
|
-
|
|
3715
|
-
// Really useful for debugging
|
|
3716
|
-
// console.log({
|
|
3717
|
-
// event,
|
|
3718
|
-
// state: state.current.state,
|
|
3719
|
-
// id: state.current.id,
|
|
3720
|
-
// nextState,
|
|
3721
|
-
// });
|
|
3722
|
-
|
|
3723
|
-
if (!nextState) {
|
|
3724
|
-
return currentState;
|
|
3725
|
-
}
|
|
3726
|
-
if (stateDef && stateDef.leave) {
|
|
3727
|
-
stateDef.leave(currentStateValue, payload);
|
|
3728
|
-
}
|
|
3729
|
-
const nextStateValue = nextState;
|
|
3730
|
-
const nextDef = chart.states[nextStateValue];
|
|
3731
|
-
if (nextDef && nextDef.enter) {
|
|
3732
|
-
nextDef.enter(nextStateValue, payload);
|
|
3733
|
-
}
|
|
3734
|
-
return {
|
|
3735
|
-
...currentState,
|
|
3736
|
-
...payload,
|
|
3737
|
-
state: nextStateValue
|
|
3738
|
-
};
|
|
3739
|
-
}
|
|
3740
|
-
function send(event, payload) {
|
|
3741
|
-
const nextState = transition(state.current, event, payload);
|
|
3742
|
-
if (state.current !== nextState) {
|
|
3743
|
-
state.current = nextState;
|
|
3744
|
-
subscription.notify();
|
|
3745
|
-
}
|
|
3746
|
-
}
|
|
3747
|
-
|
|
3748
|
-
function useTooltip(childProps, childRef, tooltipProps) {
|
|
3749
|
-
const {
|
|
3750
|
-
onMouseEnter,
|
|
3751
|
-
onMouseLeave,
|
|
3752
|
-
onMouseMove,
|
|
3753
|
-
onMouseDown,
|
|
3754
|
-
onKeyDown,
|
|
3755
|
-
onFocus,
|
|
3756
|
-
onBlur
|
|
3757
|
-
} = childProps;
|
|
3758
|
-
const anchorEl = react.useRef(null);
|
|
3759
|
-
const [visible, setVisible] = react.useState(false);
|
|
3760
|
-
const id = react.useId();
|
|
3761
|
-
react.useEffect(() => {
|
|
3762
|
-
subscription.subscribe(() => {
|
|
3763
|
-
setVisible((state.current.state === Visible || state.current.state === LeavingVisible) && state.current.id === id);
|
|
3764
|
-
});
|
|
3765
|
-
}, [id]);
|
|
3766
|
-
function handleMouseEnter() {
|
|
3767
|
-
send(MouseEnter, {
|
|
3768
|
-
id
|
|
3769
|
-
});
|
|
3770
|
-
}
|
|
3771
|
-
function handleMouseMove() {
|
|
3772
|
-
send(MouseMove, {
|
|
3773
|
-
id
|
|
3774
|
-
});
|
|
3775
|
-
}
|
|
3776
|
-
function handleMouseLeave() {
|
|
3777
|
-
send(MouseLeave);
|
|
3778
|
-
}
|
|
3779
|
-
function handleMouseDown() {
|
|
3780
|
-
// Allow quick click from one tool to another
|
|
3781
|
-
if (state.current.id === id) {
|
|
3782
|
-
send(MouseDown);
|
|
3783
|
-
}
|
|
3784
|
-
}
|
|
3785
|
-
function handleFocus() {
|
|
3786
|
-
send(Focus, {
|
|
3787
|
-
id
|
|
3788
|
-
});
|
|
3789
|
-
}
|
|
3790
|
-
function handleBlur() {
|
|
3791
|
-
// Allow quick click from one tool to another
|
|
3792
|
-
if (state.current.id === id) {
|
|
3793
|
-
send(Blur, undefined);
|
|
3794
|
-
}
|
|
3795
|
-
}
|
|
3796
|
-
function handleKeyDown(event) {
|
|
3797
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
3798
|
-
send(SelectWithKeyboard);
|
|
3799
|
-
}
|
|
3800
|
-
}
|
|
3801
|
-
const {
|
|
3802
|
-
label: children,
|
|
3803
|
-
onMouseEnter: tooltipOnMouseEnter,
|
|
3804
|
-
onMouseLeave: tooltipOnMouseLeave,
|
|
3805
|
-
onMouseMove: tooltipOnMouseMove,
|
|
3806
|
-
...otherTooltipProps
|
|
3807
|
-
} = tooltipProps;
|
|
3808
|
-
const tooltipId = `tooltip-${id}`;
|
|
3809
|
-
return [{
|
|
3810
|
-
...childProps,
|
|
3811
|
-
ref: assignMultipleRefs(childRef, anchorEl),
|
|
3812
|
-
...(visible && !childProps['aria-label'] && {
|
|
3813
|
-
'aria-describedby': tooltipId
|
|
3814
|
-
}),
|
|
3815
|
-
onMouseEnter: wrapEvent(onMouseEnter, handleMouseEnter),
|
|
3816
|
-
onMouseLeave: wrapEvent(onMouseLeave, handleMouseLeave),
|
|
3817
|
-
onMouseMove: wrapEvent(onMouseMove, handleMouseMove),
|
|
3818
|
-
onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
|
|
3819
|
-
onFocus: wrapEvent(onFocus, handleFocus),
|
|
3820
|
-
onBlur: wrapEvent(onBlur, handleBlur),
|
|
3821
|
-
onKeyDown: wrapEvent(onKeyDown, handleKeyDown)
|
|
3822
|
-
}, {
|
|
3823
|
-
id: tooltipId,
|
|
3824
|
-
anchorEl,
|
|
3825
|
-
visible,
|
|
3826
|
-
children,
|
|
3827
|
-
onMouseEnter: wrapEvent(tooltipOnMouseEnter, handleMouseEnter),
|
|
3828
|
-
onMouseLeave: wrapEvent(tooltipOnMouseLeave, handleMouseLeave),
|
|
3829
|
-
onMouseMove: wrapEvent(tooltipOnMouseMove, handleMouseMove),
|
|
3830
|
-
role: 'tooltip',
|
|
3831
|
-
...otherTooltipProps
|
|
3832
|
-
}];
|
|
3833
|
-
}
|
|
3834
|
-
|
|
3835
|
-
const Tooltip = /*#__PURE__*/react.forwardRef(function Tooltip(props, forwardedRef) {
|
|
3836
|
-
const {
|
|
3837
|
-
as: Comp = 'div',
|
|
3838
|
-
innerAs,
|
|
3839
|
-
children,
|
|
3840
|
-
disabled = false,
|
|
3841
|
-
...otherProps
|
|
3842
|
-
} = props;
|
|
3843
|
-
const child = react.Children.only(children);
|
|
3844
|
-
// React 19: ref lives in props. React <=18: ref lives on element directly.
|
|
3845
|
-
const childRef = child.props.ref ?? child.ref;
|
|
3846
|
-
const [childProps, {
|
|
3847
|
-
visible,
|
|
3848
|
-
...tooltipProps
|
|
3849
|
-
}] = useTooltip(child.props, childRef, otherProps);
|
|
3850
|
-
if (disabled) {
|
|
3851
|
-
return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
3852
|
-
children: child
|
|
3853
|
-
});
|
|
3854
|
-
}
|
|
3855
|
-
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
3856
|
-
children: [/*#__PURE__*/react.cloneElement(child, childProps), visible && /*#__PURE__*/jsxRuntime.jsx(Comp, {
|
|
3857
|
-
as: innerAs,
|
|
3858
|
-
ref: forwardedRef,
|
|
3859
|
-
...tooltipProps
|
|
3860
|
-
})]
|
|
3861
|
-
});
|
|
3862
|
-
});
|
|
3863
|
-
|
|
3864
|
-
exports.Accordion = Accordion;
|
|
3865
|
-
exports.AccordionBody = AccordionBody;
|
|
3866
|
-
exports.AccordionHeader = AccordionHeader;
|
|
3867
|
-
exports.AccordionItem = AccordionItem;
|
|
3868
|
-
exports.CheckBox = CheckBox;
|
|
3869
|
-
exports.ComboBoxProvider = ComboBoxProvider;
|
|
3870
|
-
exports.Combobox = Combobox;
|
|
3871
|
-
exports.ComboboxButton = ComboboxButton;
|
|
3872
|
-
exports.ComboboxInput = ComboboxInput;
|
|
3873
|
-
exports.ComboboxLabel = ComboboxLabel;
|
|
3874
|
-
exports.ComboboxList = ComboboxList;
|
|
3875
|
-
exports.ComboboxOption = ComboboxOption;
|
|
3876
|
-
exports.ComboboxPopover = ComboboxPopover;
|
|
3877
|
-
exports.ContextMenuTrigger = ContextMenuTrigger;
|
|
3878
|
-
exports.FocusLock = FocusLock;
|
|
3879
|
-
exports.Menu = Menu;
|
|
3880
|
-
exports.MenuButton = MenuButton;
|
|
3881
|
-
exports.MenuItem = MenuItem;
|
|
3882
|
-
exports.MenuList = MenuList;
|
|
3883
|
-
exports.MenuPopover = MenuPopover;
|
|
3884
|
-
exports.Modal = Modal;
|
|
3885
|
-
exports.ModalBackdrop = ModalBackdrop;
|
|
3886
|
-
exports.Popper = Popper;
|
|
3887
|
-
exports.PopperArrow = PopperArrow;
|
|
3888
|
-
exports.PopperProvider = PopperProvider;
|
|
3889
|
-
exports.Portal = Portal;
|
|
3890
|
-
exports.PortalSelectorProvider = PortalSelectorProvider;
|
|
3891
|
-
exports.RadioButton = RadioButton;
|
|
3892
|
-
exports.RadioGroup = RadioGroup;
|
|
3893
|
-
exports.Slider = Slider;
|
|
3894
|
-
exports.SliderHandle = SliderHandle;
|
|
3895
|
-
exports.SliderInput = SliderInput;
|
|
3896
|
-
exports.SliderMarker = SliderMarker;
|
|
3897
|
-
exports.SliderRange = SliderRange;
|
|
3898
|
-
exports.SliderTrack = SliderTrack;
|
|
3899
|
-
exports.Spinner = Spinner;
|
|
3900
|
-
exports.SpinnerButton = SpinnerButton;
|
|
3901
|
-
exports.Tab = Tab;
|
|
3902
|
-
exports.TabList = TabList;
|
|
3903
|
-
exports.TabPanel = TabPanel;
|
|
3904
|
-
exports.TabPanels = TabPanels;
|
|
3905
|
-
exports.Tabs = Tabs;
|
|
3906
|
-
exports.Tooltip = Tooltip;
|
|
3907
|
-
exports.assignMultipleRefs = assignMultipleRefs;
|
|
3908
|
-
exports.assignRef = assignRef;
|
|
3909
|
-
exports.canUseDOM = canUseDOM;
|
|
3910
|
-
exports.createContext = createContext;
|
|
3911
|
-
exports.gestureHandlers = gestureHandlers;
|
|
3912
|
-
exports.getCircularIndex = getCircularIndex;
|
|
3913
|
-
exports.getOwnerDocument = getOwnerDocument;
|
|
3914
|
-
exports.getScope = getScope;
|
|
3915
|
-
exports.initialGestureHandlersState = initialGestureHandlersState;
|
|
3916
|
-
exports.isRightClick = isRightClick;
|
|
3917
|
-
exports.rubberBand = rubberBand;
|
|
3918
|
-
exports.rubberBandClamp = rubberBandClamp;
|
|
3919
|
-
exports.useAutoFocus = useAutoFocus;
|
|
3920
|
-
exports.useChildrenCounterChild = useChildrenCounterChild;
|
|
3921
|
-
exports.useChildrenCounterParent = useChildrenCounterParent;
|
|
3922
|
-
exports.useComboBoxContext = useComboBoxContext;
|
|
3923
|
-
exports.useControlledState = useControlledState;
|
|
3924
|
-
exports.useFocusReturn = useFocusReturn;
|
|
3925
|
-
exports.useFocusState = useFocusState;
|
|
3926
|
-
exports.useGestureHandlers = useGestureHandlers;
|
|
3927
|
-
exports.useMeasure = useMeasure;
|
|
3928
|
-
exports.useOnClickOutside = useOnClickOutside;
|
|
3929
|
-
exports.useOnKeyDown = useOnKeyDown;
|
|
3930
|
-
exports.usePopperContext = usePopperContext;
|
|
3931
|
-
exports.useReducerMachine = useReducerMachine;
|
|
3932
|
-
exports.useRemoveBodyScroll = useRemoveBodyScroll;
|
|
3933
|
-
exports.useScope = useScope;
|
|
3934
|
-
exports.useStableCallback = useStableCallback;
|
|
3935
|
-
exports.useStableLayoutCallback = useStableLayoutCallback;
|
|
3936
|
-
exports.useThrottle = useThrottle;
|
|
3937
|
-
exports.wrapEvent = wrapEvent;
|
|
3938
|
-
//# sourceMappingURL=index.js.map
|