TermUI.Component.Helpers (TermUI v0.2.0)

View Source

Common helper functions and macros for TermUI components.

This module is automatically imported when you use TermUI.Component. It provides convenience functions for building render trees and working with props and styles.

Render Tree Builders

Props Helpers

  • props!/2 - Validate and extract required props

Style Helpers

  • merge_styles/2 - Merge multiple styles
  • compute_size/2 - Calculate content dimensions

Summary

Functions

Creates a box container.

Delegates to RenderNode.cells/2 for creating cell-based render nodes.

Computes the size of a render node.

Computes the display size of text content.

Creates an empty node.

Checks if a value fits within a rect.

Merges multiple styles in order, with later styles overriding earlier ones.

Creates a positioned cell for use with RenderNode.cells/2.

Validates and extracts props with type checking and defaults.

Creates a stack layout.

Creates a styled wrapper around a node.

Creates a text node.

Truncates text to fit within a given width.

Functions

box(children, opts \\ [])

Creates a box container.

Examples

box([text("Content")])
box([text("Styled")], style: Style.new() |> Style.bg(:blue))

cells(cells, opts \\ [])

Delegates to RenderNode.cells/2 for creating cell-based render nodes.

Examples

cells = [positioned_cell(0, 0, "H"), positioned_cell(1, 0, "i")]
cells(cells)

compute_node_size(render_node)

@spec compute_node_size(TermUI.Component.RenderNode.t()) ::
  {non_neg_integer() | :auto, non_neg_integer() | :auto}

Computes the size of a render node.

For text nodes, returns the text dimensions. For containers, returns explicit size or :auto.

Examples

compute_node_size(text("Hello"))
# {5, 1}

compute_node_size(box([], width: 20, height: 10))
# {20, 10}

compute_size(text)

@spec compute_size(String.t()) :: {non_neg_integer(), non_neg_integer()}

Computes the display size of text content.

Returns {width, height} where width is the maximum line length and height is the number of lines.

Examples

compute_size("Hello")
# {5, 1}

compute_size("Line 1\nLine 2")
# {6, 2}

empty()

@spec empty() :: TermUI.Component.RenderNode.t()

Creates an empty node.

Examples

empty()

fits_in_rect?(arg, map)

@spec fits_in_rect?(
  {non_neg_integer(), non_neg_integer()},
  TermUI.Component.rect()
) :: boolean()

Checks if a value fits within a rect.

Examples

fits_in_rect?({10, 5}, %{x: 0, y: 0, width: 20, height: 10})
# true

fits_in_rect?({30, 5}, %{x: 0, y: 0, width: 20, height: 10})
# false

merge_styles(styles)

@spec merge_styles([TermUI.Renderer.Style.t() | nil]) :: TermUI.Renderer.Style.t()

Merges multiple styles in order, with later styles overriding earlier ones.

Follows CSS cascade rules - later values take precedence, attributes combine.

Examples

base = Style.new() |> Style.fg(:white)
override = Style.new() |> Style.fg(:red) |> Style.bold()
merge_styles([base, override])
# Result: fg: :red, attrs: [:bold]

positioned_cell(x, y, char, style \\ nil)

Creates a positioned cell for use with RenderNode.cells/2.

Examples

cell = positioned_cell(0, 0, "A", Style.new() |> Style.fg(:red))
# %{x: 0, y: 0, cell: %Cell{char: "A", fg: :red}}

props!(props, specs)

@spec props!(map(), [{atom(), atom(), keyword()}]) :: map()

Validates and extracts props with type checking and defaults.

Raises ArgumentError if required props are missing or types don't match.

Spec Format

Each prop spec is a tuple: {name, type, opts}

Types: :string, :integer, :boolean, :atom, :any, :style

Options:

  • :required - Prop must be present (default: false)
  • :default - Default value if not provided

Examples

props!(props, [
  {:text, :string, required: true},
  {:count, :integer, default: 0},
  {:enabled, :boolean, default: true}
])
# Returns %{text: "...", count: 0, enabled: true}

stack(direction, children, opts \\ [])

Creates a stack layout.

Examples

stack(:vertical, [text("Top"), text("Bottom")])
stack(:horizontal, [text("Left"), text("Right")])

styled(node, style)

Creates a styled wrapper around a node.

Examples

styled(text("Hello"), Style.new() |> Style.fg(:red))

text(content, style \\ nil)

Creates a text node.

Examples

text("Hello, World!")
text("Styled", Style.new() |> Style.fg(:red))

truncate_text(text, max_width)

@spec truncate_text(String.t(), non_neg_integer()) :: String.t()

Truncates text to fit within a given width.

Examples

truncate_text("Hello, World!", 5)
# "Hello"

truncate_text("Hi", 10)
# "Hi"