/** * Shadow-DOM-safe containment check. * * `Node.contains` does not pierce shadow-root boundaries: a node inside a * shadow tree will report `parent.contains(child) === false` even when the * shadow host is itself a descendant of `parent`. This helper first tries * the native method (fast path) and, if the child is inside a shadow root, * walks back up through shadow-host boundaries to check containment. */ export function contains( parent?: Element | null, child?: Element | null, ): boolean { if (!parent || !child) { return false; } // First, attempt with the faster native method. if (parent.contains(child)) { return true; } // Then fall back to traversing out of shadow roots when needed. const rootNode = child.getRootNode?.(); if (rootNode && rootNode instanceof ShadowRoot) { let next: Node | null = child; while (next) { if (parent === next) { return true; } next = next.parentNode ?? (next as ShadowRoot).host ?? null; } } return false; }