Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-focus-lock

Package Overview
Dependencies
Maintainers
1
Versions
106
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-focus-lock - npm Package Compare versions

Comparing version 1.17.7 to 1.18.0

dist/cjs/FocusGuard.js

8

dist/cjs/index.js

@@ -26,2 +26,8 @@ "use strict";

});
Object.defineProperty(exports, "InFocusGuard", {
enumerable: true,
get: function get() {
return _FocusGuard.default;
}
});
exports.default = void 0;

@@ -37,3 +43,5 @@

var _FocusGuard = _interopRequireDefault(require("./FocusGuard"));
var _default = _Lock.default;
exports.default = _default;

25

dist/cjs/Lock.js

@@ -38,2 +38,4 @@ "use strict";

var _FocusGuard = require("./FocusGuard");
var RenderChildren = function RenderChildren(_ref) {

@@ -48,11 +50,3 @@ var children = _ref.children;

var Fragment = _react.default.Fragment ? _react.default.Fragment : RenderChildren;
var hidden = {
width: '1px',
height: '0px',
padding: 0,
overflow: 'hidden',
position: 'fixed',
top: '1px',
left: '1px'
};
var emptyArray = [];

@@ -139,2 +133,4 @@ var FocusLock =

whiteList = _this$props.whiteList,
_this$props$shards = _this$props.shards,
shards = _this$props$shards === void 0 ? emptyArray : _this$props$shards,
_this$props$as = _this$props.as,

@@ -158,3 +154,3 @@ Container = _this$props$as === void 0 ? 'div' : _this$props$as,

tabIndex: disabled ? -1 : 0,
style: hidden
style: _FocusGuard.hiddenGuard
}), // nearest focus guard

@@ -165,3 +161,3 @@ _react.default.createElement("div", {

tabIndex: disabled ? -1 : 1,
style: hidden
style: _FocusGuard.hiddenGuard
})], _react.default.createElement(Container, (0, _extends2.default)({

@@ -179,2 +175,3 @@ ref: this.setObserveNode

whiteList: whiteList,
shards: shards,
onActivation: this.onActivation,

@@ -185,3 +182,3 @@ onDeactivation: this.onDeactivation

tabIndex: disabled ? -1 : 0,
style: hidden
style: _FocusGuard.hiddenGuard
}));

@@ -204,2 +201,5 @@ }

whiteList: _propTypes.default.func,
shards: _propTypes.default.arrayOf(_propTypes.default.shape({
current: _propTypes.default.instanceOf(Element)
})),
as: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.object]),

@@ -220,2 +220,3 @@ lockProps: _propTypes.default.object,

whiteList: undefined,
shards: undefined,
as: 'div',

@@ -222,0 +223,0 @@ lockProps: {},

@@ -12,2 +12,4 @@ "use strict";

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _react = _interopRequireDefault(require("react"));

@@ -54,2 +56,23 @@

