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-String.t/0, the Markdown to render. Default"". Supplied positionally through themarkdown/2element; the positional argument wins unless it isnil.:padding-non_neg_integer/0, left and right padding in columns. Default1. A rect narrower than2 * paddingrenders nothing.:style-map/0of base style attributes merged under the computed theme styles. Default%{}.:height-pos_integer/0read only bypreferred_height/2, never bymount/1. Default is the line count of the content, at least3.
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)
Summary
Functions
The component tag this widget registers under.
Builds the props map for a {:markdown, content, opts} element.
Ignores every event and returns {:noreply, state}. The widget is not focusable
and never consumes input.
Builds the widget state from props.
The number of rows the element asks for.
Renders the parsed Markdown into rect, one Drafter.Draw.Strip per source line.
Merges props into state and returns the result.
Narrows a re-render to the props that may change after mount.
Types
@type t() :: %{content: String.t(), style: map(), padding: non_neg_integer()}
Functions
@spec component_tag() :: :markdown
The component tag this widget registers under.
iex> Drafter.Widget.Markdown.component_tag()
:markdown
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: %{}}
@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.
@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: %{}}
@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
@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.
@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: %{}}
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"}