UNPKG

25 kBSource Map (JSON)View Raw
1{"version":3,"file":"focus.js","sourceRoot":"../src/","sources":["focus.ts"],"names":[],"mappings":"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","sourcesContent":["import { elementContainsAttribute } from './dom/elementContainsAttribute';\nimport { elementContains } from './dom/elementContains';\nimport { getParent } from './dom/getParent';\nimport { getWindow } from './dom/getWindow';\nimport { getDocument } from './dom/getDocument';\n\nconst IS_FOCUSABLE_ATTRIBUTE = 'data-is-focusable';\nconst IS_VISIBLE_ATTRIBUTE = 'data-is-visible';\nconst FOCUSZONE_ID_ATTRIBUTE = 'data-focuszone-id';\nconst FOCUSZONE_SUB_ATTRIBUTE = 'data-is-sub-focuszone';\n\n/**\n * Gets the first focusable element.\n *\n * @public\n */\nexport function getFirstFocusable(\n rootElement: HTMLElement,\n currentElement: HTMLElement,\n includeElementsInFocusZones?: boolean,\n): HTMLElement | null {\n return getNextElement(\n rootElement,\n currentElement,\n true /*checkNode*/,\n false /*suppressParentTraversal*/,\n false /*suppressChildTraversal*/,\n includeElementsInFocusZones,\n );\n}\n\n/**\n * Gets the last focusable element.\n *\n * @public\n */\nexport function getLastFocusable(\n rootElement: HTMLElement,\n currentElement: HTMLElement,\n includeElementsInFocusZones?: boolean,\n): HTMLElement | null {\n return getPreviousElement(\n rootElement,\n currentElement,\n true /*checkNode*/,\n false /*suppressParentTraversal*/,\n true /*traverseChildren*/,\n includeElementsInFocusZones,\n );\n}\n\n/**\n * Gets the first tabbable element. (The difference between focusable and tabbable is that tabbable elements are\n * focusable elements that also have tabIndex != -1.)\n * @param rootElement - The parent element to search beneath.\n * @param currentElement - The descendant of rootElement to start the search at. This element is the first one checked,\n * and iteration continues forward. Typical use passes rootElement.firstChild.\n * @param includeElementsInFocusZones - true if traversal should go into FocusZone descendants.\n * @param checkNode - Include currentElement in search when true. Defaults to true.\n * @public\n */\nexport function getFirstTabbable(\n rootElement: HTMLElement,\n currentElement: HTMLElement,\n includeElementsInFocusZones?: boolean,\n checkNode: boolean = true,\n): HTMLElement | null {\n return getNextElement(\n rootElement,\n currentElement,\n checkNode,\n false /*suppressParentTraversal*/,\n false /*suppressChildTraversal*/,\n includeElementsInFocusZones,\n false /*allowFocusRoot*/,\n true /*tabbable*/,\n );\n}\n\n/**\n * Gets the last tabbable element. (The difference between focusable and tabbable is that tabbable elements are\n * focusable elements that also have tabIndex != -1.)\n * @param rootElement - The parent element to search beneath.\n * @param currentElement - The descendant of rootElement to start the search at. This element is the first one checked,\n * and iteration continues in reverse. Typical use passes rootElement.lastChild.\n * @param includeElementsInFocusZones - true if traversal should go into FocusZone descendants.\n * @param checkNode - Include currentElement in search when true. Defaults to true.\n * @public\n */\nexport function getLastTabbable(\n rootElement: HTMLElement,\n currentElement: HTMLElement,\n includeElementsInFocusZones?: boolean,\n checkNode: boolean = true,\n): HTMLElement | null {\n return getPreviousElement(\n rootElement,\n currentElement,\n checkNode,\n false /*suppressParentTraversal*/,\n true /*traverseChildren*/,\n includeElementsInFocusZones,\n false /*allowFocusRoot*/,\n true /*tabbable*/,\n );\n}\n\n/**\n * Attempts to focus the first focusable element that is a child or child's child of the rootElement.\n *\n * @public\n * @param rootElement - Element to start the search for a focusable child.\n * @returns True if focus was set, false if it was not.\n */\nexport function focusFirstChild(rootElement: HTMLElement): boolean {\n let element: HTMLElement | null = getNextElement(rootElement, rootElement, true, false, false, true);\n\n if (element) {\n focusAsync(element);\n return true;\n }\n return false;\n}\n\n/**\n * Traverse to find the previous element.\n * If tabbable is true, the element must have tabIndex != -1.\n *\n * @public\n */\nexport function getPreviousElement(\n rootElement: HTMLElement,\n currentElement: HTMLElement | null,\n checkNode?: boolean,\n suppressParentTraversal?: boolean,\n traverseChildren?: boolean,\n includeElementsInFocusZones?: boolean,\n allowFocusRoot?: boolean,\n tabbable?: boolean,\n): HTMLElement | null {\n if (!currentElement || (!allowFocusRoot && currentElement === rootElement)) {\n return null;\n }\n\n let isCurrentElementVisible = isElementVisible(currentElement);\n\n // Check its children.\n if (\n traverseChildren &&\n isCurrentElementVisible &&\n (includeElementsInFocusZones || !(isElementFocusZone(currentElement) || isElementFocusSubZone(currentElement)))\n ) {\n const childMatch = getPreviousElement(\n rootElement,\n currentElement.lastElementChild as HTMLElement,\n true,\n true,\n true,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n\n if (childMatch) {\n if ((tabbable && isElementTabbable(childMatch, true)) || !tabbable) {\n return childMatch;\n }\n\n const childMatchSiblingMatch = getPreviousElement(\n rootElement,\n childMatch.previousElementSibling as HTMLElement,\n true,\n true,\n true,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n if (childMatchSiblingMatch) {\n return childMatchSiblingMatch;\n }\n\n let childMatchParent = childMatch.parentElement;\n\n // At this point if we have not found any potential matches\n // start looking at the rest of the subtree under the currentParent.\n // NOTE: We do not want to recurse here because doing so could\n // cause elements to get skipped.\n while (childMatchParent && childMatchParent !== currentElement) {\n const childMatchParentMatch = getPreviousElement(\n rootElement,\n childMatchParent.previousElementSibling as HTMLElement,\n true,\n true,\n true,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n\n if (childMatchParentMatch) {\n return childMatchParentMatch;\n }\n\n childMatchParent = childMatchParent.parentElement;\n }\n }\n }\n\n // Check the current node, if it's not the first traversal.\n if (checkNode && isCurrentElementVisible && isElementTabbable(currentElement, tabbable)) {\n return currentElement;\n }\n\n // Check its previous sibling.\n const siblingMatch = getPreviousElement(\n rootElement,\n currentElement.previousElementSibling as HTMLElement,\n true,\n true,\n true,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n\n if (siblingMatch) {\n return siblingMatch;\n }\n\n // Check its parent.\n if (!suppressParentTraversal) {\n return getPreviousElement(\n rootElement,\n currentElement.parentElement,\n true,\n false,\n false,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n }\n\n return null;\n}\n\n/**\n * Traverse to find the next focusable element.\n * If tabbable is true, the element must have tabIndex != -1.\n *\n * @public\n * @param checkNode - Include currentElement in search when true.\n */\nexport function getNextElement(\n rootElement: HTMLElement,\n currentElement: HTMLElement | null,\n checkNode?: boolean,\n suppressParentTraversal?: boolean,\n suppressChildTraversal?: boolean,\n includeElementsInFocusZones?: boolean,\n allowFocusRoot?: boolean,\n tabbable?: boolean,\n): HTMLElement | null {\n if (!currentElement || (currentElement === rootElement && suppressChildTraversal && !allowFocusRoot)) {\n return null;\n }\n\n let isCurrentElementVisible = isElementVisible(currentElement);\n\n // Check the current node, if it's not the first traversal.\n if (checkNode && isCurrentElementVisible && isElementTabbable(currentElement, tabbable)) {\n return currentElement;\n }\n\n // Check its children.\n if (\n !suppressChildTraversal &&\n isCurrentElementVisible &&\n (includeElementsInFocusZones || !(isElementFocusZone(currentElement) || isElementFocusSubZone(currentElement)))\n ) {\n const childMatch = getNextElement(\n rootElement,\n currentElement.firstElementChild as HTMLElement,\n true,\n true,\n false,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n\n if (childMatch) {\n return childMatch;\n }\n }\n\n if (currentElement === rootElement) {\n return null;\n }\n\n // Check its sibling.\n const siblingMatch = getNextElement(\n rootElement,\n currentElement.nextElementSibling as HTMLElement,\n true,\n true,\n false,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n\n if (siblingMatch) {\n return siblingMatch;\n }\n\n if (!suppressParentTraversal) {\n return getNextElement(\n rootElement,\n currentElement.parentElement,\n false,\n false,\n true,\n includeElementsInFocusZones,\n allowFocusRoot,\n tabbable,\n );\n }\n\n return null;\n}\n\n/**\n * Determines if an element is visible.\n *\n * @public\n */\nexport function isElementVisible(element: HTMLElement | undefined | null): boolean {\n // If the element is not valid, return false.\n if (!element || !element.getAttribute) {\n return false;\n }\n\n const visibilityAttribute = element.getAttribute(IS_VISIBLE_ATTRIBUTE);\n\n // If the element is explicitly marked with the visibility attribute, return that value as boolean.\n if (visibilityAttribute !== null && visibilityAttribute !== undefined) {\n return visibilityAttribute === 'true';\n }\n\n // Fallback to other methods of determining actual visibility.\n return (\n element.offsetHeight !== 0 ||\n element.offsetParent !== null ||\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (element as any).isVisible === true\n ); // used as a workaround for testing.\n}\n\n/**\n * Determines if an element can receive focus programmatically or via a mouse click.\n * If checkTabIndex is true, additionally checks to ensure the element can be focused with the tab key,\n * meaning tabIndex != -1.\n *\n * @public\n */\nexport function isElementTabbable(element: HTMLElement, checkTabIndex?: boolean): boolean {\n // If this element is null or is disabled, it is not considered tabbable.\n if (!element || (element as HTMLButtonElement).disabled) {\n return false;\n }\n\n let tabIndex = 0;\n let tabIndexAttributeValue = null;\n\n if (element && element.getAttribute) {\n tabIndexAttributeValue = element.getAttribute('tabIndex');\n\n if (tabIndexAttributeValue) {\n tabIndex = parseInt(tabIndexAttributeValue, 10);\n }\n }\n\n let isFocusableAttribute = element.getAttribute ? element.getAttribute(IS_FOCUSABLE_ATTRIBUTE) : null;\n let isTabIndexSet = tabIndexAttributeValue !== null && tabIndex >= 0;\n\n const result =\n !!element &&\n isFocusableAttribute !== 'false' &&\n (element.tagName === 'A' ||\n element.tagName === 'BUTTON' ||\n element.tagName === 'INPUT' ||\n element.tagName === 'TEXTAREA' ||\n element.tagName === 'SELECT' ||\n isFocusableAttribute === 'true' ||\n isTabIndexSet);\n\n return checkTabIndex ? tabIndex !== -1 && result : result;\n}\n\n/**\n * Determines if a given element is a focus zone.\n *\n * @public\n */\nexport function isElementFocusZone(element?: HTMLElement): boolean {\n return !!(element && element.getAttribute && !!element.getAttribute(FOCUSZONE_ID_ATTRIBUTE));\n}\n\n/**\n * Determines if a given element is a focus sub zone.\n *\n * @public\n */\nexport function isElementFocusSubZone(element?: HTMLElement): boolean {\n return !!(element && element.getAttribute && element.getAttribute(FOCUSZONE_SUB_ATTRIBUTE) === 'true');\n}\n\n/**\n * Determines if an element, or any of its children, contain focus.\n *\n * @public\n */\nexport function doesElementContainFocus(element: HTMLElement): boolean {\n let document = getDocument(element);\n let currentActiveElement: HTMLElement | undefined = document && (document.activeElement as HTMLElement);\n if (currentActiveElement && elementContains(element, currentActiveElement)) {\n return true;\n }\n return false;\n}\n\n/**\n * Determines if an, or any of its ancestors, sepcificies that it doesn't want focus to wrap\n * @param element - element to start searching from\n * @param noWrapDataAttribute - the no wrap data attribute to match (either)\n * @returns true if focus should wrap, false otherwise\n */\nexport function shouldWrapFocus(\n element: HTMLElement,\n noWrapDataAttribute: 'data-no-vertical-wrap' | 'data-no-horizontal-wrap',\n): boolean {\n return elementContainsAttribute(element, noWrapDataAttribute) === 'true' ? false : true;\n}\n\nlet targetToFocusOnNextRepaint: HTMLElement | { focus: () => void } | null | undefined = undefined;\n\n/**\n * Sets focus to an element asynchronously. The focus will be set at the next browser repaint,\n * meaning it won't cause any extra recalculations. If more than one focusAsync is called during one frame,\n * only the latest called focusAsync element will actually be focused\n * @param element - The element to focus\n */\nexport function focusAsync(element: HTMLElement | { focus: () => void } | undefined | null): void {\n if (element) {\n // An element was already queued to be focused, so replace that one with the new element\n if (targetToFocusOnNextRepaint) {\n targetToFocusOnNextRepaint = element;\n return;\n }\n\n targetToFocusOnNextRepaint = element;\n\n const win = getWindow(element as Element);\n\n if (win) {\n // element.focus() is a no-op if the element is no longer in the DOM, meaning this is always safe\n win.requestAnimationFrame(() => {\n const focusableElement = targetToFocusOnNextRepaint as HTMLElement | null;\n\n // We are done focusing for this frame, so reset the queued focus element\n targetToFocusOnNextRepaint = undefined;\n\n if (focusableElement) {\n if (focusableElement.getAttribute && focusableElement.getAttribute(IS_FOCUSABLE_ATTRIBUTE) === 'true') {\n // Normally, a FocusZone would be responsible for setting the tabindex values on all its descendants.\n // However, even this animation frame callback can pre-empt the rendering of a FocusZone's child elements,\n // so it may be necessary to set the tabindex directly here.\n if (!focusableElement.getAttribute('tabindex')) {\n focusableElement.setAttribute('tabindex', '0');\n }\n }\n\n focusableElement.focus();\n }\n });\n }\n }\n}\n\n/**\n * Finds the closest focusable element via an index path from a parent. See\n * `getElementIndexPath` for getting an index path from an element to a child.\n */\nexport function getFocusableByIndexPath(parent: HTMLElement, path: number[]): HTMLElement | undefined {\n let element = parent;\n\n for (const index of path) {\n const nextChild = element.children[Math.min(index, element.children.length - 1)] as HTMLElement;\n\n if (!nextChild) {\n break;\n }\n element = nextChild;\n }\n\n element =\n isElementTabbable(element) && isElementVisible(element)\n ? element\n : getNextElement(parent, element, true) || getPreviousElement(parent, element)!;\n\n return element as HTMLElement;\n}\n\n/**\n * Finds the element index path from a parent element to a child element.\n *\n * If you had this node structure: \"A has children [B, C] and C has child D\",\n * the index path from A to D would be [1, 0], or `parent.chidren[1].children[0]`.\n */\nexport function getElementIndexPath(fromElement: HTMLElement, toElement: HTMLElement): number[] {\n const path: number[] = [];\n\n while (toElement && fromElement && toElement !== fromElement) {\n const parent = getParent(toElement, true);\n\n if (parent === null) {\n return [];\n }\n\n path.unshift(Array.prototype.indexOf.call(parent.children, toElement));\n toElement = parent;\n }\n\n return path;\n}\n"]}
\No newline at end of file