All files / utils html-color-to-rgba.js

100% Statements 58/58
66.66% Branches 6/9
100% Functions 2/2
100% Lines 58/58

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 591x 1x 1x 1x 1x 2x 2x 64x 4x 64x 64x 64x 2x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 32x 32x 32x 32x 32x 32x 32x 32x 32x  
/**
 * @template {(...args: any) => any} T
 * @param {T} func - function to memoize
 */
const memoize = function (func) {
  const cache = /** @type {{[key: string]: ReturnType<typeof func>}} */({})
  return function (/** @type {string} */ key) {
    if (!(key in cache)) {
      cache[key] = func(key)
    }
    return cache[key]
  }
}
 
const colorToRGBA = (function () {
  const canvas = new OffscreenCanvas(1, 1)
  canvas.width = canvas.height = 1
  const ctx = canvas.getContext('2d')
  if (!ctx) { throw Error('unreachable code') }
 
  /**
   * @param {string} color - color name or code
   */
  const convertColor = function (color) {
    ctx.clearRect(0, 0, 1, 1)
    // In order to detect invalid values,
    // we can't rely on col being in the same format as what fillStyle is computed as,
    // but we can ask it to implicitly compute a normalized value twice and compare.
    ctx.fillStyle = '#000'
    ctx.fillStyle = color
    const computed = ctx.fillStyle
    ctx.fillStyle = '#fff'
    ctx.fillStyle = color
    if (computed !== ctx.fillStyle) {
      return // invalid color
    }
    ctx.fillRect(0, 0, 1, 1)
    return [...ctx.getImageData(0, 0, 1, 1).data]
  }
 
  return memoize(convertColor)
})()
 
/**
 * @param {string} color - color name or code
 * @param {string} fallbackColor - fallback color name or code
 * @returns {number[]} rgba color values
 */
export function colorOrFallbackColorToRGBA (color, fallbackColor) {
  // Don't short-circuit getting the fallback RGBA -
  // it's already memoized, and we want to show an error
  // if the fallback color is invalid even if the main color is valid
  const fallbackRGBA = colorToRGBA(fallbackColor)
  if (!fallbackRGBA) {
    throw new Error(`Invalid fallbackColor ${fallbackColor != null ? JSON.stringify(fallbackColor) : fallbackColor}`)
  }
  return colorToRGBA(color) || fallbackRGBA
}