focus-trap-react 8.8.1 → 8.9.2
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 +28 -0
- package/README.md +7 -3
- package/dist/focus-trap-react.js +52 -13
- package/package.json +25 -25
- package/src/focus-trap-react.js +46 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.9.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 83e283c: Update focus-trap to v6.7.3 for bug fix related to elements with a negative `tabindex`.
|
|
8
|
+
|
|
9
|
+
## 8.9.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 3eb9421: Bump focus-trap to v6.7.2 for bug fix.
|
|
14
|
+
|
|
15
|
+
## 8.9.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 83097a5: Delay trap creation until it should be active. This is a change in behavior, however it should not break existing behavior. The delay now allows you to set `active=false` until you have the `focusTrapOptions` set correctly. [#539](https://github.com/focus-trap/focus-trap-react/issues/539)
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- 16d1ae1: Fix bug where global document was being accessed instead of first checking for `focusTrapOptions.document` option. [#539](https://github.com/focus-trap/focus-trap-react/issues/539)
|
|
24
|
+
|
|
25
|
+
## 8.8.2
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- 08a9449: Use `preventScroll` option on deactivation if returning focus.
|
|
30
|
+
|
|
3
31
|
## 8.8.1
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# focus-trap-react [](https://github.com/focus-trap/focus-trap-react/actions?query=workflow:CI+branch:master) [](https://codecov.io/gh/focus-trap/focus-trap-react) [](./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
|
A React component that traps focus.
|
|
@@ -191,20 +191,24 @@ In alphabetical order:
|
|
|
191
191
|
<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>
|
|
192
192
|
</tr>
|
|
193
193
|
<tr>
|
|
194
|
+
<td align="center"><a href="https://github.com/jhnns"><img src="https://avatars.githubusercontent.com/u/781746?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johannes Ewald</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/commits?author=jhnns" title="Code">💻</a></td>
|
|
194
195
|
<td align="center"><a href="http://josuzuki.me"><img src="https://avatars1.githubusercontent.com/u/9583920?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan Suzuki</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3AJoSuzuki" title="Bug reports">🐛</a></td>
|
|
195
196
|
<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>
|
|
197
|
+
<td align="center"><a href="https://github.com/LoganDark"><img src="https://avatars.githubusercontent.com/u/4723091?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LoganDark</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3ALoganDark" title="Bug reports">🐛</a></td>
|
|
196
198
|
<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>
|
|
197
199
|
<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-react/commits?author=liunate" title="Tests">⚠️</a></td>
|
|
198
200
|
<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>
|
|
199
|
-
<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/focus-trap/focus-trap-react/commits?author=scottrippey" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3Ascottrippey" title="Bug reports">🐛</a></td>
|
|
200
|
-
<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-react/commits?author=SeanMcP" title="Code">💻</a></td>
|
|
201
201
|
</tr>
|
|
202
202
|
<tr>
|
|
203
|
+
<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/focus-trap/focus-trap-react/commits?author=scottrippey" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3Ascottrippey" title="Bug reports">🐛</a></td>
|
|
204
|
+
<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-react/commits?author=SeanMcP" title="Code">💻</a></td>
|
|
203
205
|
<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-react/commits?author=Slapbox" title="Documentation">📖</a></td>
|
|
204
206
|
<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-react/commits?author=stefcameron" title="Code">💻</a> <a href="https://github.com/focus-trap/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/focus-trap/focus-trap-react/commits?author=stefcameron" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=stefcameron" title="Documentation">📖</a> <a href="#maintenance-stefcameron" title="Maintenance">🚧</a></td>
|
|
205
207
|
<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="https://github.com/focus-trap/focus-trap-react/commits?author=thawkin3" title="Documentation">📖</a> <a href="#example-thawkin3" title="Examples">💡</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=thawkin3" title="Tests">⚠️</a> <a href="#tool-thawkin3" title="Tools">🔧</a></td>
|
|
206
208
|
<td align="center"><a href="https://github.com/wandroll"><img src="https://avatars.githubusercontent.com/u/4492317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wandrille Verlut</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/commits?author=wandroll" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=wandroll" title="Tests">⚠️</a></td>
|
|
207
209
|
<td align="center"><a href="https://github.com/krikienoid"><img src="https://avatars3.githubusercontent.com/u/8528227?v=4?s=100" width="100px;" alt=""/><br /><sub><b>krikienoid</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3Akrikienoid" title="Bug reports">🐛</a></td>
|
|
210
|
+
</tr>
|
|
211
|
+
<tr>
|
|
208
212
|
<td align="center"><a href="https://github.com/syntactic-salt"><img src="https://avatars.githubusercontent.com/u/9385662?v=4?s=100" width="100px;" alt=""/><br /><sub><b>syntactic-salt</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3Asyntactic-salt" title="Bug reports">🐛</a></td>
|
|
209
213
|
</tr>
|
|
210
214
|
</table>
|
package/dist/focus-trap-react.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof";
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _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
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 _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
9
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
10
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); }
|
|
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 } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
|
12
12
|
|
|
13
13
|
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
|
14
14
|
|
|
@@ -86,10 +86,23 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
86
86
|
_this.updatePreviousElement();
|
|
87
87
|
|
|
88
88
|
return _this;
|
|
89
|
-
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Gets the configured document.
|
|
92
|
+
* @returns {Document|undefined} Configured document, falling back to the main
|
|
93
|
+
* document, if it exists. During SSR, `undefined` is returned since the
|
|
94
|
+
* document doesn't exist.
|
|
95
|
+
*/
|
|
90
96
|
|
|
91
97
|
|
|
92
98
|
_createClass(FocusTrap, [{
|
|
99
|
+
key: "getDocument",
|
|
100
|
+
value: function getDocument() {
|
|
101
|
+
// SSR: careful to check if `document` exists before accessing it as a variable
|
|
102
|
+
return this.props.focusTrapOptions.document || (typeof document !== 'undefined' ? document : undefined);
|
|
103
|
+
} // TODO: Need more test coverage for this function
|
|
104
|
+
|
|
105
|
+
}, {
|
|
93
106
|
key: "getNodeForOption",
|
|
94
107
|
value: function getNodeForOption(optionName) {
|
|
95
108
|
var optionValue = this.tailoredFocusTrapOptions[optionName];
|
|
@@ -101,7 +114,9 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
101
114
|
var node = optionValue;
|
|
102
115
|
|
|
103
116
|
if (typeof optionValue === 'string') {
|
|
104
|
-
|
|
117
|
+
var _this$getDocument;
|
|
118
|
+
|
|
119
|
+
node = (_this$getDocument = this.getDocument()) === null || _this$getDocument === void 0 ? void 0 : _this$getDocument.querySelector(optionValue);
|
|
105
120
|
|
|
106
121
|
if (!node) {
|
|
107
122
|
throw new Error("`".concat(optionName, "` refers to no known node"));
|
|
@@ -129,8 +144,7 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
129
144
|
}, {
|
|
130
145
|
key: "updatePreviousElement",
|
|
131
146
|
value: function updatePreviousElement() {
|
|
132
|
-
|
|
133
|
-
var currentDocument = this.props.focusTrapOptions.document || (typeof document !== 'undefined' ? document : undefined);
|
|
147
|
+
var currentDocument = this.getDocument();
|
|
134
148
|
|
|
135
149
|
if (currentDocument) {
|
|
136
150
|
this.previouslyFocusedElement = currentDocument.activeElement;
|
|
@@ -141,7 +155,10 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
141
155
|
value: function deactivateTrap() {
|
|
142
156
|
var _this2 = this;
|
|
143
157
|
|
|
144
|
-
var
|
|
158
|
+
var _this$tailoredFocusTr = this.tailoredFocusTrapOptions,
|
|
159
|
+
checkCanReturnFocus = _this$tailoredFocusTr.checkCanReturnFocus,
|
|
160
|
+
_this$tailoredFocusTr2 = _this$tailoredFocusTr.preventScroll,
|
|
161
|
+
preventScroll = _this$tailoredFocusTr2 === void 0 ? false : _this$tailoredFocusTr2;
|
|
145
162
|
|
|
146
163
|
if (this.focusTrap) {
|
|
147
164
|
// NOTE: we never let the trap return the focus since we do that ourselves
|
|
@@ -157,7 +174,9 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
157
174
|
|
|
158
175
|
if (canReturnFocus) {
|
|
159
176
|
/** Returns focus to the element that had focus when the trap was activated. */
|
|
160
|
-
returnFocusNode.focus(
|
|
177
|
+
returnFocusNode.focus({
|
|
178
|
+
preventScroll: preventScroll
|
|
179
|
+
});
|
|
161
180
|
}
|
|
162
181
|
|
|
163
182
|
if (_this2.onPostDeactivate) {
|
|
@@ -199,7 +218,14 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
199
218
|
}, {
|
|
200
219
|
key: "componentDidMount",
|
|
201
220
|
value: function componentDidMount() {
|
|
202
|
-
this.
|
|
221
|
+
if (this.props.active) {
|
|
222
|
+
this.setupFocusTrap();
|
|
223
|
+
} // else, wait for later activation in case the `focusTrapOptions` will be updated
|
|
224
|
+
// again before the trap is activated (e.g. if waiting to know what the document
|
|
225
|
+
// object will be, so the Trap must be rendered, but the consumer is waiting to
|
|
226
|
+
// activate until they have obtained the document from a ref)
|
|
227
|
+
// @see https://github.com/focus-trap/focus-trap-react/issues/539
|
|
228
|
+
|
|
203
229
|
}
|
|
204
230
|
}, {
|
|
205
231
|
key: "componentDidUpdate",
|
|
@@ -231,9 +257,22 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
|
|
|
231
257
|
if (hasUnpaused) {
|
|
232
258
|
this.focusTrap.unpause();
|
|
233
259
|
}
|
|
234
|
-
} else
|
|
235
|
-
|
|
236
|
-
|
|
260
|
+
} else {
|
|
261
|
+
// NOTE: if we're in `componentDidUpdate` and we don't have a trap yet,
|
|
262
|
+
// it either means it shouldn't be active, or it should be but none of
|
|
263
|
+
// of given `containerElements` were present in the DOM the last time
|
|
264
|
+
// we tried to create the trap
|
|
265
|
+
if (prevProps.containerElements !== this.props.containerElements) {
|
|
266
|
+
this.focusTrapElements = this.props.containerElements;
|
|
267
|
+
} // don't create the trap unless it should be active in case the consumer
|
|
268
|
+
// is still updating `focusTrapOptions`
|
|
269
|
+
// @see https://github.com/focus-trap/focus-trap-react/issues/539
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
if (this.props.active) {
|
|
273
|
+
this.updatePreviousElement();
|
|
274
|
+
this.setupFocusTrap();
|
|
275
|
+
}
|
|
237
276
|
}
|
|
238
277
|
}
|
|
239
278
|
}, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "focus-trap-react",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.9.2",
|
|
4
4
|
"description": "A React component that traps focus.",
|
|
5
5
|
"main": "dist/focus-trap-react.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -55,46 +55,46 @@
|
|
|
55
55
|
},
|
|
56
56
|
"homepage": "https://github.com/focus-trap/focus-trap-react#readme",
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@babel/cli": "^7.
|
|
59
|
-
"@babel/core": "^7.
|
|
60
|
-
"@babel/
|
|
61
|
-
"@babel/
|
|
62
|
-
"@babel/preset-
|
|
63
|
-
"@
|
|
64
|
-
"@
|
|
65
|
-
"@testing-library/
|
|
66
|
-
"@testing-library/
|
|
67
|
-
"@testing-library/
|
|
68
|
-
"@testing-library/
|
|
69
|
-
"@
|
|
58
|
+
"@babel/cli": "^7.17.0",
|
|
59
|
+
"@babel/core": "^7.17.2",
|
|
60
|
+
"@babel/eslint-parser": "^7.17.0",
|
|
61
|
+
"@babel/plugin-proposal-class-properties": "^7.16.5",
|
|
62
|
+
"@babel/preset-env": "^7.16.11",
|
|
63
|
+
"@babel/preset-react": "^7.16.7",
|
|
64
|
+
"@changesets/cli": "^2.20.0",
|
|
65
|
+
"@testing-library/cypress": "^8.0.2",
|
|
66
|
+
"@testing-library/dom": "^8.11.3",
|
|
67
|
+
"@testing-library/jest-dom": "^5.16.2",
|
|
68
|
+
"@testing-library/react": "^12.1.2",
|
|
69
|
+
"@testing-library/user-event": "^13.5.0",
|
|
70
|
+
"@types/jquery": "^3.5.13",
|
|
70
71
|
"all-contributors-cli": "^6.20.0",
|
|
71
|
-
"babel-
|
|
72
|
-
"babel-jest": "^27.2.1",
|
|
72
|
+
"babel-jest": "^27.5.1",
|
|
73
73
|
"babelify": "^10.0.0",
|
|
74
74
|
"browserify": "^17.0.0",
|
|
75
75
|
"budo": "^11.6.4",
|
|
76
|
-
"cypress": "^
|
|
76
|
+
"cypress": "^9.4.1",
|
|
77
77
|
"cypress-plugin-tab": "^1.0.5",
|
|
78
|
-
"eslint": "^
|
|
78
|
+
"eslint": "^8.8.0",
|
|
79
79
|
"eslint-config-prettier": "^8.3.0",
|
|
80
80
|
"eslint-plugin-cypress": "^2.12.1",
|
|
81
|
-
"eslint-plugin-react": "^7.
|
|
82
|
-
"jest": "^27.
|
|
83
|
-
"jest-watch-typeahead": "^0.
|
|
81
|
+
"eslint-plugin-react": "^7.28.0",
|
|
82
|
+
"jest": "^27.5.1",
|
|
83
|
+
"jest-watch-typeahead": "^1.0.0",
|
|
84
84
|
"onchange": "^7.1.0",
|
|
85
|
-
"prettier": "^2.
|
|
86
|
-
"prop-types": "^15.
|
|
85
|
+
"prettier": "^2.5.1",
|
|
86
|
+
"prop-types": "^15.8.1",
|
|
87
87
|
"react": "^17.0.2",
|
|
88
88
|
"react-dom": "^17.0.2",
|
|
89
89
|
"regenerator-runtime": "^0.13.9",
|
|
90
90
|
"start-server-and-test": "^1.14.0",
|
|
91
|
-
"typescript": "^4.
|
|
91
|
+
"typescript": "^4.5.5"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"focus-trap": "^6.7.
|
|
94
|
+
"focus-trap": "^6.7.3"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"prop-types": "^15.
|
|
97
|
+
"prop-types": "^15.8.1",
|
|
98
98
|
"react": ">=16.0.0",
|
|
99
99
|
"react-dom": ">=16.0.0"
|
|
100
100
|
}
|
package/src/focus-trap-react.js
CHANGED
|
@@ -53,6 +53,20 @@ class FocusTrap extends React.Component {
|
|
|
53
53
|
this.updatePreviousElement();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Gets the configured document.
|
|
58
|
+
* @returns {Document|undefined} Configured document, falling back to the main
|
|
59
|
+
* document, if it exists. During SSR, `undefined` is returned since the
|
|
60
|
+
* document doesn't exist.
|
|
61
|
+
*/
|
|
62
|
+
getDocument() {
|
|
63
|
+
// SSR: careful to check if `document` exists before accessing it as a variable
|
|
64
|
+
return (
|
|
65
|
+
this.props.focusTrapOptions.document ||
|
|
66
|
+
(typeof document !== 'undefined' ? document : undefined)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
// TODO: Need more test coverage for this function
|
|
57
71
|
getNodeForOption(optionName) {
|
|
58
72
|
const optionValue = this.tailoredFocusTrapOptions[optionName];
|
|
@@ -63,7 +77,7 @@ class FocusTrap extends React.Component {
|
|
|
63
77
|
let node = optionValue;
|
|
64
78
|
|
|
65
79
|
if (typeof optionValue === 'string') {
|
|
66
|
-
node =
|
|
80
|
+
node = this.getDocument()?.querySelector(optionValue);
|
|
67
81
|
if (!node) {
|
|
68
82
|
throw new Error(`\`${optionName}\` refers to no known node`);
|
|
69
83
|
}
|
|
@@ -87,17 +101,15 @@ class FocusTrap extends React.Component {
|
|
|
87
101
|
|
|
88
102
|
/** Update the previously focused element with the currently focused element. */
|
|
89
103
|
updatePreviousElement() {
|
|
90
|
-
|
|
91
|
-
const currentDocument =
|
|
92
|
-
this.props.focusTrapOptions.document ||
|
|
93
|
-
(typeof document !== 'undefined' ? document : undefined);
|
|
104
|
+
const currentDocument = this.getDocument();
|
|
94
105
|
if (currentDocument) {
|
|
95
106
|
this.previouslyFocusedElement = currentDocument.activeElement;
|
|
96
107
|
}
|
|
97
108
|
}
|
|
98
109
|
|
|
99
110
|
deactivateTrap() {
|
|
100
|
-
const { checkCanReturnFocus } =
|
|
111
|
+
const { checkCanReturnFocus, preventScroll = false } =
|
|
112
|
+
this.tailoredFocusTrapOptions;
|
|
101
113
|
|
|
102
114
|
if (this.focusTrap) {
|
|
103
115
|
// NOTE: we never let the trap return the focus since we do that ourselves
|
|
@@ -111,7 +123,9 @@ class FocusTrap extends React.Component {
|
|
|
111
123
|
|
|
112
124
|
if (canReturnFocus) {
|
|
113
125
|
/** Returns focus to the element that had focus when the trap was activated. */
|
|
114
|
-
returnFocusNode.focus(
|
|
126
|
+
returnFocusNode.focus({
|
|
127
|
+
preventScroll,
|
|
128
|
+
});
|
|
115
129
|
}
|
|
116
130
|
|
|
117
131
|
if (this.onPostDeactivate) {
|
|
@@ -158,7 +172,14 @@ class FocusTrap extends React.Component {
|
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
componentDidMount() {
|
|
161
|
-
this.
|
|
175
|
+
if (this.props.active) {
|
|
176
|
+
this.setupFocusTrap();
|
|
177
|
+
}
|
|
178
|
+
// else, wait for later activation in case the `focusTrapOptions` will be updated
|
|
179
|
+
// again before the trap is activated (e.g. if waiting to know what the document
|
|
180
|
+
// object will be, so the Trap must be rendered, but the consumer is waiting to
|
|
181
|
+
// activate until they have obtained the document from a ref)
|
|
182
|
+
// @see https://github.com/focus-trap/focus-trap-react/issues/539
|
|
162
183
|
}
|
|
163
184
|
|
|
164
185
|
componentDidUpdate(prevProps) {
|
|
@@ -189,9 +210,23 @@ class FocusTrap extends React.Component {
|
|
|
189
210
|
if (hasUnpaused) {
|
|
190
211
|
this.focusTrap.unpause();
|
|
191
212
|
}
|
|
192
|
-
} else
|
|
193
|
-
|
|
194
|
-
|
|
213
|
+
} else {
|
|
214
|
+
// NOTE: if we're in `componentDidUpdate` and we don't have a trap yet,
|
|
215
|
+
// it either means it shouldn't be active, or it should be but none of
|
|
216
|
+
// of given `containerElements` were present in the DOM the last time
|
|
217
|
+
// we tried to create the trap
|
|
218
|
+
|
|
219
|
+
if (prevProps.containerElements !== this.props.containerElements) {
|
|
220
|
+
this.focusTrapElements = this.props.containerElements;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// don't create the trap unless it should be active in case the consumer
|
|
224
|
+
// is still updating `focusTrapOptions`
|
|
225
|
+
// @see https://github.com/focus-trap/focus-trap-react/issues/539
|
|
226
|
+
if (this.props.active) {
|
|
227
|
+
this.updatePreviousElement();
|
|
228
|
+
this.setupFocusTrap();
|
|
229
|
+
}
|
|
195
230
|
}
|
|
196
231
|
}
|
|
197
232
|
|