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
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 tonil.errors(:list) - Defaults to[].refs(:map) - Defaults to%{}.selected(:string) - Defaults tonil.found(:string) - Defaults tonil.theme(:any) - Defaults tonil.defs(:map) - Defaults to%{}.origins(:map) - Defaults to%{}.guessed(:any) - Defaults toMapSet.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 tonil.target(:any) - Defaults tonil.
@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", %{}, %{})
[]
@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"}]}}]
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
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
@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]