plushie/native_widget

Native widget system for custom Rust-backed widget types.

Plushie supports two kinds of custom widgets:

Native widgets

A native widget is defined by creating a NativeDef and registering it. The widget’s Rust crate handles rendering and event emission; the Gleam side provides the typed builder API.

import plushie/native_widget
import plushie/node.{type Node}
import plushie/prop/color
import plushie/prop/length

// Define the native widget
pub const gauge_def = native_widget.NativeDef(
  kind: "gauge",
  rust_crate: "native/my_gauge",
  rust_constructor: "my_gauge::GaugeExtension::new()",
  props: [
    native_widget.NumberProp("value"),
    native_widget.NumberProp("min"),
    native_widget.NumberProp("max"),
    native_widget.ColorProp("color"),
    native_widget.LengthProp("width"),
  ],
  commands: [
    native_widget.CommandDef("set_value", [native_widget.NumberParam("value")]),
  ],
)

// Build a gauge widget
pub fn gauge(id: String, value: Float, opts: List(GaugeOpt)) -> Node {
  native_widget.build(gauge_def, id, [
    #("value", node.FloatVal(value)),
    ..gauge_opts_to_props(opts)
  ])
}

// Send a command to a gauge
pub fn set_gauge_value(node_id: String, value: Float) -> Command(msg) {
  native_widget.command(gauge_def, node_id, "set_value", [
    #("value", node.FloatVal(value)),
  ])
}

Composite widgets

Composite widgets are simpler: they’re just functions that return Node trees. No registration or Rust code needed.

import plushie/node.{type Node}
import plushie/ui
import plushie/prop/padding

// A labeled input composite widget
pub fn labeled_input(
  id: String,
  label: String,
  value: String,
  children: List(Node),
) -> Node {
  ui.column(id, [column.Spacing(4)], [
    ui.text_(id <> "-label", label),
    ui.text_input(id <> "-input", value, []),
    ..children
  ])
}

Types

Command definition for a native widget.

pub type CommandDef {
  CommandDef(name: String, params: List(ParamDef))
}

Constructors

  • CommandDef(name: String, params: List(ParamDef))

Definition of a native widget.

Describes the Rust crate, constructor, props, and commands that a native widget supports. Used at compile time to configure the plushie binary build and at runtime to construct nodes and commands.

pub type NativeDef {
  NativeDef(
    kind: String,
    rust_crate: String,
    rust_constructor: String,
    props: List(PropDef),
    commands: List(CommandDef),
  )
}

Constructors

  • NativeDef(
      kind: String,
      rust_crate: String,
      rust_constructor: String,
      props: List(PropDef),
      commands: List(CommandDef),
    )

    Arguments

    kind

    Widget kind string (e.g., “gauge”). Must match the Rust crate’s registered widget type name.

    rust_crate

    Path to the Rust crate relative to the project root (e.g., “native/my_gauge”).

    rust_constructor

    Rust expression to construct the widget instance (e.g., “my_gauge::GaugeExtension::new()”).

    props

    Declared properties with their types, for documentation and build tooling validation.

    commands

    Declared commands that can be sent to this widget type.

Parameter definition for native widget commands.

pub type ParamDef {
  NumberParam(name: String)
  StringParam(name: String)
  BooleanParam(name: String)
}

Constructors

  • NumberParam(name: String)
  • StringParam(name: String)
  • BooleanParam(name: String)

Property definition for a native widget.

pub type PropDef {
  NumberProp(name: String)
  StringProp(name: String)
  BooleanProp(name: String)
  ColorProp(name: String)
  LengthProp(name: String)
  PaddingProp(name: String)
  AlignmentProp(name: String)
  FontProp(name: String)
  StyleProp(name: String)
  MapProp(name: String)
  AnyProp(name: String)
  ListProp(name: String, inner: String)
}

Constructors

  • NumberProp(name: String)
  • StringProp(name: String)
  • BooleanProp(name: String)
  • ColorProp(name: String)
  • LengthProp(name: String)
  • PaddingProp(name: String)
  • AlignmentProp(name: String)
  • FontProp(name: String)
  • StyleProp(name: String)
  • MapProp(name: String)
  • AnyProp(name: String)
  • ListProp(name: String, inner: String)

Values

pub fn build(
  def: NativeDef,
  id: String,
  props: List(#(String, node.PropValue)),
) -> node.Node

Build a node for a native widget.

Creates a Node with the native widget’s kind and the given props. Props are passed as key-value pairs already encoded to PropValue.

pub fn build_container(
  def: NativeDef,
  id: String,
  props: List(#(String, node.PropValue)),
  children: List(node.Node),
) -> node.Node

Build a container node for a native widget with children.

pub fn command(
  def: NativeDef,
  node_id: String,
  op: String,
  payload: List(#(String, node.PropValue)),
) -> command.Command(msg)

Create a native widget command targeting a specific widget instance.

The command is sent via the wire protocol’s unified command message type and delivered to the Rust widget by node ID.

pub fn command_names(def: NativeDef) -> List(String)

Get the command definition names from a native widget definition.

pub fn commands(
  def: NativeDef,
  cmds: List(#(String, String, List(#(String, node.PropValue)))),
) -> command.Command(msg)

Create a batch of native widget commands.

pub fn prop_names(def: NativeDef) -> List(String)

Get the prop definition names from a native widget definition.

pub fn validate(def: NativeDef) -> Result(Nil, List(String))

Validate a native widget definition at runtime.

Returns Ok(Nil) when valid, or Error(errors) with a list of human-readable validation failure messages.

Checks performed:

  • kind must be non-empty
  • No duplicate prop names
  • No reserved prop names (id, type, children, a11y)
  • Command names must be safe native operation names
Search Document