{"mappings":"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","sources":["src/useFocusTrap.js","src/util.js"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport { getTabIndexOfNode, sortByTabIndex } from \"./util.js\";\n\nconst focusableElementsSelector =\n  \"a[href], area[href], input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]\";\nconst TAB_KEY = 9;\n\nexport function useFocusTrap() {\n  const trapRef = useRef(null);\n\n  const selectNextFocusableElem = useCallback(\n    (\n      sortedFocusableElems,\n      currentIndex,\n      shiftKeyPressed = false,\n      skipCount = 0\n    ) => {\n      if (skipCount > sortedFocusableElems.length) {\n        // this means that it ran through all of elements but non was properly focusable\n        // hence we stop it to avoid running in an infinite loop\n        return false;\n      }\n\n      const backwards = !!shiftKeyPressed;\n      const maxIndex = sortedFocusableElems.length - 1;\n\n      if (!currentIndex) {\n        currentIndex =\n          sortedFocusableElems.indexOf(document.activeElement) ?? 0;\n      }\n\n      let nextIndex = backwards ? currentIndex - 1 : currentIndex + 1;\n      if (nextIndex > maxIndex) {\n        nextIndex = 0;\n      }\n\n      if (nextIndex < 0) {\n        nextIndex = maxIndex;\n      }\n\n      const newFocusElem = sortedFocusableElems[nextIndex];\n\n      newFocusElem.focus();\n\n      if (document.activeElement !== newFocusElem) {\n        // run another round\n        selectNextFocusableElem(\n          sortedFocusableElems,\n          nextIndex,\n          shiftKeyPressed,\n          skipCount + 1\n        );\n      }\n    }\n  );\n\n  // defining the trap function first\n  const trapper = useCallback((evt) => {\n    const trapRefElem = trapRef.current;\n    if (trapRefElem !== null) {\n      if (evt.which === TAB_KEY || evt.key === \"Tab\") {\n        evt.preventDefault();\n        const shiftKeyPressed = !!evt.shiftKey;\n        let focusableElems = Array.from(\n          trapRefElem.querySelectorAll(focusableElementsSelector)\n        ).filter(\n          (focusableElement) => getTabIndexOfNode(focusableElement) >= 0\n        ); // caching this is NOT a good idea in dynamic applications - so don't!\n        // now we need to sort it by tabIndex, highest first\n        focusableElems = focusableElems.sort(sortByTabIndex);\n\n        selectNextFocusableElem(focusableElems, undefined, shiftKeyPressed);\n      }\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  useEffect(() => {\n    window.addEventListener(\"keydown\", trapper);\n\n    return () => {\n      window.removeEventListener(\"keydown\", trapper);\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return [trapRef];\n}\n","export function convertToIntOrFallback(stringToConvert) {\n  const parsed = parseInt(stringToConvert);\n  return parsed ? parsed : 0;\n}\n\nexport function sortByTabIndex(firstNode, secondNode) {\n  const tabIndexes = [firstNode, secondNode].map((node) =>\n    getTabIndexOfNode(node)\n  );\n  return tabIndexes\n    .map((tabIndexValue) =>\n      sanitizeTabIndexInput(tabIndexValue, Math.max(...tabIndexes))\n    )\n    .reduce((previousValue, currentValue) => previousValue - currentValue);\n}\n\n/**\n * Prepares a tab-index to be further processed for the tab order of the focus trap.\n * It can't be less than 0, because negative values can not be part of the tab order at all.\n * In case it's exactly 0 it actually needs to be higher than any positive (> 0) value, since tab-index=0 means \"follow the system default order\".\n * The default tab order comes _after_ special tab indexes (>0).\n * @param {number} tabIndex The index to sanitize\n * @param {number} highestPositiveTabIndex The largest number among the tab indexes from the same context\n * @throws An error if the tabIndex is less than 0\n * @returns Tha sanitized tab index\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex} for further information on the tabindex and its order\n */\nfunction sanitizeTabIndexInput(tabIndex, highestPositiveTabIndex) {\n  if (tabIndex < 0) {\n    throw new Error(\n      `Unable to sort given input. A negative value is not part of the tab order: ${tabIndex}`\n    );\n  }\n  // 0 based tab indexes have a higher order than positive valued indicies, thus we add 1 to the max value\n  return tabIndex === 0 ? highestPositiveTabIndex + 1 : tabIndex;\n}\n\nexport function getTabIndexOfNode(targetNode) {\n  return convertToIntOrFallback(targetNode.getAttribute(\"tabindex\"));\n}\n"],"names":[],"version":3,"file":"useFocusTrap.js.map"}