focus-trap 8.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 8.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7e0e518: Fixes lifecycle ordering bug introduced in v8.0.0 that always delays the order even if `delayInitialFocus=false`, `delayReturnFocus=false`, `checkCanFocusTrap=undefined`, `checkCanReturnFocus=undefined` (which would indicate a fully synchronous activation/pause/unpause/deactivation process) [#1862](https://github.com/focus-trap/focus-trap/issues/1862)
8
+ - 2cba31e: Improve shadow DOM focus handling for nested traps by ensuring a parent trap resumes using the innermost active element ([#1885](https://github.com/focus-trap/focus-trap/issues/1885))
9
+
3
10
  ## 8.2.0
4
11
 
5
12
  ### Minor Changes
package/README.md CHANGED
@@ -607,7 +607,7 @@ In alphabetical order:
607
607
  <td align="center" valign="top" width="14.28%"><a href="http://davidtheclark.com/"><img src="https://avatars2.githubusercontent.com/u/628431?v=4?s=100" width="100px;" alt="David Clark"/><br /><sub><b>David Clark</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=davidtheclark" title="Code">πŸ’»</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Adavidtheclark" title="Bug reports">πŸ›</a> <a href="#infra-davidtheclark" title="Infrastructure (Hosting, Build-Tools, etc)">πŸš‡</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=davidtheclark" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=davidtheclark" title="Documentation">πŸ“–</a> <a href="#maintenance-davidtheclark" title="Maintenance">🚧</a></td>
608
608
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/features/security"><img src="https://avatars1.githubusercontent.com/u/27347476?v=4?s=100" width="100px;" alt="Dependabot"/><br /><sub><b>Dependabot</b></sub></a><br /><a href="#maintenance-dependabot" title="Maintenance">🚧</a></td>
609
609
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/ShGKme"><img src="https://avatars.githubusercontent.com/u/25978914?v=4?s=100" width="100px;" alt="Grigorii K. Shartsev"/><br /><sub><b>Grigorii K. Shartsev</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3AShGKme" title="Bug reports">πŸ›</a></td>
610
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/jcfranco"><img src="https://avatars.githubusercontent.com/u/197440?v=4?s=100" width="100px;" alt="JC Franco"/><br /><sub><b>JC Franco</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=jcfranco" title="Code">πŸ’»</a></td>
610
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/jcfranco"><img src="https://avatars.githubusercontent.com/u/197440?v=4?s=100" width="100px;" alt="JC Franco"/><br /><sub><b>JC Franco</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=jcfranco" title="Code">πŸ’»</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Ajcfranco" title="Bug reports">πŸ›</a></td>
611
611
  <td align="center" valign="top" width="14.28%"><a href="https://www.schilljs.com/"><img src="https://avatars.githubusercontent.com/u/213943?v=4?s=100" width="100px;" alt="Joas Schilling"/><br /><sub><b>Joas Schilling</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/pulls?q=is%3Apr+reviewed-by%3Anickvergessen" title="Reviewed Pull Requests">πŸ‘€</a></td>
612
612
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/skjnldsv"><img src="https://avatars.githubusercontent.com/u/14975046?v=4?s=100" width="100px;" alt="John MolakvoΓ¦"/><br /><sub><b>John MolakvoΓ¦</b></sub></a><br /><a href="#ideas-skjnldsv" title="Ideas, Planning, & Feedback">πŸ€”</a></td>
613
613
  </tr>
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * focus-trap 8.2.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
  import { tabbable, focusable, isTabbable, getTabIndex, isFocusable } from 'tabbable';
@@ -12,31 +12,6 @@ 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
- }
40
15
  function _createForOfIteratorHelper(r, e) {
41
16
  var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
42
17
  if (!t) {
@@ -120,114 +95,6 @@ function _objectSpread2(e) {
120
95
  }
121
96
  return e;
122
97
  }
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
- }
231
98
  function _toConsumableArray(r) {
232
99
  return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
233
100
  }
@@ -506,6 +373,25 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
506
373
  }
507
374
  return node;
508
375
  };
