All files / src/utils dom.ts

71.87% Statements 23/32
71.42% Branches 15/21
53.84% Functions 7/13
74.19% Lines 23/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74    4x       4947x 4947x 4947x       4x                       4x 4827x 4827x 4827x 4827x 3771x 3771x     4827x 9351x       4x                 4x       60x 1129x   1129x 1129x         1041x         60x   60x            
type Selector = string | Element
 
export function findAll<T extends Element>(
    selector: Selector,
    filterType?: { new (): T }
): T[] {
    const elements = typeof selector === "string" ? Array.from(document.querySelectorAll(selector)) : [selector]
    return elements.filter((v): v is T =>
        filterType ? v instanceof filterType : true
    )
}
 
export async function DOMReady(): Promise<void> {
    return new Promise(resolve => {
        if (document.readyState !== "loading") {
            resolve()
        } else {
            window.addEventListener("DOMContentLoaded", () => {
                resolve()
            })
        }
    })
}
 
export function parents(target: Selector, selector?: string): Element[] {
    let parentList: Element[] = []
    findAll(target).forEach(element => {
        const parent = element.parentNode
        if (parent !== document && parent instanceof Element) {
            parentList.push(parent)
            parentList = parentList.concat(parents(parent))
        }
    })
    return parentList.filter(
        element => selector === undefined || matches(element, selector)
    )
}
 
export function matches(target: Selector, selector: string): boolean {
    const matchesFunc =
        Element.prototype.matches ||
        // @ts-expect-error proprietary method
        Element.prototype.msMatchesSelector ||
        Element.prototype.webkitMatchesSelector
    return findAll(target).some(element => matchesFunc.call(element, selector))
}
 
export function bindClickOutside(
    [element, input]: Array<HTMLElement>,
    callback: () => void
) {
    const onClick = (event: MouseEvent) => {
        const target = event.target
 
        if (target instanceof HTMLElement && element) {
            if (
                target !== element &&
                target !== input &&
                !parents(target).includes(element)
            ) {
                callback()
            }
        }
    }
 
    document.addEventListener("click", onClick)
 
    return {
        destroy: () => {
            document.removeEventListener("click", onClick)
        },
    }
}