function autoGuard(startIndex, end, step, allNodes) {
var lastGuard = null;
var i = startIndex;
do {
var node = allNodes[i];
if (node.guard) {
lastGuard = node;
} else if (node.lockItem) {
lastGuard = null;
} else {
break;
}
} while ((i += step) !== end);
if (lastGuard) {
lastGuard.node.tabIndex = 0;
}
}
var activateTrap = function activateTrap() {

@@ -62,19 +85,51 @@ var result = false;

persistentFocus = _lastActiveTrap.persistentFocus,
autoFocus = _lastActiveTrap.autoFocus;
autoFocus = _lastActiveTrap.autoFocus,
shards = _lastActiveTrap.shards;
var workingNode = observed || lastPortaledElement && lastPortaledElement.portaledElement;
var activeElement = document && document.activeElement;
if (!activeElement || focusWhitelisted(activeElement)) {
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) {
if (workingNode && !((0, _focusLock.focusInside)(workingNode) || focusIsPortaledPair(activeElement, workingNode))) {
if (document && !lastActiveFocus && activeElement && !autoFocus) {
activeElement.blur();
document.body.focus();
} else {
result = (0, _focusLock.default)(workingNode, lastActiveFocus);
lastPortaledElement = {};
if (workingNode) {
var workingArea = [workingNode].concat((0, _toConsumableArray2.default)(shards.map(function (_ref) {
var current = _ref.current;
return current;
})));
if (!activeElement || focusWhitelisted(activeElement)) {
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) {
if (workingNode && !((0, _focusLock.focusInside)(workingArea) || focusIsPortaledPair(activeElement, workingNode))) {
if (document && !lastActiveFocus && activeElement && !autoFocus) {
activeElement.blur();
document.body.focus();
} else {
result = (0, _focusLock.default)(workingArea, lastActiveFocus);
lastPortaledElement = {};
}
}
lastActiveFocus = document && document.activeElement;
}
}
lastActiveFocus = document && document.activeElement;
if (document) {
var newActiveElement = document && document.activeElement;
var allNodes = (0, _focusLock.getFocusabledIn)(workingArea);
var focusedItem = allNodes.find(function (_ref2) {
var node = _ref2.node;
return node === newActiveElement;
});
if (focusedItem) {
// remove old focus
allNodes.filter(function (_ref3) {
var guard = _ref3.guard,
node = _ref3.node;
return guard && node.dataset.focusAutoGuard;
}).forEach(function (_ref4) {
var node = _ref4.node;
return node.removeAttribute('tabIndex');
});
var focusedIndex = allNodes.indexOf(focusedItem);
autoGuard(focusedIndex, allNodes.length, +1, allNodes);
autoGuard(focusedIndex, -1, -1, allNodes);
}
}

@@ -117,4 +172,4 @@ }

var FocusTrap = function FocusTrap(_ref) {
var children = _ref.children;
var FocusTrap = function FocusTrap(_ref5) {
var children = _ref5.children;
return _react.default.createElement("div", {

@@ -141,4 +196,4 @@ onBlur: onBlur,

function reducePropsToState(propsList) {
return propsList.filter(function (_ref2) {
var disabled = _ref2.disabled;
return propsList.filter(function (_ref6) {
var disabled = _ref6.disabled;
return !disabled;

@@ -145,0 +200,0 @@ }).slice(-1)[0];

@@ -5,3 +5,4 @@ import FocusLock from './Lock';

import FreeFocusInside from './FreeFocusInside';
export { AutoFocusInside, MoveFocusInside, FreeFocusInside };
import InFocusGuard from './FocusGuard';
export { AutoFocusInside, MoveFocusInside, FreeFocusInside, InFocusGuard };
export default FocusLock;

@@ -9,2 +9,3 @@ import _extends from "@babel/runtime/helpers/extends";

import FocusTrap, { onBlur, onFocus } from './Trap';
import { hiddenGuard } from './FocusGuard';

@@ -20,11 +21,3 @@ var RenderChildren = function RenderChildren(_ref) {

var Fragment = React.Fragment ? React.Fragment : RenderChildren;
var hidden = {
width: '1px',
height: '0px',
padding: 0,
overflow: 'hidden',
position: 'fixed',
top: '1px',
left: '1px'
};
var emptyArray = [];

@@ -117,2 +110,4 @@ var FocusLock =

whiteList = _this$props.whiteList,
_this$props$shards = _this$props.shards,
shards = _this$props$shards === void 0 ? emptyArray : _this$props$shards,
_this$props$as = _this$props.as,

@@ -137,3 +132,3 @@ Container = _this$props$as === void 0 ? 'div' : _this$props$as,

tabIndex: disabled ? -1 : 0,
style: hidden
style: hiddenGuard
}), // nearest focus guard

@@ -144,3 +139,3 @@ React.createElement("div", {

tabIndex: disabled ? -1 : 1,
style: hidden
style: hiddenGuard
})], React.createElement(Container, _extends({

@@ -158,2 +153,3 @@ ref: this.setObserveNode

whiteList: whiteList,
shards: shards,
onActivation: this.onActivation,

@@ -164,3 +160,3 @@ onDeactivation: this.onDeactivation

tabIndex: disabled ? -1 : 0,
style: hidden
style: hiddenGuard
}));

@@ -183,2 +179,5 @@ };

whiteList: PropTypes.func,
shards: PropTypes.arrayOf(PropTypes.shape({
current: PropTypes.instanceOf(Element)
})),
as: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),

@@ -199,2 +198,3 @@ lockProps: PropTypes.object,

whiteList: undefined,
shards: undefined,
as: 'div',

@@ -201,0 +201,0 @@ lockProps: {},

import React from 'react';
import PropTypes from 'prop-types';
import withSideEffect from 'react-clientside-effect';
import moveFocusInside, { focusInside, focusIsHidden } from 'focus-lock';
import moveFocusInside, { focusInside, focusIsHidden, getFocusabledIn } from 'focus-lock';
import { deferAction } from './util';

@@ -38,2 +38,23 @@

function autoGuard(startIndex, end, step, allNodes) {
var lastGuard = null;
var i = startIndex;
do {
var node = allNodes[i];
if (node.guard) {
lastGuard = node;
} else if (node.lockItem) {
lastGuard = null;
} else {
break;
}
} while ((i += step) !== end);
if (lastGuard) {
lastGuard.node.tabIndex = 0;
}
}
var activateTrap = function activateTrap() {

@@ -46,19 +67,51 @@ var result = false;

persistentFocus = _lastActiveTrap.persistentFocus,
autoFocus = _lastActiveTrap.autoFocus;
autoFocus = _lastActiveTrap.autoFocus,
shards = _lastActiveTrap.shards;
var workingNode = observed || lastPortaledElement && lastPortaledElement.portaledElement;
var activeElement = document && document.activeElement;
if (!activeElement || focusWhitelisted(activeElement)) {
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) {
if (workingNode && !(focusInside(workingNode) || focusIsPortaledPair(activeElement, workingNode))) {
if (document && !lastActiveFocus && activeElement && !autoFocus) {
activeElement.blur();
document.body.focus();
} else {
result = moveFocusInside(workingNode, lastActiveFocus);
lastPortaledElement = {};
if (workingNode) {
var workingArea = [workingNode].concat(shards.map(function (_ref) {
var current = _ref.current;
return current;
}));
if (!activeElement || focusWhitelisted(activeElement)) {
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) {
if (workingNode && !(focusInside(workingArea) || focusIsPortaledPair(activeElement, workingNode))) {
if (document && !lastActiveFocus && activeElement && !autoFocus) {
activeElement.blur();
document.body.focus();
} else {
result = moveFocusInside(workingArea, lastActiveFocus);
lastPortaledElement = {};
}
}
lastActiveFocus = document && document.activeElement;
}
}
lastActiveFocus = document && document.activeElement;
if (document) {
var newActiveElement = document && document.activeElement;
var allNodes = getFocusabledIn(workingArea);
var focusedItem = allNodes.find(function (_ref2) {
var node = _ref2.node;
return node === newActiveElement;
});
if (focusedItem) {
// remove old focus
allNodes.filter(function (_ref3) {
var guard = _ref3.guard,
node = _ref3.node;
return guard && node.dataset.focusAutoGuard;
}).forEach(function (_ref4) {
var node = _ref4.node;
return node.removeAttribute('tabIndex');
});
var focusedIndex = allNodes.indexOf(focusedItem);
autoGuard(focusedIndex, allNodes.length, +1, allNodes);
autoGuard(focusedIndex, -1, -1, allNodes);
}
}

@@ -96,4 +149,4 @@ }

var FocusTrap = function FocusTrap(_ref) {
var children = _ref.children;
var FocusTrap = function FocusTrap(_ref5) {
var children = _ref5.children;
return React.createElement("div", {

@@ -120,4 +173,4 @@ onBlur: onBlur,

function reducePropsToState(propsList) {
return propsList.filter(function (_ref2) {
var disabled = _ref2.disabled;
return propsList.filter(function (_ref6) {
var disabled = _ref6.disabled;
return !disabled;

@@ -124,0 +177,0 @@ }).slice(-1)[0];

{
"name": "react-focus-lock",
"version": "1.17.7",
"version": "1.18.0",
"description": "It is a trap! (for a focus)",

@@ -79,3 +79,3 @@ "main": "dist/cjs/index.js",

"sinon": "3.2.1",
"size-limit": "^0.21.0"
"size-limit": "^0.21.1"
},

@@ -85,3 +85,3 @@ "homepage": "https://github.com/theKashey/react-focus-lock#readme",

"@babel/runtime": "^7.0.0",
"focus-lock": "^0.5.2",
"focus-lock": "^0.6.0",
"prop-types": "^15.6.2",

@@ -88,0 +88,0 @@ "react-clientside-effect": "^1.2.0"

@@ -70,2 +70,7 @@ declare module 'react-focus-lock' {

/**
* Shards forms a scattered lock, same as `group` does, but in more "low" and controlled way
*/
shards?: Array<React.RefObject<any>>;
children: React.ReactNode;

@@ -83,2 +88,6 @@ }

interface InFocusGuardProps {
children: React.ReactNode;
}
/**

@@ -107,2 +116,8 @@ * Traps Focus inside a Lock

}
/**
* Secures the focus around the node
*/
export class InFocusGuard extends React.Component<InFocusGuardProps> {
}
}

@@ -69,2 +69,3 @@ <div align="left">

- `group` named focus group for focus scattering aka [combined lock targets](https://github.com/theKashey/vue-focus-lock/issues/2)
- `shards` an array of `ref` pointing to the nodes, which focus lock should consider and a part of it. This is another way focus scattering.
- `whiteList` you could _whitelist_ locations FocusLock should carry about. Everything outside it will ignore. For example - any modals.

@@ -128,2 +129,66 @@ - `as` if you need to change internal `div` element, to any other. Use ref forwarding to give FocusLock the node to work with.

# Portals
Use focus scattering to handle portals
- using `groups`. Just create a few locks (only one could be active) with a same group name
```js
const PortaledElement = () => (
<FocusLock group="group42" disabled={true}>
// "discoverable" portaled content
</FocusLock>
);
<FocusLock group="group42">
// main content
</FocusLock>
```
- using `shards`. Just pass all the pieces to the "shards" prop.
```js
const PortaledElement = () => (
<div ref={ref}>
// "discoverable" portaled content
</div>
);
<FocusLock shards={[ref]}>
// main content
</FocusLock>
```
- without anything. FocusLock will not prevent focusing portaled element, but will not include them in to tab order
```js
const PortaledElement = () => (
<div>
// NON-"discoverable" portaled content
</div>
);
<FocusLock shards={[ref]}>
// main content
<PortaledElement />
</FocusLock>
```
### Guarding
As you may know - FocusLock is adding `Focus Guards` before and after lock to remove some side effects, like page scrolling.
But `shards` will not have such guards, and it might be not so cool to use them - for example if no `tabbable` would be
defined after shard - you will tab to the browser chrome.
You may wrap shard with `InFocusGuard` or just drop `InFocusGuard` here and there - that would solve the problem.
```js
import {InFocusGuard} from 'react-focus-lock';
<InFocusGuard>
<button>
</InFocusGuard>
//
<InFocusGuard />
<button>
<InFocusGuard />
```
InFocusGuards would be active(tabbable) only when tabble, it protecting, is focused.
### Automatic potral discovery
# Unmounting and focus management

@@ -130,0 +195,0 @@ - In case FocusLock has `returnFocus` enabled, and it's gonna to be unmounted - focus will be returned after zero-timeout.

Sorry, the diff of this file is not supported yet

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