All files / utils dynamic-select-dom.js

100% Statements 83/83
57.14% Branches 8/14
100% Functions 5/5
100% Lines 83/83

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 78 79 80 81 82 83 841x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 1x 1x 1x 1x 1x 1x 40x 40x 177x 177x 177x 177x 40x 1x 1x 1x 1x 1x 1x 5x 5x 17x 17x 17x 17x 5x 1x 1x 1x 1x 1x 15x 15x 15x 15x 15x 15x 8x 8x 15x 1x 1x 1x 1x 1x 1x 21x 21x  
/** @import {ParseSelector} from "typed-query-selector/parser.d.ts" */
 
/** @typedef {import('../web-component/dynamic-select.element.js').DynamicSelect} DynamicSelect */
 
export const containerEl = shadowQuery('div.container')
export const searchInputEl = shadowQuery('input.search-input')
export const inputEl = shadowQuery('span.input')
export const dropdownEl = shadowQuery('dialog.dropdown')
export const valueListEl = shadowQuery('dialog.dropdown > ul.value-list')
export const okButtonEl = shadowQuery('dialog.dropdown > .buttons > .ok')
export const cancelButtonEl = shadowQuery('dialog.dropdown > .buttons > .cancel')
export const getDynamicOptions = shadowQuery('div.dynamic-options:not(.option *)')
 
export const dropdownOptionList = shadowQueryAll('li.option-value:not(.option *)')
 
export const isSearchInputEl = elementMatcher('input.search-input')
export const isDeselectButton = elementMatcher('.multiselect-option[data-value] > button.deselect-option')
export const isClearButton = elementMatcher('a.clear-button:not(.option *)')
 
export const isDynamicSelectSymbol = Symbol('its-a-dynamic-select')
 
/**
 * Gets hots DynamicSelect element from a shadow DOM element
 *
 * @param {EventTarget | null} target - target element in shadow DOM
 * @returns {DynamicSelect} host element
 */
export function getHostDynamicSelect (target) {
  if (!(target instanceof Element)) { throw Error('target is not an element') }
  const rootNode = target.getRootNode()
  if (!(rootNode instanceof ShadowRoot)) { throw Error('target is not inside a shadow dom') }
  const host = rootNode.host
  if (!isDynamicSelect(host)) { throw Error('target is not inside a Dynamic Select shadow dom') }
  return host
}
 
/**
 * @template {string} T
 * @param {T} selector - css selector
 * @returns {(dynamicSelect: DynamicSelect) => ParseSelector<T, Element>} type guarded query function
 */
function shadowQuery (selector) {
  return (dynamicSelect) => {
    const result = dynamicSelect.shadowRoot?.querySelector(selector)
    if (!result) { throw Error(`Error: no ${JSON.stringify(selector)} found in dynamic select shadow DOM`) }
    return result
  }
}
 
/**
 * @template {string} T
 * @param {T} selector - css selector
 * @returns {(dynamicSelect: DynamicSelect) => NodeListOf<ParseSelector<T, Element>>} type guarded query function
 */
function shadowQueryAll (selector) {
  return (dynamicSelect) => {
    const result = dynamicSelect.shadowRoot?.querySelectorAll(selector)
    if (result == null) { throw Error('shadow is not yet defined') }
    return result
  }
}
 
/**
 * @template {string} T
 * @param {T} selector - selector to match
 */
function elementMatcher (selector) {
/**
 * @param {EventTarget | null} element - target element
 * @returns {element is ParseSelector<T, Element>} type guarded element matcher
 */
  return function (element) {
    return element instanceof Element && element.matches(selector)
  }
}
 
/**
 * @param {Node} node target DOM Node
 * @returns {node is DynamicSelect} true if node is a DynamicSelect web component, false otherwise
 */
export function isDynamicSelect (node) {
  return node ? /** @type {DynamicSelect} */(node)[isDynamicSelectSymbol] === true : false
}