# `Plushie.Widget`
[🔗](https://github.com/plushie-ui/plushie-elixir/blob/v0.7.2/lib/plushie/widget.ex#L1)

Macro-based DSL for declaring Plushie widgets.

Supports two kinds of widget:

- `:native_widget` - backed by a Rust crate implementing the
  `PlushieWidget` trait. Requires `rust_crate` and `rust_constructor`
  declarations.
- `:widget` - pure Elixir widget. Features are detected at compile
  time based on what callbacks are defined:
  - Has `state` declarations -> stateful (deferred view, state
    persistence via the runtime).
  - No `state` -> stateless (immediate view in `new/2`).
  - Has `handle_event/2` -> participates in event dispatch.
  - Has `subscribe/2` -> widget-scoped subscriptions.

## Usage

    defmodule MyApp.Gauge do
      use Plushie.Widget, :native_widget

      widget :gauge

      field :value, :float
      field :min, :float, default: 0
      field :max, :float, default: 100
      field :color, Plushie.Type.Color, default: :blue
      field :width, Plushie.Type.Length
      field :height, Plushie.Type.Length

      rust_crate "native/my_gauge"
      rust_constructor "my_gauge::GaugeWidget::new()"

      event :value_changed, fields: [value: :float]
      command :set_value, value: :float
    end

## Generated code

The macro generates:

- `type_names/0` - returns `[:gauge]` (from the `widget` declaration)
- `native_crate/0` - returns the `rust_crate` path (native_widget only)
- `rust_constructor/0` - returns the Rust expression (native_widget only)
- `new/2` - creates a `%Module{}` struct ()
- Setter functions per field for pipeline composition
- `with_options/2` - applies keyword options via setters
- `build/1` - converts the struct to a `ui_node()` map
- `@type t`, `@type option` - typespecs for dialyzer
- `Plushie.Widget` protocol implementation
- `__event_specs__/0`, `__event_spec__/1` - typed event metadata
- Command functions (native_widget only) that wrap
  `Plushie.Command.widget_command/3`

## Field types

Field types are resolved via `Plushie.Type.resolve/1`. Primitive
atom shortcuts (`:integer`, `:float`, `:string`, `:boolean`,
`:atom`, `:any`, `:map`), `Plushie.Type` module names (e.g.
`Plushie.Type.Color`), and composite forms (`{:list, :string}`)
are accepted. Values are stored raw; `Tree.normalize/1` handles
wire encoding in a single pass.

## Composite widgets

If the using module defines `view/2` (leaf) or `view/3` (container),
`new/2` delegates to it after resolving props:

    defmodule MyApp.LabeledInput do
      use Plushie.Widget

      widget :labeled_input

      field :label, :string

      def view(id, props) do
        import Plushie.UI
        column id: id do
          text(props.label)
        end
      end
    end

### view/2 vs view/3

Use `view/2` for simple widgets:

    def view(id, props) do
      %{id: id, type: "text", props: %{content: props.label}, children: []}
    end

Use `view/3` when the widget has state (declared via `state`).
The third argument is the widget's internal state map:

    def view(id, props, state) do
      fill = if state.hover, do: "#ff0", else: "#ccc"
      ...
    end

## Common options

Widgets that support accessibility or event rate limiting declare
these as normal fields:

- `field :a11y, Plushie.Type.A11y, merge: true` - accessibility
  overrides (see `Plushie.Type.A11y`). The `merge: true` option
  makes the setter merge user values with widget defaults.
- `field :event_rate, :integer` - maximum events per second for
  coalescable events from this widget.

# `child`

```elixir
@type child() :: ui_node() | struct()
```

A child element: either an already-resolved node map or a widget struct.

# `ui_node`

```elixir
@type ui_node() :: Plushie.Tree.Node.ui_node()
```

A UI tree node map. Every widget builder returns this shape.

# `native_crate`
*optional* 

```elixir
@callback native_crate() :: String.t()
```

Path to the Rust crate relative to the package root.

# `rust_constructor`
*optional* 

```elixir
@callback rust_constructor() :: String.t()
```

Full Rust constructor expression for the widget.

# `type_names`

```elixir
@callback type_names() :: [atom()]
```

Node type atoms this widget handles.

# `to_node`

```elixir
@spec to_node(struct()) :: ui_node()
```

Converts a widget struct to a `ui_node()` map via the Tree.Node protocol.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
