# `PhiaUi.ThemeCSS`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/theme_css.ex#L1)

Generates CSS custom property declarations from a `%PhiaUi.Theme{}` struct.

This module is responsible for converting PhiaUI theme data into valid CSS
strings. It supports three output modes that cover the most common scenarios:

## 1. Root-scoped CSS (single active theme)

Use `generate/2` when you want one theme to apply globally to your
application. The output uses `:root` and `.dark` selectors.

    theme = PhiaUi.Theme.get!(:blue)
    css = PhiaUi.ThemeCSS.generate(theme)
    # => "/* PhiaUI Theme: Blue */\n@theme { ... }\n:root { ... }\n.dark { ... }"

Inject the output as a `<style>` tag or write it to `assets/css/theme.css`
via `mix phia.theme apply blue`.

## 2. Attribute-scoped CSS (multi-theme, one theme per block)

Use `generate_for_selector/1` to scope a theme to a `[data-phia-theme]`
attribute selector instead of `:root`. This is the format used by
`mix phia.theme install`.

    css = PhiaUi.ThemeCSS.generate_for_selector(theme)
    # => ~s([data-phia-theme="blue"] { ... }\n.dark [data-phia-theme="blue"] { ... })

The resulting CSS is activated by setting the `data-phia-theme` attribute on
any ancestor element:

    <html data-phia-theme="blue" class="dark">

## 3. All themes in one file

Use `generate_all/1` to combine every preset into a single CSS file, each
scoped to its own `[data-phia-theme]` selector. This is the output of
`mix phia.theme install`.

    css = PhiaUi.ThemeCSS.generate_all()
    # => one block per theme, sorted alphabetically

    # Or for a subset of presets:
    css = PhiaUi.ThemeCSS.generate_all([:zinc, :blue])

## JSON round-trip

Themes can be serialised to JSON and back for storage, sharing, or editing:

    json  = PhiaUi.ThemeCSS.to_json(theme)
    theme = PhiaUi.ThemeCSS.from_json(json)

## CSS custom property naming convention

Color tokens use `--color-{name}` with underscores replaced by hyphens:

- `:card_foreground` → `--color-card-foreground`
- `:primary` → `--color-primary`
- `:sidebar_background` → `--color-sidebar-background`

Non-color tokens (radius, typography) are emitted inside an `@theme { }`
block using the `--radius` and `--font-*` naming scheme.

# `from_json`

```elixir
@spec from_json(String.t()) :: PhiaUi.Theme.t()
```

Deserialises a JSON string into a `%PhiaUi.Theme{}` struct.

Expects the JSON schema produced by `to_json/1`. Raises `Jason.DecodeError`
for malformed JSON and `KeyError` if required fields (`name`, `label`,
`colors`) are missing.

## Example

    iex> theme = PhiaUi.Theme.get!(:zinc)
    iex> json = PhiaUi.ThemeCSS.to_json(theme)
    iex> restored = PhiaUi.ThemeCSS.from_json(json)
    iex> restored.name
    "zinc"
    iex> restored.label
    "Zinc"

# `generate`

```elixir
@spec generate(
  PhiaUi.Theme.t(),
  keyword()
) :: String.t()
```

Generates a CSS string from a `%PhiaUi.Theme{}` struct.

Produces:

- An optional `@theme { }` block with radius and typography tokens (controlled
  by the `:include_theme_block` option).
- A light-mode block using the `:selector` (default `":root"`).
- A dark-mode block using the `:dark_selector` (default `".dark"`).

## Options

- `:selector` — CSS selector for light-mode variables (default: `":root"`)
- `:dark_selector` — CSS selector for dark-mode variables (default: `".dark"`)
- `:include_theme_block` — emit the `@theme { }` block (default: `true`)

## Examples

    iex> theme = PhiaUi.Theme.get!(:zinc)
    iex> css = PhiaUi.ThemeCSS.generate(theme)
    iex> String.contains?(css, ":root {")
    true
    iex> String.contains?(css, ".dark {")
    true
    iex> String.contains?(css, "@theme {")
    true

