# `Drafter.Widget.Rule`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/widget/rule.ex#L1)

Renders a horizontal or vertical divider line, optionally with an embedded title.

## Component tag

Tag `:rule`, built by `Drafter.App` as `{:rule, opts}`:

    rule(opts)

There is no positional argument; every prop comes from `opts`.

## Options

  * `:orientation` - `:horizontal | :vertical`. Default `:horizontal`. Any other
    value raises a `CaseClauseError` from `render/2`.
  * `:title` - `t:String.t/0` embedded in a horizontal rule, or `nil`. Default
    `nil`. Ignored when the orientation is `:vertical`. A title that is as wide
    as the rect, once padded with a space on each side, is truncated and no line
    characters are drawn.
  * `:title_align` - `:left | :center | :right`. Default `:center`. Only read
    when `:title` is set.
  * `:line_style` - `:solid | :double | :dashed | :thick`. Default `:solid`.
    Selects `─ ═ ╌ ━` horizontally and `│ ║ ╎ ┃` vertically. Any other value
    raises a `KeyError` from `render/2`.
  * `:style` - `t:map/0` of style overrides merged over the computed theme style.
    Default `%{}`.
  * `:height` - `t:pos_integer/0` read only by `preferred_height/2`, never by
    `mount/1`. Default `1`.

Every option except `:height` is live-updatable: `update/2` folds each recognised
key into the state and `update_props_from_mount/3` passes the full mount props
through.

## Usage

    rule()
    rule(title: "Section", line_style: :double)
    rule(orientation: :vertical)

# `t`

```elixir
@type t() :: %Drafter.Widget.Rule{
  app_module: module() | nil,
  line_style: :solid | :double | :dashed | :thick,
  orientation: :horizontal | :vertical,
  style: map(),
  title: String.t() | nil,
  title_align: :left | :center | :right
}
```

# `component_tag`

```elixir
@spec component_tag() :: :rule
```

The component tag this widget registers under.

    iex> Drafter.Widget.Rule.component_tag()
    :rule

# `focused`

# `from_component_opts`

```elixir
@spec from_component_opts(
  term(),
  keyword()
) :: Drafter.Widget.props()
```

Builds the props map for a `{:rule, opts}` element.

The positional argument is ignored. `:__app_module__` becomes `:app_module`;
every other option keeps its name and the default stated in the module doc.

    iex> Drafter.Widget.Rule.from_component_opts(nil, [])
    %{orientation: :horizontal, title: nil, title_align: :center, style: %{}, line_style: :solid, app_module: nil}

    iex> Drafter.Widget.Rule.from_component_opts(nil, title: "Section", title_align: :left).title_align
    :left

# `handle_event`

```elixir
@spec handle_event(Drafter.Event.t(), t()) :: {:noreply, t()}
```

Ignores every event and returns `{:noreply, state}`. The rule is not focusable.

# `mount`

```elixir
@spec mount(Drafter.Widget.props()) :: t()
```

Builds the widget state from `props`.

Reads `:orientation` (default `:horizontal`), `:title` (default `nil`),
`:title_align` (default `:center`), `:style` (default `%{}`), `:line_style`
(default `:solid`) and `:app_module` (default `nil`).

    iex> Drafter.Widget.Rule.mount(%{})
    %Drafter.Widget.Rule{orientation: :horizontal, title: nil, title_align: :center, style: %{}, line_style: :solid, app_module: nil}

    iex> Drafter.Widget.Rule.mount(%{title: "Section", line_style: :double}).line_style
    :double

# `preferred_height`

```elixir
@spec preferred_height(
  term(),
  keyword()
) :: pos_integer()
```

The number of rows the element asks for: `opts[:height]`, default `1`.

    iex> Drafter.Widget.Rule.preferred_height(nil, [])
    1

    iex> Drafter.Widget.Rule.preferred_height(nil, height: 3)
    3

# `render`

```elixir
@spec render(t(), Drafter.Widget.rect()) :: [Drafter.Draw.Strip.t()]
```

Draws the rule into `rect`.

A horizontal rule returns `rect.height` strips with the line on row
`div(rect.height, 2)` and blanks elsewhere. A vertical rule returns
`rect.height` strips each holding the line character followed by
`rect.width - 1` spaces, or `[]` when `rect.width` is not positive.

# `unmount`

# `update`

```elixir
@spec update(Drafter.Widget.props() | keyword(), t()) :: t()
```

Folds `props` into `state`, one key at a time.

Recognises `:orientation`, `:title`, `:title_align`, `:style`, `:line_style` and
`:app_module`; any other key is ignored and leaves the state untouched. `props`
may be a map or a keyword list.

    iex> state = Drafter.Widget.Rule.mount(%{})
    iex> Drafter.Widget.Rule.update(%{title: "New", unknown: 1}, state).title
    "New"

# `update_props_from_mount`

```elixir
@spec update_props_from_mount(Drafter.Widget.props(), term(), keyword()) ::
  Drafter.Widget.props()
```

Passes the mount props through unchanged, so every option is live-updatable
through the component tree.

    iex> props = Drafter.Widget.Rule.from_component_opts(nil, title: "Section")
    iex> Drafter.Widget.Rule.update_props_from_mount(props, %{}, []) == props
    true

---

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