react-focus-lock
Advanced tools
Comparing version 1.18.3 to 1.19.0
@@ -100,5 +100,7 @@ "use strict"; | ||
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "setObserveNode", function (observed) { | ||
return _this.setState({ | ||
observed: observed | ||
}); | ||
if (_this.state.observed !== observed) { | ||
_this.setState({ | ||
observed: observed | ||
}); | ||
} | ||
}); | ||
@@ -148,3 +150,5 @@ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "isActive", false); | ||
var lockProps = (0, _objectSpread3.default)((_objectSpread2 = {}, (0, _defineProperty2.default)(_objectSpread2, _focusLock.constants.FOCUS_DISABLED, disabled && 'disabled'), (0, _defineProperty2.default)(_objectSpread2, _focusLock.constants.FOCUS_GROUP, group), _objectSpread2), containerProps); | ||
return _react.default.createElement(Fragment, null, !noFocusGuards && [_react.default.createElement("div", { | ||
var hasLeadingGuards = noFocusGuards !== true; | ||
var hasTailingGuards = hasLeadingGuards && noFocusGuards !== 'tail'; | ||
return _react.default.createElement(Fragment, null, hasLeadingGuards && [_react.default.createElement("div", { | ||
key: "guard-first", | ||
@@ -175,3 +179,3 @@ "data-focus-guard": true, | ||
onDeactivation: this.onDeactivation | ||
}), children), !noFocusGuards && _react.default.createElement("div", { | ||
}), children), hasTailingGuards && _react.default.createElement("div", { | ||
"data-focus-guard": true, | ||
@@ -178,0 +182,0 @@ tabIndex: disabled ? -1 : 0, |
@@ -35,2 +35,3 @@ "use strict"; | ||
var lastPortaledElement = null; | ||
var focusWasOutsideWindow = false; | ||
@@ -104,3 +105,3 @@ var defaultWhitelist = function defaultWhitelist() { | ||
if (!activeElement || focusWhitelisted(activeElement)) { | ||
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) { | ||
if (persistentFocus || focusWasOutsideWindow || !isFreeFocus() || !lastActiveFocus && autoFocus) { | ||
if (workingNode && !((0, _focusLock.focusInside)(workingArea) || focusIsPortaledPair(activeElement, workingNode))) { | ||
@@ -114,2 +115,4 @@ if (document && !lastActiveFocus && activeElement && !autoFocus) { | ||
} | ||
focusWasOutsideWindow = false; | ||
} | ||
@@ -192,5 +195,10 @@ | ||
var onWindowBlur = function onWindowBlur() { | ||
focusWasOutsideWindow = true; | ||
}; | ||
var attachHandler = function attachHandler() { | ||
document.addEventListener('focusin', onTrap, true); | ||
document.addEventListener('focusout', onBlur); | ||
window.addEventListener('blur', onWindowBlur); | ||
}; | ||
@@ -201,2 +209,3 @@ | ||
document.removeEventListener('focusout', onBlur); | ||
window.removeEventListener('blur', onWindowBlur); | ||
}; | ||
@@ -203,0 +212,0 @@ |
@@ -73,5 +73,7 @@ import _extends from "@babel/runtime/helpers/extends"; | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setObserveNode", function (observed) { | ||
return _this.setState({ | ||
observed: observed | ||
}); | ||
if (_this.state.observed !== observed) { | ||
_this.setState({ | ||
observed: observed | ||
}); | ||
} | ||
}); | ||
@@ -126,3 +128,5 @@ | ||
return React.createElement(Fragment, null, !noFocusGuards && [React.createElement("div", { | ||
var hasLeadingGuards = noFocusGuards !== true; | ||
var hasTailingGuards = hasLeadingGuards && noFocusGuards !== 'tail'; | ||
return React.createElement(Fragment, null, hasLeadingGuards && [React.createElement("div", { | ||
key: "guard-first", | ||
@@ -153,3 +157,3 @@ "data-focus-guard": true, | ||
onDeactivation: this.onDeactivation | ||
}), children), !noFocusGuards && React.createElement("div", { | ||
}), children), hasTailingGuards && React.createElement("div", { | ||
"data-focus-guard": true, | ||
@@ -156,0 +160,0 @@ tabIndex: disabled ? -1 : 0, |
@@ -18,2 +18,3 @@ import React from 'react'; | ||
var lastPortaledElement = null; | ||
var focusWasOutsideWindow = false; | ||
@@ -87,3 +88,3 @@ var defaultWhitelist = function defaultWhitelist() { | ||
if (!activeElement || focusWhitelisted(activeElement)) { | ||
if (persistentFocus || !isFreeFocus() || !lastActiveFocus && autoFocus) { | ||
if (persistentFocus || focusWasOutsideWindow || !isFreeFocus() || !lastActiveFocus && autoFocus) { | ||
if (workingNode && !(focusInside(workingArea) || focusIsPortaledPair(activeElement, workingNode))) { | ||
@@ -97,2 +98,4 @@ if (document && !lastActiveFocus && activeElement && !autoFocus) { | ||
} | ||
focusWasOutsideWindow = false; | ||
} | ||
@@ -170,5 +173,10 @@ | ||
var onWindowBlur = function onWindowBlur() { | ||
focusWasOutsideWindow = true; | ||
}; | ||
var attachHandler = function attachHandler() { | ||
document.addEventListener('focusin', onTrap, true); | ||
document.addEventListener('focusout', onBlur); | ||
window.addEventListener('blur', onWindowBlur); | ||
}; | ||
@@ -179,2 +187,3 @@ | ||
document.removeEventListener('focusout', onBlur); | ||
window.removeEventListener('blur', onWindowBlur); | ||
}; | ||
@@ -181,0 +190,0 @@ |
{ | ||
"name": "react-focus-lock", | ||
"version": "1.18.3", | ||
"version": "1.19.0", | ||
"description": "It is a trap! (for a focus)", | ||
@@ -22,3 +22,4 @@ "main": "dist/cjs/index.js", | ||
"package-self": "package-self", | ||
"size": "npm run build && size-limit" | ||
"size": "npm run build && size-limit", | ||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" | ||
}, | ||
@@ -37,3 +38,3 @@ "repository": { | ||
"author": "theKashey <thekashey@gmail.com>", | ||
"license": "ISC", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -62,2 +63,3 @@ "url": "https://github.com/theKashey/react-focus-lock/issues" | ||
"chai-enzyme": "^1.0.0-beta.0", | ||
"conventional-changelog-cli": "^2.0.12", | ||
"enzyme": "^3.3.0", | ||
@@ -87,3 +89,3 @@ "enzyme-adapter-react-16": "^1.7.1", | ||
"@babel/runtime": "^7.0.0", | ||
"focus-lock": "^0.6.0", | ||
"focus-lock": "^0.6.3", | ||
"prop-types": "^15.6.2", | ||
@@ -90,0 +92,0 @@ "react-clientside-effect": "^1.2.0" |
@@ -36,3 +36,3 @@ declare module 'react-focus-lock' { | ||
*/ | ||
noFocusGuards?: boolean; | ||
noFocusGuards?: boolean | "tail"; | ||
@@ -39,0 +39,0 @@ /** |
101
README.md
@@ -5,32 +5,38 @@ <div align="left"> | ||
The way to manage your focus.<br/> | ||
The way to lock it inside.<br/> | ||
The way to team up with a11y.<br/> <br/> | ||
Make you site a better place. For everyone.<br/> | ||
It is a trap! For: | ||
- browser friendly focus lock<br/> | ||
- matching your use cases<br/> | ||
- trusted by best UI frameworks | ||
[![CircleCI status](https://img.shields.io/circleci/project/github/theKashey/react-focus-lock/master.svg?style=flat-square)](https://circleci.com/gh/theKashey/react-focus-lock/tree/master) | ||
[![npm](https://img.shields.io/npm/v/react-focus-lock.svg)](https://www.npmjs.com/package/react-focus-lock) | ||
[![bundle size](https://badgen.net/bundlephobia/minzip/react-focus-lock)](https://bundlephobia.com/result?p=react-focus-lock) | ||
![downloads](https://badgen.net/npm/dm/react-focus-lock) | ||
<hr/> | ||
</div> | ||
It is a trap! We got your focus and will not let him out! | ||
[![NPM](https://nodei.co/npm/react-focus-lock.png?downloads=true&stars=true)](https://nodei.co/npm/react-focus-lock/) | ||
- Modal dialogs. You can not leave it with "Tab", ie do a "tab-out". | ||
- Focused tasks. It will aways brings you back, as you can "lock" user inside a component. | ||
- You have to lock _every_ modal dialog, that's what `a11y` is asking for. | ||
This is a small library, but very useful for: | ||
- Modal dialogs. You can not leave it with "Tab", ie do a "tab-out". | ||
- Focused tasks. It will aways brings you back, as you can "lock" user inside a component. | ||
### Trusted | ||
Trusted by | ||
[Atlassian AtlasKit](https://atlaskit.atlassian.com), | ||
[ReachUI](https://ui.reach.tech/), | ||
[SmoothUI](https://smooth-ui.smooth-code.com/), | ||
[Storybook](https://storybook.js.org/) | ||
and we will do out best to earn your trust to! | ||
You have to lock _every_ modal dialog, that's what `a11y` is asking for. | ||
And this is most comprehensive focus lock/trap ever built. | ||
# Features | ||
- no keyboard control, everything is done watching a __focus behavior__, not emulating it. Thus works always and everywhere. | ||
- React __Portals__ support. Even if some data is in outerspace - it is [still in lock](https://github.com/theKashey/react-focus-lock/issues/19). | ||
- React __Portals__ support. Even if some data is in outer space - it is [still in lock](https://github.com/theKashey/react-focus-lock/issues/19). | ||
- _Scattered_ locks, or focus lock groups - you can setup different isolated locks, and _tab_ from one to another. | ||
- Controllable isolation level. | ||
> 💡 __focus__ locks is only the first part, there are also __scroll lock__ and __text-to-speech__ lock | ||
you have to use to really "lock" the user. | ||
Try [react-focus-on](https://github.com/theKashey/react-focus-on) to archive everything above, assembled in the right order. | ||
# How to use | ||
@@ -60,4 +66,6 @@ Just wrap something with focus lock, and focus will be `moved inside` on mount. | ||
# API | ||
FocusLock has few props to tune behavior | ||
- `disabled`, to disable(enable) behavior without altering the tree. | ||
> FocusLock would work perfectly even with no props set. | ||
FocusLock has few props to tune behavior, all props are optional: | ||
- `[disabled`, to disable(enable) behavior without altering the tree. | ||
- `returnFocus`, to return focus into initial position on unmount(not disable). | ||
@@ -67,10 +75,10 @@ > By default `returnFocus` is disabled, so FocusLock will not restore original focus on deactivation. | ||
This is expected behavior for Modals, but it is better to implement it by your self. | ||
- `persistentFocus`, default false, requires any element to be focused. This also disables text selections inside, and __outside__ focus lock. | ||
- `autoFocus`, default true, enables or disables focusing into on Lock activation. If disabled Lock will blur an active focus. | ||
- `noFocusGuards` disabled _focus guards_ - virtual inputs which secure tab index. | ||
- `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. | ||
- `as` if you need to change internal `div` element, to any other. Use ref forwarding to give FocusLock the node to work with. | ||
- `lockProps` to pass any extra props (except className) to the internal wrapper. | ||
- `persistentFocus=false`, requires any element to be focused. This also disables text selections inside, and __outside__ focus lock. | ||
- `autoFocus=true`, enables or disables focusing into on Lock activation. If disabled Lock will blur an active focus. | ||
- `noFocusGuards=false` disabled _focus guards_ - virtual inputs which secure tab index. | ||
- `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=fn` you could _whitelist_ locations FocusLock should carry about. Everything outside it will ignore. For example - any modals. | ||
- `as='div'` if you need to change internal `div` element, to any other. Use ref forwarding to give FocusLock the node to work with. | ||
- `lockProps={}` to pass any extra props (except className) to the internal wrapper. | ||
@@ -104,14 +112,4 @@ ### Focusing in OSX (Safary/FireFox) is strange! | ||
</FocusLock> | ||
``` | ||
<FocusLock as="section"> | ||
<button>Click</button> | ||
<button data-autofocus>will be focused</button> | ||
</FocusLock> | ||
<FocusLock as={AnotherComponent} lockProps={{anyProp: 4}}> | ||
<button>Click</button> | ||
<button data-autofocus>will be focused</button> | ||
</FocusLock> | ||
``` | ||
If there is more than one auto-focusable target - the first will be selected. | ||
@@ -173,2 +171,16 @@ If it is a part of radio group, and __rest of radio group element are also autofocusable__(just put them into AutoFocusInside) - | ||
### Using your own `Components` | ||
You may use `as` prop to change _what_ Focus-Lock will render around `children`. | ||
```js | ||
<FocusLock as="section"> | ||
<button>Click</button> | ||
<button data-autofocus>will be focused</button> | ||
</FocusLock> | ||
<FocusLock as={AnotherComponent} lockProps={{anyAnotherComponentProp: 4}}> | ||
<button>Click</button> | ||
<span>Hello there!</span> | ||
</FocusLock> | ||
``` | ||
### Guarding | ||
@@ -183,10 +195,10 @@ As you may know - FocusLock is adding `Focus Guards` before and after lock to remove some side effects, like page scrolling. | ||
// wrap with | ||
<InFocusGuard> | ||
<button> | ||
<button /> | ||
</InFocusGuard> | ||
// | ||
// place before and after | ||
<InFocusGuard /> | ||
<button> | ||
<button /> | ||
<InFocusGuard /> | ||
@@ -196,3 +208,10 @@ ``` | ||
### Automatic potral discovery | ||
#### Removing Tailing Guard | ||
If only your modal is the last tabble element on the body - you might remove the Tailing Guard, | ||
to allow user _tab_ into address bar. | ||
```js | ||
<InFocusGuard/> | ||
<button /> | ||
// there is no "tailing" guard :) | ||
``` | ||
@@ -199,0 +218,0 @@ # Unmounting and focus management |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
630606
24
0
1213
279
37
Updatedfocus-lock@^0.6.3