Socket
Socket
Sign inDemoInstall

focus-trap-react

Package Overview
Dependencies
Maintainers
5
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

focus-trap-react - npm Package Compare versions

Comparing version 8.5.1 to 8.6.0

12

CHANGELOG.md
# Changelog
## 8.6.0
### Minor Changes
- 5292ae8:
- Adding support for new focus-trap options from focus-trap v6.5.0: `checkCanFocusTrap()`, `onPostActivate()`, `checkCanReturnFocus()`, and `onPostDeactivate()`.
- Adding support (bug fix) for existing focus-trap `setReturnFocus` option that had thus far been ignored, with focus-trap-react always returning focus to the previously-focused element prior to activation regardless of the use of the `setReturnFocus` option. The option is now respected the same as it is when using focus-trap directly.
### Patch Changes
- 24704c7: Bump focus-trap dependency to 6.5.1 for bug fix to onPostDeactivate.
## 8.5.1

@@ -4,0 +16,0 @@

132

dist/focus-trap-react.js

@@ -73,2 +73,7 @@ "use strict";

if (optionName === 'onPostDeactivate') {
_this.onPostDeactivate = focusTrapOptions[optionName];
continue;
}
_this.tailoredFocusTrapOptions[optionName] = focusTrapOptions[optionName];

@@ -85,7 +90,43 @@ } // elements from which to create the focus trap on mount; if a child is used

