Current section
Files
Jump to
Current section
Files
lib/jetons/css/color.ex
defmodule Jetons.CSS.Color do
@moduledoc """
Serializes DTCG 2025.10 color value maps to CSS color strings.
Supports all 14 color spaces defined in the Color Module specification.
"""
@color_fn_spaces ~w(srgb srgb-linear display-p3 a98-rgb prophoto-rgb rec2020 xyz-d65 xyz-d50)
@named_fn_spaces ~w(hsl hwb lab lch oklab oklch)
@doc """
Serializes a color value map to a CSS color string.
## Examples
iex> Jetons.CSS.Color.serialize(%{"colorSpace" => "srgb", "components" => [1, 0, 0]})
"color(srgb 1 0 0)"
iex> Jetons.CSS.Color.serialize(%{"colorSpace" => "hsl", "components" => [330, 100, 50], "alpha" => 0.5})
"hsl(330 100% 50% / 0.5)"
"""
def serialize(%{"colorSpace" => space, "components" => components} = color) do
alpha = Map.get(color, "alpha", 1)
formatted = format_components(space, components)
alpha_part = if alpha_visible?(alpha), do: " / #{alpha}", else: ""
cond do
space in @color_fn_spaces ->
"color(#{space} #{formatted}#{alpha_part})"
space in @named_fn_spaces ->
"#{space}(#{formatted}#{alpha_part})"
true ->
"color(#{space} #{formatted}#{alpha_part})"
end
end
defp alpha_visible?(1), do: false
defp alpha_visible?(1.0), do: false
defp alpha_visible?(_), do: true
defp format_components(space, components) do
components
|> Enum.with_index()
|> Enum.map_join(" ", fn {c, i} -> format_component(space, c, i) end)
end
defp format_component(_space, "none", _index), do: "none"
defp format_component("hsl", value, i) when i in [1, 2], do: "#{value}%"
defp format_component("hwb", value, i) when i in [1, 2], do: "#{value}%"
defp format_component("lab", value, 0), do: "#{value}%"
defp format_component("lch", value, 0), do: "#{value}%"
defp format_component(_space, value, _index), do: "#{value}"
end