An animated spinner component.
Tela.Component.Spinner is a display-only widget that cycles through a list
of animation frames at a fixed interval. It is driven by a tick cmd that the
parent starts via tick_cmd/1 and routes back via handle_tick/2.
Usage
defmodule MyApp do
use Tela
alias Tela.Component.Spinner
@impl Tela
def init(_args) do
spinner = Spinner.init(spinner: :dot)
{%{spinner: spinner}, Spinner.tick_cmd(spinner)}
end
@impl Tela
def handle_event(model, %Tela.Key{key: {:char, "q"}}), do: {model, :quit}
def handle_event(model, _key), do: {model, nil}
@impl Tela
def handle_info(model, msg) do
{spinner, cmd} = Spinner.handle_tick(model.spinner, msg)
{%{model | spinner: spinner}, cmd}
end
@impl Tela
def view(model) do
Spinner.view(model.spinner) <> " Loading..."
end
endPresets
The following preset atoms are available:
:line—|,/,-,\:dot— Braille dot spinner:mini_dot— smaller Braille dot spinner:jump— Braille jump spinner:pulse— block pulse█▓▒░:points— moving dot∙∙∙ ●∙∙ ∙●∙ ∙∙●:globe— rotating globe emoji:moon— moon phase emoji:monkey— monkey emoji sequence:meter— filling bar▱▱▱ → ▰▰▰:hamburger— stacked lines☱ ☲ ☴:ellipsis— growing dots. .. ...
Custom spinners can be passed as a {frames, interval_ms} tuple.
Tick ownership
Components do not emit startup cmds from init/1. The parent must call
tick_cmd/1 to obtain the initial cmd and include it in its own init/1
return value. The tick self-re-arms: each successful handle_tick/2 call
returns a new cmd that advances the animation by one more frame.
Each spinner is assigned a unique id on init/1. Ticks carry that id, and
handle_tick/2 rejects any tick whose id does not match the current spinner's
id — silently dropping stale ticks from replaced spinners without needing
explicit cancellation.
Summary
Functions
Ignores all key events. The spinner is display-only.
Processes a tick message for this spinner.
Initialises a new spinner model.
Returns a {:task, fun} cmd that, when dispatched, sleeps for
interval_ms and then returns {:spinner_tick, id}.
Returns the current animation frame as a Tela.Frame.
Types
@type t() :: %Tela.Component.Spinner{ frame: non_neg_integer(), frames: [String.t()], id: non_neg_integer(), interval_ms: pos_integer(), style: Tela.Style.t() }
The spinner model. Build with init/1; treat as opaque.
Functions
@spec handle_event(t(), Tela.Key.t()) :: {t(), Tela.cmd()}
Ignores all key events. The spinner is display-only.
Processes a tick message for this spinner.
Matches {:spinner_tick, id} where id equals the spinner's current id. On
a match, advances the frame by one (wrapping around), assigns a new unique id,
and returns {new_spinner, tick_cmd(new_spinner)}.
Any non-matching message — including ticks with a stale id from a replaced
spinner — returns {spinner, nil} unchanged.
Initialises a new spinner model.
Options
spinner:— a preset atom (default:line) or a{frames, interval_ms}tuple for a custom spinner. See the module doc for available presets.style:— aTela.Style.t()applied when rendering (defaultTela.Style.new()).
Raises ArgumentError if the spinner option is an unrecognised atom.
Returns a {:task, fun} cmd that, when dispatched, sleeps for
interval_ms and then returns {:spinner_tick, id}.
Pass the result directly as the cmd in your parent's init/1 or
handle_info/2 return to drive the animation.
@spec view(t()) :: Tela.Frame.t()
Returns the current animation frame as a Tela.Frame.
The frame carries no cursor — Tela.Component.Spinner is a display-only
component. Compose the returned frame with surrounding content using
Tela.Frame.join/2 in the parent's view/1.