focus-trap 7.8.0 → 8.0.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 +11 -0
- package/dist/focus-trap.esm.js +217 -25
- package/dist/focus-trap.esm.js.map +1 -1
- package/dist/focus-trap.esm.min.js +4 -2
- package/dist/focus-trap.esm.min.js.map +1 -1
- package/dist/focus-trap.js +216 -24
- package/dist/focus-trap.js.map +1 -1
- package/dist/focus-trap.min.js +4 -2
- package/dist/focus-trap.min.js.map +1 -1
- package/dist/focus-trap.umd.js +216 -24
- package/dist/focus-trap.umd.js.map +1 -1
- package/dist/focus-trap.umd.min.js +4 -2
- package/dist/focus-trap.umd.min.js.map +1 -1
- package/index.js +50 -19
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- b6ea4b5: **Breaking:** Fixed a long-standing bug where `onPostActivate()` would be called _before_ the initial focus node was focused and the trap was fully activated. ([#1747](https://github.com/focus-trap/focus-trap/issues/1747))
|
|
8
|
+
- By default (and for many years now), a trap delays setting focus to the initial focus node to the next frame (`setTimeout(0)`) but wasn't delaying calling `onPostActivate()` until after that delay.
|
|
9
|
+
- With the new `isolateSubtrees='aria-hidden'` option, the currently-focused node's container (a non-subtree being "disabled") would get hidden before the delay was up, resulting in Chrome preventing the effect of `aria-hidden` on that subtree with a warning in the console due to the container being hidden still containing focus (e.g. the "activate trap" button).
|
|
10
|
+
- **With the fix**, subtree isolation and the call to `onPostActivate()` await the initial focus delay (if there is one, which is default behavior; remove it with `delayInitialFocus=false`) before being applied/called.
|
|
11
|
+
- This may cause tests to fail, requiring the addition of slight delays before testing a given state (e.g. `await waitFor(() => expect(initialFocusNode).toBeFocused())`.
|
|
12
|
+
- It may also disrupt current assumptions about the state of the initial focus node in code that runs in your `onPostActivate()` handler (prior to this change, that node would **not** be focused yet; after this change, **it will be focused**).
|
|
13
|
+
|
|
3
14
|
## 7.8.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/dist/focus-trap.esm.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap
|
|
2
|
+
* focus-trap 8.0.0
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
|
-
import { tabbable, focusable, isTabbable, getTabIndex
|
|
5
|
+
import { isFocusable, tabbable, focusable, isTabbable, getTabIndex } from 'tabbable';
|
|
6
6
|
|
|
7
7
|
function _arrayLikeToArray(r, a) {
|
|
8
8
|
(null == a || a > r.length) && (a = r.length);
|
|
@@ -12,6 +12,31 @@ function _arrayLikeToArray(r, a) {
|
|
|
12
12
|
function _arrayWithoutHoles(r) {
|
|
13
13
|
if (Array.isArray(r)) return _arrayLikeToArray(r);
|
|
14
14
|
}
|
|
15
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) {
|
|
16
|
+
try {
|
|
17
|
+
var i = n[a](c),
|
|
18
|
+
u = i.value;
|
|
19
|
+
} catch (n) {
|
|
20
|
+
return void e(n);
|
|
21
|
+
}
|
|
22
|
+
i.done ? t(u) : Promise.resolve(u).then(r, o);
|
|
23
|
+
}
|
|
24
|
+
function _asyncToGenerator(n) {
|
|
25
|
+
return function () {
|
|
26
|
+
var t = this,
|
|
27
|
+
e = arguments;
|
|
28
|
+
return new Promise(function (r, o) {
|
|
29
|
+
var a = n.apply(t, e);
|
|
30
|
+
function _next(n) {
|
|
31
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
|
|
32
|
+
}
|
|
33
|
+
function _throw(n) {
|
|
34
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
|
|
35
|
+
}
|
|
36
|
+
_next(void 0);
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
}
|
|
15
40
|
function _createForOfIteratorHelper(r, e) {
|
|
16
41
|
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
17
42
|
if (!t) {
|
|
@@ -95,6 +120,114 @@ function _objectSpread2(e) {
|
|
|
95
120
|
}
|
|
96
121
|
return e;
|
|
97
122
|
}
|
|
123
|
+
function _regenerator() {
|
|
124
|
+
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
|
125
|
+
var e,
|
|
126
|
+
t,
|
|
127
|
+
r = "function" == typeof Symbol ? Symbol : {},
|
|
128
|
+
n = r.iterator || "@@iterator",
|
|
129
|
+
o = r.toStringTag || "@@toStringTag";
|
|
130
|
+
function i(r, n, o, i) {
|
|
131
|
+
var c = n && n.prototype instanceof Generator ? n : Generator,
|
|
132
|
+
u = Object.create(c.prototype);
|
|
133
|
+
return _regeneratorDefine(u, "_invoke", function (r, n, o) {
|
|
134
|
+
var i,
|
|
135
|
+
c,
|
|
136
|
+
u,
|
|
137
|
+
f = 0,
|
|
138
|
+
p = o || [],
|
|
139
|
+
y = false,
|
|
140
|
+
G = {
|
|
141
|
+
p: 0,
|
|
142
|
+
n: 0,
|
|
143
|
+
v: e,
|
|
144
|
+
a: d,
|
|
145
|
+
f: d.bind(e, 4),
|
|
146
|
+
d: function (t, r) {
|
|
147
|
+
return i = t, c = 0, u = e, G.n = r, a;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
function d(r, n) {
|
|
151
|
+
for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
|
|
152
|
+
var o,
|
|
153
|
+
i = p[t],
|
|
154
|
+
d = G.p,
|
|
155
|
+
l = i[2];
|
|
156
|
+
r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
|
|
157
|
+
}
|
|
158
|
+
if (o || r > 1) return a;
|
|
159
|
+
throw y = true, n;
|
|
160
|
+
}
|
|
161
|
+
return function (o, p, l) {
|
|
162
|
+
if (f > 1) throw TypeError("Generator is already running");
|
|
163
|
+
for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
|
|
164
|
+
i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
|
|
165
|
+
try {
|
|
166
|
+
if (f = 2, i) {
|
|
167
|
+
if (c || (o = "next"), t = i[o]) {
|
|
168
|
+
if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
|
|
169
|
+
if (!t.done) return t;
|
|
170
|
+
u = t.value, c < 2 && (c = 0);
|
|
171
|
+
} else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
|
|
172
|
+
i = e;
|
|
173
|
+
} else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
|
|
174
|
+
} catch (t) {
|
|
175
|
+
i = e, c = 1, u = t;
|
|
176
|
+
} finally {
|
|
177
|
+
f = 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
value: t,
|
|
182
|
+
done: y
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
}(r, o, i), true), u;
|
|
186
|
+
}
|
|
187
|
+
var a = {};
|
|
188
|
+
function Generator() {}
|
|
189
|
+
function GeneratorFunction() {}
|
|
190
|
+
function GeneratorFunctionPrototype() {}
|
|
191
|
+
t = Object.getPrototypeOf;
|
|
192
|
+
var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () {
|
|
193
|
+
return this;
|
|
194
|
+
}), t),
|
|
195
|
+
u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
|
|
196
|
+
function f(e) {
|
|
197
|
+
return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
|
|
198
|
+
}
|
|
199
|
+
return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () {
|
|
200
|
+
return this;
|
|
201
|
+
}), _regeneratorDefine(u, "toString", function () {
|
|
202
|
+
return "[object Generator]";
|
|
203
|
+
}), (_regenerator = function () {
|
|
204
|
+
return {
|
|
205
|
+
w: i,
|
|
206
|
+
m: f
|
|
207
|
+
};
|
|
208
|
+
})();
|
|
209
|
+
}
|
|
210
|
+
function _regeneratorDefine(e, r, n, t) {
|
|
211
|
+
var i = Object.defineProperty;
|
|
212
|
+
try {
|
|
213
|
+
i({}, "", {});
|
|
214
|
+
} catch (e) {
|
|
215
|
+
i = 0;
|
|
216
|
+
}
|
|
217
|
+
_regeneratorDefine = function (e, r, n, t) {
|
|
218
|
+
function o(r, n) {
|
|
219
|
+
_regeneratorDefine(e, r, function (e) {
|
|
220
|
+
return this._invoke(r, n, e);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
r ? i ? i(e, r, {
|
|
224
|
+
value: n,
|
|
225
|
+
enumerable: !t,
|
|
226
|
+
configurable: !t,
|
|
227
|
+
writable: !t
|
|
228
|
+
}) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2));
|
|
229
|
+
}, _regeneratorDefine(e, r, n, t);
|
|
230
|
+
}
|
|
98
231
|
function _toConsumableArray(r) {
|
|
99
232
|
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
|
|
100
233
|
}
|
|
@@ -649,7 +782,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
649
782
|
var checkPointerDown = function checkPointerDown(e) {
|
|
650
783
|
var target = getActualTarget(e);
|
|
651
784
|
if (findContainerIndex(target, e) >= 0) {
|
|
652
|
-
// allow the click since it
|
|
785
|
+
// allow the click since it occurred inside the trap
|
|
653
786
|
return;
|
|
654
787
|
}
|
|
655
788
|
if (valueOrHandler(config.clickOutsideDeactivates, e)) {
|
|
@@ -832,9 +965,15 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
832
965
|
// EVENT LISTENERS
|
|
833
966
|
//
|
|
834
967
|
|
|
968
|
+
/**
|
|
969
|
+
* Adds listeners to the document necessary for trapping focus and attempts to set focus
|
|
970
|
+
* to the configured initial focus node. Does nothing if the trap isn't active.
|
|
971
|
+
* @returns {Promise<void>} Resolved (always) once the initial focus node has been focused.
|
|
972
|
+
* Also resolved if the trap isn't active.
|
|
973
|
+
*/
|
|
835
974
|
var addListeners = function addListeners() {
|
|
836
975
|
if (!state.active) {
|
|
837
|
-
return;
|
|
976
|
+
return Promise.resolve();
|
|
838
977
|
}
|
|
839
978
|
|
|
840
979
|
// There can be only one listening focus trap at a time
|
|
@@ -842,9 +981,21 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
842
981
|
|
|
843
982
|
// Delay ensures that the focused element doesn't capture the event
|
|
844
983
|
// that caused the focus trap activation.
|
|
845
|
-
|
|
984
|
+
/** @type {Promise<void>} */
|
|
985
|
+
var promise;
|
|
986
|
+
if (config.delayInitialFocus) {
|
|
987
|
+
// NOTE: Promise constructor callback is called synchronously, which is what we want
|
|
988
|
+
// since we need to capture the timer ID immediately
|
|
989
|
+
promise = new Promise(function (resolve) {
|
|
990
|
+
state.delayInitialFocusTimer = delay(function () {
|
|
991
|
+
_tryFocus(getInitialFocusNode());
|
|
992
|
+
resolve();
|
|
993
|
+
});
|
|
994
|
+
});
|
|
995
|
+
} else {
|
|
996
|
+
promise = Promise.resolve();
|
|
846
997
|
_tryFocus(getInitialFocusNode());
|
|
847
|
-
}
|
|
998
|
+
}
|
|
848
999
|
doc.addEventListener('focusin', checkFocusIn, true);
|
|
849
1000
|
doc.addEventListener('mousedown', checkPointerDown, {
|
|
850
1001
|
capture: true,
|
|
@@ -863,7 +1014,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
863
1014
|
passive: false
|
|
864
1015
|
});
|
|
865
1016
|
doc.addEventListener('keydown', checkEscapeKey);
|
|
866
|
-
return
|
|
1017
|
+
return promise;
|
|
867
1018
|
};
|
|
868
1019
|
|
|
869
1020
|
/**
|
|
@@ -1022,17 +1173,35 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1022
1173
|
state.paused = false;
|
|
1023
1174
|
state.nodeFocusedBeforeActivation = _getActiveElement(doc);
|
|
1024
1175
|
onActivate === null || onActivate === void 0 || onActivate();
|
|
1025
|
-
var finishActivation = function
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1176
|
+
var finishActivation = /*#__PURE__*/function () {
|
|
1177
|
+
var _ref6 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
1178
|
+
return _regenerator().w(function (_context) {
|
|
1179
|
+
while (1) switch (_context.n) {
|
|
1180
|
+
case 0:
|
|
1181
|
+
if (checkCanFocusTrap) {
|
|
1182
|
+
updateTabbableNodes();
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// NOTE: wait for initial focus node to get focused before we potentially isolate
|
|
1186
|
+
// the subtrees with aria-hidden while focus is still in some other subtree and
|
|
1187
|
+
// not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
|
|
1188
|
+
// console that they, "Blocked aria-hidden on an element because its descendant
|
|
1189
|
+
// retained focus..."
|
|
1190
|
+
_context.n = 1;
|
|
1191
|
+
return addListeners();
|
|
1192
|
+
case 1:
|
|
1193
|
+
trap._setSubtreeIsolation(true);
|
|
1194
|
+
updateObservedNodes();
|
|
1195
|
+
onPostActivate === null || onPostActivate === void 0 || onPostActivate();
|
|
1196
|
+
case 2:
|
|
1197
|
+
return _context.a(2);
|
|
1198
|
+
}
|
|
1199
|
+
}, _callee);
|
|
1200
|
+
}));
|
|
1201
|
+
return function finishActivation() {
|
|
1202
|
+
return _ref6.apply(this, arguments);
|
|
1203
|
+
};
|
|
1204
|
+
}();
|
|
1036
1205
|
if (checkCanFocusTrap) {
|
|
1037
1206
|
checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
|
|
1038
1207
|
return this;
|
|
@@ -1124,7 +1293,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1124
1293
|
}
|
|
1125
1294
|
if (state.active) {
|
|
1126
1295
|
updateTabbableNodes();
|
|
1127
|
-
if (
|
|
1296
|
+
if (!state.paused) {
|
|
1128
1297
|
trap._setSubtreeIsolation(true);
|
|
1129
1298
|
}
|
|
1130
1299
|
}
|
|
@@ -1149,18 +1318,41 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1149
1318
|
var onPostPause = getOption(options, 'onPostPause');
|
|
1150
1319
|
onPause === null || onPause === void 0 || onPause();
|
|
1151
1320
|
removeListeners();
|
|
1152
|
-
updateObservedNodes();
|
|
1153
1321
|
trap._setSubtreeIsolation(false);
|
|
1322
|
+
updateObservedNodes();
|
|
1154
1323
|
onPostPause === null || onPostPause === void 0 || onPostPause();
|
|
1155
1324
|
} else {
|
|
1156
1325
|
var onUnpause = getOption(options, 'onUnpause');
|
|
1157
1326
|
var onPostUnpause = getOption(options, 'onPostUnpause');
|
|
1158
1327
|
onUnpause === null || onUnpause === void 0 || onUnpause();
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1328
|
+
var finishUnpause = /*#__PURE__*/function () {
|
|
1329
|
+
var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
1330
|
+
return _regenerator().w(function (_context2) {
|
|
1331
|
+
while (1) switch (_context2.n) {
|
|
1332
|
+
case 0:
|
|
1333
|
+
updateTabbableNodes();
|
|
1334
|
+
|
|
1335
|
+
// NOTE: wait for initial focus node to get focused before we potentially isolate
|
|
1336
|
+
// the subtrees with aria-hidden while focus is still in some other subtree and
|
|
1337
|
+
// not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
|
|
1338
|
+
// console that they, "Blocked aria-hidden on an element because its descendant
|
|
1339
|
+
// retained focus..."
|
|
1340
|
+
_context2.n = 1;
|
|
1341
|
+
return addListeners();
|
|
1342
|
+
case 1:
|
|
1343
|
+
trap._setSubtreeIsolation(true);
|
|
1344
|
+
updateObservedNodes();
|
|
1345
|
+
onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause();
|
|
1346
|
+
case 2:
|
|
1347
|
+
return _context2.a(2);
|
|
1348
|
+
}
|
|
1349
|
+
}, _callee2);
|
|
1350
|
+
}));
|
|
1351
|
+
return function finishUnpause() {
|
|
1352
|
+
return _ref7.apply(this, arguments);
|
|
1353
|
+
};
|
|
1354
|
+
}();
|
|
1355
|
+
finishUnpause();
|
|
1164
1356
|
}
|
|
1165
1357
|
return this;
|
|
1166
1358
|
}
|