Drafter.Widget.Grid (drafter v0.3.2)

Copy Markdown View Source

Arranges child widgets in a uniform column grid, wrapping into multiple rows.

Children are laid out left-to-right, top-to-bottom. The number of columns is set via :grid_size. Column width is floor(total_width / columns) and row height is divided evenly across the number of rows required. Each child widget is mounted fresh on every render pass from its {module, props} tuple.

Component tag

This module has no component_tag/0 and no Drafter.App helper. It is used by placing it in a render tree as a {module, props} pair, or by the renderer's {:grid, children, opts} element.

Options

  • :children - list of {module, props} tuples. Default []. Each child is re-mounted from its props on every render pass, so a child holding its own state will lose it between frames
  • :grid_size - number of columns. Default 2
  • :grid_rows - pos_integer/0 or :auto. Default :auto. Carried on the state but not consulted: the row count is always ceil(child_count / grid_size)
  • :padding - Default 1. Carried on the state but not consulted while rendering
  • :style - map/0 of style properties. Default %{}. Carried on the state but not consulted while rendering

update/2 merges the props map into the state, so every option is live.

Widget value

Drafter.get_widget_value/1 is not implemented for this widget and returns nil.

Usage

grid(children: [
  {Drafter.Widget.Label, %{text: "A"}},
  {Drafter.Widget.Label, %{text: "B"}},
  {Drafter.Widget.Label, %{text: "C"}},
  {Drafter.Widget.Label, %{text: "D"}}
], grid_size: 2)

Summary

Functions

Ignores every event and returns {:noreply, state}. The grid is not focusable and does not forward events to its children.

Builds the grid state from props. The state is a plain map, not a struct.

Renders every child into its cell and returns one strip per row of rect.height.

Merges props into state, so every option is live-updatable.

Types

child_spec()

@type child_spec() :: {module(), Drafter.Widget.props()}

t()

@type t() :: %{
  children: [child_spec()],
  grid_size: pos_integer(),
  grid_rows: pos_integer() | :auto,
  style: map(),
  padding: non_neg_integer()
}

Functions

handle_event(event, state)

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

Ignores every event and returns {:noreply, state}. The grid is not focusable and does not forward events to its children.

mount(props)

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

Builds the grid state from props. The state is a plain map, not a struct.

iex> Drafter.Widget.Grid.mount(%{})
%{children: [], grid_size: 2, grid_rows: :auto, style: %{}, padding: 1}

iex> g = Drafter.Widget.Grid.mount(%{grid_size: 3, children: [{Drafter.Widget.Label, %{}}]})
iex> {g.grid_size, length(g.children)}
{3, 1}

render(state, rect)

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

Renders every child into its cell and returns one strip per row of rect.height.

Returns [] when there are no children. Each cell is div(rect.width, grid_size) columns wide and div(rect.height, rows_needed) rows tall, where rows_needed is ceil(child_count / grid_size); rect.height smaller than rows_needed gives a cell height of 0 and raises ArithmeticError. A child strip's segments are taken only up to the first one wider than the cell, so an over-wide segment ends the row early rather than being cropped.

iex> Drafter.Widget.Grid.render(Drafter.Widget.Grid.mount(%{}), %{x: 0, y: 0, width: 10, height: 2})
[]

update(props, state)

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

Merges props into state, so every option is live-updatable.

iex> g = Drafter.Widget.Grid.mount(%{})
iex> Drafter.Widget.Grid.update(%{grid_size: 4}, g).grid_size
4