Visualize.Chart.Builder.StyleForm (Visualize v0.8.3)

Copy Markdown View Source

A style's form in its parts (spec/14 §18.7, D-178).

A style is compound parts (§3.1, D-172), and its form is the whole element's keys — extends, opacity, blend, class — then one fieldset per part, in the schema's order: fill, stroke, font, text, effect, marker, curve, transition, animation, enter, exit. A part's controls are its own kind's keys, read from Visualize.Chart.Schema.describe/1; a node-typed key inside a part is a fieldset of its own, and a list of nodes — a gradient's stops — is rows. Nothing here lists a style key.

A paint's type is its first control and decides which of its keys follow (§18.6); a part the element does not draw is grayed with a note, where the form is told the element's kind (§5.6).

A control is named by its path within the style — stroke.width, fill.stops.1.color, transition.fill.duration — and locate/2 reads a name back through the schema. write/4 is what an edit at a path means for the node it lands in: the top-level parts it rewrites, a type change replacing what only the old type meant, a node in the flat keys of version 2 rewritten in its parts.

This module compiles only when Phoenix.Component is loaded (spec/10 §1.1, D-45, D-85).

Summary

Functions

Renders a style's controls in its parts (spec/14 §18.7): the whole element's keys, then a <fieldset class="vis-builder-part"> per part, inside the caller's form.

Every write a change to a style's form means (spec/14 §18.7): the control target submitted value, read at its path, written into node — the node the write lands in — with seed the style the site resolves to, which a type change starts a gradient from. A name that is no key is no write.