Override the selector for a custom scope:

    iex> theme = PhiaUi.Theme.get!(:blue)
    iex> css = PhiaUi.ThemeCSS.generate(theme, selector: "#app", dark_selector: "#app.dark")
    iex> String.contains?(css, "#app {")
    true

Omit the `@theme` block when composing multiple themes:

    iex> theme = PhiaUi.Theme.get!(:rose)
    iex> css = PhiaUi.ThemeCSS.generate(theme, include_theme_block: false)
    iex> String.contains?(css, "@theme {")
    false

# `generate_all`

```elixir
@spec generate_all([atom() | PhiaUi.Theme.t()] | nil) :: String.t()
```

Generates a complete CSS string containing all (or a selected subset of)
themes, each scoped to its `[data-phia-theme]` attribute selector.

This is the output written by `mix phia.theme install`. The resulting file
is designed to be imported into `assets/css/app.css` and does not contain
any `@theme { }` blocks — those remain in the base `theme.css`.

Themes are sorted alphabetically by name for deterministic, diffable output.

## Arguments

- `nil` (default) — includes all built-in presets from `Theme.list/0`.
- A list of atoms, e.g. `[:zinc, :blue, :rose]` — loads those named presets.
- A list of `%Theme{}` structs — uses the structs directly (custom themes).

## Examples

    iex> css = PhiaUi.ThemeCSS.generate_all()
    iex> String.contains?(css, ~s([data-phia-theme="zinc"]))
    true
    iex> String.contains?(css, ~s([data-phia-theme="blue"]))
    true

Subset of themes:

    iex> css = PhiaUi.ThemeCSS.generate_all([:zinc, :blue])
    iex> String.contains?(css, ~s([data-phia-theme="zinc"]))
    true
    iex> String.contains?(css, ~s([data-phia-theme="rose"]))
    false

The generated file begins with a usage comment:

    /* PhiaUI Themes — generated by mix phia.theme install
     * Usage: import this file and set data-phia-theme on any ancestor element
     * Example: <html data-phia-theme="blue" class="dark">
     */

# `generate_for_selector`

```elixir
@spec generate_for_selector(PhiaUi.Theme.t()) :: String.t()
```

Generates a CSS string scoped to `[data-phia-theme="<name>"]` attribute
selectors, without any `@theme { }` block or `:root` selector.

This is the multi-theme format: multiple themes can coexist in the same CSS
file, each activated by setting `data-phia-theme` on an ancestor element.
Dark mode is handled by prefixing the selector with `.dark`.

The output for the `:blue` theme looks like:

    [data-phia-theme="blue"] {
      --color-background: oklch(1 0 0);
      --color-primary: oklch(0.546 0.245 262.881);
      ...
    }

    .dark [data-phia-theme="blue"] {
      --color-background: oklch(0.145 0.01 237.938);
      ...
    }

## Example

    iex> theme = PhiaUi.Theme.get!(:blue)
    iex> css = PhiaUi.ThemeCSS.generate_for_selector(theme)
    iex> String.contains?(css, ~s([data-phia-theme="blue"]))
    true
    iex> String.contains?(css, ~s(.dark[data-phia-theme="blue"]))
    true

# `to_json`

```elixir
@spec to_json(PhiaUi.Theme.t()) :: String.t()
```

Serialises a `%PhiaUi.Theme{}` to a pretty-printed JSON string.

The output can be redirected to a file and later restored with `from_json/1`
or passed to `mix phia.theme import`. Requires `:jason` as a dependency
(available as a transitive dependency of Phoenix).

## Example

    iex> theme = PhiaUi.Theme.get!(:zinc)
    iex> json = PhiaUi.ThemeCSS.to_json(theme)
    iex> String.contains?(json, "\"name\"")
    true
    iex> String.contains?(json, "\"zinc\"")
    true

---

*Consult [api-reference.md](api-reference.md) for complete listing*
