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.
- package/CHANGELOG.md +26 -0
- package/README.md +28 -12
- package/dist/focus-trap.esm.js +182 -106
- package/dist/focus-trap.esm.js.map +1 -1
- package/dist/focus-trap.esm.min.js +2 -7
- package/dist/focus-trap.esm.min.js.map +1 -1
- package/dist/focus-trap.js +182 -106
- package/dist/focus-trap.js.map +1 -1
- package/dist/focus-trap.min.js +2 -7
- package/dist/focus-trap.min.js.map +1 -1
- package/dist/focus-trap.umd.js +182 -106
- package/dist/focus-trap.umd.js.map +1 -1
- package/dist/focus-trap.umd.min.js +2 -7
- package/dist/focus-trap.umd.min.js.map +1 -1
- package/index.d.ts +6 -5
- package/index.js +83 -23
- package/package.json +23 -22
|
@@ -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":";;;;wEAEIA,8WAEJ,IACMC,EADFC,GACED,EAAY,GACT,CACLE,aAAc,SAAUC,MAClBH,EAAUI,OAAS,EAAG,KACpBC,EAAaL,EAAUA,EAAUI,OAAS,GAC1CC,IAAeF,GACjBE,EAAWC,YAIXC,EAAYP,EAAUQ,QAAQL,IACf,IAAfI,GAIFP,EAAUS,OAAOF,EAAW,GAH5BP,EAAUU,KAAKP,IAQnBQ,eAAgB,SAAUR,OACpBI,EAAYP,EAAUQ,QAAQL,IACf,IAAfI,GACFP,EAAUS,OAAOF,EAAW,GAG1BP,EAAUI,OAAS,GACrBJ,EAAUA,EAAUI,OAAS,GAAGQ,aAsYxC,SAASC,EAAMC,UACNC,WAAWD,EAAI,2BAjYxB,SAAyBE,EAAUC,OAC7BC,EAAMC,SAENC,mWACFC,yBAAyB,EACzBC,mBAAmB,EACnBC,mBAAmB,GAChBN,GAGDO,EAAQ,CAEVC,WAAY,GAEZC,eAAgB,GAChBC,4BAA6B,KAC7BC,wBAAyB,KACzBC,QAAQ,EACRC,QAAQ,GAGN3B,EAAO,CACT4B,kBAyBgBC,MACZR,EAAMK,OAAQ,OAElBI,IAEAT,EAAMK,QAAS,EACfL,EAAMM,QAAS,EACfN,EAAMG,4BAA8BT,EAAIgB,kBAEpCC,EACFH,GAAmBA,EAAgBG,WAC/BH,EAAgBG,WAChBf,EAAOe,WACTA,GACFA,WAGFC,IACOjC,GA1CPkC,WAAYA,EACZ/B,wBA6EIkB,EAAMM,SAAWN,EAAMK,SAC3BL,EAAMM,QAAS,EACfQ,KAF0CnC,GA5E1CS,0BAoFKY,EAAMM,QAAWN,EAAMK,QAC5BL,EAAMM,QAAS,EACfG,IACAG,IAEOjC,GALoCA,GAnF3CoC,wBAAyBA,UAG3BA,EAAwBvB,GAEjBb,WAEEoC,EAAwBC,OAC3BC,EAAkB,GAAGC,OAAOF,GAAmBG,OAAOC,gBAE1DpB,EAAMC,WAAagB,EAAgBI,KAAI,SAACC,SACnB,iBAAZA,EAAuB5B,EAAI6B,cAAcD,GAAWA,KAGzDtB,EAAMK,QACRI,IAGK9B,WAwBAkC,EAAWW,MACbxB,EAAMK,QAEXoB,aAAalD,GAEbuC,IACAd,EAAMK,QAAS,EACfL,EAAMM,QAAS,EAEf7B,EAAiBU,eAAeR,OAE5B+C,EACFF,QAAwDG,IAAnCH,EAAkBE,aACnCF,EAAkBE,aAClB9B,EAAO8B,oBACTA,GACFA,KAIAF,QAAuDG,IAAlCH,EAAkBI,YACnCJ,EAAkBI,YAClBhC,EAAOC,0BAEXR,GAAM,eAmHkBwC,EAlHtBC,GAkHsBD,EAlHM7B,EAAMG,4BAmH3B4B,EAAiB,mBACPF,OAhHdlD,YAoBAiC,OACFZ,EAAMK,cAGX5B,EAAiBC,aAAaC,GAI9BJ,EAAmBqB,EAAOG,kBACtBV,GAAM,WACJyC,EAASE,QAEXF,EAASE,KAEbtC,EAAIuC,iBAAiB,UAAWC,GAAc,GAC9CxC,EAAIuC,iBAAiB,YAAaE,EAAkB,CAClDC,SAAS,EACTC,SAAS,IAEX3C,EAAIuC,iBAAiB,aAAcE,EAAkB,CACnDC,SAAS,EACTC,SAAS,IAEX3C,EAAIuC,iBAAiB,QAASK,EAAY,CACxCF,SAAS,EACTC,SAAS,IAEX3C,EAAIuC,iBAAiB,UAAWM,EAAU,CACxCH,SAAS,EACTC,SAAS,IAGJ1D,WAGAmC,OACFd,EAAMK,cAEXX,EAAI8C,oBAAoB,UAAWN,GAAc,GACjDxC,EAAI8C,oBAAoB,YAAaL,GAAkB,GACvDzC,EAAI8C,oBAAoB,aAAcL,GAAkB,GACxDzC,EAAI8C,oBAAoB,QAASF,GAAY,GAC7C5C,EAAI8C,oBAAoB,UAAWD,GAAU,GAEtC5D,WAGAoD,EAAiBU,OACpBC,EAAc9C,EAAO6C,GACrBE,EAAOD,MACNA,SACI,QAEkB,iBAAhBA,KACTC,EAAOjD,EAAI6B,cAAcmB,UAEjB,IAAIE,MAAM,IAAMH,EAAa,gCAGZ,mBAAhBC,KACTC,EAAOD,WAEC,IAAIE,MAAM,IAAMH,EAAa,kCAGhCE,WAGAX,QACHW,KACqC,OAArCZ,EAAiB,gBACnBY,EAAOZ,EAAiB,qBACnB,GAAIc,EAAkBnD,EAAIgB,eAC/BiC,EAAOjD,EAAIgB,kBACN,KACDoC,EAAqB9C,EAAME,eAAe,GAG9CyC,EADEG,GAAsBA,EAAmBC,mBACfhB,EAAiB,qBAG1CY,QACG,IAAIC,MACR,uEAIGD,WAUAR,EAAiBa,GACpBH,EAAkBG,EAAEC,UAKpBrD,EAAOsD,wBAETrC,EAAW,CAYTe,YAAahC,EAAOC,0BAA4BsD,cAAYH,EAAEC,UAShErD,EAAOwD,oBAC8B,kBAA7BxD,EAAOwD,kBACXxD,EAAOwD,kBACPxD,EAAOwD,kBAAkBJ,KAO/BA,EAAEK,2BAIKnB,EAAac,GAEhBH,EAAkBG,EAAEC,SAAWD,EAAEC,kBAAkBK,WAGvDN,EAAEO,2BACFzB,EAAS9B,EAAMI,yBAA2B4B,eAGnCO,EAASS,OACiB,IAA7BpD,EAAOE,mBA6Gf,SAAuBkD,SACJ,WAAVA,EAAEQ,KAA8B,QAAVR,EAAEQ,KAA+B,KAAdR,EAAES,QA9GNC,CAAcV,UACtDA,EAAEK,sBACFxC,KA+GN,SAAoBmC,SACD,QAAVA,EAAEQ,KAA+B,IAAdR,EAAES,SA7GtBE,CAAWX,aAUCA,GAChBvC,QAEImD,EAAkB,QAElBZ,EAAEa,SAAU,KACRC,EAAoB9D,EAAME,eAAe6D,WAC7C,gBAAGhB,IAAAA,yBAAwBC,EAAEC,SAAWF,QAGtCe,GAAqB,EAAG,KACpBE,EACkB,IAAtBF,EACI9D,EAAME,eAAetB,OAAS,EAC9BkF,EAAoB,EAG1BF,EADyB5D,EAAME,eAAe8D,GACXC,sBAEhC,KACCC,EAAmBlE,EAAME,eAAe6D,WAC5C,gBAAGE,IAAAA,wBAAuBjB,EAAEC,SAAWgB,QAGrCC,GAAoB,EAAG,KACnBF,EACJE,IAAqBlE,EAAME,eAAetB,OAAS,EAC/C,EACAsF,EAAmB,EAGzBN,EADyB5D,EAAME,eAAe8D,GACXjB,mBAInCa,IACFZ,EAAEK,iBAEFvB,EAAS8B,IA/CTO,CAASnB,YAmDJV,EAAWU,GACdpD,EAAOsD,yBACPL,EAAkBG,EAAEC,SAEtBrD,EAAOwD,oBAC8B,kBAA7BxD,EAAOwD,kBACXxD,EAAOwD,kBACPxD,EAAOwD,kBAAkBJ,MAI/BA,EAAEK,iBACFL,EAAEO,qCAGK9C,IACPT,EAAME,eAAiBF,EAAMC,WAAWoB,KAAI,SAAC+C,OACvCC,EAAgBC,WAASF,SAEtB,CACLrB,kBAAmBsB,EAAc,GACjCJ,iBAAkBI,EAAcA,EAAczF,OAAS,gBAKpDkD,EAASa,GACZA,IAASjD,EAAIgB,gBACZiC,GAASA,EAAK4B,OAInB5B,EAAK4B,MAAM,CAAEC,gBAAiB5E,EAAO4E,gBACrCxE,EAAMI,wBAA0BuC,EAWpC,SAA2BA,UAEvBA,EAAK8B,SAC0B,UAA/B9B,EAAK8B,QAAQC,eACU,mBAAhB/B,EAAKgC,OAdRC,CAAkBjC,IACpBA,EAAKgC,UANL7C,EAASE,eAUJa,EAAkBvB,UAClBtB,EAAMC,WAAW4E,MAAK,SAACT,UAAcA,EAAUU,SAASxD"}
|
package/dist/focus-trap.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* focus-trap 6.
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
62
|
-
};
|
|
109
|
+
delayInitialFocus: true
|
|
110
|
+
}, userOptions);
|
|
63
111
|
|
|
64
112
|
var state = {
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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 (
|
|
271
|
+
} else if (containersContain(doc.activeElement)) {
|
|
221
272
|
node = doc.activeElement;
|
|
222
273
|
} else {
|
|
223
|
-
|
|
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 (
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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 (
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
386
|
+
|
|
387
|
+
if (destinationNode) {
|
|
318
388
|
e.preventDefault();
|
|
319
|
-
tryFocus(
|
|
320
|
-
return;
|
|
389
|
+
tryFocus(destinationNode);
|
|
321
390
|
}
|
|
322
391
|
}
|
|
323
392
|
|
|
324
393
|
function checkClick(e) {
|
|
325
394
|
if (config.clickOutsideDeactivates) return;
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
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) {
|