focus-trap 8.1.0 → 8.2.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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * focus-trap 8.1.0
2
+ * focus-trap 8.2.1
3
3
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
4
4
  */
5
5
  'use strict';
@@ -14,31 +14,6 @@ function _arrayLikeToArray(r, a) {
14
14
  function _arrayWithoutHoles(r) {
15
15
  if (Array.isArray(r)) return _arrayLikeToArray(r);
16
16
  }
17
- function asyncGeneratorStep(n, t, e, r, o, a, c) {
18
- try {
19
- var i = n[a](c),
20
- u = i.value;
21
- } catch (n) {
22
- return void e(n);
23
- }
24
- i.done ? t(u) : Promise.resolve(u).then(r, o);
25
- }
26
- function _asyncToGenerator(n) {
27
- return function () {
28
- var t = this,
29
- e = arguments;
30
- return new Promise(function (r, o) {
31
- var a = n.apply(t, e);
32
- function _next(n) {
33
- asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
34
- }
35
- function _throw(n) {
36
- asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
37
- }
38
- _next(void 0);
39
- });
40
- };
41
- }
42
17
  function _createForOfIteratorHelper(r, e) {
43
18
  var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
44
19
  if (!t) {
@@ -122,114 +97,6 @@ function _objectSpread2(e) {
122
97
  }
123
98
  return e;
124
99
  }
125
- function _regenerator() {
126
- /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
127
- var e,
128
- t,
129
- r = "function" == typeof Symbol ? Symbol : {},
130
- n = r.iterator || "@@iterator",
131
- o = r.toStringTag || "@@toStringTag";
132
- function i(r, n, o, i) {
133
- var c = n && n.prototype instanceof Generator ? n : Generator,
134
- u = Object.create(c.prototype);
135
- return _regeneratorDefine(u, "_invoke", function (r, n, o) {
136
- var i,
137
- c,
138
- u,
139
- f = 0,
140
- p = o || [],
141
- y = false,
142
- G = {
143
- p: 0,
144
- n: 0,
145
- v: e,
146
- a: d,
147
- f: d.bind(e, 4),
148
- d: function (t, r) {
149
- return i = t, c = 0, u = e, G.n = r, a;
150
- }
151
- };
152
- function d(r, n) {
153
- for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
154
- var o,
155
- i = p[t],
156
- d = G.p,
157
- l = i[2];
158
- 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));
159
- }
160
- if (o || r > 1) return a;
161
- throw y = true, n;
162
- }
163
- return function (o, p, l) {
164
- if (f > 1) throw TypeError("Generator is already running");
165
- for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
166
- i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
167
- try {
168
- if (f = 2, i) {
169
- if (c || (o = "next"), t = i[o]) {
170
- if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
171
- if (!t.done) return t;
172
- u = t.value, c < 2 && (c = 0);
173
- } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
174
- i = e;
175
- } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
176
- } catch (t) {
177
- i = e, c = 1, u = t;
178
- } finally {
179
- f = 1;
180
- }
181
- }
182
- return {
183
- value: t,
184
- done: y
185
- };
186
- };
187
- }(r, o, i), true), u;
188
- }
189
- var a = {};
190
- function Generator() {}
191
- function GeneratorFunction() {}
192
- function GeneratorFunctionPrototype() {}
193
- t = Object.getPrototypeOf;
194
- var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () {
195
- return this;
196
- }), t),
197
- u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
198
- function f(e) {
199
- return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
200
- }
201
- 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 () {
202
- return this;
203
- }), _regeneratorDefine(u, "toString", function () {
204
- return "[object Generator]";
205
- }), (_regenerator = function () {
206
- return {
207
- w: i,
208
- m: f
209
- };
210
- })();
211
- }
212
- function _regeneratorDefine(e, r, n, t) {
213
- var i = Object.defineProperty;
214
- try {
215
- i({}, "", {});
216
- } catch (e) {
217
- i = 0;
218
- }
219
- _regeneratorDefine = function (e, r, n, t) {
220
- function o(r, n) {
221
- _regeneratorDefine(e, r, function (e) {
222
- return this._invoke(r, n, e);
223
- });
224
- }
225
- r ? i ? i(e, r, {
226
- value: n,
227
- enumerable: !t,
228
- configurable: !t,
229
- writable: !t
230
- }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2));
231
- }, _regeneratorDefine(e, r, n, t);
232
- }
233
100
  function _toConsumableArray(r) {
234
101
  return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
235
102
  }
