focus-trap 6.1.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"focus-trap.min.js","sources":["../node_modules/tabbable/src/index.js","../index.js"],"sourcesContent":["let candidateSelectors = [\n 'input',\n 'select',\n 'textarea',\n 'a[href]',\n 'button',\n '[tabindex]',\n 'audio[controls]',\n 'video[controls]',\n '[contenteditable]:not([contenteditable=\"false\"])',\n 'details>summary',\n];\nlet candidateSelector = /* #__PURE__ */ candidateSelectors.join(',');\n\nlet matches =\n typeof Element === 'undefined'\n ? function () {}\n : Element.prototype.matches ||\n Element.prototype.msMatchesSelector ||\n Element.prototype.webkitMatchesSelector;\n\nfunction tabbable(el, options) {\n options = options || {};\n\n let regularTabbables = [];\n let orderedTabbables = [];\n\n let candidates = getCandidates(\n el,\n options.includeContainer,\n isNodeMatchingSelectorTabbable\n );\n\n candidates.forEach(function (candidate, i) {\n let candidateTabindex = getTabindex(candidate);\n if (candidateTabindex === 0) {\n regularTabbables.push(candidate);\n } else {\n orderedTabbables.push({\n documentOrder: i,\n tabIndex: candidateTabindex,\n node: candidate,\n });\n }\n });\n\n let tabbableNodes = orderedTabbables\n .sort(sortOrderedTabbables)\n .map((a) => a.node)\n .concat(regularTabbables);\n\n return tabbableNodes;\n}\n\nfunction focusable(el, options) {\n options = options || {};\n\n let candidates = getCandidates(\n el,\n options.includeContainer,\n isNodeMatchingSelectorFocusable\n );\n\n return candidates;\n}\n\nfunction getCandidates(el, includeContainer, filter) {\n let candidates = Array.prototype.slice.apply(\n el.querySelectorAll(candidateSelector)\n );\n if (includeContainer && matches.call(el, candidateSelector)) {\n candidates.unshift(el);\n }\n candidates = candidates.filter(filter);\n return candidates;\n}\n\nfunction isNodeMatchingSelectorTabbable(node) {\n if (\n !isNodeMatchingSelectorFocusable(node) ||\n isNonTabbableRadio(node) ||\n getTabindex(node) < 0\n ) {\n return false;\n }\n return true;\n}\n\nfunction isTabbable(node) {\n if (!node) {\n throw new Error('No node provided');\n }\n if (matches.call(node, candidateSelector) === false) {\n return false;\n }\n return isNodeMatchingSelectorTabbable(node);\n}\n\nfunction isNodeMatchingSelectorFocusable(node) {\n if (node.disabled || isHiddenInput(node) || isHidden(node)) {\n return false;\n }\n return true;\n}\n\nlet focusableCandidateSelector = /* #__PURE__ */ candidateSelectors\n .concat('iframe')\n .join(',');\nfunction isFocusable(node) {\n if (!node) {\n throw new Error('No node provided');\n }\n if (matches.call(node, focusableCandidateSelector) === false) {\n return false;\n }\n return isNodeMatchingSelectorFocusable(node);\n}\n\nfunction getTabindex(node) {\n let tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);\n\n if (!isNaN(tabindexAttr)) {\n return tabindexAttr;\n }\n\n // Browsers do not return `tabIndex` correctly for contentEditable nodes;\n // so if they don't have a tabindex attribute specifically set, assume it's 0.\n if (isContentEditable(node)) {\n return 0;\n }\n\n // in Chrome, <audio controls/> and <video controls/> elements get a default\n // `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,\n // yet they are still part of the regular tab order; in FF, they get a default\n // `tabIndex` of 0; since Chrome still puts those elements in the regular tab\n // order, consider their tab index to be 0\n if (\n (node.nodeName === 'AUDIO' || node.nodeName === 'VIDEO') &&\n node.getAttribute('tabindex') === null\n ) {\n return 0;\n }\n\n return node.tabIndex;\n}\n\nfunction sortOrderedTabbables(a, b) {\n return a.tabIndex === b.tabIndex\n ? a.documentOrder - b.documentOrder\n : a.tabIndex - b.tabIndex;\n}\n\nfunction isContentEditable(node) {\n return node.contentEditable === 'true';\n}\n\nfunction isInput(node) {\n return node.tagName === 'INPUT';\n}\n\nfunction isHiddenInput(node) {\n return isInput(node) && node.type === 'hidden';\n}\n\nfunction isRadio(node) {\n return isInput(node) && node.type === 'radio';\n}\n\nfunction isNonTabbableRadio(node) {\n return isRadio(node) && !isTabbableRadio(node);\n}\n\nfunction getCheckedRadio(nodes, form) {\n for (let i = 0; i < nodes.length; i++) {\n if (nodes[i].checked && nodes[i].form === form) {\n return nodes[i];\n }\n }\n}\n\nfunction isTabbableRadio(node) {\n if (!node.name) {\n return true;\n }\n const radioScope = node.form || node.ownerDocument;\n let radioSet = radioScope.querySelectorAll(\n 'input[type=\"radio\"][name=\"' + node.name + '\"]'\n );\n let checked = getCheckedRadio(radioSet, node.form);\n return !checked || checked === node;\n}\n\nfunction isHidden(node) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n\n while (node) {\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement;\n }\n\n return false;\n}\n\nexport { tabbable, focusable, isTabbable, isFocusable };\n","import { tabbable, isFocusable } from 'tabbable';\n\nvar activeFocusDelay;\n\nvar activeFocusTraps = (function () {\n var trapQueue = [];\n return {\n activateTrap: function (trap) {\n if (trapQueue.length > 0) {\n var activeTrap = trapQueue[trapQueue.length - 1];\n if (activeTrap !== trap) {\n activeTrap.pause();\n }\n }\n\n var trapIndex = trapQueue.indexOf(trap);\n if (trapIndex === -1) {\n trapQueue.push(trap);\n } else {\n // move this existing trap to the front of the queue\n trapQueue.splice(trapIndex, 1);\n trapQueue.push(trap);\n }\n },\n\n deactivateTrap: function (trap) {\n var trapIndex = trapQueue.indexOf(trap);\n if (trapIndex !== -1) {\n trapQueue.splice(trapIndex, 1);\n }\n\n if (trapQueue.length > 0) {\n trapQueue[trapQueue.length - 1].unpause();\n }\n },\n };\n})();\n\nfunction createFocusTrap(element, userOptions) {\n var doc = document;\n var container =\n typeof element === 'string' ? doc.querySelector(element) : element;\n\n var config = {\n returnFocusOnDeactivate: true,\n escapeDeactivates: true,\n delayInitialFocus: true,\n ...userOptions,\n };\n\n var state = {\n firstTabbableNode: null,\n lastTabbableNode: null,\n nodeFocusedBeforeActivation: null,\n mostRecentlyFocusedNode: null,\n active: false,\n paused: false,\n };\n\n var trap = {\n activate: activate,\n deactivate: deactivate,\n pause: pause,\n unpause: unpause,\n };\n\n return trap;\n\n function activate(activateOptions) {\n if (state.active) return;\n\n updateTabbableNodes();\n\n state.active = true;\n state.paused = false;\n state.nodeFocusedBeforeActivation = doc.activeElement;\n\n var onActivate =\n activateOptions && activateOptions.onActivate\n ? activateOptions.onActivate\n : config.onActivate;\n if (onActivate) {\n onActivate();\n }\n\n addListeners();\n return trap;\n }\n\n function deactivate(deactivateOptions) {\n if (!state.active) return;\n\n clearTimeout(activeFocusDelay);\n\n removeListeners();\n state.active = false;\n state.paused = false;\n\n activeFocusTraps.deactivateTrap(trap);\n\n var onDeactivate =\n deactivateOptions && deactivateOptions.onDeactivate !== undefined\n ? deactivateOptions.onDeactivate\n : config.onDeactivate;\n if (onDeactivate) {\n onDeactivate();\n }\n\n var returnFocus =\n deactivateOptions && deactivateOptions.returnFocus !== undefined\n ? deactivateOptions.returnFocus\n : config.returnFocusOnDeactivate;\n if (returnFocus) {\n delay(function () {\n tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));\n });\n }\n\n return trap;\n }\n\n function pause() {\n if (state.paused || !state.active) return;\n state.paused = true;\n removeListeners();\n }\n\n function unpause() {\n if (!state.paused || !state.active) return;\n state.paused = false;\n updateTabbableNodes();\n addListeners();\n }\n\n function addListeners() {\n if (!state.active) return;\n\n // There can be only one listening focus trap at a time\n activeFocusTraps.activateTrap(trap);\n\n // Delay ensures that the focused element doesn't capture the event\n // that caused the focus trap activation.\n activeFocusDelay = config.delayInitialFocus\n ? delay(function () {\n tryFocus(getInitialFocusNode());\n })\n : tryFocus(getInitialFocusNode());\n\n doc.addEventListener('focusin', checkFocusIn, true);\n doc.addEventListener('mousedown', checkPointerDown, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('touchstart', checkPointerDown, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('click', checkClick, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('keydown', checkKey, {\n capture: true,\n passive: false,\n });\n\n return trap;\n }\n\n function removeListeners() {\n if (!state.active) return;\n\n doc.removeEventListener('focusin', checkFocusIn, true);\n doc.removeEventListener('mousedown', checkPointerDown, true);\n doc.removeEventListener('touchstart', checkPointerDown, true);\n doc.removeEventListener('click', checkClick, true);\n doc.removeEventListener('keydown', checkKey, true);\n\n return trap;\n }\n\n function getNodeForOption(optionName) {\n var optionValue = config[optionName];\n var node = optionValue;\n if (!optionValue) {\n return null;\n }\n if (typeof optionValue === 'string') {\n node = doc.querySelector(optionValue);\n if (!node) {\n throw new Error('`' + optionName + '` refers to no known node');\n }\n }\n if (typeof optionValue === 'function') {\n node = optionValue();\n if (!node) {\n throw new Error('`' + optionName + '` did not return a node');\n }\n }\n return node;\n }\n\n function getInitialFocusNode() {\n var node;\n if (getNodeForOption('initialFocus') !== null) {\n node = getNodeForOption('initialFocus');\n } else if (container.contains(doc.activeElement)) {\n node = doc.activeElement;\n } else {\n node = state.firstTabbableNode || getNodeForOption('fallbackFocus');\n }\n\n if (!node) {\n throw new Error(\n 'Your focus-trap needs to have at least one focusable element'\n );\n }\n\n return node;\n }\n\n function getReturnFocusNode(previousActiveElement) {\n var node = getNodeForOption('setReturnFocus');\n return node ? node : previousActiveElement;\n }\n\n // This needs to be done on mousedown and touchstart instead of click\n // so that it precedes the focus event.\n function checkPointerDown(e) {\n if (container.contains(e.target)) {\n // allow the click since it ocurred inside the trap\n return;\n }\n\n if (config.clickOutsideDeactivates) {\n // immediately deactivate the trap\n deactivate({\n // if, on deactivation, we should return focus to the node originally-focused\n // when the trap was activated (or the configured `setReturnFocus` node),\n // then assume it's also OK to return focus to the outside node that was\n // just clicked, causing deactivation, as long as that node is focusable;\n // if it isn't focusable, then return focus to the original node focused\n // on activation (or the configured `setReturnFocus` node)\n // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,\n // which will result in the outside click setting focus to the node\n // that was clicked, whether it's focusable or not; by setting\n // `returnFocus: true`, we'll attempt to re-focus the node originally-focused\n // on activation (or the configured `setReturnFocus` node)\n returnFocus: config.returnFocusOnDeactivate && !isFocusable(e.target),\n });\n return;\n }\n\n // This is needed for mobile devices.\n // (If we'll only let `click` events through,\n // then on mobile they will be blocked anyways if `touchstart` is blocked.)\n if (\n config.allowOutsideClick &&\n (typeof config.allowOutsideClick === 'boolean'\n ? config.allowOutsideClick\n : config.allowOutsideClick(e))\n ) {\n // allow the click outside the trap to take place\n return;\n }\n\n // otherwise, prevent the click\n e.preventDefault();\n }\n\n // In case focus escapes the trap for some strange reason, pull it back in.\n function checkFocusIn(e) {\n // In Firefox when you Tab out of an iframe the Document is briefly focused.\n if (container.contains(e.target) || e.target instanceof Document) {\n return;\n }\n e.stopImmediatePropagation();\n tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());\n }\n\n function checkKey(e) {\n if (config.escapeDeactivates !== false && isEscapeEvent(e)) {\n e.preventDefault();\n deactivate();\n return;\n }\n if (isTabEvent(e)) {\n checkTab(e);\n return;\n }\n }\n\n // Hijack Tab events on the first and last focusable nodes of the trap,\n // in order to prevent focus from escaping. If it escapes for even a\n // moment it can end up scrolling the page and causing confusion so we\n // kind of need to capture the action at the keydown phase.\n function checkTab(e) {\n updateTabbableNodes();\n if (e.shiftKey && e.target === state.firstTabbableNode) {\n e.preventDefault();\n tryFocus(state.lastTabbableNode);\n return;\n }\n if (!e.shiftKey && e.target === state.lastTabbableNode) {\n e.preventDefault();\n tryFocus(state.firstTabbableNode);\n return;\n }\n }\n\n function checkClick(e) {\n if (config.clickOutsideDeactivates) return;\n if (container.contains(e.target)) return;\n if (\n config.allowOutsideClick &&\n (typeof config.allowOutsideClick === 'boolean'\n ? config.allowOutsideClick\n : config.allowOutsideClick(e))\n ) {\n return;\n }\n e.preventDefault();\n e.stopImmediatePropagation();\n }\n\n function updateTabbableNodes() {\n var tabbableNodes = tabbable(container);\n state.firstTabbableNode = tabbableNodes[0] || getInitialFocusNode();\n state.lastTabbableNode =\n tabbableNodes[tabbableNodes.length - 1] || getInitialFocusNode();\n }\n\n function tryFocus(node) {\n if (node === doc.activeElement) return;\n if (!node || !node.focus) {\n tryFocus(getInitialFocusNode());\n return;\n }\n node.focus({ preventScroll: !!config.preventScroll });\n state.mostRecentlyFocusedNode = node;\n if (isSelectableInput(node)) {\n node.select();\n }\n }\n}\n\nfunction isSelectableInput(node) {\n return (\n node.tagName &&\n node.tagName.toLowerCase() === 'input' &&\n typeof node.select === 'function'\n );\n}\n\nfunction isEscapeEvent(e) {\n return e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27;\n}\n\nfunction isTabEvent(e) {\n return e.key === 'Tab' || e.keyCode === 9;\n}\n\nfunction delay(fn) {\n return setTimeout(fn, 0);\n}\n\nexport { createFocusTrap };\n"],"names":["candidateSelectors","candidateSelector","join","matches","Element","prototype","msMatchesSelector","webkitMatchesSelector","tabbable","el","options","regularTabbables","orderedTabbables","includeContainer","filter","candidates","Array","slice","apply","querySelectorAll","call","unshift","getCandidates","isNodeMatchingSelectorTabbable","forEach","candidate","i","candidateTabindex","getTabindex","push","documentOrder","tabIndex","node","sort","sortOrderedTabbables","map","a","concat","isNodeMatchingSelectorFocusable","isInput","type","isRadio","name","checked","nodes","form","length","getCheckedRadio","ownerDocument","isTabbableRadio","isNonTabbableRadio","disabled","isHiddenInput","getComputedStyle","visibility","display","parentElement","isHidden","focusableCandidateSelector","isFocusable","Error","tabindexAttr","parseInt","getAttribute","isNaN","contentEditable","isContentEditable","nodeName","b","tagName","activeFocusDelay","trapQueue","activeFocusTraps","activateTrap","trap","activeTrap","pause","trapIndex","indexOf","splice","deactivateTrap","unpause","delay","fn","setTimeout","element","userOptions","doc","document","container","querySelector","config","returnFocusOnDeactivate","escapeDeactivates","delayInitialFocus","state","firstTabbableNode","lastTabbableNode","nodeFocusedBeforeActivation","mostRecentlyFocusedNode","active","paused","activate","activateOptions","updateTabbableNodes","activeElement","onActivate","addListeners","deactivate","removeListeners","deactivateOptions","clearTimeout","onDeactivate","undefined","returnFocus","previousActiveElement","tryFocus","getNodeForOption","getInitialFocusNode","addEventListener","checkFocusIn","checkPointerDown","capture","passive","checkClick","checkKey","removeEventListener","optionName","optionValue","contains","e","target","clickOutsideDeactivates","allowOutsideClick","preventDefault","Document","stopImmediatePropagation","key","keyCode","isEscapeEvent","isTabEvent","shiftKey","checkTab","tabbableNodes","focus","preventScroll","toLowerCase","select","isSelectableInput"],"mappings":"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"}
1
+ {"version":3,"file":"focus-trap.min.js","sources":["../index.js"],"sourcesContent":["import { tabbable, isFocusable } from 'tabbable';\n\nvar activeFocusDelay;\n\nvar activeFocusTraps = (function () {\n var trapQueue = [];\n return {\n activateTrap: function (trap) {\n if (trapQueue.length > 0) {\n var activeTrap = trapQueue[trapQueue.length - 1];\n if (activeTrap !== trap) {\n activeTrap.pause();\n }\n }\n\n var trapIndex = trapQueue.indexOf(trap);\n if (trapIndex === -1) {\n trapQueue.push(trap);\n } else {\n // move this existing trap to the front of the queue\n trapQueue.splice(trapIndex, 1);\n trapQueue.push(trap);\n }\n },\n\n deactivateTrap: function (trap) {\n var trapIndex = trapQueue.indexOf(trap);\n if (trapIndex !== -1) {\n trapQueue.splice(trapIndex, 1);\n }\n\n if (trapQueue.length > 0) {\n trapQueue[trapQueue.length - 1].unpause();\n }\n },\n };\n})();\n\nfunction createFocusTrap(elements, userOptions) {\n var doc = document;\n\n var config = {\n returnFocusOnDeactivate: true,\n escapeDeactivates: true,\n delayInitialFocus: true,\n ...userOptions,\n };\n\n var state = {\n // @type {Array<HTMLElement>}\n containers: [],\n // @type {{ firstTabbableNode: HTMLElement, lastTabbableNode: HTMLElement }}\n tabbableGroups: [],\n nodeFocusedBeforeActivation: null,\n mostRecentlyFocusedNode: null,\n active: false,\n paused: false,\n };\n\n var trap = {\n activate: activate,\n deactivate: deactivate,\n pause: pause,\n unpause: unpause,\n updateContainerElements: updateContainerElements,\n };\n\n updateContainerElements(elements);\n\n return trap;\n\n function updateContainerElements(containerElements) {\n var elementsAsArray = [].concat(containerElements).filter(Boolean);\n\n state.containers = elementsAsArray.map((element) =>\n typeof element === 'string' ? doc.querySelector(element) : element\n );\n\n if (state.active) {\n updateTabbableNodes();\n }\n\n return trap;\n }\n\n function activate(activateOptions) {\n if (state.active) return;\n\n updateTabbableNodes();\n\n state.active = true;\n state.paused = false;\n state.nodeFocusedBeforeActivation = doc.activeElement;\n\n var onActivate =\n activateOptions && activateOptions.onActivate\n ? activateOptions.onActivate\n : config.onActivate;\n if (onActivate) {\n onActivate();\n }\n\n addListeners();\n return trap;\n }\n\n function deactivate(deactivateOptions) {\n if (!state.active) return;\n\n clearTimeout(activeFocusDelay);\n\n removeListeners();\n state.active = false;\n state.paused = false;\n\n activeFocusTraps.deactivateTrap(trap);\n\n var onDeactivate =\n deactivateOptions && deactivateOptions.onDeactivate !== undefined\n ? deactivateOptions.onDeactivate\n : config.onDeactivate;\n if (onDeactivate) {\n onDeactivate();\n }\n\n var returnFocus =\n deactivateOptions && deactivateOptions.returnFocus !== undefined\n ? deactivateOptions.returnFocus\n : config.returnFocusOnDeactivate;\n if (returnFocus) {\n delay(function () {\n tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));\n });\n }\n\n return trap;\n }\n\n function pause() {\n if (state.paused || !state.active) return trap;\n state.paused = true;\n removeListeners();\n\n return trap;\n }\n\n function unpause() {\n if (!state.paused || !state.active) return trap;\n state.paused = false;\n updateTabbableNodes();\n addListeners();\n\n return trap;\n }\n\n function addListeners() {\n if (!state.active) return;\n\n // There can be only one listening focus trap at a time\n activeFocusTraps.activateTrap(trap);\n\n // Delay ensures that the focused element doesn't capture the event\n // that caused the focus trap activation.\n activeFocusDelay = config.delayInitialFocus\n ? delay(function () {\n tryFocus(getInitialFocusNode());\n })\n : tryFocus(getInitialFocusNode());\n\n doc.addEventListener('focusin', checkFocusIn, true);\n doc.addEventListener('mousedown', checkPointerDown, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('touchstart', checkPointerDown, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('click', checkClick, {\n capture: true,\n passive: false,\n });\n doc.addEventListener('keydown', checkKey, {\n capture: true,\n passive: false,\n });\n\n return trap;\n }\n\n function removeListeners() {\n if (!state.active) return;\n\n doc.removeEventListener('focusin', checkFocusIn, true);\n doc.removeEventListener('mousedown', checkPointerDown, true);\n doc.removeEventListener('touchstart', checkPointerDown, true);\n doc.removeEventListener('click', checkClick, true);\n doc.removeEventListener('keydown', checkKey, true);\n\n return trap;\n }\n\n function getNodeForOption(optionName) {\n var optionValue = config[optionName];\n var node = optionValue;\n if (!optionValue) {\n return null;\n }\n if (typeof optionValue === 'string') {\n node = doc.querySelector(optionValue);\n if (!node) {\n throw new Error('`' + optionName + '` refers to no known node');\n }\n }\n if (typeof optionValue === 'function') {\n node = optionValue();\n if (!node) {\n throw new Error('`' + optionName + '` did not return a node');\n }\n }\n return node;\n }\n\n function getInitialFocusNode() {\n var node;\n if (getNodeForOption('initialFocus') !== null) {\n node = getNodeForOption('initialFocus');\n } else if (containersContain(doc.activeElement)) {\n node = doc.activeElement;\n } else {\n var firstTabbableGroup = state.tabbableGroups[0];\n var firstTabbableNode =\n firstTabbableGroup && firstTabbableGroup.firstTabbableNode;\n node = firstTabbableNode || getNodeForOption('fallbackFocus');\n }\n\n if (!node) {\n throw new Error(\n 'Your focus-trap needs to have at least one focusable element'\n );\n }\n\n return node;\n }\n\n function getReturnFocusNode(previousActiveElement) {\n var node = getNodeForOption('setReturnFocus');\n return node ? node : previousActiveElement;\n }\n\n // This needs to be done on mousedown and touchstart instead of click\n // so that it precedes the focus event.\n function checkPointerDown(e) {\n if (containersContain(e.target)) {\n // allow the click since it ocurred inside the trap\n return;\n }\n\n if (config.clickOutsideDeactivates) {\n // immediately deactivate the trap\n deactivate({\n // if, on deactivation, we should return focus to the node originally-focused\n // when the trap was activated (or the configured `setReturnFocus` node),\n // then assume it's also OK to return focus to the outside node that was\n // just clicked, causing deactivation, as long as that node is focusable;\n // if it isn't focusable, then return focus to the original node focused\n // on activation (or the configured `setReturnFocus` node)\n // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,\n // which will result in the outside click setting focus to the node\n // that was clicked, whether it's focusable or not; by setting\n // `returnFocus: true`, we'll attempt to re-focus the node originally-focused\n // on activation (or the configured `setReturnFocus` node)\n returnFocus: config.returnFocusOnDeactivate && !isFocusable(e.target),\n });\n return;\n }\n\n // This is needed for mobile devices.\n // (If we'll only let `click` events through,\n // then on mobile they will be blocked anyways if `touchstart` is blocked.)\n if (\n config.allowOutsideClick &&\n (typeof config.allowOutsideClick === 'boolean'\n ? config.allowOutsideClick\n : config.allowOutsideClick(e))\n ) {\n // allow the click outside the trap to take place\n return;\n }\n\n // otherwise, prevent the click\n e.preventDefault();\n }\n\n // In case focus escapes the trap for some strange reason, pull it back in.\n function checkFocusIn(e) {\n // In Firefox when you Tab out of an iframe the Document is briefly focused.\n if (containersContain(e.target) || e.target instanceof Document) {\n return;\n }\n e.stopImmediatePropagation();\n tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());\n }\n\n function checkKey(e) {\n if (config.escapeDeactivates !== false && isEscapeEvent(e)) {\n e.preventDefault();\n deactivate();\n return;\n }\n if (isTabEvent(e)) {\n checkTab(e);\n return;\n }\n }\n\n // Hijack Tab events on the first and last focusable nodes of the trap,\n // in order to prevent focus from escaping. If it escapes for even a\n // moment it can end up scrolling the page and causing confusion so we\n // kind of need to capture the action at the keydown phase.\n function checkTab(e) {\n updateTabbableNodes();\n\n let destinationNode = null;\n\n if (e.shiftKey) {\n const startOfGroupIndex = state.tabbableGroups.findIndex(\n ({ firstTabbableNode }) => e.target === firstTabbableNode\n );\n\n if (startOfGroupIndex >= 0) {\n const destinationGroupIndex =\n startOfGroupIndex === 0\n ? state.tabbableGroups.length - 1\n : startOfGroupIndex - 1;\n\n const destinationGroup = state.tabbableGroups[destinationGroupIndex];\n destinationNode = destinationGroup.lastTabbableNode;\n }\n } else {\n const lastOfGroupIndex = state.tabbableGroups.findIndex(\n ({ lastTabbableNode }) => e.target === lastTabbableNode\n );\n\n if (lastOfGroupIndex >= 0) {\n const destinationGroupIndex =\n lastOfGroupIndex === state.tabbableGroups.length - 1\n ? 0\n : lastOfGroupIndex + 1;\n\n const destinationGroup = state.tabbableGroups[destinationGroupIndex];\n destinationNode = destinationGroup.firstTabbableNode;\n }\n }\n\n if (destinationNode) {\n e.preventDefault();\n\n tryFocus(destinationNode);\n }\n }\n\n function checkClick(e) {\n if (config.clickOutsideDeactivates) return;\n if (containersContain(e.target)) return;\n if (\n config.allowOutsideClick &&\n (typeof config.allowOutsideClick === 'boolean'\n ? config.allowOutsideClick\n : config.allowOutsideClick(e))\n ) {\n return;\n }\n e.preventDefault();\n e.stopImmediatePropagation();\n }\n\n function updateTabbableNodes() {\n state.tabbableGroups = state.containers.map((container) => {\n var tabbableNodes = tabbable(container);\n\n return {\n firstTabbableNode: tabbableNodes[0],\n lastTabbableNode: tabbableNodes[tabbableNodes.length - 1],\n };\n });\n }\n\n function tryFocus(node) {\n if (node === doc.activeElement) return;\n if (!node || !node.focus) {\n tryFocus(getInitialFocusNode());\n return;\n }\n node.focus({ preventScroll: !!config.preventScroll });\n state.mostRecentlyFocusedNode = node;\n if (isSelectableInput(node)) {\n node.select();\n }\n }\n\n function containersContain(element) {\n return state.containers.some((container) => container.contains(element));\n }\n}\n\nfunction isSelectableInput(node) {\n return (\n node.tagName &&\n node.tagName.toLowerCase() === 'input' &&\n typeof node.select === 'function'\n );\n}\n\nfunction isEscapeEvent(e) {\n return e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27;\n}\n\nfunction isTabEvent(e) {\n return e.key === 'Tab' || e.keyCode === 9;\n}\n\nfunction delay(fn) {\n return setTimeout(fn, 0);\n}\n\nexport { createFocusTrap };\n"],"names":["activeFocusDelay","trapQueue","activeFocusTraps","activateTrap","trap","length","activeTrap","pause","trapIndex","indexOf","splice","push","deactivateTrap","unpause","delay","fn","setTimeout","elements","userOptions","doc","document","config","returnFocusOnDeactivate","escapeDeactivates","delayInitialFocus","state","containers","tabbableGroups","nodeFocusedBeforeActivation","mostRecentlyFocusedNode","active","paused","activate","activateOptions","updateTabbableNodes","activeElement","onActivate","addListeners","deactivate","removeListeners","updateContainerElements","containerElements","elementsAsArray","concat","filter","Boolean","map","element","querySelector","deactivateOptions","clearTimeout","onDeactivate","undefined","returnFocus","previousActiveElement","tryFocus","getNodeForOption","getInitialFocusNode","addEventListener","checkFocusIn","checkPointerDown","capture","passive","checkClick","checkKey","removeEventListener","optionName","optionValue","node","Error","containersContain","firstTabbableGroup","firstTabbableNode","e","target","clickOutsideDeactivates","isFocusable","allowOutsideClick","preventDefault","Document","stopImmediatePropagation","key","keyCode","isEscapeEvent","isTabEvent","destinationNode","shiftKey","startOfGroupIndex","findIndex","destinationGroupIndex","lastTabbableNode","lastOfGroupIndex","checkTab","container","tabbableNodes","tabbable","focus","preventScroll","tagName","toLowerCase","select","isSelectableInput","some","contains"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * focus-trap 6.1.1
2
+ * focus-trap 6.2.0
3
3
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
4
4
  */
5
5
  (function (global, factory) {
@@ -13,20 +13,71 @@
13
13
  }()));
14
14
  }(this, (function (exports, tabbable) { 'use strict';
15
15
 
16
+ function _defineProperty(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+
28
+ return obj;
29
+ }
30
+
31
+ function ownKeys(object, enumerableOnly) {
32
+ var keys = Object.keys(object);
33
+
34
+ if (Object.getOwnPropertySymbols) {
35
+ var symbols = Object.getOwnPropertySymbols(object);
36
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
37
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
38
+ });
39
+ keys.push.apply(keys, symbols);
40
+ }
41
+
42
+ return keys;
43
+ }
44
+
45
+ function _objectSpread2(target) {
46
+ for (var i = 1; i < arguments.length; i++) {
47
+ var source = arguments[i] != null ? arguments[i] : {};
48
+
49
+ if (i % 2) {
50
+ ownKeys(Object(source), true).forEach(function (key) {
51
+ _defineProperty(target, key, source[key]);
52
+ });
53
+ } else if (Object.getOwnPropertyDescriptors) {
54
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
55
+ } else {
56
+ ownKeys(Object(source)).forEach(function (key) {
57
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
58
+ });
59
+ }
60
+ }
61
+
62
+ return target;
63
+ }
64
+
16
65
  var activeFocusDelay;
17
66
 
18
- var activeFocusTraps = (function () {
67
+ var activeFocusTraps = function () {
19
68
  var trapQueue = [];
20
69
  return {
21
- activateTrap: function (trap) {
70
+ activateTrap: function activateTrap(trap) {
22
71
  if (trapQueue.length > 0) {
23
72
  var activeTrap = trapQueue[trapQueue.length - 1];
73
+
24
74
  if (activeTrap !== trap) {
25
75
  activeTrap.pause();
26
76
  }
27
77
  }
28
78
 
29
79
  var trapIndex = trapQueue.indexOf(trap);
80
+
30
81
  if (trapIndex === -1) {
31
82
  trapQueue.push(trap);
32
83
  } else {
@@ -35,9 +86,9 @@
35
86
  trapQueue.push(trap);
36
87
  }
37
88
  },
38
-
39
- deactivateTrap: function (trap) {
89
+ deactivateTrap: function deactivateTrap(trap) {
40
90
  var trapIndex = trapQueue.indexOf(trap);
91
+
41
92
  if (trapIndex !== -1) {
42
93
  trapQueue.splice(trapIndex, 1);
43
94
  }
@@ -45,53 +96,60 @@
45
96
  if (trapQueue.length > 0) {
46
97
  trapQueue[trapQueue.length - 1].unpause();
47
98
  }
48
- },
99
+ }
49
100
  };
50
- })();
101
+ }();
51
102
 
52
- function createFocusTrap(element, userOptions) {
103
+ function createFocusTrap(elements, userOptions) {
53
104
  var doc = document;
54
- var container =
55
- typeof element === 'string' ? doc.querySelector(element) : element;
56
105
 
57
- var config = {
106
+ var config = _objectSpread2({
58
107
  returnFocusOnDeactivate: true,
59
108
  escapeDeactivates: true,
60
- delayInitialFocus: true,
61
- ...userOptions,
62
- };
109
+ delayInitialFocus: true
110
+ }, userOptions);
63
111
 
64
112
  var state = {
65
- firstTabbableNode: null,
66
- lastTabbableNode: null,
113
+ // @type {Array<HTMLElement>}
114
+ containers: [],
115
+ // @type {{ firstTabbableNode: HTMLElement, lastTabbableNode: HTMLElement }}
116
+ tabbableGroups: [],
67
117
  nodeFocusedBeforeActivation: null,
68
118
  mostRecentlyFocusedNode: null,
69
119
  active: false,
70
- paused: false,
120
+ paused: false
71
121
  };
72
-
73
122
  var trap = {
74
123
  activate: activate,
75
124
  deactivate: deactivate,
76
125
  pause: pause,
77
126
  unpause: unpause,
127
+ updateContainerElements: updateContainerElements
78
128
  };
79
-
129
+ updateContainerElements(elements);
80
130
  return trap;
81
131
 
132
+ function updateContainerElements(containerElements) {
133
+ var elementsAsArray = [].concat(containerElements).filter(Boolean);
134
+ state.containers = elementsAsArray.map(function (element) {
135
+ return typeof element === 'string' ? doc.querySelector(element) : element;
136
+ });
137
+
138
+ if (state.active) {
139
+ updateTabbableNodes();
140
+ }
141
+
142
+ return trap;
143
+ }
144
+
82
145
  function activate(activateOptions) {
83
146
  if (state.active) return;
84
-
85
147
  updateTabbableNodes();
86
-
87
148
  state.active = true;
88
149
  state.paused = false;
89
150
  state.nodeFocusedBeforeActivation = doc.activeElement;
151
+ var onActivate = activateOptions && activateOptions.onActivate ? activateOptions.onActivate : config.onActivate;
90
152
 
91
- var onActivate =
92
- activateOptions && activateOptions.onActivate
93
- ? activateOptions.onActivate
94
- : config.onActivate;
95
153
  if (onActivate) {
96
154
  onActivate();
97
155
  }
@@ -102,27 +160,19 @@
102
160
 
103
161
  function deactivate(deactivateOptions) {
104
162
  if (!state.active) return;
105
-
106
163
  clearTimeout(activeFocusDelay);
107
-
108
164
  removeListeners();
109
165
  state.active = false;
110
166
  state.paused = false;
111
-
112
167
  activeFocusTraps.deactivateTrap(trap);
168
+ var onDeactivate = deactivateOptions && deactivateOptions.onDeactivate !== undefined ? deactivateOptions.onDeactivate : config.onDeactivate;
113
169
 
114
- var onDeactivate =
115
- deactivateOptions && deactivateOptions.onDeactivate !== undefined
116
- ? deactivateOptions.onDeactivate
117
- : config.onDeactivate;
118
170
  if (onDeactivate) {
119
171
  onDeactivate();
120
172
  }
121
173
 
122
- var returnFocus =
123
- deactivateOptions && deactivateOptions.returnFocus !== undefined
124
- ? deactivateOptions.returnFocus
125
- : config.returnFocusOnDeactivate;
174
+ var returnFocus = deactivateOptions && deactivateOptions.returnFocus !== undefined ? deactivateOptions.returnFocus : config.returnFocusOnDeactivate;
175
+
126
176
  if (returnFocus) {
127
177
  delay(function () {
128
178
  tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation));
@@ -133,100 +183,101 @@
133
183
  }
134
184
 
135
185
  function pause() {
136
- if (state.paused || !state.active) return;
186
+ if (state.paused || !state.active) return trap;
137
187
  state.paused = true;
138
188
  removeListeners();
189
+ return trap;
139
190
  }
140
191
 
141
192
  function unpause() {
142
- if (!state.paused || !state.active) return;
193
+ if (!state.paused || !state.active) return trap;
143
194
  state.paused = false;
144
195
  updateTabbableNodes();
145
196
  addListeners();
197
+ return trap;
146
198
  }
147
199
 
148
200
  function addListeners() {
149
- if (!state.active) return;
150
-
151
- // There can be only one listening focus trap at a time
152
- activeFocusTraps.activateTrap(trap);
201
+ if (!state.active) return; // There can be only one listening focus trap at a time
153
202
 
154
- // Delay ensures that the focused element doesn't capture the event
203
+ activeFocusTraps.activateTrap(trap); // Delay ensures that the focused element doesn't capture the event
155
204
  // that caused the focus trap activation.
156
- activeFocusDelay = config.delayInitialFocus
157
- ? delay(function () {
158
- tryFocus(getInitialFocusNode());
159
- })
160
- : tryFocus(getInitialFocusNode());
161
205
 
206
+ activeFocusDelay = config.delayInitialFocus ? delay(function () {
207
+ tryFocus(getInitialFocusNode());
208
+ }) : tryFocus(getInitialFocusNode());
162
209
  doc.addEventListener('focusin', checkFocusIn, true);
163
210
  doc.addEventListener('mousedown', checkPointerDown, {
164
211
  capture: true,
165
- passive: false,
212
+ passive: false
166
213
  });
167
214
  doc.addEventListener('touchstart', checkPointerDown, {
168
215
  capture: true,
169
- passive: false,
216
+ passive: false
170
217
  });
171
218
  doc.addEventListener('click', checkClick, {
172
219
  capture: true,
173
- passive: false,
220
+ passive: false
174
221
  });
175
222
  doc.addEventListener('keydown', checkKey, {
176
223
  capture: true,
177
- passive: false,
224
+ passive: false
178
225
  });
179
-
180
226
  return trap;
181
227
  }
182
228
 
183
229
  function removeListeners() {
184
230
  if (!state.active) return;
185
-
186
231
  doc.removeEventListener('focusin', checkFocusIn, true);
187
232
  doc.removeEventListener('mousedown', checkPointerDown, true);
188
233
  doc.removeEventListener('touchstart', checkPointerDown, true);
189
234
  doc.removeEventListener('click', checkClick, true);
190
235
  doc.removeEventListener('keydown', checkKey, true);
191
-
192
236
  return trap;
193
237
  }
194
238
 
195
239
  function getNodeForOption(optionName) {
196
240
  var optionValue = config[optionName];
197
241
  var node = optionValue;
242
+
198
243
  if (!optionValue) {
199
244
  return null;
200
245
  }
246
+
201
247
  if (typeof optionValue === 'string') {
202
248
  node = doc.querySelector(optionValue);
249
+
203
250
  if (!node) {
204
251
  throw new Error('`' + optionName + '` refers to no known node');
205
252
  }
206
253
  }
254
+
207
255
  if (typeof optionValue === 'function') {
208
256
  node = optionValue();
257
+
209
258
  if (!node) {
210
259
  throw new Error('`' + optionName + '` did not return a node');
211
260
  }
212
261
  }
262
+
213
263
  return node;
214
264
  }
215
265
 
216
266
  function getInitialFocusNode() {
217
267
  var node;
268
+
218
269
  if (getNodeForOption('initialFocus') !== null) {
219
270
  node = getNodeForOption('initialFocus');
220
- } else if (container.contains(doc.activeElement)) {
271
+ } else if (containersContain(doc.activeElement)) {
221
272
  node = doc.activeElement;
222
273
  } else {
223
- node = state.firstTabbableNode || getNodeForOption('fallbackFocus');
274
+ var firstTabbableGroup = state.tabbableGroups[0];
275
+ var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode;
276
+ node = firstTabbableNode || getNodeForOption('fallbackFocus');
224
277
  }
225
278
 
226
279
  if (!node) {
227
- throw new Error(
228
- 'Your focus-trap needs to have at least one focusable element'
229
- );
280
+ throw new Error('Your focus-trap needs to have at least one focusable element');
230
281
  }
231
282
 
232
283
  return node;
@@ -235,12 +286,12 @@
235
286
  function getReturnFocusNode(previousActiveElement) {
236
287
  var node = getNodeForOption('setReturnFocus');
237
288
  return node ? node : previousActiveElement;
238
- }
239
-
240
- // This needs to be done on mousedown and touchstart instead of click
289
+ } // This needs to be done on mousedown and touchstart instead of click
241
290
  // so that it precedes the focus event.
291
+
292
+
242
293
  function checkPointerDown(e) {
243
- if (container.contains(e.target)) {
294
+ if (containersContain(e.target)) {
244
295
  // allow the click since it ocurred inside the trap
245
296
  return;
246
297
  }
@@ -259,34 +310,30 @@
259
310
  // that was clicked, whether it's focusable or not; by setting
260
311
  // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
261
312
  // on activation (or the configured `setReturnFocus` node)
262
- returnFocus: config.returnFocusOnDeactivate && !tabbable.isFocusable(e.target),
313
+ returnFocus: config.returnFocusOnDeactivate && !tabbable.isFocusable(e.target)
263
314
  });
264
315
  return;
265
- }
266
-
267
- // This is needed for mobile devices.
316
+ } // This is needed for mobile devices.
268
317
  // (If we'll only let `click` events through,
269
318
  // then on mobile they will be blocked anyways if `touchstart` is blocked.)
270
- if (
271
- config.allowOutsideClick &&
272
- (typeof config.allowOutsideClick === 'boolean'
273
- ? config.allowOutsideClick
274
- : config.allowOutsideClick(e))
275
- ) {
319
+
320
+
321
+ if (config.allowOutsideClick && (typeof config.allowOutsideClick === 'boolean' ? config.allowOutsideClick : config.allowOutsideClick(e))) {
276
322
  // allow the click outside the trap to take place
277
323
  return;
278
- }
324
+ } // otherwise, prevent the click
325
+
279
326
 
280
- // otherwise, prevent the click
281
327
  e.preventDefault();
282
- }
328
+ } // In case focus escapes the trap for some strange reason, pull it back in.
329
+
283
330
 
284
- // In case focus escapes the trap for some strange reason, pull it back in.
285
331
  function checkFocusIn(e) {
286
332
  // In Firefox when you Tab out of an iframe the Document is briefly focused.
287
- if (container.contains(e.target) || e.target instanceof Document) {
333
+ if (containersContain(e.target) || e.target instanceof Document) {
288
334
  return;
289
335
  }
336
+
290
337
  e.stopImmediatePropagation();
291
338
  tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
292
339
  }
@@ -297,72 +344,101 @@
297
344
  deactivate();
298
345
  return;
299
346
  }
347
+
300
348
  if (isTabEvent(e)) {
301
349
  checkTab(e);
302
350
  return;
303
351
  }
304
- }
305
-
306
- // Hijack Tab events on the first and last focusable nodes of the trap,
352
+ } // Hijack Tab events on the first and last focusable nodes of the trap,
307
353
  // in order to prevent focus from escaping. If it escapes for even a
