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 75 76 77    5x         4949x     4949x 4949x       5x                       5x 4827x 4827x 4827x 4827x 3771x 3771x     4827x 9351x       5x                 5x       61x 1130x   1130x 1130x         1041x         61x   61x            
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)
    },
  }
}