@@ -358,6 +225,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
358
225
  returnFocusOnDeactivate: true,
359
226
  escapeDeactivates: true,
360
227
  delayInitialFocus: true,
228
+ delayReturnFocus: true,
361
229
  isolateSubtrees: false,
362
230
  isKeyForward: isKeyForward,
363
231
  isKeyBackward: isKeyBackward
@@ -507,6 +375,25 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
507
375
  }
508
376
  return node;
509
377
  };
378
+
379
+ /**
380
+ * Gets the current activeElement. If it's a web-component and has open shadow-root
381
+ * it will recursively search inside shadow roots for the "true" activeElement.
382
+ *
383
+ * @param {Document | ShadowRoot} el
384
+ *
385
+ * @returns {HTMLElement|null} The element that currently has the focus. `null` if a focused element isn't found.
386
+ **/
387
+ var _getActiveElement = function getActiveElement(el) {
388
+ var activeElement = el.activeElement;
389
+ if (!activeElement) {
390
+ return null;
391
+ }
392
+ if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
393
+ return _getActiveElement(activeElement.shadowRoot);
394
+ }
395
+ return activeElement;
396
+ };
510
397
  var getInitialFocusNode = function getInitialFocusNode() {
511
398
  var node = getNodeForOption('initialFocus', {
512
399
  hasFallback: true
@@ -517,9 +404,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
517
404
  return false;
518
405
  }
519
406
  if (node === undefined || node && !tabbable.isFocusable(node, config.tabbableOptions)) {
407
+ var activeElement = _getActiveElement(doc);
408
+
520
409
  // option not specified nor focusable: use fallback options
521
- if (findContainerIndex(doc.activeElement) >= 0) {
522
- node = doc.activeElement;
410
+ if (findContainerIndex(activeElement) >= 0) {
411
+ node = activeElement;
523
412
  } else {
524
413
  var firstTabbableGroup = state.tabbableGroups[0];
525
414
  var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode;
@@ -631,25 +520,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
631
520
  throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.");
632
521
  }
633
522
  };
634
-
635
- /**
636
- * Gets the current activeElement. If it's a web-component and has open shadow-root
637
- * it will recursively search inside shadow roots for the "true" activeElement.
638
- *
639
- * @param {Document | ShadowRoot} el
640
- *
641
- * @returns {HTMLElement} The element that currently has the focus
642
- **/
643
- var _getActiveElement = function getActiveElement(el) {
644
- var activeElement = el.activeElement;
645
- if (!activeElement) {
646
- return;
647
- }
648
- if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
649
- return _getActiveElement(activeElement.shadowRoot);
650
- }
651
- return activeElement;
652
- };
653
523
  var _tryFocus = function tryFocus(node) {
654
524
  if (node === false) {
655
525
  return;
@@ -970,12 +840,13 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
970
840
  /**
971
841
  * Adds listeners to the document necessary for trapping focus and attempts to set focus
972
842
  * to the configured initial focus node. Does nothing if the trap isn't active.
973
- * @returns {Promise<void>} Resolved (always) once the initial focus node has been focused.
974
- * Also resolved if the trap isn't active.
843
+ * @returns {Promise<void> | undefined} A promise resolved once the initial focus node has
844
+ * been focused when `delayInitialFocus=true`; `undefined` when focus is set synchronously
845
+ * or the trap isn't active.
975
846
  */
976
847
  var addListeners = function addListeners() {
977
848
  if (!state.active) {
978
- return Promise.resolve();
849
+ return;
979
850
  }
980
851
 
981
852
  // There can be only one listening focus trap at a time
@@ -983,7 +854,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
983
854
 
984
855
  // Delay ensures that the focused element doesn't capture the event
985
856
  // that caused the focus trap activation.
986
- /** @type {Promise<void>} */
857
+ /** @type {Promise<void> | undefined} */
987
858
  var promise;
988
859
  if (config.delayInitialFocus) {
989
860
  // NOTE: Promise constructor callback is called synchronously, which is what we want
@@ -995,7 +866,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
995
866
  });
996
867
  });
997
868
  } else {
998
- promise = Promise.resolve();
999
869
  _tryFocus(getInitialFocusNode());
1000
870
  }
1001
871
  doc.addEventListener('focusin', checkFocusIn, true);
@@ -1104,17 +974,27 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1104
974
  //
1105
975
 
1106
976
  var checkDomRemoval = function checkDomRemoval(mutations) {
977
+ var focusedNode = state.mostRecentlyFocusedNode;
978
+ if (!focusedNode) {
979
+ return;
980
+ }
1107
981
  var isFocusedNodeRemoved = mutations.some(function (mutation) {
1108
982
  var removedNodes = Array.from(mutation.removedNodes);
1109
983
  return removedNodes.some(function (node) {
1110
- return node === state.mostRecentlyFocusedNode;
984
+ return node === focusedNode || typeof node.contains === 'function' && node.contains(focusedNode);
1111
985
  });
1112
986
  });
1113
987
 
1114
- // If the currently focused is removed then browsers will move focus to the
988
+ // If the currently focused node is removed then browsers will move focus to the
1115
989
  // <body> element. If this happens, try to move focus back into the trap.
1116
- if (isFocusedNodeRemoved) {
1117
- _tryFocus(getInitialFocusNode());
990
+ if (isFocusedNodeRemoved && state.containers.some(function (container) {
991
+ return container === null || container === void 0 ? void 0 : container.isConnected;
992
+ })) {
993
+ // Refresh tabbable state before resolving initial focus because
994
+ // getInitialFocusNode() may fall back to the first tabbable node in the trap.
995
+ updateTabbableNodes();
996
+ var initialFocusNode = getInitialFocusNode();
997
+ _tryFocus(initialFocusNode);
1118
998
  }
1119
999
  };
1120
1000
 
@@ -1177,37 +1057,30 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1177
1057
  onActivate === null || onActivate === void 0 || onActivate({
1178
1058
  trap: trap
1179
1059
  });
1180
- var finishActivation = /*#__PURE__*/function () {
1181
- var _ref6 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
1182
- return _regenerator().w(function (_context) {
1183
- while (1) switch (_context.n) {
1184
- case 0:
1185
- if (checkCanFocusTrap) {
1186
- updateTabbableNodes();
1187
- }
1188
-
1189
- // NOTE: wait for initial focus node to get focused before we potentially isolate
1190
- // the subtrees with aria-hidden while focus is still in some other subtree and
1191
- // not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
1192
- // console that they, "Blocked aria-hidden on an element because its descendant
1193
- // retained focus..."
1194
- _context.n = 1;
1195
- return addListeners();
1196
- case 1:
1197
- trap._setSubtreeIsolation(true);
1198
- updateObservedNodes();
1199
- onPostActivate === null || onPostActivate === void 0 || onPostActivate({
1200
- trap: trap
1201
- });
1202
- case 2:
1203
- return _context.a(2);
1204
- }
1205
- }, _callee);
1206
- }));
1207
- return function finishActivation() {
1208
- return _ref6.apply(this, arguments);
1060
+ var finishActivation = function finishActivation() {
1061
+ if (checkCanFocusTrap) {
1062
+ updateTabbableNodes();
1063
+ }
1064
+ var afterListeners = function afterListeners() {
1065
+ trap._setSubtreeIsolation(true);
1066
+ updateObservedNodes();
1067
+ onPostActivate === null || onPostActivate === void 0 || onPostActivate({
1068
+ trap: trap
1069
+ });
1209
1070
  };
1210
- }();
1071
+
1072
+ // NOTE: wait for initial focus node to get focused (whether activation is fully,
1073
+ // partially, or not asynchronous) before we potentially isolate the subtrees
1074
+ // with aria-hidden while focus is still in some other subtree and not yet in
1075
+ // the trap, resulting in some browsers (e.g. Chrome) logging to the console that
1076
+ // they, "Blocked aria-hidden on an element because its descendant retained focus..."
1077
+ var listenersPromise = addListeners();
1078
+ if (listenersPromise) {
1079
+ listenersPromise.then(afterListeners);
1080
+ } else {
1081
+ afterListeners();
1082
+ }
1083
+ };
1211
1084
  if (checkCanFocusTrap) {
1212
1085
  checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
1213
1086
  return this;
@@ -1255,20 +1128,26 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1255
1128
  var onDeactivate = getOption(options, 'onDeactivate');
1256
1129
  var onPostDeactivate = getOption(options, 'onPostDeactivate');
1257
1130
  var checkCanReturnFocus = getOption(options, 'checkCanReturnFocus');
1131
+ var delayReturnFocus = getOption(options, 'delayReturnFocus');
1258
1132
  var returnFocus = getOption(options, 'returnFocus', 'returnFocusOnDeactivate');
1259
1133
  onDeactivate === null || onDeactivate === void 0 || onDeactivate({
1260
1134
  trap: trap
1261
1135
  });
1262
- var finishDeactivation = function finishDeactivation() {
1263
- delay(function () {
1264
- if (returnFocus) {
1265
- _tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
1266
- }
1267
- onPostDeactivate === null || onPostDeactivate === void 0 || onPostDeactivate({
1268
- trap: trap
1269
- });
1136
+ var completeDeactivation = function completeDeactivation() {
1137
+ if (returnFocus) {
1138
+ _tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
1139
+ }
1140
+ onPostDeactivate === null || onPostDeactivate === void 0 || onPostDeactivate({
1141
+ trap: trap
1270
1142
  });
1271
1143
  };
1144
+ var finishDeactivation = function finishDeactivation() {
1145
+ if (delayReturnFocus && returnFocus) {
1146
+ delay(completeDeactivation);
1147
+ } else {
1148
+ completeDeactivation();
1149
+ }
1150
+ };
1272
1151
  if (returnFocus && checkCanReturnFocus) {
1273
1152
  checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation);
1274
1153
  return this;
@@ -1341,35 +1220,28 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1341
1220
  onUnpause === null || onUnpause === void 0 || onUnpause({
1342
1221
  trap: trap
1343
1222
  });
1344
- var finishUnpause = /*#__PURE__*/function () {
1345
- var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
1346
- return _regenerator().w(function (_context2) {
1347
- while (1) switch (_context2.n) {
1348
- case 0:
1349
- updateTabbableNodes();
1350
-
1351
- // NOTE: wait for initial focus node to get focused before we potentially isolate
1352
- // the subtrees with aria-hidden while focus is still in some other subtree and
1353
- // not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
1354
- // console that they, "Blocked aria-hidden on an element because its descendant
1355
- // retained focus..."
1356
- _context2.n = 1;
1357
- return addListeners();
1358
- case 1:
1359
- trap._setSubtreeIsolation(true);
1360
- updateObservedNodes();
1361
- onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause({
1362
- trap: trap
1363
- });
1364
- case 2:
1365
- return _context2.a(2);
1366
- }
1367
- }, _callee2);
1368
- }));
1369
- return function finishUnpause() {
1370
- return _ref7.apply(this, arguments);
1223
+ var finishUnpause = function finishUnpause() {
1224
+ updateTabbableNodes();
1225
+ var afterListeners = function afterListeners() {
1226
+ trap._setSubtreeIsolation(true);
1227
+ updateObservedNodes();
1228
+ onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause({
1229
+ trap: trap
1230
+ });
1371
1231
  };
1372
- }();
1232
+
1233
+ // NOTE: wait for initial focus node to get focused (whether activation is fully,
1234
+ // partially, or not asynchronous) before we potentially isolate the subtrees
1235
+ // with aria-hidden while focus is still in some other subtree and not yet in
1236
+ // the trap, resulting in some browsers (e.g. Chrome) logging to the console that
1237
+ // they, "Blocked aria-hidden on an element because its descendant retained focus..."
1238
+ var listenersPromise = addListeners();
1239
+ if (listenersPromise) {
1240
+ listenersPromise.then(afterListeners);
1241
+ } else {
1242
+ afterListeners();
1243
+ }
1244
+ };
1373
1245
  finishUnpause();
1374
1246
  }
1375
1247
  return this;