focus-trap 7.6.6 → 7.7.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/CHANGELOG.md +12 -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 +32 -22
package/dist/focus-trap.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 7.
|
|
2
|
+
* focus-trap 7.7.1
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
@@ -14,6 +14,54 @@ function _arrayLikeToArray(r, a) {
|
|
|
14
14
|
function _arrayWithoutHoles(r) {
|
|
15
15
|
if (Array.isArray(r)) return _arrayLikeToArray(r);
|
|
16
16
|
}
|
|
17
|
+
function _createForOfIteratorHelper(r, e) {
|
|
18
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
19
|
+
if (!t) {
|
|
20
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
|
|
21
|
+
t && (r = t);
|
|
22
|
+
var n = 0,
|
|
23
|
+
F = function () {};
|
|
24
|
+
return {
|
|
25
|
+
s: F,
|
|
26
|
+
n: function () {
|
|
27
|
+
return n >= r.length ? {
|
|
28
|
+
done: true
|
|
29
|
+
} : {
|
|
30
|
+
done: false,
|
|
31
|
+
value: r[n++]
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
e: function (r) {
|
|
35
|
+
throw r;
|
|
36
|
+
},
|
|
37
|
+
f: F
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
41
|
+
}
|
|
42
|
+
var o,
|
|
43
|
+
a = true,
|
|
44
|
+
u = false;
|
|
45
|
+
return {
|
|
46
|
+
s: function () {
|
|
47
|
+
t = t.call(r);
|
|
48
|
+
},
|
|
49
|
+
n: function () {
|
|
50
|
+
var r = t.next();
|
|
51
|
+
return a = r.done, r;
|
|
52
|
+
},
|
|
53
|
+
e: function (r) {
|
|
54
|
+
u = true, o = r;
|
|
55
|
+
},
|
|
56
|
+
f: function () {
|
|
57
|
+
try {
|
|
58
|
+
a || null == t.return || t.return();
|
|
59
|
+
} finally {
|
|
60
|
+
if (u) throw o;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
17
65
|
function _defineProperty(e, r, t) {
|
|
18
66
|
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
19
67
|
value: t,
|
|
@@ -75,12 +123,18 @@ function _unsupportedIterableToArray(r, a) {
|
|
|
75
123
|
}
|
|
76
124
|
|
|
77
125
|
var activeFocusTraps = {
|
|
126
|
+
// Returns the trap from the top of the stack.
|
|
127
|
+
getActiveTrap: function getActiveTrap(trapStack) {
|
|
128
|
+
if ((trapStack === null || trapStack === void 0 ? void 0 : trapStack.length) > 0) {
|
|
129
|
+
return trapStack[trapStack.length - 1];
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
},
|
|
133
|
+
// Pauses the currently active trap, then adds a new trap to the stack.
|
|
78
134
|
activateTrap: function activateTrap(trapStack, trap) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
activeTrap._setPausedState(true);
|
|
83
|
-
}
|
|
135
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
136
|
+
if (trap !== activeTrap) {
|
|
137
|
+
activeFocusTraps.pauseTrap(trapStack);
|
|
84
138
|
}
|
|
85
139
|
var trapIndex = trapStack.indexOf(trap);
|
|
86
140
|
if (trapIndex === -1) {
|
|
@@ -91,13 +145,24 @@ var activeFocusTraps = {
|
|
|
91
145
|
trapStack.push(trap);
|
|
92
146
|
}
|
|
93
147
|
},
|
|
148
|
+
// Removes the trap from the top of the stack, then unpauses the next trap down.
|
|
94
149
|
deactivateTrap: function deactivateTrap(trapStack, trap) {
|
|
95
150
|
var trapIndex = trapStack.indexOf(trap);
|
|
96
151
|
if (trapIndex !== -1) {
|
|
97
152
|
trapStack.splice(trapIndex, 1);
|
|
98
153
|
}
|
|
99
|
-
|
|
100
|
-
|
|
154
|
+
activeFocusTraps.unpauseTrap(trapStack);
|
|
155
|
+
},
|
|
156
|
+
// Pauses the trap at the top of the stack.
|
|
157
|
+
pauseTrap: function pauseTrap(trapStack) {
|
|
158
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
159
|
+
activeTrap === null || activeTrap === void 0 || activeTrap._setPausedState(true);
|
|
160
|
+
},
|
|
161
|
+
// Unpauses the trap at the top of the stack.
|
|
162
|
+
unpauseTrap: function unpauseTrap(trapStack) {
|
|
163
|
+
var activeTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
164
|
+
if (activeTrap && !activeTrap._isManuallyPaused()) {
|
|
165
|
+
activeTrap._setPausedState(false);
|
|
101
166
|
}
|
|
102
167
|
}
|
|
103
168
|
};
|
|
@@ -160,29 +225,31 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
160
225
|
returnFocusOnDeactivate: true,
|
|
161
226
|
escapeDeactivates: true,
|
|
162
227
|
delayInitialFocus: true,
|
|
228
|
+
isolateSubtrees: false,
|
|
163
229
|
isKeyForward: isKeyForward,
|
|
164
230
|
isKeyBackward: isKeyBackward
|
|
165
231
|
}, userOptions);
|
|
166
232
|
var state = {
|
|
167
233
|
// containers given to createFocusTrap()
|
|
168
|
-
|
|
234
|
+
/** @type {Array<HTMLElement>} */
|
|
169
235
|
containers: [],
|
|
170
236
|
// list of objects identifying tabbable nodes in `containers` in the trap
|
|
171
237
|
// NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap
|
|
172
238
|
// is active, but the trap should never get to a state where there isn't at least one group
|
|
173
239
|
// with at least one tabbable node in it (that would lead to an error condition that would
|
|
174
240
|
// result in an error being thrown)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
241
|
+
/** @type {Array<{
|
|
242
|
+
* container: HTMLElement,
|
|
243
|
+
* tabbableNodes: Array<HTMLElement>, // empty if none
|
|
244
|
+
* focusableNodes: Array<HTMLElement>, // empty if none
|
|
245
|
+
* posTabIndexesFound: boolean,
|
|
246
|
+
* firstTabbableNode: HTMLElement|undefined,
|
|
247
|
+
* lastTabbableNode: HTMLElement|undefined,
|
|
248
|
+
* firstDomTabbableNode: HTMLElement|undefined,
|
|
249
|
+
* lastDomTabbableNode: HTMLElement|undefined,
|
|
250
|
+
* nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
|
|
251
|
+
* }>}
|
|
252
|
+
*/
|
|
186
253
|
containerGroups: [],
|
|
187
254
|
// same order/length as `containers` list
|
|
188
255
|
|
|
@@ -191,6 +258,12 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
191
258
|
// NOTE: same order as `containers` and `containerGroups`, but __not necessarily__
|
|
192
259
|
// the same length
|
|
193
260
|
tabbableGroups: [],
|
|
261
|
+
// references to nodes that are siblings to the ancestors of this trap's containers.
|
|
262
|
+
/** @type {Set<HTMLElement>} */
|
|
263
|
+
adjacentElements: new Set(),
|
|
264
|
+
// references to nodes that were inert before the trap was activated.
|
|
265
|
+
/** @type {Set<HTMLElement>} */
|
|
266
|
+
alreadyInert: new Set(),
|
|
194
267
|
nodeFocusedBeforeActivation: null,
|
|
195
268
|
mostRecentlyFocusedNode: null,
|
|
196
269
|
active: false,
|
|
@@ -794,6 +867,74 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
794
867
|
doc.addEventListener('keydown', checkEscapeKey);
|
|
795
868
|
return trap;
|
|
796
869
|
};
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* Traverses up the DOM from each of `containers`, collecting references to
|
|
873
|
+
* the elements that are siblings to `container` or an ancestor of `container`.
|
|
874
|
+
* @param {Array<HTMLElement>} containers
|
|
875
|
+
*/
|
|
876
|
+
var collectAdjacentElements = function collectAdjacentElements(containers) {
|
|
877
|
+
// Re-activate all adjacent elements & clear previous collection.
|
|
878
|
+
if (state.active && !state.paused) {
|
|
879
|
+
trap._setSubtreeIsolation(false);
|
|
880
|
+
}
|
|
881
|
+
state.adjacentElements.clear();
|
|
882
|
+
state.alreadyInert.clear();
|
|
883
|
+
|
|
884
|
+
// Collect all ancestors of all containers to avoid redundant processing.
|
|
885
|
+
var containerAncestors = new Set();
|
|
886
|
+
var adjacentElements = new Set();
|
|
887
|
+
|
|
888
|
+
// Compile all elements adjacent to the focus trap containers & lineage.
|
|
889
|
+
var _iterator = _createForOfIteratorHelper(containers),
|
|
890
|
+
_step;
|
|
891
|
+
try {
|
|
892
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
893
|
+
var container = _step.value;
|
|
894
|
+
containerAncestors.add(container);
|
|
895
|
+
var insideShadowRoot = typeof ShadowRoot !== 'undefined' && container.getRootNode() instanceof ShadowRoot;
|
|
896
|
+
var current = container;
|
|
897
|
+
while (current) {
|
|
898
|
+
containerAncestors.add(current);
|
|
899
|
+
var parent = current.parentElement;
|
|
900
|
+
var siblings = [];
|
|
901
|
+
if (parent) {
|
|
902
|
+
siblings = parent.children;
|
|
903
|
+
} else if (!parent && insideShadowRoot) {
|
|
904
|
+
siblings = current.getRootNode().children;
|
|
905
|
+
parent = current.getRootNode().host;
|
|
906
|
+
insideShadowRoot = typeof ShadowRoot !== 'undefined' && parent.getRootNode() instanceof ShadowRoot;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Add all the children, we'll remove container lineage later.
|
|
910
|
+
var _iterator2 = _createForOfIteratorHelper(siblings),
|
|
911
|
+
_step2;
|
|
912
|
+
try {
|
|
913
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
914
|
+
var child = _step2.value;
|
|
915
|
+
adjacentElements.add(child);
|
|
916
|
+
}
|
|
917
|
+
} catch (err) {
|
|
918
|
+
_iterator2.e(err);
|
|
919
|
+
} finally {
|
|
920
|
+
_iterator2.f();
|
|
921
|
+
}
|
|
922
|
+
current = parent;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Multi-container traps may overlap.
|
|
927
|
+
// Remove elements within container lineages.
|
|
928
|
+
} catch (err) {
|
|
929
|
+
_iterator.e(err);
|
|
930
|
+
} finally {
|
|
931
|
+
_iterator.f();
|
|
932
|
+
}
|
|
933
|
+
containerAncestors.forEach(function (el) {
|
|
934
|
+
adjacentElements["delete"](el);
|
|
935
|
+
});
|
|
936
|
+
state.adjacentElements = adjacentElements;
|
|
937
|
+
};
|
|
797
938
|
var removeListeners = function removeListeners() {
|
|
798
939
|
if (!state.active) {
|
|
799
940
|
return;
|
|
@@ -862,26 +1003,47 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
862
1003
|
var onActivate = getOption(activateOptions, 'onActivate');
|
|
863
1004
|
var onPostActivate = getOption(activateOptions, 'onPostActivate');
|
|
864
1005
|
var checkCanFocusTrap = getOption(activateOptions, 'checkCanFocusTrap');
|
|
865
|
-
|
|
866
|
-
|
|
1006
|
+
|
|
1007
|
+
// If a currently-active trap is isolating its subtree, we need to remove
|
|
1008
|
+
// that isolation to allow the new trap to find tabbable nodes.
|
|
1009
|
+
var preexistingTrap = activeFocusTraps.getActiveTrap(trapStack);
|
|
1010
|
+
var revertState = false;
|
|
1011
|
+
if (preexistingTrap && !preexistingTrap.paused) {
|
|
1012
|
+
preexistingTrap._setSubtreeIsolation(false);
|
|
1013
|
+
revertState = true;
|
|
867
1014
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
state.nodeFocusedBeforeActivation = _getActiveElement(doc);
|
|
871
|
-
onActivate === null || onActivate === void 0 || onActivate();
|
|
872
|
-
var finishActivation = function finishActivation() {
|
|
873
|
-
if (checkCanFocusTrap) {
|
|
1015
|
+
try {
|
|
1016
|
+
if (!checkCanFocusTrap) {
|
|
874
1017
|
updateTabbableNodes();
|
|
875
1018
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1019
|
+
state.active = true;
|
|
1020
|
+
state.paused = false;
|
|
1021
|
+
state.nodeFocusedBeforeActivation = _getActiveElement(doc);
|
|
1022
|
+
onActivate === null || onActivate === void 0 || onActivate();
|
|
1023
|
+
var finishActivation = function finishActivation() {
|
|
1024
|
+
if (checkCanFocusTrap) {
|
|
1025
|
+
updateTabbableNodes();
|
|
1026
|
+
}
|
|
1027
|
+
addListeners();
|
|
1028
|
+
updateObservedNodes();
|
|
1029
|
+
if (config.isolateSubtrees) {
|
|
1030
|
+
trap._setSubtreeIsolation(true);
|
|
1031
|
+
}
|
|
1032
|
+
onPostActivate === null || onPostActivate === void 0 || onPostActivate();
|
|
1033
|
+
};
|
|
1034
|
+
if (checkCanFocusTrap) {
|
|
1035
|
+
checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
|
|
1036
|
+
return this;
|
|
1037
|
+
}
|
|
1038
|
+
finishActivation();
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
// If our activation throws an exception and the stack hasn't changed,
|
|
1041
|
+
// we need to re-enable the prior trap's subtree isolation.
|
|
1042
|
+
if (preexistingTrap === activeFocusTraps.getActiveTrap(trapStack) && revertState) {
|
|
1043
|
+
preexistingTrap._setSubtreeIsolation(true);
|
|
1044
|
+
}
|
|
1045
|
+
throw error;
|
|
883
1046
|
}
|
|
884
|
-
finishActivation();
|
|
885
1047
|
return this;
|
|
886
1048
|
},
|
|
887
1049
|
deactivate: function deactivate(deactivateOptions) {
|
|
@@ -895,6 +1057,15 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
895
1057
|
}, deactivateOptions);
|
|
896
1058
|
clearTimeout(state.delayInitialFocusTimer); // noop if undefined
|
|
897
1059
|
state.delayInitialFocusTimer = undefined;
|
|
1060
|
+
|
|
1061
|
+
// Prior to removing this trap from the trapStack, we need to remove any applications of `inert`.
|
|
1062
|
+
// This allows the next trap down to update its tabbable nodes properly.
|
|
1063
|
+
//
|
|
1064
|
+
// If this trap is not top of the stack, don't change any current isolation.
|
|
1065
|
+
if (!state.paused) {
|
|
1066
|
+
trap._setSubtreeIsolation(false);
|
|
1067
|
+
}
|
|
1068
|
+
state.alreadyInert.clear();
|
|
898
1069
|
removeListeners();
|
|
899
1070
|
state.active = false;
|
|
900
1071
|
state.paused = false;
|
|
@@ -942,8 +1113,14 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
942
1113
|
state.containers = elementsAsArray.map(function (element) {
|
|
943
1114
|
return typeof element === 'string' ? doc.querySelector(element) : element;
|
|
944
1115
|
});
|
|
1116
|
+
if (config.isolateSubtrees) {
|
|
1117
|
+
collectAdjacentElements(state.containers);
|
|
1118
|
+
}
|
|
945
1119
|
if (state.active) {
|
|
946
1120
|
updateTabbableNodes();
|
|
1121
|
+
if (config.isolateSubtrees && !state.paused) {
|
|
1122
|
+
trap._setSubtreeIsolation(true);
|
|
1123
|
+
}
|
|
947
1124
|
}
|
|
948
1125
|
updateObservedNodes();
|
|
949
1126
|
return this;
|
|
@@ -967,11 +1144,13 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
967
1144
|
onPause === null || onPause === void 0 || onPause();
|
|
968
1145
|
removeListeners();
|
|
969
1146
|
updateObservedNodes();
|
|
1147
|
+
trap._setSubtreeIsolation(false);
|
|
970
1148
|
onPostPause === null || onPostPause === void 0 || onPostPause();
|
|
971
1149
|
} else {
|
|
972
1150
|
var onUnpause = getOption(options, 'onUnpause');
|
|
973
1151
|
var onPostUnpause = getOption(options, 'onPostUnpause');
|
|
974
1152
|
onUnpause === null || onUnpause === void 0 || onUnpause();
|
|
1153
|
+
trap._setSubtreeIsolation(true);
|
|
975
1154
|
updateTabbableNodes();
|
|
976
1155
|
addListeners();
|
|
977
1156
|
updateObservedNodes();
|
|
@@ -979,6 +1158,27 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
979
1158
|
}
|
|
980
1159
|
return this;
|
|
981
1160
|
}
|
|
1161
|
+
},
|
|
1162
|
+
_setSubtreeIsolation: {
|
|
1163
|
+
value: function value(isEnabled) {
|
|
1164
|
+
if (config.isolateSubtrees) {
|
|
1165
|
+
state.adjacentElements.forEach(function (el) {
|
|
1166
|
+
if (isEnabled) {
|
|
1167
|
+
// check both attribute and property to ensure initial state is captured
|
|
1168
|
+
// correctly across different browsers and test environments (like JSDOM)
|
|
1169
|
+
var isInitiallyInert = el.inert || el.hasAttribute('inert');
|
|
1170
|
+
if (isInitiallyInert) {
|
|
1171
|
+
state.alreadyInert.add(el);
|
|
1172
|
+
}
|
|
1173
|
+
el.inert = true;
|
|
1174
|
+
} else {
|
|
1175
|
+
if (state.alreadyInert.has(el)) ; else {
|
|
1176
|
+
el.inert = false;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
982
1182
|
}
|
|
983
1183
|
});
|
|
984
1184
|
|