@react-aria/focus 3.19.1 → 3.20.1
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/FocusScope.main.js +34 -48
- package/dist/FocusScope.main.js.map +1 -1
- package/dist/FocusScope.mjs +36 -49
- package/dist/FocusScope.module.js +36 -49
- package/dist/FocusScope.module.js.map +1 -1
- package/dist/import.mjs +6 -4
- package/dist/main.js +13 -6
- package/dist/main.js.map +1 -1
- package/dist/module.js +6 -4
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +10 -28
- package/dist/types.d.ts.map +1 -1
- package/dist/virtualFocus.main.js +46 -0
- package/dist/virtualFocus.main.js.map +1 -0
- package/dist/virtualFocus.mjs +38 -0
- package/dist/virtualFocus.module.js +38 -0
- package/dist/virtualFocus.module.js.map +1 -0
- package/package.json +5 -5
- package/src/FocusScope.tsx +60 -63
- package/src/index.ts +6 -4
- package/src/virtualFocus.ts +33 -0
- package/dist/focusSafely.main.js +0 -39
- package/dist/focusSafely.main.js.map +0 -1
- package/dist/focusSafely.mjs +0 -34
- package/dist/focusSafely.module.js +0 -34
- package/dist/focusSafely.module.js.map +0 -1
- package/dist/useFocusable.main.js +0 -72
- package/dist/useFocusable.main.js.map +0 -1
- package/dist/useFocusable.mjs +0 -62
- package/dist/useFocusable.module.js +0 -62
- package/dist/useFocusable.module.js.map +0 -1
- package/src/focusSafely.ts +0 -39
- package/src/useFocusable.tsx +0 -94
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {getOwnerDocument as $hpDQO$getOwnerDocument, getActiveElement as $hpDQO$getActiveElement} from "@react-aria/utils";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function $55f9b1ae81f22853$export$76e4e37e5339496d(to) {
|
|
5
|
+
let from = $55f9b1ae81f22853$export$759df0d867455a91((0, $hpDQO$getOwnerDocument)(to));
|
|
6
|
+
if (from !== to) {
|
|
7
|
+
if (from) $55f9b1ae81f22853$export$6c5dc7e81d2cc29a(from, to);
|
|
8
|
+
if (to) $55f9b1ae81f22853$export$2b35b76d2e30e129(to, from);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function $55f9b1ae81f22853$export$6c5dc7e81d2cc29a(from, to) {
|
|
12
|
+
from.dispatchEvent(new FocusEvent('blur', {
|
|
13
|
+
relatedTarget: to
|
|
14
|
+
}));
|
|
15
|
+
from.dispatchEvent(new FocusEvent('focusout', {
|
|
16
|
+
bubbles: true,
|
|
17
|
+
relatedTarget: to
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
function $55f9b1ae81f22853$export$2b35b76d2e30e129(to, from) {
|
|
21
|
+
to.dispatchEvent(new FocusEvent('focus', {
|
|
22
|
+
relatedTarget: from
|
|
23
|
+
}));
|
|
24
|
+
to.dispatchEvent(new FocusEvent('focusin', {
|
|
25
|
+
bubbles: true,
|
|
26
|
+
relatedTarget: from
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
function $55f9b1ae81f22853$export$759df0d867455a91(document) {
|
|
30
|
+
let activeElement = (0, $hpDQO$getActiveElement)(document);
|
|
31
|
+
let activeDescendant = activeElement === null || activeElement === void 0 ? void 0 : activeElement.getAttribute('aria-activedescendant');
|
|
32
|
+
if (activeDescendant) return document.getElementById(activeDescendant) || activeElement;
|
|
33
|
+
return activeElement;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export {$55f9b1ae81f22853$export$76e4e37e5339496d as moveVirtualFocus, $55f9b1ae81f22853$export$759df0d867455a91 as getVirtuallyFocusedElement, $55f9b1ae81f22853$export$6c5dc7e81d2cc29a as dispatchVirtualBlur, $55f9b1ae81f22853$export$2b35b76d2e30e129 as dispatchVirtualFocus};
|
|
38
|
+
//# sourceMappingURL=virtualFocus.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;AAEO,SAAS,0CAAiB,EAAkB;IACjD,IAAI,OAAO,0CAA2B,CAAA,GAAA,uBAAe,EAAE;IACvD,IAAI,SAAS,IAAI;QACf,IAAI,MACF,0CAAoB,MAAM;QAE5B,IAAI,IACF,0CAAqB,IAAI;IAE7B;AACF;AAEO,SAAS,0CAAoB,IAAa,EAAE,EAAkB;IACnE,KAAK,aAAa,CAAC,IAAI,WAAW,QAAQ;QAAC,eAAe;IAAE;IAC5D,KAAK,aAAa,CAAC,IAAI,WAAW,YAAY;QAAC,SAAS;QAAM,eAAe;IAAE;AACjF;AAEO,SAAS,0CAAqB,EAAW,EAAE,IAAoB;IACpE,GAAG,aAAa,CAAC,IAAI,WAAW,SAAS;QAAC,eAAe;IAAI;IAC7D,GAAG,aAAa,CAAC,IAAI,WAAW,WAAW;QAAC,SAAS;QAAM,eAAe;IAAI;AAChF;AAEO,SAAS,0CAA2B,QAAkB;IAC3D,IAAI,gBAAgB,CAAA,GAAA,uBAAe,EAAE;IACrC,IAAI,mBAAmB,0BAAA,oCAAA,cAAe,YAAY,CAAC;IACnD,IAAI,kBACF,OAAO,SAAS,cAAc,CAAC,qBAAqB;IAGtD,OAAO;AACT","sources":["packages/@react-aria/focus/src/virtualFocus.ts"],"sourcesContent":["import {getActiveElement, getOwnerDocument} from '@react-aria/utils';\n\nexport function moveVirtualFocus(to: Element | null) {\n let from = getVirtuallyFocusedElement(getOwnerDocument(to));\n if (from !== to) {\n if (from) {\n dispatchVirtualBlur(from, to);\n }\n if (to) {\n dispatchVirtualFocus(to, from);\n }\n }\n}\n\nexport function dispatchVirtualBlur(from: Element, to: Element | null) {\n from.dispatchEvent(new FocusEvent('blur', {relatedTarget: to}));\n from.dispatchEvent(new FocusEvent('focusout', {bubbles: true, relatedTarget: to}));\n}\n\nexport function dispatchVirtualFocus(to: Element, from: Element | null) {\n to.dispatchEvent(new FocusEvent('focus', {relatedTarget: from}));\n to.dispatchEvent(new FocusEvent('focusin', {bubbles: true, relatedTarget: from}));\n}\n\nexport function getVirtuallyFocusedElement(document: Document) {\n let activeElement = getActiveElement(document);\n let activeDescendant = activeElement?.getAttribute('aria-activedescendant');\n if (activeDescendant) {\n return document.getElementById(activeDescendant) || activeElement;\n }\n\n return activeElement;\n}\n"],"names":[],"version":3,"file":"virtualFocus.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/focus",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.1",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-aria/interactions": "^3.
|
|
26
|
-
"@react-aria/utils": "^3.
|
|
27
|
-
"@react-types/shared": "^3.
|
|
25
|
+
"@react-aria/interactions": "^3.24.1",
|
|
26
|
+
"@react-aria/utils": "^3.28.1",
|
|
27
|
+
"@react-types/shared": "^3.28.0",
|
|
28
28
|
"@swc/helpers": "^0.5.0",
|
|
29
29
|
"clsx": "^2.0.0"
|
|
30
30
|
},
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "9c4ebbc0c1972cc880febc29de995ca58caa3ba4"
|
|
39
39
|
}
|
package/src/FocusScope.tsx
CHANGED
|
@@ -10,10 +10,20 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import {
|
|
14
|
+
createShadowTreeWalker,
|
|
15
|
+
getActiveElement,
|
|
16
|
+
getEventTarget,
|
|
17
|
+
getOwnerDocument,
|
|
18
|
+
isAndroid,
|
|
19
|
+
isChrome,
|
|
20
|
+
isFocusable,
|
|
21
|
+
isTabbable,
|
|
22
|
+
ShadowTreeWalker,
|
|
23
|
+
useLayoutEffect
|
|
24
|
+
} from '@react-aria/utils';
|
|
13
25
|
import {FocusableElement, RefObject} from '@react-types/shared';
|
|
14
|
-
import {focusSafely} from '
|
|
15
|
-
import {getInteractionModality} from '@react-aria/interactions';
|
|
16
|
-
import {getOwnerDocument, isAndroid, isChrome, useLayoutEffect} from '@react-aria/utils';
|
|
26
|
+
import {focusSafely, getInteractionModality} from '@react-aria/interactions';
|
|
17
27
|
import {isElementVisible} from './isElementVisible';
|
|
18
28
|
import React, {ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
|
|
19
29
|
|
|
@@ -55,7 +65,7 @@ export interface FocusManager {
|
|
|
55
65
|
focusPrevious(opts?: FocusManagerOptions): FocusableElement | null,
|
|
56
66
|
/** Moves focus to the first focusable or tabbable element in the focus scope. */
|
|
57
67
|
focusFirst(opts?: FocusManagerOptions): FocusableElement | null,
|
|
58
|
-
|
|
68
|
+
/** Moves focus to the last focusable or tabbable element in the focus scope. */
|
|
59
69
|
focusLast(opts?: FocusManagerOptions): FocusableElement | null
|
|
60
70
|
}
|
|
61
71
|
|
|
@@ -144,7 +154,7 @@ export function FocusScope(props: FocusScopeProps) {
|
|
|
144
154
|
// This needs to be an effect so that activeScope is updated after the FocusScope tree is complete.
|
|
145
155
|
// It cannot be a useLayoutEffect because the parent of this node hasn't been attached in the tree yet.
|
|
146
156
|
useEffect(() => {
|
|
147
|
-
const activeElement = getOwnerDocument(scopeRef.current ? scopeRef.current[0] : undefined)
|
|
157
|
+
const activeElement = getActiveElement(getOwnerDocument(scopeRef.current ? scopeRef.current[0] : undefined));
|
|
148
158
|
let scope: TreeNode | null = null;
|
|
149
159
|
|
|
150
160
|
if (isElementInScope(activeElement, scopeRef.current)) {
|
|
@@ -208,7 +218,7 @@ function createFocusManagerForScope(scopeRef: React.RefObject<Element[] | null>)
|
|
|
208
218
|
focusNext(opts: FocusManagerOptions = {}) {
|
|
209
219
|
let scope = scopeRef.current!;
|
|
210
220
|
let {from, tabbable, wrap, accept} = opts;
|
|
211
|
-
let node = from || getOwnerDocument(scope[0])
|
|
221
|
+
let node = from || getActiveElement(getOwnerDocument(scope[0] ?? undefined))!;
|
|
212
222
|
let sentinel = scope[0].previousElementSibling!;
|
|
213
223
|
let scopeRoot = getScopeRoot(scope);
|
|
214
224
|
let walker = getFocusableTreeWalker(scopeRoot, {tabbable, accept}, scope);
|
|
@@ -226,11 +236,11 @@ function createFocusManagerForScope(scopeRef: React.RefObject<Element[] | null>)
|
|
|
226
236
|
focusPrevious(opts: FocusManagerOptions = {}) {
|
|
227
237
|
let scope = scopeRef.current!;
|
|
228
238
|
let {from, tabbable, wrap, accept} = opts;
|
|
229
|
-
let node = from || getOwnerDocument(scope[0])
|
|
239
|
+
let node = from || getActiveElement(getOwnerDocument(scope[0] ?? undefined))!;
|
|
230
240
|
let sentinel = scope[scope.length - 1].nextElementSibling!;
|
|
231
241
|
let scopeRoot = getScopeRoot(scope);
|
|
232
242
|
let walker = getFocusableTreeWalker(scopeRoot, {tabbable, accept}, scope);
|
|
233
|
-
walker.currentNode = isElementInScope(node, scope) ? node
|
|
243
|
+
walker.currentNode = isElementInScope(node, scope) ? node : sentinel;
|
|
234
244
|
let previousNode = walker.previousNode() as FocusableElement;
|
|
235
245
|
if (!previousNode && wrap) {
|
|
236
246
|
walker.currentNode = sentinel;
|
|
@@ -268,31 +278,6 @@ function createFocusManagerForScope(scopeRef: React.RefObject<Element[] | null>)
|
|
|
268
278
|
};
|
|
269
279
|
}
|
|
270
280
|
|
|
271
|
-
const focusableElements = [
|
|
272
|
-
'input:not([disabled]):not([type=hidden])',
|
|
273
|
-
'select:not([disabled])',
|
|
274
|
-
'textarea:not([disabled])',
|
|
275
|
-
'button:not([disabled])',
|
|
276
|
-
'a[href]',
|
|
277
|
-
'area[href]',
|
|
278
|
-
'summary',
|
|
279
|
-
'iframe',
|
|
280
|
-
'object',
|
|
281
|
-
'embed',
|
|
282
|
-
'audio[controls]',
|
|
283
|
-
'video[controls]',
|
|
284
|
-
'[contenteditable]:not([contenteditable^="false"])'
|
|
285
|
-
];
|
|
286
|
-
|
|
287
|
-
const FOCUSABLE_ELEMENT_SELECTOR = focusableElements.join(':not([hidden]),') + ',[tabindex]:not([disabled]):not([hidden])';
|
|
288
|
-
|
|
289
|
-
focusableElements.push('[tabindex]:not([tabindex="-1"]):not([disabled])');
|
|
290
|
-
const TABBABLE_ELEMENT_SELECTOR = focusableElements.join(':not([hidden]):not([tabindex="-1"]),');
|
|
291
|
-
|
|
292
|
-
export function isFocusable(element: HTMLElement) {
|
|
293
|
-
return element.matches(FOCUSABLE_ELEMENT_SELECTOR);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
281
|
function getScopeRoot(scope: Element[]) {
|
|
297
282
|
return scope[0].parentElement!;
|
|
298
283
|
}
|
|
@@ -333,7 +318,7 @@ function useFocusContainment(scopeRef: RefObject<Element[] | null>, contain?: bo
|
|
|
333
318
|
return;
|
|
334
319
|
}
|
|
335
320
|
|
|
336
|
-
let focusedElement = ownerDocument
|
|
321
|
+
let focusedElement = getActiveElement(ownerDocument);
|
|
337
322
|
let scope = scopeRef.current;
|
|
338
323
|
if (!scope || !isElementInScope(focusedElement, scope)) {
|
|
339
324
|
return;
|
|
@@ -357,13 +342,13 @@ function useFocusContainment(scopeRef: RefObject<Element[] | null>, contain?: bo
|
|
|
357
342
|
}
|
|
358
343
|
};
|
|
359
344
|
|
|
360
|
-
let onFocus = (e) => {
|
|
345
|
+
let onFocus: EventListener = (e) => {
|
|
361
346
|
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
362
347
|
// Moving out of the active scope to an ancestor is not allowed.
|
|
363
|
-
if ((!activeScope || isAncestorScope(activeScope, scopeRef)) && isElementInScope(e
|
|
348
|
+
if ((!activeScope || isAncestorScope(activeScope, scopeRef)) && isElementInScope(getEventTarget(e) as Element, scopeRef.current)) {
|
|
364
349
|
activeScope = scopeRef;
|
|
365
|
-
focusedNode.current = e
|
|
366
|
-
} else if (shouldContainFocus(scopeRef) && !isElementInChildScope(e
|
|
350
|
+
focusedNode.current = getEventTarget(e) as FocusableElement;
|
|
351
|
+
} else if (shouldContainFocus(scopeRef) && !isElementInChildScope(getEventTarget(e) as Element, scopeRef)) {
|
|
367
352
|
// If a focus event occurs outside the active scope (e.g. user tabs from browser location bar),
|
|
368
353
|
// restore focus to the previously focused node or the first tabbable element in the active scope.
|
|
369
354
|
if (focusedNode.current) {
|
|
@@ -372,11 +357,11 @@ function useFocusContainment(scopeRef: RefObject<Element[] | null>, contain?: bo
|
|
|
372
357
|
focusFirstInScope(activeScope.current);
|
|
373
358
|
}
|
|
374
359
|
} else if (shouldContainFocus(scopeRef)) {
|
|
375
|
-
focusedNode.current = e
|
|
360
|
+
focusedNode.current = getEventTarget(e) as FocusableElement;
|
|
376
361
|
}
|
|
377
362
|
};
|
|
378
363
|
|
|
379
|
-
let onBlur = (e) => {
|
|
364
|
+
let onBlur: EventListener = (e) => {
|
|
380
365
|
// Firefox doesn't shift focus back to the Dialog properly without this
|
|
381
366
|
if (raf.current) {
|
|
382
367
|
cancelAnimationFrame(raf.current);
|
|
@@ -389,10 +374,12 @@ function useFocusContainment(scopeRef: RefObject<Element[] | null>, contain?: bo
|
|
|
389
374
|
let shouldSkipFocusRestore = (modality === 'virtual' || modality === null) && isAndroid() && isChrome();
|
|
390
375
|
|
|
391
376
|
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
392
|
-
|
|
377
|
+
let activeElement = getActiveElement(ownerDocument);
|
|
378
|
+
if (!shouldSkipFocusRestore && activeElement && shouldContainFocus(scopeRef) && !isElementInChildScope(activeElement, scopeRef)) {
|
|
393
379
|
activeScope = scopeRef;
|
|
394
|
-
|
|
395
|
-
|
|
380
|
+
let target = getEventTarget(e) as FocusableElement;
|
|
381
|
+
if (target && target.isConnected) {
|
|
382
|
+
focusedNode.current = target;
|
|
396
383
|
focusedNode.current?.focus();
|
|
397
384
|
} else if (activeScope.current) {
|
|
398
385
|
focusFirstInScope(activeScope.current);
|
|
@@ -515,7 +502,7 @@ function useAutoFocus(scopeRef: RefObject<Element[] | null>, autoFocus?: boolean
|
|
|
515
502
|
if (autoFocusRef.current) {
|
|
516
503
|
activeScope = scopeRef;
|
|
517
504
|
const ownerDocument = getOwnerDocument(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
518
|
-
if (!isElementInScope(ownerDocument
|
|
505
|
+
if (!isElementInScope(getActiveElement(ownerDocument), activeScope.current) && scopeRef.current) {
|
|
519
506
|
focusFirstInScope(scopeRef.current);
|
|
520
507
|
}
|
|
521
508
|
}
|
|
@@ -535,7 +522,7 @@ function useActiveScopeTracker(scopeRef: RefObject<Element[] | null>, restore?:
|
|
|
535
522
|
const ownerDocument = getOwnerDocument(scope ? scope[0] : undefined);
|
|
536
523
|
|
|
537
524
|
let onFocus = (e) => {
|
|
538
|
-
let target = e
|
|
525
|
+
let target = getEventTarget(e) as Element;
|
|
539
526
|
if (isElementInScope(target, scopeRef.current)) {
|
|
540
527
|
activeScope = scopeRef;
|
|
541
528
|
} else if (!isElementInAnyScope(target)) {
|
|
@@ -568,7 +555,7 @@ function shouldRestoreFocus(scopeRef: ScopeRef) {
|
|
|
568
555
|
function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: boolean, contain?: boolean) {
|
|
569
556
|
// create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
|
|
570
557
|
// eslint-disable-next-line no-restricted-globals
|
|
571
|
-
const nodeToRestoreRef = useRef(typeof document !== 'undefined' ? getOwnerDocument(scopeRef.current ? scopeRef.current[0] : undefined)
|
|
558
|
+
const nodeToRestoreRef = useRef(typeof document !== 'undefined' ? getActiveElement(getOwnerDocument(scopeRef.current ? scopeRef.current[0] : undefined)) as FocusableElement : null);
|
|
572
559
|
|
|
573
560
|
// restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
|
|
574
561
|
// restoring-non-containing scopes should only care if they become active so they can perform the restore
|
|
@@ -583,7 +570,7 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
583
570
|
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
584
571
|
// Moving out of the active scope to an ancestor is not allowed.
|
|
585
572
|
if ((!activeScope || isAncestorScope(activeScope, scopeRef)) &&
|
|
586
|
-
|
|
573
|
+
isElementInScope(getActiveElement(ownerDocument), scopeRef.current)
|
|
587
574
|
) {
|
|
588
575
|
activeScope = scopeRef;
|
|
589
576
|
}
|
|
@@ -595,7 +582,7 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
595
582
|
ownerDocument.removeEventListener('focusin', onFocus, false);
|
|
596
583
|
scope?.forEach(element => element.removeEventListener('focusin', onFocus, false));
|
|
597
584
|
};
|
|
598
|
-
|
|
585
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
599
586
|
}, [scopeRef, contain]);
|
|
600
587
|
|
|
601
588
|
useLayoutEffect(() => {
|
|
@@ -631,7 +618,7 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
631
618
|
walker.currentNode = focusedElement;
|
|
632
619
|
let nextElement = (e.shiftKey ? walker.previousNode() : walker.nextNode()) as FocusableElement;
|
|
633
620
|
|
|
634
|
-
if (!nodeToRestore || !
|
|
621
|
+
if (!nodeToRestore || !nodeToRestore.isConnected || nodeToRestore === ownerDocument.body) {
|
|
635
622
|
nodeToRestore = undefined;
|
|
636
623
|
treeNode.nodeToRestore = undefined;
|
|
637
624
|
}
|
|
@@ -651,9 +638,9 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
651
638
|
if (nextElement) {
|
|
652
639
|
focusElement(nextElement, true);
|
|
653
640
|
} else {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
641
|
+
// If there is no next element and the nodeToRestore isn't within a FocusScope (i.e. we are leaving the top level focus scope)
|
|
642
|
+
// then move focus to the body.
|
|
643
|
+
// Otherwise restore focus to the nodeToRestore (e.g menu within a popover -> tabbing to close the menu should move focus to menu trigger)
|
|
657
644
|
if (!isElementInAnyScope(nodeToRestore)) {
|
|
658
645
|
focusedElement.blur();
|
|
659
646
|
} else {
|
|
@@ -664,12 +651,12 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
664
651
|
};
|
|
665
652
|
|
|
666
653
|
if (!contain) {
|
|
667
|
-
ownerDocument.addEventListener('keydown', onKeyDown, true);
|
|
654
|
+
ownerDocument.addEventListener('keydown', onKeyDown as EventListener, true);
|
|
668
655
|
}
|
|
669
656
|
|
|
670
657
|
return () => {
|
|
671
658
|
if (!contain) {
|
|
672
|
-
ownerDocument.removeEventListener('keydown', onKeyDown, true);
|
|
659
|
+
ownerDocument.removeEventListener('keydown', onKeyDown as EventListener, true);
|
|
673
660
|
}
|
|
674
661
|
};
|
|
675
662
|
}, [scopeRef, restoreFocus, contain]);
|
|
@@ -695,11 +682,12 @@ function useRestoreFocus(scopeRef: RefObject<Element[] | null>, restoreFocus?: b
|
|
|
695
682
|
let nodeToRestore = treeNode.nodeToRestore;
|
|
696
683
|
|
|
697
684
|
// if we already lost focus to the body and this was the active scope, then we should attempt to restore
|
|
685
|
+
let activeElement = getActiveElement(ownerDocument);
|
|
698
686
|
if (
|
|
699
687
|
restoreFocus
|
|
700
688
|
&& nodeToRestore
|
|
701
689
|
&& (
|
|
702
|
-
((
|
|
690
|
+
((activeElement && isElementInChildScope(activeElement, scopeRef)) || (activeElement === ownerDocument.body && shouldRestoreFocus(scopeRef)))
|
|
703
691
|
)
|
|
704
692
|
) {
|
|
705
693
|
// freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
|
|
@@ -748,10 +736,19 @@ function restoreFocusToElement(node: FocusableElement) {
|
|
|
748
736
|
* Create a [TreeWalker]{@link https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker}
|
|
749
737
|
* that matches all focusable/tabbable elements.
|
|
750
738
|
*/
|
|
751
|
-
export function getFocusableTreeWalker(root: Element, opts?: FocusManagerOptions, scope?: Element[]) {
|
|
752
|
-
let
|
|
753
|
-
|
|
754
|
-
|
|
739
|
+
export function getFocusableTreeWalker(root: Element, opts?: FocusManagerOptions, scope?: Element[]): ShadowTreeWalker | TreeWalker {
|
|
740
|
+
let filter = opts?.tabbable ? isTabbable : isFocusable;
|
|
741
|
+
|
|
742
|
+
// Ensure that root is an Element or fall back appropriately
|
|
743
|
+
let rootElement = root?.nodeType === Node.ELEMENT_NODE ? (root as Element) : null;
|
|
744
|
+
|
|
745
|
+
// Determine the document to use
|
|
746
|
+
let doc = getOwnerDocument(rootElement);
|
|
747
|
+
|
|
748
|
+
// Create a TreeWalker, ensuring the root is an Element or Document
|
|
749
|
+
let walker = createShadowTreeWalker(
|
|
750
|
+
doc,
|
|
751
|
+
root || doc,
|
|
755
752
|
NodeFilter.SHOW_ELEMENT,
|
|
756
753
|
{
|
|
757
754
|
acceptNode(node) {
|
|
@@ -760,7 +757,7 @@ export function getFocusableTreeWalker(root: Element, opts?: FocusManagerOptions
|
|
|
760
757
|
return NodeFilter.FILTER_REJECT;
|
|
761
758
|
}
|
|
762
759
|
|
|
763
|
-
if ((node as Element)
|
|
760
|
+
if (filter(node as Element)
|
|
764
761
|
&& isElementVisible(node as Element)
|
|
765
762
|
&& (!scope || isElementInScope(node as Element, scope))
|
|
766
763
|
&& (!opts?.accept || opts.accept(node as Element))
|
|
@@ -791,7 +788,7 @@ export function createFocusManager(ref: RefObject<Element | null>, defaultOption
|
|
|
791
788
|
return null;
|
|
792
789
|
}
|
|
793
790
|
let {from, tabbable = defaultOptions.tabbable, wrap = defaultOptions.wrap, accept = defaultOptions.accept} = opts;
|
|
794
|
-
let node = from || getOwnerDocument(root)
|
|
791
|
+
let node = from || getActiveElement(getOwnerDocument(root));
|
|
795
792
|
let walker = getFocusableTreeWalker(root, {tabbable, accept});
|
|
796
793
|
if (root.contains(node)) {
|
|
797
794
|
walker.currentNode = node!;
|
|
@@ -812,7 +809,7 @@ export function createFocusManager(ref: RefObject<Element | null>, defaultOption
|
|
|
812
809
|
return null;
|
|
813
810
|
}
|
|
814
811
|
let {from, tabbable = defaultOptions.tabbable, wrap = defaultOptions.wrap, accept = defaultOptions.accept} = opts;
|
|
815
|
-
let node = from || getOwnerDocument(root)
|
|
812
|
+
let node = from || getActiveElement(getOwnerDocument(root));
|
|
816
813
|
let walker = getFocusableTreeWalker(root, {tabbable, accept});
|
|
817
814
|
if (root.contains(node)) {
|
|
818
815
|
walker.currentNode = node!;
|
|
@@ -867,7 +864,7 @@ export function createFocusManager(ref: RefObject<Element | null>, defaultOption
|
|
|
867
864
|
};
|
|
868
865
|
}
|
|
869
866
|
|
|
870
|
-
function last(walker: TreeWalker) {
|
|
867
|
+
function last(walker: ShadowTreeWalker | TreeWalker) {
|
|
871
868
|
let next: FocusableElement | undefined = undefined;
|
|
872
869
|
let last: FocusableElement;
|
|
873
870
|
do {
|
package/src/index.ts
CHANGED
|
@@ -10,14 +10,16 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export {FocusScope, useFocusManager, getFocusableTreeWalker, createFocusManager, isElementInChildOfActiveScope
|
|
13
|
+
export {FocusScope, useFocusManager, getFocusableTreeWalker, createFocusManager, isElementInChildOfActiveScope} from './FocusScope';
|
|
14
14
|
export {FocusRing} from './FocusRing';
|
|
15
|
-
export {FocusableProvider, useFocusable} from './useFocusable';
|
|
16
15
|
export {useFocusRing} from './useFocusRing';
|
|
17
|
-
export {focusSafely} from './focusSafely';
|
|
18
16
|
export {useHasTabbableChild} from './useHasTabbableChild';
|
|
17
|
+
export {moveVirtualFocus, dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement} from './virtualFocus';
|
|
18
|
+
// For backward compatibility.
|
|
19
|
+
export {isFocusable} from '@react-aria/utils';
|
|
20
|
+
export {FocusableProvider, Focusable, useFocusable, focusSafely} from '@react-aria/interactions';
|
|
19
21
|
|
|
20
22
|
export type {FocusScopeProps, FocusManager, FocusManagerOptions} from './FocusScope';
|
|
21
23
|
export type {FocusRingProps} from './FocusRing';
|
|
22
|
-
export type {FocusableAria, FocusableOptions, FocusableProviderProps} from '
|
|
24
|
+
export type {FocusableAria, FocusableOptions, FocusableProviderProps} from '@react-aria/interactions';
|
|
23
25
|
export type {AriaFocusRingProps, FocusRingAria} from './useFocusRing';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {getActiveElement, getOwnerDocument} from '@react-aria/utils';
|
|
2
|
+
|
|
3
|
+
export function moveVirtualFocus(to: Element | null) {
|
|
4
|
+
let from = getVirtuallyFocusedElement(getOwnerDocument(to));
|
|
5
|
+
if (from !== to) {
|
|
6
|
+
if (from) {
|
|
7
|
+
dispatchVirtualBlur(from, to);
|
|
8
|
+
}
|
|
9
|
+
if (to) {
|
|
10
|
+
dispatchVirtualFocus(to, from);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function dispatchVirtualBlur(from: Element, to: Element | null) {
|
|
16
|
+
from.dispatchEvent(new FocusEvent('blur', {relatedTarget: to}));
|
|
17
|
+
from.dispatchEvent(new FocusEvent('focusout', {bubbles: true, relatedTarget: to}));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function dispatchVirtualFocus(to: Element, from: Element | null) {
|
|
21
|
+
to.dispatchEvent(new FocusEvent('focus', {relatedTarget: from}));
|
|
22
|
+
to.dispatchEvent(new FocusEvent('focusin', {bubbles: true, relatedTarget: from}));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getVirtuallyFocusedElement(document: Document) {
|
|
26
|
+
let activeElement = getActiveElement(document);
|
|
27
|
+
let activeDescendant = activeElement?.getAttribute('aria-activedescendant');
|
|
28
|
+
if (activeDescendant) {
|
|
29
|
+
return document.getElementById(activeDescendant) || activeElement;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return activeElement;
|
|
33
|
+
}
|
package/dist/focusSafely.main.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
var $cBYLt$reactariautils = require("@react-aria/utils");
|
|
2
|
-
var $cBYLt$reactariainteractions = require("@react-aria/interactions");
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function $parcel$export(e, n, v, s) {
|
|
6
|
-
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
$parcel$export(module.exports, "focusSafely", () => $1c7f9157d722357d$export$80f3e147d781571c);
|
|
10
|
-
/*
|
|
11
|
-
* Copyright 2020 Adobe. All rights reserved.
|
|
12
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the 'License');
|
|
13
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
14
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
-
*
|
|
16
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
17
|
-
* the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
18
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
19
|
-
* governing permissions and limitations under the License.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
function $1c7f9157d722357d$export$80f3e147d781571c(element) {
|
|
23
|
-
// If the user is interacting with a virtual cursor, e.g. screen reader, then
|
|
24
|
-
// wait until after any animated transitions that are currently occurring on
|
|
25
|
-
// the page before shifting focus. This avoids issues with VoiceOver on iOS
|
|
26
|
-
// causing the page to scroll when moving focus if the element is transitioning
|
|
27
|
-
// from off the screen.
|
|
28
|
-
const ownerDocument = (0, $cBYLt$reactariautils.getOwnerDocument)(element);
|
|
29
|
-
if ((0, $cBYLt$reactariainteractions.getInteractionModality)() === 'virtual') {
|
|
30
|
-
let lastFocusedElement = ownerDocument.activeElement;
|
|
31
|
-
(0, $cBYLt$reactariautils.runAfterTransition)(()=>{
|
|
32
|
-
// If focus did not move and the element is still in the document, focus it.
|
|
33
|
-
if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) (0, $cBYLt$reactariautils.focusWithoutScrolling)(element);
|
|
34
|
-
});
|
|
35
|
-
} else (0, $cBYLt$reactariautils.focusWithoutScrolling)(element);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//# sourceMappingURL=focusSafely.main.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAUM,SAAS,0CAAY,OAAyB;IACnD,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,+EAA+E;IAC/E,uBAAuB;IACvB,MAAM,gBAAgB,CAAA,GAAA,sCAAe,EAAE;IACvC,IAAI,CAAA,GAAA,mDAAqB,QAAQ,WAAW;QAC1C,IAAI,qBAAqB,cAAc,aAAa;QACpD,CAAA,GAAA,wCAAiB,EAAE;YACjB,4EAA4E;YAC5E,IAAI,cAAc,aAAa,KAAK,sBAAsB,QAAQ,WAAW,EAC3E,CAAA,GAAA,2CAAoB,EAAE;QAE1B;IACF,OACE,CAAA,GAAA,2CAAoB,EAAE;AAE1B","sources":["packages/@react-aria/focus/src/focusSafely.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {FocusableElement} from '@react-types/shared';\nimport {focusWithoutScrolling, getOwnerDocument, runAfterTransition} from '@react-aria/utils';\nimport {getInteractionModality} from '@react-aria/interactions';\n\n/**\n * A utility function that focuses an element while avoiding undesired side effects such\n * as page scrolling and screen reader issues with CSS transitions.\n */\nexport function focusSafely(element: FocusableElement) {\n // If the user is interacting with a virtual cursor, e.g. screen reader, then\n // wait until after any animated transitions that are currently occurring on\n // the page before shifting focus. This avoids issues with VoiceOver on iOS\n // causing the page to scroll when moving focus if the element is transitioning\n // from off the screen.\n const ownerDocument = getOwnerDocument(element);\n if (getInteractionModality() === 'virtual') {\n let lastFocusedElement = ownerDocument.activeElement;\n runAfterTransition(() => {\n // If focus did not move and the element is still in the document, focus it.\n if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) {\n focusWithoutScrolling(element);\n }\n });\n } else {\n focusWithoutScrolling(element);\n }\n}\n"],"names":[],"version":3,"file":"focusSafely.main.js.map"}
|
package/dist/focusSafely.mjs
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {getOwnerDocument as $jlOai$getOwnerDocument, runAfterTransition as $jlOai$runAfterTransition, focusWithoutScrolling as $jlOai$focusWithoutScrolling} from "@react-aria/utils";
|
|
2
|
-
import {getInteractionModality as $jlOai$getInteractionModality} from "@react-aria/interactions";
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
* Copyright 2020 Adobe. All rights reserved.
|
|
6
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the 'License');
|
|
7
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
8
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
11
|
-
* the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
12
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
13
|
-
* governing permissions and limitations under the License.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
function $6a99195332edec8b$export$80f3e147d781571c(element) {
|
|
17
|
-
// If the user is interacting with a virtual cursor, e.g. screen reader, then
|
|
18
|
-
// wait until after any animated transitions that are currently occurring on
|
|
19
|
-
// the page before shifting focus. This avoids issues with VoiceOver on iOS
|
|
20
|
-
// causing the page to scroll when moving focus if the element is transitioning
|
|
21
|
-
// from off the screen.
|
|
22
|
-
const ownerDocument = (0, $jlOai$getOwnerDocument)(element);
|
|
23
|
-
if ((0, $jlOai$getInteractionModality)() === 'virtual') {
|
|
24
|
-
let lastFocusedElement = ownerDocument.activeElement;
|
|
25
|
-
(0, $jlOai$runAfterTransition)(()=>{
|
|
26
|
-
// If focus did not move and the element is still in the document, focus it.
|
|
27
|
-
if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) (0, $jlOai$focusWithoutScrolling)(element);
|
|
28
|
-
});
|
|
29
|
-
} else (0, $jlOai$focusWithoutScrolling)(element);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export {$6a99195332edec8b$export$80f3e147d781571c as focusSafely};
|
|
34
|
-
//# sourceMappingURL=focusSafely.module.js.map
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {getOwnerDocument as $jlOai$getOwnerDocument, runAfterTransition as $jlOai$runAfterTransition, focusWithoutScrolling as $jlOai$focusWithoutScrolling} from "@react-aria/utils";
|
|
2
|
-
import {getInteractionModality as $jlOai$getInteractionModality} from "@react-aria/interactions";
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
* Copyright 2020 Adobe. All rights reserved.
|
|
6
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the 'License');
|
|
7
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
8
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
11
|
-
* the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
12
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
13
|
-
* governing permissions and limitations under the License.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
function $6a99195332edec8b$export$80f3e147d781571c(element) {
|
|
17
|
-
// If the user is interacting with a virtual cursor, e.g. screen reader, then
|
|
18
|
-
// wait until after any animated transitions that are currently occurring on
|
|
19
|
-
// the page before shifting focus. This avoids issues with VoiceOver on iOS
|
|
20
|
-
// causing the page to scroll when moving focus if the element is transitioning
|
|
21
|
-
// from off the screen.
|
|
22
|
-
const ownerDocument = (0, $jlOai$getOwnerDocument)(element);
|
|
23
|
-
if ((0, $jlOai$getInteractionModality)() === 'virtual') {
|
|
24
|
-
let lastFocusedElement = ownerDocument.activeElement;
|
|
25
|
-
(0, $jlOai$runAfterTransition)(()=>{
|
|
26
|
-
// If focus did not move and the element is still in the document, focus it.
|
|
27
|
-
if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) (0, $jlOai$focusWithoutScrolling)(element);
|
|
28
|
-
});
|
|
29
|
-
} else (0, $jlOai$focusWithoutScrolling)(element);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export {$6a99195332edec8b$export$80f3e147d781571c as focusSafely};
|
|
34
|
-
//# sourceMappingURL=focusSafely.module.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAUM,SAAS,0CAAY,OAAyB;IACnD,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,+EAA+E;IAC/E,uBAAuB;IACvB,MAAM,gBAAgB,CAAA,GAAA,uBAAe,EAAE;IACvC,IAAI,CAAA,GAAA,6BAAqB,QAAQ,WAAW;QAC1C,IAAI,qBAAqB,cAAc,aAAa;QACpD,CAAA,GAAA,yBAAiB,EAAE;YACjB,4EAA4E;YAC5E,IAAI,cAAc,aAAa,KAAK,sBAAsB,QAAQ,WAAW,EAC3E,CAAA,GAAA,4BAAoB,EAAE;QAE1B;IACF,OACE,CAAA,GAAA,4BAAoB,EAAE;AAE1B","sources":["packages/@react-aria/focus/src/focusSafely.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {FocusableElement} from '@react-types/shared';\nimport {focusWithoutScrolling, getOwnerDocument, runAfterTransition} from '@react-aria/utils';\nimport {getInteractionModality} from '@react-aria/interactions';\n\n/**\n * A utility function that focuses an element while avoiding undesired side effects such\n * as page scrolling and screen reader issues with CSS transitions.\n */\nexport function focusSafely(element: FocusableElement) {\n // If the user is interacting with a virtual cursor, e.g. screen reader, then\n // wait until after any animated transitions that are currently occurring on\n // the page before shifting focus. This avoids issues with VoiceOver on iOS\n // causing the page to scroll when moving focus if the element is transitioning\n // from off the screen.\n const ownerDocument = getOwnerDocument(element);\n if (getInteractionModality() === 'virtual') {\n let lastFocusedElement = ownerDocument.activeElement;\n runAfterTransition(() => {\n // If focus did not move and the element is still in the document, focus it.\n if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) {\n focusWithoutScrolling(element);\n }\n });\n } else {\n focusWithoutScrolling(element);\n }\n}\n"],"names":[],"version":3,"file":"focusSafely.module.js.map"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
var $1c7f9157d722357d$exports = require("./focusSafely.main.js");
|
|
2
|
-
var $ggOO2$reactariautils = require("@react-aria/utils");
|
|
3
|
-
var $ggOO2$react = require("react");
|
|
4
|
-
var $ggOO2$reactariainteractions = require("@react-aria/interactions");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function $parcel$interopDefault(a) {
|
|
8
|
-
return a && a.__esModule ? a.default : a;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function $parcel$export(e, n, v, s) {
|
|
12
|
-
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
$parcel$export(module.exports, "FocusableProvider", () => $fb504d83237fd6ac$export$13f3202a3e5ddd5);
|
|
16
|
-
$parcel$export(module.exports, "useFocusable", () => $fb504d83237fd6ac$export$4c014de7c8940b4c);
|
|
17
|
-
/*
|
|
18
|
-
* Copyright 2020 Adobe. All rights reserved.
|
|
19
|
-
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
20
|
-
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
21
|
-
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
22
|
-
*
|
|
23
|
-
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
24
|
-
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
25
|
-
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
26
|
-
* governing permissions and limitations under the License.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
let $fb504d83237fd6ac$var$FocusableContext = /*#__PURE__*/ (0, ($parcel$interopDefault($ggOO2$react))).createContext(null);
|
|
32
|
-
function $fb504d83237fd6ac$var$useFocusableContext(ref) {
|
|
33
|
-
let context = (0, $ggOO2$react.useContext)($fb504d83237fd6ac$var$FocusableContext) || {};
|
|
34
|
-
(0, $ggOO2$reactariautils.useSyncRef)(context, ref);
|
|
35
|
-
// eslint-disable-next-line
|
|
36
|
-
let { ref: _, ...otherProps } = context;
|
|
37
|
-
return otherProps;
|
|
38
|
-
}
|
|
39
|
-
const $fb504d83237fd6ac$export$13f3202a3e5ddd5 = /*#__PURE__*/ (0, ($parcel$interopDefault($ggOO2$react))).forwardRef(function FocusableProvider(props, ref) {
|
|
40
|
-
let { children: children, ...otherProps } = props;
|
|
41
|
-
let objRef = (0, $ggOO2$reactariautils.useObjectRef)(ref);
|
|
42
|
-
let context = {
|
|
43
|
-
...otherProps,
|
|
44
|
-
ref: objRef
|
|
45
|
-
};
|
|
46
|
-
return /*#__PURE__*/ (0, ($parcel$interopDefault($ggOO2$react))).createElement($fb504d83237fd6ac$var$FocusableContext.Provider, {
|
|
47
|
-
value: context
|
|
48
|
-
}, children);
|
|
49
|
-
});
|
|
50
|
-
function $fb504d83237fd6ac$export$4c014de7c8940b4c(props, domRef) {
|
|
51
|
-
let { focusProps: focusProps } = (0, $ggOO2$reactariainteractions.useFocus)(props);
|
|
52
|
-
let { keyboardProps: keyboardProps } = (0, $ggOO2$reactariainteractions.useKeyboard)(props);
|
|
53
|
-
let interactions = (0, $ggOO2$reactariautils.mergeProps)(focusProps, keyboardProps);
|
|
54
|
-
let domProps = $fb504d83237fd6ac$var$useFocusableContext(domRef);
|
|
55
|
-
let interactionProps = props.isDisabled ? {} : domProps;
|
|
56
|
-
let autoFocusRef = (0, $ggOO2$react.useRef)(props.autoFocus);
|
|
57
|
-
(0, $ggOO2$react.useEffect)(()=>{
|
|
58
|
-
if (autoFocusRef.current && domRef.current) (0, $1c7f9157d722357d$exports.focusSafely)(domRef.current);
|
|
59
|
-
autoFocusRef.current = false;
|
|
60
|
-
}, [
|
|
61
|
-
domRef
|
|
62
|
-
]);
|
|
63
|
-
return {
|
|
64
|
-
focusableProps: (0, $ggOO2$reactariautils.mergeProps)({
|
|
65
|
-
...interactions,
|
|
66
|
-
tabIndex: props.excludeFromTabOrder && !props.isDisabled ? -1 : undefined
|
|
67
|
-
}, interactionProps)
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
//# sourceMappingURL=useFocusable.main.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;AAsBD,IAAI,uDAAmB,CAAA,GAAA,sCAAI,EAAE,aAAa,CAA+B;AAEzE,SAAS,0CAAoB,GAAuC;IAClE,IAAI,UAAU,CAAA,GAAA,uBAAS,EAAE,2CAAqB,CAAC;IAC/C,CAAA,GAAA,gCAAS,EAAE,SAAS;IAEpB,2BAA2B;IAC3B,IAAI,EAAC,KAAK,CAAC,EAAE,GAAG,YAAW,GAAG;IAC9B,OAAO;AACT;AAKO,MAAM,yDAAoB,CAAA,GAAA,sCAAI,EAAE,UAAU,CAAC,SAAS,kBAAkB,KAA6B,EAAE,GAAmC;IAC7I,IAAI,YAAC,QAAQ,EAAE,GAAG,YAAW,GAAG;IAChC,IAAI,SAAS,CAAA,GAAA,kCAAW,EAAE;IAC1B,IAAI,UAAU;QACZ,GAAG,UAAU;QACb,KAAK;IACP;IAEA,qBACE,0DAAC,uCAAiB,QAAQ;QAAC,OAAO;OAC/B;AAGP;AAUO,SAAS,0CAA4D,KAA0B,EAAE,MAA0C;IAChJ,IAAI,cAAC,UAAU,EAAC,GAAG,CAAA,GAAA,qCAAO,EAAE;IAC5B,IAAI,iBAAC,aAAa,EAAC,GAAG,CAAA,GAAA,wCAAU,EAAE;IAClC,IAAI,eAAe,CAAA,GAAA,gCAAS,EAAE,YAAY;IAC1C,IAAI,WAAW,0CAAoB;IACnC,IAAI,mBAAmB,MAAM,UAAU,GAAG,CAAC,IAAI;IAC/C,IAAI,eAAe,CAAA,GAAA,mBAAK,EAAE,MAAM,SAAS;IAEzC,CAAA,GAAA,sBAAQ,EAAE;QACR,IAAI,aAAa,OAAO,IAAI,OAAO,OAAO,EACxC,CAAA,GAAA,qCAAU,EAAE,OAAO,OAAO;QAE5B,aAAa,OAAO,GAAG;IACzB,GAAG;QAAC;KAAO;IAEX,OAAO;QACL,gBAAgB,CAAA,GAAA,gCAAS,EACvB;YACE,GAAG,YAAY;YACf,UAAU,MAAM,mBAAmB,IAAI,CAAC,MAAM,UAAU,GAAG,KAAK;QAClE,GACA;IAEJ;AACF","sources":["packages/@react-aria/focus/src/useFocusable.tsx"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {DOMAttributes, FocusableDOMProps, FocusableElement, FocusableProps, RefObject} from '@react-types/shared';\nimport {focusSafely} from './';\nimport {mergeProps, useObjectRef, useSyncRef} from '@react-aria/utils';\nimport React, {ForwardedRef, MutableRefObject, ReactNode, useContext, useEffect, useRef} from 'react';\nimport {useFocus, useKeyboard} from '@react-aria/interactions';\n\nexport interface FocusableOptions<T = FocusableElement> extends FocusableProps<T>, FocusableDOMProps {\n /** Whether focus should be disabled. */\n isDisabled?: boolean\n}\n\nexport interface FocusableProviderProps extends DOMAttributes {\n /** The child element to provide DOM props to. */\n children?: ReactNode\n}\n\ninterface FocusableContextValue extends FocusableProviderProps {\n ref?: MutableRefObject<FocusableElement | null>\n}\n\nlet FocusableContext = React.createContext<FocusableContextValue | null>(null);\n\nfunction useFocusableContext(ref: RefObject<FocusableElement | null>): FocusableContextValue {\n let context = useContext(FocusableContext) || {};\n useSyncRef(context, ref);\n\n // eslint-disable-next-line\n let {ref: _, ...otherProps} = context;\n return otherProps;\n}\n\n/**\n * Provides DOM props to the nearest focusable child.\n */\nexport const FocusableProvider = React.forwardRef(function FocusableProvider(props: FocusableProviderProps, ref: ForwardedRef<FocusableElement>) {\n let {children, ...otherProps} = props;\n let objRef = useObjectRef(ref);\n let context = {\n ...otherProps,\n ref: objRef\n };\n\n return (\n <FocusableContext.Provider value={context}>\n {children}\n </FocusableContext.Provider>\n );\n});\n\nexport interface FocusableAria {\n /** Props for the focusable element. */\n focusableProps: DOMAttributes\n}\n\n/**\n * Used to make an element focusable and capable of auto focus.\n */\nexport function useFocusable<T extends FocusableElement = FocusableElement>(props: FocusableOptions<T>, domRef: RefObject<FocusableElement | null>): FocusableAria {\n let {focusProps} = useFocus(props);\n let {keyboardProps} = useKeyboard(props);\n let interactions = mergeProps(focusProps, keyboardProps);\n let domProps = useFocusableContext(domRef);\n let interactionProps = props.isDisabled ? {} : domProps;\n let autoFocusRef = useRef(props.autoFocus);\n\n useEffect(() => {\n if (autoFocusRef.current && domRef.current) {\n focusSafely(domRef.current);\n }\n autoFocusRef.current = false;\n }, [domRef]);\n\n return {\n focusableProps: mergeProps(\n {\n ...interactions,\n tabIndex: props.excludeFromTabOrder && !props.isDisabled ? -1 : undefined\n },\n interactionProps\n )\n };\n}\n"],"names":[],"version":3,"file":"useFocusable.main.js.map"}
|