focus-trap-react 9.0.1 → 9.0.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 4d8e041: Fix an issue when running in strict mode which has React immediately unmount/remount the trap, causing it to deactivate and then have to reactivate (per existing component state) on the remount. [#720](https://github.com/focus-trap/focus-trap-react/issues/720)
8
+
3
9
  ## 9.0.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # focus-trap-react [![CI](https://github.com/focus-trap/focus-trap-react/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/focus-trap/focus-trap-react/actions?query=workflow:CI+branch:master) [![Codecov](https://img.shields.io/codecov/c/github/focus-trap/focus-trap-react)](https://codecov.io/gh/focus-trap/focus-trap-react) [![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-23-orange.svg?style=flat-square)](#contributors)
4
+ [![All Contributors](https://img.shields.io/badge/all_contributors-24-orange.svg?style=flat-square)](#contributors)
5
5
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
6
6
 
7
7
  A React component that traps focus.
@@ -214,19 +214,20 @@ In alphabetical order:
214
214
  <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>
215
215
  <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>
216
216
  <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>
217
+ <td align="center"><a href="https://www.moroshko.me"><img src="https://avatars.githubusercontent.com/u/259753?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Misha Moroshko</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3Amoroshko" title="Bug reports">🐛</a></td>
217
218
  <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>
218
- <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>
219
219
  </tr>
220
220
  <tr>
221
+ <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>
221
222
  <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>
222
223
  <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>
223
224
  <td align="center"><a href="http://smoores.dev"><img src="https://avatars.githubusercontent.com/u/5354254?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shane Moore</b></sub></a><br /><a href="#platform-SMores" title="Packaging/porting to new platform">📦</a></td>
224
225
  <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> <a href="https://github.com/focus-trap/focus-trap-react/issues?q=author%3ASlapbox" title="Bug reports">🐛</a></td>
225
226
  <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>
226
227
  <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>
227
- <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>
228
228
  </tr>
229
229
  <tr>
230
+ <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>
230
231
  <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>
231
232
  <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>
232
233
  </tr>
@@ -299,7 +299,28 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
299
299
  }, {
300
300
  key: "setupFocusTrap",
301
301
  value: function setupFocusTrap() {
302
- if (!this.focusTrap) {
302
+ if (this.focusTrap) {
303
+ // trap already exists: it's possible we're in StrictMode and we're being remounted,
304
+ // in which case, we will have deactivated the trap when we got unmounted (remember,
305
+ // StrictMode, in development, purposely unmounts and remounts components after
306
+ // mounting them the first time to make sure they have reusable state,
307
+ // @see https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state) so now
308
+ // we need to restore the state of the trap according to our component state
309
+ // NOTE: Strict mode __violates__ assumptions about the `componentWillUnmount()` API
310
+ // which clearly states -- even for React 18 -- that, "Once a component instance is
311
+ // unmounted, __it will never be mounted again.__" (emphasis ours). So when we get
312
+ // unmounted, we assume we're gone forever and we deactivate the trap. But then
313
+ // we get remounted and we're supposed to restore state. But if you had paused,
314
+ // we've now deactivated (we don't know we're amount to get remounted again)
315
+ // which means we need to reactivate and then pause. Otherwise, do nothing.
316
+ if (this.props.active && !this.focusTrap.active) {
317
+ this.focusTrap.activate();
318
+
319
+ if (this.props.paused) {
320
+ this.focusTrap.pause();
321
+ }
322
+ }
323
+ } else {
303
324
  var nodesExist = this.focusTrapElements.some(Boolean);
304
325
 
305
326
  if (nodesExist) {
@@ -448,6 +469,7 @@ FocusTrap.propTypes = {
448
469
  })
449
470
  }),
450
471
  containerElements: PropTypes.arrayOf(PropTypes.instanceOf(ElementType)),
472
+ // DOM element ONLY
451
473
  children: PropTypes.oneOfType([PropTypes.element, // React element
452
474
  PropTypes.instanceOf(ElementType) // DOM element
453
475
  ]) // NOTE: _createFocusTrap is internal, for testing purposes only, so we don't
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "focus-trap-react",
3
- "version": "9.0.1",
3
+ "version": "9.0.2",
4
4
  "description": "A React component that traps focus.",
5
5
  "main": "dist/focus-trap-react.js",
6
6
  "types": "index.d.ts",
@@ -14,8 +14,8 @@
14
14
  "index.d.ts"
15
15
  ],
16
16
  "scripts": {
17
- "demo-bundle": "browserify demo/js -t babelify --extension=.jsx -o demo/demo-bundle.js",
18
- "start": "yarn build && budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify --extension=.jsx",
17
+ "demo-bundle": "NODE_ENV=production browserify demo/js -t babelify --extension=.jsx -o demo/demo-bundle.js",
18
+ "start": "yarn build && NODE_ENV=development budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify --extension=.jsx",
19
19
  "lint": "eslint \"*.js\" \"src/**/*.js\" \"test/**/*.js\" \"demo/**/*.js\" \"cypress/**/*.js\"",
20
20
  "format": "prettier --write \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
21
21
  "format:check": "prettier --check \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*,cypress/**/*}.+(js|yml)\"",
@@ -24,10 +24,10 @@
24
24
  "test:types": "tsc index.d.ts",
25
25
  "test:unit": "jest",
26
26
  "test:coverage": "jest --coverage",
27
- "test:cypress": "start-server-and-test start 9966 'cypress open'",
28
- "test:cypress:ci": "start-server-and-test start 9966 'cypress run --browser $CYPRESS_BROWSER --headless'",
29
- "test:chrome": "CYPRESS_BROWSER=chrome yarn test:cypress:ci",
30
- "test": "yarn format:check && yarn lint && yarn test:unit && yarn test:types && CYPRESS_BROWSER=chrome yarn test:cypress:ci",
27
+ "test:e2e": "ELECTRON_ENABLE_LOGGING=1 start-server-and-test start 9966 'cypress run --browser $CYPRESS_BROWSER --headless'",
28
+ "test:e2e:chrome": "CYPRESS_BROWSER=chrome yarn test:e2e",
29
+ "test:e2e:dev": "ELECTRON_ENABLE_LOGGING=1 start-server-and-test start 9966 'cypress open --browser --e2e'",
30
+ "test": "yarn format:check && yarn lint && yarn test:unit && yarn test:types && yarn test:e2e:chrome",
31
31
  "prepare": "yarn build",
32
32
  "prepublishOnly": "yarn test && yarn build",
33
33
  "release": "yarn build && changeset publish"
@@ -58,12 +58,12 @@
58
58
  "homepage": "https://github.com/focus-trap/focus-trap-react#readme",
59
59
  "devDependencies": {
60
60
  "@babel/cli": "^7.17.10",
61
- "@babel/core": "^7.18.2",
61
+ "@babel/core": "^7.18.5",
62
62
  "@babel/eslint-parser": "^7.18.2",
63
63
  "@babel/plugin-proposal-class-properties": "^7.17.12",
64
64
  "@babel/preset-env": "^7.18.2",
65
65
  "@babel/preset-react": "^7.17.12",
66
- "@changesets/cli": "^2.22.0",
66
+ "@changesets/cli": "^2.23.0",
67
67
  "@testing-library/cypress": "^8.0.3",
68
68
  "@testing-library/dom": "^8.13.0",
69
69
  "@testing-library/jest-dom": "^5.16.4",
@@ -75,7 +75,7 @@
75
75
  "babelify": "^10.0.0",
76
76
  "browserify": "^17.0.0",
77
77
  "budo": "^11.7.0",
78
- "cypress": "^9.7.0",
78
+ "cypress": "^10.1.0",
79
79
  "cypress-plugin-tab": "^1.0.5",
80
80
  "eslint": "^8.17.0",
81
81
  "eslint-config-prettier": "^8.5.0",
@@ -86,10 +86,10 @@
86
86
  "jest-environment-jsdom": "^28.1.1",
87
87
  "jest-watch-typeahead": "^1.1.0",
88
88
  "onchange": "^7.1.0",
89
- "prettier": "^2.6.2",
89
+ "prettier": "^2.7.0",
90
90
  "prop-types": "^15.8.1",
91
- "react": "^18.1.0",
92
- "react-dom": "^18.1.0",
91
+ "react": "^18.2.0",
92
+ "react-dom": "^18.2.0",
93
93
  "regenerator-runtime": "^0.13.9",
94
94
  "start-server-and-test": "^1.14.0",
95
95
  "typescript": "^4.7.3"
@@ -270,7 +270,27 @@ class FocusTrap extends React.Component {
270
270
  }
271
271
 
272
272
  setupFocusTrap() {
273
- if (!this.focusTrap) {
273
+ if (this.focusTrap) {
274
+ // trap already exists: it's possible we're in StrictMode and we're being remounted,
275
+ // in which case, we will have deactivated the trap when we got unmounted (remember,
276
+ // StrictMode, in development, purposely unmounts and remounts components after
277
+ // mounting them the first time to make sure they have reusable state,
278
+ // @see https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state) so now
279
+ // we need to restore the state of the trap according to our component state
280
+ // NOTE: Strict mode __violates__ assumptions about the `componentWillUnmount()` API
281
+ // which clearly states -- even for React 18 -- that, "Once a component instance is
282
+ // unmounted, __it will never be mounted again.__" (emphasis ours). So when we get
283
+ // unmounted, we assume we're gone forever and we deactivate the trap. But then
284
+ // we get remounted and we're supposed to restore state. But if you had paused,
285
+ // we've now deactivated (we don't know we're amount to get remounted again)
286
+ // which means we need to reactivate and then pause. Otherwise, do nothing.
287
+ if (this.props.active && !this.focusTrap.active) {
288
+ this.focusTrap.activate();
289
+ if (this.props.paused) {
290
+ this.focusTrap.pause();
291
+ }
292
+ }
293
+ } else {
274
294
  const nodesExist = this.focusTrapElements.some(Boolean);
275
295
  if (nodesExist) {
276
296
  // eslint-disable-next-line react/prop-types -- _createFocusTrap is an internal prop
@@ -437,7 +457,7 @@ FocusTrap.propTypes = {
437
457
  getShadowRoot: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
438
458
  }),
439
459
  }),
440
- containerElements: PropTypes.arrayOf(PropTypes.instanceOf(ElementType)),
460
+ containerElements: PropTypes.arrayOf(PropTypes.instanceOf(ElementType)), // DOM element ONLY
441
461
  children: PropTypes.oneOfType([
442
462
  PropTypes.element, // React element
443
463
  PropTypes.instanceOf(ElementType), // DOM element