A per-surface layout tree: the taffy engine plus the node→rect-signal registry. The layout tree is
a per-surface world so nodes can be created and laid out from anywhere — including reactive effects
(reactive lists) that fire from an effect body. Under M3 several surfaces share one UI thread, so the
runner activates each surface’s LayoutContext around its build/event/frame; app code just calls
the free functions, which operate on whichever surface is currently active.
The node’s WINDOW-absolute rect (top-left from the top-level walk, size from its layout), or None if it
has not been laid out under a window root yet. Unlike track_layout, this is correct even for a node in a
sub-root computed separately (whose rect signal is root-local) — use it to anchor a portaled overlay to a
trigger, since the portal hoists out of ancestor transforms and needs absolute coordinates.
Attaches node (an overlay’s out-of-flow content) as an extra child of the current layout host — the
top-level root computed against the window — so it fills the viewport regardless of where the overlay
was declared in the tree. Returns true when attached; false when no host has been computed yet (the
caller then falls back to normal in-tree layout). The host is marked dirty so the next frame lays the
portal out.
Lays out root against the given space and reflects the result into each node’s rect signal.
Collects the (signal, rect) updates while holding the runtime borrow, then applies them in a batch
after releasing it — a rect .set() can flush effects, and one of those may itself touch the
layout runtime (a reactive list), which would re-enter the borrow.
Whether node is a flex row (main axis horizontal). A transparent for … gap:N fragment reads its host
container’s axis to know which edge the per-item gap margin sits on.
Detaches an overlay’s content from the layout host (inverse of attach_overlay); the caller frees it
afterwards with remove_node. A no-op if the host is gone.
Whether node is ancestor or sits anywhere beneath it. Follows the parent links the runtime records, so
it crosses into a separately-computed sub-root (a scroll’s content) the way the layout tree does.
A leaf whose intrinsic size is computed by measure at layout time (e.g. text
whose height depends on how many lines it wraps into at the resolved width).
Pins the overlay host to node — the app’s window-spanning root — so overlays always fill the viewport
even when the app computes several independent layout roots (e.g. a shell with a separate sidebar root
computed after the main one, which the auto-detection would otherwise pick as the host). Call it each
relayout with the current main root (it survives hot-reload rebuilds, which mint a new root node). Once
pinned, auto-detection no longer overrides the host.
The area an overlay may occupy: the laid-out rect of the host its content is attached to, which is the
window (or the surface) it will be composed into.
Re-lays out every root that has been computed at least once, picking up any nodes a reactive change
dirtied since the last frame. Each compute_layout early-returns when its root is clean and the space
is unchanged, so this is cheap on a still frame. The runtime calls it once per redraw (after flushing
reactive effects, before rendering) so a data change deep in the tree — e.g. a reactive list adding an
item — is reflected in layout without the app shell knowing about it. Node dirtiness propagates up to
the root through taffy, so a dirtied list container makes its root recompute.
Detaches and frees node (a former list item) from the runtime: removes it from the layout tree and
drops its rect signal and bookkeeping. The caller must have removed it from its parent’s child list
(via set_children) first.
Resets the active surface’s layout runtime to a fresh, empty tree. The single-window app/preview harness
calls this at construction; a multi-surface runner instead gives each surface its own LayoutContext.
Replaces parent’s children with children, in order, marking parent dirty. Operates on the
thread-local runtime; parent must be a container already registered in the runtime.
Lays node’s children along the horizontal axis, after the node was built as a column. A reconciling
list boxed inside a row calls this: its own node exists before it is attached, so the direction it
should have cannot be known at construction.
Shows or hides a node in layout flow. A hidden node takes no space (and lays out none of its subtree); mark an ancestor dirty and recompute for the change to take effect. Used for responsive layouts (e.g. collapsing a sidebar on narrow windows).
Sets node’s leading main-axis margin (left for a row host, top for a column) to px — the primitive
a transparent for … gap:N uses to space its items without a container of its own. Marks the node dirty.
Sets node’s minimum height to px after the initial layout (dirtying it, which propagates up), so a
content-measured leaf grows to at least px even when its content is shorter. A scrolling editor uses it
to fill its viewport so a click anywhere in the empty area — not just over the text — lands on the leaf.
Reactive read of the active direction — subscribes the caller, for the rare widget that has to mirror
something layout cannot flip on its own (a chevron glyph, a directional icon).
Sets the distribution of space between and around content items.
For Flexbox it controls alignment in the main axis.
For Grid it controls alignment in the inline axis.
Per-node measure callback: given the available main-axis width, returns the
node’s intrinsic (width, height). Used for text nodes whose height depends on
how many lines the content wraps into at the resolved width.