vuestic-ui
Version:
Vue 3 UI Framework
1 lines • 7.18 kB
Source Map (JSON)
{"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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"}