return _this;
}
/** Update the previously focused element with the currently focused element. */
} // TODO: Need more test coverage for this function
_createClass(FocusTrap, [{
key: "getNodeForOption",
value: function getNodeForOption(optionName) {
var optionValue = this.tailoredFocusTrapOptions[optionName];
if (!optionValue) {
return null;
}
var node = optionValue;
if (typeof optionValue === 'string') {
node = document.querySelector(optionValue);
if (!node) {
throw new Error("`".concat(optionName, "` refers to no known node"));
}
}
if (typeof optionValue === 'function') {
node = optionValue();
if (!node) {
throw new Error("`".concat(optionName, "` did not return a node"));
}
}
return node;
}
}, {
key: "getReturnFocusNode",
value: function getReturnFocusNode() {
var node = this.getNodeForOption('setReturnFocus');
return node ? node : this.previouslyFocusedElement;
}
/** Update the previously focused element with the currently focused element. */
}, {
key: "updatePreviousElement",

@@ -97,10 +138,37 @@ value: function updatePreviousElement() {

}
/** Returns focus to the element that had focus when the trap was activated. */
}, {
key: "deactivateTrap",
value: function deactivateTrap() {
var _this2 = this;
}, {
key: "returnFocus",
value: function returnFocus() {
if (this.previouslyFocusedElement && this.previouslyFocusedElement.focus) {
this.previouslyFocusedElement.focus();
var checkCanReturnFocus = this.tailoredFocusTrapOptions.checkCanReturnFocus;
if (this.focusTrap) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({
returnFocus: false
});
}
var finishDeactivation = function finishDeactivation() {
var returnFocusNode = _this2.getReturnFocusNode();
var canReturnFocus = (returnFocusNode === null || returnFocusNode === void 0 ? void 0 : returnFocusNode.focus) && _this2.returnFocusOnDeactivate;
if (canReturnFocus) {
/** Returns focus to the element that had focus when the trap was activated. */
returnFocusNode.focus();
}
if (_this2.onPostDeactivate) {
_this2.onPostDeactivate.call(null); // don't call it in context of "this"
}
};
if (checkCanReturnFocus) {
checkCanReturnFocus(this.getReturnFocusNode()).then(finishDeactivation, finishDeactivation);
} else {
finishDeactivation();
}
}

@@ -144,24 +212,23 @@ }, {

if (prevProps.active && !this.props.active) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({
returnFocus: false
});
var hasActivated = !prevProps.active && this.props.active;
var hasDeactivated = prevProps.active && !this.props.active;
var hasPaused = !prevProps.paused && this.props.paused;
var hasUnpaused = prevProps.paused && !this.props.paused;
if (this.returnFocusOnDeactivate) {
this.returnFocus();
}
if (hasActivated) {
this.updatePreviousElement();
this.focusTrap.activate();
}
if (hasDeactivated) {
this.deactivateTrap();
return; // un/pause does nothing on an inactive trap
}
if (!prevProps.active && this.props.active) {
this.updatePreviousElement();
this.focusTrap.activate();
if (hasPaused) {
this.focusTrap.pause();
}
if (prevProps.paused && !this.props.paused) {
if (hasUnpaused) {
this.focusTrap.unpause();
} else if (!prevProps.paused && this.props.paused) {
this.focusTrap.pause();
}

@@ -176,12 +243,3 @@ } else if (prevProps.containerElements !== this.props.containerElements) {

value: function componentWillUnmount() {
if (this.focusTrap) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({
returnFocus: false
});
}
if (this.returnFocusOnDeactivate) {
this.returnFocus();
}
this.deactivateTrap();
}

@@ -191,3 +249,3 @@ }, {

value: function render() {
var _this2 = this;
var _this3 = this;

@@ -202,3 +260,3 @@ var child = this.props.children ? React.Children.only(this.props.children) : undefined;

var composedRefCallback = function composedRefCallback(element) {
var containerElements = _this2.props.containerElements;
var containerElements = _this3.props.containerElements;

@@ -213,3 +271,3 @@ if (child) {

_this2.focusTrapElements = containerElements ? containerElements : [element];
_this3.focusTrapElements = containerElements ? containerElements : [element];
};

@@ -237,3 +295,7 @@

onActivate: PropTypes.func,
onPostActivate: PropTypes.func,
checkCanFocusTrap: PropTypes.func,
onDeactivate: PropTypes.func,
onPostDeactivate: PropTypes.func,
checkCanReturnFocus: PropTypes.func,
initialFocus: PropTypes.oneOfType([PropTypes.instanceOf(ElementType), PropTypes.string, PropTypes.func]),

@@ -240,0 +302,0 @@ fallbackFocus: PropTypes.oneOfType([PropTypes.instanceOf(ElementType), PropTypes.string, PropTypes.func]),

{
"name": "focus-trap-react",
"version": "8.5.1",
"version": "8.6.0",
"description": "A React component that traps focus.",

@@ -58,11 +58,11 @@ "main": "dist/focus-trap-react.js",

"devDependencies": {
"@babel/cli": "^7.14.3",
"@babel/core": "^7.14.3",
"@babel/cli": "^7.14.5",
"@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/preset-env": "^7.14.4",
"@babel/preset-react": "^7.13.13",
"@babel/preset-env": "^7.14.5",
"@babel/preset-react": "^7.14.5",
"@changesets/cli": "^2.16.0",
"@testing-library/cypress": "^7.0.6",
"@testing-library/dom": "^7.31.0",
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/dom": "^7.31.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",

@@ -77,12 +77,12 @@ "@testing-library/user-event": "^13.1.9",

"budo": "^11.6.4",
"cypress": "^7.4.0",
"cypress": "^7.5.0",
"cypress-plugin-tab": "^1.0.5",
"eslint": "^7.27.0",
"eslint": "^7.28.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-react": "^7.24.0",
"jest": "^26.6.3",
"jest": "^27.0.4",
"jest-watch-typeahead": "^0.6.4",
"onchange": "^7.1.0",
"prettier": "^2.3.0",
"prettier": "^2.3.1",
"prop-types": "^15.7.2",

@@ -92,7 +92,7 @@ "react": "^17.0.2",

"regenerator-runtime": "^0.13.7",
"start-server-and-test": "^1.12.3",
"start-server-and-test": "^1.12.5",
"typescript": "^4.3.2"
},
"dependencies": {
"focus-trap": "^6.5.0"
"focus-trap": "^6.5.1"
},

@@ -99,0 +99,0 @@ "peerDependencies": {

# 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)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

@@ -189,7 +189,8 @@

<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/focus-trap/focus-trap-react/commits?author=DSil" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/Dan503"><img src="https://avatars.githubusercontent.com/u/10610368?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Tonon</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/commits?author=Dan503" title="Documentation">📖</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=Dan503" title="Code">💻</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=Dan503" title="Tests">⚠️</a></td>
<td align="center"><a href="http://davidtheclark.com/"><img src="https://avatars2.githubusercontent.com/u/628431?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Clark</b></sub></a><br /><a href="https://github.com/focus-trap/focus-trap-react/commits?author=davidtheclark" title="Code">💻</a> <a href="https://github.com/focus-trap/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/focus-trap/focus-trap-react/commits?author=davidtheclark" title="Tests">⚠️</a> <a href="https://github.com/focus-trap/focus-trap-react/commits?author=davidtheclark" title="Documentation">📖</a> <a href="#maintenance-davidtheclark" title="Maintenance">🚧</a></td>
<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>
<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>
</tr>
<tr>
<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>
<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>

@@ -201,5 +202,5 @@ <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>

<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>
<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>
</tr>
<tr>
<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>
<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>

@@ -206,0 +207,0 @@ <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>

@@ -39,2 +39,7 @@ const React = require('react');

if (optionName === 'onPostDeactivate') {
this.onPostDeactivate = focusTrapOptions[optionName];
continue;
}
this.tailoredFocusTrapOptions[optionName] = focusTrapOptions[optionName];

@@ -52,2 +57,34 @@ }

// TODO: Need more test coverage for this function
getNodeForOption(optionName) {
const optionValue = this.tailoredFocusTrapOptions[optionName];
if (!optionValue) {
return null;
}
let node = optionValue;
if (typeof optionValue === 'string') {
node = document.querySelector(optionValue);
if (!node) {
throw new Error(`\`${optionName}\` refers to no known node`);
}
}
if (typeof optionValue === 'function') {
node = optionValue();
if (!node) {
throw new Error(`\`${optionName}\` did not return a node`);
}
}
return node;
}
getReturnFocusNode() {
const node = this.getNodeForOption('setReturnFocus');
return node ? node : this.previouslyFocusedElement;
}
/** Update the previously focused element with the currently focused element. */

@@ -60,7 +97,33 @@ updatePreviousElement() {

/** Returns focus to the element that had focus when the trap was activated. */
returnFocus() {
if (this.previouslyFocusedElement && this.previouslyFocusedElement.focus) {
this.previouslyFocusedElement.focus();
deactivateTrap() {
const { checkCanReturnFocus } = this.tailoredFocusTrapOptions;
if (this.focusTrap) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({ returnFocus: false });
}
const finishDeactivation = () => {
const returnFocusNode = this.getReturnFocusNode();
const canReturnFocus =
returnFocusNode?.focus && this.returnFocusOnDeactivate;
if (canReturnFocus) {
/** Returns focus to the element that had focus when the trap was activated. */
returnFocusNode.focus();
}
if (this.onPostDeactivate) {
this.onPostDeactivate.call(null); // don't call it in context of "this"
}
};
if (checkCanReturnFocus) {
checkCanReturnFocus(this.getReturnFocusNode()).then(
finishDeactivation,
finishDeactivation
);
} else {
finishDeactivation();
}
}

@@ -106,12 +169,8 @@

if (prevProps.active && !this.props.active) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({ returnFocus: false });
if (this.returnFocusOnDeactivate) {
this.returnFocus();
}
return; // un/pause does nothing on an inactive trap
}
const hasActivated = !prevProps.active && this.props.active;
const hasDeactivated = prevProps.active && !this.props.active;
const hasPaused = !prevProps.paused && this.props.paused;
const hasUnpaused = prevProps.paused && !this.props.paused;
if (!prevProps.active && this.props.active) {
if (hasActivated) {
this.updatePreviousElement();

@@ -121,7 +180,14 @@ this.focusTrap.activate();

if (prevProps.paused && !this.props.paused) {
this.focusTrap.unpause();
} else if (!prevProps.paused && this.props.paused) {
if (hasDeactivated) {
this.deactivateTrap();
return; // un/pause does nothing on an inactive trap
}
if (hasPaused) {
this.focusTrap.pause();
}
if (hasUnpaused) {
this.focusTrap.unpause();
}
} else if (prevProps.containerElements !== this.props.containerElements) {

@@ -134,10 +200,3 @@ this.focusTrapElements = this.props.containerElements;

componentWillUnmount() {
if (this.focusTrap) {
// NOTE: we never let the trap return the focus since we do that ourselves
this.focusTrap.deactivate({ returnFocus: false });
}
if (this.returnFocusOnDeactivate) {
this.returnFocus();
}
this.deactivateTrap();
}

@@ -192,3 +251,7 @@

onActivate: PropTypes.func,
onPostActivate: PropTypes.func,
checkCanFocusTrap: PropTypes.func,
onDeactivate: PropTypes.func,
onPostDeactivate: PropTypes.func,
checkCanReturnFocus: PropTypes.func,
initialFocus: PropTypes.oneOfType([

@@ -195,0 +258,0 @@ PropTypes.instanceOf(ElementType),

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc