# `Plushie.Type.Theme`
[🔗](https://github.com/plushie-ui/plushie-elixir/blob/v0.7.2/lib/plushie/type/theme.ex#L1)

Built-in iced themes and custom palette support.

Each built-in theme is an atom that maps to the corresponding `iced::Theme`
variant on the Rust side. Custom themes are plain maps that the renderer
parses into an `iced::Theme::custom()` palette.

## Extended palette shade overrides

Custom themes automatically generate shade variants (strong, weak, etc.)
from the six core palette colors using iced's Oklch-based algorithm. If
you need precise control over specific shades, you can override them with
flat keys in the theme map. Shade overrides only apply to custom themes --
built-in themes are not affected.

Each shade key targets a specific `Pair` (background color + text color)
in the extended palette. Append `_text` to any shade key to override
the text color for that shade.

### Color families (base, weak, strong)

`primary`, `success`, `warning`, `danger` are core palette seeds
(set via `custom/2`). `secondary` is auto-derived from `background`
and `text` by iced's palette generator.

All five families support shade overrides: `{family}_base`,
`{family}_weak`, `{family}_strong`, plus `_text` variants.

### Background family (8 levels)

`background_base`, `background_weakest`, `background_weaker`,
`background_weak`, `background_neutral`, `background_strong`,
`background_stronger`, `background_strongest`, plus `_text` variants.

### Example

    # Custom theme with shade overrides
    theme = %{
      name: "my-theme",
      background: "#1a1a2e",
      text: "#e0e0e0",
      primary: "#0f3460",
      primary_strong: "#1a5276",
      primary_strong_text: "#ffffff",
      background_weakest: "#0d0d1a"
    }

Any shade key you omit keeps the auto-generated value.

## Widget chrome colour tokens

Custom themes can also carry theme-level colour tokens for cursor and
scrollbar styling:

* `cursor_color`
* `scrollbar_color`
* `scroller_color`

These values are cast as colours and sent in the custom theme map.
The renderer uses scrollbar tokens as scrollable defaults. The cursor
token applies to focused text entry widgets through iced's focused text
style, and explicit widget text styling still wins.

# `builtin`

```elixir
@type builtin() ::
  :ferra
  | :oxocarbon
  | :nightfly
  | :moonfly
  | :kanagawa_lotus
  | :kanagawa_dragon
  | :kanagawa_wave
  | :tokyo_night_light
  | :tokyo_night_storm
  | :tokyo_night
  | :catppuccin_mocha
  | :catppuccin_macchiato
  | :catppuccin_frappe
  | :catppuccin_latte
  | :gruvbox_dark
  | :gruvbox_light
  | :solarized_dark
  | :solarized_light
  | :nord
  | :dracula
  | :dark
  | :light
```

# `t`

```elixir
@type t() :: builtin() | :system | map()
```

# `builtin_themes`

```elixir
@spec builtin_themes() :: [atom()]
```

Returns the list of all known built-in theme atoms.

# `cast`

```elixir
@spec cast(term()) :: {:ok, t()} | :error
```

Validates a theme value.

Accepts built-in theme atoms, `:system`, or a custom theme map
(a map with at least a `:name` key).

## Examples

    iex> Plushie.Type.Theme.cast(:dark)
    {:ok, :dark}

    iex> Plushie.Type.Theme.cast(:system)
    {:ok, :system}

    iex> Plushie.Type.Theme.cast(%{name: "custom"})
    {:ok, %{name: "custom"}}

    iex> Plushie.Type.Theme.cast(:bogus)
    :error

# `custom`

```elixir
@spec custom(name :: String.t(), opts :: keyword()) :: map()
```

Build a custom theme palette map.

The returned map is passed through to the Rust renderer, which uses it to
construct an `iced::Theme::custom()` with a modified `Palette`.

## Options

  * `:base`       - built-in theme atom to use as the palette starting point
  * `:background` - page background color
  * `:text`       - default text color
  * `:primary`    - primary accent color
  * `:success`    - success color
  * `:danger`     - danger color
  * `:warning`    - warning color
  * `:cursor_color` - text cursor color
  * `:scrollbar_color` - scrollbar track color
  * `:scroller_color` - scrollbar handle color

All color values accept any form `Color.cast/1` supports (hex
strings or named atoms). Shade override keys (e.g. `primary_strong`,
`background_weakest`, `primary_strong_text`) are also accepted and
cast as colors.

Note: `:secondary` is not a core seed. It is auto-derived from
`:background` and `:text` by iced's palette generator. To customize
the secondary palette, use shade overrides: `secondary_base`,
`secondary_weak`, `secondary_strong` (plus `_text` variants).

Unknown keys raise `ArgumentError`. Use `valid_custom_keys/0` for
the complete set.

## Examples

    iex> Plushie.Type.Theme.custom("Tokyo Remix", primary: "#7aa2f7", danger: "#f7768e")
    %{name: "Tokyo Remix", primary: "#7aa2f7", danger: "#f7768e"}

    iex> Plushie.Type.Theme.custom("Nord+", base: :nord, primary: "#88c0d0")
    %{name: "Nord+", base: "nord", primary: "#88c0d0"}

# `valid_custom_keys`

```elixir
@spec valid_custom_keys() :: MapSet.t(atom())
```

Returns the set of valid keys for `custom/2` (excluding `:base`, which
is handled separately).

---

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