# `Expresso.Element.Hierarchy`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/element/hierarchy.ex#L1)

A tree: a hierarchy of nodes as boxes and lines, such as an org chart or the
use of a disk

The `tree` entity holds one `node` entity, the root, and each node holds the
nodes under it. The name of a node is its identity, and the default text of
its box. The `detail` option of a node gives a second line, such as a role.
A box can also show an image or an icon, and a line for each field.

The color of a box comes from the `color` option of the node or of the
nearest node above it, then from the `color` option of the tree, which takes
the colors of the palette for each branch or for each value of a field.
`colors/1` returns the color of each node.

`Expresso.Element.Hierarchy.Layout` places each box, and the drawing is one
SVG with the `viewBox` of the layout, so it scales to the box of the element.
The lines are paths in the SVG. Each box is a `foreignObject` that holds the
HTML of the box, so its text ends with an ellipsis as HTML does. The SVG is
hidden from a screen reader. A nested list with the same tree holds the text
for a screen reader, and the eye does not see it.

The element module is `Hierarchy`, because `Expresso.Element.Tree` holds the
functions that walk the elements of a slide. `docs/tree.md` gives the plan,
and `docs/reference/tree-element.md` gives the rules for the author.

# `t`

```elixir
@type t() :: %Expresso.Element.Hierarchy{
  __spark_metadata__: term(),
  at: term(),
  bar: term(),
  box: term(),
  class: term(),
  color: term(),
  delimiter: term(),
  depth: term(),
  dim: term(),
  easing: term(),
  effect: term(),
  el: term(),
  elements: term(),
  fields: term(),
  focus: term(),
  frames: term(),
  highlight: term(),
  layout: term(),
  limit: term(),
  morph: term(),
  on: term(),
  reflow: term(),
  reveal: term(),
  separator: term(),
  signature: term(),
  sort: term(),
  speed: term(),
  src: term(),
  stack_from: term(),
  steps: term(),
  sum: term(),
  timeline: term(),
  title: term(),
  value_format: term(),
  whole_first: term(),
  width: term()
}
```

The struct of a tree

# `box`

```elixir
@spec box(term()) ::
  {:ok, [Expresso.Element.Hierarchy.Layout.size()]} | {:error, String.t()}
```

Make sure that a `box` option gives the size of each level

This function is the custom type of the option. The value is a list of
sizes, one for each level from the root down, or one size for each level.
A size is a keyword list with a positive integer for `width` and for
`height`.

    iex> Expresso.Element.Hierarchy.box(width: 200, height: 80)
    {:ok, [%{width: 200, height: 80}]}

    iex> Expresso.Element.Hierarchy.box([[width: 280, height: 120], [width: 220, height: 96]])
    {:ok, [%{width: 280, height: 120}, %{width: 220, height: 96}]}

    iex> {:error, _message} = Expresso.Element.Hierarchy.box(width: 0, height: 80)

# `branch`

```elixir
@spec branch(String.t()) :: {:branch, String.t()}
```

Return the item of the `highlight` option for a node and each node under it

`use Expresso` imports this function, so a deck can write
`highlight ["Ben", branch("Ben")]`.

    iex> Expresso.Element.Hierarchy.branch("Ben")
    {:branch, "Ben"}

# `build`

```elixir
@spec build(t()) :: {:ok, t()} | {:error, String.t()}
```

Read the CSV file of a tree with `src`, and make its nodes

`Expresso.PathTransformer` calls this function after it joins the path to
the root of the deck. `Expresso.Element.Hierarchy.Data` tells the two
forms of a file. The function reads the file through `Expresso.DeckFile`,
so the watch mode renders the deck again after a change to the file.

# `check`

```elixir
@spec check(t()) :: {:ok, t()} | {:error, String.t()}
```

Make sure that a tree has one root, and that each node is a node of a tree

`Expresso.Extension` calls this function when it builds the entity, so the
DSL and `Expresso.Builder` give the same errors. A tree with `src` has no
nodes yet, so the function checks only its options, and `build/1` checks
the tree after it reads the file. Nodes with the `parent` option become a
nested tree first.

# `color`

```elixir
@spec color(term()) :: {:ok, :branch | {:field, String.t()}} | {:error, String.t()}
```

Make sure that a `color` option of a tree is `:branch` or a field

This function is the custom type of the option. The name of a field can be
an atom or a string, and the function returns it as a string.

    iex> Expresso.Element.Hierarchy.color(:branch)
    {:ok, :branch}

    iex> Expresso.Element.Hierarchy.color({:field, :team})
    {:ok, {:field, "team"}}

    iex> {:error, _message} = Expresso.Element.Hierarchy.color(:leaf)

# `colors`

```elixir
@spec colors(t()) :: {%{required(String.t()) =&gt; color}, [{String.t(), pos_integer()}]}
when color: {:role, atom()} | {:palette, pos_integer()} | nil
```