376
+
377
+ /**
378
+ * Gets the current activeElement. If it's a web-component and has open shadow-root
379
+ * it will recursively search inside shadow roots for the "true" activeElement.
380
+ *
381
+ * @param {Document | ShadowRoot} el
382
+ *
383
+ * @returns {HTMLElement|null} The element that currently has the focus. `null` if a focused element isn't found.
384
+ **/
385
+ var _getActiveElement = function getActiveElement(el) {
386
+ var activeElement = el.activeElement;
387
+ if (!activeElement) {
388
+ return null;
389
+ }
390
+ if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
391
+ return _getActiveElement(activeElement.shadowRoot);
392
+ }
393
+ return activeElement;
394
+ };
509
395
  var getInitialFocusNode = function getInitialFocusNode() {
510
396
  var node = getNodeForOption('initialFocus', {
511
397
  hasFallback: true
@@ -516,9 +402,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
516
402
  return false;
517
403
  }
518
404
  if (node === undefined || node && !isFocusable(node, config.tabbableOptions)) {
405
+ var activeElement = _getActiveElement(doc);
406
+
519
407
  // option not specified nor focusable: use fallback options
520
- if (findContainerIndex(doc.activeElement) >= 0) {
521
- node = doc.activeElement;
408
+ if (findContainerIndex(activeElement) >= 0) {
409
+ node = activeElement;
522
410
  } else {
523
411
  var firstTabbableGroup = state.tabbableGroups[0];
524
412
  var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode;
@@ -630,25 +518,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
630
518
  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.");
631
519
  }
632
520
  };
633
-
634
- /**
635
- * Gets the current activeElement. If it's a web-component and has open shadow-root
636
- * it will recursively search inside shadow roots for the "true" activeElement.
637
- *
638
- * @param {Document | ShadowRoot} el
639
- *
640
- * @returns {HTMLElement} The element that currently has the focus
641
- **/
642
- var _getActiveElement = function getActiveElement(el) {
643
- var activeElement = el.activeElement;
644
- if (!activeElement) {
645
- return;
646
- }
647
- if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
648
- return _getActiveElement(activeElement.shadowRoot);
649
- }
650
- return activeElement;
651
- };
652
521
  var _tryFocus = function tryFocus(node) {
653
522
  if (node === false) {
654
523
  return;
@@ -969,12 +838,13 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
969
838
  /**
970
839
  * Adds listeners to the document necessary for trapping focus and attempts to set focus
971
840
  * to the configured initial focus node. Does nothing if the trap isn't active.
972
- * @returns {Promise<void>} Resolved (always) once the initial focus node has been focused.
973
- * Also resolved if the trap isn't active.
841
+ * @returns {Promise<void> | undefined} A promise resolved once the initial focus node has
842
+ * been focused when `delayInitialFocus=true`; `undefined` when focus is set synchronously
843
+ * or the trap isn't active.
974
844
  */
975
845
  var addListeners = function addListeners() {
976
846
  if (!state.active) {
977
- return Promise.resolve();
847
+ return;
978
848
  }
979
849
 
980
850
  // There can be only one listening focus trap at a time
@@ -982,7 +852,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
982
852
 
983
853
  // Delay ensures that the focused element doesn't capture the event
984
854
  // that caused the focus trap activation.
985
- /** @type {Promise<void>} */
855
+ /** @type {Promise<void> | undefined} */
986
856
  var promise;
987
857
  if (config.delayInitialFocus) {
988
858
  // NOTE: Promise constructor callback is called synchronously, which is what we want
@@ -994,7 +864,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
994
864
  });
995
865
  });
996
866
  } else {
997
- promise = Promise.resolve();
998
867
  _tryFocus(getInitialFocusNode());
999
868
  }
1000
869
  doc.addEventListener('focusin', checkFocusIn, true);
@@ -1186,37 +1055,30 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1186
1055
  onActivate === null || onActivate === void 0 || onActivate({
1187
1056
  trap: trap
1188
1057
  });
1189
- var finishActivation = /*#__PURE__*/function () {
1190
- var _ref6 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
1191
- return _regenerator().w(function (_context) {
1192
- while (1) switch (_context.n) {
1193
- case 0:
1194
- if (checkCanFocusTrap) {
1195
- updateTabbableNodes();
1196
- }
1197
-
1198
- // NOTE: wait for initial focus node to get focused before we potentially isolate
1199
- // the subtrees with aria-hidden while focus is still in some other subtree and
1200
- // not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
1201
- // console that they, "Blocked aria-hidden on an element because its descendant
1202
- // retained focus..."
1203
- _context.n = 1;
1204
- return addListeners();
1205
- case 1:
1206
- trap._setSubtreeIsolation(true);
1207
- updateObservedNodes();
1208
- onPostActivate === null || onPostActivate === void 0 || onPostActivate({
1209
- trap: trap
1210
- });
1211
- case 2:
1212
- return _context.a(2);
1213
- }
1214
- }, _callee);
1215
- }));
1216
- return function finishActivation() {
1217
- return _ref6.apply(this, arguments);
1058
+ var finishActivation = function finishActivation() {
1059
+ if (checkCanFocusTrap) {
1060
+ updateTabbableNodes();
1061
+ }
1062
+ var afterListeners = function afterListeners() {
1063
+ trap._setSubtreeIsolation(true);
1064
+ updateObservedNodes();
1065
+ onPostActivate === null || onPostActivate === void 0 || onPostActivate({
1066
+ trap: trap
1067
+ });
1218
1068
  };
1219
- }();
1069
+
1070
+ // NOTE: wait for initial focus node to get focused (whether activation is fully,
1071
+ // partially, or not asynchronous) before we potentially isolate the subtrees
1072
+ // with aria-hidden while focus is still in some other subtree and not yet in
1073
+ // the trap, resulting in some browsers (e.g. Chrome) logging to the console that
1074
+ // they, "Blocked aria-hidden on an element because its descendant retained focus..."
1075
+ var listenersPromise = addListeners();
1076
+ if (listenersPromise) {
1077
+ listenersPromise.then(afterListeners);
1078
+ } else {
1079
+ afterListeners();
1080
+ }
1081
+ };
1220
1082
  if (checkCanFocusTrap) {
1221
1083
  checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
1222
1084
  return this;
@@ -1356,35 +1218,28 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1356
1218
  onUnpause === null || onUnpause === void 0 || onUnpause({
1357
1219
  trap: trap
1358
1220
  });
1359
- var finishUnpause = /*#__PURE__*/function () {
1360
- var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
1361
- return _regenerator().w(function (_context2) {
1362
- while (1) switch (_context2.n) {
1363
- case 0:
1364
- updateTabbableNodes();
1365
-
1366
- // NOTE: wait for initial focus node to get focused before we potentially isolate
1367
- // the subtrees with aria-hidden while focus is still in some other subtree and
1368
- // not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
1369
- // console that they, "Blocked aria-hidden on an element because its descendant
1370
- // retained focus..."
1371
- _context2.n = 1;
1372
- return addListeners();
1373
- case 1:
1374
- trap._setSubtreeIsolation(true);
1375
- updateObservedNodes();
1376
- onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause({
1377
- trap: trap
1378
- });
1379
- case 2:
1380
- return _context2.a(2);
1381
- }
1382
- }, _callee2);
1383
- }));
1384
- return function finishUnpause() {
1385
- return _ref7.apply(this, arguments);
1221
+ var finishUnpause = function finishUnpause() {
1222
+ updateTabbableNodes();
1223
+ var afterListeners = function afterListeners() {
1224
+ trap._setSubtreeIsolation(true);
1225
+ updateObservedNodes();
1226
+ onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause({
1227
+ trap: trap
1228
+ });
1386
1229
  };
1387
- }();
1230
+
1231
+ // NOTE: wait for initial focus node to get focused (whether activation is fully,
1232
+ // partially, or not asynchronous) before we potentially isolate the subtrees
1233
+ // with aria-hidden while focus is still in some other subtree and not yet in
1234
+ // the trap, resulting in some browsers (e.g. Chrome) logging to the console that
1235
+ // they, "Blocked aria-hidden on an element because its descendant retained focus..."
1236
+ var listenersPromise = addListeners();
1237
+ if (listenersPromise) {
1238
+ listenersPromise.then(afterListeners);
1239
+ } else {
1240
+ afterListeners();
1241
+ }
1242
+ };
1388
1243
  finishUnpause();
1389
1244
  }
1390
1245
  return this;