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

tabbable

Package Overview
Dependencies
Maintainers
2
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tabbable - npm Package Compare versions

Comparing version 5.2.1 to 5.3.0-beta.0

5

CHANGELOG.md
# Changelog
## 5.3.0-beta.0
- Includes new Shadow DOM support for open shadows by default
- Includes a new `getShadowRoot()` configuration option, enabling support for closed shadows
## 5.2.1

@@ -4,0 +9,0 @@

209

dist/index.esm.js
/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]:not(slot)', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelector = /* #__PURE__ */candidateSelectors.join(',');
var matches = typeof Element === 'undefined' ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var NoElement = typeof Element === 'undefined';
var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {
return element.getRootNode();
} : function (element) {
return element.ownerDocument;
};
/**
* @param {Element} el container to check in
* @param {boolean} includeContainer add container to check
* @param {(node: Element) => boolean} filter filter candidates
* @returns {Element[]}
*/

@@ -19,3 +31,83 @@ var getCandidates = function getCandidates(el, includeContainer, filter) {

};
/**
* @callback GetShadowRoot
* @param {Element} element to check for shadow root
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
*/
/**
* @typedef {Object} CandidatesScope
* @property {Element} scope contains inner candidates
* @property {Element[]} candidates
*/
/**
* @typedef {Object} IterativeOptions
* @property {GetShadowRoot} getShadowRoot returns the shadow root of an element or a boolean stating if it has a shadow root
* @property {(node: Element) => boolean} filter filter candidates
* @property {boolean} flatten if true then result will flatten any CandidatesScope into the returned list
*/
/**
* @param {Element[]} elements list of element containers to match candidates from
* @param {boolean} includeContainer add container list to check
* @param {IterativeOptions} options
* @returns {Array.<Element|CandidatesScope>}
*/
var getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {
var candidates = [];
var elementsToCheck = Array.from(elements);
while (elementsToCheck.length) {
var element = elementsToCheck.shift();
if (element.tagName === 'SLOT') {
// add shadow dom slot scope (slot itself cannot be focusable)
var assigned = element.assignedElements();
var content = assigned.length ? assigned : element.children;
var nestedCandidates = getCandidatesIteratively(content, true, options);
if (options.flatten) {
candidates.push.apply(candidates, nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: nestedCandidates
});
}
} else {
// check candidate element
var validCandidate = matches.call(element, candidateSelector);
if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) {
candidates.push(element);
} // iterate over content
var shadowRoot = element.shadowRoot || options.getShadowRoot(element);
if (shadowRoot) {
// add shadow dom scope
var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);
if (options.flatten) {
candidates.push.apply(candidates, _nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: _nestedCandidates
});
}
} else {
// add light dom scope
elementsToCheck.unshift.apply(elementsToCheck, element.children);
}
}
}
return candidates;
};
var isContentEditable = function isContentEditable(node) {

@@ -25,3 +117,3 @@ return node.contentEditable === 'true';

var getTabindex = function getTabindex(node) {
var getTabindex = function getTabindex(node, isScope) {
var tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);

@@ -42,5 +134,9 @@

// order, consider their tab index to be 0.
//
// isScope is positive for custom element with shadow root or slot that by default
// have tabIndex -1, but need to be sorted by document order in order for their
// content to be inserted in the correct position
if ((node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
if ((isScope || node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
return 0;

@@ -84,3 +180,3 @@ }

var radioScope = node.form || node.ownerDocument;
var radioScope = node.form || getRootNode(node);

@@ -117,3 +213,17 @@ var queryRadios = function queryRadios(name) {

var isHidden = function isHidden(node, displayCheck) {
var noop = function noop() {};
var isZeroArea = function isZeroArea(node) {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
};
var isHidden = function isHidden(node, _ref) {
var displayCheck = _ref.displayCheck,
_ref$getShadowRoot = _ref.getShadowRoot,
getShadowRoot = _ref$getShadowRoot === void 0 ? noop : _ref$getShadowRoot;
if (getComputedStyle(node).visibility === 'hidden') {

@@ -136,10 +246,21 @@ return true;

node = node.parentElement;
var parentElement = node.parentElement;
var rootNode = getRootNode(node);
if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement)) {
// fallback to zero area size for unreachable shadow dom
return isZeroArea(node);
} else if (node.assignedSlot) {
// iterate up slot
node = node.assignedSlot;
} else if (!parentElement && rootNode !== node.ownerDocument) {
// cross shadow boundary
node = rootNode.host;
} else {
// iterate up normal dom
node = parentElement;
}
}
} else if (displayCheck === 'non-zero-area') {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
return isZeroArea(node);
}

@@ -192,3 +313,3 @@

var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) {
if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || // For a details element with a summary, the summary element gets the focus
if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus
isDetailsWithSummary(node) || isDisabledFromFieldset(node)) {

@@ -208,13 +329,19 @@ return false;

};
/**
* @param {Array.<Element|CandidatesScope>} candidates
* @returns Element[]
*/
var tabbable = function tabbable(el, options) {
options = options || {};
var sortByOrder = function sortByOrder(candidates) {
var regularTabbables = [];
var orderedTabbables = [];
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
candidates.forEach(function (candidate, i) {
var candidateTabindex = getTabindex(candidate);
candidates.forEach(function (item, i) {
var isScope = !!item.scope;
var element = isScope ? item.scope : item;
var candidateTabindex = getTabindex(element, isScope);
var elements = isScope ? sortByOrder(item.candidates) : element;
if (candidateTabindex === 0) {
regularTabbables.push(candidate);
isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
} else {

@@ -224,15 +351,45 @@ orderedTabbables.push({

tabIndex: candidateTabindex,
node: candidate
item: item,
isScope: isScope,
content: elements
});
}
});
var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function (a) {
return a.node;
}).concat(regularTabbables);
return tabbableNodes;
return orderedTabbables.sort(sortOrderedTabbables).reduce(function (acc, sortable) {
sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content);
return acc;
}, []).concat(regularTabbables);
};
var tabbable = function tabbable(el, options) {
options = options || {};
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorTabbable.bind(null, options),
flatten: false,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
}
return sortByOrder(candidates);
};
var focusable = function focusable(el, options) {
options = options || {};
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorFocusable.bind(null, options),
flatten: true,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
}
return candidates;

@@ -239,0 +396,0 @@ };

4

dist/index.esm.min.js
/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
var e=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],t=e.join(","),n="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,r=function(e,r,o){var i=Array.prototype.slice.apply(e.querySelectorAll(t));return r&&n.call(e,t)&&i.unshift(e),i=i.filter(o)},o=function(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&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:t},i=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},a=function(e){return"INPUT"===e.tagName},u=function(e){return function(e){return a(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||e.ownerDocument,r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var o=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!o||o===e}(e)},c=function(e,t){return!(t.disabled||function(e){return a(e)&&"hidden"===e.type}(t)||function(e,t){if("hidden"===getComputedStyle(e).visibility)return!0;var r=n.call(e,"details>summary:first-of-type")?e.parentElement:e;if(n.call(r,"details:not([open]) *"))return!0;if(t&&"full"!==t){if("non-zero-area"===t){var o=e.getBoundingClientRect(),i=o.width,a=o.height;return 0===i&&0===a}}else for(;e;){if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}(t,e.displayCheck)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(a(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var r=t.children.item(n);if("LEGEND"===r.tagName)return!r.contains(e)}return!0}t=t.parentElement}return!1}(t))},l=function(e,t){return!(!c(e,t)||u(t)||o(t)<0)},d=function(e,t){var n=[],a=[];return r(e,(t=t||{}).includeContainer,l.bind(null,t)).forEach((function(e,t){var r=o(e);0===r?n.push(e):a.push({documentOrder:t,tabIndex:r,node:e})})),a.sort(i).map((function(e){return e.node})).concat(n)},f=function(e,t){return r(e,(t=t||{}).includeContainer,c.bind(null,t))},m=function(e,r){if(r=r||{},!e)throw new Error("No node provided");return!1!==n.call(e,t)&&l(r,e)},p=e.concat("iframe").join(","),s=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==n.call(e,p)&&c(t,e)};export{f as focusable,s as isFocusable,m as isTabbable,d as tabbable};
var e=["input","select","textarea","a[href]","button","[tabindex]:not(slot)","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],t=e.join(","),n="undefined"==typeof Element,r=n?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,o=!n&&Element.prototype.getRootNode?function(e){return e.getRootNode()}:function(e){return e.ownerDocument},a=function(e,n,o){var a=Array.prototype.slice.apply(e.querySelectorAll(t));return n&&r.call(e,t)&&a.unshift(e),a=a.filter(o)},i=function e(n,o,a){for(var i=[],u=Array.from(n);u.length;){var l=u.shift();if("SLOT"===l.tagName){var c=l.assignedElements(),d=e(c.length?c:l.children,!0,a);a.flatten?i.push.apply(i,d):i.push({scope:l,candidates:d})}else{r.call(l,t)&&a.filter(l)&&(o||!n.includes(l))&&i.push(l);var f=l.shadowRoot||a.getShadowRoot(l);if(f){var s=e(!0===f?l.children:f.children,!0,a);a.flatten?i.push.apply(i,s):i.push({scope:l,candidates:s})}else u.unshift.apply(u,l.children)}}return i},u=function(e,t){var n=parseInt(e.getAttribute("tabindex"),10);return isNaN(n)?function(e){return"true"===e.contentEditable}(e)?0:!t&&"AUDIO"!==e.nodeName&&"VIDEO"!==e.nodeName&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:n},l=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},c=function(e){return"INPUT"===e.tagName},d=function(e){return function(e){return c(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||o(e),r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var a=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!a||a===e}(e)},f=function(){},s=function(e){var t=e.getBoundingClientRect(),n=t.width,r=t.height;return 0===n&&0===r},p=function(e,t){return!(t.disabled||function(e){return c(e)&&"hidden"===e.type}(t)||function(e,t){var n=t.displayCheck,a=t.getShadowRoot,i=void 0===a?f:a;if("hidden"===getComputedStyle(e).visibility)return!0;var u=r.call(e,"details>summary:first-of-type")?e.parentElement:e;if(r.call(u,"details:not([open]) *"))return!0;if(n&&"full"!==n){if("non-zero-area"===n)return s(e)}else for(;e;){if("none"===getComputedStyle(e).display)return!0;var l=e.parentElement,c=o(e);if(l&&!l.shadowRoot&&i(l))return s(e);e=e.assignedSlot?e.assignedSlot:l||c===e.ownerDocument?l:c.host}return!1}(t,e)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(c(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var r=t.children.item(n);if("LEGEND"===r.tagName)return!r.contains(e)}return!0}t=t.parentElement}return!1}(t))},h=function(e,t){return!(!p(e,t)||d(t)||u(t)<0)},m=function(e,t){return function e(t){var n=[],r=[];return t.forEach((function(t,o){var a=!!t.scope,i=a?t.scope:t,l=u(i,a),c=a?e(t.candidates):i;0===l?a?n.push.apply(n,c):n.push(i):r.push({documentOrder:o,tabIndex:l,item:t,isScope:a,content:c})})),r.sort(l).reduce((function(e,t){return t.isScope?e.push.apply(e,t.content):e.push(t.content),e}),[]).concat(n)}((t=t||{}).getShadowRoot?i([e],t.includeContainer,{filter:h.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot}):a(e,t.includeContainer,h.bind(null,t)))},y=function(e,t){return(t=t||{}).getShadowRoot?i([e],t.includeContainer,{filter:p.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):a(e,t.includeContainer,p.bind(null,t))},g=function(e,n){if(n=n||{},!e)throw new Error("No node provided");return!1!==r.call(e,t)&&h(n,e)},S=e.concat("iframe").join(","),v=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,S)&&p(t,e)};export{y as focusable,v as isFocusable,g as isTabbable,m as tabbable};
//# sourceMappingURL=index.esm.min.js.map
/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE

@@ -9,5 +9,17 @@ */

var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]:not(slot)', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelector = /* #__PURE__ */candidateSelectors.join(',');
var matches = typeof Element === 'undefined' ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var NoElement = typeof Element === 'undefined';
var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {
return element.getRootNode();
} : function (element) {
return element.ownerDocument;
};
/**
* @param {Element} el container to check in
* @param {boolean} includeContainer add container to check
* @param {(node: Element) => boolean} filter filter candidates
* @returns {Element[]}
*/

@@ -24,3 +36,83 @@ var getCandidates = function getCandidates(el, includeContainer, filter) {

};
/**
* @callback GetShadowRoot
* @param {Element} element to check for shadow root
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
*/
/**
* @typedef {Object} CandidatesScope
* @property {Element} scope contains inner candidates
* @property {Element[]} candidates
*/
/**
* @typedef {Object} IterativeOptions
* @property {GetShadowRoot} getShadowRoot returns the shadow root of an element or a boolean stating if it has a shadow root
* @property {(node: Element) => boolean} filter filter candidates
* @property {boolean} flatten if true then result will flatten any CandidatesScope into the returned list
*/
/**
* @param {Element[]} elements list of element containers to match candidates from
* @param {boolean} includeContainer add container list to check
* @param {IterativeOptions} options
* @returns {Array.<Element|CandidatesScope>}
*/
var getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {
var candidates = [];
var elementsToCheck = Array.from(elements);
while (elementsToCheck.length) {
var element = elementsToCheck.shift();
if (element.tagName === 'SLOT') {
// add shadow dom slot scope (slot itself cannot be focusable)
var assigned = element.assignedElements();
var content = assigned.length ? assigned : element.children;
var nestedCandidates = getCandidatesIteratively(content, true, options);
if (options.flatten) {
candidates.push.apply(candidates, nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: nestedCandidates
});
}
} else {
// check candidate element
var validCandidate = matches.call(element, candidateSelector);
if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) {
candidates.push(element);
} // iterate over content
var shadowRoot = element.shadowRoot || options.getShadowRoot(element);
if (shadowRoot) {
// add shadow dom scope
var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);
if (options.flatten) {
candidates.push.apply(candidates, _nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: _nestedCandidates
});
}
} else {
// add light dom scope
elementsToCheck.unshift.apply(elementsToCheck, element.children);
}
}
}
return candidates;
};
var isContentEditable = function isContentEditable(node) {

@@ -30,3 +122,3 @@ return node.contentEditable === 'true';

var getTabindex = function getTabindex(node) {
var getTabindex = function getTabindex(node, isScope) {
var tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);

@@ -47,5 +139,9 @@

// order, consider their tab index to be 0.
//
// isScope is positive for custom element with shadow root or slot that by default
// have tabIndex -1, but need to be sorted by document order in order for their
// content to be inserted in the correct position
if ((node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
if ((isScope || node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
return 0;

@@ -89,3 +185,3 @@ }

var radioScope = node.form || node.ownerDocument;
var radioScope = node.form || getRootNode(node);

@@ -122,3 +218,17 @@ var queryRadios = function queryRadios(name) {

var isHidden = function isHidden(node, displayCheck) {
var noop = function noop() {};
var isZeroArea = function isZeroArea(node) {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
};
var isHidden = function isHidden(node, _ref) {
var displayCheck = _ref.displayCheck,
_ref$getShadowRoot = _ref.getShadowRoot,
getShadowRoot = _ref$getShadowRoot === void 0 ? noop : _ref$getShadowRoot;
if (getComputedStyle(node).visibility === 'hidden') {

@@ -141,10 +251,21 @@ return true;

node = node.parentElement;
var parentElement = node.parentElement;
var rootNode = getRootNode(node);
if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement)) {
// fallback to zero area size for unreachable shadow dom
return isZeroArea(node);
} else if (node.assignedSlot) {
// iterate up slot
node = node.assignedSlot;
} else if (!parentElement && rootNode !== node.ownerDocument) {
// cross shadow boundary
node = rootNode.host;
} else {
// iterate up normal dom
node = parentElement;
}
}
} else if (displayCheck === 'non-zero-area') {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
return isZeroArea(node);
}

@@ -197,3 +318,3 @@

var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) {
if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || // For a details element with a summary, the summary element gets the focus
if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus
isDetailsWithSummary(node) || isDisabledFromFieldset(node)) {

@@ -213,13 +334,19 @@ return false;

};
/**
* @param {Array.<Element|CandidatesScope>} candidates
* @returns Element[]
*/
var tabbable = function tabbable(el, options) {
options = options || {};
var sortByOrder = function sortByOrder(candidates) {
var regularTabbables = [];
var orderedTabbables = [];
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
candidates.forEach(function (candidate, i) {
var candidateTabindex = getTabindex(candidate);
candidates.forEach(function (item, i) {
var isScope = !!item.scope;
var element = isScope ? item.scope : item;
var candidateTabindex = getTabindex(element, isScope);
var elements = isScope ? sortByOrder(item.candidates) : element;
if (candidateTabindex === 0) {
regularTabbables.push(candidate);
isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
} else {

@@ -229,15 +356,45 @@ orderedTabbables.push({

tabIndex: candidateTabindex,
node: candidate
item: item,
isScope: isScope,
content: elements
});
}
});
var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function (a) {
return a.node;
}).concat(regularTabbables);
return tabbableNodes;
return orderedTabbables.sort(sortOrderedTabbables).reduce(function (acc, sortable) {
sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content);
return acc;
}, []).concat(regularTabbables);
};
var tabbable = function tabbable(el, options) {
options = options || {};
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorTabbable.bind(null, options),
flatten: false,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
}
return sortByOrder(candidates);
};
var focusable = function focusable(el, options) {
options = options || {};
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorFocusable.bind(null, options),
flatten: true,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
}
return candidates;

@@ -244,0 +401,0 @@ };

/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],t=e.join(","),n="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,r=function(e,r,o){var a=Array.prototype.slice.apply(e.querySelectorAll(t));return r&&n.call(e,t)&&a.unshift(e),a=a.filter(o)},o=function(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&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:t},a=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},i=function(e){return"INPUT"===e.tagName},u=function(e){return function(e){return i(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||e.ownerDocument,r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var o=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!o||o===e}(e)},l=function(e,t){return!(t.disabled||function(e){return i(e)&&"hidden"===e.type}(t)||function(e,t){if("hidden"===getComputedStyle(e).visibility)return!0;var r=n.call(e,"details>summary:first-of-type")?e.parentElement:e;if(n.call(r,"details:not([open]) *"))return!0;if(t&&"full"!==t){if("non-zero-area"===t){var o=e.getBoundingClientRect(),a=o.width,i=o.height;return 0===a&&0===i}}else for(;e;){if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}(t,e.displayCheck)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(i(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var r=t.children.item(n);if("LEGEND"===r.tagName)return!r.contains(e)}return!0}t=t.parentElement}return!1}(t))},c=function(e,t){return!(!l(e,t)||u(t)||o(t)<0)},d=e.concat("iframe").join(",");exports.focusable=function(e,t){return r(e,(t=t||{}).includeContainer,l.bind(null,t))},exports.isFocusable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==n.call(e,d)&&l(t,e)},exports.isTabbable=function(e,r){if(r=r||{},!e)throw new Error("No node provided");return!1!==n.call(e,t)&&c(r,e)},exports.tabbable=function(e,t){var n=[],i=[];return r(e,(t=t||{}).includeContainer,c.bind(null,t)).forEach((function(e,t){var r=o(e);0===r?n.push(e):i.push({documentOrder:t,tabIndex:r,node:e})})),i.sort(a).map((function(e){return e.node})).concat(n)};
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=["input","select","textarea","a[href]","button","[tabindex]:not(slot)","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],t=e.join(","),n="undefined"==typeof Element,r=n?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,o=!n&&Element.prototype.getRootNode?function(e){return e.getRootNode()}:function(e){return e.ownerDocument},a=function(e,n,o){var a=Array.prototype.slice.apply(e.querySelectorAll(t));return n&&r.call(e,t)&&a.unshift(e),a=a.filter(o)},i=function e(n,o,a){for(var i=[],u=Array.from(n);u.length;){var l=u.shift();if("SLOT"===l.tagName){var c=l.assignedElements(),d=e(c.length?c:l.children,!0,a);a.flatten?i.push.apply(i,d):i.push({scope:l,candidates:d})}else{r.call(l,t)&&a.filter(l)&&(o||!n.includes(l))&&i.push(l);var s=l.shadowRoot||a.getShadowRoot(l);if(s){var f=e(!0===s?l.children:s.children,!0,a);a.flatten?i.push.apply(i,f):i.push({scope:l,candidates:f})}else u.unshift.apply(u,l.children)}}return i},u=function(e,t){var n=parseInt(e.getAttribute("tabindex"),10);return isNaN(n)?function(e){return"true"===e.contentEditable}(e)?0:!t&&"AUDIO"!==e.nodeName&&"VIDEO"!==e.nodeName&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:n},l=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},c=function(e){return"INPUT"===e.tagName},d=function(e){return function(e){return c(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||o(e),r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var a=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!a||a===e}(e)},s=function(){},f=function(e){var t=e.getBoundingClientRect(),n=t.width,r=t.height;return 0===n&&0===r},p=function(e,t){return!(t.disabled||function(e){return c(e)&&"hidden"===e.type}(t)||function(e,t){var n=t.displayCheck,a=t.getShadowRoot,i=void 0===a?s:a;if("hidden"===getComputedStyle(e).visibility)return!0;var u=r.call(e,"details>summary:first-of-type")?e.parentElement:e;if(r.call(u,"details:not([open]) *"))return!0;if(n&&"full"!==n){if("non-zero-area"===n)return f(e)}else for(;e;){if("none"===getComputedStyle(e).display)return!0;var l=e.parentElement,c=o(e);if(l&&!l.shadowRoot&&i(l))return f(e);e=e.assignedSlot?e.assignedSlot:l||c===e.ownerDocument?l:c.host}return!1}(t,e)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(c(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var r=t.children.item(n);if("LEGEND"===r.tagName)return!r.contains(e)}return!0}t=t.parentElement}return!1}(t))},h=function(e,t){return!(!p(e,t)||d(t)||u(t)<0)},m=e.concat("iframe").join(",");exports.focusable=function(e,t){return(t=t||{}).getShadowRoot?i([e],t.includeContainer,{filter:p.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):a(e,t.includeContainer,p.bind(null,t))},exports.isFocusable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,m)&&p(t,e)},exports.isTabbable=function(e,n){if(n=n||{},!e)throw new Error("No node provided");return!1!==r.call(e,t)&&h(n,e)},exports.tabbable=function(e,t){return function e(t){var n=[],r=[];return t.forEach((function(t,o){var a=!!t.scope,i=a?t.scope:t,l=u(i,a),c=a?e(t.candidates):i;0===l?a?n.push.apply(n,c):n.push(i):r.push({documentOrder:o,tabIndex:l,item:t,isScope:a,content:c})})),r.sort(l).reduce((function(e,t){return t.isScope?e.push.apply(e,t.content):e.push(t.content),e}),[]).concat(n)}((t=t||{}).getShadowRoot?i([e],t.includeContainer,{filter:h.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot}):a(e,t.includeContainer,h.bind(null,t)))};
//# sourceMappingURL=index.min.js.map
/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE

@@ -13,8 +13,20 @@ */

exports.noConflict = function () { global.tabbable = current; return exports; };
}()));
}(this, (function (exports) { 'use strict';
})());
})(this, (function (exports) { 'use strict';
var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelectors = ['input', 'select', 'textarea', 'a[href]', 'button', '[tabindex]:not(slot)', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details'];
var candidateSelector = /* #__PURE__ */candidateSelectors.join(',');
var matches = typeof Element === 'undefined' ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var NoElement = typeof Element === 'undefined';
var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {
return element.getRootNode();
} : function (element) {
return element.ownerDocument;
};
/**
* @param {Element} el container to check in
* @param {boolean} includeContainer add container to check
* @param {(node: Element) => boolean} filter filter candidates
* @returns {Element[]}
*/

@@ -31,3 +43,83 @@ var getCandidates = function getCandidates(el, includeContainer, filter) {

};
/**
* @callback GetShadowRoot
* @param {Element} element to check for shadow root
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
*/
/**
* @typedef {Object} CandidatesScope
* @property {Element} scope contains inner candidates
* @property {Element[]} candidates
*/
/**
* @typedef {Object} IterativeOptions
* @property {GetShadowRoot} getShadowRoot returns the shadow root of an element or a boolean stating if it has a shadow root
* @property {(node: Element) => boolean} filter filter candidates
* @property {boolean} flatten if true then result will flatten any CandidatesScope into the returned list
*/
/**
* @param {Element[]} elements list of element containers to match candidates from
* @param {boolean} includeContainer add container list to check
* @param {IterativeOptions} options
* @returns {Array.<Element|CandidatesScope>}
*/
var getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {
var candidates = [];
var elementsToCheck = Array.from(elements);
while (elementsToCheck.length) {
var element = elementsToCheck.shift();
if (element.tagName === 'SLOT') {
// add shadow dom slot scope (slot itself cannot be focusable)
var assigned = element.assignedElements();
var content = assigned.length ? assigned : element.children;
var nestedCandidates = getCandidatesIteratively(content, true, options);
if (options.flatten) {
candidates.push.apply(candidates, nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: nestedCandidates
});
}
} else {
// check candidate element
var validCandidate = matches.call(element, candidateSelector);
if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) {
candidates.push(element);
} // iterate over content
var shadowRoot = element.shadowRoot || options.getShadowRoot(element);
if (shadowRoot) {
// add shadow dom scope
var _nestedCandidates = getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);
if (options.flatten) {
candidates.push.apply(candidates, _nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: _nestedCandidates
});
}
} else {
// add light dom scope
elementsToCheck.unshift.apply(elementsToCheck, element.children);
}
}
}
return candidates;
};
var isContentEditable = function isContentEditable(node) {

@@ -37,3 +129,3 @@ return node.contentEditable === 'true';

var getTabindex = function getTabindex(node) {
var getTabindex = function getTabindex(node, isScope) {
var tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);

@@ -54,5 +146,9 @@

// order, consider their tab index to be 0.
//
// isScope is positive for custom element with shadow root or slot that by default
// have tabIndex -1, but need to be sorted by document order in order for their
// content to be inserted in the correct position
if ((node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
if ((isScope || node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO' || node.nodeName === 'DETAILS') && node.getAttribute('tabindex') === null) {
return 0;

@@ -96,3 +192,3 @@ }

var radioScope = node.form || node.ownerDocument;
var radioScope = node.form || getRootNode(node);

@@ -129,3 +225,17 @@ var queryRadios = function queryRadios(name) {

var isHidden = function isHidden(node, displayCheck) {
var noop = function noop() {};
var isZeroArea = function isZeroArea(node) {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
};
var isHidden = function isHidden(node, _ref) {
var displayCheck = _ref.displayCheck,
_ref$getShadowRoot = _ref.getShadowRoot,
getShadowRoot = _ref$getShadowRoot === void 0 ? noop : _ref$getShadowRoot;
if (getComputedStyle(node).visibility === 'hidden') {

@@ -148,10 +258,21 @@ return true;

node = node.parentElement;
var parentElement = node.parentElement;
var rootNode = getRootNode(node);
if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement)) {
// fallback to zero area size for unreachable shadow dom
return isZeroArea(node);
} else if (node.assignedSlot) {
// iterate up slot
node = node.assignedSlot;
} else if (!parentElement && rootNode !== node.ownerDocument) {
// cross shadow boundary
node = rootNode.host;
} else {
// iterate up normal dom
node = parentElement;
}
}
} else if (displayCheck === 'non-zero-area') {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
return isZeroArea(node);
}

@@ -204,3 +325,3 @@

var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) {
if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || // For a details element with a summary, the summary element gets the focus
if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus
isDetailsWithSummary(node) || isDisabledFromFieldset(node)) {

@@ -220,13 +341,19 @@ return false;

};
/**
* @param {Array.<Element|CandidatesScope>} candidates
* @returns Element[]
*/
var tabbable = function tabbable(el, options) {
options = options || {};
var sortByOrder = function sortByOrder(candidates) {
var regularTabbables = [];
var orderedTabbables = [];
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
candidates.forEach(function (candidate, i) {
var candidateTabindex = getTabindex(candidate);
candidates.forEach(function (item, i) {
var isScope = !!item.scope;
var element = isScope ? item.scope : item;
var candidateTabindex = getTabindex(element, isScope);
var elements = isScope ? sortByOrder(item.candidates) : element;
if (candidateTabindex === 0) {
regularTabbables.push(candidate);
isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
} else {

@@ -236,15 +363,45 @@ orderedTabbables.push({

tabIndex: candidateTabindex,
node: candidate
item: item,
isScope: isScope,
content: elements
});
}
});
var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function (a) {
return a.node;
}).concat(regularTabbables);
return tabbableNodes;
return orderedTabbables.sort(sortOrderedTabbables).reduce(function (acc, sortable) {
sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content);
return acc;
}, []).concat(regularTabbables);
};
var tabbable = function tabbable(el, options) {
options = options || {};
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorTabbable.bind(null, options),
flatten: false,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
}
return sortByOrder(candidates);
};
var focusable = function focusable(el, options) {
options = options || {};
var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
var candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorFocusable.bind(null, options),
flatten: true,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
}
return candidates;

@@ -290,3 +447,3 @@ };

})));
}));
//# sourceMappingURL=index.umd.js.map
/*!
* tabbable 5.2.1
* tabbable 5.3.0-beta.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):(e="undefined"!=typeof globalThis?globalThis:e||self,function(){var n=e.tabbable,r=e.tabbable={};t(r),r.noConflict=function(){return e.tabbable=n,r}}())}(this,(function(e){"use strict";var t=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],n=t.join(","),r="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,o=function(e,t,o){var i=Array.prototype.slice.apply(e.querySelectorAll(n));return t&&r.call(e,n)&&i.unshift(e),i=i.filter(o)},i=function(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&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:t},a=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},u=function(e){return"INPUT"===e.tagName},l=function(e){return function(e){return u(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||e.ownerDocument,r=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=r(window.CSS.escape(e.name));else try{t=r(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var o=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!o||o===e}(e)},c=function(e,t){return!(t.disabled||function(e){return u(e)&&"hidden"===e.type}(t)||function(e,t){if("hidden"===getComputedStyle(e).visibility)return!0;var n=r.call(e,"details>summary:first-of-type")?e.parentElement:e;if(r.call(n,"details:not([open]) *"))return!0;if(t&&"full"!==t){if("non-zero-area"===t){var o=e.getBoundingClientRect(),i=o.width,a=o.height;return 0===i&&0===a}}else for(;e;){if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}(t,e.displayCheck)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(u(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var r=t.children.item(n);if("LEGEND"===r.tagName)return!r.contains(e)}return!0}t=t.parentElement}return!1}(t))},d=function(e,t){return!(!c(e,t)||l(t)||i(t)<0)},f=t.concat("iframe").join(",");e.focusable=function(e,t){return o(e,(t=t||{}).includeContainer,c.bind(null,t))},e.isFocusable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,f)&&c(t,e)},e.isTabbable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,n)&&d(t,e)},e.tabbable=function(e,t){var n=[],r=[];return o(e,(t=t||{}).includeContainer,d.bind(null,t)).forEach((function(e,t){var o=i(e);0===o?n.push(e):r.push({documentOrder:t,tabIndex:o,node:e})})),r.sort(a).map((function(e){return e.node})).concat(n)},Object.defineProperty(e,"__esModule",{value:!0})}));
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):(e="undefined"!=typeof globalThis?globalThis:e||self,function(){var n=e.tabbable,o=e.tabbable={};t(o),o.noConflict=function(){return e.tabbable=n,o}}())}(this,(function(e){"use strict";var t=["input","select","textarea","a[href]","button","[tabindex]:not(slot)","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],n=t.join(","),o="undefined"==typeof Element,r=o?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,a=!o&&Element.prototype.getRootNode?function(e){return e.getRootNode()}:function(e){return e.ownerDocument},i=function(e,t,o){var a=Array.prototype.slice.apply(e.querySelectorAll(n));return t&&r.call(e,n)&&a.unshift(e),a=a.filter(o)},u=function e(t,o,a){for(var i=[],u=Array.from(t);u.length;){var l=u.shift();if("SLOT"===l.tagName){var c=l.assignedElements(),d=e(c.length?c:l.children,!0,a);a.flatten?i.push.apply(i,d):i.push({scope:l,candidates:d})}else{r.call(l,n)&&a.filter(l)&&(o||!t.includes(l))&&i.push(l);var f=l.shadowRoot||a.getShadowRoot(l);if(f){var s=e(!0===f?l.children:f.children,!0,a);a.flatten?i.push.apply(i,s):i.push({scope:l,candidates:s})}else u.unshift.apply(u,l.children)}}return i},l=function(e,t){var n=parseInt(e.getAttribute("tabindex"),10);return isNaN(n)?function(e){return"true"===e.contentEditable}(e)?0:!t&&"AUDIO"!==e.nodeName&&"VIDEO"!==e.nodeName&&"DETAILS"!==e.nodeName||null!==e.getAttribute("tabindex")?e.tabIndex:0:n},c=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},d=function(e){return"INPUT"===e.tagName},f=function(e){return function(e){return d(e)&&"radio"===e.type}(e)&&!function(e){if(!e.name)return!0;var t,n=e.form||a(e),o=function(e){return n.querySelectorAll('input[type="radio"][name="'+e+'"]')};if("undefined"!=typeof window&&void 0!==window.CSS&&"function"==typeof window.CSS.escape)t=o(window.CSS.escape(e.name));else try{t=o(e.name)}catch(e){return console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s",e.message),!1}var r=function(e,t){for(var n=0;n<e.length;n++)if(e[n].checked&&e[n].form===t)return e[n]}(t,e.form);return!r||r===e}(e)},s=function(){},p=function(e){var t=e.getBoundingClientRect(),n=t.width,o=t.height;return 0===n&&0===o},h=function(e,t){return!(t.disabled||function(e){return d(e)&&"hidden"===e.type}(t)||function(e,t){var n=t.displayCheck,o=t.getShadowRoot,i=void 0===o?s:o;if("hidden"===getComputedStyle(e).visibility)return!0;var u=r.call(e,"details>summary:first-of-type")?e.parentElement:e;if(r.call(u,"details:not([open]) *"))return!0;if(n&&"full"!==n){if("non-zero-area"===n)return p(e)}else for(;e;){if("none"===getComputedStyle(e).display)return!0;var l=e.parentElement,c=a(e);if(l&&!l.shadowRoot&&i(l))return p(e);e=e.assignedSlot?e.assignedSlot:l||c===e.ownerDocument?l:c.host}return!1}(t,e)||function(e){return"DETAILS"===e.tagName&&Array.prototype.slice.apply(e.children).some((function(e){return"SUMMARY"===e.tagName}))}(t)||function(e){if(d(e)||"SELECT"===e.tagName||"TEXTAREA"===e.tagName||"BUTTON"===e.tagName)for(var t=e.parentElement;t;){if("FIELDSET"===t.tagName&&t.disabled){for(var n=0;n<t.children.length;n++){var o=t.children.item(n);if("LEGEND"===o.tagName)return!o.contains(e)}return!0}t=t.parentElement}return!1}(t))},m=function(e,t){return!(!h(e,t)||f(t)||l(t)<0)},b=t.concat("iframe").join(",");e.focusable=function(e,t){return(t=t||{}).getShadowRoot?u([e],t.includeContainer,{filter:h.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):i(e,t.includeContainer,h.bind(null,t))},e.isFocusable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,b)&&h(t,e)},e.isTabbable=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return!1!==r.call(e,n)&&m(t,e)},e.tabbable=function(e,t){return function e(t){var n=[],o=[];return t.forEach((function(t,r){var a=!!t.scope,i=a?t.scope:t,u=l(i,a),c=a?e(t.candidates):i;0===u?a?n.push.apply(n,c):n.push(i):o.push({documentOrder:r,tabIndex:u,item:t,isScope:a,content:c})})),o.sort(c).reduce((function(e,t){return t.isScope?e.push.apply(e,t.content):e.push(t.content),e}),[]).concat(n)}((t=t||{}).getShadowRoot?u([e],t.includeContainer,{filter:m.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot}):i(e,t.includeContainer,m.bind(null,t)))},Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=index.umd.min.js.map

@@ -5,2 +5,3 @@ type FocusableElement = HTMLElement | SVGElement;

displayCheck?: 'full' | 'non-zero-area' | 'none';
getShadowRoot?: (node: FocusableElement) => ShadowRoot | boolean | undefined;
};

@@ -7,0 +8,0 @@

{
"name": "tabbable",
"version": "5.2.1",
"version": "5.3.0-beta.0",
"description": "Returns an array of all tabbable DOM nodes within a containing node.",

@@ -54,17 +54,17 @@ "main": "dist/index.js",

"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.2",
"@babel/plugin-proposal-optional-chaining": "^7.14.2",
"@babel/preset-env": "^7.15.0",
"@changesets/cli": "^2.16.0",
"@cypress/code-coverage": "^3.9.10",
"@babel/core": "^7.16.12",
"@babel/eslint-parser": "^7.16.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
"@babel/plugin-proposal-optional-chaining": "^7.16.0",
"@babel/preset-env": "^7.16.11",
"@changesets/cli": "^2.20.0",
"@cypress/code-coverage": "^3.9.12",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@testing-library/dom": "^8.1.0",
"@testing-library/jest-dom": "^5.14.1",
"@types/node": "^16.4.13",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.1.3",
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "^5.16.1",
"@types/node": "^17.0.12",
"all-contributors-cli": "^6.20.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.6",
"babel-jest": "^27.4.6",
"brfs": "^2.0.2",

@@ -74,17 +74,17 @@ "browserify": "^17.0.0",

"cross-env": "^7.0.3",
"cypress": "^8.2.0",
"eslint": "^7.32.0",
"cypress": "^9.3.1",
"eslint": "^8.7.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-import": "^2.24.0",
"jest": "^27.0.6",
"jest-watch-typeahead": "^0.6.4",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-import": "^2.25.4",
"jest": "^27.4.7",
"jest-watch-typeahead": "^1.0.0",
"onchange": "^7.1.0",
"prettier": "^2.3.2",
"rollup": "^2.56.2",
"prettier": "^2.5.1",
"rollup": "^2.66.1",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^4.3.5",
"typescript": "^4.5.5",
"watchify": "^4.0.0"
}
}

@@ -94,2 +94,12 @@ # tabbable [![CI](https://github.com/focus-trap/tabbable/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/focus-trap/tabbable/actions?query=workflow:CI+branch:master) [![Codecov](https://img.shields.io/codecov/c/github/focus-trap/tabbable)](https://codecov.io/gh/focus-trap/tabbable) [![license](https://badgen.now.sh/badge/license/MIT)](./LICENSE)

##### getShadowRoot
Type: `(node: FocusableElement) => ShadowRoot | boolean | undefined`
Returns the node's `ShadowRoot` if available, or a `boolean` indicating if a `ShadowRoot` is attached but not available. `node` will be a descendent of the `rootNode` given to `tabbable()`.
If `true` is returned, Tabbable assumes a closed `ShadowRoot` is attached and will iterate the `node`'s children for additional tabbable/focusable candidates.
If a falsy value is returned, all children will be ignored as candidates.
### isTabbable

@@ -96,0 +106,0 @@

@@ -7,3 +7,3 @@ const candidateSelectors = [

'button',
'[tabindex]',
'[tabindex]:not(slot)',
'audio[controls]',

@@ -17,9 +17,21 @@ 'video[controls]',

const matches =
typeof Element === 'undefined'
? function () {}
: Element.prototype.matches ||
Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
const NoElement = typeof Element === 'undefined';
const matches = NoElement
? function () {}
: Element.prototype.matches ||
Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
const getRootNode =
!NoElement && Element.prototype.getRootNode
? (element) => element.getRootNode()
: (element) => element.ownerDocument;
/**
* @param {Element} el container to check in
* @param {boolean} includeContainer add container to check
* @param {(node: Element) => boolean} filter filter candidates
* @returns {Element[]}
*/
const getCandidates = function (el, includeContainer, filter) {

@@ -36,2 +48,85 @@ let candidates = Array.prototype.slice.apply(

/**
* @callback GetShadowRoot
* @param {Element} element to check for shadow root
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
*/
/**
* @typedef {Object} CandidatesScope
* @property {Element} scope contains inner candidates
* @property {Element[]} candidates
*/
/**
* @typedef {Object} IterativeOptions
* @property {GetShadowRoot} getShadowRoot returns the shadow root of an element or a boolean stating if it has a shadow root
* @property {(node: Element) => boolean} filter filter candidates
* @property {boolean} flatten if true then result will flatten any CandidatesScope into the returned list
*/
/**
* @param {Element[]} elements list of element containers to match candidates from
* @param {boolean} includeContainer add container list to check
* @param {IterativeOptions} options
* @returns {Array.<Element|CandidatesScope>}
*/
const getCandidatesIteratively = function (
elements,
includeContainer,
options
) {
const candidates = [];
const elementsToCheck = Array.from(elements);
while (elementsToCheck.length) {
const element = elementsToCheck.shift();
if (element.tagName === 'SLOT') {
// add shadow dom slot scope (slot itself cannot be focusable)
const assigned = element.assignedElements();
const content = assigned.length ? assigned : element.children;
const nestedCandidates = getCandidatesIteratively(content, true, options);
if (options.flatten) {
candidates.push(...nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: nestedCandidates,
});
}
} else {
// check candidate element
const validCandidate = matches.call(element, candidateSelector);
if (
validCandidate &&
options.filter(element) &&
(includeContainer || !elements.includes(element))
) {
candidates.push(element);
}
// iterate over content
const shadowRoot = element.shadowRoot || options.getShadowRoot(element);
if (shadowRoot) {
// add shadow dom scope
const nestedCandidates = getCandidatesIteratively(
shadowRoot === true ? element.children : shadowRoot.children,
true,
options
);
if (options.flatten) {
candidates.push(...nestedCandidates);
} else {
candidates.push({
scope: element,
candidates: nestedCandidates,
});
}
} else {
// add light dom scope
elementsToCheck.unshift(...element.children);
}
}
}
return candidates;
};
const isContentEditable = function (node) {

@@ -41,3 +136,3 @@ return node.contentEditable === 'true';

const getTabindex = function (node) {
const getTabindex = function (node, isScope) {
const tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);

@@ -60,4 +155,9 @@

// order, consider their tab index to be 0.
//
// isScope is positive for custom element with shadow root or slot that by default
// have tabIndex -1, but need to be sorted by document order in order for their
// content to be inserted in the correct position
if (
(node.nodeName === 'AUDIO' ||
(isScope ||
node.nodeName === 'AUDIO' ||
node.nodeName === 'VIDEO' ||

@@ -108,4 +208,3 @@ node.nodeName === 'DETAILS') &&

}
const radioScope = node.form || node.ownerDocument;
const radioScope = node.form || getRootNode(node);
const queryRadios = function (name) {

@@ -149,3 +248,8 @@ return radioScope.querySelectorAll(

const isHidden = function (node, displayCheck) {
const noop = () => {};
const isZeroArea = function (node) {
const { width, height } = node.getBoundingClientRect();
return width === 0 && height === 0;
};
const isHidden = function (node, { displayCheck, getShadowRoot = noop }) {
if (getComputedStyle(node).visibility === 'hidden') {

@@ -160,2 +264,3 @@ return true;

}
if (!displayCheck || displayCheck === 'full') {

@@ -166,7 +271,24 @@ while (node) {

}
node = node.parentElement;
const parentElement = node.parentElement;
const rootNode = getRootNode(node);
if (
parentElement &&
!parentElement.shadowRoot &&
getShadowRoot(parentElement)
) {
// fallback to zero area size for unreachable shadow dom
return isZeroArea(node);
} else if (node.assignedSlot) {
// iterate up slot
node = node.assignedSlot;
} else if (!parentElement && rootNode !== node.ownerDocument) {
// cross shadow boundary
node = rootNode.host;
} else {
// iterate up normal dom
node = parentElement;
}
}
} else if (displayCheck === 'non-zero-area') {
const { width, height } = node.getBoundingClientRect();
return width === 0 && height === 0;
return isZeroArea(node);
}

@@ -225,3 +347,3 @@

isHiddenInput(node) ||
isHidden(node, options.displayCheck) ||
isHidden(node, options) ||
// For a details element with a summary, the summary element gets the focus

@@ -247,18 +369,18 @@ isDetailsWithSummary(node) ||

const tabbable = function (el, options) {
options = options || {};
/**
* @param {Array.<Element|CandidatesScope>} candidates
* @returns Element[]
*/
const sortByOrder = function (candidates) {
const regularTabbables = [];
const orderedTabbables = [];
const candidates = getCandidates(
el,
options.includeContainer,
isNodeMatchingSelectorTabbable.bind(null, options)
);
candidates.forEach(function (candidate, i) {
const candidateTabindex = getTabindex(candidate);
candidates.forEach(function (item, i) {
const isScope = !!item.scope;
const element = isScope ? item.scope : item;
const candidateTabindex = getTabindex(element, isScope);
const elements = isScope ? sortByOrder(item.candidates) : element;
if (candidateTabindex === 0) {
regularTabbables.push(candidate);
isScope
? regularTabbables.push(...elements)
: regularTabbables.push(element);
} else {

@@ -268,3 +390,5 @@ orderedTabbables.push({

tabIndex: candidateTabindex,
node: candidate,
item: item,
isScope: isScope,
content: elements,
});

@@ -274,8 +398,31 @@ }

const tabbableNodes = orderedTabbables
return orderedTabbables
.sort(sortOrderedTabbables)
.map((a) => a.node)
.reduce((acc, sortable) => {
sortable.isScope
? acc.push(...sortable.content)
: acc.push(sortable.content);
return acc;
}, [])
.concat(regularTabbables);
};
return tabbableNodes;
const tabbable = function (el, options) {
options = options || {};
let candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorTabbable.bind(null, options),
flatten: false,
getShadowRoot: options.getShadowRoot,
});
} else {
candidates = getCandidates(
el,
options.includeContainer,
isNodeMatchingSelectorTabbable.bind(null, options)
);
}
return sortByOrder(candidates);
};

@@ -286,7 +433,16 @@

const candidates = getCandidates(
el,
options.includeContainer,
isNodeMatchingSelectorFocusable.bind(null, options)
);
let candidates;
if (options.getShadowRoot) {
candidates = getCandidatesIteratively([el], options.includeContainer, {
filter: isNodeMatchingSelectorFocusable.bind(null, options),
flatten: true,
getShadowRoot: options.getShadowRoot,
});
} else {
candidates = getCandidates(
el,
options.includeContainer,
isNodeMatchingSelectorFocusable.bind(null, options)
);
}

@@ -293,0 +449,0 @@ return candidates;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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