@react-md/core 6.2.1 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/datetime/NativeDateField.d.ts +24 -0
- package/dist/datetime/NativeDateField.js +63 -0
- package/dist/datetime/NativeDateField.js.map +1 -0
- package/dist/datetime/NativeTimeField.d.ts +26 -0
- package/dist/datetime/NativeTimeField.js +63 -0
- package/dist/datetime/NativeTimeField.js.map +1 -0
- package/dist/datetime/useDateField.d.ts +120 -0
- package/dist/datetime/useDateField.js +35 -0
- package/dist/datetime/useDateField.js.map +1 -0
- package/dist/datetime/useTimeField.d.ts +124 -0
- package/dist/datetime/useTimeField.js +65 -0
- package/dist/datetime/useTimeField.js.map +1 -0
- package/dist/datetime/utils.d.ts +34 -0
- package/dist/datetime/utils.js +27 -0
- package/dist/datetime/utils.js.map +1 -0
- package/dist/draggable/utils.d.ts +3 -6
- package/dist/draggable/utils.js.map +1 -1
- package/dist/expansion-panel/ExpansionList.js +1 -1
- package/dist/expansion-panel/ExpansionList.js.map +1 -1
- package/dist/expansion-panel/useExpansionList.d.ts +2 -7
- package/dist/expansion-panel/useExpansionList.js.map +1 -1
- package/dist/form/FormMessage.js +3 -1
- package/dist/form/FormMessage.js.map +1 -1
- package/dist/form/FormMessageContainer.d.ts +2 -1
- package/dist/form/FormMessageContainer.js +3 -2
- package/dist/form/FormMessageContainer.js.map +1 -1
- package/dist/form/FormMessageCounter.d.ts +3 -2
- package/dist/form/FormMessageCounter.js +5 -2
- package/dist/form/FormMessageCounter.js.map +1 -1
- package/dist/form/Listbox.d.ts +3 -10
- package/dist/form/Listbox.js +8 -27
- package/dist/form/Listbox.js.map +1 -1
- package/dist/form/ListboxProvider.d.ts +17 -0
- package/dist/form/ListboxProvider.js +33 -1
- package/dist/form/ListboxProvider.js.map +1 -1
- package/dist/form/NativeSelect.js +1 -0
- package/dist/form/NativeSelect.js.map +1 -1
- package/dist/form/TextArea.js +1 -0
- package/dist/form/TextArea.js.map +1 -1
- package/dist/form/TextField.js +1 -0
- package/dist/form/TextField.js.map +1 -1
- package/dist/form/_form-message.scss +13 -0
- package/dist/form/_text-field.scss +12 -3
- package/dist/form/formMessageContainerStyles.d.ts +7 -0
- package/dist/form/formMessageContainerStyles.js +4 -2
- package/dist/form/formMessageContainerStyles.js.map +1 -1
- package/dist/form/sliderUtils.d.ts +3 -7
- package/dist/form/sliderUtils.js.map +1 -1
- package/dist/form/types.d.ts +13 -0
- package/dist/form/types.js.map +1 -1
- package/dist/form/useCombobox.d.ts +6 -2
- package/dist/form/useCombobox.js +8 -9
- package/dist/form/useCombobox.js.map +1 -1
- package/dist/form/useFormReset.d.ts +4 -1
- package/dist/form/useFormReset.js +9 -4
- package/dist/form/useFormReset.js.map +1 -1
- package/dist/form/useNumberField.d.ts +5 -5
- package/dist/form/useNumberField.js +10 -2
- package/dist/form/useNumberField.js.map +1 -1
- package/dist/form/useSelectCombobox.js +2 -2
- package/dist/form/useSelectCombobox.js.map +1 -1
- package/dist/form/useTextField.d.ts +76 -59
- package/dist/form/useTextField.js +7 -1
- package/dist/form/useTextField.js.map +1 -1
- package/dist/interaction/utils.d.ts +14 -0
- package/dist/interaction/utils.js +23 -12
- package/dist/interaction/utils.js.map +1 -1
- package/dist/menu/MenuBar.js +1 -1
- package/dist/menu/MenuBar.js.map +1 -1
- package/dist/menu/MenuItemTextField.d.ts +1 -2
- package/dist/menu/MenuItemTextField.js.map +1 -1
- package/dist/menu/MenuWidget.js +3 -2
- package/dist/menu/MenuWidget.js.map +1 -1
- package/dist/movement/constants.d.ts +10 -0
- package/dist/movement/constants.js +20 -4
- package/dist/movement/constants.js.map +1 -1
- package/dist/movement/types.d.ts +59 -10
- package/dist/movement/types.js.map +1 -1
- package/dist/movement/useKeyboardMovementProvider.d.ts +5 -1
- package/dist/movement/useKeyboardMovementProvider.js +171 -73
- package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
- package/dist/tabs/useTabList.js +1 -1
- package/dist/tabs/useTabList.js.map +1 -1
- package/dist/test-utils/drag.d.ts +6 -9
- package/dist/transition/useCarousel.d.ts +2 -2
- package/dist/transition/useCarousel.js.map +1 -1
- package/dist/tree/Tree.js +1 -1
- package/dist/tree/Tree.js.map +1 -1
- package/dist/tree/useTreeMovement.d.ts +2 -1
- package/dist/tree/useTreeMovement.js +2 -1
- package/dist/tree/useTreeMovement.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/getMiddleOfRange.d.ts +2 -3
- package/dist/utils/getMiddleOfRange.js.map +1 -1
- package/dist/utils/getPercentage.d.ts +2 -9
- package/dist/utils/getPercentage.js +1 -1
- package/dist/utils/getPercentage.js.map +1 -1
- package/dist/utils/getRangeSteps.d.ts +2 -3
- package/dist/utils/getRangeSteps.js +0 -3
- package/dist/utils/getRangeSteps.js.map +1 -1
- package/dist/utils/nearest.d.ts +2 -3
- package/dist/utils/nearest.js +0 -3
- package/dist/utils/nearest.js.map +1 -1
- package/dist/utils/trigonometry.d.ts +31 -0
- package/dist/utils/trigonometry.js +25 -0
- package/dist/utils/trigonometry.js.map +1 -0
- package/dist/window-splitter/useWindowSplitter.d.ts +1 -1
- package/dist/window-splitter/useWindowSplitter.js.map +1 -1
- package/package.json +1 -1
- package/src/datetime/NativeDateField.tsx +92 -0
- package/src/datetime/NativeTimeField.tsx +94 -0
- package/src/datetime/useDateField.ts +193 -0
- package/src/datetime/useTimeField.ts +233 -0
- package/src/datetime/utils.ts +48 -0
- package/src/draggable/utils.ts +3 -6
- package/src/expansion-panel/ExpansionList.tsx +2 -1
- package/src/expansion-panel/useExpansionList.ts +6 -12
- package/src/form/FormMessage.tsx +4 -0
- package/src/form/FormMessageContainer.tsx +8 -4
- package/src/form/FormMessageCounter.tsx +17 -6
- package/src/form/Listbox.tsx +18 -46
- package/src/form/ListboxProvider.ts +61 -1
- package/src/form/NativeSelect.tsx +1 -0
- package/src/form/TextArea.tsx +1 -0
- package/src/form/TextField.tsx +1 -0
- package/src/form/formMessageContainerStyles.ts +10 -2
- package/src/form/sliderUtils.ts +3 -7
- package/src/form/types.ts +15 -0
- package/src/form/useCombobox.ts +15 -10
- package/src/form/useFormReset.ts +12 -5
- package/src/form/useNumberField.ts +17 -14
- package/src/form/useSelectCombobox.ts +2 -2
- package/src/form/useTextField.ts +102 -69
- package/src/interaction/utils.ts +18 -20
- package/src/menu/MenuBar.tsx +1 -1
- package/src/menu/MenuItemTextField.tsx +1 -3
- package/src/menu/MenuWidget.tsx +4 -2
- package/src/movement/constants.ts +26 -4
- package/src/movement/types.ts +84 -19
- package/src/movement/useKeyboardMovementProvider.ts +209 -95
- package/src/tabs/useTabList.ts +1 -1
- package/src/test-utils/drag.ts +8 -12
- package/src/transition/useCarousel.ts +2 -2
- package/src/tree/Tree.tsx +1 -1
- package/src/tree/useTreeMovement.ts +4 -0
- package/src/types.ts +16 -0
- package/src/utils/getMiddleOfRange.ts +2 -3
- package/src/utils/getPercentage.ts +3 -11
- package/src/utils/getRangeSteps.ts +3 -3
- package/src/utils/nearest.ts +3 -3
- package/src/utils/trigonometry.ts +46 -0
- package/src/window-splitter/useWindowSplitter.ts +3 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
createContext,
|
|
5
|
+
useCallback,
|
|
5
6
|
useContext,
|
|
6
7
|
useEffect,
|
|
7
8
|
useMemo,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
import { getFocusableElements as defaultGetFocusableElements } from "../focus/utils.js";
|
|
13
14
|
import { useUserInteractionMode } from "../interaction/UserInteractionModeProvider.js";
|
|
14
15
|
import { useDir } from "../typography/WritingDirectionProvider.js";
|
|
16
|
+
import { useEnsuredRef } from "../useEnsuredRef.js";
|
|
15
17
|
import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect.js";
|
|
16
18
|
import {
|
|
17
19
|
DEFAULT_KEYBOARD_MOVEMENT,
|
|
@@ -19,12 +21,13 @@ import {
|
|
|
19
21
|
DEFAULT_RTL_KEYBOARD_MOVEMENT,
|
|
20
22
|
} from "./constants.js";
|
|
21
23
|
import { findMatchIndex } from "./findMatchIndex.js";
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
import {
|
|
25
|
+
type KeyboardFocusFromKeyOptions,
|
|
26
|
+
type KeyboardMovementConfig,
|
|
27
|
+
type KeyboardMovementConfiguration,
|
|
28
|
+
type KeyboardMovementContext,
|
|
29
|
+
type KeyboardMovementProviderImplementation,
|
|
30
|
+
type KeyboardMovementProviderOptions,
|
|
28
31
|
} from "./types.js";
|
|
29
32
|
import {
|
|
30
33
|
getFirstFocusableIndex,
|
|
@@ -38,19 +41,36 @@ import {
|
|
|
38
41
|
recalculateFocusIndex,
|
|
39
42
|
} from "./utils.js";
|
|
40
43
|
|
|
44
|
+
const noop = (): void => {
|
|
45
|
+
// do nothing
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @since 6.3.0
|
|
50
|
+
*/
|
|
51
|
+
export const DEFAULT_KEYBOARD_MOVEMENT_CONTEXT: Readonly<KeyboardMovementContext> =
|
|
52
|
+
{
|
|
53
|
+
config: { current: DEFAULT_KEYBOARD_MOVEMENT },
|
|
54
|
+
loopable: false,
|
|
55
|
+
searchable: false,
|
|
56
|
+
horizontal: false,
|
|
57
|
+
includeDisabled: false,
|
|
58
|
+
tabIndexBehavior: undefined,
|
|
59
|
+
activeDescendantId: "",
|
|
60
|
+
focusFirst: noop,
|
|
61
|
+
focusLast: noop,
|
|
62
|
+
focusNext: noop,
|
|
63
|
+
focusPrevious: noop,
|
|
64
|
+
focusFromKey: noop,
|
|
65
|
+
};
|
|
66
|
+
|
|
41
67
|
/**
|
|
42
68
|
* @since 5.0.0
|
|
43
69
|
* @internal
|
|
44
70
|
*/
|
|
45
|
-
const context = createContext<KeyboardMovementContext>(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
searchable: false,
|
|
49
|
-
horizontal: false,
|
|
50
|
-
includeDisabled: false,
|
|
51
|
-
tabIndexBehavior: undefined,
|
|
52
|
-
activeDescendantId: "",
|
|
53
|
-
});
|
|
71
|
+
const context = createContext<KeyboardMovementContext>(
|
|
72
|
+
DEFAULT_KEYBOARD_MOVEMENT_CONTEXT
|
|
73
|
+
);
|
|
54
74
|
context.displayName = "KeyboardMovement";
|
|
55
75
|
export const { Provider: KeyboardMovementProvider } = context;
|
|
56
76
|
|
|
@@ -62,10 +82,6 @@ export function useKeyboardMovementContext(): Readonly<KeyboardMovementContext>
|
|
|
62
82
|
return useContext(context);
|
|
63
83
|
}
|
|
64
84
|
|
|
65
|
-
const noop = (): void => {
|
|
66
|
-
// do nothing
|
|
67
|
-
};
|
|
68
|
-
|
|
69
85
|
const returnNegative1 = (): number => -1;
|
|
70
86
|
|
|
71
87
|
/**
|
|
@@ -193,6 +209,7 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
193
209
|
options: KeyboardMovementProviderOptions<E> = {}
|
|
194
210
|
): KeyboardMovementProviderImplementation<E> {
|
|
195
211
|
const {
|
|
212
|
+
ref: propRef,
|
|
196
213
|
onClick = noop,
|
|
197
214
|
onFocus = noop,
|
|
198
215
|
onKeyDown = noop,
|
|
@@ -200,6 +217,7 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
200
217
|
disabled,
|
|
201
218
|
searchable = false,
|
|
202
219
|
horizontal = false,
|
|
220
|
+
trackTabKeys = false,
|
|
203
221
|
includeDisabled = false,
|
|
204
222
|
tabIndexBehavior,
|
|
205
223
|
extendKeyDown = noop,
|
|
@@ -214,6 +232,8 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
214
232
|
isNegativeOneAllowed = false,
|
|
215
233
|
} = options;
|
|
216
234
|
|
|
235
|
+
const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);
|
|
236
|
+
|
|
217
237
|
const isRTL = useDir().dir === "rtl";
|
|
218
238
|
let defaults: Readonly<Required<KeyboardMovementConfiguration>>;
|
|
219
239
|
if (horizontal) {
|
|
@@ -240,29 +260,10 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
240
260
|
config.current = configuration;
|
|
241
261
|
});
|
|
242
262
|
|
|
243
|
-
const [activeDescendantId, setActiveDescendantId] = useState("");
|
|
244
|
-
const movementContext = useMemo<KeyboardMovementContext>(
|
|
245
|
-
() => ({
|
|
246
|
-
config,
|
|
247
|
-
loopable,
|
|
248
|
-
searchable,
|
|
249
|
-
horizontal,
|
|
250
|
-
includeDisabled,
|
|
251
|
-
tabIndexBehavior,
|
|
252
|
-
activeDescendantId,
|
|
253
|
-
}),
|
|
254
|
-
[
|
|
255
|
-
activeDescendantId,
|
|
256
|
-
horizontal,
|
|
257
|
-
includeDisabled,
|
|
258
|
-
loopable,
|
|
259
|
-
searchable,
|
|
260
|
-
tabIndexBehavior,
|
|
261
|
-
]
|
|
262
|
-
);
|
|
263
|
-
const currentFocusIndex = useRef(-1);
|
|
264
263
|
const mode = useUserInteractionMode();
|
|
265
264
|
const refocus = useRef(false);
|
|
265
|
+
const currentFocusIndex = useRef(-1);
|
|
266
|
+
const [activeDescendantId, setActiveDescendantId] = useState("");
|
|
266
267
|
|
|
267
268
|
if (process.env.NODE_ENV !== "production") {
|
|
268
269
|
// this fixes issues during hot reloading and using the `useId()` hook
|
|
@@ -282,10 +283,155 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
282
283
|
: 0;
|
|
283
284
|
}
|
|
284
285
|
|
|
286
|
+
const getFocusableElementsFromRef = useCallback(() => {
|
|
287
|
+
const container = nodeRef.current;
|
|
288
|
+
if (!container) {
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return getFocusableElements(container, programmatic);
|
|
293
|
+
}, [getFocusableElements, nodeRef, programmatic]);
|
|
294
|
+
const updateFocusIndex = useCallback(
|
|
295
|
+
(index: number, focusables = getFocusableElementsFromRef()) => {
|
|
296
|
+
if (currentFocusIndex.current === index || index === -1) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
currentFocusIndex.current = index;
|
|
301
|
+
const focused = focusables[index];
|
|
302
|
+
if (tabIndexBehavior) {
|
|
303
|
+
focused.scrollIntoView({
|
|
304
|
+
block: "nearest",
|
|
305
|
+
inline: "nearest",
|
|
306
|
+
});
|
|
307
|
+
setActiveDescendantId(focused.id);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (tabIndexBehavior !== "virtual") {
|
|
311
|
+
focused.focus();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
onFocusChange({
|
|
315
|
+
index,
|
|
316
|
+
element: focused,
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
[getFocusableElementsFromRef, onFocusChange, tabIndexBehavior]
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const focusNext = useCallback(
|
|
323
|
+
(focusables = getFocusableElementsFromRef()) => {
|
|
324
|
+
updateFocusIndex(
|
|
325
|
+
getNextFocusableIndex({
|
|
326
|
+
loopable,
|
|
327
|
+
increment: true,
|
|
328
|
+
focusables,
|
|
329
|
+
includeDisabled: true,
|
|
330
|
+
currentFocusIndex: currentFocusIndex.current,
|
|
331
|
+
}),
|
|
332
|
+
focusables
|
|
333
|
+
);
|
|
334
|
+
},
|
|
335
|
+
[getFocusableElementsFromRef, loopable, updateFocusIndex]
|
|
336
|
+
);
|
|
337
|
+
const focusPrevious = useCallback(
|
|
338
|
+
(focusables = getFocusableElementsFromRef()) => {
|
|
339
|
+
updateFocusIndex(
|
|
340
|
+
getNextFocusableIndex({
|
|
341
|
+
loopable,
|
|
342
|
+
increment: false,
|
|
343
|
+
focusables,
|
|
344
|
+
includeDisabled: true,
|
|
345
|
+
currentFocusIndex: currentFocusIndex.current,
|
|
346
|
+
}),
|
|
347
|
+
focusables
|
|
348
|
+
);
|
|
349
|
+
},
|
|
350
|
+
[getFocusableElementsFromRef, loopable, updateFocusIndex]
|
|
351
|
+
);
|
|
352
|
+
const focusFirst = useCallback(
|
|
353
|
+
(focusables = getFocusableElementsFromRef()) => {
|
|
354
|
+
updateFocusIndex(
|
|
355
|
+
getFirstFocusableIndex({
|
|
356
|
+
focusables,
|
|
357
|
+
includeDisabled,
|
|
358
|
+
}),
|
|
359
|
+
focusables
|
|
360
|
+
);
|
|
361
|
+
},
|
|
362
|
+
[getFocusableElementsFromRef, includeDisabled, updateFocusIndex]
|
|
363
|
+
);
|
|
364
|
+
const focusLast = useCallback(
|
|
365
|
+
(focusables = getFocusableElementsFromRef()) => {
|
|
366
|
+
updateFocusIndex(
|
|
367
|
+
getLastFocusableIndex({
|
|
368
|
+
focusables,
|
|
369
|
+
includeDisabled,
|
|
370
|
+
}),
|
|
371
|
+
focusables
|
|
372
|
+
);
|
|
373
|
+
},
|
|
374
|
+
[getFocusableElementsFromRef, includeDisabled, updateFocusIndex]
|
|
375
|
+
);
|
|
376
|
+
const focusFromKey = useCallback(
|
|
377
|
+
(options: KeyboardFocusFromKeyOptions) => {
|
|
378
|
+
const {
|
|
379
|
+
key,
|
|
380
|
+
reversed,
|
|
381
|
+
focusables = getFocusableElementsFromRef(),
|
|
382
|
+
} = options;
|
|
383
|
+
if (!searchable) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const index = findMatchIndex({
|
|
388
|
+
value: key,
|
|
389
|
+
values: focusables.map((element) =>
|
|
390
|
+
getSearchText(element, !isNotFocusable(element, includeDisabled))
|
|
391
|
+
),
|
|
392
|
+
startIndex: reversed ? -1 : currentFocusIndex.current,
|
|
393
|
+
});
|
|
394
|
+
updateFocusIndex(index, focusables);
|
|
395
|
+
},
|
|
396
|
+
[getFocusableElementsFromRef, includeDisabled, searchable, updateFocusIndex]
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const movementContext = useMemo<KeyboardMovementContext>(
|
|
400
|
+
() => ({
|
|
401
|
+
config,
|
|
402
|
+
loopable,
|
|
403
|
+
searchable,
|
|
404
|
+
horizontal,
|
|
405
|
+
focusFirst,
|
|
406
|
+
focusLast,
|
|
407
|
+
focusNext,
|
|
408
|
+
focusPrevious,
|
|
409
|
+
focusFromKey,
|
|
410
|
+
includeDisabled,
|
|
411
|
+
tabIndexBehavior,
|
|
412
|
+
activeDescendantId,
|
|
413
|
+
}),
|
|
414
|
+
[
|
|
415
|
+
activeDescendantId,
|
|
416
|
+
focusFirst,
|
|
417
|
+
focusFromKey,
|
|
418
|
+
focusLast,
|
|
419
|
+
focusNext,
|
|
420
|
+
focusPrevious,
|
|
421
|
+
horizontal,
|
|
422
|
+
includeDisabled,
|
|
423
|
+
loopable,
|
|
424
|
+
searchable,
|
|
425
|
+
tabIndexBehavior,
|
|
426
|
+
]
|
|
427
|
+
);
|
|
428
|
+
|
|
285
429
|
return {
|
|
430
|
+
nodeRef,
|
|
286
431
|
movementProps: {
|
|
287
432
|
"aria-activedescendant":
|
|
288
433
|
tabIndexBehavior === "virtual" ? activeDescendantId : undefined,
|
|
434
|
+
ref: nodeRefCallback,
|
|
289
435
|
tabIndex,
|
|
290
436
|
|
|
291
437
|
// Note: This used to be on the `onFocus` event, but this causes issues in
|
|
@@ -411,28 +557,7 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
411
557
|
): void => {
|
|
412
558
|
event.preventDefault();
|
|
413
559
|
event.stopPropagation();
|
|
414
|
-
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
currentFocusIndex.current = index;
|
|
419
|
-
const focused = focusables[index];
|
|
420
|
-
if (tabIndexBehavior) {
|
|
421
|
-
focused.scrollIntoView({
|
|
422
|
-
block: "nearest",
|
|
423
|
-
inline: "nearest",
|
|
424
|
-
});
|
|
425
|
-
setActiveDescendantId(focused.id);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (tabIndexBehavior !== "virtual") {
|
|
429
|
-
focused.focus();
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
onFocusChange({
|
|
433
|
-
index,
|
|
434
|
-
element: focused,
|
|
435
|
-
});
|
|
560
|
+
updateFocusIndex(index, focusables);
|
|
436
561
|
};
|
|
437
562
|
|
|
438
563
|
extendKeyDown({
|
|
@@ -487,15 +612,14 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
487
612
|
} = config.current;
|
|
488
613
|
|
|
489
614
|
if (searchable && isSearchableEvent(event)) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
setFocusIndex(index, focusables);
|
|
615
|
+
event.preventDefault();
|
|
616
|
+
event.stopPropagation();
|
|
617
|
+
focusFromKey({ key, reversed: shiftKey });
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (trackTabKeys && key === "Tab") {
|
|
622
|
+
currentFocusIndex.current += event.shiftKey ? -1 : 1;
|
|
499
623
|
return;
|
|
500
624
|
}
|
|
501
625
|
|
|
@@ -509,33 +633,23 @@ export function useKeyboardMovementProvider<E extends HTMLElement>(
|
|
|
509
633
|
!increment &&
|
|
510
634
|
decrementKeys.includes(key);
|
|
511
635
|
|
|
512
|
-
if (!jumpToFirst && !jumpToLast && !increment && !decrement) {
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
const focusables = getFocusableElements(currentTarget, programmatic);
|
|
516
|
-
|
|
517
|
-
let index: number;
|
|
518
636
|
if (jumpToFirst) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
});
|
|
637
|
+
event.preventDefault();
|
|
638
|
+
event.stopPropagation();
|
|
639
|
+
focusFirst();
|
|
523
640
|
} else if (jumpToLast) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
});
|
|
641
|
+
event.preventDefault();
|
|
642
|
+
event.stopPropagation();
|
|
643
|
+
focusLast();
|
|
644
|
+
} else if (increment) {
|
|
645
|
+
event.preventDefault();
|
|
646
|
+
event.stopPropagation();
|
|
647
|
+
focusNext();
|
|
648
|
+
} else if (decrement) {
|
|
649
|
+
event.preventDefault();
|
|
650
|
+
event.stopPropagation();
|
|
651
|
+
focusPrevious();
|
|
536
652
|
}
|
|
537
|
-
|
|
538
|
-
setFocusIndex(index, focusables);
|
|
539
653
|
},
|
|
540
654
|
},
|
|
541
655
|
movementContext,
|
package/src/tabs/useTabList.ts
CHANGED
|
@@ -176,6 +176,7 @@ export function useTabList(
|
|
|
176
176
|
const forwardRef = useRef<HTMLDivElement>(null);
|
|
177
177
|
const backwardRef = useRef<HTMLDivElement>(null);
|
|
178
178
|
const { movementProps, movementContext } = useKeyboardMovementProvider({
|
|
179
|
+
ref: tabListRef,
|
|
179
180
|
onClick(event) {
|
|
180
181
|
onClick(event);
|
|
181
182
|
if (event.isPropagationStopped() || !(event.target instanceof Element)) {
|
|
@@ -226,7 +227,6 @@ export function useTabList(
|
|
|
226
227
|
return {
|
|
227
228
|
elementProps: {
|
|
228
229
|
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
229
|
-
ref: tabListRef,
|
|
230
230
|
style: {
|
|
231
231
|
...style,
|
|
232
232
|
...(disableTransition ? undefined : indicatorStyles),
|
package/src/test-utils/drag.ts
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import { fireEvent } from "@testing-library/dom";
|
|
2
2
|
import type { MouseEvent } from "react";
|
|
3
3
|
|
|
4
|
+
import { type Point } from "../types.js";
|
|
4
5
|
import { wait } from "../utils/wait.js";
|
|
5
6
|
|
|
6
|
-
interface XYCoords {
|
|
7
|
-
x: number;
|
|
8
|
-
y: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
7
|
interface BaseDragOptions {
|
|
12
|
-
to?:
|
|
13
|
-
from?:
|
|
14
|
-
delta?:
|
|
8
|
+
to?: Point | Element;
|
|
9
|
+
from?: Point;
|
|
10
|
+
delta?: Point;
|
|
15
11
|
steps?: number;
|
|
16
12
|
duration?: number;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
15
|
type DragOptions = BaseDragOptions &
|
|
20
|
-
({ to:
|
|
16
|
+
({ to: Point | Element; delta?: never } | { delta: Point; to?: never });
|
|
21
17
|
|
|
22
|
-
const getElementClientCenter = (element: Element):
|
|
18
|
+
const getElementClientCenter = (element: Element): Point => {
|
|
23
19
|
const { left, top, width, height } = element.getBoundingClientRect();
|
|
24
20
|
return {
|
|
25
21
|
x: left + width / 2,
|
|
@@ -27,7 +23,7 @@ const getElementClientCenter = (element: Element): XYCoords => {
|
|
|
27
23
|
};
|
|
28
24
|
};
|
|
29
25
|
|
|
30
|
-
const getCoords = (elementOrCoords: Element |
|
|
26
|
+
const getCoords = (elementOrCoords: Element | Point): Point =>
|
|
31
27
|
"x" in elementOrCoords && "y" in elementOrCoords
|
|
32
28
|
? elementOrCoords
|
|
33
29
|
: getElementClientCenter(elementOrCoords);
|
|
@@ -58,7 +54,7 @@ export async function drag(
|
|
|
58
54
|
}
|
|
59
55
|
: getCoords(inTo);
|
|
60
56
|
|
|
61
|
-
const step:
|
|
57
|
+
const step: Point = {
|
|
62
58
|
x: (to.x - from.x) / steps,
|
|
63
59
|
y: (to.y - from.y) / steps,
|
|
64
60
|
};
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
|
|
5
|
-
import type
|
|
5
|
+
import { type UseStateSetter } from "../types.js";
|
|
6
6
|
import { useToggle } from "../useToggle.js";
|
|
7
7
|
import { loop } from "../utils/loop.js";
|
|
8
|
-
import type
|
|
8
|
+
import { type SlideDirection } from "./SlideContainer.js";
|
|
9
9
|
|
|
10
10
|
/** @since 6.0.0 */
|
|
11
11
|
export interface CarouselSlideState {
|
package/src/tree/Tree.tsx
CHANGED
|
@@ -270,6 +270,7 @@ export function Tree<T extends TreeItemNode>(
|
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
const { metadataLookup, movementContext, movementProps } = useTreeMovement({
|
|
273
|
+
ref: treeRef,
|
|
273
274
|
onClick,
|
|
274
275
|
onFocus,
|
|
275
276
|
onKeyDown,
|
|
@@ -305,7 +306,6 @@ export function Tree<T extends TreeItemNode>(
|
|
|
305
306
|
{...remaining}
|
|
306
307
|
{...movementProps}
|
|
307
308
|
id={treeId}
|
|
308
|
-
ref={treeRef}
|
|
309
309
|
role="tree"
|
|
310
310
|
tabIndex={0}
|
|
311
311
|
className={tree({ className })}
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
FocusEventHandler,
|
|
5
5
|
KeyboardEventHandler,
|
|
6
6
|
MouseEventHandler,
|
|
7
|
+
Ref,
|
|
7
8
|
} from "react";
|
|
8
9
|
import { useRef } from "react";
|
|
9
10
|
|
|
@@ -59,6 +60,7 @@ const getVisibleTreeItems = (
|
|
|
59
60
|
* @internal
|
|
60
61
|
*/
|
|
61
62
|
interface TreeMovementOptions<T extends TreeItemNode> extends TreeExpansion {
|
|
63
|
+
ref?: Ref<HTMLUListElement>;
|
|
62
64
|
data: TreeData<T>;
|
|
63
65
|
onClick: MouseEventHandler<HTMLUListElement> | undefined;
|
|
64
66
|
onFocus: FocusEventHandler<HTMLUListElement> | undefined;
|
|
@@ -88,6 +90,7 @@ export function useTreeMovement<T extends TreeItemNode>(
|
|
|
88
90
|
options: TreeMovementOptions<T>
|
|
89
91
|
): TreeMovement {
|
|
90
92
|
const {
|
|
93
|
+
ref,
|
|
91
94
|
onClick,
|
|
92
95
|
onFocus,
|
|
93
96
|
onKeyDown,
|
|
@@ -106,6 +109,7 @@ export function useTreeMovement<T extends TreeItemNode>(
|
|
|
106
109
|
itemToElement: {},
|
|
107
110
|
});
|
|
108
111
|
const movement = useKeyboardMovementProvider({
|
|
112
|
+
ref,
|
|
109
113
|
onClick,
|
|
110
114
|
onFocus,
|
|
111
115
|
onKeyDown,
|
package/src/types.ts
CHANGED
|
@@ -227,6 +227,22 @@ export interface ElementSize {
|
|
|
227
227
|
width: number;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
/**
|
|
231
|
+
* @since 6.3.0
|
|
232
|
+
*/
|
|
233
|
+
export interface Point {
|
|
234
|
+
x: number;
|
|
235
|
+
y: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @since 6.3.0
|
|
240
|
+
*/
|
|
241
|
+
export interface MinMaxRange {
|
|
242
|
+
min: number;
|
|
243
|
+
max: number;
|
|
244
|
+
}
|
|
245
|
+
|
|
230
246
|
/**
|
|
231
247
|
* @since 6.2.0
|
|
232
248
|
*/
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import { type MinMaxRange } from "../types.js";
|
|
1
2
|
import { getRangeSteps } from "./getRangeSteps.js";
|
|
2
3
|
import { nearest } from "./nearest.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @since 6.0.0
|
|
6
7
|
*/
|
|
7
|
-
export interface GetMiddleOfRangeOptions {
|
|
8
|
-
min: number;
|
|
9
|
-
max: number;
|
|
8
|
+
export interface GetMiddleOfRangeOptions extends MinMaxRange {
|
|
10
9
|
step: number;
|
|
11
10
|
}
|
|
12
11
|
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export interface GetPercentageOptions {
|
|
3
|
-
/**
|
|
4
|
-
* The min value allowed.
|
|
5
|
-
*/
|
|
6
|
-
min: number;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The max value allowed.
|
|
10
|
-
*/
|
|
11
|
-
max: number;
|
|
1
|
+
import { type MinMaxRange } from "../types.js";
|
|
12
2
|
|
|
3
|
+
/** @since 4.0.1 */
|
|
4
|
+
export interface GetPercentageOptions extends MinMaxRange {
|
|
13
5
|
/**
|
|
14
6
|
* The current value
|
|
15
7
|
*/
|
package/src/utils/nearest.ts
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Point } from "../types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @since 6.3.0
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export const radiansToDegrees = (radians: number): number =>
|
|
8
|
+
(radians * 180) / Math.PI;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @since 6.3.0
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export const degreesToRadians = (degrees: number): number =>
|
|
15
|
+
(degrees * Math.PI) / 180;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @since 6.3.0
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
interface IsPointInCircleOptions {
|
|
22
|
+
point: Point;
|
|
23
|
+
center: Point;
|
|
24
|
+
radius: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @since 6.3.0
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export function isPointInCircle(options: IsPointInCircleOptions): boolean {
|
|
32
|
+
const { point, center, radius } = options;
|
|
33
|
+
|
|
34
|
+
const distance = (center.x - point.x) ** 2 + (center.y - point.y) ** 2;
|
|
35
|
+
return distance <= radius ** 2;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
* @since 6.3.0
|
|
41
|
+
*/
|
|
42
|
+
export function calcHypotenuse(point: Point): number {
|
|
43
|
+
const { x, y } = point;
|
|
44
|
+
|
|
45
|
+
return Math.sqrt(x * x + y * y);
|
|
46
|
+
}
|
|
@@ -42,8 +42,9 @@ export type WindowSplitterOptions<E extends HTMLElement = HTMLButtonElement> =
|
|
|
42
42
|
/**
|
|
43
43
|
* @since 6.0.0
|
|
44
44
|
*/
|
|
45
|
-
export interface WindowSplitterWidgetProps<
|
|
46
|
-
extends
|
|
45
|
+
export interface WindowSplitterWidgetProps<
|
|
46
|
+
E extends HTMLElement = HTMLButtonElement,
|
|
47
|
+
> extends Required<DraggableMouseEventHandlers<E>>,
|
|
47
48
|
Required<DraggableKeyboardEventHandlers<E>> {
|
|
48
49
|
"aria-orientation": "vertical" | undefined;
|
|
49
50
|
"aria-valuenow": number;
|