focus-trap 7.5.4 β†’ 7.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fc5910d: Fix fallbackFocus not used when initialFocus is selector to non-existent node ([#1218](https://github.com/focus-trap/focus-trap/issues/1218))
8
+
9
+ ## 7.6.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 8aeacee: Move `Escape` key handler to target phase to allow more control in `escapeDeactivates` ([#1247](https://github.com/focus-trap/focus-trap/issues/1247))
14
+
3
15
  ## 7.5.4
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # focus-trap [![CI](https://github.com/focus-trap/focus-trap/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/focus-trap/focus-trap/actions?query=workflow:CI+branch:master) [![license](https://badgen.now.sh/badge/license/MIT)](./LICENSE)
2
2
 
3
3
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
4
- [![All Contributors](https://img.shields.io/badge/all_contributors-30-orange.svg?style=flat-square)](#contributors)
4
+ [![All Contributors](https://img.shields.io/badge/all_contributors-33-orange.svg?style=flat-square)](#contributors)
5
5
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
6
6
 
7
7
  Trap focus within a DOM node.
@@ -101,9 +101,12 @@ Returns a new focus trap on `element` (one or more "containers" of tabbable node
101
101
  - **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.
102
102
  - **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.
103
103
  - **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).
104
- - **initialFocus** `{HTMLElement | SVGElement | string | false | undefined | (() => HTMLElement | SVGElement | string | false | undefined)}`: 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 any of these. You can also set this option to `false` (or to a function that returns `false`) to prevent any initial focus at all when the trap activates.
104
+ - **initialFocus** `{HTMLElement | SVGElement | string | false | undefined | (() => HTMLElement | SVGElement | string | false | undefined)}`: By default (when `undefined` or the function returns `undefined`), when a focus trap is activated, the active element will receive focus if it's in the trap, otherwise, 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 any of these. You can also set this option to `false` (or to a function that returns `false`) to prevent any initial focus at all when the trap activates.
105
105
  - πŸ’¬ Setting this option to `false` (or a function that returns `false`) will prevent the `fallbackFocus` option from being used.
106
- - Returning `undefined` from a function will result in the default behavior.
106
+ - πŸ’¬ If the option resolves to a non-focusable node (e.g. one that exists, but is hidden), the default behavior will be used (as though the option weren't set at all).
107
+ - πŸ’¬ If the option resolves to a non-existent node, an exception will be thrown.
108
+ - πŸ’¬ If the option resolves to a valid selector string (directly set, or returned from a function), but the selector doesn't match a node, the trap will fall back to the `fallbackFocus` node option. If that option also fails to yield a node, an exception will be thrown.
109
+ - πŸ’¬ If the option resolves to `undefined` (i.e. not set or function returns `undefined`), the default behavior will be used.
107
110
  - ⚠️ See warning below about **Shadow DOM** and selector strings.
108
111
  - **fallbackFocus** `{HTMLElement | SVGElement | string | () => HTMLElement | SVGElement | string}`: 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 any of these.
109
112
  - πŸ’¬ If `initialFocus` is `false` (or a function that returns `false`), this function will not be called when the trap is activated, and no element will be initially focused. This function may still be called while the trap is active if things change such that there are no longer any tabbable nodes in the trap.
@@ -348,6 +351,18 @@ You will hit this error if your trap does not have (or no longer has) any [tabba
348
351
 
349
352
  This often happens when traps are related to elements that appear and disappear dynamically. Typically, the error will fire either as the element is being shown (because the trap gets created before the trapped children have been inserted into the DOM), or as it's being hidden (because the trapped children are destroyed before the trap is either destroyed or disabled).
350
353
 
354
+ ### First element in trap is unreachable with the TAB key
355
+
356
+ If you create a trap and try to use the TAB key to set focus to the first element in your trap, the first element seems unreachable because focus keeps skipping over it for some reason.
357
+
358
+ This can happen in projects where the Angular-related [zone.js](https://www.npmjs.com/package/zone.js) module is being used because Zone can interfere with Focus-trap's ability to control where focus goes when it _leaves an edge node_ (that is, a node that is on the edge of a container in which it is trapping focus).
359
+
360
+ What is actually happening is that Focus-trap is correctly wrapping focus around to that first element (or last element, if going in reverse with SHIFT+TAB, and you're seeing that get skipped) and setting focus to it, but because of Zone's interference (in which Focus-trap's call to `preventDefault()` on the focus event triggered by the TAB key press is rendered ineffective), once Focus-trap is done handling the event, the browser hasn't received the signal that its default behavior should be prevented, and so it proceeds to move focus to the _next_ element -- effectively "skipping" over the element to which Focus-trap set focus, making it seem "unreachable".
361
+
362
+ Unfortunately, there's no good workaround to this issue from Focus-trap's perspective. The issue was [reported to Angular](https://github.com/angular/angular/issues/45020) (not by Focus-trap) and [has a PR](https://github.com/angular/angular/pull/49477) (also not by Focus-trap) for a fix.
363
+
364
+ This was originally investigated in [#1165](https://github.com/focus-trap/focus-trap/issues/1165) if you want to go deeper.
365
+
351
366
  # Contributing
352
367
 
353
368
  See [CONTRIBUTING](CONTRIBUTING.md).
@@ -371,34 +386,37 @@ In alphabetical order:
371
386
  <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>
372
387
  </tr>
373
388
  <tr>
389
+ <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>
374
390
  <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>
375
391
  <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>
376
392
  <td align="center" valign="top" width="14.28%"><a href="http://reload.dk"><img src="https://avatars.githubusercontent.com/u/73966?v=4?s=100" width="100px;" alt="Kasper GarnΓ¦s"/><br /><sub><b>Kasper GarnΓ¦s</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=kasperg" title="Documentation">πŸ“–</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Akasperg" title="Bug reports">πŸ›</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=kasperg" title="Code">πŸ’»</a></td>
377
393
  <td align="center" valign="top" width="14.28%"><a href="http://blogs.esri.com/esri/arcgis/"><img src="https://avatars.githubusercontent.com/u/1231455?v=4?s=100" width="100px;" alt="Matt Driscoll"/><br /><sub><b>Matt Driscoll</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Adriskull" title="Bug reports">πŸ›</a> <a href="https://github.com/focus-trap/focus-trap/commits?author=driskull" title="Code">πŸ’»</a> <a href="#tutorial-driskull" title="Tutorials">βœ…</a></td>
378
394
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/msev"><img src="https://avatars.githubusercontent.com/u/1529562?v=4?s=100" width="100px;" alt="Maxime"/><br /><sub><b>Maxime</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Amsev" title="Bug reports">πŸ›</a></td>
379
395
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/michael-ar"><img src="https://avatars3.githubusercontent.com/u/18557997?v=4?s=100" width="100px;" alt="Michael Reynolds"/><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>
380
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/liunate"><img src="https://avatars2.githubusercontent.com/u/38996291?v=4?s=100" width="100px;" alt="Nate Liu"/><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>
381
396
  </tr>
382
397
  <tr>
398
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/liunate"><img src="https://avatars2.githubusercontent.com/u/38996291?v=4?s=100" width="100px;" alt="Nate Liu"/><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>
383
399
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/far-fetched"><img src="https://avatars.githubusercontent.com/u/11621383?v=4?s=100" width="100px;" alt="Piotr Panek"/><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>
384
400
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/randypuro"><img src="https://avatars2.githubusercontent.com/u/2579?v=4?s=100" width="100px;" alt="Randy Puro"/><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>
385
401
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sadick254"><img src="https://avatars2.githubusercontent.com/u/5238135?v=4?s=100" width="100px;" alt="Sadick"/><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>
386
402
  <td align="center" valign="top" width="14.28%"><a href="https://scottblinch.me/"><img src="https://avatars2.githubusercontent.com/u/4682114?v=4?s=100" width="100px;" alt="Scott Blinch"/><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>
387
403
  <td align="center" valign="top" width="14.28%"><a href="https://seanmcp.com/"><img src="https://avatars1.githubusercontent.com/u/6360367?v=4?s=100" width="100px;" alt="Sean McPherson"/><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>
388
404
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/skriems"><img src="https://avatars.githubusercontent.com/u/15573317?v=4?s=100" width="100px;" alt="Sebastian Kriems"/><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>
389
- <td align="center" valign="top" width="14.28%"><a href="https://recollectr.io"><img src="https://avatars2.githubusercontent.com/u/6835891?v=4?s=100" width="100px;" alt="Slapbox"/><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>
390
405
  </tr>
391
406
  <tr>
407
+ <td align="center" valign="top" width="14.28%"><a href="https://recollectr.io"><img src="https://avatars2.githubusercontent.com/u/6835891?v=4?s=100" width="100px;" alt="Slapbox"/><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>
392
408
  <td align="center" valign="top" width="14.28%"><a href="https://stefancameron.com/"><img src="https://avatars3.githubusercontent.com/u/2855350?v=4?s=100" width="100px;" alt="Stefan Cameron"/><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>
393
409
  <td align="center" valign="top" width="14.28%"><a href="http://tylerhawkins.info/201R/"><img src="https://avatars0.githubusercontent.com/u/13806458?v=4?s=100" width="100px;" alt="Tyler Hawkins"/><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>
394
410
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/vasiliki-b"><img src="https://avatars.githubusercontent.com/u/98032598?v=4?s=100" width="100px;" alt="Vasiliki Boutas"/><br /><sub><b>Vasiliki Boutas</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Avasiliki-b" title="Bug reports">πŸ›</a></td>
395
411
  <td align="center" valign="top" width="14.28%"><a href="https://vinicius73.dev/"><img src="https://avatars.githubusercontent.com/u/1561347?v=4?s=100" width="100px;" alt="Vinicius Reis"/><br /><sub><b>Vinicius Reis</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=vinicius73" title="Code">πŸ’»</a> <a href="#ideas-vinicius73" title="Ideas, Planning, & Feedback">πŸ€”</a></td>
396
412
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/wandroll"><img src="https://avatars.githubusercontent.com/u/4492317?v=4?s=100" width="100px;" alt="Wandrille Verlut"/><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>
397
413
  <td align="center" valign="top" width="14.28%"><a href="http://willmruzek.com/"><img src="https://avatars.githubusercontent.com/u/108522?v=4?s=100" width="100px;" alt="Will Mruzek"/><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>
398
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/zioth"><img src="https://avatars3.githubusercontent.com/u/945603?v=4?s=100" width="100px;" alt="Zioth"/><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>
399
414
  </tr>
400
415
  <tr>
416
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/zioth"><img src="https://avatars3.githubusercontent.com/u/945603?v=4?s=100" width="100px;" alt="Zioth"/><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>
417
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/glushkova91"><img src="https://avatars.githubusercontent.com/u/13402897?v=4?s=100" width="100px;" alt="glushkova91"/><br /><sub><b>glushkova91</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=glushkova91" title="Documentation">πŸ“–</a></td>
401
418
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/jpveooys"><img src="https://avatars.githubusercontent.com/u/66470099?v=4?s=100" width="100px;" alt="jpveooys"/><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>
419
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/konradr33"><img src="https://avatars.githubusercontent.com/u/32595283?v=4?s=100" width="100px;" alt="konradr33"/><br /><sub><b>konradr33</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Akonradr33" title="Bug reports">πŸ›</a></td>
402
420
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/simonxabris"><img src="https://avatars.githubusercontent.com/u/27497229?v=4?s=100" width="100px;" alt="Ábris Simon"/><br /><sub><b>Ábris Simon</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap/commits?author=simonxabris" title="Code">πŸ’»</a> <a href="https://github.com/focus-trap/focus-trap/issues?q=author%3Asimonxabris" title="Bug reports">πŸ›</a></td>
403
421
  </tr>
404
422
  </tbody>
@@ -1,9 +1,31 @@
1
1
  /*!
2
- * focus-trap 7.5.4
2
+ * focus-trap 7.6.1
3
3
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
4
4
  */
5
5
  import { isFocusable, tabbable, focusable, isTabbable, getTabIndex } from 'tabbable';
6
6
 
7
+ function _arrayLikeToArray(r, a) {
8
+ (null == a || a > r.length) && (a = r.length);
9
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
10
+ return n;
11
+ }
12
+ function _arrayWithoutHoles(r) {
13
+ if (Array.isArray(r)) return _arrayLikeToArray(r);
14
+ }
15
+ function _defineProperty(e, r, t) {
16
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
17
+ value: t,
18
+ enumerable: !0,
19
+ configurable: !0,
20
+ writable: !0
21
+ }) : e[r] = t, e;
22
+ }
23
+ function _iterableToArray(r) {
24
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
25
+ }
26
+ function _nonIterableSpread() {
27
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
28
+ }
7
29
  function ownKeys(e, r) {
8
30
  var t = Object.keys(e);
9
31
  if (Object.getOwnPropertySymbols) {
@@ -25,33 +47,29 @@ function _objectSpread2(e) {
25
47
  }
26
48
  return e;
27
49
  }
28
- function _defineProperty(obj, key, value) {
29
- key = _toPropertyKey(key);
30
- if (key in obj) {
31
- Object.defineProperty(obj, key, {
32
- value: value,
33
- enumerable: true,
34
- configurable: true,
35
- writable: true
36
- });
37
- } else {
38
- obj[key] = value;
39
- }
40
- return obj;
50
+ function _toConsumableArray(r) {
51
+ return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
41
52
  }
42
- function _toPrimitive(input, hint) {
43
- if (typeof input !== "object" || input === null) return input;
44
- var prim = input[Symbol.toPrimitive];
45
- if (prim !== undefined) {
46
- var res = prim.call(input, hint || "default");
47
- if (typeof res !== "object") return res;
53
+ function _toPrimitive(t, r) {
54
+ if ("object" != typeof t || !t) return t;
55
+ var e = t[Symbol.toPrimitive];
56
+ if (void 0 !== e) {
57
+ var i = e.call(t, r || "default");
58
+ if ("object" != typeof i) return i;
48
59
  throw new TypeError("@@toPrimitive must return a primitive value.");
49
60
  }
50
- return (hint === "string" ? String : Number)(input);
61
+ return ("string" === r ? String : Number)(t);
51
62
  }
52
- function _toPropertyKey(arg) {
53
- var key = _toPrimitive(arg, "string");
54
- return typeof key === "symbol" ? key : String(key);
63
+ function _toPropertyKey(t) {
64
+ var i = _toPrimitive(t, "string");
65
+ return "symbol" == typeof i ? i : i + "";
66
+ }
67
+ function _unsupportedIterableToArray(r, a) {
68
+ if (r) {
69
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
70
+ var t = {}.toString.call(r).slice(8, -1);
71
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
72
+ }
55
73
  }
56
74
 
57
75
  var activeFocusTraps = {
@@ -113,10 +131,8 @@ var findIndex = function findIndex(arr, fn) {
113
131
  idx = i;
114
132
  return false; // break
115
133
  }
116
-
117
134
  return true; // next
118
135
  });
119
-
120
136
  return idx;
121
137
  };
122
138
 
@@ -229,7 +245,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
229
245
  return state.containerGroups.findIndex(function (_ref) {
230
246
  var container = _ref.container,
231
247
  tabbableNodes = _ref.tabbableNodes;
232
- return container.contains(element) || ( // fall back to explicit tabbable search which will take into consideration any
248
+ return container.contains(element) || (// fall back to explicit tabbable search which will take into consideration any
233
249
  // web components if the `tabbableOptions.getShadowRoot` option was used for
234
250
  // the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't
235
251
  // look inside web components even if open)
@@ -245,25 +261,31 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
245
261
  * (if a node is explicitly NOT given), or a function that returns any of these
246
262
  * values.
247
263
  * @param {string} optionName
248
- * @returns {undefined | false | HTMLElement | SVGElement} Returns
249
- * `undefined` if the option is not specified; `false` if the option
250
- * resolved to `false` (node explicitly not given); otherwise, the resolved
251
- * DOM node.
264
+ * @param {Object} options
265
+ * @param {boolean} [options.hasFallback] True if the option could be a selector string
266
+ * and the option allows for a fallback scenario in the case where the selector is
267
+ * valid but does not match a node (i.e. the queried node doesn't exist in the DOM).
268
+ * @param {Array} [options.params] Params to pass to the option if it's a function.
269
+ * @returns {undefined | null | false | HTMLElement | SVGElement} Returns
270
+ * `undefined` if the option is not specified; `null` if the option didn't resolve
271
+ * to a node but `options.hasFallback=true`, `false` if the option resolved to `false`
272
+ * (node explicitly not given); otherwise, the resolved DOM node.
252
273
  * @throws {Error} If the option is set, not `false`, and is not, or does not
253
- * resolve to a node.
274
+ * resolve to a node, unless the option is a selector string and `options.hasFallback=true`.
254
275
  */
255
276
  var getNodeForOption = function getNodeForOption(optionName) {
277
+ var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
278
+ _ref2$hasFallback = _ref2.hasFallback,
279
+ hasFallback = _ref2$hasFallback === void 0 ? false : _ref2$hasFallback,
280
+ _ref2$params = _ref2.params,
281
+ params = _ref2$params === void 0 ? [] : _ref2$params;
256
282
  var optionValue = config[optionName];
257
283
  if (typeof optionValue === 'function') {
258
- for (var _len2 = arguments.length, params = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
259
- params[_key2 - 1] = arguments[_key2];
260
- }
261
- optionValue = optionValue.apply(void 0, params);
284
+ optionValue = optionValue.apply(void 0, _toConsumableArray(params));
262
285
  }
263
286
  if (optionValue === true) {
264
287
  optionValue = undefined; // use default value
265
288
  }
266
-
267
289
  if (!optionValue) {
268
290
  if (optionValue === undefined || optionValue === false) {
269
291
  return optionValue;
@@ -275,21 +297,31 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
275
297
  var node = optionValue; // could be HTMLElement, SVGElement, or non-empty string at this point
276
298
 
277
299
  if (typeof optionValue === 'string') {
278
- node = doc.querySelector(optionValue); // resolve to node, or null if fails
300
+ try {
301
+ node = doc.querySelector(optionValue); // resolve to node, or null if fails
302
+ } catch (err) {
303
+ throw new Error("`".concat(optionName, "` appears to be an invalid selector; error=\"").concat(err.message, "\""));
304
+ }
279
305
  if (!node) {
280
- throw new Error("`".concat(optionName, "` as selector refers to no known node"));
306
+ if (!hasFallback) {
307
+ throw new Error("`".concat(optionName, "` as selector refers to no known node"));
308
+ }
309
+ // else, `node` MUST be `null` because that's what `Document.querySelector()` returns
310
+ // if the selector is valid but doesn't match anything
281
311
  }
282
312
  }
283
313
  return node;
284
314
  };
285
315
  var getInitialFocusNode = function getInitialFocusNode() {
286
- var node = getNodeForOption('initialFocus');
316
+ var node = getNodeForOption('initialFocus', {
317
+ hasFallback: true
318
+ });
287
319
 
288
320
  // false explicitly indicates we want no initialFocus at all
289
321
  if (node === false) {
290
322
  return false;
291
323
  }
292
- if (node === undefined || !isFocusable(node, config.tabbableOptions)) {
324
+ if (node === undefined || node && !isFocusable(node, config.tabbableOptions)) {
293
325
  // option not specified nor focusable: use fallback options
294
326
  if (findContainerIndex(doc.activeElement) >= 0) {
295
327
  node = doc.activeElement;
@@ -300,6 +332,10 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
300
332
  // NOTE: `fallbackFocus` option function cannot return `false` (not supported)
301
333
  node = firstTabbableNode || getNodeForOption('fallbackFocus');
302
334
  }
335
+ } else if (node === null) {
336
+ // option is a VALID selector string that doesn't yield a node: use the `fallbackFocus`
337
+ // option instead of the default behavior when the option isn't specified at all
338
+ node = getNodeForOption('fallbackFocus');
303
339
  }
304
340
  if (!node) {
305
341
  throw new Error('Your focus-trap needs to have at least one focusable element');
@@ -409,25 +445,25 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
409
445
  *
410
446
  * @returns {HTMLElement} The element that currently has the focus
411
447
  **/
412
- var getActiveElement = function getActiveElement(el) {
448
+ var _getActiveElement = function getActiveElement(el) {
413
449
  var activeElement = el.activeElement;
414
450
  if (!activeElement) {
415
451
  return;
416
452
  }
417
453
  if (activeElement.shadowRoot && activeElement.shadowRoot.activeElement !== null) {
418
- return getActiveElement(activeElement.shadowRoot);
454
+ return _getActiveElement(activeElement.shadowRoot);
419
455
  }
420
456
  return activeElement;
421
457
  };
422
- var tryFocus = function tryFocus(node) {
458
+ var _tryFocus = function tryFocus(node) {
423
459
  if (node === false) {
424
460
  return;
425
461
  }
426
- if (node === getActiveElement(document)) {
462
+ if (node === _getActiveElement(document)) {
427
463
  return;
428
464
  }
429
465
  if (!node || !node.focus) {
430
- tryFocus(getInitialFocusNode());
466
+ _tryFocus(getInitialFocusNode());
431
467
  return;
432
468
  }
433
469
  node.focus({
@@ -440,7 +476,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
440
476
  }
441
477
  };
442
478
  var getReturnFocusNode = function getReturnFocusNode(previousActiveElement) {
443
- var node = getNodeForOption('setReturnFocus', previousActiveElement);
479
+ var node = getNodeForOption('setReturnFocus', {
480
+ params: [previousActiveElement]
481
+ });
444
482
  return node ? node : node === false ? false : previousActiveElement;
445
483
  };
446
484
 
@@ -455,11 +493,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
455
493
  * @returns {Node|undefined} The next node, or `undefined` if a next node couldn't be
456
494
  * determined given the current state of the trap.
457
495
  */
458
- var findNextNavNode = function findNextNavNode(_ref2) {
459
- var target = _ref2.target,
460
- event = _ref2.event,
461
- _ref2$isBackward = _ref2.isBackward,
462
- isBackward = _ref2$isBackward === void 0 ? false : _ref2$isBackward;
496
+ var findNextNavNode = function findNextNavNode(_ref3) {
497
+ var target = _ref3.target,
498
+ event = _ref3.event,
499
+ _ref3$isBackward = _ref3.isBackward,
500
+ isBackward = _ref3$isBackward === void 0 ? false : _ref3$isBackward;
463
501
  target = target || getActualTarget(event);
464
502
  updateTabbableNodes();
465
503
  var destinationNode = null;
@@ -483,8 +521,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
483
521
  // REVERSE
484
522
 
485
523
  // is the target the first tabbable node in a group?
486
- var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
487
- var firstTabbableNode = _ref3.firstTabbableNode;
524
+ var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref4) {
525
+ var firstTabbableNode = _ref4.firstTabbableNode;
488
526
  return target === firstTabbableNode;
489
527
  });
490
528
  if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) {
@@ -512,8 +550,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
512
550
  // FORWARD
513
551
 
514
552
  // is the target the last tabbable node in a group?
515
- var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref4) {
516
- var lastTabbableNode = _ref4.lastTabbableNode;
553
+ var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref5) {
554
+ var lastTabbableNode = _ref5.lastTabbableNode;
517
555
  return target === lastTabbableNode;
518
556
  });
519
557
  if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) {
@@ -671,9 +709,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
671
709
  });
672
710
  }
673
711
  if (nextNode) {
674
- tryFocus(nextNode);
712
+ _tryFocus(nextNode);
675
713
  } else {
676
- tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
714
+ _tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
677
715
  }
678
716
  }
679
717
  state.recentNavEvent = undefined; // clear
@@ -698,19 +736,21 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
698
736
  // to where it normally would
699
737
  event.preventDefault();
700
738
  }
701
- tryFocus(destinationNode);
739
+ _tryFocus(destinationNode);
702
740
  }
703
741
  // else, let the browser take care of [shift+]tab and move the focus
704
742
  };
743
+ var checkTabKey = function checkTabKey(event) {
744
+ if (config.isKeyForward(event) || config.isKeyBackward(event)) {
745
+ checkKeyNav(event, config.isKeyBackward(event));
746
+ }
747
+ };
705
748
 
706
- var checkKey = function checkKey(event) {
749
+ // we use a different event phase for the Escape key to allow canceling the event and checking for this in escapeDeactivates
750
+ var checkEscapeKey = function checkEscapeKey(event) {
707
751
  if (isEscapeEvent(event) && valueOrHandler(config.escapeDeactivates, event) !== false) {
708
752
  event.preventDefault();
709
753
  trap.deactivate();
710
- return;
711
- }
712
- if (config.isKeyForward(event) || config.isKeyBackward(event)) {
713
- checkKeyNav(event, config.isKeyBackward(event));
714
754
  }
715
755
  };
716
756
  var checkClick = function checkClick(e) {
@@ -743,8 +783,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
743
783
  // Delay ensures that the focused element doesn't capture the event
744
784
  // that caused the focus trap activation.
745
785
  state.delayInitialFocusTimer = config.delayInitialFocus ? delay(function () {
746
- tryFocus(getInitialFocusNode());
747
- }) : tryFocus(getInitialFocusNode());
786
+ _tryFocus(getInitialFocusNode());
787
+ }) : _tryFocus(getInitialFocusNode());
748
788
  doc.addEventListener('focusin', checkFocusIn, true);
749
789
  doc.addEventListener('mousedown', checkPointerDown, {
750
790
  capture: true,
@@ -758,10 +798,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
758
798
  capture: true,
759
799
  passive: false
760
800
  });
761
- doc.addEventListener('keydown', checkKey, {
801
+ doc.addEventListener('keydown', checkTabKey, {
762
802
  capture: true,
763
803
  passive: false
764
804
  });
805
+ doc.addEventListener('keydown', checkEscapeKey);
765
806
  return trap;
766
807
  };
767
808
  var removeListeners = function removeListeners() {
@@ -772,7 +813,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
772
813
  doc.removeEventListener('mousedown', checkPointerDown, true);
773
814
  doc.removeEventListener('touchstart', checkPointerDown, true);
774
815
  doc.removeEventListener('click', checkClick, true);
775
- doc.removeEventListener('keydown', checkKey, true);
816
+ doc.removeEventListener('keydown', checkTabKey, true);
817
+ doc.removeEventListener('keydown', checkEscapeKey);
776
818
  return trap;
777
819
  };
778
820
 
@@ -791,7 +833,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
791
833
  // If the currently focused is removed then browsers will move focus to the
792
834
  // <body> element. If this happens, try to move focus back into the trap.
793
835
  if (isFocusedNodeRemoved) {
794
- tryFocus(getInitialFocusNode());
836
+ _tryFocus(getInitialFocusNode());
795
837
  }
796
838
  };
797
839
 
@@ -877,7 +919,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
877
919
  var finishDeactivation = function finishDeactivation() {
878
920
  delay(function () {
879
921
  if (returnFocus) {
880
- tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
922
+ _tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
881
923
  }
882
924
  onPostDeactivate === null || onPostDeactivate === void 0 || onPostDeactivate();
883
925
  });