focus-trap 7.6.6 → 7.7.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/CHANGELOG.md +6 -0
- package/README.md +19 -6
- package/dist/focus-trap.esm.js +236 -36
- package/dist/focus-trap.esm.js.map +1 -1
- package/dist/focus-trap.esm.min.js +2 -2
- package/dist/focus-trap.esm.min.js.map +1 -1
- package/dist/focus-trap.js +236 -36
- package/dist/focus-trap.js.map +1 -1
- package/dist/focus-trap.min.js +2 -2
- package/dist/focus-trap.min.js.map +1 -1
- package/dist/focus-trap.umd.js +236 -36
- package/dist/focus-trap.umd.js.map +1 -1
- package/dist/focus-trap.umd.min.js +2 -2
- package/dist/focus-trap.umd.min.js.map +1 -1
- package/index.d.ts +10 -6
- package/index.js +194 -42
- package/package.json +31 -21
package/dist/focus-trap.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 7.
|
|
2
|
+
* focus-trap 7.7.0
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
5
|
(function (global, factory) {
|
|
@@ -21,6 +21,54 @@
|
|
|
21
21
|
function _arrayWithoutHoles(r) {
|
|
22
22
|
if (Array.isArray(r)) return _arrayLikeToArray(r);
|
|
23
23
|
}
|
|
24
|
+
function _createForOfIteratorHelper(r, e) {
|
|
25
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
26
|
+
if (!t) {
|
|
27
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
|
|
28
|
+
t && (r = t);
|
|
29
|
+
var n = 0,
|
|
30
|
+
F = function () {};
|
|
31
|
+
return {
|
|
32
|
+
s: F,
|
|
33
|
+
n: function () {
|
|
34
|
+
return n >= r.length ? {
|
|
35
|
+
done: true
|
|
36
|
+
} : {
|
|
37
|
+
done: false,
|
|
38
|
+
value: r[n++]
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
e: function (r) {
|
|
42
|
+
throw r;
|
|
43
|
+
},
|
|
44
|
+
f: F
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
48
|
+
}
|
|
49
|
+
var o,
|
|
50
|
+
a = true,
|
|
51
|
+
u = false;
|
|
52
|
+
return {
|
|
53
|
+
s: function () {
|
|
54
|
+
t = t.call(r);
|
|
55
|
+
},
|
|
56
|
+
n: function () {
|
|
57
|
+
var r = t.next();
|
|
58
|
+
return a = r.done, r;
|
|
59
|
+
},
|
|
60
|
+
e: function (r) {
|
|
61
|
+
u = true, o = r;
|
|
62
|
+
},
|
|
63
|
+
f: function () {
|
|
64
|
+
try {
|
|
65
|
+
a || null == t.return || t.return();
|
|
66
|
+
} finally {
|
|
67
|
+
if (u) throw o;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
24
72
|
function _defineProperty(e, r, t) {
|
|
25
73
|
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
26
74
|
value: t,
|
|
@@ -82,12 +130,18 @@
|
|
|
82
130
|
}
|
|
83
131
|
|
|
84
132
|
var activeFocusTraps = {
|
|
133
|
+
// Returns the trap from the top of the stack.
|
|
134
|
+
getActiveTrap: function getActiveTrap(trapStack) {
|
|
135
|
+
if ((trapStack === null || trapStack === void 0 ? void 0 : trapStack.length) > 0) {
|
|
136
|
+
return trapStack[trapStack.length - 1];
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
},
|
|
140
|
+
// Pauses the currently active trap, then adds a new trap to the stack.
|
|
85
141
|
activateTrap: function activateTrap(trapStack, trap) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
activeTrap._setPausedState(true);
|
|
90
|
-
}
|
|
142
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
143
|
+
if (trap !== activeTrap) {
|
|
144
|
+
activeFocusTraps.pauseTrap(trapStack);
|
|
91
145
|
}
|
|
92
146
|
var trapIndex = trapStack.indexOf(trap);
|
|
93
147
|
if (trapIndex === -1) {
|
|
@@ -98,13 +152,24 @@
|
|
|
98
152
|
trapStack.push(trap);
|
|
99
153
|
}
|
|
100
154
|
},
|
|
155
|
+
// Removes the trap from the top of the stack, then unpauses the next trap down.
|
|
101
156
|
deactivateTrap: function deactivateTrap(trapStack, trap) {
|
|
102
157
|
var trapIndex = trapStack.indexOf(trap);
|
|
103
158
|
if (trapIndex !== -1) {
|
|
104
159
|
trapStack.splice(trapIndex, 1);
|
|
105
160
|
}
|
|
106
|
-
|
|
107
|
-
|
|
161
|
+
activeFocusTraps.unpauseTrap(trapStack);
|
|
162
|
+
},
|
|
163
|
+
// Pauses the trap at the top of the stack.
|
|
164
|
+
pauseTrap: function pauseTrap(trapStack) {
|
|
165
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
166
|
+
activeTrap === null || activeTrap === void 0 || activeTrap._setPausedState(true);
|
|
167
|
+
},
|
|
168
|
+
// Unpauses the trap at the top of the stack.
|
|
169
|
+
unpauseTrap: function unpauseTrap(trapStack) {
|
|
170
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
171
|
+
if (activeTrap && !activeTrap._isManuallyPaused()) {
|
|
172
|
+
activeTrap._setPausedState(false);
|
|
108
173
|
}
|
|
109
174
|
}
|
|
110
175
|
};
|
|
@@ -167,29 +232,31 @@
|
|
|
167
232
|
returnFocusOnDeactivate: true,
|
|
168
233
|
escapeDeactivates: true,
|
|
169
234
|
delayInitialFocus: true,
|
|
235
|
+
isolateSubtrees: false,
|
|
170
236
|
isKeyForward: isKeyForward,
|
|
171
237
|
isKeyBackward: isKeyBackward
|
|
172
238
|
}, userOptions);
|
|
173
239
|
var state = {
|
|
174
240
|
// containers given to createFocusTrap()
|
|
175
|
-
|
|
241
|
+
/** @type {Array<HTMLElement>} */
|
|
176
242
|
containers: [],
|
|
177
243
|
// list of objects identifying tabbable nodes in `containers` in the trap
|
|
178
244
|
// NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap
|
|
179
245
|
// is active, but the trap should never get to a state where there isn't at least one group
|
|
180
246
|
// with at least one tabbable node in it (that would lead to an error condition that would
|
|
181
247
|
// result in an error being thrown)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
248
|
+
/** @type {Array<{
|
|
249
|
+
* container: HTMLElement,
|
|
250
|
+
* tabbableNodes: Array<HTMLElement>, // empty if none
|
|
251
|
+
* focusableNodes: Array<HTMLElement>, // empty if none
|
|
252
|
+
* posTabIndexesFound: boolean,
|
|
253
|
+
* firstTabbableNode: HTMLElement|undefined,
|
|
254
|
+
* lastTabbableNode: HTMLElement|undefined,
|
|
255
|
+
* firstDomTabbableNode: HTMLElement|undefined,
|
|
256
|
+
* lastDomTabbableNode: HTMLElement|undefined,
|
|
257
|
+
* nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
|
|
258
|
+
* }>}
|
|
259
|
+
*/
|
|
193
260
|
containerGroups: [],
|
|
194
261
|
// same order/length as `containers` list
|
|
195
262
|
|
|
@@ -198,6 +265,12 @@
|
|
|
198
265
|
// NOTE: same order as `containers` and `containerGroups`, but __not necessarily__
|
|
199
266
|
// the same length
|
|
200
267
|
tabbableGroups: [],
|
|
268
|
+
// references to nodes that are siblings to the ancestors of this trap's containers.
|
|
269
|
+
/** @type {Set<HTMLElement>} */
|
|
270
|
+
adjacentElements: new Set(),
|
|
271
|
+
// references to nodes that were inert before the trap was activated.
|
|
272
|
+
/** @type {Set<HTMLElement>} */
|
|
273
|
+
alreadyInert: new Set(),
|
|
201
274
|
nodeFocusedBeforeActivation: null,
|
|
202
275
|
mostRecentlyFocusedNode: null,
|
|
203
276
|
active: false,
|
|
@@ -801,6 +874,74 @@
|
|
|
801
874
|
doc.addEventListener('keydown', checkEscapeKey);
|
|
802
875
|
return trap;
|
|
803
876
|
};
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Traverses up the DOM from each of `containers`, collecting references to
|
|
880
|
+
* the elements that are siblings to `container` or an ancestor of `container`.
|
|
881
|
+
* @param {Array<HTMLElement>} containers
|
|
882
|
+
*/
|
|
883
|
+
var collectAdjacentElements = function collectAdjacentElements(containers) {
|
|
884
|
+
// Re-activate all adjacent elements & clear previous collection.
|
|
885
|
+
if (state.active && !state.paused) {
|
|
886
|
+
trap._setSubtreeIsolation(false);
|
|
887
|
+
}
|
|
888
|
+
state.adjacentElements.clear();
|
|
889
|
+
state.alreadyInert.clear();
|
|
890
|
+
|
|
891
|
+
// Collect all ancestors of all containers to avoid redundant processing.
|
|
892
|
+
var containerAncestors = new Set();
|
|
893
|
+
var adjacentElements = new Set();
|
|
894
|
+
|
|
895
|
+
// Compile all elements adjacent to the focus trap containers & lineage.
|
|
896
|
+
var _iterator = _createForOfIteratorHelper(containers),
|
|
897
|
+
_step;
|
|
898
|
+
try {
|
|
899
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
900
|
+
var container = _step.value;
|
|
901
|
+
containerAncestors.add(container);
|
|
902
|
+
var insideShadowRoot = typeof ShadowRoot !== 'undefined' && container.getRootNode() instanceof ShadowRoot;
|
|
903
|
+
var current = container;
|
|
904
|
+
while (current) {
|
|
905
|
+
containerAncestors.add(current);
|
|
906
|
+
var parent = current.parentElement;
|
|
907
|
+
var siblings = [];
|
|
908
|
+
if (parent) {
|
|
909
|
+
siblings = parent.children;
|
|
910
|
+
} else if (!parent && insideShadowRoot) {
|
|
911
|
+
siblings = current.getRootNode().children;
|
|
912
|
+
parent = current.getRootNode().host;
|
|
913
|
+
insideShadowRoot = typeof ShadowRoot !== 'undefined' && parent.getRootNode() instanceof ShadowRoot;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Add all the children, we'll remove container lineage later.
|
|
917
|
+
var _iterator2 = _createForOfIteratorHelper(siblings),
|
|
918
|
+
_step2;
|
|
919
|
+
try {
|
|
920
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
921
|
+
var child = _step2.value;
|
|
922
|
+
adjacentElements.add(child);
|
|
923
|
+
}
|
|
924
|
+
} catch (err) {
|
|
925
|
+
_iterator2.e(err);
|
|
926
|
+
} finally {
|
|
927
|
+
_iterator2.f();
|
|
928
|
+
}
|
|
929
|
+
current = parent;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Multi-container traps may overlap.
|
|
934
|
+
// Remove elements within container lineages.
|
|
935
|
+
} catch (err) {
|
|
936
|
+
_iterator.e(err);
|
|
937
|
+
} finally {
|
|
938
|
+
_iterator.f();
|
|
939
|
+
}
|
|
940
|
+
containerAncestors.forEach(function (el) {
|
|
941
|
+
adjacentElements["delete"](el);
|
|
942
|
+
});
|
|
943
|
+
state.adjacentElements = adjacentElements;
|
|
944
|
+
};
|
|
804
945
|
var removeListeners = function removeListeners() {
|
|
805
946
|
if (!state.active) {
|
|
806
947
|
return;
|
|
@@ -869,26 +1010,47 @@
|
|
|
869
1010
|
var onActivate = getOption(activateOptions, 'onActivate');
|
|
870
1011
|
var onPostActivate = getOption(activateOptions, 'onPostActivate');
|
|
871
1012
|
var checkCanFocusTrap = getOption(activateOptions, 'checkCanFocusTrap');
|
|
872
|
-
|
|
873
|
-
|
|
1013
|
+
|
|
1014
|
+
// If a currently-active trap is isolating its subtree, we need to remove
|
|
1015
|
+
// that isolation to allow the new trap to find tabbable nodes.
|
|
1016
|
+
var preexistingTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
1017
|
+
var revertState = false;
|
|
1018
|
+
if (preexistingTrap && !preexistingTrap.paused) {
|
|
1019
|
+
preexistingTrap._setSubtreeIsolation(false);
|
|
1020
|
+
revertState = true;
|
|
874
1021
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
state.nodeFocusedBeforeActivation = _getActiveElement(doc);
|
|
878
|
-
onActivate === null || onActivate === void 0 || onActivate();
|
|
879
|
-
var finishActivation = function finishActivation() {
|
|
880
|
-
if (checkCanFocusTrap) {
|
|
1022
|
+
try {
|
|
1023
|
+
if (!checkCanFocusTrap) {
|
|
881
1024
|
updateTabbableNodes();
|
|
882
1025
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1026
|
+
state.active = true;
|
|
1027
|
+
state.paused = false;
|
|
1028
|
+
state.nodeFocusedBeforeActivation = _getActiveElement(doc);
|
|
1029
|
+
onActivate === null || onActivate === void 0 || onActivate();
|
|
1030
|
+
var finishActivation = function finishActivation() {
|
|
1031
|
+
if (checkCanFocusTrap) {
|
|
1032
|
+
updateTabbableNodes();
|
|
1033
|
+
}
|
|
1034
|
+
addListeners();
|
|
1035
|
+
updateObservedNodes();
|
|
1036
|
+
if (config.isolateSubtrees) {
|
|
1037
|
+
trap._setSubtreeIsolation(true);
|
|
1038
|
+
}
|
|
1039
|
+
onPostActivate === null || onPostActivate === void 0 || onPostActivate();
|
|
1040
|
+
};
|
|
1041
|
+
if (checkCanFocusTrap) {
|
|
1042
|
+
checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
|
|
1043
|
+
return this;
|
|
1044
|
+
}
|
|
1045
|
+
finishActivation();
|
|
1046
|
+
} catch (error) {
|
|
1047
|
+
// If our activation throws an exception and the stack hasn't changed,
|
|
1048
|
+
// we need to re-enable the prior trap's subtree isolation.
|
|
1049
|
+
if (preexistingTrap === activeFocusTraps.getActiveTrap(trapStack) && revertState) {
|
|
1050
|
+
preexistingTrap._setSubtreeIsolation(true);
|
|
1051
|
+
}
|
|
1052
|
+
throw error;
|
|
890
1053
|
}
|
|
891
|
-
finishActivation();
|
|
892
1054
|
return this;
|
|
893
1055
|
},
|
|
894
1056
|
deactivate: function deactivate(deactivateOptions) {
|
|
@@ -902,6 +1064,15 @@
|
|
|
902
1064
|
}, deactivateOptions);
|
|
903
1065
|
clearTimeout(state.delayInitialFocusTimer); // noop if undefined
|
|
904
1066
|
state.delayInitialFocusTimer = undefined;
|
|
1067
|
+
|
|
1068
|
+
// Prior to removing this trap from the trapStack, we need to remove any applications of `inert`.
|
|
1069
|
+
// This allows the next trap down to update its tabbable nodes properly.
|
|
1070
|
+
//
|
|
1071
|
+
// If this trap is not top of the stack, don't change any current isolation.
|
|
1072
|
+
if (!state.paused) {
|
|
1073
|
+
trap._setSubtreeIsolation(false);
|
|
1074
|
+
}
|
|
1075
|
+
state.alreadyInert.clear();
|
|
905
1076
|
removeListeners();
|
|
906
1077
|
state.active = false;
|
|
907
1078
|
state.paused = false;
|
|
@@ -949,8 +1120,14 @@
|
|
|
949
1120
|
state.containers = elementsAsArray.map(function (element) {
|
|
950
1121
|
return typeof element === 'string' ? doc.querySelector(element) : element;
|
|
951
1122
|
});
|
|
1123
|
+
if (config.isolateSubtrees) {
|
|
1124
|
+
collectAdjacentElements(state.containers);
|
|
1125
|
+
}
|
|
952
1126
|
if (state.active) {
|
|
953
1127
|
updateTabbableNodes();
|
|
1128
|
+
if (config.isolateSubtrees && !state.paused) {
|
|
1129
|
+
trap._setSubtreeIsolation(true);
|
|
1130
|
+
}
|
|
954
1131
|
}
|
|
955
1132
|
updateObservedNodes();
|
|
956
1133
|
return this;
|
|
@@ -974,11 +1151,13 @@
|
|
|
974
1151
|
onPause === null || onPause === void 0 || onPause();
|
|
975
1152
|
removeListeners();
|
|
976
1153
|
updateObservedNodes();
|
|
1154
|
+
trap._setSubtreeIsolation(false);
|
|
977
1155
|
onPostPause === null || onPostPause === void 0 || onPostPause();
|
|
978
1156
|
} else {
|
|
979
1157
|
var onUnpause = getOption(options, 'onUnpause');
|
|
980
1158
|
var onPostUnpause = getOption(options, 'onPostUnpause');
|
|
981
1159
|
onUnpause === null || onUnpause === void 0 || onUnpause();
|
|
1160
|
+
trap._setSubtreeIsolation(true);
|
|
982
1161
|
updateTabbableNodes();
|
|
983
1162
|
addListeners();
|
|
984
1163
|
updateObservedNodes();
|
|
@@ -986,6 +1165,27 @@
|
|
|
986
1165
|
}
|
|
987
1166
|
return this;
|
|
988
1167
|
}
|
|
1168
|
+
},
|
|
1169
|
+
_setSubtreeIsolation: {
|
|
1170
|
+
value: function value(isEnabled) {
|
|
1171
|
+
if (config.isolateSubtrees) {
|
|
1172
|
+
state.adjacentElements.forEach(function (el) {
|
|
1173
|
+
if (isEnabled) {
|
|
1174
|
+
// check both attribute and property to ensure initial state is captured
|
|
1175
|
+
// correctly across different browsers and test environments (like JSDOM)
|
|
1176
|
+
var isInitiallyInert = el.inert || el.hasAttribute('inert');
|
|
1177
|
+
if (isInitiallyInert) {
|
|
1178
|
+
state.alreadyInert.add(el);
|
|
1179
|
+
}
|
|
1180
|
+
el.inert = true;
|
|
1181
|
+
} else {
|
|
1182
|
+
if (state.alreadyInert.has(el)) ; else {
|
|
1183
|
+
el.inert = false;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
989
1189
|
}
|
|
990
1190
|
});
|
|
991
1191
|
|