# `Expresso.Placement`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/placement.ex#L1)

The places of the elements: which element can hold which child

The DSL accepts an element in more places than these rules give, because
the macros of the outer entities stay in scope in each nested block. See
"The definitions of the elements" in `docs/architecture.md`.
`Expresso.PlacementTransformer` calls `slide/1` for each slide, and it refuses
an element in a wrong place. `docs/reference/placement.md` gives the rules.

A transformer adds children to two elements, and these children are in their
place: the `Expresso.Element.Lines` of a code element and the
`Expresso.Element.TocEntry` of a toc. `Expresso.Overlay.Check` reports a
`pause` inside an element, so this module accepts a pause in each place.

# `children`

```elixir
@spec children(module(), atom()) :: [module()]
```

Return the children that an element holds under a key, as a list of modules

    iex> Expresso.Element.Columns in Expresso.Placement.children(Expresso.Element.TextBox, :elements)
    true
    iex> Expresso.Placement.children(Expresso.Element.Callout, :elements) |> Enum.member?(Expresso.Element.Callout)
    false

# `element`

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

Give an error for the first child of an element in a wrong place, at each
depth

`Expresso.Element.Chart` calls this function for each frame, because the
transform of the chart reads the flows of a frame before
`Expresso.PlacementTransformer` runs.

    iex> alias Expresso.Builder
    iex> {:error, message} = Expresso.Placement.element(%Expresso.Element.Frame{flows: [Builder.node("b")]})
    iex> message
    "a node is inside a frame, and a frame holds flow"

# `slide`

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

Give an error for the first element of a slide in a wrong place

    iex> alias Expresso.Builder
    iex> Expresso.Placement.slide(Builder.slide("s", elements: [Builder.callout(:tip)]))
    :ok
    iex> slide = Builder.slide("s", elements: [Builder.callout(:tip, elements: [Builder.callout(:note)])])
    iex> {:error, message} = Expresso.Placement.slide(slide)
    iex> message =~ "a callout is inside a callout"
    true

---

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