{"version":3,"file":"utils.cjs","sources":["../../../components/color-picker/utils.ts"],"sourcesContent":["import {\n  clampChroma,\n  clampRgb,\n  converter,\n  formatHex,\n  formatHex8,\n  formatHsl,\n  formatRgb,\n  parse,\n  toGamut\n} from 'culori';\n\nexport const SUPPORTED_MODES = ['hex', 'hsl', 'rgb', 'oklch'] as const;\n\nexport type ModeType = (typeof SUPPORTED_MODES)[number];\n\nexport type ColorObject = {\n  l: number;\n  c: number;\n  h: number;\n  alpha?: number;\n};\n\n// Practical upper bound for the chroma axis. Covers Rec.2020; the displayable\n// region for sRGB and Display-P3 falls inside this range.\nexport const CHROMA_MAX = 0.4;\n\nconst toOklch = converter('oklch');\nconst toRgb = converter('rgb');\nconst toHsl = converter('hsl');\n\n// Reusable gamut-mapper: reduces chroma in OKLCH space until the color fits\n// sRGB while preserving lightness and hue. Created once because `toGamut`\n// returns a function and the inputs ('rgb' / 'oklch') are constant.\nconst toSrgb = toGamut('rgb', 'oklch');\n\nconst FALLBACK: ColorObject = { l: 1, c: 0, h: 0, alpha: 1 };\n\nconst round = (n: number, p: number) => Number.parseFloat(n.toFixed(p));\n\nexport const clamp01 = (n: number) => Math.max(0, Math.min(1, n));\n\n/**\n * Parses any CSS color string into the picker's OKLCH `{l, c, h, alpha}` shape.\n * Returns white when the input fails to parse so the picker never throws on\n * bad consumer input. Hue is pinned to 0 for achromatic colors because culori\n * may report it as NaN per CSS Color 4.\n */\nexport const parseColor = (value: string): ColorObject => {\n  const parsed = parse(value);\n  if (!parsed) return FALLBACK;\n  const oklch = toOklch(parsed);\n  if (!oklch) return FALLBACK;\n  const c = oklch.c ?? 0;\n  return {\n    l: oklch.l ?? 0,\n    c,\n    h: c === 0 || !Number.isFinite(oklch.h) ? 0 : (oklch.h as number),\n    alpha: oklch.alpha ?? 1\n  };\n};\n\nconst formatOklchString = (color: ColorObject): string => {\n  const L = round(color.l, 4);\n  const C = round(color.c, 4);\n  const H = C === 0 ? 0 : round(color.h, 2);\n  const alpha = color.alpha ?? 1;\n  const body = `${L} ${C} ${H}`;\n  return alpha === 1 ? `oklch(${body})` : `oklch(${body} / ${round(alpha, 4)})`;\n};\n\n/**\n * Convert any CSS color string to the requested format.\n *\n * Wide-gamut OKLCH inputs are gamut-mapped into sRGB for `hex`/`rgb`/`hsl`\n * outputs (chroma reduced, lightness and hue preserved), so the result is\n * the closest sRGB representation of the requested color rather than a\n * per-channel-clipped one that would distort hue. `oklch` output preserves\n * the full color, since OKLCH can express the wide gamut natively.\n *\n * Hex is uppercase; uses 8-digit form when alpha < 1. RGB/HSL produce\n * `rgb()`/`rgba()` and `hsl()`/`hsla()`. OKLCH matches the design system's\n * token format (4-decimal L/C, 2-decimal H, hue pinned to 0 when achromatic).\n *\n * Returns `null` for unparseable input.\n *\n * @example\n *   formatColor('oklch(0.5438 0.191 267.01)', 'hex')   // '#3E63DD'\n *   formatColor('oklch(0.7 0.32 30)', 'hex')           // '#FF5843'\n *   formatColor('red', 'rgb')                          // 'rgb(255, 0, 0)'\n *   formatColor('rgba(255, 0, 0, 0.5)', 'hsl')         // 'hsla(0, 100%, 50%, 0.5)'\n *   formatColor('#FF0000', 'oklch')                    // 'oklch(0.6279 0.2577 29.23)'\n *   formatColor('not a color', 'hex')                  // null\n */\nexport const formatColor = (\n  value: string,\n  format: 'hex' | 'rgb' | 'hsl' | 'oklch'\n): string | null => {\n  const parsed = parse(value);\n  if (!parsed) return null;\n\n  if (format === 'oklch') {\n    const oklch = toOklch(parsed);\n    if (!oklch) return null;\n    return formatOklchString({\n      l: oklch.l ?? 0,\n      c: oklch.c ?? 0,\n      h: Number.isFinite(oklch.h) ? (oklch.h as number) : 0,\n      alpha: oklch.alpha ?? 1\n    });\n  }\n\n  // sRGB-bound formats: gamut-map first so wide-gamut OKLCH inputs land on\n  // the closest sRGB color (hue/lightness preserved) instead of producing\n  // per-channel-clipped hex/rgb/hsl that would shift the hue.\n  const safe = toSrgb(parsed);\n  if (format === 'hex') {\n    const hex = (safe.alpha ?? 1) === 1 ? formatHex(safe) : formatHex8(safe);\n    return hex.toUpperCase();\n  }\n  if (format === 'hsl') return formatHsl(safe);\n  return formatRgb(safe);\n};\n\n/**\n * Serializes the OKLCH color to a CSS string in the requested mode. Non-oklch\n * modes clip out-of-gamut channels to sRGB so the output is always a valid\n * representable value in that format.\n */\nexport const getColorString = (color: ColorObject, mode: ModeType): string => {\n  if (mode === 'oklch') return formatOklchString(color);\n\n  const rgb = toRgb({\n    mode: 'oklch',\n    l: color.l,\n    c: color.c,\n    h: color.h,\n    alpha: color.alpha ?? 1\n  });\n  if (!rgb) return '';\n  // clampRgb is culori's per-channel clip to [0, 1] — identical to the manual\n  // clamp it replaces, keeping non-oklch output a valid representable value.\n  const clipped = clampRgb(rgb);\n\n  if (mode === 'hex') {\n    const hex = clipped.alpha === 1 ? formatHex(clipped) : formatHex8(clipped);\n    return hex.toUpperCase();\n  }\n  if (mode === 'hsl') return formatHsl(clipped);\n  return formatRgb(clipped);\n};\n\n/**\n * Converts an OKLCH triple to a culori RGB object. The returned r/g/b channels\n * may fall outside [0, 1] when the input is outside the sRGB gamut — callers\n * use that signal to detect and mark the gamut boundary.\n */\nexport const oklchToRgb = (l: number, c: number, h: number) =>\n  toRgb({ mode: 'oklch', l, c, h });\n\ntype HslView = {\n  h: number;\n  s: number;\n  l: number;\n};\n\n/**\n * Derives an HSL view (h: 0-360, s/l: 0-100) from the picker's OKLCH state.\n * Falls back to the input hue when the color is achromatic so the user's last\n * hue choice isn't lost at the s=0 axis. Used by the area + hue slider in\n * non-oklch modes to drive the classic gradient square.\n */\nexport const oklchToHsl = (color: ColorObject): HslView => {\n  const hsl = toHsl({\n    mode: 'oklch',\n    l: color.l,\n    c: color.c,\n    h: color.h,\n    alpha: color.alpha ?? 1\n  });\n  if (!hsl) return { h: color.h, s: 0, l: 100 };\n  // At c=0 the color is achromatic and the HSL hue carries no information;\n  // culori may still return a finite hue from floating-point drift, so trust\n  // the input hue to keep the user's last choice intact at the s=0 axis.\n  const isAchromatic = color.c <= 1e-6;\n  return {\n    h: isAchromatic || !Number.isFinite(hsl.h) ? color.h : (hsl.h as number),\n    s: clamp01(hsl.s ?? 0) * 100,\n    l: clamp01(hsl.l ?? 0) * 100\n  };\n};\n\n/**\n * Converts an HSL triple (h: 0-360, s/l: 0-100) back to the picker's OKLCH\n * shape. Preserves the input hue when culori reports NaN (e.g. on grays) so\n * the user's hue choice survives a round-trip through s=0.\n */\nexport const hslToOklch = (\n  h: number,\n  s: number,\n  l: number,\n  alpha = 1\n): ColorObject => {\n  const oklch = toOklch({\n    mode: 'hsl',\n    h,\n    s: clamp01(s / 100),\n    l: clamp01(l / 100),\n    alpha\n  });\n  if (!oklch) return { l: 0, c: 0, h, alpha };\n  return {\n    l: oklch.l ?? 0,\n    c: oklch.c ?? 0,\n    h: Number.isFinite(oklch.h) ? (oklch.h as number) : h,\n    alpha\n  };\n};\n\n/**\n * Reduces chroma until the OKLCH color is displayable in sRGB, preserving L\n * and H. Used in non-oklch modes so the picker can only emit colors that the\n * output format can actually represent.\n */\nexport const clampToSrgb = (color: ColorObject): ColorObject => {\n  const result = clampChroma(\n    {\n      mode: 'oklch',\n      l: color.l,\n      c: color.c,\n      h: color.h,\n      alpha: color.alpha ?? 1\n    },\n    'oklch',\n    'rgb'\n  );\n  return {\n    l: result.l ?? color.l,\n    c: result.c ?? 0,\n    h: result.h ?? color.h,\n    alpha: result.alpha ?? color.alpha ?? 1\n  };\n};\n"],"names":["converter","toGamut","parse","formatHex","formatHex8","formatHsl","formatRgb","clampRgb","clampChroma"],"mappings":"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"}