focus-trap 6.4.0 → 6.6.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 +53 -0
- package/README.md +53 -47
- package/dist/focus-trap.esm.js +88 -32
- 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 +88 -32
- 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 +88 -32
- 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 +62 -13
- package/index.js +82 -22
- package/package.json +27 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 6.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 24063d7: Update tabbable to v5.2.1 to get bug fix for disabled fieldsets.
|
|
8
|
+
|
|
9
|
+
## 6.6.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 281e66c: Add option to allow no initial focus when trap activates via `initialFocus: false`
|
|
14
|
+
|
|
15
|
+
There may be cases where we don't want to focus the first tabbable element when a focus trap activates.
|
|
16
|
+
|
|
17
|
+
Examples use-cases:
|
|
18
|
+
|
|
19
|
+
- Modals/dialogs
|
|
20
|
+
- On mobile devices where "tabbing" doesn't make sense without a connected Bluetooth keyboard
|
|
21
|
+
|
|
22
|
+
In addition, this change ensures that any element inside the trap manually focused outside of `focus-trap` code will be brought back in focus if focus is somehow found outside of the trap.
|
|
23
|
+
|
|
24
|
+
Example usage:
|
|
25
|
+
|
|
26
|
+
When the trap activates, there will be no initially focused element inside the new trap.
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const focusTrap = createFocusTrap('#some-container', {
|
|
30
|
+
initialFocus: false,
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- 75be463: `escapeDeactivates` can now be either a boolean (as before) or a function that takes an event and returns a boolean.
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- e2294f0: Fix race condition when activating a second trap where initial focus in the second trap may be thwarted because pausing of first trap clears the `delayInitialFocus` timer created for the second trap before during its activation sequence.
|
|
39
|
+
|
|
40
|
+
## 6.5.1
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- c38bf3f: onPostDeactivate should always be called even if returnFocus/OnDeactivate is disabled.
|
|
45
|
+
|
|
46
|
+
## 6.5.0
|
|
47
|
+
|
|
48
|
+
### Minor Changes
|
|
49
|
+
|
|
50
|
+
- 278e77e: Adding 4 new configuration event options to improve support for animated dialogs and animated focus trap triggers: `checkCanFocusTrap()`, `onPostActivate()`, `checkCanReturnFocus()`, and `onPostDeactivate()`.
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- 8d11e15: Improve docs and types for most options, adding `SVGElement` as a supported type of "DOM node" since it supports the `focus()` method, same as `HTMLElement`.
|
|
55
|
+
|
|
3
56
|
## 6.4.0
|
|
4
57
|
|
|
5
58
|
### Minor Changes
|
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.
|
|
@@ -28,7 +28,7 @@ When the focus trap is deactivated, this is what should happen:
|
|
|
28
28
|
- Focus is passed to *whichever element had focus when the trap was activated* (e.g. the button that opened the modal or menu).
|
|
29
29
|
- Tabbing and clicking behave normally everywhere.
|
|
30
30
|
|
|
31
|
-
[Check out the demos.](http://focus-trap.github.io/focus-trap/
|
|
31
|
+
[Check out the demos.](http://focus-trap.github.io/focus-trap/)
|
|
32
32
|
|
|
33
33
|
For more advanced usage (e.g. focus traps within focus traps), you can also pause a focus trap's behavior without deactivating it entirely, then unpause at will.
|
|
34
34
|
|
|
@@ -80,20 +80,25 @@ Returns a new focus trap on `element` (one or more "containers" of tabbable node
|
|
|
80
80
|
|
|
81
81
|
> A focus trap must have at least one container with at least one tabbable/focusable node in it to be considered valid. While nodes can be added/removed at runtime, with the trap adjusting to added/removed tabbable nodes, __an error will be thrown__ if the trap ever gets into a state where it determines none of its containers have any tabbable nodes in them _and_ the `fallbackFocus` option does not resolve to an alternate node where focus can go.
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- **onActivate** {
|
|
86
|
-
- **
|
|
87
|
-
- **
|
|
88
|
-
- **
|
|
89
|
-
- **
|
|
90
|
-
- **
|
|
83
|
+
#### createOptions
|
|
84
|
+
|
|
85
|
+
- **onActivate** `{() => void}`: A function that will be called **before** sending focus to the target element upon activation.
|
|
86
|
+
- **onPostActivate** `{() => void}`: A function that will be called **after** sending focus to the target element upon activation.
|
|
87
|
+
- **checkCanFocusTrap** `{(containers: Array<HTMLElement | SVGElement>) => Promise<void>}`: 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). Due to the lack of Promise support, `checkCanFocusTrap` is not supported in IE unless you provide a Promise polyfill.
|
|
88
|
+
- **onDeactivate** `{() => void}`: A function that will be called **before** returning focus to the node that had focus prior to activation (or configured with the `setReturnFocus` option) upon deactivation.
|
|
89
|
+
- **onPostDeactivate** `{() => void}`: 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.
|
|
90
|
+
- **checkCanReturnFocus** `{(trigger: HTMLElement | SVGElement) => Promise<void>}`: 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). Due to the lack of Promise support, `checkCanReturnFocus` is not supported in IE unless you provide a Promise polyfill.
|
|
91
|
+
- **initialFocus** `{HTMLElement | SVGElement | string | () => HTMLElement | SVGElement | false}`: By default, when a focus trap is activated the first element in the focus trap's tab order will receive focus. With this option you can specify a different element to receive that initial focus. Can be a DOM node, or a selector string (which will be passed to `document.querySelector()` to find the DOM node), or a function that returns a DOM node. You can also set this option to `false` to prevent any initial focus at all when the trap activates.
|
|
92
|
+
- **fallbackFocus** `{HTMLElement | SVGElement | string | () => HTMLElement | SVGElement}`: By default, an error will be thrown if the focus trap contains no elements in its tab order. With this option you can specify a fallback element to programmatically receive focus if no other tabbable elements are found. For example, you may want a popover's `<div>` to receive focus if the popover's content includes no tabbable elements. *Make sure the fallback element has a negative `tabindex` so it can be programmatically focused.* The option value can be a DOM node, a selector string (which will be passed to `document.querySelector()` to find the DOM node), or a function that returns a DOM node.
|
|
93
|
+
- **escapeDeactivates** `{boolean} | (e: KeyboardEvent) => boolean)`: Default: `true`. If `false` or returns `false`, the `Escape` key will not trigger deactivation of the focus trap. This can be useful if you want to force the user to make a decision instead of allowing an easy way out. Note that if a function is given, it's only called if the ESC key was pressed.
|
|
94
|
+
- **clickOutsideDeactivates** `{boolean | (e: MouseEvent | TouchEvent) => boolean}`: If `true` or returns `true`, a click outside the focus trap will deactivate the focus trap and allow the click event to do its thing (i.e. to pass-through to the element that was clicked). This option **takes precedence** over `allowOutsideClick` when it's set to `true`. Default: `false`.
|
|
91
95
|
- ⚠️ If you're using a password manager such as 1Password, where the app adds a clickable icon to all fillable fields, you should avoid using this option, and instead use the `allowOutsideClick` option to better control exactly when the focus trap can be deactivated. The clickable icons are usually positioned absolutely, floating on top of the fields, and therefore _not_ part of the container the trap is managing. When using the `clickOutsideDeactivates` option, clicking on a field's 1Password icon will likely cause the trap to be unintentionally deactivated.
|
|
92
|
-
- **allowOutsideClick** {boolean|(e: MouseEvent) => boolean}
|
|
93
|
-
- **
|
|
94
|
-
- **
|
|
95
|
-
- **
|
|
96
|
-
- **
|
|
96
|
+
- **allowOutsideClick** `{boolean | (e: MouseEvent | TouchEvent) => boolean}`: If set and is or returns `true`, a click outside the focus trap will not be prevented, even when `clickOutsideDeactivates` is `false`. When `clickOutsideDeactivates` is `true`, this option is **ignored** (i.e. if it's a function, it will not be called). Use this option to control if (and even which) clicks are allowed outside the trap in conjunction with `clickOutsideDeactivates: false`. Default: `false`.
|
|
97
|
+
- ⚠️ If this is a function, it will be called **twice** on every click: First on `mousedown` (or `touchstart` on mobile), and then on the actual `click` if the function returned `true` on the first event. Be sure to check the event type if the double call is an issue in your code.
|
|
98
|
+
- **returnFocusOnDeactivate** `{boolean}`: Default: `true`. If `false`, when the trap is deactivated, focus will *not* return to the element that had focus before activation.
|
|
99
|
+
- **setReturnFocus** `{HTMLElement | SVGElement | string | () => HTMLElement | SVGElement}`: By default, focus trap on deactivation will return to the element that was focused before activation. With this option you can specify another element to programmatically receive focus after deactivation. Can be a DOM node, or a selector string (which will be passed to `document.querySelector()` to find the DOM node), or a function that returns a DOM node.
|
|
100
|
+
- **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.
|
|
101
|
+
- **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.
|
|
97
102
|
|
|
98
103
|
### trap.activate([activateOptions])
|
|
99
104
|
|
|
@@ -113,7 +118,9 @@ Returns the `trap`.
|
|
|
113
118
|
|
|
114
119
|
These options are used to override the focus trap's default behavior for this particular activation.
|
|
115
120
|
|
|
116
|
-
- **onActivate** {
|
|
121
|
+
- **onActivate** `{() => void}`: Default: whatever you chose for `createOptions.onActivate`. `null` or `false` are the equivalent of a `noop`.
|
|
122
|
+
- **onPostActivate** `{() => void}`: Default: whatever you chose for `createOptions.onPostActivate`. `null` or `false` are the equivalent of a `noop`.
|
|
123
|
+
- **checkCanFocusTrap** `{(containers: Array<HTMLElement | SVGElement>) => Promise<void>}`: Default: whatever you chose for `createOptions.checkCanFocusTrap`.
|
|
117
124
|
|
|
118
125
|
### trap.deactivate([deactivateOptions])
|
|
119
126
|
|
|
@@ -125,8 +132,10 @@ Returns the `trap`.
|
|
|
125
132
|
|
|
126
133
|
These options are used to override the focus trap's default behavior for this particular deactivation.
|
|
127
134
|
|
|
128
|
-
- **returnFocus** {boolean}
|
|
129
|
-
- **onDeactivate** {
|
|
135
|
+
- **returnFocus** `{boolean}`: Default: whatever you chose for `createOptions.returnFocusOnDeactivate`.
|
|
136
|
+
- **onDeactivate** `{() => void}`: Default: whatever you chose for `createOptions.onDeactivate`. `null` or `false` are the equivalent of a `noop`.
|
|
137
|
+
- **onPostDeactivate** `{() => void}`: Default: whatever you chose for `createOptions.onPostDeactivate`. `null` or `false` are the equivalent of a `noop`.
|
|
138
|
+
- **checkCanReturnFocus** `{(trigger: HTMLElement | SVGElement) => Promise<void>}`: Default: whatever you chose 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.
|
|
130
139
|
|
|
131
140
|
### trap.pause()
|
|
132
141
|
|
|
@@ -162,7 +171,7 @@ Returns the `trap`.
|
|
|
162
171
|
|
|
163
172
|
## Examples
|
|
164
173
|
|
|
165
|
-
Read code in `
|
|
174
|
+
Read code in `docs/` and [see how it works](http://focus-trap.github.io/focus-trap/).
|
|
166
175
|
|
|
167
176
|
Here's what happens in `default.js` (the "default behavior" demo):
|
|
168
177
|
|
|
@@ -172,25 +181,16 @@ const { createFocusTrap } = require('../../dist/focus-trap');
|
|
|
172
181
|
const container = document.getElementById('default');
|
|
173
182
|
|
|
174
183
|
const focusTrap = createFocusTrap('#default', {
|
|
175
|
-
onActivate:
|
|
176
|
-
|
|
177
|
-
},
|
|
178
|
-
onDeactivate: function () {
|
|
179
|
-
container.className = 'trap';
|
|
180
|
-
},
|
|
184
|
+
onActivate: () => container.classList.add('is-active'),
|
|
185
|
+
onDeactivate: () => container.classList.remove('is-active'),
|
|
181
186
|
});
|
|
182
187
|
|
|
183
188
|
document
|
|
184
189
|
.getElementById('activate-default')
|
|
185
|
-
.addEventListener('click',
|
|
186
|
-
focusTrap.activate();
|
|
187
|
-
});
|
|
188
|
-
|
|
190
|
+
.addEventListener('click', focusTrap.activate);
|
|
189
191
|
document
|
|
190
192
|
.getElementById('deactivate-default')
|
|
191
|
-
.addEventListener('click',
|
|
192
|
-
focusTrap.deactivate();
|
|
193
|
-
});
|
|
193
|
+
.addEventListener('click', focusTrap.deactivate);
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
## Other details
|
|
@@ -232,25 +232,31 @@ In alphabetical order:
|
|
|
232
232
|
<!-- markdownlint-disable -->
|
|
233
233
|
<table>
|
|
234
234
|
<tr>
|
|
235
|
-
<td align="center"><a href="
|
|
236
|
-
<td align="center"><a href="https://
|
|
237
|
-
<td align="center"><a href="https://github.com/
|
|
238
|
-
<td align="center"><a href="
|
|
239
|
-
<td align="center"><a href="https://github.com/
|
|
240
|
-
<td align="center"><a href="https://
|
|
241
|
-
<td align="center"><a href="https://github.com/
|
|
235
|
+
<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>
|
|
236
|
+
<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>
|
|
237
|
+
<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>
|
|
238
|
+
<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>
|
|
239
|
+
<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>
|
|
240
|
+
<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>
|
|
241
|
+
<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>
|
|
242
242
|
</tr>
|
|
243
243
|
<tr>
|
|
244
|
-
<td align="center"><a href="https://
|
|
245
|
-
<td align="center"><a href="https://github.com/
|
|
246
|
-
<td align="center"><a href="https://
|
|
247
|
-
<td align="center"><a href="https://
|
|
248
|
-
<td align="center"><a href="https://
|
|
249
|
-
<td align="center"><a href="https://
|
|
250
|
-
<td align="center"><a href="
|
|
244
|
+
<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></td>
|
|
245
|
+
<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>
|
|
246
|
+
<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>
|
|
247
|
+
<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>
|
|
248
|
+
<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>
|
|
249
|
+
<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>
|
|
250
|
+
<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>
|
|
251
|
+
</tr>
|
|
252
|
+
<tr>
|
|
253
|
+
<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>
|
|
254
|
+
<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>
|
|
255
|
+
<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>
|
|
251
256
|
</tr>
|
|
252
257
|
</table>
|
|
253
258
|
|
|
254
|
-
<!-- markdownlint-
|
|
259
|
+
<!-- markdownlint-restore -->
|
|
255
260
|
<!-- prettier-ignore-end -->
|
|
261
|
+
|
|
256
262
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
package/dist/focus-trap.esm.js
CHANGED
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 6.
|
|
2
|
+
* focus-trap 6.6.1
|
|
3
3
|
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
|
|
4
4
|
*/
|
|
5
5
|
import { tabbable, isFocusable } from 'tabbable';
|
|
6
6
|
|
|
7
|
-
function _defineProperty(obj, key, value) {
|
|
8
|
-
if (key in obj) {
|
|
9
|
-
Object.defineProperty(obj, key, {
|
|
10
|
-
value: value,
|
|
11
|
-
enumerable: true,
|
|
12
|
-
configurable: true,
|
|
13
|
-
writable: true
|
|
14
|
-
});
|
|
15
|
-
} else {
|
|
16
|
-
obj[key] = value;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return obj;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
7
|
function ownKeys(object, enumerableOnly) {
|
|
23
8
|
var keys = Object.keys(object);
|
|
24
9
|
|
|
25
10
|
if (Object.getOwnPropertySymbols) {
|
|
26
11
|
var symbols = Object.getOwnPropertySymbols(object);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
|
|
13
|
+
if (enumerableOnly) {
|
|
14
|
+
symbols = symbols.filter(function (sym) {
|
|
15
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
30
19
|
keys.push.apply(keys, symbols);
|
|
31
20
|
}
|
|
32
21
|
|
|
@@ -53,7 +42,20 @@ function _objectSpread2(target) {
|
|
|
53
42
|
return target;
|
|
54
43
|
}
|
|
55
44
|
|
|
56
|
-
|
|
45
|
+
function _defineProperty(obj, key, value) {
|
|
46
|
+
if (key in obj) {
|
|
47
|
+
Object.defineProperty(obj, key, {
|
|
48
|
+
value: value,
|
|
49
|
+
enumerable: true,
|
|
50
|
+
configurable: true,
|
|
51
|
+
writable: true
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
obj[key] = value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return obj;
|
|
58
|
+
}
|
|
57
59
|
|
|
58
60
|
var activeFocusTraps = function () {
|
|
59
61
|
var trapQueue = [];
|
|
@@ -161,10 +163,17 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
161
163
|
nodeFocusedBeforeActivation: null,
|
|
162
164
|
mostRecentlyFocusedNode: null,
|
|
163
165
|
active: false,
|
|
164
|
-
paused: false
|
|
166
|
+
paused: false,
|
|
167
|
+
// timer ID for when delayInitialFocus is true and initial focus in this trap
|
|
168
|
+
// has been delayed during activation
|
|
169
|
+
delayInitialFocusTimer: undefined
|
|
165
170
|
};
|
|
166
171
|
var trap; // eslint-disable-line prefer-const -- some private functions reference it, and its methods reference private functions, so we must declare here and define later
|
|
167
172
|
|
|
173
|
+
var getOption = function getOption(configOverrideOptions, optionName, configOptionName) {
|
|
174
|
+
return configOverrideOptions && configOverrideOptions[optionName] !== undefined ? configOverrideOptions[optionName] : config[configOptionName || optionName];
|
|
175
|
+
};
|
|
176
|
+
|
|
168
177
|
var containersContain = function containersContain(element) {
|
|
169
178
|
return state.containers.some(function (container) {
|
|
170
179
|
return container.contains(element);
|
|
@@ -200,7 +209,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
200
209
|
};
|
|
201
210
|
|
|
202
211
|
var getInitialFocusNode = function getInitialFocusNode() {
|
|
203
|
-
var node;
|
|
212
|
+
var node; // false indicates we want no initialFocus at all
|
|
213
|
+
|
|
214
|
+
if (getOption({}, 'initialFocus') === false) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
204
217
|
|
|
205
218
|
if (getNodeForOption('initialFocus') !== null) {
|
|
206
219
|
node = getNodeForOption('initialFocus');
|
|
@@ -243,6 +256,10 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
243
256
|
};
|
|
244
257
|
|
|
245
258
|
var tryFocus = function tryFocus(node) {
|
|
259
|
+
if (node === false) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
246
263
|
if (node === doc.activeElement) {
|
|
247
264
|
return;
|
|
248
265
|
}
|
|
@@ -408,7 +425,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
408
425
|
};
|
|
409
426
|
|
|
410
427
|
var checkKey = function checkKey(e) {
|
|
411
|
-
if (config.escapeDeactivates !== false
|
|
428
|
+
if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates) !== false) {
|
|
412
429
|
e.preventDefault();
|
|
413
430
|
trap.deactivate();
|
|
414
431
|
return;
|
|
@@ -449,7 +466,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
449
466
|
activeFocusTraps.activateTrap(trap); // Delay ensures that the focused element doesn't capture the event
|
|
450
467
|
// that caused the focus trap activation.
|
|
451
468
|
|
|
452
|
-
|
|
469
|
+
state.delayInitialFocusTimer = config.delayInitialFocus ? delay(function () {
|
|
453
470
|
tryFocus(getInitialFocusNode());
|
|
454
471
|
}) : tryFocus(getInitialFocusNode());
|
|
455
472
|
doc.addEventListener('focusin', checkFocusIn, true);
|
|
@@ -494,17 +511,40 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
494
511
|
return this;
|
|
495
512
|
}
|
|
496
513
|
|
|
497
|
-
|
|
514
|
+
var onActivate = getOption(activateOptions, 'onActivate');
|
|
515
|
+
var onPostActivate = getOption(activateOptions, 'onPostActivate');
|
|
516
|
+
var checkCanFocusTrap = getOption(activateOptions, 'checkCanFocusTrap');
|
|
517
|
+
|
|
518
|
+
if (!checkCanFocusTrap) {
|
|
519
|
+
updateTabbableNodes();
|
|
520
|
+
}
|
|
521
|
+
|
|
498
522
|
state.active = true;
|
|
499
523
|
state.paused = false;
|
|
500
524
|
state.nodeFocusedBeforeActivation = doc.activeElement;
|
|
501
|
-
var onActivate = activateOptions && activateOptions.onActivate ? activateOptions.onActivate : config.onActivate;
|
|
502
525
|
|
|
503
526
|
if (onActivate) {
|
|
504
527
|
onActivate();
|
|
505
528
|
}
|
|
506
529
|
|
|
507
|
-
|
|
530
|
+
var finishActivation = function finishActivation() {
|
|
531
|
+
if (checkCanFocusTrap) {
|
|
532
|
+
updateTabbableNodes();
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
addListeners();
|
|
536
|
+
|
|
537
|
+
if (onPostActivate) {
|
|
538
|
+
onPostActivate();
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
if (checkCanFocusTrap) {
|
|
543
|
+
checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation);
|
|
544
|
+
return this;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
finishActivation();
|
|
508
548
|
return this;
|
|
509
549
|
},
|
|
510
550
|
deactivate: function deactivate(deactivateOptions) {
|
|
@@ -512,25 +552,41 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
|
|
|
512
552
|
return this;
|
|
513
553
|
}
|
|
514
554
|
|
|
515
|
-
clearTimeout(
|
|
555
|
+
clearTimeout(state.delayInitialFocusTimer); // noop if undefined
|
|
556
|
+
|
|
557
|
+
state.delayInitialFocusTimer = undefined;
|
|
516
558
|
removeListeners();
|
|
517
559
|
state.active = false;
|
|
518
560
|
state.paused = false;
|
|
519
561
|
activeFocusTraps.deactivateTrap(trap);
|
|
520
|
-
var onDeactivate = deactivateOptions
|
|
562
|
+
var onDeactivate = getOption(deactivateOptions, 'onDeactivate');
|
|
563
|
+
var onPostDeactivate = getOption(deactivateOptions, 'onPostDeactivate');
|
|
564
|
+
var checkCanReturnFocus = getOption(deactivateOptions, 'checkCanReturnFocus');
|
|
521
565
|
|
|
522
566
|
if (onDeactivate) {
|
|
523
567
|
onDeactivate();
|
|
524
568
|
}
|
|
525
569
|
|
|
526
|
-
var returnFocus = deactivateOptions
|
|
570
|
+
var returnFocus = getOption(deactivateOptions, 'returnFocus', 'returnFocusOnDeactivate');
|
|
527
571
|
|
|
528
|
-
|
|
572
|
+
var finishDeactivation = function finishDeactivation() {
|
|
529
573
|
delay(function () {
|
|
530
|
-
|
|
574
|
+
if (returnFocus) {
|
|
575
|
+
tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (onPostDeactivate) {
|
|
579
|
+
onPostDeactivate();
|
|
580
|
+
}
|
|
531
581
|
});
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
if (returnFocus && checkCanReturnFocus) {
|
|
585
|
+
checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation);
|
|
586
|
+
return this;
|
|
532
587
|
}
|
|
533
588
|
|
|
589
|
+
finishDeactivation();
|
|
534
590
|
return this;
|
|
535
591
|
},
|
|
536
592
|
pause: function pause() {
|