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

focus-trap

Package Overview
Dependencies
Maintainers
2
Versions
83
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

focus-trap - npm Package Compare versions

Comparing version 5.1.0 to 6.0.0

dist/focus-trap.esm.js

16

CHANGELOG.md
# Changelog
## 6.0.0
- Add boolean value support for `allowOutsideClick` option.
- New `preventScroll` feature to *prevent* scrolling to the element getting focus if not in the viewport.
- Changed code formatting to use dangling commas where ES5 supports them.
- **BREAKING**: Updated [tabbable](https://github.com/focus-trap/tabbable/blob/master/CHANGELOG.md#500) dependency to the new 5.0.0 release which contains breaking changes to its `isTabbableRadio()` internal function.
- Help with tree shaking by having `package.json` state `sideEffects: false` to mark this module as having no side effects as a result of merely importing it.
- **BREAKING**: This `package.json`'s "main" no longer points to `./index.js` in the package (although it still points to a CJS module, so it's possible this actually doesn't break anything). It now has:
- "main": `dist/focus-trap.min.js` (the CJS bundle)
- "module": `dist/focus-trap.esm.min.js` (the **new ESM bundle**)
- the UMD is `dist/focus-trap.umd.min.js` if needed (convenient for loading directly in an older browser that doesn't support ESM)
- **NOTE:** The CJS build no longer provides a function as a default export. Use `const { createFocusTrap } = require('focus-trap');` to get the function from before.
- **NOTE:** The ESM build does not provide a default export. Use `import { createFocusTrap } from 'focus-trap';` to import the module.
- **New ESM Build**: Included in `dist/focus-trap.esm.*`.
- New UMD Build: Included in `dist/focus-trap.umd.*`.
## 5.1.0

@@ -4,0 +20,0 @@

250

dist/focus-trap.js

@@ -1,11 +0,17 @@

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.focusTrap = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
/*!
* focus-trap 6.0.0
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var tabbable = require('tabbable');
var xtend = require('xtend');
var activeFocusDelay;
var activeFocusTraps = (function() {
var activeFocusTraps = (function () {
var trapQueue = [];
return {
activateTrap: function(trap) {
activateTrap: function (trap) {
if (trapQueue.length > 0) {

@@ -28,3 +34,3 @@ var activeTrap = trapQueue[trapQueue.length - 1];

deactivateTrap: function(trap) {
deactivateTrap: function (trap) {
var trapIndex = trapQueue.indexOf(trap);

@@ -38,7 +44,7 @@ if (trapIndex !== -1) {

}
}
},
};
})();
function focusTrap(element, userOptions) {
function createFocusTrap(element, userOptions) {
var doc = document;

@@ -48,9 +54,7 @@ var container =

var config = xtend(
{
returnFocusOnDeactivate: true,
escapeDeactivates: true
},
userOptions
);
var config = {
returnFocusOnDeactivate: true,
escapeDeactivates: true,
...userOptions,
};

@@ -63,3 +67,3 @@ var state = {

active: false,
paused: false
paused: false,
};

@@ -71,3 +75,3 @@

pause: pause,
unpause: unpause
unpause: unpause,
};

@@ -122,3 +126,3 @@

if (returnFocus) {
delay(function() {
delay(function () {
tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));

@@ -152,3 +156,3 @@ });

// that caused the focus trap activation.
activeFocusDelay = delay(function() {
activeFocusDelay = delay(function () {
tryFocus(getInitialFocusNode());

@@ -160,15 +164,15 @@ });

capture: true,
passive: false
passive: false,
});
doc.addEventListener('touchstart', checkPointerDown, {
capture: true,
passive: false
passive: false,
});
doc.addEventListener('click', checkClick, {
capture: true,
passive: false
passive: false,
});
doc.addEventListener('keydown', checkKey, {
capture: true,
passive: false
passive: false,
});

@@ -242,3 +246,3 @@

deactivate({
returnFocus: !tabbable.isFocusable(e.target)
returnFocus: !tabbable.isFocusable(e.target),
});

@@ -250,3 +254,8 @@ return;

// then on mobile they will be blocked anyways if `touchstart` is blocked.)
if (config.allowOutsideClick && config.allowOutsideClick(e)) {
if (
config.allowOutsideClick &&
(typeof config.allowOutsideClick === 'boolean'
? config.allowOutsideClick
: config.allowOutsideClick(e))
) {
return;

@@ -300,3 +309,8 @@ }

if (container.contains(e.target)) return;
if (config.allowOutsideClick && config.allowOutsideClick(e)) {
if (
config.allowOutsideClick &&
(typeof config.allowOutsideClick === 'boolean'
? config.allowOutsideClick
: config.allowOutsideClick(e))
) {
return;

@@ -309,3 +323,3 @@ }

function updateTabbableNodes() {
var tabbableNodes = tabbable(container);
var tabbableNodes = tabbable.tabbable(container);
state.firstTabbableNode = tabbableNodes[0] || getInitialFocusNode();

@@ -322,3 +336,3 @@ state.lastTabbableNode =

}
node.focus();
node.focus({ preventScroll: !!config.preventScroll });
state.mostRecentlyFocusedNode = node;

@@ -351,181 +365,3 @@ if (isSelectableInput(node)) {

module.exports = focusTrap;
},{"tabbable":2,"xtend":3}],2:[function(require,module,exports){
var candidateSelectors = [
'input',
'select',
'textarea',
'a[href]',
'button',
'[tabindex]',
'audio[controls]',
'video[controls]',
'[contenteditable]:not([contenteditable="false"])',
];
var candidateSelector = candidateSelectors.join(',');
var matches = typeof Element === 'undefined'
? function () {}
: Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
function tabbable(el, options) {
options = options || {};
var regularTabbables = [];
var orderedTabbables = [];
var candidates = el.querySelectorAll(candidateSelector);
if (options.includeContainer) {
if (matches.call(el, candidateSelector)) {
candidates = Array.prototype.slice.apply(candidates);
candidates.unshift(el);
}
}
var i, candidate, candidateTabindex;
for (i = 0; i < candidates.length; i++) {
candidate = candidates[i];
if (!isNodeMatchingSelectorTabbable(candidate)) continue;
candidateTabindex = getTabindex(candidate);
if (candidateTabindex === 0) {
regularTabbables.push(candidate);
} else {
orderedTabbables.push({
documentOrder: i,
tabIndex: candidateTabindex,
node: candidate,
});
}
}
var tabbableNodes = orderedTabbables
.sort(sortOrderedTabbables)
.map(function(a) { return a.node })
.concat(regularTabbables);
return tabbableNodes;
}
tabbable.isTabbable = isTabbable;
tabbable.isFocusable = isFocusable;
function isNodeMatchingSelectorTabbable(node) {
if (
!isNodeMatchingSelectorFocusable(node)
|| isNonTabbableRadio(node)
|| getTabindex(node) < 0
) {
return false;
}
return true;
}
function isTabbable(node) {
if (!node) throw new Error('No node provided');
if (matches.call(node, candidateSelector) === false) return false;
return isNodeMatchingSelectorTabbable(node);
}
function isNodeMatchingSelectorFocusable(node) {
if (
node.disabled
|| isHiddenInput(node)
|| isHidden(node)
) {
return false;
}
return true;
}
var focusableCandidateSelector = candidateSelectors.concat('iframe').join(',');
function isFocusable(node) {
if (!node) throw new Error('No node provided');
if (matches.call(node, focusableCandidateSelector) === false) return false;
return isNodeMatchingSelectorFocusable(node);
}
function getTabindex(node) {
var tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);
if (!isNaN(tabindexAttr)) return tabindexAttr;
// Browsers do not return `tabIndex` correctly for contentEditable nodes;
// so if they don't have a tabindex attribute specifically set, assume it's 0.
if (isContentEditable(node)) return 0;
return node.tabIndex;
}
function sortOrderedTabbables(a, b) {
return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
}
function isContentEditable(node) {
return node.contentEditable === 'true';
}
function isInput(node) {
return node.tagName === 'INPUT';
}
function isHiddenInput(node) {
return isInput(node) && node.type === 'hidden';
}
function isRadio(node) {
return isInput(node) && node.type === 'radio';
}
function isNonTabbableRadio(node) {
return isRadio(node) && !isTabbableRadio(node);
}
function getCheckedRadio(nodes) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].checked) {
return nodes[i];
}
}
}
function isTabbableRadio(node) {
if (!node.name) return true;
// This won't account for the edge case where you have radio groups with the same
// in separate forms on the same page.
var radioSet = node.ownerDocument.querySelectorAll('input[type="radio"][name="' + node.name + '"]');
var checked = getCheckedRadio(radioSet);
return !checked || checked === node;
}
function isHidden(node) {
// offsetParent being null will allow detecting cases where an element is invisible or inside an invisible element,
// as long as the element does not use position: fixed. For them, their visibility has to be checked directly as well.
return node.offsetParent === null || getComputedStyle(node).visibility === 'hidden';
}
module.exports = tabbable;
},{}],3:[function(require,module,exports){
module.exports = extend
var hasOwnProperty = Object.prototype.hasOwnProperty;
function extend() {
var target = {}
for (var i = 0; i < arguments.length; i++) {
var source = arguments[i]
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
target[key] = source[key]
}
}
}
return target
}
},{}]},{},[1])(1)
});
exports.createFocusTrap = createFocusTrap;
//# sourceMappingURL=focus-trap.js.map

@@ -1,1 +0,6 @@

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.focusTrap=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){var tabbable=require("tabbable");var xtend=require("xtend");var activeFocusDelay;var activeFocusTraps=function(){var trapQueue=[];return{activateTrap:function(trap){if(trapQueue.length>0){var activeTrap=trapQueue[trapQueue.length-1];if(activeTrap!==trap){activeTrap.pause()}}var trapIndex=trapQueue.indexOf(trap);if(trapIndex===-1){trapQueue.push(trap)}else{trapQueue.splice(trapIndex,1);trapQueue.push(trap)}},deactivateTrap:function(trap){var trapIndex=trapQueue.indexOf(trap);if(trapIndex!==-1){trapQueue.splice(trapIndex,1)}if(trapQueue.length>0){trapQueue[trapQueue.length-1].unpause()}}}}();function focusTrap(element,userOptions){var doc=document;var container=typeof element==="string"?doc.querySelector(element):element;var config=xtend({returnFocusOnDeactivate:true,escapeDeactivates:true},userOptions);var state={firstTabbableNode:null,lastTabbableNode:null,nodeFocusedBeforeActivation:null,mostRecentlyFocusedNode:null,active:false,paused:false};var trap={activate:activate,deactivate:deactivate,pause:pause,unpause:unpause};return trap;function activate(activateOptions){if(state.active)return;updateTabbableNodes();state.active=true;state.paused=false;state.nodeFocusedBeforeActivation=doc.activeElement;var onActivate=activateOptions&&activateOptions.onActivate?activateOptions.onActivate:config.onActivate;if(onActivate){onActivate()}addListeners();return trap}function deactivate(deactivateOptions){if(!state.active)return;clearTimeout(activeFocusDelay);removeListeners();state.active=false;state.paused=false;activeFocusTraps.deactivateTrap(trap);var onDeactivate=deactivateOptions&&deactivateOptions.onDeactivate!==undefined?deactivateOptions.onDeactivate:config.onDeactivate;if(onDeactivate){onDeactivate()}var returnFocus=deactivateOptions&&deactivateOptions.returnFocus!==undefined?deactivateOptions.returnFocus:config.returnFocusOnDeactivate;if(returnFocus){delay(function(){tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation))})}return trap}function pause(){if(state.paused||!state.active)return;state.paused=true;removeListeners()}function unpause(){if(!state.paused||!state.active)return;state.paused=false;updateTabbableNodes();addListeners()}function addListeners(){if(!state.active)return;activeFocusTraps.activateTrap(trap);activeFocusDelay=delay(function(){tryFocus(getInitialFocusNode())});doc.addEventListener("focusin",checkFocusIn,true);doc.addEventListener("mousedown",checkPointerDown,{capture:true,passive:false});doc.addEventListener("touchstart",checkPointerDown,{capture:true,passive:false});doc.addEventListener("click",checkClick,{capture:true,passive:false});doc.addEventListener("keydown",checkKey,{capture:true,passive:false});return trap}function removeListeners(){if(!state.active)return;doc.removeEventListener("focusin",checkFocusIn,true);doc.removeEventListener("mousedown",checkPointerDown,true);doc.removeEventListener("touchstart",checkPointerDown,true);doc.removeEventListener("click",checkClick,true);doc.removeEventListener("keydown",checkKey,true);return trap}function getNodeForOption(optionName){var optionValue=config[optionName];var node=optionValue;if(!optionValue){return null}if(typeof optionValue==="string"){node=doc.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}function getInitialFocusNode(){var node;if(getNodeForOption("initialFocus")!==null){node=getNodeForOption("initialFocus")}else if(container.contains(doc.activeElement)){node=doc.activeElement}else{node=state.firstTabbableNode||getNodeForOption("fallbackFocus")}if(!node){throw new Error("Your focus-trap needs to have at least one focusable element")}return node}function getReturnFocusNode(previousActiveElement){var node=getNodeForOption("setReturnFocus");return node?node:previousActiveElement}function checkPointerDown(e){if(container.contains(e.target))return;if(config.clickOutsideDeactivates){deactivate({returnFocus:!tabbable.isFocusable(e.target)});return}if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault()}function checkFocusIn(e){if(container.contains(e.target)||e.target instanceof Document){return}e.stopImmediatePropagation();tryFocus(state.mostRecentlyFocusedNode||getInitialFocusNode())}function checkKey(e){if(config.escapeDeactivates!==false&&isEscapeEvent(e)){e.preventDefault();deactivate();return}if(isTabEvent(e)){checkTab(e);return}}function checkTab(e){updateTabbableNodes();if(e.shiftKey&&e.target===state.firstTabbableNode){e.preventDefault();tryFocus(state.lastTabbableNode);return}if(!e.shiftKey&&e.target===state.lastTabbableNode){e.preventDefault();tryFocus(state.firstTabbableNode);return}}function checkClick(e){if(config.clickOutsideDeactivates)return;if(container.contains(e.target))return;if(config.allowOutsideClick&&config.allowOutsideClick(e)){return}e.preventDefault();e.stopImmediatePropagation()}function updateTabbableNodes(){var tabbableNodes=tabbable(container);state.firstTabbableNode=tabbableNodes[0]||getInitialFocusNode();state.lastTabbableNode=tabbableNodes[tabbableNodes.length-1]||getInitialFocusNode()}function tryFocus(node){if(node===doc.activeElement)return;if(!node||!node.focus){tryFocus(getInitialFocusNode());return}node.focus();state.mostRecentlyFocusedNode=node;if(isSelectableInput(node)){node.select()}}}function isSelectableInput(node){return node.tagName&&node.tagName.toLowerCase()==="input"&&typeof node.select==="function"}function isEscapeEvent(e){return e.key==="Escape"||e.key==="Esc"||e.keyCode===27}function isTabEvent(e){return e.key==="Tab"||e.keyCode===9}function delay(fn){return setTimeout(fn,0)}module.exports=focusTrap},{tabbable:2,xtend:3}],2:[function(require,module,exports){var candidateSelectors=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])'];var candidateSelector=candidateSelectors.join(",");var matches=typeof Element==="undefined"?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function tabbable(el,options){options=options||{};var regularTabbables=[];var orderedTabbables=[];var candidates=el.querySelectorAll(candidateSelector);if(options.includeContainer){if(matches.call(el,candidateSelector)){candidates=Array.prototype.slice.apply(candidates);candidates.unshift(el)}}var i,candidate,candidateTabindex;for(i=0;i<candidates.length;i++){candidate=candidates[i];if(!isNodeMatchingSelectorTabbable(candidate))continue;candidateTabindex=getTabindex(candidate);if(candidateTabindex===0){regularTabbables.push(candidate)}else{orderedTabbables.push({documentOrder:i,tabIndex:candidateTabindex,node:candidate})}}var tabbableNodes=orderedTabbables.sort(sortOrderedTabbables).map(function(a){return a.node}).concat(regularTabbables);return tabbableNodes}tabbable.isTabbable=isTabbable;tabbable.isFocusable=isFocusable;function isNodeMatchingSelectorTabbable(node){if(!isNodeMatchingSelectorFocusable(node)||isNonTabbableRadio(node)||getTabindex(node)<0){return false}return true}function isTabbable(node){if(!node)throw new Error("No node provided");if(matches.call(node,candidateSelector)===false)return false;return isNodeMatchingSelectorTabbable(node)}function isNodeMatchingSelectorFocusable(node){if(node.disabled||isHiddenInput(node)||isHidden(node)){return false}return true}var focusableCandidateSelector=candidateSelectors.concat("iframe").join(",");function isFocusable(node){if(!node)throw new Error("No node provided");if(matches.call(node,focusableCandidateSelector)===false)return false;return isNodeMatchingSelectorFocusable(node)}function getTabindex(node){var tabindexAttr=parseInt(node.getAttribute("tabindex"),10);if(!isNaN(tabindexAttr))return tabindexAttr;if(isContentEditable(node))return 0;return node.tabIndex}function sortOrderedTabbables(a,b){return a.tabIndex===b.tabIndex?a.documentOrder-b.documentOrder:a.tabIndex-b.tabIndex}function isContentEditable(node){return node.contentEditable==="true"}function isInput(node){return node.tagName==="INPUT"}function isHiddenInput(node){return isInput(node)&&node.type==="hidden"}function isRadio(node){return isInput(node)&&node.type==="radio"}function isNonTabbableRadio(node){return isRadio(node)&&!isTabbableRadio(node)}function getCheckedRadio(nodes){for(var i=0;i<nodes.length;i++){if(nodes[i].checked){return nodes[i]}}}function isTabbableRadio(node){if(!node.name)return true;var radioSet=node.ownerDocument.querySelectorAll('input[type="radio"][name="'+node.name+'"]');var checked=getCheckedRadio(radioSet);return!checked||checked===node}function isHidden(node){return node.offsetParent===null||getComputedStyle(node).visibility==="hidden"}module.exports=tabbable},{}],3:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target}},{}]},{},[1])(1)});
/*!
* focus-trap 6.0.0
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
*/
"use strict";function e(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}Object.defineProperty(exports,"__esModule",{value:!0});var n=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary"],r=n.join(","),o="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function a(e){return!(!i(e)||function(e){return function(e){return d(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}((e.form||e.ownerDocument).querySelectorAll('input[type="radio"][name="'+e.name+'"]'),e.form);return!t||t===e}(e)}(e)||l(e)<0)}function i(e){return!(e.disabled||function(e){return d(e)&&"hidden"===e.type}(e)||function(e){return null===e.offsetParent||"hidden"===getComputedStyle(e).visibility}(e))}var c,u=n.concat("iframe").join(",");function s(e){if(!e)throw new Error("No node provided");return!1!==o.call(e,u)&&i(e)}function l(e){var t=parseInt(e.getAttribute("tabindex"),10);return isNaN(t)?function(e){return"true"===e.contentEditable}(e)?0:"AUDIO"!==e.nodeName&&"VIDEO"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:t}function f(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex}function d(e){return"INPUT"===e.tagName}var v,p=(v=[],{activateTrap:function(e){if(v.length>0){var t=v[v.length-1];t!==e&&t.pause()}var n=v.indexOf(e);-1===n||v.splice(n,1),v.push(e)},deactivateTrap:function(e){var t=v.indexOf(e);-1!==t&&v.splice(t,1),v.length>0&&v[v.length-1].unpause()}});function b(e){return setTimeout(e,0)}exports.createFocusTrap=function(n,i){var u=document,d="string"==typeof n?u.querySelector(n):n,v=function(n){for(var r=1;r<arguments.length;r++){var o=null!=arguments[r]?arguments[r]:{};r%2?t(Object(o),!0).forEach((function(t){e(n,t,o[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(n,Object.getOwnPropertyDescriptors(o)):t(Object(o)).forEach((function(e){Object.defineProperty(n,e,Object.getOwnPropertyDescriptor(o,e))}))}return n}({returnFocusOnDeactivate:!0,escapeDeactivates:!0},i),m={firstTabbableNode:null,lastTabbableNode:null,nodeFocusedBeforeActivation:null,mostRecentlyFocusedNode:null,active:!1,paused:!1},y={activate:function(e){if(m.active)return;F(),m.active=!0,m.paused=!1,m.nodeFocusedBeforeActivation=u.activeElement;var t=e&&e.onActivate?e.onActivate:v.onActivate;t&&t();return g(),y},deactivate:O,pause:function(){if(m.paused||!m.active)return;m.paused=!0,h()},unpause:function(){if(!m.paused||!m.active)return;m.paused=!1,F(),g()}};return y;function O(e){if(m.active){clearTimeout(c),h(),m.active=!1,m.paused=!1,p.deactivateTrap(y);var t=e&&void 0!==e.onDeactivate?e.onDeactivate:v.onDeactivate;return t&&t(),(e&&void 0!==e.returnFocus?e.returnFocus:v.returnFocusOnDeactivate)&&b((function(){var e;j((e=m.nodeFocusedBeforeActivation,w("setReturnFocus")||e))})),y}}function g(){if(m.active)return p.activateTrap(y),c=b((function(){j(E())})),u.addEventListener("focusin",D,!0),u.addEventListener("mousedown",k,{capture:!0,passive:!1}),u.addEventListener("touchstart",k,{capture:!0,passive:!1}),u.addEventListener("click",T,{capture:!0,passive:!1}),u.addEventListener("keydown",N,{capture:!0,passive:!1}),y}function h(){if(m.active)return u.removeEventListener("focusin",D,!0),u.removeEventListener("mousedown",k,!0),u.removeEventListener("touchstart",k,!0),u.removeEventListener("click",T,!0),u.removeEventListener("keydown",N,!0),y}function w(e){var t=v[e],n=t;if(!t)return null;if("string"==typeof t&&!(n=u.querySelector(t)))throw new Error("`"+e+"` refers to no known node");if("function"==typeof t&&!(n=t()))throw new Error("`"+e+"` did not return a node");return n}function E(){var e;if(!(e=null!==w("initialFocus")?w("initialFocus"):d.contains(u.activeElement)?u.activeElement:m.firstTabbableNode||w("fallbackFocus")))throw new Error("Your focus-trap needs to have at least one focusable element");return e}function k(e){d.contains(e.target)||(v.clickOutsideDeactivates?O({returnFocus:!s(e.target)}):v.allowOutsideClick&&("boolean"==typeof v.allowOutsideClick?v.allowOutsideClick:v.allowOutsideClick(e))||e.preventDefault())}function D(e){d.contains(e.target)||e.target instanceof Document||(e.stopImmediatePropagation(),j(m.mostRecentlyFocusedNode||E()))}function N(e){if(!1!==v.escapeDeactivates&&function(e){return"Escape"===e.key||"Esc"===e.key||27===e.keyCode}(e))return e.preventDefault(),void O();(function(e){return"Tab"===e.key||9===e.keyCode})(e)&&function(e){if(F(),e.shiftKey&&e.target===m.firstTabbableNode)return e.preventDefault(),void j(m.lastTabbableNode);if(!e.shiftKey&&e.target===m.lastTabbableNode)e.preventDefault(),j(m.firstTabbableNode)}(e)}function T(e){v.clickOutsideDeactivates||d.contains(e.target)||v.allowOutsideClick&&("boolean"==typeof v.allowOutsideClick?v.allowOutsideClick:v.allowOutsideClick(e))||(e.preventDefault(),e.stopImmediatePropagation())}function F(){var e=function(e,t){t=t||{};var n,i,c=[],u=[],s=e.querySelectorAll(r);t.includeContainer&&o.call(e,r)&&(s=Array.prototype.slice.apply(s)).unshift(e);for(var d=0;d<s.length;d++)a(n=s[d])&&(0===(i=l(n))?c.push(n):u.push({documentOrder:d,tabIndex:i,node:n}));return u.sort(f).map((function(e){return e.node})).concat(c)}(d);m.firstTabbableNode=e[0]||E(),m.lastTabbableNode=e[e.length-1]||E()}function j(e){e!==u.activeElement&&(e&&e.focus?(e.focus({preventScroll:!!v.preventScroll}),m.mostRecentlyFocusedNode=e,function(e){return e.tagName&&"input"===e.tagName.toLowerCase()&&"function"==typeof e.select}(e)&&e.select()):j(E()))}};
//# sourceMappingURL=focus-trap.min.js.map

@@ -1,2 +0,2 @@

declare module "focus-trap" {
declare module 'focus-trap' {
/**

@@ -9,2 +9,4 @@ * A DOM node, a selector string (which will be passed to

type MouseEventToBoolean = (event: MouseEvent) => boolean
export interface Options {

@@ -15,3 +17,2 @@ /**

onActivate?: () => void;
/**

@@ -21,3 +22,2 @@ * A function that will be called when the focus trap deactivates.

onDeactivate?: () => void;
/**

@@ -29,3 +29,2 @@ * By default, when a focus trap is activated the first element in the

initialFocus?: FocusTarget;
/**

@@ -41,3 +40,2 @@ * By default, an error will be thrown if the focus trap contains no

fallbackFocus?: FocusTarget;
/**

@@ -48,9 +46,7 @@ * Default: `true`. If `false`, when the trap is deactivated,

returnFocusOnDeactivate?: boolean;
/**
* By default, focus trap on deactivation will return to the element
* that was focused before activation.
*/
*/
setReturnFocus?: FocusTarget;
/**

@@ -63,3 +59,2 @@ * Default: `true`. If `false`, the `Escape` key will not trigger

escapeDeactivates?: boolean;
/**

@@ -70,9 +65,19 @@ * Default: `false`. If `true`, a click outside the focus trap will

clickOutsideDeactivates?: boolean;
allowOutsideClick?: (event: MouseEvent) => boolean;
/**
* If set and is or returns `true`,
* a click outside the focus trap will not be prevented,
* even when `clickOutsideDeactivates` is `false`.
*/
allowOutsideClick?: boolean | MouseEventToBoolean;
/**
* By default, focus() will scroll to the element if not in viewport.
* It can produce unintended effects like scrolling back to the top of a modal.
* If set to `true`, no scroll will happen.
*/
preventScroll?: boolean;
}
type ActivateOptions = Pick<Options, "onActivate">;
type ActivateOptions = Pick<Options, 'onActivate'>;
interface DeactivateOptions extends Pick<Options, "onDeactivate"> {
interface DeactivateOptions extends Pick<Options, 'onDeactivate'> {
returnFocus?: boolean;

@@ -95,3 +100,3 @@ }

*/
export default function focusTrap(
export function createFocusTrap(
element: HTMLElement | string,

@@ -98,0 +103,0 @@ userOptions?: Options

@@ -1,10 +0,9 @@

var tabbable = require('tabbable');
var xtend = require('xtend');
import { tabbable, isFocusable } from 'tabbable';
var activeFocusDelay;
var activeFocusTraps = (function() {
var activeFocusTraps = (function () {
var trapQueue = [];
return {
activateTrap: function(trap) {
activateTrap: function (trap) {
if (trapQueue.length > 0) {

@@ -27,3 +26,3 @@ var activeTrap = trapQueue[trapQueue.length - 1];

deactivateTrap: function(trap) {
deactivateTrap: function (trap) {
var trapIndex = trapQueue.indexOf(trap);

@@ -37,7 +36,7 @@ if (trapIndex !== -1) {

}
}
},
};
})();
function focusTrap(element, userOptions) {
function createFocusTrap(element, userOptions) {
var doc = document;

@@ -47,9 +46,7 @@ var container =

var config = xtend(
{
returnFocusOnDeactivate: true,
escapeDeactivates: true
},
userOptions
);
var config = {
returnFocusOnDeactivate: true,
escapeDeactivates: true,
...userOptions,
};

@@ -62,3 +59,3 @@ var state = {

active: false,
paused: false
paused: false,
};

@@ -70,3 +67,3 @@

pause: pause,
unpause: unpause
unpause: unpause,
};

@@ -121,3 +118,3 @@

if (returnFocus) {
delay(function() {
delay(function () {
tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));

@@ -151,3 +148,3 @@ });

// that caused the focus trap activation.
activeFocusDelay = delay(function() {
activeFocusDelay = delay(function () {
tryFocus(getInitialFocusNode());

@@ -159,15 +156,15 @@ });

capture: true,
passive: false
passive: false,
});
doc.addEventListener('touchstart', checkPointerDown, {
capture: true,
passive: false
passive: false,
});
doc.addEventListener('click', checkClick, {
capture: true,
passive: false
passive: false,
});
doc.addEventListener('keydown', checkKey, {
capture: true,
passive: false
passive: false,
});

@@ -241,3 +238,3 @@

deactivate({
returnFocus: !tabbable.isFocusable(e.target)
returnFocus: !isFocusable(e.target),
});

@@ -249,3 +246,8 @@ return;

// then on mobile they will be blocked anyways if `touchstart` is blocked.)
if (config.allowOutsideClick && config.allowOutsideClick(e)) {
if (
config.allowOutsideClick &&
(typeof config.allowOutsideClick === 'boolean'
? config.allowOutsideClick
: config.allowOutsideClick(e))
) {
return;

@@ -299,3 +301,8 @@ }

if (container.contains(e.target)) return;
if (config.allowOutsideClick && config.allowOutsideClick(e)) {
if (
config.allowOutsideClick &&
(typeof config.allowOutsideClick === 'boolean'
? config.allowOutsideClick
: config.allowOutsideClick(e))
) {
return;

@@ -320,3 +327,3 @@ }

}
node.focus();
node.focus({ preventScroll: !!config.preventScroll });
state.mostRecentlyFocusedNode = node;

@@ -349,2 +356,2 @@ if (isSelectableInput(node)) {

module.exports = focusTrap;
export { createFocusTrap };
{
"name": "focus-trap",
"version": "5.1.0",
"version": "6.0.0",
"description": "Trap focus within a DOM node.",
"main": "index.js",
"main": "dist/focus-trap.min.js",
"module": "dist/focus-trap.esm.min.js",
"types": "index.d.ts",
"sideEffects": false,
"files": [
"package.json",
"README.md",
"CHANGELOG.md",
"LICENSE",
"index.js",
"index.d.ts",
"dist"
],
"scripts": {
"precommit": "lint-staged",
"format": "prettier --write '**/*.{js,json}'",
"lint": "eslint .",
"demo-bundle": "browserify demo/js/index.js -o demo/demo-bundle.js",
"clean": "del-cli dist && make-dir dist",
"build-dev": "npm run clean && browserify index.js -s focusTrap > dist/focus-trap.js",
"minify": "uglifyjs dist/focus-trap.js > dist/focus-trap.min.js",
"build": "npm run build-dev && npm run minify",
"start": "budo demo/js/index.js:demo-bundle.js --dir demo --live",
"test": "npm run lint",
"prepublishOnly": "npm run build"
"format": "prettier --write \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*}.+(js|yml)\"",
"format-check": "prettier --check \"{*,src/**/*,test/**/*,demo/js/**/*,.github/workflows/*}.+(js|yml)\"",
"lint": "eslint \"*.js\" \"demo/**/*.js\"",
"clean": "rm -rf ./dist",
"compile-esm": "BUILD_ENV=esm rollup -c",
"compile-cjs": "BUILD_ENV=cjs rollup -c",
"compile-umd": "BUILD_ENV=umd rollup -c",
"compile": "yarn compile-esm && yarn compile-cjs && yarn compile-umd",
"build": "yarn clean && yarn compile",
"start": "yarn build && budo demo/js/index.js:demo-bundle.js --dir demo --live -- -t babelify",
"test-types": "tsc index.d.ts",
"test-unit": "echo \"No unit tests to run!\"",
"test": "yarn format-check && yarn lint && yarn test-unit && yarn test-types",
"prepublishOnly": "yarn build",
"release": "yarn build && changeset publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/davidtheclark/focus-trap.git"
"url": "git+https://github.com/focus-trap/focus-trap.git"
},

@@ -33,27 +48,40 @@ "keywords": [

"author": "David Clark",
"contributors": [
{
"name": "David Clark",
"url": "http://davidtheclark.com/"
},
{
"name": "Stefan Cameron",
"url": "https://stefancameron.com/"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/davidtheclark/focus-trap/issues"
"url": "https://github.com/focus-trap/focus-trap/issues"
},
"homepage": "https://github.com/davidtheclark/focus-trap#readme",
"homepage": "https://github.com/focus-trap/focus-trap#readme",
"dependencies": {
"tabbable": "^4.0.0",
"xtend": "^4.0.1"
"tabbable": "^5.0.0"
},
"devDependencies": {
"browserify": "^13.3.0",
"budo": "^9.4.1",
"del-cli": "^1.1.0",
"eslint": "^3.13.1",
"husky": "^0.14.3",
"lint-staged": "^7.2.0",
"make-dir-cli": "^1.0.0",
"prettier": "^1.14.0",
"uglify-js": "^3.3.22"
},
"files": [
"dist",
"index.js",
"index.d.ts"
]
"@babel/cli": "^7.11.5",
"@babel/core": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@changesets/cli": "^2.10.2",
"@rollup/plugin-babel": "^5.2.0",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babelify": "^10.0.0",
"budo": "^11.6.4",
"eslint": "^7.8.1",
"eslint-config-prettier": "^6.11.0",
"prettier": "^2.1.1",
"rollup": "^2.26.9",
"rollup-plugin-sourcemaps": "^0.6.2",
"rollup-plugin-terser": "^7.0.1",
"typescript": "^4.0.2"
}
}

@@ -1,2 +0,2 @@

# focus-trap
# focus-trap [![CI](https://github.com/focus-trap/focus-trap/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/focus-trap/focus-trap/actions?query=workflow:CI+branch:master)

@@ -55,4 +55,11 @@ ---

### focusTrap = createFocusTrap(element[, createOptions]);
### createFocusTrap(element[, createOptions])
```javascript
import { createFocusTrap } from 'focus-trap'; // ESM
const { createFocusTrap } = require('focus-trap'); // CJS
focusTrap = createFocusTrap(element[, createOptions]);
```
Returns a new focus trap on `element`.

@@ -74,3 +81,4 @@

- **setReturnFocus** {element|string|function}: By default, focus trap on deactivation will return to the element that was focused before activation. With this option you can specify another element to programmatically receive focus after deactivation. Can be a DOM node, or a selector string (which will be passed to `document.querySelector()` to find the DOM node), or a function that returns a DOM node.
- **allowOutsideClick** {function}: If set and returns `true`, a click outside the focus trap will not be prevented, even when `clickOutsideDeactivates` is `false`.
- **allowOutsideClick** {boolean|function}: If set and is or returns `true`, a click outside the focus trap will not be prevented, even when `clickOutsideDeactivates` is `false`.
- **preventScroll** {boolean}: By default, focus() will scroll to the element if not in viewport. It can produce unintended effects like scrolling back to the top of a modal. If set to `true`, no scroll will happen.

@@ -136,22 +144,29 @@ ### focusTrap.activate([activateOptions])

Here's what happens in `demo-one.js`:
Here's what happens in `default.js` (the "default behavior" demo):
```js
var createFocusTrap = require('../../');
var { createFocusTrap } = require('../../dist/focus-trap');
var containerOne = document.getElementById('demo-one');
var focusTrapOne = createFocusTrap('#demo-one', {
var container = document.getElementById('default');
var focusTrap = createFocusTrap('#default', {
onActivate: function () {
container.className = 'trap is-active';
},
onDeactivate: function () {
containerOne.className = 'trap';
container.className = 'trap';
},
});
document.getElementById('activate-one').addEventListener('click', function () {
focusTrapOne.activate();
containerOne.className = 'trap is-active';
});
document
.getElementById('activate-default')
.addEventListener('click', function () {
focusTrap.activate();
});
document.getElementById('deactivate-one').addEventListener('click', function () {
focusTrapOne.deactivate();
});
document
.getElementById('deactivate-default')
.addEventListener('click', function () {
focusTrap.deactivate();
});
```

@@ -158,0 +173,0 @@

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