UNPKG

@dvcol/common-utils

Version:

Typescript library for common utility functions and constants

62 lines (49 loc) 3.96 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// lib/common/utils/element.utils.ts var focusableElementSelectors = Object.freeze([ "button:not([disabled])", "[href]", // Ensures only real links are focusable "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", "[tabindex]" // Includes manually focusable elements ]); var tabFocusableElementSelectors = Object.freeze([ 'button:not([disabled], [tabindex="-1"])', '[href]:not([tabindex="-1"])', 'input:not([disabled], [tabindex="-1"])', 'select:not([disabled], [tabindex="-1"])', 'textarea:not([disabled], [tabindex="-1"])', '[tabindex]:not([tabindex="-1"])' ]); var getFocusableElement = (element, targets = tabFocusableElementSelectors) => _optionalChain([element, 'optionalAccess', _ => _.querySelector, 'call', _2 => _2(targets.join(","))]); var getFocusableElements = (element, targets = tabFocusableElementSelectors) => { const elements = _optionalChain([element, 'optionalAccess', _3 => _3.querySelectorAll, 'call', _4 => _4(targets.join(","))]); if (!elements) return; return Array.from(elements).sort((a, b) => (a.tabIndex || 0) - (b.tabIndex || 0)); }; var getLastFocusableElement = (element, targets = tabFocusableElementSelectors) => { const elements = getFocusableElements(element, targets); if (!elements || !elements.length) return; return elements[elements.length - 1]; }; var clickableTags = /* @__PURE__ */ new Set(["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA", "LABEL", "SUMMARY", "OPTION", "DETAILS", "VIDEO", "AUDIO"]); var isClickable = (element) => { if (element.hasAttribute("disabled") && ["", "true", null].includes(element.getAttribute("disabled"))) return false; if (element.hasAttribute("readonly") && ["", "true", null].includes(element.getAttribute("readonly"))) return false; if (element.tabIndex < 0) return false; if (element.hasAttribute("role") && ["button", "link"].includes(_optionalChain([element, 'access', _5 => _5.getAttribute, 'call', _6 => _6("role"), 'optionalAccess', _7 => _7.toLowerCase, 'call', _8 => _8()]))) return true; return clickableTags.has(element.tagName) || element.hasAttribute("onclick") || element.hasAttribute("onkeydown") || element.isContentEditable || element.tabIndex >= 0; }; var getClickableAncestor = (element, boundary, selector = isClickable) => { if (!element) return; if (typeof boundary === "function" && boundary() === element) return; if (boundary === element) return; if (selector(element)) return element; if (!element.parentElement) return; return getClickableAncestor(element.parentElement, boundary, selector); }; var clickableSelector = "a, button, input, textarea, select, details, summary, [role='button'], [role='link'], [onclick], audio, video, [tabindex]:not([tabindex='-1'])"; var closestClickableElement = (element) => element.closest(clickableSelector); exports.focusableElementSelectors = focusableElementSelectors; exports.tabFocusableElementSelectors = tabFocusableElementSelectors; exports.getFocusableElement = getFocusableElement; exports.getFocusableElements = getFocusableElements; exports.getLastFocusableElement = getLastFocusableElement; exports.clickableTags = clickableTags; exports.isClickable = isClickable; exports.getClickableAncestor = getClickableAncestor; exports.clickableSelector = clickableSelector; exports.closestClickableElement = closestClickableElement;