UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

141 lines 5.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hideNonTargetElements = hideNonTargetElements; /** * Modified version of `aria-hidden`-package. * - Removed "inert"-functionality. * - Removed flexibility for different data-attributes. * https://github.com/theKashey/aria-hidden/blob/720e8a8e1cfa047bd299a929d95d47ac860a5c1a/src/index.ts */ const owner_1 = require("./owner"); let ariaHiddenCounter = new WeakMap(); let markerCounter = new WeakMap(); let uncontrolledElementsSet = new WeakSet(); let lockCount = 0; const controlAttribute = "aria-hidden"; const markerName = "data-aksel-hidden"; /** * Unwraps a Shadow DOM host to find the actual Element in the light DOM. */ function unwrapHost(node) { return (node && (node.host || unwrapHost(node.parentNode))); } /** * Corrects the target elements by unwrapping Shadow DOM hosts if necessary. * * @param parent - The parent HTMLElement to check containment against. * @param targets - An array of target Elements to correct. * @returns An array of corrected Elements that are contained within the parent. */ function correctElements(parent, targets) { return targets .map((target) => { if (parent.contains(target)) { return target; } const correctedTarget = unwrapHost(target); if (parent.contains(correctedTarget)) { return correctedTarget; } return null; }) .filter((x) => x !== null); } /** * Applies the aria-hidden attribute to all elements in the body except the specified avoid elements. */ function applyAttributeToOthers(uncorrectedAvoidElements, body) { const avoidElements = correctElements(body, uncorrectedAvoidElements); const elementsToAvoidWithParents = new Set(); const elementsToAvoidUpdating = new Set(avoidElements); const hiddenElements = []; avoidElements.forEach(addToAvoidList); applyAttributes(body); elementsToAvoidWithParents.clear(); function addToAvoidList(el) { if (!el || elementsToAvoidWithParents.has(el)) { return; } elementsToAvoidWithParents.add(el); if (el.parentNode) { addToAvoidList(el.parentNode); } } function applyAttributes(parent) { if (!parent || elementsToAvoidUpdating.has(parent)) { return; } const parentChildren = parent.children; for (let index = 0; index < parentChildren.length; index += 1) { const node = parentChildren[index]; if (elementsToAvoidWithParents.has(node)) { applyAttributes(node); } else { const attr = node.getAttribute(controlAttribute); /* * We only check for falsy values here since since arbitrary values * (e.g. "true", "foo", "") are all valid for indicating that the element is already hidden. */ const alreadyHidden = attr !== null && attr !== "false"; const counterValue = (ariaHiddenCounter.get(node) || 0) + 1; const markerValue = (markerCounter.get(node) || 0) + 1; ariaHiddenCounter.set(node, counterValue); markerCounter.set(node, markerValue); hiddenElements.push(node); if (counterValue === 1 && alreadyHidden) { uncontrolledElementsSet.add(node); } if (markerValue === 1) { node.setAttribute(markerName, ""); } if (!alreadyHidden) { node.setAttribute(controlAttribute, "true"); } } } } lockCount += 1; /* Cleanup */ return () => { for (const element of hiddenElements) { const currentCounterValue = ariaHiddenCounter.get(element) || 0; const counterValue = currentCounterValue - 1; const markerValue = (markerCounter.get(element) || 0) - 1; ariaHiddenCounter.set(element, counterValue); markerCounter.set(element, markerValue); if (!counterValue) { if (!uncontrolledElementsSet.has(element)) { element.removeAttribute(controlAttribute); } uncontrolledElementsSet.delete(element); } if (!markerValue) { element.removeAttribute(markerName); } } lockCount -= 1; /* Reset */ if (!lockCount) { ariaHiddenCounter = new WeakMap(); uncontrolledElementsSet = new WeakSet(); markerCounter = new WeakMap(); } }; } /** * Hides all elements in the document body for assertive technologies except the specified elements with `aria-hidden`. * @param avoidElements - An array of elements to avoid hiding. * @returns A function that, when called, will undo the hiding of elements. */ function hideNonTargetElements(avoidElements) { const body = (0, owner_1.ownerDocument)(avoidElements[0]).body; /** * Assume that elements with `aria-live` or `script` tags should not be hidden. * This ensures that live regions and scripts continue to function properly. */ const ingoredElements = Array.from(body.querySelectorAll("[aria-live], script")); return applyAttributeToOthers(avoidElements.concat(ingoredElements), body); } //# sourceMappingURL=hideNonTargetElements.js.map