308
354
  // moment it can end up scrolling the page and causing confusion so we
309
355
  // kind of need to capture the action at the keydown phase.
356
+
357
+
310
358
  function checkTab(e) {
311
359
  updateTabbableNodes();
312
- if (e.shiftKey && e.target === state.firstTabbableNode) {
313
- e.preventDefault();
314
- tryFocus(state.lastTabbableNode);
315
- return;
360
+ var destinationNode = null;
361
+
362
+ if (e.shiftKey) {
363
+ var startOfGroupIndex = state.tabbableGroups.findIndex(function (_ref) {
364
+ var firstTabbableNode = _ref.firstTabbableNode;
365
+ return e.target === firstTabbableNode;
366
+ });
367
+
368
+ if (startOfGroupIndex >= 0) {
369
+ var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1;
370
+ var destinationGroup = state.tabbableGroups[destinationGroupIndex];
371
+ destinationNode = destinationGroup.lastTabbableNode;
372
+ }
373
+ } else {
374
+ var lastOfGroupIndex = state.tabbableGroups.findIndex(function (_ref2) {
375
+ var lastTabbableNode = _ref2.lastTabbableNode;
376
+ return e.target === lastTabbableNode;
377
+ });
378
+
379
+ if (lastOfGroupIndex >= 0) {
380
+ var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1;
381
+
382
+ var _destinationGroup = state.tabbableGroups[_destinationGroupIndex];
383
+ destinationNode = _destinationGroup.firstTabbableNode;
384
+ }
316
385
  }
317
- if (!e.shiftKey && e.target === state.lastTabbableNode) {
386
+
387
+ if (destinationNode) {
318
388
  e.preventDefault();
319
- tryFocus(state.firstTabbableNode);
320
- return;
389
+ tryFocus(destinationNode);
321
390
  }
322
391
  }
323
392
 
324
393
  function checkClick(e) {
325
394
  if (config.clickOutsideDeactivates) return;
326
- if (container.contains(e.target)) return;
327
- if (
328
- config.allowOutsideClick &&
329
- (typeof config.allowOutsideClick === 'boolean'
330
- ? config.allowOutsideClick
331
- : config.allowOutsideClick(e))
332
- ) {
395
+ if (containersContain(e.target)) return;
396
+
397
+ if (config.allowOutsideClick && (typeof config.allowOutsideClick === 'boolean' ? config.allowOutsideClick : config.allowOutsideClick(e))) {
333
398
  return;
334
399
  }
400
+
335
401
  e.preventDefault();
336
402
  e.stopImmediatePropagation();
337
403
  }
338
404
 
339
405
  function updateTabbableNodes() {
340
- var tabbableNodes = tabbable.tabbable(container);
341
- state.firstTabbableNode = tabbableNodes[0] || getInitialFocusNode();
342
- state.lastTabbableNode =
343
- tabbableNodes[tabbableNodes.length - 1] || getInitialFocusNode();
406
+ state.tabbableGroups = state.containers.map(function (container) {
407
+ var tabbableNodes = tabbable.tabbable(container);
408
+ return {
409
+ firstTabbableNode: tabbableNodes[0],
410
+ lastTabbableNode: tabbableNodes[tabbableNodes.length - 1]
411
+ };
412
+ });
344
413
  }
345
414
 
346
415
  function tryFocus(node) {
347
416
  if (node === doc.activeElement) return;
417
+
348
418
  if (!node || !node.focus) {
349
419
  tryFocus(getInitialFocusNode());
350
420
  return;
351
421
  }
352
- node.focus({ preventScroll: !!config.preventScroll });
422
+
423
+ node.focus({
424
+ preventScroll: !!config.preventScroll
425
+ });
353
426
  state.mostRecentlyFocusedNode = node;
427
+
354
428
  if (isSelectableInput(node)) {
355
429
  node.select();
356
430
  }
357
431
  }
432
+
433
+ function containersContain(element) {
434
+ return state.containers.some(function (container) {
435
+ return container.contains(element);
436
+ });
437
+ }
358
438
  }
359
439
 
360
440
  function isSelectableInput(node) {
361
- return (
362
- node.tagName &&
363
- node.tagName.toLowerCase() === 'input' &&
364
- typeof node.select === 'function'
365
- );
441
+ return node.tagName && node.tagName.toLowerCase() === 'input' && typeof node.select === 'function';
366
442
  }
367
443
 
368
444
  function isEscapeEvent(e) {