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 2.10.1 to 2.11.0

25

dist/cjs/Lock.js

@@ -13,4 +13,3 @@ "use strict";

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var React = _interopRequireWildcard(require("react"));
var _propTypes = require("prop-types");

@@ -69,4 +68,12 @@ var constants = _interopRequireWildcard(require("focus-lock/constants"));

id = _React$useState6[0];
var onActivation = React.useCallback(function () {
originalFocusedElement.current = originalFocusedElement.current || document && document.activeElement;
var onActivation = React.useCallback(function (_ref) {
var captureFocusRestore = _ref.captureFocusRestore;
if (!originalFocusedElement.current) {
var _document;
var activeElement = (_document = document) === null || _document === void 0 ? void 0 : _document.activeElement;
originalFocusedElement.current = activeElement;
if (activeElement !== document.body) {
originalFocusedElement.current = captureFocusRestore(activeElement);
}
}
if (observed.current && onActivationCallback) {

@@ -85,10 +92,6 @@ onActivationCallback(observed.current);

}, [onDeactivationCallback]);
(0, _react.useEffect)(function () {
if (!disabled) {
originalFocusedElement.current = null;
}
}, []);
var returnFocus = React.useCallback(function (allowDefer) {
var returnFocusTo = originalFocusedElement.current;
if (returnFocusTo && returnFocusTo.focus) {
var focusRestore = originalFocusedElement.current;
if (focusRestore) {
var returnFocusTo = (typeof focusRestore === 'function' ? focusRestore() : focusRestore) || document.body;
var howToReturnFocus = typeof shouldReturnFocus === 'function' ? shouldReturnFocus(returnFocusTo) : shouldReturnFocus;

@@ -95,0 +98,0 @@ if (howToReturnFocus) {

@@ -187,2 +187,11 @@ "use strict";

}
var focusLockAPI = {
moveFocusInside: _focusLock.moveFocusInside,
focusInside: _focusLock.focusInside,
focusNextElement: _focusLock.focusNextElement,
focusPrevElement: _focusLock.focusPrevElement,
focusFirstElement: _focusLock.focusFirstElement,
focusLastElement: _focusLock.focusLastElement,
captureFocusRestore: _focusLock.captureFocusRestore
};
function handleStateChangeOnClient(traps) {

@@ -208,3 +217,3 @@ var trap = traps.slice(-1)[0];

if (!sameTrap || lastTrap.observed !== trap.observed) {
trap.onActivation();
trap.onActivation(focusLockAPI);
}

@@ -221,9 +230,4 @@ activateTrap(true);

_medium.mediumEffect.assignMedium(function (cb) {
return cb({
moveFocusInside: _focusLock.moveFocusInside,
focusInside: _focusLock.focusInside,
focusNextElement: _focusLock.focusNextElement,
focusPrevElement: _focusLock.focusPrevElement
});
return cb(focusLockAPI);
});
var _default = exports["default"] = (0, _reactClientsideEffect["default"])(reducePropsToState, handleStateChangeOnClient)(FocusWatcher);

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

});
},
focusFirst: function focusFirst(options) {
return withMedium(function (car) {
car.focusFirstElement(collapseRefs(ref.current), options);
});
},
focusLast: function focusLast(options) {
return withMedium(function (car) {
car.focusLastElement(collapseRefs(ref.current), options);
});
}

@@ -60,0 +70,0 @@ };

@@ -45,2 +45,3 @@ "use strict";

var useFocusState = exports.useFocusState = function useFocusState() {
var callbacks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _useState = (0, _react.useState)(false),

@@ -56,6 +57,11 @@ _useState2 = (0, _slicedToArray2["default"])(_useState, 2),

var focusState = (0, _react.useRef)({});
var stateTracker = (0, _react.useRef)(false);
(0, _react.useEffect)(function () {
if (ref.current) {
setActive(ref.current === document.activeElement || ref.current.contains(document.activeElement));
var isAlreadyFocused = ref.current === document.activeElement || ref.current.contains(document.activeElement);
setActive(isAlreadyFocused);
setState(getFocusState(document.activeElement, ref.current));
if (isAlreadyFocused && callbacks.onFocus) {
callbacks.onFocus();
}
}

@@ -75,4 +81,13 @@ }, []);

var fin = mainbus.on('assign', function () {
setActive(focusState.current.focused || false);
var newState = focusState.current.focused || false;
setActive(newState);
setState(focusState.current.state || '');
if (newState !== stateTracker.current) {
stateTracker.current = newState;
if (newState) {
callbacks.onFocus && callbacks.onFocus();
} else {
callbacks.onBlur && callbacks.onBlur();
}
}
});

@@ -79,0 +94,0 @@ return function () {

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

import { useMergeRefs } from 'use-callback-ref';
import { useEffect } from 'react';
import { hiddenGuard } from './FocusGuard';

@@ -52,4 +51,12 @@ import { mediumFocus, mediumBlur, mediumSidecar } from './medium';

id = _React$useState3[0];
var onActivation = React.useCallback(function () {
originalFocusedElement.current = originalFocusedElement.current || document && document.activeElement;
var onActivation = React.useCallback(function (_ref) {
var captureFocusRestore = _ref.captureFocusRestore;
if (!originalFocusedElement.current) {
var _document;
var activeElement = (_document = document) == null ? void 0 : _document.activeElement;
originalFocusedElement.current = activeElement;
if (activeElement !== document.body) {
originalFocusedElement.current = captureFocusRestore(activeElement);
}
}
if (observed.current && onActivationCallback) {

@@ -68,10 +75,6 @@ onActivationCallback(observed.current);

}, [onDeactivationCallback]);
useEffect(function () {
if (!disabled) {
originalFocusedElement.current = null;
}
}, []);
var returnFocus = React.useCallback(function (allowDefer) {
var returnFocusTo = originalFocusedElement.current;
if (returnFocusTo && returnFocusTo.focus) {
var focusRestore = originalFocusedElement.current;
if (focusRestore) {
var returnFocusTo = (typeof focusRestore === 'function' ? focusRestore() : focusRestore) || document.body;
var howToReturnFocus = typeof shouldReturnFocus === 'function' ? shouldReturnFocus(returnFocusTo) : shouldReturnFocus;

@@ -78,0 +81,0 @@ if (howToReturnFocus) {

import * as React from 'react';
import PropTypes from 'prop-types';
import withSideEffect from 'react-clientside-effect';
import { moveFocusInside, focusInside, focusIsHidden, expandFocusableNodes, focusNextElement, focusPrevElement } from 'focus-lock';
import { moveFocusInside, focusInside, focusIsHidden, expandFocusableNodes, focusNextElement, focusPrevElement, focusFirstElement, focusLastElement, captureFocusRestore } from 'focus-lock';
import { deferAction, extractRef } from './util';

@@ -176,2 +176,11 @@ import { mediumFocus, mediumBlur, mediumEffect } from './medium';

}
var focusLockAPI = {
moveFocusInside: moveFocusInside,
focusInside: focusInside,
focusNextElement: focusNextElement,
focusPrevElement: focusPrevElement,
focusFirstElement: focusFirstElement,
focusLastElement: focusLastElement,
captureFocusRestore: captureFocusRestore
};
function handleStateChangeOnClient(traps) {

@@ -197,3 +206,3 @@ var trap = traps.slice(-1)[0];

if (!sameTrap || lastTrap.observed !== trap.observed) {
trap.onActivation();
trap.onActivation(focusLockAPI);
}

@@ -210,9 +219,4 @@ activateTrap(true);

mediumEffect.assignMedium(function (cb) {
return cb({
moveFocusInside: moveFocusInside,
focusInside: focusInside,
focusNextElement: focusNextElement,
focusPrevElement: focusPrevElement
});
return cb(focusLockAPI);
});
export default withSideEffect(reducePropsToState, handleStateChangeOnClient)(FocusWatcher);

@@ -50,2 +50,12 @@ import _extends from "@babel/runtime/helpers/esm/extends";

});
},
focusFirst: function focusFirst(options) {
return withMedium(function (car) {
car.focusFirstElement(collapseRefs(ref.current), options);
});
},
focusLast: function focusLast(options) {
return withMedium(function (car) {
car.focusLastElement(collapseRefs(ref.current), options);
});
}

@@ -52,0 +62,0 @@ };

@@ -36,3 +36,6 @@ import { useCallback, useRef, useState, useEffect } from 'react';

};
export var useFocusState = function useFocusState() {
export var useFocusState = function useFocusState(callbacks) {
if (callbacks === void 0) {
callbacks = {};
}
var _useState = useState(false),

@@ -46,6 +49,11 @@ active = _useState[0],

var focusState = useRef({});
var stateTracker = useRef(false);
useEffect(function () {
if (ref.current) {
setActive(ref.current === document.activeElement || ref.current.contains(document.activeElement));
var isAlreadyFocused = ref.current === document.activeElement || ref.current.contains(document.activeElement);
setActive(isAlreadyFocused);
setState(getFocusState(document.activeElement, ref.current));
if (isAlreadyFocused && callbacks.onFocus) {
callbacks.onFocus();
}
}

@@ -65,4 +73,13 @@ }, []);

var fin = mainbus.on('assign', function () {
setActive(focusState.current.focused || false);
var newState = focusState.current.focused || false;
setActive(newState);
setState(focusState.current.state || '');
if (newState !== stateTracker.current) {
stateTracker.current = newState;
if (newState) {
callbacks.onFocus && callbacks.onFocus();
} else {
callbacks.onBlur && callbacks.onBlur();
}
}
});

@@ -69,0 +86,0 @@ return function () {

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

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

"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^12.0.0",
"@types/react": "^18.0.8",

@@ -76,0 +77,0 @@ "babel-eslint": "^10.0.1",

@@ -33,2 +33,89 @@ import * as React from 'react';

export class InFocusGuard extends React.Component<InFocusGuardProps> {
}
/**
* Moves focus inside a given node
*/
export function useFocusInside(node: React.RefObject<HTMLElement>): void;
export type FocusOptions = {
/**
* enables focus cycle
* @default true
*/
cycle?: boolean;
/**
* limits focusables to tabbables (tabindex>=0) elements only
* @default true
*/
onlyTabbable?:boolean
}
export type FocusControl = {
/**
* moves focus to the current scope, can be considered as autofocus
*/
autoFocus():Promise<void>;
/**
* focuses the next element in the scope.
* If active element is not in the scope, autofocus will be triggered first
*/
focusNext(options:FocusOptions):Promise<void>;
/**
* focuses the prev element in the scope.
* If active element is not in the scope, autofocus will be triggered first
*/
focusPrev():Promise<void>;
/**
* focused the first element in the scope
*/
focusFirst(options: Pick<FocusOptions,'onlyTabbable'>):Promise<void>;
/**
* focused the last element in the scope
*/
focusLast(options: Pick<FocusOptions,'onlyTabbable'>):Promise<void>;
}
/**
* returns FocusControl over the union given elements, one or many
* - can be used outside of FocusLock
* @see {@link useFocusScope} for use cases inside of FocusLock
*/
export function useFocusController(...shards: HTMLElement[]):FocusControl;
/**
* returns FocusControl over the current FocusLock
* - can be used only within FocusLock
* - can be used by disabled FocusLock
* @see {@link useFocusController} for use cases outside of FocusLock
*/
export function useFocusScope():FocusControl
export type FocusCallbacks = {
onFocus():void;
onBlur():void;
}
/**
* returns information about FocusState of a given node
* @example
* ```tsx
* const {active, ref, onFocus} = useFocusState();
* return <div ref={ref} onFocus={onFocus}>{active ? 'is focused' : 'not focused'}</div>
* ```
*/
export function useFocusState<T extends Element>(callbacks?: FocusCallbacks ):{
/**
* is currently focused, or is focus is inside
*/
active: boolean;
/**
* focus handled. SHALL be passed to the node down
*/
onFocus: React.FocusEventHandler<T>;
/**
* reference to the node
* only required to capture current status of the node
*/
ref: React.RefObject<T>;
}

@@ -64,4 +64,5 @@ <div align="left">

- `className`, to set the `className` of the internal wrapper.
- `returnFocus`, to return focus into initial position on unmount(not disable).
> By default `returnFocus` is disabled, so FocusLock will __not__ restore original focus on deactivation.
- `returnFocus`, to return focus into initial position on unmount
> By default `returnFocus` is disabled, so FocusLock __will not__ restore original focus on deactivation.
> This was done mostly to avoid breaking changes. We __strong recommend enabling it__, to provide a better user experience.

@@ -333,2 +334,28 @@ This is expected behavior for Modals, but it is better to implement it by your self. See [unmounting and focus management](https://github.com/theKashey/react-focus-lock#unmounting-and-focus-management) for details

## Return focus to another node
In some cases the original node that was focused before the lock was activated is not the desired node to return focus to.
Some times this node might not exists at all.
- first of all, FocusLock need a moment to record this node, please do not hide it onClick, but hide onBlur (Dropdown, looking at you)
- second, you may specify a callback as `returnFocus`, letting you decide where to return focus to.
```tsx
<FocusLock
returnFocus={(suggestedNode) => {
// somehow activeElement should not be changed
if(document.activeElement.hasAttributes('main-content')) {
// opt out from default behavior
return false;
}
if (someCondition(suggestedNode)) {
// proceed with the suggested node
return true;
}
// handle return focus manually
document.getElementById('the-button').focus();
// opt out from default behavior
return false;
}}
/>
````
## Return focus with no scroll

@@ -335,0 +362,0 @@ > read more at the [issue #83](https://github.com/theKashey/react-focus-lock/issues/83) or

@@ -68,2 +68,10 @@ import * as React from 'react';

focusPrev():Promise<void>;
/**
* focused the first element in the scope
*/
focusFirst(options: Pick<FocusOptions,'onlyTabbable'>):Promise<void>;
/**
* focused the last element in the scope
*/
focusLast(options: Pick<FocusOptions,'onlyTabbable'>):Promise<void>;
}

@@ -87,2 +95,7 @@

export type FocusCallbacks = {
onFocus():void;
onBlur():void;
}
/**

@@ -96,3 +109,3 @@ * returns information about FocusState of a given node

*/
export function useFocusState<T extends Element>():{
export function useFocusState<T extends Element>(callbacks?: FocusCallbacks ):{
/**

@@ -99,0 +112,0 @@ * is currently focused, or is focus is inside

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