focus-trap 6.8.0-beta.1 → 6.8.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 +24 -1
- package/README.md +22 -5
- package/dist/focus-trap.esm.js +92 -71
- 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 +92 -71
- 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 +92 -71
- 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 +1 -1
- package/index.js +98 -69
- package/package.json +17 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 6.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7c86111:
|
|
8
|
+
- Bump tabbable to `^5.3.1` (fixing previous update which was incorrectly set to `5.3.0`).
|
|
9
|
+
- Fix `tabbableOptions` not being used in all internal uses of tabbable APIs.
|
|
10
|
+
- Expose `displayCheck` option in `tabbableOptions` typings and pass it through to tabbable APIs.
|
|
11
|
+
- Add info to README about testing traps in JSDom (which is not officially supported).
|
|
12
|
+
|
|
13
|
+
## 6.8.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 21458c9: Bumps tabbable to v5.3.0 and includes all changes from the past v6.8.0 beta releases. The big new feature is opt-in Shadow DOM support in tabbable, and a new `getShadowRoot` tabbable option exposed in a new `tabbableOptions` focus-trap config option.
|
|
18
|
+
|
|
19
|
+
## 6.8.0-beta.2
|
|
20
|
+
|
|
21
|
+
- When updating tabbable nodes, make sure that `getShadowRoot` tabbable option is also passed to `focusable()`.
|
|
22
|
+
- Fix bug where having a tabbable node inside a web component in the middle of a tab sequence would cause the tab key to seemingly stop working just before focus should move to it ((#643)[https://github.com/focus-trap/focus-trap/issues/643]).
|
|
23
|
+
- Bumps tabbable to `v5.3.0-beta.1`
|
|
24
|
+
|
|
3
25
|
## 6.8.0-beta.1
|
|
4
26
|
|
|
5
|
-
-
|
|
27
|
+
- Previous beta didn't include new source. This one does.
|
|
6
28
|
|
|
7
29
|
## 6.8.0-beta.0
|
|
8
30
|
|
|
9
31
|
- Adds new `tabbableOptions` configuration option, which allows specifically for the new `getShadowRoot` Tabbable configuration option: `focusTrap.createFocusTrap(rootElement, { tabbableOptions: { getShadowRoot: (node) => closedShadowRoot } })`, for example (where your code has the reference to `closedShadowRoot` previously created on `node` which Tabbable cannot find on its own).
|
|
32
|
+
- Bumps tabbable to `v5.3.0-beta.0`
|
|
10
33
|
|
|
11
34
|
## 6.7.3
|
|
12
35
|
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# focus-trap [](https://github.com/focus-trap/focus-trap/actions?query=workflow:CI+branch:master) [](./LICENSE)
|
|
2
2
|
|
|
3
3
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
4
|
-
[](#contributors)
|
|
5
5
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
6
6
|
|
|
7
7
|
Trap focus within a DOM node.
|
|
@@ -106,8 +106,8 @@ Returns a new focus trap on `element` (one or more "containers" of tabbable node
|
|
|
106
106
|
- **preventScroll** `{boolean}`: By default, focus() will scroll to the element if not in viewport. It can produce unintended effects like scrolling back to the top of a modal. If set to `true`, no scroll will happen.
|
|
107
107
|
- **delayInitialFocus** `{boolean}`: 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.
|
|
108
108
|
- **document** {Document}: Default: `window.document`. Document where the focus trap will be active. This allows to use FocusTrap in an iFrame context.
|
|
109
|
-
- **tabbableOptions**: (optional)
|
|
110
|
-
-
|
|
109
|
+
- **tabbableOptions**: (optional) [tabbable options](https://github.com/focus-trap/tabbable#common-options) configurable on FocusTrap (all the _common options_).
|
|
110
|
+
- ⚠️ See notes about __[testing in JSDom](#testing-in-jsdom)__ (e.g. using Jest).
|
|
111
111
|
|
|
112
112
|
#### Shadow DOM
|
|
113
113
|
|
|
@@ -241,6 +241,20 @@ If you find yourself in this situation, you should give you container `tabindex=
|
|
|
241
241
|
|
|
242
242
|
Because of the nature of the functionality, involving keyboard and click and (especially) focus events, JavaScript unit tests don't make sense. After all, JSDom does not fully support focus events. Since the demo was developed to also be the test, we use Cypress to automate running through all demos in the demo page.
|
|
243
243
|
|
|
244
|
+
## Help
|
|
245
|
+
|
|
246
|
+
### Testing in JSDom
|
|
247
|
+
|
|
248
|
+
> ⚠️ JSDom is not officially supported. Your mileage may vary, and tests may break from one release to the next (even a patch or minor release).
|
|
249
|
+
>
|
|
250
|
+
> This topic is just here to help with what we know may affect your tests.
|
|
251
|
+
|
|
252
|
+
In general, a focus trap is best tested in a full browser environment such as Cypress, Playwright, or Nightwatch where a full DOM is available.
|
|
253
|
+
|
|
254
|
+
Sometimes, that's not entirely desirable, and depending on what you're testing, you may be able to get away with using JSDom (e.g. via Jest), but you'll have to configure your traps using the `tabbableOptions.displayCheck: 'none'` option.
|
|
255
|
+
|
|
256
|
+
See [Testing tabbable in JSDom](https://github.com/focus-trap/tabbable#testing-in-jsdom) for more details.
|
|
257
|
+
|
|
244
258
|
# Contributing
|
|
245
259
|
|
|
246
260
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
|
@@ -258,26 +272,29 @@ In alphabetical order:
|
|
|
258
272
|
<td align="center"><a href="https://github.com/bparish628"><img src="https://avatars1.githubusercontent.com/u/8492971?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Parish</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Abparish628" title="Bug reports">🐛</a></td>
|
|
259
273
|
<td align="center"><a href="https://clintgoodman.com"><img src="https://avatars3.githubusercontent.com/u/5473697?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Clint Goodman</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=cgood92" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=cgood92" title="Documentation">📖</a> <a href="#example-cgood92" title="Examples">💡</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=cgood92" title="Tests">⚠️</a></td>
|
|
260
274
|
<td align="center"><a href="https://github.com/Dan503"><img src="https://avatars.githubusercontent.com/u/10610368?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Tonon</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=Dan503" title="Documentation">📖</a> <a href="#tool-Dan503" title="Tools">🔧</a> <a href="#a11y-Dan503" title="Accessibility">️️️️♿️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=Dan503" title="Code">💻</a></td>
|
|
275
|
+
<td align="center"><a href="https://github.com/DaviDevMod"><img src="https://avatars.githubusercontent.com/u/98312056?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DaviDevMod</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=DaviDevMod" title="Documentation">📖</a></td>
|
|
261
276
|
<td align="center"><a href="http://davidtheclark.com/"><img src="https://avatars2.githubusercontent.com/u/628431?v=4?s=100" width="100px;" alt=""/><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>
|
|
262
277
|
<td align="center"><a href="https://github.com/features/security"><img src="https://avatars1.githubusercontent.com/u/27347476?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dependabot</b></sub></a><br /><a href="#maintenance-dependabot" title="Maintenance">🚧</a></td>
|
|
263
|
-
<td align="center"><a href="https://github.com/michael-ar"><img src="https://avatars3.githubusercontent.com/u/18557997?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Reynolds</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Amichael-ar" title="Bug reports">🐛</a></td>
|
|
264
278
|
</tr>
|
|
265
279
|
<tr>
|
|
280
|
+
<td align="center"><a href="https://github.com/michael-ar"><img src="https://avatars3.githubusercontent.com/u/18557997?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Reynolds</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Amichael-ar" title="Bug reports">🐛</a></td>
|
|
266
281
|
<td align="center"><a href="https://github.com/liunate"><img src="https://avatars2.githubusercontent.com/u/38996291?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nate Liu</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=liunate" title="Tests">⚠️</a></td>
|
|
267
282
|
<td align="center"><a href="https://github.com/far-fetched"><img src="https://avatars.githubusercontent.com/u/11621383?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotr Panek</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Afar-fetched" title="Bug reports">🐛</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=far-fetched" title="Documentation">📖</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=far-fetched" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=far-fetched" title="Tests">⚠️</a></td>
|
|
268
283
|
<td align="center"><a href="https://github.com/randypuro"><img src="https://avatars2.githubusercontent.com/u/2579?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Randy Puro</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Arandypuro" title="Bug reports">🐛</a></td>
|
|
269
284
|
<td align="center"><a href="https://github.com/sadick254"><img src="https://avatars2.githubusercontent.com/u/5238135?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sadick</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=sadick254" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=sadick254" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=sadick254" title="Documentation">📖</a></td>
|
|
270
285
|
<td align="center"><a href="https://scottblinch.me/"><img src="https://avatars2.githubusercontent.com/u/4682114?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Scott Blinch</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=scottblinch" title="Documentation">📖</a></td>
|
|
271
286
|
<td align="center"><a href="https://seanmcp.com/"><img src="https://avatars1.githubusercontent.com/u/6360367?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sean McPherson</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=SeanMcP" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=SeanMcP" title="Documentation">📖</a></td>
|
|
272
|
-
<td align="center"><a href="https://github.com/skriems"><img src="https://avatars.githubusercontent.com/u/15573317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sebastian Kriems</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Askriems" title="Bug reports">🐛</a></td>
|
|
273
287
|
</tr>
|
|
274
288
|
<tr>
|
|
289
|
+
<td align="center"><a href="https://github.com/skriems"><img src="https://avatars.githubusercontent.com/u/15573317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sebastian Kriems</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Askriems" title="Bug reports">🐛</a></td>
|
|
275
290
|
<td align="center"><a href="https://recollectr.io"><img src="https://avatars2.githubusercontent.com/u/6835891?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Slapbox</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3ASlapbox" title="Bug reports">🐛</a></td>
|
|
276
291
|
<td align="center"><a href="https://stefancameron.com/"><img src="https://avatars3.githubusercontent.com/u/2855350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Cameron</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=stefcameron" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Astefcameron" title="Bug reports">🐛</a> <a href="#infra-stefcameron" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=stefcameron" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=stefcameron" title="Documentation">📖</a> <a href="#maintenance-stefcameron" title="Maintenance">🚧</a></td>
|
|
277
292
|
<td align="center"><a href="http://tylerhawkins.info/201R/"><img src="https://avatars0.githubusercontent.com/u/13806458?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tyler Hawkins</b></sub></a><br /><a href="#tool-thawkin3" title="Tools">🔧</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=thawkin3" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=thawkin3" title="Documentation">📖</a></td>
|
|
278
293
|
<td align="center"><a href="https://github.com/wandroll"><img src="https://avatars.githubusercontent.com/u/4492317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wandrille Verlut</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=wandroll" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=wandroll" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=wandroll" title="Documentation">📖</a> <a href="#tool-wandroll" title="Tools">🔧</a></td>
|
|
279
294
|
<td align="center"><a href="http://willmruzek.com/"><img src="https://avatars.githubusercontent.com/u/108522?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Will Mruzek</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=mruzekw" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=mruzekw" title="Documentation">📖</a> <a href="#example-mruzekw" title="Examples">💡</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=mruzekw" title="Tests">⚠️</a> <a href="#question-mruzekw" title="Answering Questions">💬</a></td>
|
|
280
295
|
<td align="center"><a href="https://github.com/zioth"><img src="https://avatars3.githubusercontent.com/u/945603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zioth</b></sub></a><br /><a href="#ideas-zioth" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Azioth" title="Bug reports">🐛</a></td>
|
|
296
|
+
</tr>
|
|
297
|
+
<tr>
|
|
281
298
|
<td align="center"><a href="https://github.com/jpveooys"><img src="https://avatars.githubusercontent.com/u/66470099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jpveooys</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Ajpveooys" title="Bug reports">🐛</a></td>
|
|
282
299
|
</tr>
|
|
283
300
|
</table>
|
package/dist/focus-trap.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 6.8.
|
|
2
|
+
* focus-trap 6.8.1
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
5
|
import { tabbable, focusable, isTabbable, isFocusable } from 'tabbable';
|
|
@@ -151,20 +151,28 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
151
151
|
}, userOptions);
|
|
152
152
|
|
|
153
153
|
var state = {
|
|
154
|
+
// containers given to createFocusTrap()
|
|
154
155
|
// @type {Array<HTMLElement>}
|
|
155
156
|
containers: [],
|
|
156
|
-
// list of objects identifying
|
|
157
|
-
// the trap
|
|
157
|
+
// list of objects identifying tabbable nodes in `containers` in the trap
|
|
158
158
|
// NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap
|
|
159
159
|
// is active, but the trap should never get to a state where there isn't at least one group
|
|
160
160
|
// with at least one tabbable node in it (that would lead to an error condition that would
|
|
161
161
|
// result in an error being thrown)
|
|
162
162
|
// @type {Array<{
|
|
163
163
|
// container: HTMLElement,
|
|
164
|
+
// tabbableNodes: Array<HTMLElement>, // empty if none
|
|
165
|
+
// focusableNodes: Array<HTMLElement>, // empty if none
|
|
164
166
|
// firstTabbableNode: HTMLElement|null,
|
|
165
167
|
// lastTabbableNode: HTMLElement|null,
|
|
166
168
|
// nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
|
|
167
169
|
// }>}
|
|
170
|
+
containerGroups: [],
|
|
171
|
+
// same order/length as `containers` list
|
|
172
|
+
// references to objects in `containerGroups`, but only those that actually have
|
|
173
|
+
// tabbable nodes in them
|
|
174
|
+
// NOTE: same order as `containers` and `containerGroups`, but __not necessarily__
|
|
175
|
+
// the same length
|
|
168
176
|
tabbableGroups: [],
|
|
169
177
|
nodeFocusedBeforeActivation: null,
|
|
170
178
|
mostRecentlyFocusedNode: null,
|
|
@@ -188,11 +196,30 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
188
196
|
var getOption = function getOption(configOverrideOptions, optionName, configOptionName) {
|
|
189
197
|
return configOverrideOptions && configOverrideOptions[optionName] !== undefined ? configOverrideOptions[optionName] : config[configOptionName || optionName];
|
|
190
198
|
};
|
|
199
|
+
/**
|
|
200
|
+
* Finds the index of the container that contains the element.
|
|
201
|
+
* @param {HTMLElement} element
|
|
202
|
+
* @returns {number} Index of the container in either `state.containers` or
|
|
203
|
+
* `state.containerGroups` (the order/length of these lists are the same); -1
|
|
204
|
+
* if the element isn't found.
|
|
205
|
+
*/
|
|
191
206
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
207
|
+
|
|
208
|
+
var findContainerIndex = function findContainerIndex(element) {
|
|
209
|
+
// NOTE: search `containerGroups` because it's possible a group contains no tabbable
|
|
210
|
+
// nodes, but still contains focusable nodes (e.g. if they all have `tabindex=-1`)
|
|
211
|
+
// and we still need to find the element in there
|
|
212
|
+
return state.containerGroups.findIndex(function (_ref) {
|
|
213
|
+
var container = _ref.container,
|
|
214
|
+
tabbableNodes = _ref.tabbableNodes;
|
|
215
|
+
return container.contains(element) || // fall back to explicit tabbable search which will take into consideration any
|
|
216
|
+
// web components if the `tabbableOptions.getShadowRoot` option was used for
|
|
217
|
+
// the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't
|
|
218
|
+
// look inside web components even if open)
|
|
219
|
+
tabbableNodes.find(function (node) {
|
|
220
|
+
return node === element;
|
|
221
|
+
});
|
|
222
|
+
});
|
|
196
223
|
};
|
|
197
224
|
/**
|
|
198
225
|
* Gets the node for the given option, which is expected to be an option that
|
|
@@ -251,7 +278,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
251
278
|
|
|
252
279
|
if (node === undefined) {
|
|
253
280
|
// option not specified: use fallback options
|
|
254
|
-
if (
|
|
281
|
+
if (findContainerIndex(doc.activeElement) >= 0) {
|
|
255
282
|
node = doc.activeElement;
|
|
256
283
|
} else {
|
|
257
284
|
var firstTabbableGroup = state.tabbableGroups[0];
|
|
@@ -269,64 +296,61 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
269
296
|
};
|
|
270
297
|
|
|
271
298
|
var updateTabbableNodes = function updateTabbableNodes() {
|
|
272
|
-
state.
|
|
273
|
-
var
|
|
274
|
-
|
|
275
|
-
var tabbableNodes = tabbable(container, {
|
|
276
|
-
getShadowRoot: (_config$tabbableOptio = config.tabbableOptions) === null || _config$tabbableOptio === void 0 ? void 0 : _config$tabbableOptio.getShadowRoot
|
|
277
|
-
}); // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes
|
|
299
|
+
state.containerGroups = state.containers.map(function (container) {
|
|
300
|
+
var tabbableNodes = tabbable(container, config.tabbableOptions); // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes
|
|
278
301
|
// are a superset of tabbable nodes
|
|
279
302
|
|
|
280
|
-
var focusableNodes = focusable(container);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
});
|
|
316
|
-
}
|
|
303
|
+
var focusableNodes = focusable(container, config.tabbableOptions);
|
|
304
|
+
return {
|
|
305
|
+
container: container,
|
|
306
|
+
tabbableNodes: tabbableNodes,
|
|
307
|
+
focusableNodes: focusableNodes,
|
|
308
|
+
firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null,
|
|
309
|
+
lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null,
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Finds the __tabbable__ node that follows the given node in the specified direction,
|
|
313
|
+
* in this container, if any.
|
|
314
|
+
* @param {HTMLElement} node
|
|
315
|
+
* @param {boolean} [forward] True if going in forward tab order; false if going
|
|
316
|
+
* in reverse.
|
|
317
|
+
* @returns {HTMLElement|undefined} The next tabbable node, if any.
|
|
318
|
+
*/
|
|
319
|
+
nextTabbableNode: function nextTabbableNode(node) {
|
|
320
|
+
var forward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
321
|
+
// NOTE: If tabindex is positive (in order to manipulate the tab order separate
|
|
322
|
+
// from the DOM order), this __will not work__ because the list of focusableNodes,
|
|
323
|
+
// while it contains tabbable nodes, does not sort its nodes in any order other
|
|
324
|
+
// than DOM order, because it can't: Where would you place focusable (but not
|
|
325
|
+
// tabbable) nodes in that order? They have no order, because they aren't tabbale...
|
|
326
|
+
// Support for positive tabindex is already broken and hard to manage (possibly
|
|
327
|
+
// not supportable, TBD), so this isn't going to make things worse than they
|
|
328
|
+
// already are, and at least makes things better for the majority of cases where
|
|
329
|
+
// tabindex is either 0/unset or negative.
|
|
330
|
+
// FYI, positive tabindex issue: https://github.com/focus-trap/focus-trap/issues/375
|
|
331
|
+
var nodeIdx = focusableNodes.findIndex(function (n) {
|
|
332
|
+
return n === node;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
if (nodeIdx < 0) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
317
338
|
|
|
318
|
-
|
|
319
|
-
|
|
339
|
+
if (forward) {
|
|
340
|
+
return focusableNodes.slice(nodeIdx + 1).find(function (n) {
|
|
341
|
+
return isTabbable(n, config.tabbableOptions);
|
|
320
342
|
});
|
|
321
343
|
}
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
344
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
345
|
+
return focusableNodes.slice(0, nodeIdx).reverse().find(function (n) {
|
|
346
|
+
return isTabbable(n, config.tabbableOptions);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
});
|
|
351
|
+
state.tabbableGroups = state.containerGroups.filter(function (group) {
|
|
352
|
+
return group.tabbableNodes.length > 0;
|
|
353
|
+
}); // throw if no groups have tabbable nodes and we don't have a fallback focus node either
|
|
330
354
|
|
|
331
355
|
if (state.tabbableGroups.length <= 0 && !getNodeForOption('fallbackFocus') // returning false not supported for this option
|
|
332
356
|
) {
|
|
@@ -368,7 +392,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
368
392
|
var checkPointerDown = function checkPointerDown(e) {
|
|
369
393
|
var target = getActualTarget(e);
|
|
370
394
|
|
|
371
|
-
if (
|
|
395
|
+
if (findContainerIndex(target) >= 0) {
|
|
372
396
|
// allow the click since it ocurred inside the trap
|
|
373
397
|
return;
|
|
374
398
|
}
|
|
@@ -387,7 +411,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
387
411
|
// that was clicked, whether it's focusable or not; by setting
|
|
388
412
|
// `returnFocus: true`, we'll attempt to re-focus the node originally-focused
|
|
389
413
|
// on activation (or the configured `setReturnFocus` node)
|
|
390
|
-
returnFocus: config.returnFocusOnDeactivate && !isFocusable(target)
|
|
414
|
+
returnFocus: config.returnFocusOnDeactivate && !isFocusable(target, config.tabbableOptions)
|
|
391
415
|
});
|
|
392
416
|
return;
|
|
393
417
|
} // This is needed for mobile devices.
|
|
@@ -407,7 +431,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
407
431
|
|
|
408
432
|
var checkFocusIn = function checkFocusIn(e) {
|
|
409
433
|
var target = getActualTarget(e);
|
|
410
|
-
var targetContained =
|
|
434
|
+
var targetContained = findContainerIndex(target) >= 0; // In Firefox when you Tab out of an iframe the Document is briefly focused.
|
|
411
435
|
|
|
412
436
|
if (targetContained || target instanceof Document) {
|
|
413
437
|
if (targetContained) {
|
|
@@ -433,11 +457,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
433
457
|
// make sure the target is actually contained in a group
|
|
434
458
|
// NOTE: the target may also be the container itself if it's focusable
|
|
435
459
|
// with tabIndex='-1' and was given initial focus
|
|
436
|
-
var containerIndex =
|
|
437
|
-
|
|
438
|
-
return container.contains(target);
|
|
439
|
-
});
|
|
440
|
-
var containerGroup = containerIndex >= 0 ? state.tabbableGroups[containerIndex] : undefined;
|
|
460
|
+
var containerIndex = findContainerIndex(target);
|
|
461
|
+
var containerGroup = containerIndex >= 0 ? state.containerGroups[containerIndex] : undefined;
|
|
441
462
|
|
|
442
463
|
if (containerIndex < 0) {
|
|
443
464
|
// target not found in any group: quite possible focus has escaped the trap,
|
|
@@ -457,7 +478,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
457
478
|
return target === firstTabbableNode;
|
|
458
479
|
});
|
|
459
480
|
|
|
460
|
-
if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target) && !isTabbable(target) && !containerGroup.nextTabbableNode(target, false))) {
|
|
481
|
+
if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) {
|
|
461
482
|
// an exception case where the target is either the container itself, or
|
|
462
483
|
// a non-tabbable node that was given focus (i.e. tabindex is negative
|
|
463
484
|
// and user clicked on it or node was programmatically given focus)
|
|
@@ -483,7 +504,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
483
504
|
return target === lastTabbableNode;
|
|
484
505
|
});
|
|
485
506
|
|
|
486
|
-
if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target) && !isTabbable(target) && !containerGroup.nextTabbableNode(target))) {
|
|
507
|
+
if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) {
|
|
487
508
|
// an exception case where the target is the container itself, or
|
|
488
509
|
// a non-tabbable node that was given focus (i.e. tabindex is negative
|
|
489
510
|
// and user clicked on it or node was programmatically given focus)
|
|
@@ -535,7 +556,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
535
556
|
|
|
536
557
|
var target = getActualTarget(e);
|
|
537
558
|
|
|
538
|
-
if (
|
|
559
|
+
if (findContainerIndex(target) >= 0) {
|
|
539
560
|
return;
|
|
540
561
|
}
|
|
541
562
|
|