AshUi.Patch.Skeleton (ash_ui v0.1.0)

Copy Markdown View Source

Target-specific static skeleton compiled from a resource's lowered view: interleaved static markup + ordered dynamic refs, the exact statics/dynamics contract the host bridge's Rendered structs consume.

Compilation renders the view ONCE through the ordinary render pipeline (ViewRender → RenderTree.render → RenderTarget.Html) with unique alphanumeric sentinels substituted at every dynamic position, then splits the produced HTML on those sentinels. Statics are therefore byte-aligned with the full renderer by construction — themes, parts, aria, event bindings and attribute ordering all come from the same code path. The compiled skeleton is pure data + evaluator closures; the runtime render path never materializes a tree.

Dynamic refs (document order):

{:text, addr, eval}                 — escaped text position
{:attr_pair, addr, name, eval}      — whole ` name="value"` pair
{:attr_value, addr, name, eval}     — value embedded in a merged attr
{:branch, addr, cond_eval, arms}    — arms: %{true: skel|nil, false: skel|nil}
{:keyed, addr, items_eval, item}    — item: %{skeleton, as, index}
{:child, addr, resource}            — nested render(Resource, input)

addr is the SAME lowered address the patch table assigns its slots, so the changed-address set from AshUi.Patch.Runtime.changed_addresses/3 gates re-emission directly.

Summary

Functions

Compile the skeleton for a lowered view node of resource. base addresses the subtree: arm and item skeletons compile under their REAL address prefix (addr/t, addr/f, addr/*) so element addresses are unique across the whole table — binding keys depend on it.

Types

dyn()

@type dyn() ::
  {:text, String.t(), (term() -> term())}
  | {:attr_pair, String.t(), String.t(), (term() -> term())}
  | {:attr_value, String.t(), String.t(), (term() -> term())}
  | {:branch, String.t(), (term() -> term()),
     %{true: t() | nil, false: t() | nil}}
  | {:keyed, String.t(), (term() -> term()), map()}
  | {:child, String.t(), module()}

t()

@type t() :: %AshUi.Patch.Skeleton{
  dynamics: [dyn()],
  fingerprint: term(),
  root?: term(),
  statics: [binary()]
}

Functions

compile(resource, lowered, opts \\ [])

@spec compile(module(), map() | nil, keyword()) :: t()

Compile the skeleton for a lowered view node of resource. base addresses the subtree: arm and item skeletons compile under their REAL address prefix (addr/t, addr/f, addr/*) so element addresses are unique across the whole table — binding keys depend on it.