Return the color of each node, by its name, and the values of the legend

A color is `{:role, role}` for the `color` option of a node or of a node
above it, `{:palette, n}` for a color of the palette from 1 to 8, or `nil`.
The legend holds each value of the field of `color {:field, name}` and its
color of the palette, in the order of the first node with the value.

    iex> alias Expresso.Element.{Hierarchy, Node}
    iex> root = %Node{name: "A", elements: [%Node{name: "B", elements: [%Node{name: "C"}]}, %Node{name: "D", color: :danger}]}
    iex> Hierarchy.colors(%Hierarchy{color: :branch, elements: [root]})
    {%{"A" => nil, "B" => {:palette, 1}, "C" => {:palette, 1}, "D" => {:role, :danger}}, []}

# `colors`

```elixir
@spec colors(t(), [{String.t(), pos_integer()}]) ::
  {%{required(String.t()) =&gt; color}, [{String.t(), pos_integer()}]}
when color: {:role, atom()} | {:palette, pos_integer()} | nil
```

Return the color of each node and the values of a legend that holds the
values of more than one tree, such as the frames of a tree

The colors of a field come from the legend, so a value has one color in
each frame.

# `get_assigns`

```elixir
@spec get_assigns(t()) :: map()
```

Make the assigns of the render function from the struct

The key `boxes` holds each box with its overlay attributes and its cards,
one card for each content of the box. The key `lines` holds the path and
the attributes of each line. The key `lists` holds the root of each list
for a screen reader, and the key `copies` holds the small trees of the
handout view. A tree without frames has one card for each box, one list
and no copy.

# `highlight`

```elixir
@spec highlight(term()) ::
  {:ok, [[String.t() | {:branch, String.t()}]]} | {:error, String.t()}
```

Make sure that a `highlight` option is a list of groups

This function is the custom type of the option. A group is the name of a
node, `{:branch, name}`, or a list of those. The function returns each
group as a list.

    iex> Expresso.Element.Hierarchy.highlight(["Ben", {:branch, "Eve"}, ["Cy", "Di"]])
    {:ok, [["Ben"], [{:branch, "Eve"}], ["Cy", "Di"]]}

    iex> {:error, _message} = Expresso.Element.Hierarchy.highlight([[]])

# `map_frames`

```elixir
@spec map_frames(t(), (map() -&gt; {:ok, map()} | {:error, reason})) ::
  {:ok, t()} | {:error, reason}
when reason: term()
```

Change each node of each frame of a tree, and stop at the first error

`Expresso.Element.Tree.map_ok/2` walks the key `:elements` only, so a
transformer calls this function for the nodes of the frames.

# `prepared`

```elixir
@spec prepared(t()) :: t()
```

Return the tree after the options of the values

`Expresso.Element.Hierarchy.Values.prepare/2` applies `depth`, `sum`,
`sort` and `limit` to the root. The layout, the colors and the HTML read
this tree, so each one shows the same nodes.

# `render`

```elixir
@spec render(map()) :: Phoenix.HTML.safe()
```

Make the HTML of a tree

The `figure` holds the SVG of the drawing, which a screen reader does not
read, and a nested list of the nodes, which the eye does not see. The
legend is in the SVG under the tree, and each field of a node is in the
list, so a screen reader reads the value that gives a color.

# `rules`

```elixir
@spec rules(t()) :: [String.t()]
```

Return the rules of the moves and of the groups of a tree

With frames, each box is at its place in the first frame that holds it. At
each step of a later frame, a box at a different place gets the custom
properties `--tree-dx` and `--tree-dy`, as with `reflow`.

With `reflow`, at each step, a box that is not in its place of the full
layout gets the custom properties `--tree-dx` and `--tree-dy`, and the style
sheet moves it with a transition.

A group of the `highlight` option gives one rule at its step. The rule sets
`--dimmed: 1` on each box and each line whose node is not in the group, so
the line to a box in focus keeps its color. A branch holds the node and
each node under it in the tree after the options of the values, also the
node of the rest of a `limit`. A node that `depth` or `limit` removes has
no box, so the rule leaves it out.

`Expresso.Overlay.Render.style/1` adds the rules to the style block of the
deck. A tree without `reflow` and without `highlight` has no rules.

# `stack_from`

```elixir
@spec stack_from(term()) :: {:ok, pos_integer()} | {:error, String.t()}
```

Make sure that a `stack_from` option is a level under the root

This function is the custom type of the option. The root is level 1, and
it has no node above it to stack under, so the first level is 2.

    iex> Expresso.Element.Hierarchy.stack_from(3)
    {:ok, 3}

    iex> {:error, _message} = Expresso.Element.Hierarchy.stack_from(1)

---

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