@octanejs/floating-ui 0.1.9 → 0.1.10
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/package.json +3 -3
- package/src/Composite.ts +118 -20
- package/src/FloatingArrow.ts +61 -4
- package/src/FloatingFocusManager.ts +127 -26
- package/src/FloatingList.ts +58 -13
- package/src/FloatingOverlay.ts +26 -3
- package/src/FloatingPortal.ts +100 -23
- package/src/context.ts +43 -15
- package/src/delayGroup.ts +66 -8
- package/src/index.ts +108 -0
- package/src/pubsub.ts +3 -1
- package/src/safePolygon.ts +13 -4
- package/src/transitions.ts +76 -10
- package/src/tree.ts +53 -11
- package/src/types.ts +337 -0
- package/src/useClick.ts +63 -13
- package/src/useClientPoint.ts +50 -10
- package/src/useDismiss.ts +86 -12
- package/src/useFloating.ts +46 -14
- package/src/useFocus.ts +33 -7
- package/src/useHover.ts +80 -19
- package/src/useId.ts +1 -1
- package/src/useInteractions.ts +12 -3
- package/src/useListNavigation.ts +162 -8
- package/src/useMergeRefs.ts +6 -1
- package/src/useRole.ts +41 -12
- package/src/useTypeahead.ts +75 -10
- package/src/utils/index.ts +159 -62
package/src/utils/index.ts
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
// Ported from @floating-ui/react/utils. The DOM/grid/tabbable helpers are
|
|
2
|
-
// framework-agnostic and copied ~verbatim
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// framework-agnostic and copied ~verbatim (signatures mirror upstream's
|
|
3
|
+
// `@floating-ui/react/utils` typings, with React event/ref types replaced by the
|
|
4
|
+
// native-DOM/octane analogs); the three React hooks (useLatestRef, useEffectEvent,
|
|
5
|
+
// useModernLayoutEffect) become octane hooks that take an explicit slot (forwarded
|
|
6
|
+
// by their callers via subSlot — see ../internal).
|
|
5
7
|
import { isShadowRoot, isHTMLElement } from '@floating-ui/utils/dom';
|
|
6
8
|
import { floor } from '@floating-ui/utils';
|
|
7
|
-
import { tabbable } from 'tabbable';
|
|
9
|
+
import { tabbable, type FocusableElement } from 'tabbable';
|
|
8
10
|
import { useCallback, useLayoutEffect, useRef } from 'octane';
|
|
11
|
+
import type { Octane } from 'octane/jsx-runtime';
|
|
12
|
+
import type { Dimensions } from '@floating-ui/dom';
|
|
9
13
|
|
|
10
14
|
import { subSlot } from '../internal';
|
|
15
|
+
import type { Delay, FloatingNodeType, MutableRefObject, ReferenceType } from '../types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The OBJECT form of octane's `style` prop — the port's analog of
|
|
19
|
+
* `React.CSSProperties` (octane's `style` additionally accepts a plain string;
|
|
20
|
+
* helpers that merge/inspect style objects require this form).
|
|
21
|
+
*/
|
|
22
|
+
export type CSSProperties = Exclude<
|
|
23
|
+
Octane.HTMLAttributes<HTMLElement>['style'],
|
|
24
|
+
string | undefined
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
/** Which list items are disabled (mirrors upstream's unexported `DisabledIndices`). */
|
|
28
|
+
export type DisabledIndices = Array<number> | ((index: number) => boolean);
|
|
11
29
|
|
|
12
30
|
export function getPlatform(): string {
|
|
13
31
|
const uaData = (navigator as any).userAgentData;
|
|
@@ -43,7 +61,7 @@ export function isMacSafari(): boolean {
|
|
|
43
61
|
export function createAttribute(name: string): string {
|
|
44
62
|
return 'data-floating-ui-' + name;
|
|
45
63
|
}
|
|
46
|
-
export function clearTimeoutIfSet(timeoutRef:
|
|
64
|
+
export function clearTimeoutIfSet(timeoutRef: MutableRefObject<number>): void {
|
|
47
65
|
if (timeoutRef.current !== -1) {
|
|
48
66
|
clearTimeout(timeoutRef.current);
|
|
49
67
|
timeoutRef.current = -1;
|
|
@@ -85,36 +103,39 @@ export function contains(parent?: Element | null, child?: Element | null): boole
|
|
|
85
103
|
}
|
|
86
104
|
return false;
|
|
87
105
|
}
|
|
88
|
-
export function getTarget(event:
|
|
106
|
+
export function getTarget(event: Event): EventTarget | null {
|
|
89
107
|
if ('composedPath' in event) {
|
|
90
108
|
return event.composedPath()[0];
|
|
91
109
|
}
|
|
92
|
-
|
|
110
|
+
// Old-browser fallback: `lib.dom` types every Event with `composedPath`, so
|
|
111
|
+
// the false branch narrows `event` to `never` — widen for the legacy read.
|
|
112
|
+
return (event as Event).target;
|
|
93
113
|
}
|
|
94
|
-
export function isEventTargetWithin(event:
|
|
114
|
+
export function isEventTargetWithin(event: Event, node: Node | null | undefined): boolean {
|
|
95
115
|
if (node == null) {
|
|
96
116
|
return false;
|
|
97
117
|
}
|
|
98
118
|
if ('composedPath' in event) {
|
|
99
119
|
return event.composedPath().includes(node);
|
|
100
120
|
}
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
// Old-browser fallback (see getTarget).
|
|
122
|
+
const e = event as Event;
|
|
123
|
+
return e.target != null && node.contains(e.target as Node);
|
|
103
124
|
}
|
|
104
125
|
export function isRootElement(element: Element): boolean {
|
|
105
126
|
return element.matches('html,body');
|
|
106
127
|
}
|
|
107
|
-
export function getDocument(node
|
|
128
|
+
export function getDocument(node?: Element | null): Document {
|
|
108
129
|
return node?.ownerDocument || document;
|
|
109
130
|
}
|
|
110
|
-
export function isTypeableElement(element:
|
|
131
|
+
export function isTypeableElement(element: unknown): boolean {
|
|
111
132
|
return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
|
|
112
133
|
}
|
|
113
|
-
export function isTypeableCombobox(element:
|
|
134
|
+
export function isTypeableCombobox(element: Element | null): boolean {
|
|
114
135
|
if (!element) return false;
|
|
115
136
|
return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
|
|
116
137
|
}
|
|
117
|
-
export function matchesFocusVisible(element:
|
|
138
|
+
export function matchesFocusVisible(element: Element | null): boolean {
|
|
118
139
|
if (!element || isJSDOM()) return true;
|
|
119
140
|
try {
|
|
120
141
|
return element.matches(':focus-visible');
|
|
@@ -122,16 +143,23 @@ export function matchesFocusVisible(element: any): boolean {
|
|
|
122
143
|
return true;
|
|
123
144
|
}
|
|
124
145
|
}
|
|
125
|
-
export function getFloatingFocusElement(
|
|
146
|
+
export function getFloatingFocusElement(
|
|
147
|
+
floatingElement: HTMLElement | null | undefined,
|
|
148
|
+
): HTMLElement | null {
|
|
126
149
|
if (!floatingElement) {
|
|
127
150
|
return null;
|
|
128
151
|
}
|
|
129
152
|
return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE)
|
|
130
153
|
? floatingElement
|
|
131
|
-
: floatingElement.querySelector('[' + FOCUSABLE_ATTRIBUTE + ']') ||
|
|
154
|
+
: floatingElement.querySelector<HTMLElement>('[' + FOCUSABLE_ATTRIBUTE + ']') ||
|
|
155
|
+
floatingElement;
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
export function getNodeChildren
|
|
158
|
+
export function getNodeChildren<RT extends ReferenceType = ReferenceType>(
|
|
159
|
+
nodes: Array<FloatingNodeType<RT>>,
|
|
160
|
+
id: string | undefined,
|
|
161
|
+
onlyOpenChildren = true,
|
|
162
|
+
): Array<FloatingNodeType<RT>> {
|
|
135
163
|
const directChildren = nodes.filter(
|
|
136
164
|
(node) => node.parentId === id && (!onlyOpenChildren || node.context?.open),
|
|
137
165
|
);
|
|
@@ -140,10 +168,13 @@ export function getNodeChildren(nodes: any[], id: any, onlyOpenChildren = true):
|
|
|
140
168
|
...getNodeChildren(nodes, child.id, onlyOpenChildren),
|
|
141
169
|
]);
|
|
142
170
|
}
|
|
143
|
-
export function getDeepestNode
|
|
144
|
-
|
|
171
|
+
export function getDeepestNode<RT extends ReferenceType = ReferenceType>(
|
|
172
|
+
nodes: Array<FloatingNodeType<RT>>,
|
|
173
|
+
id: string | undefined,
|
|
174
|
+
): FloatingNodeType<RT> | undefined {
|
|
175
|
+
let deepestNodeId: string | undefined;
|
|
145
176
|
let maxDepth = -1;
|
|
146
|
-
function findDeepest(nodeId:
|
|
177
|
+
function findDeepest(nodeId: string | undefined, depth: number) {
|
|
147
178
|
if (depth > maxDepth) {
|
|
148
179
|
deepestNodeId = nodeId;
|
|
149
180
|
maxDepth = depth;
|
|
@@ -156,8 +187,11 @@ export function getDeepestNode(nodes: any[], id: any): any {
|
|
|
156
187
|
findDeepest(id, 0);
|
|
157
188
|
return nodes.find((node) => node.id === deepestNodeId);
|
|
158
189
|
}
|
|
159
|
-
export function getNodeAncestors
|
|
160
|
-
|
|
190
|
+
export function getNodeAncestors<RT extends ReferenceType = ReferenceType>(
|
|
191
|
+
nodes: Array<FloatingNodeType<RT>>,
|
|
192
|
+
id: string | undefined,
|
|
193
|
+
): Array<FloatingNodeType<RT>> {
|
|
194
|
+
let allAncestors: Array<FloatingNodeType<RT>> = [];
|
|
161
195
|
let currentParentId = nodes.find((node) => node.id === id)?.parentId;
|
|
162
196
|
while (currentParentId) {
|
|
163
197
|
const currentNode = nodes.find((node) => node.id === currentParentId);
|
|
@@ -169,7 +203,7 @@ export function getNodeAncestors(nodes: any[], id: any): any[] {
|
|
|
169
203
|
return allAncestors;
|
|
170
204
|
}
|
|
171
205
|
|
|
172
|
-
export function stopEvent(event:
|
|
206
|
+
export function stopEvent(event: Event): void {
|
|
173
207
|
event.preventDefault();
|
|
174
208
|
event.stopPropagation();
|
|
175
209
|
}
|
|
@@ -177,16 +211,16 @@ export function isReactEvent(event: any): boolean {
|
|
|
177
211
|
return 'nativeEvent' in event;
|
|
178
212
|
}
|
|
179
213
|
|
|
180
|
-
export function isVirtualClick(event:
|
|
181
|
-
if (event.mozInputSource === 0 && event.isTrusted) {
|
|
214
|
+
export function isVirtualClick(event: MouseEvent | PointerEvent): boolean {
|
|
215
|
+
if ((event as any).mozInputSource === 0 && event.isTrusted) {
|
|
182
216
|
return true;
|
|
183
217
|
}
|
|
184
|
-
if (isAndroid() && event.pointerType) {
|
|
218
|
+
if (isAndroid() && (event as PointerEvent).pointerType) {
|
|
185
219
|
return event.type === 'click' && event.buttons === 1;
|
|
186
220
|
}
|
|
187
|
-
return event.detail === 0 && !event.pointerType;
|
|
221
|
+
return event.detail === 0 && !(event as PointerEvent).pointerType;
|
|
188
222
|
}
|
|
189
|
-
export function isVirtualPointerEvent(event:
|
|
223
|
+
export function isVirtualPointerEvent(event: PointerEvent): boolean {
|
|
190
224
|
if (isJSDOM()) return false;
|
|
191
225
|
return (
|
|
192
226
|
(!isAndroid() && event.width === 0 && event.height === 0) ||
|
|
@@ -203,15 +237,19 @@ export function isVirtualPointerEvent(event: any): boolean {
|
|
|
203
237
|
event.pointerType === 'touch')
|
|
204
238
|
);
|
|
205
239
|
}
|
|
206
|
-
export function isMouseLikePointerType(pointerType:
|
|
207
|
-
const values:
|
|
240
|
+
export function isMouseLikePointerType(pointerType: string | undefined, strict?: boolean): boolean {
|
|
241
|
+
const values: Array<string | undefined> = ['mouse', 'pen'];
|
|
208
242
|
if (!strict) {
|
|
209
243
|
values.push('', undefined);
|
|
210
244
|
}
|
|
211
245
|
return values.includes(pointerType);
|
|
212
246
|
}
|
|
213
247
|
|
|
214
|
-
export function getDelay(
|
|
248
|
+
export function getDelay(
|
|
249
|
+
value: Delay | ((...args: any[]) => Delay) | undefined,
|
|
250
|
+
prop: 'open' | 'close',
|
|
251
|
+
pointerType?: string,
|
|
252
|
+
): number | undefined {
|
|
215
253
|
if (pointerType && !isMouseLikePointerType(pointerType)) {
|
|
216
254
|
return 0;
|
|
217
255
|
}
|
|
@@ -232,8 +270,13 @@ export function getDelay(value: any, prop: string, pointerType?: any): any {
|
|
|
232
270
|
export function camelCaseToKebabCase(str: string): string {
|
|
233
271
|
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase());
|
|
234
272
|
}
|
|
235
|
-
export function execWithArgsOrReturn
|
|
236
|
-
|
|
273
|
+
export function execWithArgsOrReturn<Value, SidePlacement>(
|
|
274
|
+
valueOrFn: Value | ((args: SidePlacement) => Value),
|
|
275
|
+
args: SidePlacement,
|
|
276
|
+
): Value {
|
|
277
|
+
return typeof valueOrFn === 'function'
|
|
278
|
+
? (valueOrFn as (args: SidePlacement) => Value)(args)
|
|
279
|
+
: valueOrFn;
|
|
237
280
|
}
|
|
238
281
|
|
|
239
282
|
// Fork of `fast-deep-equal` (from @floating-ui/react-dom) — compares functions by
|
|
@@ -313,7 +356,7 @@ export function useModernLayoutEffect(
|
|
|
313
356
|
}
|
|
314
357
|
}
|
|
315
358
|
|
|
316
|
-
export function useLatestRef<T>(value: T, slot: symbol | undefined):
|
|
359
|
+
export function useLatestRef<T>(value: T, slot: symbol | undefined): MutableRefObject<T> {
|
|
317
360
|
const ref = useRef(value, subSlot(slot, 'lr:ref'));
|
|
318
361
|
useModernLayoutEffect(
|
|
319
362
|
() => {
|
|
@@ -352,20 +395,37 @@ export function useEffectEvent<T extends (...args: any[]) => any>(
|
|
|
352
395
|
export function isDifferentGridRow(index: number, cols: number, prevRow: number): boolean {
|
|
353
396
|
return Math.floor(index / cols) !== prevRow;
|
|
354
397
|
}
|
|
355
|
-
export function isIndexOutOfListBounds(
|
|
398
|
+
export function isIndexOutOfListBounds(
|
|
399
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
400
|
+
index: number,
|
|
401
|
+
): boolean {
|
|
356
402
|
return index < 0 || index >= listRef.current.length;
|
|
357
403
|
}
|
|
358
|
-
export function getMinListIndex(
|
|
404
|
+
export function getMinListIndex(
|
|
405
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
406
|
+
disabledIndices: DisabledIndices | undefined,
|
|
407
|
+
): number {
|
|
359
408
|
return findNonDisabledListIndex(listRef, { disabledIndices });
|
|
360
409
|
}
|
|
361
|
-
export function getMaxListIndex(
|
|
410
|
+
export function getMaxListIndex(
|
|
411
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
412
|
+
disabledIndices: DisabledIndices | undefined,
|
|
413
|
+
): number {
|
|
362
414
|
return findNonDisabledListIndex(listRef, {
|
|
363
415
|
decrement: true,
|
|
364
416
|
startingIndex: listRef.current.length,
|
|
365
417
|
disabledIndices,
|
|
366
418
|
});
|
|
367
419
|
}
|
|
368
|
-
export function findNonDisabledListIndex(
|
|
420
|
+
export function findNonDisabledListIndex(
|
|
421
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
422
|
+
_temp?: {
|
|
423
|
+
startingIndex?: number;
|
|
424
|
+
decrement?: boolean;
|
|
425
|
+
disabledIndices?: DisabledIndices;
|
|
426
|
+
amount?: number;
|
|
427
|
+
},
|
|
428
|
+
): number {
|
|
369
429
|
const {
|
|
370
430
|
startingIndex = -1,
|
|
371
431
|
decrement = false,
|
|
@@ -382,7 +442,21 @@ export function findNonDisabledListIndex(listRef: any, _temp?: any): number {
|
|
|
382
442
|
);
|
|
383
443
|
return index;
|
|
384
444
|
}
|
|
385
|
-
export function getGridNavigatedIndex(
|
|
445
|
+
export function getGridNavigatedIndex(
|
|
446
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
447
|
+
_ref: {
|
|
448
|
+
event: KeyboardEvent;
|
|
449
|
+
orientation: 'horizontal' | 'vertical' | 'both';
|
|
450
|
+
loop: boolean;
|
|
451
|
+
rtl: boolean;
|
|
452
|
+
cols: number;
|
|
453
|
+
disabledIndices: DisabledIndices | undefined;
|
|
454
|
+
minIndex: number;
|
|
455
|
+
maxIndex: number;
|
|
456
|
+
prevIndex: number;
|
|
457
|
+
stopEvent?: boolean;
|
|
458
|
+
},
|
|
459
|
+
): number {
|
|
386
460
|
const {
|
|
387
461
|
event,
|
|
388
462
|
orientation,
|
|
@@ -513,8 +587,13 @@ export function getGridNavigatedIndex(listRef: any, _ref: any): number {
|
|
|
513
587
|
return nextIndex;
|
|
514
588
|
}
|
|
515
589
|
|
|
516
|
-
|
|
517
|
-
|
|
590
|
+
/** For each cell index, gets the item index that occupies that cell. */
|
|
591
|
+
export function createGridCellMap(
|
|
592
|
+
sizes: Dimensions[],
|
|
593
|
+
cols: number,
|
|
594
|
+
dense: boolean,
|
|
595
|
+
): Array<number | undefined> {
|
|
596
|
+
const cellMap: Array<number | undefined> = [];
|
|
518
597
|
let startIndex = 0;
|
|
519
598
|
sizes.forEach((_ref2, index) => {
|
|
520
599
|
const { width, height } = _ref2;
|
|
@@ -551,12 +630,13 @@ export function createGridCellMap(sizes: any[], cols: number, dense: boolean): a
|
|
|
551
630
|
});
|
|
552
631
|
return [...cellMap];
|
|
553
632
|
}
|
|
633
|
+
/** Gets cell index of an item's corner or -1 when index is -1. */
|
|
554
634
|
export function getGridCellIndexOfCorner(
|
|
555
635
|
index: number,
|
|
556
|
-
sizes:
|
|
557
|
-
cellMap:
|
|
636
|
+
sizes: Dimensions[],
|
|
637
|
+
cellMap: Array<number | undefined>,
|
|
558
638
|
cols: number,
|
|
559
|
-
corner:
|
|
639
|
+
corner: 'tl' | 'tr' | 'bl' | 'br',
|
|
560
640
|
): number {
|
|
561
641
|
if (index === -1) return -1;
|
|
562
642
|
const firstCellIndex = cellMap.indexOf(index);
|
|
@@ -579,10 +659,18 @@ export function getGridCellIndexOfCorner(
|
|
|
579
659
|
}
|
|
580
660
|
return -1;
|
|
581
661
|
}
|
|
582
|
-
|
|
662
|
+
/** Gets all cell indices that correspond to the specified indices. */
|
|
663
|
+
export function getGridCellIndices(
|
|
664
|
+
indices: Array<number | undefined>,
|
|
665
|
+
cellMap: Array<number | undefined>,
|
|
666
|
+
): number[] {
|
|
583
667
|
return cellMap.flatMap((index, cellIndex) => (indices.includes(index) ? [cellIndex] : []));
|
|
584
668
|
}
|
|
585
|
-
export function isListIndexDisabled(
|
|
669
|
+
export function isListIndexDisabled(
|
|
670
|
+
listRef: MutableRefObject<Array<HTMLElement | null>>,
|
|
671
|
+
index: number,
|
|
672
|
+
disabledIndices?: DisabledIndices,
|
|
673
|
+
): boolean {
|
|
586
674
|
if (typeof disabledIndices === 'function') {
|
|
587
675
|
return disabledIndices(index);
|
|
588
676
|
} else if (disabledIndices) {
|
|
@@ -596,14 +684,14 @@ export function isListIndexDisabled(listRef: any, index: number, disabledIndices
|
|
|
596
684
|
);
|
|
597
685
|
}
|
|
598
686
|
|
|
599
|
-
export const getTabbableOptions = ():
|
|
687
|
+
export const getTabbableOptions = (): { getShadowRoot: true; displayCheck: 'full' | 'none' } => ({
|
|
600
688
|
getShadowRoot: true,
|
|
601
689
|
displayCheck:
|
|
602
690
|
typeof ResizeObserver === 'function' && ResizeObserver.toString().includes('[native code]')
|
|
603
691
|
? 'full'
|
|
604
692
|
: 'none',
|
|
605
693
|
});
|
|
606
|
-
function getTabbableIn(container:
|
|
694
|
+
function getTabbableIn(container: HTMLElement, dir: 1 | -1): FocusableElement | undefined {
|
|
607
695
|
const list = tabbable(container, getTabbableOptions());
|
|
608
696
|
const len = list.length;
|
|
609
697
|
if (len === 0) return;
|
|
@@ -612,17 +700,26 @@ function getTabbableIn(container: any, dir: number): any {
|
|
|
612
700
|
const nextIndex = index === -1 ? (dir === 1 ? 0 : len - 1) : index + dir;
|
|
613
701
|
return list[nextIndex];
|
|
614
702
|
}
|
|
615
|
-
export function getNextTabbable(referenceElement:
|
|
616
|
-
return
|
|
703
|
+
export function getNextTabbable(referenceElement: Element | null): FocusableElement | null {
|
|
704
|
+
return (
|
|
705
|
+
getTabbableIn(getDocument(referenceElement).body, 1) ||
|
|
706
|
+
(referenceElement as FocusableElement | null)
|
|
707
|
+
);
|
|
617
708
|
}
|
|
618
|
-
export function getPreviousTabbable(referenceElement:
|
|
619
|
-
return
|
|
709
|
+
export function getPreviousTabbable(referenceElement: Element | null): FocusableElement | null {
|
|
710
|
+
return (
|
|
711
|
+
getTabbableIn(getDocument(referenceElement).body, -1) ||
|
|
712
|
+
(referenceElement as FocusableElement | null)
|
|
713
|
+
);
|
|
620
714
|
}
|
|
621
715
|
let rafId = 0;
|
|
622
|
-
export function enqueueFocus(
|
|
716
|
+
export function enqueueFocus(
|
|
717
|
+
el: Element | FocusableElement | null | undefined,
|
|
718
|
+
options: { preventScroll?: boolean; cancelPrevious?: boolean; sync?: boolean } = {},
|
|
719
|
+
): void {
|
|
623
720
|
const { preventScroll = false, cancelPrevious = true, sync = false } = options;
|
|
624
721
|
cancelPrevious && cancelAnimationFrame(rafId);
|
|
625
|
-
const exec = () => el?.focus({ preventScroll });
|
|
722
|
+
const exec = () => (el as FocusableElement | null | undefined)?.focus({ preventScroll });
|
|
626
723
|
if (sync) {
|
|
627
724
|
exec();
|
|
628
725
|
} else {
|
|
@@ -630,21 +727,21 @@ export function enqueueFocus(el: any, options: any = {}): void {
|
|
|
630
727
|
}
|
|
631
728
|
}
|
|
632
729
|
|
|
633
|
-
export function isOutsideEvent(event:
|
|
634
|
-
const containerElement = container || event.currentTarget;
|
|
635
|
-
const relatedTarget = event.relatedTarget;
|
|
730
|
+
export function isOutsideEvent(event: FocusEvent, container?: Element | null): boolean {
|
|
731
|
+
const containerElement = container || (event.currentTarget as Element | null);
|
|
732
|
+
const relatedTarget = event.relatedTarget as Element | null;
|
|
636
733
|
return !relatedTarget || !contains(containerElement, relatedTarget);
|
|
637
734
|
}
|
|
638
|
-
export function disableFocusInside(container:
|
|
735
|
+
export function disableFocusInside(container: HTMLElement): void {
|
|
639
736
|
const tabbableElements = tabbable(container, getTabbableOptions());
|
|
640
|
-
tabbableElements.forEach((element
|
|
737
|
+
tabbableElements.forEach((element) => {
|
|
641
738
|
element.dataset.tabindex = element.getAttribute('tabindex') || '';
|
|
642
739
|
element.setAttribute('tabindex', '-1');
|
|
643
740
|
});
|
|
644
741
|
}
|
|
645
|
-
export function enableFocusInside(container:
|
|
646
|
-
const elements = container.querySelectorAll('[data-tabindex]');
|
|
647
|
-
elements.forEach((element
|
|
742
|
+
export function enableFocusInside(container: HTMLElement): void {
|
|
743
|
+
const elements = container.querySelectorAll<HTMLElement>('[data-tabindex]');
|
|
744
|
+
elements.forEach((element) => {
|
|
648
745
|
const tabindex = element.dataset.tabindex;
|
|
649
746
|
delete element.dataset.tabindex;
|
|
650
747
|
if (tabindex) {
|