# `Macaw.Layers.Theme.Document`
[🔗](https://github.com/dcoai/macaw_layers/blob/v0.2.2/lib/macaw/layers/theme/document.ex#L11)

A theme as a document (spec/04 §5): stored and shipped as a value, and read back through
every gate.

  * the map form is `%{version: v, theme: node}` (`to_map/1`), and a store's fragment
    `%{theme: node}` (`fragment/1`), a library entry of kind `:theme`, reads as the same
    document;
  * the JSON form is `{"$version": v, "theme": {…}}` (`to_json/1`), each color value a tag
    (`$color`, `$series`, `$ramp`, the transforms by name, `$blend`, `$contrast`) and
    pinned steps `$steps`.

Reading (`from_map/2`, `from_json/2`) runs the kernel's gates (spec/01 §5) — the version,
the limits, the migration — then reads the form, then: a node that is a **name** reads as
the built-in theme of that name, any other name is `{:unknown_theme, name}`; a variable
anywhere is `{:unresolved, :var, name}`, since nothing applies a theme; a key the theme
does not have is `:unknown_key`; and every contract a ramp, color or palette entry breaks
is `{:contract, message}` at `[:theme, :ramps | :colors | :styles, name]`.

As a fragment type (spec/02 §1), `ramps`, `colors`, `styles` and `defaults` are `:union`
name maps and every other key `:override`, so a theme document stacks over a built-in as
`Macaw.Layers.Theme.new/1` merges.

    iex> theme = Macaw.Layers.Theme.new(name: :house, axis: "#555555")
    iex> Macaw.Layers.Theme.Document.from_map(Macaw.Layers.Theme.Document.to_map(theme))
    {:ok, theme}
    iex> Macaw.Layers.Theme.Document.from_map(%{theme: :dark})
    {:ok, Macaw.Layers.Theme.dark()}

Ported from visualize's `Visualize.Chart.Theme`.

# `fragment`

```elixir
@spec fragment(Macaw.Layers.Theme.t()) :: %{theme: map()}
```

`%{theme: node}`: a store's fragment of kind `:theme`.

# `from_json`

```elixir
@spec from_json(String.t(), keyword()) ::
  {:ok, Macaw.Layers.Theme.t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The theme a JSON document holds, read as `from_map/2` reads a map, every gate first.

# `from_map`

```elixir
@spec from_map(term(), keyword()) ::
  {:ok, Macaw.Layers.Theme.t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The theme a map document or a theme fragment holds, or every fault. `limits:` as
`Macaw.Layers.Document.read/3` takes them; `extensions:` the extensions the host
registers, which the theme carries and its contracts hold.

# `node`

```elixir
@spec node(Macaw.Layers.Theme.t()) :: map()
```

The theme as its node: every field but `extensions`, an unset counterpart and empty
defaults left out, and a palette name outside the library's vocabulary (an extension's)
spelled as its string, which a reader given the extension reads back as its name.

# `to_json`

```elixir
@spec to_json(Macaw.Layers.Theme.t()) ::
  {:ok, String.t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The JSON document, `{:ok, json}`, stamped `"$version"`.

# `to_map`

```elixir
@spec to_map(Macaw.Layers.Theme.t()) :: %{version: pos_integer(), theme: map()}
```

`%{version: current, theme: node}`.

---

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