focus-trap-react 6.0.0 → 8.1.0
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 +38 -4
- package/README.md +46 -23
- package/dist/focus-trap-react.js +91 -22
- package/index.d.ts +1 -1
- package/package.json +57 -50
- package/src/focus-trap-react.js +73 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5994a8c: Bump focus-trap from 6.0.1 to 6.1.0. This new version of focus-trap provides a new `delayInitialFocus` flag that can be used to further customize trap behavior.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 0562ef0: Change `prepublishOnly` script to `prepare` script so that it also runs if someone installs the package directly from the git repo (e.g. from your work in which you fixed a bug or added a feature you're waiting to get merged to master and published to NPM).
|
|
12
|
+
|
|
13
|
+
## 8.0.0
|
|
14
|
+
|
|
15
|
+
### Major Changes
|
|
16
|
+
|
|
17
|
+
- 513a2d3: **BREAKING**: Updated [focus-trap](https://github.com/focus-trap/focus-trap/blob/master/CHANGELOG.md#600) dependency to new 6.0.1 release, which contains breaking changes. This update means it's also now using the latest version of [tabbable](https://github.com/focus-trap/tabbable/blob/master/CHANGELOG.md#500), which also has breaking changes. See respective CHANGELOGs for details.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 35040fa: Remove call for maintainers. @stefcameron and @maraisr hope to take up the charge. Additional help and contributors are most welcome for anyone interested!
|
|
22
|
+
- 513a2d3: Changed code formatting to use dangling commas where ES5 supports them.
|
|
23
|
+
|
|
24
|
+
## 7.0.1
|
|
25
|
+
|
|
26
|
+
- Fix: PropTypes definition now supports server-side rendering. [#83](https://github.com/davidtheclark/focus-trap-react/issues/83)
|
|
27
|
+
|
|
28
|
+
## 7.0.0
|
|
29
|
+
|
|
30
|
+
- Add: Prop types for `<FocusTrap>`.
|
|
31
|
+
- Update: `focus-trap` dependency from 4.0.2 to [5.1.0](https://github.com/davidtheclark/focus-trap/blob/master/CHANGELOG.md#510) for the latest features/fixes it provides. [#71](https://github.com/davidtheclark/focus-trap-react/issues/71)
|
|
32
|
+
- **BREAKING** Update: Only React 16.0+ is supported going forward. [#55](https://github.com/davidtheclark/focus-trap-react/issues/55)
|
|
33
|
+
- **BREAKING** Update: All dependencies updated to their latest versions.
|
|
34
|
+
- Fix: `children`'s type is `React.ReactNode`, not `React.ReactElement`. [#66](https://github.com/davidtheclark/focus-trap-react/issues/66)
|
|
35
|
+
- Fix: Allow mutable object refs to be used for FocusTrap child. [#72](https://github.com/davidtheclark/focus-trap-react/issues/72)
|
|
36
|
+
- Fix: `specifiedFocusTrapOptions.includes(optionName)` statement in `componentDidMount()` was causing an exception because `includes()` is not a function defined on `Object`.
|
|
37
|
+
|
|
3
38
|
## 6.0.0
|
|
4
39
|
|
|
5
40
|
- Update focus-trap to 4.0.2, which includes [a queue of traps](https://github.com/davidtheclark/focus-trap/blob/master/CHANGELOG.md#400), so when a trap is paused because another trap activates, it will be unpaused when that other trap deactivates. If Trap A was automatically paused because Trap B activated (existing behavior), when Trap B is deactivated Trap A will be automatically unpaused (new behavior).
|
|
@@ -10,7 +45,7 @@
|
|
|
10
45
|
|
|
11
46
|
## 5.0.0
|
|
12
47
|
|
|
13
|
-
- **
|
|
48
|
+
- **BREAKING:** `<FocusTrap>` now expects exactly one child element which can be any HTML element or other React component that contains focusable elements. The `tag` prop has been removed, as has support for additional props that are passed through to the `tag`, because it is no longer necessary: you should provide your own element, with whatever props you want, as a child of `<FocusTrap>`.
|
|
14
49
|
|
|
15
50
|
## 4.0.1
|
|
16
51
|
|
|
@@ -19,7 +54,7 @@
|
|
|
19
54
|
## 4.0.0
|
|
20
55
|
|
|
21
56
|
- Update focus-trap to 3.0.0, which includes [a couple of behavior changes](https://github.com/davidtheclark/focus-trap/blob/master/CHANGELOG.md#300). The key change is that focus management has been changed so that you can include tricky focusable elements like radio groups, iframes, and shadow DOM components in your trap — as long as the first and last focusable elements in the trap can still be detected by [Tabbable](https://github.com/davidtheclark/tabbable).
|
|
22
|
-
- An effect of this change is that
|
|
57
|
+
- An effect of this change is that _positive tabindexes are no longer guaranteed to work as expected_. You should avoid these.
|
|
23
58
|
|
|
24
59
|
## 3.1.4
|
|
25
60
|
|
|
@@ -51,8 +86,7 @@
|
|
|
51
86
|
|
|
52
87
|
## 3.0.3
|
|
53
88
|
|
|
54
|
-
- Introduce `dist/focus-trap-react.js`, where `src/` now compiles to, since React 15.5+ demands `class`es, so Babel-compilation.
|
|
55
|
-
Which is actually a huge overhaul, though in semver it's just a patch.
|
|
89
|
+
- Introduce `dist/focus-trap-react.js`, where `src/` now compiles to, since React 15.5+ demands `class`es, so Babel-compilation. Which is actually a huge overhaul, though in semver it's just a patch.
|
|
56
90
|
|
|
57
91
|
## 3.0.2
|
|
58
92
|
|
package/README.md
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
# focus-trap-react [](https://github.com/focus-trap/focus-trap-react/actions?query=workflow:CI+branch:master) [](./LICENSE)
|
|
2
|
+
|
|
3
|
+
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
4
|
+
[](#contributors)
|
|
5
|
+
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
2
6
|
|
|
3
7
|
A React component that traps focus.
|
|
4
8
|
|
|
5
|
-
This component is a light wrapper around [focus-trap](https://github.com/
|
|
9
|
+
This component is a light wrapper around [focus-trap](https://github.com/focus-trap/focus-trap),
|
|
6
10
|
tailored to your React-specific needs.
|
|
7
11
|
|
|
8
12
|
You might want it for, say, building [an accessible modal](https://github.com/davidtheclark/react-aria-modal)?
|
|
9
13
|
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
**Looking for co-maintainers!** If you'd like to help maintain this project, please let me know.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
14
|
## What it does
|
|
17
15
|
|
|
18
|
-
[Check out the demo](http://
|
|
16
|
+
[Check out the demo](http://focus-trap.github.io/focus-trap-react/demo/).
|
|
19
17
|
|
|
20
|
-
Please read [the focus-trap documentation](https://github.com/
|
|
18
|
+
Please read [the focus-trap documentation](https://github.com/focus-trap/focus-trap) to understand what a focus trap is, what happens when a focus trap is activated, and what happens when one is deactivated.
|
|
21
19
|
|
|
22
20
|
This module simply provides a React component that creates and manages a focus trap.
|
|
23
21
|
|
|
@@ -66,7 +64,7 @@ For example:
|
|
|
66
64
|
</FocusTrap>
|
|
67
65
|
```
|
|
68
66
|
|
|
69
|
-
You can read further code examples in `demo/` (it's very simple), and [see how it works](http://
|
|
67
|
+
You can read further code examples in `demo/` (it's very simple), and [see how it works](http://focus-trap.github.io/focus-trap-react/demo/).
|
|
70
68
|
|
|
71
69
|
Here's one more simple example:
|
|
72
70
|
|
|
@@ -147,7 +145,7 @@ ReactDOM.render(<DemoOne />, container);
|
|
|
147
145
|
|
|
148
146
|
Type: `Object`, optional
|
|
149
147
|
|
|
150
|
-
Pass any of the options available in [`focus-trap`'s `createOptions`](https://github.com/
|
|
148
|
+
Pass any of the options available in [`focus-trap`'s `createOptions`](https://github.com/focus-trap/focus-trap#focustrap--createfocustrapelement-createoptions).
|
|
151
149
|
|
|
152
150
|
#### active
|
|
153
151
|
|
|
@@ -161,14 +159,39 @@ See `demo/demo-three.jsx`.
|
|
|
161
159
|
|
|
162
160
|
Type: `Boolean`, optional
|
|
163
161
|
|
|
164
|
-
If you would like to pause or unpause the focus trap (see [`focus-trap`'s documentation](https://github.com/
|
|
165
|
-
|
|
166
|
-
## Contributing
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
If you would like to pause or unpause the focus trap (see [`focus-trap`'s documentation](https://github.com/focus-trap/focus-trap#focustrappause)), toggle this prop.
|
|
163
|
+
|
|
164
|
+
## Contributing
|
|
165
|
+
|
|
166
|
+
See [CONTRIBUTING](CONTRIBUTING.md).
|
|
167
|
+
|
|
168
|
+
## Contributors
|
|
169
|
+
|
|
170
|
+
In alphabetical order:
|
|
171
|
+
|
|
172
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
173
|
+
<!-- prettier-ignore-start -->
|
|
174
|
+
<!-- markdownlint-disable -->
|
|
175
|
+
<table>
|
|
176
|
+
<tr>
|
|
177
|
+
<td align="center"><a href="https://github.com/Ayc0"><img src="https://avatars3.githubusercontent.com/u/22725671?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Koltes</b></sub></a><br /><a href="https://github.com/stefcameron/focus-trap-react/issues?q=author%3AAyc0" title="Bug reports">🐛</a></td>
|
|
178
|
+
<td align="center"><a href="https://ofcr.se/"><img src="https://avatars1.githubusercontent.com/u/813865?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Tan</b></sub></a><br /><a href="https://github.com/stefcameron/focus-trap-react/commits?author=bnjmnt4n" title="Documentation">📖</a></td>
|
|
179
|
+
<td align="center"><a href="https://github.com/DSil"><img src="https://avatars1.githubusercontent.com/u/6265045?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel</b></sub></a><br /><a href="#maintenance-DSil" title="Maintenance">🚧</a> <a href="https://github.com/stefcameron/focus-trap-react/commits?author=DSil" title="Tests">⚠️</a></td>
|
|
180
|
+
<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/stefcameron/focus-trap-react/commits?author=davidtheclark" title="Code">💻</a> <a href="https://github.com/stefcameron/focus-trap-react/issues?q=author%3Adavidtheclark" title="Bug reports">🐛</a> <a href="#infra-davidtheclark" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/stefcameron/focus-trap-react/commits?author=davidtheclark" title="Tests">⚠️</a> <a href="https://github.com/stefcameron/focus-trap-react/commits?author=davidtheclark" title="Documentation">📖</a> <a href="#maintenance-davidtheclark" title="Maintenance">🚧</a></td>
|
|
181
|
+
<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>
|
|
182
|
+
<td align="center"><a href="http://kathleenmcmahon.dev/"><img src="https://avatars1.githubusercontent.com/u/11621935?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kathleen McMahon</b></sub></a><br /><a href="#maintenance-resource11" title="Maintenance">🚧</a></td>
|
|
183
|
+
<td align="center"><a href="https://marais.io/"><img src="https://avatars2.githubusercontent.com/u/599459?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marais Rossouw</b></sub></a><br /><a href="#infra-maraisr" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
|
184
|
+
</tr>
|
|
185
|
+
<tr>
|
|
186
|
+
<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/stefcameron/focus-trap-react/commits?author=liunate" title="Tests">⚠️</a></td>
|
|
187
|
+
<td align="center"><a href="https://www.linkedin.com/in/rivajunior/"><img src="https://avatars1.githubusercontent.com/u/11370172?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rivaldo Junior</b></sub></a><br /><a href="#maintenance-rivajunior" title="Maintenance">🚧</a></td>
|
|
188
|
+
<td align="center"><a href="https://scottrippey.github.io/"><img src="https://avatars3.githubusercontent.com/u/430608?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Scott Rippey</b></sub></a><br /><a href="https://github.com/stefcameron/focus-trap-react/commits?author=scottrippey" title="Code">💻</a> <a href="https://github.com/stefcameron/focus-trap-react/issues?q=author%3Ascottrippey" title="Bug reports">🐛</a></td>
|
|
189
|
+
<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/stefcameron/focus-trap-react/commits?author=SeanMcP" title="Code">💻</a></td>
|
|
190
|
+
<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/stefcameron/focus-trap-react/commits?author=stefcameron" title="Code">💻</a> <a href="https://github.com/stefcameron/focus-trap-react/issues?q=author%3Astefcameron" title="Bug reports">🐛</a> <a href="#infra-stefcameron" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/stefcameron/focus-trap-react/commits?author=stefcameron" title="Tests">⚠️</a> <a href="https://github.com/stefcameron/focus-trap-react/commits?author=stefcameron" title="Documentation">📖</a> <a href="#maintenance-stefcameron" title="Maintenance">🚧</a></td>
|
|
191
|
+
</tr>
|
|
192
|
+
</table>
|
|
193
|
+
|
|
194
|
+
<!-- markdownlint-restore -->
|
|
195
|
+
<!-- prettier-ignore-end -->
|
|
196
|
+
|
|
197
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
package/dist/focus-trap-react.js
CHANGED
|
@@ -1,37 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
4
4
|
|
|
5
5
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
6
6
|
|
|
7
|
-
function
|
|
7
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
10
|
+
|
|
11
|
+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
|
12
|
+
|
|
13
|
+
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
|
14
|
+
|
|
15
|
+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
16
|
+
|
|
17
|
+
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
|
18
|
+
|
|
19
|
+
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
|
20
|
+
|
|
21
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
22
|
+
|
|
23
|
+
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|
24
|
+
|
|
25
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
10
26
|
|
|
11
27
|
var React = require('react');
|
|
28
|
+
|
|
12
29
|
var ReactDOM = require('react-dom');
|
|
13
|
-
var createFocusTrap = require('focus-trap');
|
|
14
30
|
|
|
15
|
-
var
|
|
31
|
+
var PropTypes = require('prop-types');
|
|
32
|
+
|
|
33
|
+
var _require = require('focus-trap'),
|
|
34
|
+
createFocusTrap = _require.createFocusTrap; // TODO: These issues are related to older React features which we'll likely need
|
|
35
|
+
// to fix in order to move the code forward to the next major version of React.
|
|
36
|
+
// @see https://github.com/davidtheclark/focus-trap-react/issues/77
|
|
37
|
+
|
|
38
|
+
/* eslint-disable react/no-find-dom-node */
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
16
42
|
_inherits(FocusTrap, _React$Component);
|
|
17
43
|
|
|
44
|
+
var _super = _createSuper(FocusTrap);
|
|
45
|
+
|
|
18
46
|
function FocusTrap(props) {
|
|
47
|
+
var _this;
|
|
48
|
+
|
|
19
49
|
_classCallCheck(this, FocusTrap);
|
|
20
50
|
|
|
21
|
-
|
|
51
|
+
_this = _super.call(this, props);
|
|
22
52
|
|
|
23
|
-
_this
|
|
53
|
+
_defineProperty(_assertThisInitialized(_this), "setFocusTrapElement", function (element) {
|
|
24
54
|
_this.focusTrapElement = element;
|
|
25
|
-
};
|
|
55
|
+
});
|
|
26
56
|
|
|
27
57
|
if (typeof document !== 'undefined') {
|
|
28
58
|
_this.previouslyFocusedElement = document.activeElement;
|
|
29
59
|
}
|
|
60
|
+
|
|
30
61
|
return _this;
|
|
31
62
|
}
|
|
32
63
|
|
|
33
64
|
_createClass(FocusTrap, [{
|
|
34
|
-
key:
|
|
65
|
+
key: "componentDidMount",
|
|
35
66
|
value: function componentDidMount() {
|
|
36
67
|
// We need to hijack the returnFocusOnDeactivate option,
|
|
37
68
|
// because React can move focus into the element before we arrived at
|
|
@@ -42,30 +73,40 @@ var FocusTrap = function (_React$Component) {
|
|
|
42
73
|
var tailoredFocusTrapOptions = {
|
|
43
74
|
returnFocusOnDeactivate: false
|
|
44
75
|
};
|
|
76
|
+
|
|
45
77
|
for (var optionName in specifiedFocusTrapOptions) {
|
|
46
|
-
if (!
|
|
47
|
-
|
|
78
|
+
if (!Object.prototype.hasOwnProperty.call(specifiedFocusTrapOptions, optionName)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (optionName === 'returnFocusOnDeactivate') {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
48
86
|
tailoredFocusTrapOptions[optionName] = specifiedFocusTrapOptions[optionName];
|
|
49
87
|
}
|
|
50
88
|
|
|
51
|
-
var focusTrapElementDOMNode = ReactDOM.findDOMNode(this.focusTrapElement);
|
|
89
|
+
var focusTrapElementDOMNode = ReactDOM.findDOMNode(this.focusTrapElement); // eslint-disable-next-line react/prop-types -- _createFocusTrap is an internal prop
|
|
52
90
|
|
|
53
91
|
this.focusTrap = this.props._createFocusTrap(focusTrapElementDOMNode, tailoredFocusTrapOptions);
|
|
92
|
+
|
|
54
93
|
if (this.props.active) {
|
|
55
94
|
this.focusTrap.activate();
|
|
56
95
|
}
|
|
96
|
+
|
|
57
97
|
if (this.props.paused) {
|
|
58
98
|
this.focusTrap.pause();
|
|
59
99
|
}
|
|
60
100
|
}
|
|
61
101
|
}, {
|
|
62
|
-
key:
|
|
102
|
+
key: "componentDidUpdate",
|
|
63
103
|
value: function componentDidUpdate(prevProps) {
|
|
64
104
|
if (prevProps.active && !this.props.active) {
|
|
65
105
|
var returnFocusOnDeactivate = this.props.focusTrapOptions.returnFocusOnDeactivate;
|
|
66
|
-
|
|
67
106
|
var returnFocus = returnFocusOnDeactivate || false;
|
|
68
|
-
var config = {
|
|
107
|
+
var config = {
|
|
108
|
+
returnFocus: returnFocus
|
|
109
|
+
};
|
|
69
110
|
this.focusTrap.deactivate(config);
|
|
70
111
|
} else if (!prevProps.active && this.props.active) {
|
|
71
112
|
this.focusTrap.activate();
|
|
@@ -78,15 +119,16 @@ var FocusTrap = function (_React$Component) {
|
|
|
78
119
|
}
|
|
79
120
|
}
|
|
80
121
|
}, {
|
|
81
|
-
key:
|
|
122
|
+
key: "componentWillUnmount",
|
|
82
123
|
value: function componentWillUnmount() {
|
|
83
124
|
this.focusTrap.deactivate();
|
|
125
|
+
|
|
84
126
|
if (this.props.focusTrapOptions.returnFocusOnDeactivate !== false && this.previouslyFocusedElement && this.previouslyFocusedElement.focus) {
|
|
85
127
|
this.previouslyFocusedElement.focus();
|
|
86
128
|
}
|
|
87
129
|
}
|
|
88
130
|
}, {
|
|
89
|
-
key:
|
|
131
|
+
key: "render",
|
|
90
132
|
value: function render() {
|
|
91
133
|
var _this2 = this;
|
|
92
134
|
|
|
@@ -94,25 +136,52 @@ var FocusTrap = function (_React$Component) {
|
|
|
94
136
|
|
|
95
137
|
var composedRefCallback = function composedRefCallback(element) {
|
|
96
138
|
_this2.setFocusTrapElement(element);
|
|
139
|
+
|
|
97
140
|
if (typeof child.ref === 'function') {
|
|
98
141
|
child.ref(element);
|
|
142
|
+
} else if (child.ref) {
|
|
143
|
+
child.ref.current = element;
|
|
99
144
|
}
|
|
100
145
|
};
|
|
101
146
|
|
|
102
|
-
var childWithRef = React.cloneElement(child, {
|
|
103
|
-
|
|
147
|
+
var childWithRef = React.cloneElement(child, {
|
|
148
|
+
ref: composedRefCallback
|
|
149
|
+
});
|
|
104
150
|
return childWithRef;
|
|
105
151
|
}
|
|
106
152
|
}]);
|
|
107
153
|
|
|
108
154
|
return FocusTrap;
|
|
109
|
-
}(React.Component);
|
|
155
|
+
}(React.Component); // support server-side rendering where `Element` will not be defined
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
var ElementType = typeof Element === 'undefined' ? Function : Element;
|
|
159
|
+
FocusTrap.propTypes = {
|
|
160
|
+
active: PropTypes.bool,
|
|
161
|
+
paused: PropTypes.bool,
|
|
162
|
+
focusTrapOptions: PropTypes.shape({
|
|
163
|
+
onActivate: PropTypes.func,
|
|
164
|
+
onDeactivate: PropTypes.func,
|
|
165
|
+
initialFocus: PropTypes.oneOfType([PropTypes.instanceOf(ElementType), PropTypes.string, PropTypes.func]),
|
|
166
|
+
fallbackFocus: PropTypes.oneOfType([PropTypes.instanceOf(ElementType), PropTypes.string, PropTypes.func]),
|
|
167
|
+
escapeDeactivates: PropTypes.bool,
|
|
168
|
+
clickOutsideDeactivates: PropTypes.bool,
|
|
169
|
+
returnFocusOnDeactivate: PropTypes.bool,
|
|
170
|
+
setReturnFocus: PropTypes.oneOfType([PropTypes.instanceOf(ElementType), PropTypes.string, PropTypes.func]),
|
|
171
|
+
allowOutsideClick: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
|
172
|
+
preventScroll: PropTypes.bool
|
|
173
|
+
}),
|
|
174
|
+
children: PropTypes.oneOfType([PropTypes.element, // React element
|
|
175
|
+
PropTypes.instanceOf(ElementType) // DOM element
|
|
176
|
+
]) // NOTE: _createFocusTrap is internal, for testing purposes only, so we don't
|
|
177
|
+
// specify it here. It's expected to be set to the function returned from
|
|
178
|
+
// require('focus-trap'), or one with a compatible interface.
|
|
110
179
|
|
|
180
|
+
};
|
|
111
181
|
FocusTrap.defaultProps = {
|
|
112
182
|
active: true,
|
|
113
183
|
paused: false,
|
|
114
184
|
focusTrapOptions: {},
|
|
115
185
|
_createFocusTrap: createFocusTrap
|
|
116
186
|
};
|
|
117
|
-
|
|
118
187
|
module.exports = FocusTrap;
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "focus-trap-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "A React component that traps focus.",
|
|
5
5
|
"main": "dist/focus-trap-react.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"dist",
|
|
12
|
+
"src",
|
|
13
|
+
"index.d.ts"
|
|
14
|
+
],
|
|
7
15
|
"scripts": {
|
|
8
16
|
"demo-bundle": "browserify demo/js -t babelify --extension=.jsx -o demo/demo-bundle.js",
|
|
9
|
-
"start": "budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify --extension=.jsx",
|
|
10
|
-
"lint": "eslint
|
|
11
|
-
"format": "prettier --
|
|
17
|
+
"start": "yarn build && budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify --extension=.jsx",
|
|
18
|
+
"lint": "eslint \"*.js\" \"src/**/*.js\" \"test/**/*.js\" \"demo/**/*.js\"",
|
|
19
|
+
"format": "prettier --write \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
|
|
20
|
+
"format-check": "prettier --check \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
|
|
12
21
|
"build": "babel src -d dist",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"test": "
|
|
16
|
-
"
|
|
22
|
+
"test-types": "tsc index.d.ts",
|
|
23
|
+
"test-unit": "jest",
|
|
24
|
+
"test-cypress": "start-server-and-test start 9966 'cypress open'",
|
|
25
|
+
"test-cypress-ci": "start-server-and-test start 9966 'cypress run --browser $CYPRESS_BROWSER --headless'",
|
|
26
|
+
"test": "yarn format-check && yarn lint && yarn test-unit && yarn test-types && CYPRESS_BROWSER=chrome yarn test-cypress-ci",
|
|
27
|
+
"prepare": "yarn build",
|
|
28
|
+
"release": "yarn build && changeset publish"
|
|
17
29
|
},
|
|
18
30
|
"repository": {
|
|
19
31
|
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/
|
|
32
|
+
"url": "git+https://github.com/focus-trap/focus-trap-react.git"
|
|
21
33
|
},
|
|
22
|
-
"files": [
|
|
23
|
-
"dist",
|
|
24
|
-
"src",
|
|
25
|
-
"index.d.ts"
|
|
26
|
-
],
|
|
27
34
|
"keywords": [
|
|
28
35
|
"react",
|
|
29
36
|
"reactjs",
|
|
@@ -35,49 +42,49 @@
|
|
|
35
42
|
"focus",
|
|
36
43
|
"keyboard"
|
|
37
44
|
],
|
|
38
|
-
"author":
|
|
45
|
+
"author": {
|
|
46
|
+
"name": "David Clark",
|
|
47
|
+
"url": "http://davidtheclark.com/"
|
|
48
|
+
},
|
|
39
49
|
"license": "MIT",
|
|
40
50
|
"bugs": {
|
|
41
|
-
"url": "https://github.com/
|
|
51
|
+
"url": "https://github.com/focus-trap/focus-trap-react/issues"
|
|
42
52
|
},
|
|
43
|
-
"homepage": "https://github.com/
|
|
53
|
+
"homepage": "https://github.com/focus-trap/focus-trap-react#readme",
|
|
44
54
|
"devDependencies": {
|
|
45
|
-
"babel
|
|
46
|
-
"babel
|
|
47
|
-
"babel
|
|
48
|
-
"babel
|
|
49
|
-
"babel
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"eslint
|
|
55
|
-
"jest": "^
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
55
|
+
"@babel/cli": "^7.11.6",
|
|
56
|
+
"@babel/core": "^7.11.6",
|
|
57
|
+
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
|
58
|
+
"@babel/preset-env": "^7.11.5",
|
|
59
|
+
"@babel/preset-react": "^7.10.4",
|
|
60
|
+
"@changesets/cli": "^2.10.3",
|
|
61
|
+
"@testing-library/cypress": "^7.0.1",
|
|
62
|
+
"@types/jquery": "^3.5.1",
|
|
63
|
+
"all-contributors-cli": "^6.17.4",
|
|
64
|
+
"babel-eslint": "^10.1.0",
|
|
65
|
+
"babel-jest": "^26.3.0",
|
|
66
|
+
"babelify": "^10.0.0",
|
|
67
|
+
"browserify": "^16.5.2",
|
|
68
|
+
"budo": "^11.6.4",
|
|
69
|
+
"cypress": "^5.2.0",
|
|
70
|
+
"cypress-plugin-tab": "^1.0.5",
|
|
71
|
+
"eslint": "^7.9.0",
|
|
72
|
+
"eslint-config-prettier": "^6.11.0",
|
|
73
|
+
"eslint-plugin-react": "^7.21.0",
|
|
74
|
+
"jest": "^26.4.2",
|
|
75
|
+
"prettier": "^2.1.2",
|
|
76
|
+
"prop-types": "^15.7.2",
|
|
77
|
+
"react": "^16.13.1",
|
|
78
|
+
"react-dom": "^16.13.1",
|
|
79
|
+
"start-server-and-test": "^1.11.4",
|
|
80
|
+
"typescript": "^4.0.3"
|
|
59
81
|
},
|
|
60
82
|
"dependencies": {
|
|
61
|
-
"focus-trap": "^
|
|
83
|
+
"focus-trap": "^6.1.0"
|
|
62
84
|
},
|
|
63
85
|
"peerDependencies": {
|
|
64
|
-
"
|
|
65
|
-
"react
|
|
66
|
-
|
|
67
|
-
"babel": {
|
|
68
|
-
"presets": [
|
|
69
|
-
"react",
|
|
70
|
-
"es2015"
|
|
71
|
-
],
|
|
72
|
-
"plugins": [
|
|
73
|
-
"transform-class-properties"
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
"jest": {
|
|
77
|
-
"setupFiles": [
|
|
78
|
-
"<rootDir>/test/jest-setup.js"
|
|
79
|
-
],
|
|
80
|
-
"clearMocks": true,
|
|
81
|
-
"testURL": "http://localhost"
|
|
86
|
+
"prop-types": "^15.7.2",
|
|
87
|
+
"react": "^16.0.0",
|
|
88
|
+
"react-dom": "^16.0.0"
|
|
82
89
|
}
|
|
83
90
|
}
|
package/src/focus-trap-react.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
const React = require('react');
|
|
2
2
|
const ReactDOM = require('react-dom');
|
|
3
|
-
const
|
|
3
|
+
const PropTypes = require('prop-types');
|
|
4
|
+
const { createFocusTrap } = require('focus-trap');
|
|
5
|
+
|
|
6
|
+
// TODO: These issues are related to older React features which we'll likely need
|
|
7
|
+
// to fix in order to move the code forward to the next major version of React.
|
|
8
|
+
// @see https://github.com/davidtheclark/focus-trap-react/issues/77
|
|
9
|
+
/* eslint-disable react/no-find-dom-node */
|
|
4
10
|
|
|
5
11
|
class FocusTrap extends React.Component {
|
|
6
12
|
constructor(props) {
|
|
7
|
-
super(props)
|
|
13
|
+
super(props);
|
|
8
14
|
|
|
9
15
|
if (typeof document !== 'undefined') {
|
|
10
16
|
this.previouslyFocusedElement = document.activeElement;
|
|
@@ -19,17 +25,30 @@ class FocusTrap extends React.Component {
|
|
|
19
25
|
// then (optionally) returns focus to it in componentWillUnmount.
|
|
20
26
|
const specifiedFocusTrapOptions = this.props.focusTrapOptions;
|
|
21
27
|
const tailoredFocusTrapOptions = {
|
|
22
|
-
returnFocusOnDeactivate: false
|
|
28
|
+
returnFocusOnDeactivate: false,
|
|
23
29
|
};
|
|
30
|
+
|
|
24
31
|
for (const optionName in specifiedFocusTrapOptions) {
|
|
25
|
-
if (
|
|
26
|
-
|
|
32
|
+
if (
|
|
33
|
+
!Object.prototype.hasOwnProperty.call(
|
|
34
|
+
specifiedFocusTrapOptions,
|
|
35
|
+
optionName
|
|
36
|
+
)
|
|
37
|
+
) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (optionName === 'returnFocusOnDeactivate') {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
27
45
|
tailoredFocusTrapOptions[optionName] =
|
|
28
46
|
specifiedFocusTrapOptions[optionName];
|
|
29
47
|
}
|
|
30
48
|
|
|
31
49
|
const focusTrapElementDOMNode = ReactDOM.findDOMNode(this.focusTrapElement);
|
|
32
50
|
|
|
51
|
+
// eslint-disable-next-line react/prop-types -- _createFocusTrap is an internal prop
|
|
33
52
|
this.focusTrap = this.props._createFocusTrap(
|
|
34
53
|
focusTrapElementDOMNode,
|
|
35
54
|
tailoredFocusTrapOptions
|
|
@@ -70,31 +89,75 @@ class FocusTrap extends React.Component {
|
|
|
70
89
|
}
|
|
71
90
|
}
|
|
72
91
|
|
|
73
|
-
setFocusTrapElement = element => {
|
|
92
|
+
setFocusTrapElement = (element) => {
|
|
74
93
|
this.focusTrapElement = element;
|
|
75
94
|
};
|
|
76
95
|
|
|
77
96
|
render() {
|
|
78
97
|
const child = React.Children.only(this.props.children);
|
|
79
98
|
|
|
80
|
-
const composedRefCallback = element => {
|
|
99
|
+
const composedRefCallback = (element) => {
|
|
81
100
|
this.setFocusTrapElement(element);
|
|
82
101
|
if (typeof child.ref === 'function') {
|
|
83
102
|
child.ref(element);
|
|
103
|
+
} else if (child.ref) {
|
|
104
|
+
child.ref.current = element;
|
|
84
105
|
}
|
|
85
|
-
}
|
|
106
|
+
};
|
|
86
107
|
|
|
87
|
-
const childWithRef = React.cloneElement(child, {
|
|
108
|
+
const childWithRef = React.cloneElement(child, {
|
|
109
|
+
ref: composedRefCallback,
|
|
110
|
+
});
|
|
88
111
|
|
|
89
112
|
return childWithRef;
|
|
90
113
|
}
|
|
91
114
|
}
|
|
92
115
|
|
|
116
|
+
// support server-side rendering where `Element` will not be defined
|
|
117
|
+
const ElementType = typeof Element === 'undefined' ? Function : Element;
|
|
118
|
+
|
|
119
|
+
FocusTrap.propTypes = {
|
|
120
|
+
active: PropTypes.bool,
|
|
121
|
+
paused: PropTypes.bool,
|
|
122
|
+
focusTrapOptions: PropTypes.shape({
|
|
123
|
+
onActivate: PropTypes.func,
|
|
124
|
+
onDeactivate: PropTypes.func,
|
|
125
|
+
initialFocus: PropTypes.oneOfType([
|
|
126
|
+
PropTypes.instanceOf(ElementType),
|
|
127
|
+
PropTypes.string,
|
|
128
|
+
PropTypes.func,
|
|
129
|
+
]),
|
|
130
|
+
fallbackFocus: PropTypes.oneOfType([
|
|
131
|
+
PropTypes.instanceOf(ElementType),
|
|
132
|
+
PropTypes.string,
|
|
133
|
+
PropTypes.func,
|
|
134
|
+
]),
|
|
135
|
+
escapeDeactivates: PropTypes.bool,
|
|
136
|
+
clickOutsideDeactivates: PropTypes.bool,
|
|
137
|
+
returnFocusOnDeactivate: PropTypes.bool,
|
|
138
|
+
setReturnFocus: PropTypes.oneOfType([
|
|
139
|
+
PropTypes.instanceOf(ElementType),
|
|
140
|
+
PropTypes.string,
|
|
141
|
+
PropTypes.func,
|
|
142
|
+
]),
|
|
143
|
+
allowOutsideClick: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
|
144
|
+
preventScroll: PropTypes.bool,
|
|
145
|
+
}),
|
|
146
|
+
children: PropTypes.oneOfType([
|
|
147
|
+
PropTypes.element, // React element
|
|
148
|
+
PropTypes.instanceOf(ElementType), // DOM element
|
|
149
|
+
]),
|
|
150
|
+
|
|
151
|
+
// NOTE: _createFocusTrap is internal, for testing purposes only, so we don't
|
|
152
|
+
// specify it here. It's expected to be set to the function returned from
|
|
153
|
+
// require('focus-trap'), or one with a compatible interface.
|
|
154
|
+
};
|
|
155
|
+
|
|
93
156
|
FocusTrap.defaultProps = {
|
|
94
157
|
active: true,
|
|
95
158
|
paused: false,
|
|
96
159
|
focusTrapOptions: {},
|
|
97
|
-
_createFocusTrap: createFocusTrap
|
|
160
|
+
_createFocusTrap: createFocusTrap,
|
|
98
161
|
};
|
|
99
162
|
|
|
100
163
|
module.exports = FocusTrap;
|