{"version":3,"file":"useElementBackground.mjs","sources":["../../../../src/composables/useElementBackground.ts"],"sourcesContent":["import { Ref, ref, watchEffect } from 'vue'\n\n/**\n * This module works with element background\n * Finding element background is not so easy, because it may be transparent\n * So we need to find all parent elements with background and apply them\n * It is not performant, but it is the only way to do it\n * So there is used ugly code which work fast enough\n */\n\n/** Value returned from window.getComputedStyle(el).backgroundColor */\ntype RGBAColorString = `rgba(${number}, ${number}, ${number}, $${number})`\n/** Parsed value [r, g, b, a] */\ntype RGBAColorParsed = [number, number, number, number]\n\nconst parseRgba = (rgba: RGBAColorString): RGBAColorParsed => {\n  let values: any[]\n\n  if (rgba.startsWith('rgba')) {\n    values = rgba\n      .substring(5, rgba.length - 1) // Remove 'rgba(' and ')'\n      .split(',')\n  } else {\n    values = rgba\n      .substring(4, rgba.length - 1) // Remove 'rgb(' and ')'\n      .split(',')\n  }\n\n  values[0] = Number(values[0])\n  values[1] = Number(values[1])\n  values[2] = Number(values[2])\n  if (values[3] === undefined) {\n    values[3] = 1\n  } else {\n    values[3] = Number(values[3])\n  }\n\n  return values as RGBAColorParsed\n}\n\nconst toHex = (color: RGBAColorParsed): string => {\n  return '#' +\n    (color[0] | 1 << 8).toString(16).slice(1) +\n    (color[1] | 1 << 8).toString(16).slice(1) +\n    (color[2] | 1 << 8).toString(16).slice(1) +\n    (color[3] * 255 | 1 << 8).toString(16).slice(1)\n}\n\nconst getParentsWithBackground = (el: HTMLElement): HTMLElement[] => {\n  const parents = []\n\n  let currentEl: HTMLElement | null = el\n  while (currentEl) {\n    if (!(currentEl instanceof HTMLElement) || !currentEl) {\n      return parents\n    }\n\n    const { backgroundColor, willChange } = window.getComputedStyle(currentEl)\n\n    const bgWillChange = willChange.includes('background')\n\n    const parsedColor = parseRgba(backgroundColor as RGBAColorString)\n\n    // In case color is not transparent, we can stop\n    if (parsedColor[3] === 1 && !bgWillChange) {\n      parents.push(currentEl)\n      return parents\n    }\n\n    // If color is not fully transparent we need to add it to parents\n    if (parsedColor[3] !== 0 || bgWillChange) {\n      parents.push(currentEl)\n    }\n\n    currentEl = currentEl.parentElement\n  }\n\n  return parents\n}\n\n// Add fake transition to element to make it trigger transitionend event, add as first class to not break other transitions\nconst WATCHER_CLASS = 'va-background-watcher'\n\nconst watchElementBackground = (el: HTMLElement, cb: () => void) => {\n  el.className = WATCHER_CLASS + ' ' + el.className\n\n  el.addEventListener('transitionend', (e) => {\n    if (e.target !== el) { return }\n    cb()\n  })\n\n  return () => {\n    el.className = el.className.replace(WATCHER_CLASS, '')\n    el.removeEventListener('transitionend', cb)\n  }\n}\n\nconst watchElementsBackground = (els: HTMLElement[], cb: () => void) => {\n  const unwatchers = els.map((el) => watchElementBackground(el, cb))\n\n  return () => {\n    unwatchers.forEach((unwatch) => unwatch())\n  }\n}\n\n/** It is not ideal. browser applies colors in a bit different way */\nconst applyColors = (color1: RGBAColorParsed, color2: RGBAColorParsed): RGBAColorParsed => {\n  const weight = color2[3]\n\n  if (weight === 1) { return color2 }\n  if (weight === 0) { return color1 }\n\n  const c1 = Math.round((color1[0]) * (1 - weight) + (color2[0]) * weight)\n  const c2 = Math.round((color1[1]) * (1 - weight) + (color2[1]) * weight)\n  const c3 = Math.round((color1[2]) * (1 - weight) + (color2[2]) * weight)\n\n  return [c1, c2, c3, 1]\n}\n\nconst getColorFromElements = (els: HTMLElement[]): RGBAColorParsed => {\n  let currentColor = [0, 0, 0, 0] as RGBAColorParsed\n\n  for (let i = els.length - 1; i >= 0; i--) {\n    currentColor = applyColors(currentColor, parseRgba(window.getComputedStyle(els[i]).backgroundColor as RGBAColorString))\n  }\n\n  return currentColor\n}\n\nexport const useElementBackground = (el: Ref<HTMLElement | undefined | null>) => {\n  const color = ref<string>('#000000')\n  let unWatchAll = () => void 0 as void\n\n  watchEffect(() => {\n    unWatchAll()\n\n    if (el.value) {\n      const parents = getParentsWithBackground(el.value)\n\n      unWatchAll = watchElementsBackground(parents, () => {\n        color.value = toHex(getColorFromElements(parents))\n      })\n\n      color.value = toHex(getColorFromElements(parents))\n    }\n  })\n\n  return color\n}\n"],"names":[],"mappings":"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"}