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.
- package/CHANGELOG.md +17 -0
- package/README.md +20 -2
- package/dist/focus-trap.esm.js +103 -231
- package/dist/focus-trap.esm.js.map +1 -1
- package/dist/focus-trap.esm.min.js +2 -4
- package/dist/focus-trap.esm.min.js.map +1 -1
- package/dist/focus-trap.js +102 -230
- package/dist/focus-trap.js.map +1 -1
- package/dist/focus-trap.min.js +2 -4
- package/dist/focus-trap.min.js.map +1 -1
- package/dist/focus-trap.umd.js +102 -230
- package/dist/focus-trap.umd.js.map +1 -1
- package/dist/focus-trap.umd.min.js +2 -4
- package/dist/focus-trap.umd.min.js.map +1 -1
- package/index.d.ts +15 -0
- package/index.js +102 -63
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
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
|
+
|
|
10
|
+
## 8.2.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 567dbe1: Add new `delayReturnFocus` option (default true) to control whether return focus and onPostDeactivate are deferred by one frame (#1689).
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- b70e8d9: Fix bug where removing the ancestor of a focused node within a trap would result in focus landing on the body instead of remaining in the trap (#1660).
|
|
19
|
+
|
|
3
20
|
## 8.1.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -150,6 +150,7 @@ Note that if [delayInitialFocus](#delayinitialfocus) is true, this handler will
|
|
|
150
150
|
Animated dialogs have a small delay between when `onActivate` is called and when the focus trap is focusable. `checkCanFocusTrap` expects a promise to be returned. When that promise settles (resolves or rejects), focus will be sent to the first tabbable node (in tab order) in the focus trap (or the node configured in the `initialFocus` option).
|
|
151
151
|
|
|
152
152
|
πΊ It does not matter whether the Promise resolves or rejects, only that it settles. A rejected Promise will not result in cancellation of trap activation.
|
|
153
|
+
πΊ This controls **when activation may proceed**. The separate [delayInitialFocus](#delayinitialfocus) option controls whether there is an additional one-frame delay before focus is sent once activation can proceed.
|
|
153
154
|
|
|
154
155
|
##### onDeactivate
|
|
155
156
|
|
|
@@ -167,6 +168,8 @@ A function that will be called **before** returning focus to the node that had f
|
|
|
167
168
|
|
|
168
169
|
A function that will be called after the trap is deactivated, after `onDeactivate`. If the `returnFocus` deactivation option was set, it will be called **after** returning focus to the node that had focus prior to activation (or configured with the `setReturnFocus` option) upon deactivation; otherwise, it will be called after deactivation completes.
|
|
169
170
|
|
|
171
|
+
By default, this callback is delayed by one frame along with return-focus timing; set [delayReturnFocus](#delayreturnfocus) to `false` to remove that extra delay.
|
|
172
|
+
|
|
170
173
|
##### checkCanReturnFocus
|
|
171
174
|
|
|
172
175
|
```typescript
|
|
@@ -175,6 +178,8 @@ A function that will be called after the trap is deactivated, after `onDeactivat
|
|
|
175
178
|
|
|
176
179
|
An animated trigger button will have a small delay between when `onDeactivate` is called and when the focus is able to be sent back to the trigger. `checkCanReturnFocus` expects a promise to be returned. When that promise settles (resolves or rejects), focus will be sent to to the node that had focus prior to the activation of the trap (or the node configured in the `setReturnFocus` option).
|
|
177
180
|
|
|
181
|
+
πΊ If [delayReturnFocus](#delayreturnfocus) is `true` (default), there is still an additional one-frame delay after this Promise settles before focus is returned and `onPostDeactivate` is called.
|
|
182
|
+
|
|
178
183
|
##### initialFocus
|
|
179
184
|
|
|
180
185
|
```typescript
|
|
@@ -272,6 +277,19 @@ boolean
|
|
|
272
277
|
Default: `true`. Delays the autofocus to the next execution frame when the focus trap is activated. This prevents elements within the focusable element from capturing the event that triggered the focus trap activation.
|
|
273
278
|
|
|
274
279
|
πΊ Note that when this option is `true` (default), it means the initial element to be focused will not be focused until **after** [onPostActivate](#onpostactivate) or [onPostUnpause](#onpostunpause) are called.
|
|
280
|
+
πΊ This option controls the extra frame delay on activation. Use [checkCanFocusTrap](#checkcanfocustrap) to gate activation readiness, and [delayReturnFocus](#delayreturnfocus) plus [checkCanReturnFocus](#checkcanreturnfocus) for the equivalent deactivation timing controls.
|
|
281
|
+
|
|
282
|
+
##### delayReturnFocus
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
boolean
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Default: `true`. Delays return-focus to the next execution frame when the focus trap is deactivated.
|
|
289
|
+
|
|
290
|
+
- This same delay also applies to [onPostDeactivate](#onpostdeactivate).
|
|
291
|
+
- Set to `false` to skip the extra frame delay.
|
|
292
|
+
- If [checkCanReturnFocus](#checkcanreturnfocus) is configured, that Promise must still settle first.
|
|
275
293
|
|
|
276
294
|
##### isolateSubtrees
|
|
277
295
|
|
|
@@ -410,7 +428,7 @@ These options are used to override the focus trap's default behavior for this pa
|
|
|
410
428
|
- **returnFocus** `{boolean}`: Default: whatever you set for `createOptions.returnFocusOnDeactivate`. If `true`, then the `setReturnFocus` option (specified when the trap was created) is used to determine where focus will be returned.
|
|
411
429
|
- **onDeactivate** `{(params: LifecycleParameters) => void}`: Default: whatever you set for `createOptions.onDeactivate`. `null` or `false` are the equivalent of a `noop`.
|
|
412
430
|
- **onPostDeactivate** `{(params: LifecycleParameters) => void}`: Default: whatever you set for `createOptions.onPostDeactivate`. `null` or `false` are the equivalent of a `noop`.
|
|
413
|
-
- **checkCanReturnFocus** `{(trigger: HTMLElement | SVGElement) => Promise<void>}`: Default: whatever you set for `createOptions.checkCanReturnFocus`. Not called if the `returnFocus` option is falsy. `trigger` is either the originally focused node prior to activation, or the result of the `setReturnFocus` configuration option.
|
|
431
|
+
- **checkCanReturnFocus** `{(trigger: HTMLElement | SVGElement) => Promise<void>}`: Default: whatever you set for `createOptions.checkCanReturnFocus`. Not called if the `returnFocus` option is falsy. `trigger` is either the originally focused node prior to activation, or the result of the `setReturnFocus` configuration option. After this Promise settles, `createOptions.delayReturnFocus` determines whether return-focus and `onPostDeactivate` are immediate (`false`) or delayed by one frame (`true`, default).
|
|
414
432
|
|
|
415
433
|
### trap.pause()
|
|
416
434
|
|
|
@@ -589,7 +607,7 @@ In alphabetical order:
|
|
|
589
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>
|
|
590
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>
|
|
591
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>
|
|
592
|
-
<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>
|
|
593
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>
|
|
594
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>
|
|
595
613
|
</tr>
|
package/dist/focus-trap.esm.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 8.1
|
|
2
|
+
* focus-trap 8.2.1
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { tabbable, focusable, isTabbable, getTabIndex, isFocusable } from 'tabbable';
|
|
6
6
|
|
|
7
7
|
function _arrayLikeToArray(r, a) {
|
|
8
8
|
(null == a || a > r.length) && (a = r.length);
|
|
@@ -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
|
}
|
|
@@ -356,6 +223,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
356
223
|
returnFocusOnDeactivate: true,
|
|
357
224
|
escapeDeactivates: true,
|
|
358
225
|
delayInitialFocus: true,
|
|
226
|
+
delayReturnFocus: true,
|
|
359
227
|
isolateSubtrees: false,
|
|
360
228
|
isKeyForward: isKeyForward,
|
|
361
229
|
isKeyBackward: isKeyBackward
|
|
@@ -505,6 +373,25 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
505
373
|
}
|
|
506
374
|
return node;
|
|
507
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
|
+
};
|
|
508
395
|
var getInitialFocusNode = function getInitialFocusNode() {
|
|
509
396
|
var node = getNodeForOption('initialFocus', {
|
|
510
397
|
hasFallback: true
|
|
@@ -515,9 +402,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
515
402
|
return false;
|
|
516
403
|
}
|
|
517
404
|
if (node === undefined || node && !isFocusable(node, config.tabbableOptions)) {
|
|
405
|
+
var activeElement = _getActiveElement(doc);
|
|
406
|
+
|
|
518
407
|
// option not specified nor focusable: use fallback options
|
|
519
|
-
if (findContainerIndex(
|
|
520
|
-
node =
|
|
408
|
+
if (findContainerIndex(activeElement) >= 0) {
|
|
409
|
+
node = activeElement;
|
|
521
410
|
} else {
|
|
522
411
|
var firstTabbableGroup = state.tabbableGroups[0];
|
|
523
412
|
var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode;
|
|
@@ -629,25 +518,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
629
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.");
|
|
630
519
|
}
|
|
631
520
|
};
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Gets the current activeElement. If it's a web-component and has open shadow-root
|
|
635
|
-
* it will recursively search inside shadow roots for the "true" activeElement.
|
|
636
|
-
*
|
|
637
|
-
* @param {Document | ShadowRoot} el
|
|
638
|
-
*
|
|
639
|
-
* @returns {HTMLElement} The element that currently has the focus
|
|
640
|
-
**/
|
|
641
|
-
var _getActiveElement = function getActiveElement(el) {
|
|
642
|
-
var activeElement = el.activeElement;
|
|
643
|
-
if (!activeElement) {
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
|
|
647
|
-
return _getActiveElement(activeElement.shadowRoot);
|
|
648
|
-
}
|
|
649
|
-
return activeElement;
|
|
650
|
-
};
|
|
651
521
|
var _tryFocus = function tryFocus(node) {
|
|
652
522
|
if (node === false) {
|
|
653
523
|
return;
|
|
@@ -968,12 +838,13 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
968
838
|
/**
|
|
969
839
|
* Adds listeners to the document necessary for trapping focus and attempts to set focus
|
|
970
840
|
* to the configured initial focus node. Does nothing if the trap isn't active.
|
|
971
|
-
* @returns {Promise<void>}
|
|
972
|
-
*
|
|
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.
|
|
973
844
|
*/
|
|
974
845
|
var addListeners = function addListeners() {
|
|
975
846
|
if (!state.active) {
|
|
976
|
-
return
|
|
847
|
+
return;
|
|
977
848
|
}
|
|
978
849
|
|
|
979
850
|
// There can be only one listening focus trap at a time
|
|
@@ -981,7 +852,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
981
852
|
|
|
982
853
|
// Delay ensures that the focused element doesn't capture the event
|
|
983
854
|
// that caused the focus trap activation.
|
|
984
|
-
/** @type {Promise<void>} */
|
|
855
|
+
/** @type {Promise<void> | undefined} */
|
|
985
856
|
var promise;
|
|
986
857
|
if (config.delayInitialFocus) {
|
|
987
858
|
// NOTE: Promise constructor callback is called synchronously, which is what we want
|
|
@@ -993,7 +864,6 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
993
864
|
});
|
|
994
865
|
});
|
|
995
866
|
} else {
|
|
996
|
-
promise = Promise.resolve();
|
|
997
867
|
_tryFocus(getInitialFocusNode());
|
|
998
868
|
}
|
|
999
869
|
doc.addEventListener('focusin', checkFocusIn, true);
|
|
@@ -1102,17 +972,27 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1102
972
|
//
|
|
1103
973
|
|
|
1104
974
|
var checkDomRemoval = function checkDomRemoval(mutations) {
|
|
975
|
+
var focusedNode = state.mostRecentlyFocusedNode;
|
|
976
|
+
if (!focusedNode) {
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
1105
979
|
var isFocusedNodeRemoved = mutations.some(function (mutation) {
|
|
1106
980
|
var removedNodes = Array.from(mutation.removedNodes);
|
|
1107
981
|
return removedNodes.some(function (node) {
|
|
1108
|
-
return node ===
|
|
982
|
+
return node === focusedNode || typeof node.contains === 'function' && node.contains(focusedNode);
|
|
1109
983
|
});
|
|
1110
984
|
});
|
|
1111
985
|
|
|
1112
|
-
// If the currently focused is removed then browsers will move focus to the
|
|
986
|
+
// If the currently focused node is removed then browsers will move focus to the
|
|
1113
987
|
// <body> element. If this happens, try to move focus back into the trap.
|
|
1114
|
-
if (isFocusedNodeRemoved) {
|
|
1115
|
-
|
|
988
|
+
if (isFocusedNodeRemoved && state.containers.some(function (container) {
|
|
989
|
+
return container === null || container === void 0 ? void 0 : container.isConnected;
|
|
990
|
+
})) {
|
|
991
|
+
// Refresh tabbable state before resolving initial focus because
|
|
992
|
+
// getInitialFocusNode() may fall back to the first tabbable node in the trap.
|
|
993
|
+
updateTabbableNodes();
|
|
994
|
+
var initialFocusNode = getInitialFocusNode();
|
|
995
|
+
_tryFocus(initialFocusNode);
|
|
1116
996
|
}
|
|
1117
997
|
};
|
|
1118
998
|
|
|
@@ -1175,37 +1055,30 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1175
1055
|
onActivate === null || onActivate === void 0 || onActivate({
|
|
1176
1056
|
trap: trap
|
|
1177
1057
|
});
|
|
1178
|
-
var finishActivation =
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
// the subtrees with aria-hidden while focus is still in some other subtree and
|
|
1189
|
-
// not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
|
|
1190
|
-
// console that they, "Blocked aria-hidden on an element because its descendant
|
|
1191
|
-
// retained focus..."
|
|
1192
|
-
_context.n = 1;
|
|
1193
|
-
return addListeners();
|
|
1194
|
-
case 1:
|
|
1195
|
-
trap._setSubtreeIsolation(true);
|
|
1196
|
-
updateObservedNodes();
|
|
1197
|
-
onPostActivate === null || onPostActivate === void 0 || onPostActivate({
|
|
1198
|
-
trap: trap
|
|
1199
|
-
});
|
|
1200
|
-
case 2:
|
|
1201
|
-
return _context.a(2);
|
|
1202
|
-
}
|
|
1203
|
-
}, _callee);
|
|
1204
|
-
}));
|
|
1205
|
-
return function finishActivation() {
|
|
1206
|
-
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
|
+
});
|
|
1207
1068
|
};
|
|
1208
|
-
|
|
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
|
+
};
|
|
1209
1082
|
if (checkCanFocusTrap) {
|
|
1210
1083
|
checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
|
|
1211
1084
|
return this;
|
|
@@ -1253,20 +1126,26 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1253
1126
|
var onDeactivate = getOption(options, 'onDeactivate');
|
|
1254
1127
|
var onPostDeactivate = getOption(options, 'onPostDeactivate');
|
|
1255
1128
|
var checkCanReturnFocus = getOption(options, 'checkCanReturnFocus');
|
|
1129
|
+
var delayReturnFocus = getOption(options, 'delayReturnFocus');
|
|
1256
1130
|
var returnFocus = getOption(options, 'returnFocus', 'returnFocusOnDeactivate');
|
|
1257
1131
|
onDeactivate === null || onDeactivate === void 0 || onDeactivate({
|
|
1258
1132
|
trap: trap
|
|
1259
1133
|
});
|
|
1260
|
-
var
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
trap: trap
|
|
1267
|
-
});
|
|
1134
|
+
var completeDeactivation = function completeDeactivation() {
|
|
1135
|
+
if (returnFocus) {
|
|
1136
|
+
_tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
|
|
1137
|
+
}
|
|
1138
|
+
onPostDeactivate === null || onPostDeactivate === void 0 || onPostDeactivate({
|
|
1139
|
+
trap: trap
|
|
1268
1140
|
});
|
|
1269
1141
|
};
|
|
1142
|
+
var finishDeactivation = function finishDeactivation() {
|
|
1143
|
+
if (delayReturnFocus && returnFocus) {
|
|
1144
|
+
delay(completeDeactivation);
|
|
1145
|
+
} else {
|
|
1146
|
+
completeDeactivation();
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1270
1149
|
if (returnFocus && checkCanReturnFocus) {
|
|
1271
1150
|
checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation);
|
|
1272
1151
|
return this;
|
|
@@ -1339,35 +1218,28 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
1339
1218
|
onUnpause === null || onUnpause === void 0 || onUnpause({
|
|
1340
1219
|
trap: trap
|
|
1341
1220
|
});
|
|
1342
|
-
var finishUnpause =
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
// the subtrees with aria-hidden while focus is still in some other subtree and
|
|
1351
|
-
// not yet in the trap, resulting in some browsers (e.g. Chrome) logging to the
|
|
1352
|
-
// console that they, "Blocked aria-hidden on an element because its descendant
|
|
1353
|
-
// retained focus..."
|
|
1354
|
-
_context2.n = 1;
|
|
1355
|
-
return addListeners();
|
|
1356
|
-
case 1:
|
|
1357
|
-
trap._setSubtreeIsolation(true);
|
|
1358
|
-
updateObservedNodes();
|
|
1359
|
-
onPostUnpause === null || onPostUnpause === void 0 || onPostUnpause({
|
|
1360
|
-
trap: trap
|
|
1361
|
-
});
|
|
1362
|
-
case 2:
|
|
1363
|
-
return _context2.a(2);
|
|
1364
|
-
}
|
|
1365
|
-
}, _callee2);
|
|
1366
|
-
}));
|
|
1367
|
-
return function finishUnpause() {
|
|
1368
|
-
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
|
+
});
|
|
1369
1229
|
};
|
|
1370
|
-
|
|
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
|
+
};
|
|
1371
1243
|
finishUnpause();
|
|
1372
1244
|
}
|
|
1373
1245
|
return this;
|