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

Renders a subset of Markdown to the terminal with themed styling.

Supported syntax: `#` and `##` headings, `**bold**`, `*italic*`, and
`` `inline code` ``. Block elements are styled via the theme system using
the `:h1`, `:h2`, and `:text` theme parts. A configurable horizontal
padding is applied inside the widget boundaries.

## Component tag

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

    markdown(content, opts)

The positional argument becomes `:content`, falling back to `opts[:content]`
when `nil`.

## Options

  * `:content` - `t:String.t/0`, the Markdown to render. Default `""`. Supplied
    positionally through the `markdown/2` element; the positional argument wins
    unless it is `nil`.
  * `:padding` - `t:non_neg_integer/0`, left and right padding in columns.
    Default `1`. A rect narrower than `2 * padding` renders nothing.
  * `:style` - `t:map/0` of base style attributes merged under the computed theme
    styles. Default `%{}`.
  * `:height` - `t:pos_integer/0` read only by `preferred_height/2`, never by
    `mount/1`. Default is the line count of the content, at least `3`.

Every option is live-updatable: `update/2` merges the props map straight into the
state. `update_props_from_mount/3` narrows a re-render to `:content` alone, so a
`:padding` or `:style` change made after mount through the component tree is not
picked up.

## Usage

    markdown(content: "# Title\n\nSome **bold** and *italic* text with `code`.")
    markdown(content: readme_text, padding: 2)

# `t`

```elixir
@type t() :: %{content: String.t(), style: map(), padding: non_neg_integer()}
```

# `component_tag`

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

The component tag this widget registers under.

    iex> Drafter.Widget.Markdown.component_tag()
    :markdown

# `from_component_opts`

```elixir
@spec from_component_opts(
  String.t() | nil,
  keyword()
) :: t()
```

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

`content` is the positional argument; when it is `nil`, `opts[:content]` is used
instead, defaulting to `""`. Also reads `:style` (default `%{}`) and `:padding`
(default `1`).

    iex> Drafter.Widget.Markdown.from_component_opts("# Title", padding: 0)
    %{content: "# Title", padding: 0, style: %{}}

    iex> Drafter.Widget.Markdown.from_component_opts(nil, content: "fallback")
    %{content: "fallback", padding: 1, style: %{}}

# `handle_event`

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

Ignores every event and returns `{:noreply, state}`. The widget is not focusable
and never consumes input.

# `mount`

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

Builds the widget state from `props`.

Reads `:content` (default `""`), `:style` (default `%{}`) and `:padding`
(default `1`).

    iex> Drafter.Widget.Markdown.mount(%{})
    %{content: "", padding: 1, style: %{}}

    iex> Drafter.Widget.Markdown.mount(%{content: "# Title", padding: 2})
    %{content: "# Title", padding: 2, style: %{}}

# `preferred_height`

```elixir
@spec preferred_height(
  String.t() | nil,
  keyword()
) :: pos_integer()
```

The number of rows the element asks for.

`args` is the positional content string, or `nil`. Returns `opts[:height]` when
given, otherwise the line count of `args` with a floor of `3`.

    iex> Drafter.Widget.Markdown.preferred_height("# Title", [])
    3

    iex> Drafter.Widget.Markdown.preferred_height("a\nb\nc\nd", [])
    4

    iex> Drafter.Widget.Markdown.preferred_height(nil, height: 10)
    10

# `render`

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

Renders the parsed Markdown into `rect`, one `Drafter.Draw.Strip` per source line.

Headings are styled through the `:h1` and `:h2` theme parts and every other line
through `:text`. Returns `[]` when `rect.width` leaves no room after padding.

# `update`

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

Merges `props` into `state` and returns the result.

Any key present in `props` replaces the one in the state, so `:content`,
`:padding` and `:style` are all live-updatable.

    iex> state = Drafter.Widget.Markdown.mount(%{content: "a"})
    iex> Drafter.Widget.Markdown.update(%{content: "b"}, state)
    %{content: "b", padding: 1, style: %{}}

# `update_props_from_mount`

```elixir
@spec update_props_from_mount(t(), term(), keyword()) :: %{content: String.t()}
```

Narrows a re-render to the props that may change after mount.

Only `:content` is carried over, so a `:padding` or `:style` change made through
the component tree after the first mount is not picked up.

    iex> props = Drafter.Widget.Markdown.from_component_opts("# New", padding: 4)
    iex> Drafter.Widget.Markdown.update_props_from_mount(props, %{}, [])
    %{content: "# New"}

---

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