Tela.Frame (tela v0.1.0)

Copy Markdown View Source

A rendered frame returned by Tela.view/1 and Tela.Component.view/1.

A Frame carries two pieces of information: the rendered UI content as a plain string, and an optional cursor position that tells the runtime where to place the real terminal cursor after rendering.

Content

content is the full UI string for this frame, with lines separated by \n. It is passed directly to Tela.Renderer.diff/2 for line-diff rendering, exactly as the String.t() return from view/1 was previously.

Cursor

cursor is either nil (hide the terminal cursor) or a {row, col, shape} tuple:

  • row — 0-indexed row relative to this frame's top-left.
  • col — 0-indexed column relative to this frame's top-left.
  • shape:block, :bar, or :underline.

Cursor coordinates are relative to the component's own top-left. When frames are composed with join/2, the accumulated row offset of each preceding frame is added to the cursor row of the frame that holds it.

Composition

Use join/2 to stack frames vertically. It concatenates content strings with a separator (default "\n"), adjusts the cursor row of each frame by the cumulative line count of all preceding frames and their separators, and takes the cursor from the first frame in the list that has a non-nil cursor.

a = Frame.new("Line A")
b = Frame.new("Line B", cursor: {0, 3, :block})
Frame.join([a, b])
# => %Frame{content: "Line A\nLine B", cursor: {1, 3, :block}}

Usage in view/1

A top-level app with no interactive cursor:

def view(model) do
  Frame.new("Count: #{model.count}\nPress q to quit.")
end

A top-level app composing a TextInput component:

def view(model) do
  header = Frame.new("What's your name?\n")
  input  = TextInput.view(model.input)
  footer = Frame.new("\n(esc to quit)")
  Frame.join([header, input, footer], separator: "")
end

Summary

Types

A cursor position within a frame. Coordinates are 0-indexed and relative to the frame's own top-left corner.

The shape of the terminal cursor.

t()

A rendered frame, optionally carrying a cursor position.

Functions

Stacks a list of frames vertically, producing a single composed frame.

Returns a new frame with the given content and no cursor.

Returns a new frame with the given content and cursor options.

Types

cursor()

@type cursor() ::
  {row :: non_neg_integer(), col :: non_neg_integer(), shape :: cursor_shape()}

A cursor position within a frame. Coordinates are 0-indexed and relative to the frame's own top-left corner.

cursor_shape()

@type cursor_shape() :: :block | :bar | :underline

The shape of the terminal cursor.

t()

@type t() :: %Tela.Frame{content: String.t(), cursor: cursor() | nil}

A rendered frame, optionally carrying a cursor position.

Functions

join(frames, opts \\ [])

@spec join([t()], [{:separator, String.t()}]) :: t()

Stacks a list of frames vertically, producing a single composed frame.

Content strings are joined with separator (default "\n"). The cursor is taken from the first frame in the list that has a non-nil cursor, with its row adjusted by the cumulative line count of all preceding frames and their separators.

Options

  • separator: — the string inserted between each frame's content (default "\n").

Examples

iex> alias Tela.Frame
iex> a = Frame.new("Line A")
iex> b = Frame.new("Line B", cursor: {0, 2, :block})
iex> Frame.join([a, b])
%Frame{content: "Line A\nLine B", cursor: {1, 2, :block}}

iex> alias Tela.Frame
iex> frames = [Frame.new("A"), Frame.new("B"), Frame.new("C")]
iex> Frame.join(frames)
%Frame{content: "A\nB\nC", cursor: nil}

new(content)

@spec new(content :: String.t()) :: t()

Returns a new frame with the given content and no cursor.

The terminal cursor will be hidden while this frame is displayed.

new(content, opts)

@spec new(content :: String.t(), [{:cursor, cursor() | nil}]) :: t()

Returns a new frame with the given content and cursor options.

Options

  • cursor:{row, col, shape} tuple or nil. Coordinates are 0-indexed and relative to this frame's top-left. Shape is :block, :bar, or :underline. nil hides the cursor (equivalent to new/1).