{"version":3,"file":"toHex.mjs","names":[],"sources":["../../../../package/common/colorPicker/toHex.ts"],"sourcesContent":["/**\n * Normalises any CSS colour the browser understands into hex, which is the only form\n * ColorPicker's own arithmetic can take. Without it every non-hex value — `transparent`,\n * `rgba(...)`, and above all `oklch(...)`, which a whole theme may be written in — silently\n * became the picker's default blue: a swatch confidently showing a colour nothing asked for.\n *\n * The canvas 2D context is the browser's own colour parser. Under jsdom there is none, so\n * this returns `undefined` and callers keep their previous fallback — meaning the widened\n * behaviour is only observable in a real browser, and only `*.browser.test.ts` can cover it.\n */\n\n/** `undefined` until first use, `null` once we know there is no 2D context (jsdom). */\nlet ctx: CanvasRenderingContext2D | null | undefined;\n\n/*\n * Six or eight digits only. Shorthand is deliberately NOT short-circuited: ColorPicker's own\n * isValidHex accepts those two lengths and nothing else, so handing it `#abc` untouched would\n * have produced exactly the default-blue swatch this helper exists to prevent. Letting it fall\n * through to the canvas expands it.\n */\nconst HEX = /^#([0-9a-f]{6}|[0-9a-f]{8})$/i;\n/*\n * Two of them, because an unparseable value leaves fillStyle at whatever preceded it: seed\n * with each in turn and a real colour resolves the same way twice, while a rejected one\n * comes back as the two different seeds. One sentinel could not tell a rejected value from\n * a value that happens to BE the sentinel — `rgb(1, 2, 3)` normalises to exactly `#010203`.\n */\nconst SEED_A = '#010203';\nconst SEED_B = '#040506';\n\nfunction byteToHex(n: number): string {\n  return Math.max(0, Math.min(255, Math.round(n)))\n    .toString(16)\n    .padStart(2, '0');\n}\n\n/** `#rrggbb`, widened to `#rrggbbaa` only when the colour is not fully opaque. */\nfunction pack(r: number, g: number, b: number, a: number): string {\n  const alpha = Math.round(a);\n  return `#${byteToHex(r)}${byteToHex(g)}${byteToHex(b)}${alpha === 255 ? '' : byteToHex(alpha)}`;\n}\n\nexport function toHex(value: string | undefined): string | undefined {\n  const raw = value?.trim();\n  if (!raw) return undefined;\n  if (HEX.test(raw)) return raw;\n\n  if (ctx === undefined) ctx = document.createElement('canvas').getContext('2d');\n  if (!ctx) return undefined;\n\n  ctx.fillStyle = SEED_A;\n  ctx.fillStyle = raw;\n  const resolved = ctx.fillStyle;\n  ctx.fillStyle = SEED_B;\n  ctx.fillStyle = raw;\n  if (ctx.fillStyle !== resolved) return undefined;\n\n  // fillStyle normalises sRGB inputs to `#rrggbb` or `rgba(r, g, b, a)`, which are exact.\n  if (resolved.startsWith('#')) return resolved;\n  const parts = /^rgba?\\(([^)]+)\\)$/i.exec(resolved);\n  if (parts) {\n    const [r, g, b, a = '1'] = parts[1].split(',').map((part) => part.trim());\n    return pack(Number(r), Number(g), Number(b), Number(a) * 255);\n  }\n\n  /*\n   * Anything in a wide-gamut syntax — oklch(), oklab(), color-mix() — comes back verbatim\n   * rather than as sRGB, so the browser is asked to paint it and the pixel is read instead.\n   * Only reached for those: canvas un-premultiplies alpha on the way out, which costs a\n   * little precision on a very transparent colour, and the exact paths above avoid it.\n   */\n  ctx.clearRect(0, 0, 1, 1);\n  ctx.fillRect(0, 0, 1, 1);\n  const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;\n  return pack(r, g, b, a);\n}\n"],"mappings":"aAYA,IAAI,EAQE,EAAM,gCAUZ,SAAS,EAAU,EAAmB,CACpC,OAAO,KAAK,IAAI,EAAG,KAAK,IAAI,IAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAC7C,SAAS,EAAE,CAAC,CACZ,SAAS,EAAG,GAAG,CACpB,CAGA,SAAS,EAAK,EAAW,EAAW,EAAW,EAAmB,CAChE,IAAM,EAAQ,KAAK,MAAM,CAAC,EAC1B,MAAO,IAAI,EAAU,CAAC,IAAI,EAAU,CAAC,IAAI,EAAU,CAAC,IAAI,IAAU,IAAM,GAAK,EAAU,CAAK,GAC9F,CAEA,SAAgB,EAAM,EAA+C,CACnE,IAAM,EAAM,GAAO,KAAK,EACxB,GAAI,CAAC,EAAK,OACV,GAAI,EAAI,KAAK,CAAG,EAAG,OAAO,EAG1B,GADI,IAAQ,IAAA,KAAW,EAAM,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI,GACzE,CAAC,EAAK,OAEV,EAAI,UAAY,UAChB,EAAI,UAAY,EAChB,IAAM,EAAW,EAAI,UAGrB,GAFA,EAAI,UAAY,UAChB,EAAI,UAAY,EACZ,EAAI,YAAc,EAAU,OAGhC,GAAI,EAAS,WAAW,GAAG,EAAG,OAAO,EACrC,IAAM,EAAQ,sBAAsB,KAAK,CAAQ,EACjD,GAAI,EAAO,CACT,GAAM,CAAC,EAAG,EAAG,EAAG,EAAI,KAAO,EAAM,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAK,GAAS,EAAK,KAAK,CAAC,EACxE,OAAO,EAAK,OAAO,CAAC,EAAG,OAAO,CAAC,EAAG,OAAO,CAAC,EAAG,OAAO,CAAC,EAAI,GAAG,CAC9D,CAQA,EAAI,UAAU,EAAG,EAAG,EAAG,CAAC,EACxB,EAAI,SAAS,EAAG,EAAG,EAAG,CAAC,EACvB,GAAM,CAAC,EAAG,EAAG,EAAG,GAAK,EAAI,aAAa,EAAG,EAAG,EAAG,CAAC,CAAC,CAAC,KAClD,OAAO,EAAK,EAAG,EAAG,EAAG,CAAC,CACxB"}