@zag-js/dom-query
Version:
The dom helper library for zag.js machines
100 lines (98 loc) • 4.04 kB
JavaScript
import "./chunk-QZ7TP4HQ.mjs";
// src/controller.ts
import { getRootNode } from "./node.mjs";
var INTERACTIVE_CONTAINER_ROLE = /* @__PURE__ */ new Set(["menu", "listbox", "dialog", "grid", "tree", "region", "application"]);
var isInteractiveContainerRole = (role) => INTERACTIVE_CONTAINER_ROLE.has(role);
var getAriaControls = (element) => element.getAttribute("aria-controls")?.split(" ") || [];
function isControlledElement(container, element) {
const visitedIds = /* @__PURE__ */ new Set();
const rootNode = getRootNode(container);
const checkElement = (searchRoot) => {
const controllingElements = searchRoot.querySelectorAll("[aria-controls]");
for (const controller of controllingElements) {
if (controller.getAttribute("aria-expanded") !== "true") continue;
const controlledIds = getAriaControls(controller);
for (const id of controlledIds) {
if (!id || visitedIds.has(id)) continue;
visitedIds.add(id);
const controlledElement = rootNode.getElementById(id);
if (controlledElement) {
const role = controlledElement.getAttribute("role");
const modal = controlledElement.getAttribute("aria-modal") === "true";
if (role && isInteractiveContainerRole(role) && !modal) {
if (controlledElement === element || controlledElement.contains(element)) {
return true;
}
if (checkElement(controlledElement)) {
return true;
}
}
}
}
}
return false;
};
return checkElement(container);
}
function findControlledElements(searchRoot, callback) {
const rootNode = getRootNode(searchRoot);
const visitedIds = /* @__PURE__ */ new Set();
const findRecursive = (root) => {
const controllingElements = root.querySelectorAll("[aria-controls]");
for (const controller of controllingElements) {
if (controller.getAttribute("aria-expanded") !== "true") continue;
const controlledIds = getAriaControls(controller);
for (const id of controlledIds) {
if (!id || visitedIds.has(id)) continue;
visitedIds.add(id);
const controlledElement = rootNode.getElementById(id);
if (controlledElement) {
const role = controlledElement.getAttribute("role");
const modal = controlledElement.getAttribute("aria-modal") === "true";
if (role && INTERACTIVE_CONTAINER_ROLE.has(role) && !modal) {
callback(controlledElement);
findRecursive(controlledElement);
}
}
}
}
};
findRecursive(searchRoot);
}
function getControlledElements(container) {
const controlledElements = /* @__PURE__ */ new Set();
findControlledElements(container, (controlledElement) => {
if (!container.contains(controlledElement)) {
controlledElements.add(controlledElement);
}
});
return Array.from(controlledElements);
}
function isInteractiveContainerElement(element) {
const role = element.getAttribute("role");
return Boolean(role && INTERACTIVE_CONTAINER_ROLE.has(role));
}
function isControllerElement(element) {
return element.hasAttribute("aria-controls") && element.getAttribute("aria-expanded") === "true";
}
function hasControllerElements(element) {
if (isControllerElement(element)) return true;
return Boolean(element.querySelector?.('[aria-controls][aria-expanded="true"]'));
}
function isControlledByExpandedController(element) {
if (!element.id) return false;
const rootNode = getRootNode(element);
const escapedId = CSS.escape(element.id);
const selector = `[aria-controls~="${escapedId}"][aria-expanded="true"], [aria-controls="${escapedId}"][aria-expanded="true"]`;
const controller = rootNode.querySelector(selector);
return Boolean(controller && isInteractiveContainerElement(element));
}
export {
findControlledElements,
getControlledElements,
hasControllerElements,
isControlledByExpandedController,
isControlledElement,
isControllerElement,
isInteractiveContainerElement
};