# `Ascii.Compose`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/compose.ex#L1)

Frames put together into one: a frame in a bordered panel with a title,
rules between sections, frames side by side or one above another. For a
dashboard on a plain terminal (`Ascii.Render.ANSI`), a Nerves device's
screen, an SVG, or anything else that draws one frame.

    {gauge, _} = Ascii.frame(gauge, t)
    {spark, _} = Ascii.frame(spark, t)

    Ascii.Compose.above([
      Ascii.Compose.beside([
        Ascii.Compose.panel(gauge, title: "load"),
        Ascii.Compose.panel(spark, title: "history", style: :double)
      ]),
      Ascii.Compose.divider(80, label: "processes"),
      Ascii.Compose.text(["pid  name", "123  my_app"])
    ])

Every function takes and returns `Ascii.Frame`s, so they nest. Each
frame keeps its colours: the result's palette holds every frame's, once
each, and cells in no colour (a frame without colours, the spaces between)
are in the renderer's own ink, a `nil` in the palette. A frame of only
uncoloured frames has no colours either. A frame's `ground` is kept only
where every coloured frame shares it; a scene's dark ground is otherwise
lost, so give one behind the whole with `:ground` (or draw over a dark
terminal). Composing an animation is composing its frames: draw each
piece's frame at `t`, then put them together, every tick.

# `align`

```elixir
@type align() :: :left | :center | :right | :top | :middle | :bottom
```

Where a smaller frame goes in the room it is given.

# `color`

```elixir
@type color() :: String.t() | nil
```

A colour (as `Ascii.Ink.color/1` takes one), or `nil` for the renderer's own.

# `above`

```elixir
@spec above(frames :: [Ascii.Frame.t(), ...], opts :: keyword()) :: Ascii.Frame.t()
```

Frames one above another, their left edges level (or as `:align` says),
`:gap` blank rows apart (default 0).

## Options

  * `:gap` - blank rows between neighbours (default 0).
  * `:align` - `:left` (the default), `:center` or `:right`.
  * `:ground` - the result's ground.

# `beside`

```elixir
@spec beside(frames :: [Ascii.Frame.t(), ...], opts :: keyword()) :: Ascii.Frame.t()
```

Frames side by side, their tops level (or as `:align` says), `:gap`
blank cells apart (default 1).

## Options

  * `:gap` - blank cells between neighbours (default 1).
  * `:align` - `:top` (the default), `:middle` or `:bottom`.
  * `:ground` - the result's ground.

# `divider`

```elixir
@spec divider(cols :: pos_integer(), opts :: keyword()) :: Ascii.Frame.t()
```

A rule across `cols` cells, for between sections, with a label in it if
given.

## Options

  * `:style` - `:single` (the default), `:double`, `:heavy`, `:dashed`,
    `:dotted`, `:ascii` or `:wave`.
  * `:label` - text set into the rule, a space either side.
  * `:align` - where the label goes: `:left` (two cells in, the default),
    `:center` or `:right`.
  * `:color`, `:label_color` - the rule's and the label's colours.

# `fit`

```elixir
@spec fit(
  frame :: Ascii.Frame.t(),
  cols :: pos_integer(),
  rows :: pos_integer(),
  opts :: keyword()
) ::
  Ascii.Frame.t()
```

The frame in exactly `cols` by `rows` cells: placed as `:align` and
`:valign` say in a larger room, or its middle (as aligned) in a smaller.
For a frame to fill an area of a screen.

## Options

  * `:align` - `:center` (the default), `:left` or `:right`.
  * `:valign` - `:middle` (the default), `:top` or `:bottom`.

# `panel`

```elixir
@spec panel(frame :: Ascii.Frame.t(), opts :: keyword()) :: Ascii.Frame.t()
```

The frame in a box, a title set into its top edge.

## Options

  * `:title` - text in the top edge, a space either side.
  * `:style` - the box: `:rounded` (the default), `:single`, `:double`,
    `:heavy`, `:dashed`, `:ascii` or `:block`.
  * `:padding` - blank cells between the box and the frame, at the sides
    (default 1); `:padding_y` above and below (default 0).
  * `:width`, `:height` - the panel's whole size, box included, the frame
    placed in it by `:align`: for panels of one size in a row or a grid.
    The panel is never smaller than the frame and its title need, so a
    frame too big for the room keeps all of its picture.
  * `:align` - where the frame sits in a larger panel: `:center` (the
    default), `:left` or `:right`; and `:valign`, `:middle` (the
    default), `:top` or `:bottom`.
  * `:color`, `:title_color` - the box's and the title's colours.
  * `:ground` - the result's ground.

# `text`

```elixir
@spec text(lines :: String.t() | [String.t()], opts :: keyword()) :: Ascii.Frame.t()
```

Plain text as a frame: lines, each padded to the longest (or `:width`,
cut to it), in one colour or the renderer's own. For labels, readouts and
tables beside the pieces.

## Options

  * `:width` - the frame's width; lines are cut or padded to it.
  * `:align` - `:left` (the default), `:center` or `:right`.
  * `:color` - the text's colour.

---

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