The writes an item added to or removed from a list of nodes at path means — a gradient's stops (§18.6): :add appends a copy of the last item at the end of the list (a stop at 1), {:remove, i} takes the item out, and :drop takes the whole key out — a defaults node's entry for a mark kind (#684). A node that holds no list there starts from seed's, the list the site resolves to.

Whether a node kind is edited in its parts.

A control's name read back through the schema: the spec of the key at that path of a node of kind, the path, and the suffix the name ends in (slot, range, other, or nil). A font's face is the one name that is two keys: it answers the font's path with face: true. A name no key of the schema has is nil.

The top-level writes one edit at a path means for the node it lands in (spec/14 §18.7, D-178): {key, {:ok, value}} for each top-level key that changes, {key, :error} for each that goes. The node is read in its parts first, so a node written in the flat keys of version 2 is rewritten whole by its first edit. A key blanked removes itself and any part it leaves empty. Choosing a paint's type keeps only what no type decides and what the new one reads, starting a gradient, a solid or a hatch from the color the part — else seed's part, the site's resolved style — has.

Functions

body(assigns)

Renders a style's controls in its parts (spec/14 §18.7): the whole element's keys, then a <fieldset class="vis-builder-part"> per part, inside the caller's form.

Attributes

  • kind (:atom) (required) - the style kind: :style, :defaults.
  • node (:any) (required) - the node, in any spelling the design reads.
  • path (:list) - Defaults to [].
  • label (:string) - the node's label, aimed at by every event. Defaults to nil.
  • errors (:list) - Defaults to [].
  • refs (:map) - Defaults to %{}.
  • selected (:string) - Defaults to nil.
  • found (:string) - Defaults to nil.
  • theme (:any) - Defaults to nil.
  • defs (:map) - Defaults to %{}.
  • origins (:map) - Defaults to %{}.
  • guessed (:any) - Defaults to MapSet.new([]).
  • event (:string) - the event the form's changes push. Defaults to "edit".
  • drawn_by (:atom) - the kind of the element the style draws, whose undrawn parts are grayed (§5.6). Defaults to nil.
  • target (:any) - Defaults to nil.

changes(kind, target, value, node, seed)

@spec changes(atom(), String.t(), String.t() | nil, term(), term()) :: [
  {atom(), {:ok, term()} | :error}
]

Every write a change to a style's form means (spec/14 §18.7): the control target submitted value, read at its path, written into node — the node the write lands in — with seed the style the site resolves to, which a type change starts a gradient from. A name that is no key is no write.

iex> Visualize.Chart.Builder.StyleForm.changes(:style, "stroke.width", "7", %{}, %{})
[stroke: {:ok, %{width: 7}}]

iex> Visualize.Chart.Builder.StyleForm.changes(:style, "font.face", "light_italic", %{font: %{size: 12}}, %{})
[font: {:ok, %{size: 12, weight: :light, style: :italic}}]

iex> Visualize.Chart.Builder.StyleForm.changes(:style, "nonsense", "1", %{}, %{})
[]

item(node, path, op, seed)

@spec item(term(), [atom()], :add | :drop | {:remove, non_neg_integer()}, term()) :: [
  {atom(), {:ok, term()} | :error}
]

The writes an item added to or removed from a list of nodes at path means — a gradient's stops (§18.6): :add appends a copy of the last item at the end of the list (a stop at 1), {:remove, i} takes the item out, and :drop takes the whole key out — a defaults node's entry for a mark kind (#684). A node that holds no list there starts from seed's, the list the site resolves to.

iex> node = %{fill: %{type: :linear, stops: [%{at: 0, color: "#abc"}]}}
iex> Visualize.Chart.Builder.StyleForm.item(node, [:fill, :stops], :add, %{})
[fill: {:ok, %{type: :linear, stops: [%{at: 0, color: "#abc"}, %{at: 1, color: "#abc"}]}}]

kind?(kind)

@spec kind?(atom()) :: boolean()

Whether a node kind is edited in its parts.

iex> Visualize.Chart.Builder.StyleForm.kind?(:style)
true

iex> Visualize.Chart.Builder.StyleForm.kind?(:mark)
false

locate(kind, name)

@spec locate(atom(), String.t()) :: map() | nil

A control's name read back through the schema: the spec of the key at that path of a node of kind, the path, and the suffix the name ends in (slot, range, other, or nil). A font's face is the one name that is two keys: it answers the font's path with face: true. A name no key of the schema has is nil.

iex> located = Visualize.Chart.Builder.StyleForm.locate(:style, "stroke.width.range")
iex> {located.path, located.spec.type, located.suffix}
{[:stroke, :width], :size, "range"}

iex> Visualize.Chart.Builder.StyleForm.locate(:style, "fill.stops.1.color").path
[:fill, :stops, 1, :color]

iex> Visualize.Chart.Builder.StyleForm.locate(:style, "font.face")
%{path: [:font], face: true}

iex> Visualize.Chart.Builder.StyleForm.locate(:style, "stroke.nonsense")
nil

write(node, path, parsed, seed)

@spec write(term(), [atom() | non_neg_integer()], {:ok, term()} | :error, term()) :: [
  {atom(), {:ok, term()} | :error}
]

The top-level writes one edit at a path means for the node it lands in (spec/14 §18.7, D-178): {key, {:ok, value}} for each top-level key that changes, {key, :error} for each that goes. The node is read in its parts first, so a node written in the flat keys of version 2 is rewritten whole by its first edit. A key blanked removes itself and any part it leaves empty. Choosing a paint's type keeps only what no type decides and what the new one reads, starting a gradient, a solid or a hatch from the color the part — else seed's part, the site's resolved style — has.

iex> Visualize.Chart.Builder.StyleForm.write(%{stroke: :red, stroke_width: 2}, [:stroke, :width], {:ok, 5}, %{})
[stroke: {:ok, %{type: :solid, color: :red, width: 5}}, stroke_width: :error]

iex> Visualize.Chart.Builder.StyleForm.write(%{fill: %{type: :solid, color: "#abc", opacity: 0.5}}, [:fill, :type], {:ok, :linear}, %{})
[fill: {:ok, %{type: :linear, opacity: 0.5, stops: [%{at: 0, color: "#abc", opacity: 0.8}, %{at: 1, color: "#abc", opacity: 0.1}]}}]

iex> Visualize.Chart.Builder.StyleForm.write(%{stroke: %{width: 2}}, [:stroke, :width], :error, %{})
[stroke: :error]