Macaw.Layers.Theme.Document (macaw_layers v0.3.0)

Copy Markdown View Source

A theme as a document (spec/04 §5): stored and shipped as a value, and judged as one.

  • the value 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 a tag (a literal $rgb, $color, $series, $ramp, the transforms by name, $blend, $contrast) and pinned steps $steps, written and read by the JSON adapter (Macaw.Layers.Form, Macaw.Layers.Color.Form), every name in ramps, colors, styles and defaults a string, as the theme holds it, and every word (an entry's keys and atom values) read from the library's vocabulary and the registered extensions' words (Macaw.Layers.Theme.Extension.words/0).

from_map/2 judges the value as terms, after the version check, with no form written or read; from_json/2 reads the JSON form through the adapter's gates (spec/01 §5: the limits, the version, the migration) to the same value. A name given both as its atom and as its string in one name map of a value is {:duplicate, :name} at its path. 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].

The line is at version 2: a literal color is a term, tagged $rgb in the JSON form. Version 1 wrote it as CSS text; its step tags each string at a color position that Macaw.Layers.Color.parse/1 reads, so a version 1 document, or a bundle's entry of one, reads to the same theme.

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: Macaw.Layers.Color.parse!("#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.

Summary

Functions

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

The theme a JSON document holds: read through the JSON adapter (Macaw.Layers.Form.read/3: every gate, then the value, judged), then built as from_map/2 builds it. limits: as Macaw.Layers.Form.gates/3 takes them, and extensions: as from_map/2: the reader's vocabulary is the library's words and these extensions' (Extension.words/0), so an adopter's words read back only with its extension given, and no other atom is made.

The theme a document value or a theme fragment holds, judged as terms, or every fault. extensions: the extensions the host registers, which the theme carries and its contracts hold. No form is written or read, so no limit applies: the limits bound what reading an encoding costs (from_json/2).

The theme as its node: every field but extensions, an unset counterpart and empty defaults left out. Its names are strings, as the theme holds them (spec/04 §2.1), and its words as given.

The JSON document, {:ok, json}, stamped "$version", its words written with the theme's extensions' (Macaw.Layers.Theme.Extension.words/0).

%{version: current, theme: node}.

Functions

fragment(theme)

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

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

from_json(json, opts \\ [])

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

The theme a JSON document holds: read through the JSON adapter (Macaw.Layers.Form.read/3: every gate, then the value, judged), then built as from_map/2 builds it. limits: as Macaw.Layers.Form.gates/3 takes them, and extensions: as from_map/2: the reader's vocabulary is the library's words and these extensions' (Extension.words/0), so an adopter's words read back only with its extension given, and no other atom is made.

from_map(document, opts \\ [])

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

The theme a document value or a theme fragment holds, judged as terms, or every fault. extensions: the extensions the host registers, which the theme carries and its contracts hold. No form is written or read, so no limit applies: the limits bound what reading an encoding costs (from_json/2).

node(theme)

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

The theme as its node: every field but extensions, an unset counterpart and empty defaults left out. Its names are strings, as the theme holds them (spec/04 §2.1), and its words as given.

to_json(theme)

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

The JSON document, {:ok, json}, stamped "$version", its words written with the theme's extensions' (Macaw.Layers.Theme.Extension.words/0).

to_map(theme)

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

%{version: current, theme: node}.