@react-aria/focus 3.7.0 → 3.8.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/main.js +170 -36
- package/dist/main.js.map +1 -1
- package/dist/module.js +170 -36
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/FocusScope.tsx +224 -53
package/dist/main.js
CHANGED
|
@@ -70,14 +70,15 @@ function $d5156037ad898a4d$export$e989c0fffaa6b27a(element, childElement) {
|
|
|
70
70
|
|
|
71
71
|
const $a7a032acae3ddda9$var$FocusContext = /*#__PURE__*/ ($parcel$interopDefault($aB6Cp$react)).createContext(null);
|
|
72
72
|
let $a7a032acae3ddda9$var$activeScope = null;
|
|
73
|
-
let $a7a032acae3ddda9$var$scopes = new Map();
|
|
74
73
|
function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
75
74
|
let { children: children , contain: contain , restoreFocus: restoreFocus , autoFocus: autoFocus } = props;
|
|
76
75
|
let startRef = $aB6Cp$react.useRef();
|
|
77
76
|
let endRef = $aB6Cp$react.useRef();
|
|
78
77
|
let scopeRef = $aB6Cp$react.useRef([]);
|
|
79
78
|
let ctx = $aB6Cp$react.useContext($a7a032acae3ddda9$var$FocusContext);
|
|
80
|
-
|
|
79
|
+
var ref;
|
|
80
|
+
// if there is no scopeRef on the context, then the parent is the focusScopeTree's root, represented by null
|
|
81
|
+
let parentScope = (ref = ctx === null || ctx === void 0 ? void 0 : ctx.scopeRef) !== null && ref !== void 0 ? ref : null;
|
|
81
82
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
82
83
|
// Find all rendered nodes between the sentinels and add them to the scope.
|
|
83
84
|
let node = startRef.current.nextSibling;
|
|
@@ -91,22 +92,27 @@ function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
|
91
92
|
children,
|
|
92
93
|
parentScope
|
|
93
94
|
]);
|
|
95
|
+
// add to the focus scope tree in render order because useEffects/useLayoutEffects run children first whereas render runs parent first
|
|
96
|
+
// which matters when constructing a tree
|
|
97
|
+
if ($a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(parentScope) && !$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef)) $a7a032acae3ddda9$export$d06fae2ee68b101e.addTreeNode(scopeRef, parentScope);
|
|
98
|
+
let node1 = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
99
|
+
node1.contain = contain;
|
|
100
|
+
$a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain);
|
|
101
|
+
$a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain);
|
|
102
|
+
$a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus);
|
|
103
|
+
// this layout effect needs to run last so that focusScopeTree cleanup happens at the last moment possible
|
|
94
104
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
95
|
-
|
|
96
|
-
return ()=>{
|
|
105
|
+
if (scopeRef && (parentScope || parentScope == null)) return ()=>{
|
|
97
106
|
// Restore the active scope on unmount if this scope or a descendant scope is active.
|
|
98
107
|
// Parent effect cleanups run before children, so we need to check if the
|
|
99
108
|
// parent scope actually still exists before restoring the active scope to it.
|
|
100
|
-
if ((scopeRef === $a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope(scopeRef, $a7a032acae3ddda9$var$activeScope)) && (!parentScope || $a7a032acae3ddda9$
|
|
101
|
-
$a7a032acae3ddda9$
|
|
109
|
+
if ((scopeRef === $a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope(scopeRef, $a7a032acae3ddda9$var$activeScope)) && (!parentScope || $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(parentScope))) $a7a032acae3ddda9$var$activeScope = parentScope;
|
|
110
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.removeTreeNode(scopeRef);
|
|
102
111
|
};
|
|
103
112
|
}, [
|
|
104
113
|
scopeRef,
|
|
105
114
|
parentScope
|
|
106
115
|
]);
|
|
107
|
-
$a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain);
|
|
108
|
-
$a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain);
|
|
109
|
-
$a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus);
|
|
110
116
|
let focusManager = $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef);
|
|
111
117
|
return(/*#__PURE__*/ ($parcel$interopDefault($aB6Cp$react)).createElement($a7a032acae3ddda9$var$FocusContext.Provider, {
|
|
112
118
|
value: {
|
|
@@ -216,6 +222,14 @@ const $a7a032acae3ddda9$var$TABBABLE_ELEMENT_SELECTOR = $a7a032acae3ddda9$var$fo
|
|
|
216
222
|
function $a7a032acae3ddda9$var$getScopeRoot(scope) {
|
|
217
223
|
return scope[0].parentElement;
|
|
218
224
|
}
|
|
225
|
+
function $a7a032acae3ddda9$var$shouldContainFocus(scopeRef) {
|
|
226
|
+
let scope = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode($a7a032acae3ddda9$var$activeScope);
|
|
227
|
+
while(scope && scope.scopeRef !== scopeRef){
|
|
228
|
+
if (scope.contain) return false;
|
|
229
|
+
scope = scope.parent;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
219
233
|
function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
220
234
|
let focusedNode = $aB6Cp$react.useRef();
|
|
221
235
|
let raf = $aB6Cp$react.useRef(null);
|
|
@@ -231,7 +245,7 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
231
245
|
}
|
|
232
246
|
// Handle the Tab key to contain focus within the scope
|
|
233
247
|
let onKeyDown = (e)=>{
|
|
234
|
-
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey ||
|
|
248
|
+
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey || !$a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) return;
|
|
235
249
|
let focusedElement = document.activeElement;
|
|
236
250
|
let scope = scopeRef.current;
|
|
237
251
|
if (!$a7a032acae3ddda9$var$isElementInScope(focusedElement, scope)) return;
|
|
@@ -253,21 +267,23 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
253
267
|
if (!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) {
|
|
254
268
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
255
269
|
focusedNode.current = e.target;
|
|
256
|
-
} else if (
|
|
270
|
+
} else if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef) && !$a7a032acae3ddda9$var$isElementInChildScope(e.target, scopeRef)) {
|
|
257
271
|
// If a focus event occurs outside the active scope (e.g. user tabs from browser location bar),
|
|
258
272
|
// restore focus to the previously focused node or the first tabbable element in the active scope.
|
|
259
273
|
if (focusedNode.current) focusedNode.current.focus();
|
|
260
274
|
else if ($a7a032acae3ddda9$var$activeScope) $a7a032acae3ddda9$var$focusFirstInScope($a7a032acae3ddda9$var$activeScope.current);
|
|
261
|
-
} else if (
|
|
275
|
+
} else if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) focusedNode.current = e.target;
|
|
262
276
|
};
|
|
263
277
|
let onBlur = (e)=>{
|
|
264
278
|
// Firefox doesn't shift focus back to the Dialog properly without this
|
|
265
279
|
raf.current = requestAnimationFrame(()=>{
|
|
266
280
|
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
267
|
-
if (
|
|
281
|
+
if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef) && !$a7a032acae3ddda9$var$isElementInChildScope(document.activeElement, scopeRef)) {
|
|
268
282
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
269
|
-
|
|
270
|
-
|
|
283
|
+
if (document.body.contains(e.target)) {
|
|
284
|
+
focusedNode.current = e.target;
|
|
285
|
+
focusedNode.current.focus();
|
|
286
|
+
} else if ($a7a032acae3ddda9$var$activeScope) $a7a032acae3ddda9$var$focusFirstInScope($a7a032acae3ddda9$var$activeScope.current);
|
|
271
287
|
}
|
|
272
288
|
});
|
|
273
289
|
};
|
|
@@ -299,28 +315,28 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
299
315
|
]);
|
|
300
316
|
}
|
|
301
317
|
function $a7a032acae3ddda9$var$isElementInAnyScope(element) {
|
|
302
|
-
|
|
303
|
-
if ($a7a032acae3ddda9$var$isElementInScope(element, scope.current)) return true;
|
|
304
|
-
}
|
|
305
|
-
return false;
|
|
318
|
+
return $a7a032acae3ddda9$var$isElementInChildScope(element);
|
|
306
319
|
}
|
|
307
320
|
function $a7a032acae3ddda9$var$isElementInScope(element, scope) {
|
|
308
321
|
return scope.some((node)=>node.contains(element)
|
|
309
322
|
);
|
|
310
323
|
}
|
|
311
|
-
function $a7a032acae3ddda9$var$isElementInChildScope(element, scope) {
|
|
324
|
+
function $a7a032acae3ddda9$var$isElementInChildScope(element, scope = null) {
|
|
312
325
|
// node.contains in isElementInScope covers child scopes that are also DOM children,
|
|
313
326
|
// but does not cover child scopes in portals.
|
|
314
|
-
for (let s of $a7a032acae3ddda9$
|
|
315
|
-
if (
|
|
327
|
+
for (let { scopeRef: s } of $a7a032acae3ddda9$export$d06fae2ee68b101e.traverse($a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scope))){
|
|
328
|
+
if ($a7a032acae3ddda9$var$isElementInScope(element, s.current)) return true;
|
|
316
329
|
}
|
|
317
330
|
return false;
|
|
318
331
|
}
|
|
319
332
|
function $a7a032acae3ddda9$var$isAncestorScope(ancestor, scope) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
333
|
+
var ref;
|
|
334
|
+
let parent = (ref = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scope)) === null || ref === void 0 ? void 0 : ref.parent;
|
|
335
|
+
while(parent){
|
|
336
|
+
if (parent.scopeRef === ancestor) return true;
|
|
337
|
+
parent = parent.parent;
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
324
340
|
}
|
|
325
341
|
function $a7a032acae3ddda9$var$focusElement(element, scroll = false) {
|
|
326
342
|
if (element != null && !scroll) try {
|
|
@@ -334,13 +350,22 @@ function $a7a032acae3ddda9$var$focusElement(element, scroll = false) {
|
|
|
334
350
|
// ignore
|
|
335
351
|
}
|
|
336
352
|
}
|
|
337
|
-
function $a7a032acae3ddda9$var$focusFirstInScope(scope) {
|
|
353
|
+
function $a7a032acae3ddda9$var$focusFirstInScope(scope, tabbable = true) {
|
|
338
354
|
let sentinel = scope[0].previousElementSibling;
|
|
339
355
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
340
|
-
tabbable:
|
|
356
|
+
tabbable: tabbable
|
|
341
357
|
}, scope);
|
|
342
358
|
walker.currentNode = sentinel;
|
|
343
|
-
|
|
359
|
+
let nextNode = walker.nextNode();
|
|
360
|
+
// If the scope does not contain a tabbable element, use the first focusable element.
|
|
361
|
+
if (tabbable && !nextNode) {
|
|
362
|
+
walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
363
|
+
tabbable: false
|
|
364
|
+
}, scope);
|
|
365
|
+
walker.currentNode = sentinel;
|
|
366
|
+
nextNode = walker.nextNode();
|
|
367
|
+
}
|
|
368
|
+
$a7a032acae3ddda9$var$focusElement(nextNode);
|
|
344
369
|
}
|
|
345
370
|
function $a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus) {
|
|
346
371
|
const autoFocusRef = ($parcel$interopDefault($aB6Cp$react)).useRef(autoFocus);
|
|
@@ -350,14 +375,38 @@ function $a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus) {
|
|
|
350
375
|
if (!$a7a032acae3ddda9$var$isElementInScope(document.activeElement, $a7a032acae3ddda9$var$activeScope.current)) $a7a032acae3ddda9$var$focusFirstInScope(scopeRef.current);
|
|
351
376
|
}
|
|
352
377
|
autoFocusRef.current = false;
|
|
353
|
-
}, [
|
|
378
|
+
}, [
|
|
379
|
+
scopeRef
|
|
380
|
+
]);
|
|
354
381
|
}
|
|
355
382
|
function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain) {
|
|
356
383
|
// create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
|
|
357
384
|
const nodeToRestoreRef = $aB6Cp$react.useRef(typeof document !== 'undefined' ? document.activeElement : null);
|
|
385
|
+
// restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
|
|
386
|
+
// restoring-non-containing scopes should only care if they become active so they can perform the restore
|
|
387
|
+
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
388
|
+
let scope = scopeRef.current;
|
|
389
|
+
if (!restoreFocus || contain) return;
|
|
390
|
+
let onFocus = ()=>{
|
|
391
|
+
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
392
|
+
// Moving out of the active scope to an ancestor is not allowed.
|
|
393
|
+
if (!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) $a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
394
|
+
};
|
|
395
|
+
document.addEventListener('focusin', onFocus, false);
|
|
396
|
+
scope.forEach((element)=>element.addEventListener('focusin', onFocus, false)
|
|
397
|
+
);
|
|
398
|
+
return ()=>{
|
|
399
|
+
document.removeEventListener('focusin', onFocus, false);
|
|
400
|
+
scope.forEach((element)=>element.removeEventListener('focusin', onFocus, false)
|
|
401
|
+
);
|
|
402
|
+
};
|
|
403
|
+
}, [
|
|
404
|
+
scopeRef,
|
|
405
|
+
contain
|
|
406
|
+
]);
|
|
358
407
|
// useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
|
|
359
408
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
360
|
-
|
|
409
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = nodeToRestoreRef.current;
|
|
361
410
|
if (!restoreFocus) return;
|
|
362
411
|
// Handle the Tab key so that tabbing out of the scope goes to the next element
|
|
363
412
|
// after the node that had focus when the scope mounted. This is important when
|
|
@@ -367,6 +416,7 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
367
416
|
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
368
417
|
let focusedElement = document.activeElement;
|
|
369
418
|
if (!$a7a032acae3ddda9$var$isElementInScope(focusedElement, scopeRef.current)) return;
|
|
419
|
+
let nodeToRestore = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
|
|
370
420
|
// Create a DOM tree walker that matches all tabbable elements
|
|
371
421
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(document.body, {
|
|
372
422
|
tabbable: true
|
|
@@ -374,7 +424,10 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
374
424
|
// Find the next tabbable element after the currently focused element
|
|
375
425
|
walker.currentNode = focusedElement;
|
|
376
426
|
let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
377
|
-
if (!document.body.contains(nodeToRestore) || nodeToRestore === document.body)
|
|
427
|
+
if (!document.body.contains(nodeToRestore) || nodeToRestore === document.body) {
|
|
428
|
+
nodeToRestore = null;
|
|
429
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = null;
|
|
430
|
+
}
|
|
378
431
|
// If there is no next element, or it is outside the current scope, move focus to the
|
|
379
432
|
// next element after the node to restore to instead.
|
|
380
433
|
if ((!nextElement || !$a7a032acae3ddda9$var$isElementInScope(nextElement, scopeRef.current)) && nodeToRestore) {
|
|
@@ -395,10 +448,26 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
395
448
|
if (!contain) document.addEventListener('keydown', onKeyDown, true);
|
|
396
449
|
return ()=>{
|
|
397
450
|
if (!contain) document.removeEventListener('keydown', onKeyDown, true);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
451
|
+
let nodeToRestore = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
|
|
452
|
+
// if we already lost focus to the body and this was the active scope, then we should attempt to restore
|
|
453
|
+
if (restoreFocus && nodeToRestore && ($a7a032acae3ddda9$var$isElementInScope(document.activeElement, scopeRef.current) || document.activeElement === document.body && $a7a032acae3ddda9$var$activeScope === scopeRef)) {
|
|
454
|
+
// freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
|
|
455
|
+
let clonedTree = $a7a032acae3ddda9$export$d06fae2ee68b101e.clone();
|
|
456
|
+
requestAnimationFrame(()=>{
|
|
457
|
+
// Only restore focus if we've lost focus to the body, the alternative is that focus has been purposefully moved elsewhere
|
|
458
|
+
if (document.activeElement === document.body) {
|
|
459
|
+
// look up the tree starting with our scope to find a nodeToRestore still in the DOM
|
|
460
|
+
let treeNode = clonedTree.getTreeNode(scopeRef);
|
|
461
|
+
while(treeNode){
|
|
462
|
+
if (treeNode.nodeToRestore && document.body.contains(treeNode.nodeToRestore)) {
|
|
463
|
+
$a7a032acae3ddda9$var$focusElement(treeNode.nodeToRestore);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
treeNode = treeNode.parent;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
402
471
|
};
|
|
403
472
|
}, [
|
|
404
473
|
scopeRef,
|
|
@@ -500,6 +569,71 @@ function $a7a032acae3ddda9$var$last(walker) {
|
|
|
500
569
|
}while (last)
|
|
501
570
|
return next;
|
|
502
571
|
}
|
|
572
|
+
class $a7a032acae3ddda9$var$Tree {
|
|
573
|
+
get size() {
|
|
574
|
+
return this.fastMap.size;
|
|
575
|
+
}
|
|
576
|
+
getTreeNode(data) {
|
|
577
|
+
return this.fastMap.get(data);
|
|
578
|
+
}
|
|
579
|
+
addTreeNode(scopeRef, parent, nodeToRestore) {
|
|
580
|
+
let parentNode = this.fastMap.get(parent !== null && parent !== void 0 ? parent : null);
|
|
581
|
+
let node = new $a7a032acae3ddda9$var$TreeNode({
|
|
582
|
+
scopeRef: scopeRef
|
|
583
|
+
});
|
|
584
|
+
parentNode.addChild(node);
|
|
585
|
+
node.parent = parentNode;
|
|
586
|
+
this.fastMap.set(scopeRef, node);
|
|
587
|
+
if (nodeToRestore) node.nodeToRestore = nodeToRestore;
|
|
588
|
+
}
|
|
589
|
+
removeTreeNode(scopeRef) {
|
|
590
|
+
// never remove the root
|
|
591
|
+
if (scopeRef === null) return;
|
|
592
|
+
let node = this.fastMap.get(scopeRef);
|
|
593
|
+
let parentNode = node.parent;
|
|
594
|
+
// when we remove a scope, check if any sibling scopes are trying to restore focus to something inside the scope we're removing
|
|
595
|
+
// if we are, then replace the siblings restore with the restore from the scope we're removing
|
|
596
|
+
for (let current of this.traverse())if (current !== node && node.nodeToRestore && current.nodeToRestore && node.scopeRef.current && $a7a032acae3ddda9$var$isElementInScope(current.nodeToRestore, node.scopeRef.current)) current.nodeToRestore = node.nodeToRestore;
|
|
597
|
+
let children = node.children;
|
|
598
|
+
parentNode.removeChild(node);
|
|
599
|
+
if (children.length > 0) children.forEach((child)=>parentNode.addChild(child)
|
|
600
|
+
);
|
|
601
|
+
this.fastMap.delete(node.scopeRef);
|
|
602
|
+
}
|
|
603
|
+
// Pre Order Depth First
|
|
604
|
+
*traverse(node = this.root) {
|
|
605
|
+
if (node.scopeRef != null) yield node;
|
|
606
|
+
if (node.children.length > 0) for (let child of node.children)yield* this.traverse(child);
|
|
607
|
+
}
|
|
608
|
+
clone() {
|
|
609
|
+
let newTree = new $a7a032acae3ddda9$var$Tree();
|
|
610
|
+
for (let node of this.traverse())newTree.addTreeNode(node.scopeRef, node.parent.scopeRef, node.nodeToRestore);
|
|
611
|
+
return newTree;
|
|
612
|
+
}
|
|
613
|
+
constructor(){
|
|
614
|
+
this.fastMap = new Map();
|
|
615
|
+
this.root = new $a7a032acae3ddda9$var$TreeNode({
|
|
616
|
+
scopeRef: null
|
|
617
|
+
});
|
|
618
|
+
this.fastMap.set(null, this.root);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
class $a7a032acae3ddda9$var$TreeNode {
|
|
622
|
+
addChild(node) {
|
|
623
|
+
this.children.push(node);
|
|
624
|
+
node.parent = this;
|
|
625
|
+
}
|
|
626
|
+
removeChild(node) {
|
|
627
|
+
this.children.splice(this.children.indexOf(node), 1);
|
|
628
|
+
node.parent = undefined;
|
|
629
|
+
}
|
|
630
|
+
constructor(props){
|
|
631
|
+
this.children = [];
|
|
632
|
+
this.contain = false;
|
|
633
|
+
this.scopeRef = props.scopeRef;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
let $a7a032acae3ddda9$export$d06fae2ee68b101e = new $a7a032acae3ddda9$var$Tree();
|
|
503
637
|
|
|
504
638
|
|
|
505
639
|
|