@watervein/dom-core
v0.1.54-dev.2
Published
Watervein DOM core package
Maintainers
Readme
@watervein/dom-core
The DOM rendering orchestration layer for Watervein. It binds @watervein/core's Node Edge System (NES) graph directly to the browser DOM, handling node scheduling, non-VNode control flows, and reactive template patching.
Key Features
- Zero-Virtual DOM Tracking: Binds reactive graph nodes (
WvNode) directly to specific DOM attributes, text pieces, and style properties viacreateEffect. - Marker-Based Control Flow: Uses hidden anchor text nodes (
document.createTextNode("")) anddisplay: contentswrapper elements to pivot conditional views (Show) and lists (For) without disrupting layout. - Single-Pass List Reconciliation: The
Forhelper generates, destroys, and reorders entities within one reactive pass, using a reversed-indexinsertBeforesweep to keep DOM mutation cost close to $O(N)$ per update. - Polymorphic Style & Class Binder: Handles object-literal style/class tracking, reactive function values, and direct atomic updates without re-triggering broad element repaint.
Installation
pnpm add @watervein/core @watervein/dom-coreCore API & Component Structures
element(tag, props, children)
The structural primitive builder for HTML tags. Processes event listeners (on*), reactive attributes, arrays of children, and nested graph callbacks.
import { element } from '@watervein/dom-core';
import { createState, write } from '@watervein/core';
const bg = createState("blue");
// Generates an HTMLElement with a live style binding tied to the graph
const button = element("button", {
style: { backgroundColor: bg },
onclick: () => write(bg, "red")
}, "Click Me");Show(condition, thenFn, elseFn?)
A reactive conditional rendering boundary. Uses @watervein/core's matchEntity internally to destroy the previous branch's entity (and all of its reactive nodes) whenever the condition flips.
import { Show } from '@watervein/dom-core';
const isLogged = createState(false);
const view = Show(
isLogged,
() => element("div", {}, "Welcome Back!"),
() => element("div", {}, "Please Log In")
);For<T>(listNode, keyFn, renderFn)
A keyed list renderer backed by a flat cache (entryCache, keyed by keyFn). On each update it destroys entities/DOM for removed keys, creates entities/DOM for new keys, and repositions existing DOM nodes to match the new order — all within a single createEffect, iterating the list backwards.
import { For } from '@watervein/dom-core';
const items = createState([{ id: 1, text: "Task A" }]);
const listView = For(
items,
(item) => item.id,
(getItem, getIndex) => element("li", {}, () => getItem().text)
);Mount Helpers
Lightweight mounting helpers to attach a graph's root element to the document.
import { mount, mountToBody, mountToHead, mountToRoot } from '@watervein/dom-core';
// Standard target mount
mount(document.getElementById("app")!, myLayout);
// Global scopes
mountToBody(modalContainer);Deep Performance Architecture (The List Engine)
For performs generation, destruction, and reordering in a single backward pass over the list, so a newly-inserted item is placed at the correct DOM position within the same reactive flush that created it — there's no separate "reorder" pass that could run before the "create" pass has registered the new entity.
graph TD
Start["[ For's createEffect runs ]"]
Diff["Diff current keys against previous keys"]
Destroy["Destroy entities/DOM for removed keys<br>(via DestructionSystem.destroyEntities)"]
Walk["Walk the list backwards (len - 1 .. 0)"]
Start --> Diff
Diff --> Destroy
Destroy --> Walk
Walk --> ChoiceCached{"Key already cached?"}
ChoiceCached -- Yes --> UpdateExisting["write() updated item/index<br>into existing nodes"]
ChoiceCached -- No --> CreateNew["createEntity + renderFn,<br>cache the resulting DOM"]
UpdateExisting --> CheckAnchor
CreateNew --> CheckAnchor
CheckAnchor{"Is el.nextSibling !== anchor?"}
CheckAnchor -- YES --> Insert["wrapper.insertBefore(el, anchor)"]
CheckAnchor -- NO --> Skip["skip (already in the correct position)"]
style ChoiceCached fill:#fff3cd,stroke:#ffc107,stroke-width:1px
style CheckAnchor fill:#fff3cd,stroke:#ffc107,stroke-width:1px
style Skip fill:#e2e3e5,stroke:#6c757d,stroke-width:1px
style Insert fill:#d4edda,stroke:#155724,stroke-width:1pxBackwards DOM Drift Avoidance: Walking the list from the end avoids the classic issue where shifting one element forces a layout recalculation cascade across its siblings, since each
anchoris already resolved by the time its predecessor is placed.True Componentless Lifecycles: Since there are no nested class-based components, lifecycle teardown happens directly through
@watervein/core's entity registry. When a keyed row is removed, its entity is destroyed and every dependent node/edge is pruned from the reactive graph in the same pass.
License
This project is licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
