telega/dialog/widget

Built-in managed keyboard widgets for dialogs.

A widget renders extra button rows for a window and handles their events itself (see KeyboardWidget in telega/dialog/types): the dialog engine appends widget rows after the window’s own buttons and routes widget button presses (w:<widget_id>:<cmd> action ids) to the widget, bypassing the window’s on_action. Widget state lives in a per-widget WidgetStore persisted with the dialog instance, so selections and page positions survive restarts.

Built-ins:

Reading widget state from window handlers (on_action, on_text, on_done) and renders goes through dialog.widget_store:

let zone =
  dialog.widget_store(ctx, window_id: "prefs", widget_id: "zone")
  |> widget.radio_value
  |> option.unwrap("hall")

All user-facing symbols (, , , , “done”) come from the dialog’s Labels — override them with dialog.with_labels for i18n.

Types

An item offered by select/radio/multiselect/paged_select. The id travels in callback data — keep it short (the 64-byte limit is validated on every render) and without : at the edges of your scheme (an id may contain :, it is re-joined on parse).

pub type SelectItem {
  SelectItem(id: String, label: String)
}

Constructors

  • SelectItem(id: String, label: String)

Values

pub fn current_page(store store: types.WidgetStore) -> Int

The current 0-based page kept by a pager/paged_select store.

pub fn multiselect(
  id id: String,
  items items: fn(
    state,
    bot.Context(session, error, dependencies),
  ) -> List(SelectItem),
  min min: Int,
  max max: Int,
  done done: String,
) -> types.KeyboardWidget(state, session, error, dependencies)

A set of choices with checkbox marks. Toggling above max is ignored; the labels.done button renders only while the count is within min/max and emits Goto(done, state) when pressed. done must be an existing window id — validated by dialog.build().

pub fn multiselect_values(
  store store: types.WidgetStore,
) -> List(String)

The item ids currently selected in a multiselect store, in pick order.

pub fn paged_select(
  id id: String,
  items items: fn(
    state,
    bot.Context(session, error, dependencies),
  ) -> List(SelectItem),
  page_size page_size: Int,
  columns columns: Int,
  on_selected on_selected: fn(
    state,
    String,
    bot.Context(session, error, dependencies),
  ) -> Result(types.DialogAction(state), error),
) -> types.KeyboardWidget(state, session, error, dependencies)

select and pager in one widget: items are sliced to the current page by the widget itself (page_size counts items, not rows), the pager row appears only when there is more than one page.

pub fn pager(
  id id: String,
  page_size page_size: Int,
  total total: fn(
    state,
    bot.Context(session, error, dependencies),
  ) -> Int,
) -> types.KeyboardWidget(state, session, error, dependencies)

Page navigation: the store keeps the current page, the row renders as ‹ 2/5 › (the counter is a no-op button). total returns the number of items; the row disappears when everything fits on one page. Slice your content in the window’s render with current_page.

pub fn radio(
  id id: String,
  items items: fn(
    state,
    bot.Context(session, error, dependencies),
  ) -> List(SelectItem),
  default default: option.Option(String),
) -> types.KeyboardWidget(state, session, error, dependencies)

Single choice kept in the widget store: the selected item is marked with labels.checked, the rest with labels.unchecked. default is only a visual pre-selection — radio_value stays None until the user actually picks, so apply the same default when reading.

pub fn radio_value(
  store store: types.WidgetStore,
) -> option.Option(String)

The item id picked in a radio store, None until the first press.

pub fn seed_store(
  window_id window_id: String,
  widget_id widget_id: String,
  store store: types.WidgetStore,
) -> Nil

Seed a widget store for pure render tests — the runtime equivalent is the engine’s automatic stash before user code. Merges into the current stash.

pub fn select(
  id id: String,
  items items: fn(
    state,
    bot.Context(session, error, dependencies),
  ) -> List(SelectItem),
  columns columns: Int,
  on_selected on_selected: fn(
    state,
    String,
    bot.Context(session, error, dependencies),
  ) -> Result(types.DialogAction(state), error),
) -> types.KeyboardWidget(state, session, error, dependencies)

One-shot choice: each item is a button, a press calls on_selected with the item id and the resulting DialogAction is applied (usually a Goto). Nothing is stored. columns lays the buttons out in a grid (1 = one item per row).

pub fn widget_store(
  ctx: bot.Context(session, error, dependencies),
  window_id window_id: String,
  widget_id widget_id: String,
) -> types.WidgetStore

Read a widget’s store from inside a window render or handler. Returns an empty store when the widget has no state yet. Prefer the typed readers on top: radio_value, multiselect_values, current_page.

Search Document