First piloted slice of the closed architecture: a runtime that interprets
the morfo declaration and writes mutable attrs to the DOM via dom.apply,
removing the need for the provider to hand-roll resolveMorfoProps bindings
on every part.
src/uix/soma/morfo/
- resolver.ts — pure morfo → attrs resolver, extracted from Provider so
both legacy Provider (still in place) and the new runtime can share it
- runtime.svelte.ts — `createMorfoRuntime(morfo, sources)` with V1 surface:
- registerPart(part, opts) — registers per-instance id/ref/sources and
sets up a $effect that reapplies attrs whenever sources change
- partProps(part) — returns ONLY identity (id + marker + ref attachment),
never mutable attrs (those go through dom.apply)
- runtime.svelte.test.ts — 4 tests verifying initial application, reactive
reapplication, and unknown-part rejection
ARIA stateRef refinement
The shared resolver now stringifies ARIA stateRef values to 'true'/'false'.
Boolean false on aria-* must mean "explicitly unpressed/unexpanded", not
"attribute absent" — the previous boolean return wired into dom.apply's
`false → removeAttribute` semantics, which is correct for data-* presence
flags but wrong for ARIA. Distinct contracts; resolver decides at the
boundary, not dom.apply.
Toggle morfo
Added explicit `value` sources to all data entries. The legacy provider
hard-coded data-state etc.; the runtime needs the morfo to declare where
each attr's value comes from. Now data-state references stateRef('on') and
data-disabled / data-readonly / data-required / data-invalid reference
their corresponding propRef with prop-truthy conditions.
Toggle provider migration
- ToggleProvider creates a MorfoRuntime in its constructor with Soma's dom.
- registerPart('provider', { id, ref }) wires the runtime to the button.
- props derivation now returns only:
- runtime.partProps('provider') — id + data-toggle + ref attachment
- disabled (HTML attr; not in morfo by design — primitive button concern)
- onclick handler
- All morfo-declared attrs (data-state, aria-pressed, data-disabled,
aria-disabled, aria-label, etc.) are written by the runtime's effect via
dom.apply.
Verification
- Unit tests: 4/4 morfo runtime + full focused suite green.
- morfo:check: 66/66 — Toggle's emitted DOM matches the morfo declaration
end-to-end now that data-* sources are pinned.
- smoke: 68/68 routes 200 OK.
- svelte-check: no new errors.
V2 (deferred — not part of this pilot):
- runtime.keydown(part, event) for morfo.keyboard dispatch.
- runtime.trigger(eventName) — prewrite + semantic.emit + handler chain
(Toast will be the first component to exercise this).
- OptsFromProps + bindProps helper to absorb the props bridge boilerplate.