v0.4.0
[0.4.0] - 2026-03-22
Breaking
- Project renamed from toddy to plushie. All module names (
Toddy.*
->Plushie.*), config keys (:toddy->:plushie), environment
variables (TODDY_*->PLUSHIE_*), and mix tasks (toddy.*->
plushie.*) have changed. - Canvas shapes are now typed structs instead of plain maps. Builder
functions (rect,circle,line,text,path,image,svg,
stroke,linear_gradient) return struct instances (%Rect{},
%Circle{}, etc.) withPlushie.Encodeprotocol implementations.
Code that pattern-matched on%{type: "rect"}must use%Rect{}. import Plushie.Canvas.Shapeno longer needed forgroup,layer,
orinteractivein canvas blocks. Useimport Plushie.UIinstead.
Canvastext,image, andsvgcalls are automatically resolved
inside canvas/layer/group blocks.- Test backend renamed:
:pooled_mock->:mock,
Plushie.Test.Backend.Pooled->Plushie.Test.Backend.MockRenderer.
The env var value changes:PLUSHIE_TEST_BACKEND=mock(was
pooled_mock).Plushie.Test.MockBridgerenamed to
Plushie.Test.InternalMockBridge(@moduledoc false). Padding.encode/1renamed toPadding.cast/1(normalization, not
wire encoding).
Added
- Block-form options for all widgets. Every leaf widget and canvas
shape supports a do-block syntax for declaring options:button "save", "Save" do style :primary padding %{top: 10, bottom: 10} end
- Container inline props. Container widgets (column, row, container,
etc.) accept option declarations directly in their do-blocks, mixed
with children:column do spacing 8 padding 16 text("Hello") end
- Nested do-blocks for struct-typed options. Options like
padding,
a11y,border,shadow, andstylesupport nested do-blocks that
construct typed structs:container "card" do border do width 1 color "#ddd" rounded 8 end shadow do color "#0000001a" offset_y 2 blur_radius 8 end text("Content") end
interactivedirective with id-first syntax, keyword form, block
form, and pipe form for canvas shape interactivity.Plushie.DSL.Buildablebehaviour -- formal contract for types
participating in the DSL block-form pattern (from_opts/1,
__field_keys__/0,__field_types__/0).- Compile-time validation everywhere. All widget block forms validate
option keys at compile time. Using an option that doesn't belong to
the current widget produces a helpful error. Canvas blocks validate
every call against its context (canvas/layer/group). - Context-aware
canvas_scopewalker validates and rewrites calls
inside canvas blocks. Wrong-aritytext/image/svgcalls,
widget macros, and misplaced shapes produce compile-time errors. - Context-aware
container_scopewalker validates container options.
Using an option on the wrong container lists which containers support
it. - New value structs --
ShapeStyle(hover/pressed overrides),
DragBounds,HitRect,Dash, plusPaddingandFontconverted
from utility types to proper structs. - Extension DSL integration -- extension widgets automatically
generateBuildablecallbacks and option metadata fromprop
declarations. - Tree normalizer leak detection -- shape structs and DSL metadata
tuples in the widget tree produce clear error messages. - Event coalescing --
max_rateon subscriptions,event_rateon
widgets, host-side pending coalesce buffer for mouse moves and sensor
resizes. - Three transport modes --
:spawn(default),:stdio(for
plushie --exec), and{:iostream, pid}(for SSH/TCP/custom). - Canvas interactive shapes -- renderer-side hit testing with click,
hover, drag, focus events via theinteractivefield on shapes. docs/dsl-internals.md-- maintainer guide for the DSL
architecture, Buildable behaviour, and scope walkers.--wasmflag formix plushie.downloadandmix plushie.build.bin/plushiesymlink created bymix plushie.downloadfor
stable path references without the platform-specific name.mix plushie.connectreplacesmix plushie.stdio. Connects to
the renderer via Unix socket or TCP instead of stdin/stdout. Token
auth via Settings message.- Doc-sync tests linking doc code blocks to test functions via
HTML comment markers.
Changed
-
Downloaded binaries moved from
priv/bin/to_build/plushie/bin/.
Build artifacts belong in_build/wheremix cleanremoves them. -
mix plushie.stdiorenamed tomix plushie.connect. The old
stdin/stdout transport is still available as a fallback when
PLUSHIE_SOCKETis not set. -
Plushie.UIis now the single macro/DSL layer. All shape macros
(rect,circle,group,layer, etc.), path commands, transforms,
clips, and gradients are available viaimport Plushie.UI. -
Plushie.Canvas.Shapeis now a pure-function module (no macros).
Import it directly only for helper functions outside canvas blocks. -
All
Encodeprotocol implementations moved to their respective struct
module files.Plushie.Encodecontains only the protocol definition
and primitive implementations. -
Widget struct field types tightened to reference specific type modules
(e.g.,Plushie.Type.Padding.t()instead ofterm()). -
Canvas widget type annotations use
canvas_shape()union type. -
@widget_callsderived from component lists instead of manually
maintained. -
Doc code examples use
use Plushie.Appinstead of
@behaviour Plushie.App(the latter misses default implementations
of optional callbacks likewindow_config/1).