Skip to content

TermDOM 0.1.1

Choose a tag to compare

@brainkim brainkim released this 11 Aug 18:00
· 318 commits to main since this release

TermDOM now ships its own DOM and CSSOM

jsdom and cssstyle are gone. The DOM tree, mutation algorithms, events with shadow retargeting, live collections, ranges and selection, custom elements, and the full CSSOM — stylesheets, rules, declarations, computed and resolved values — are TermDOM's own, written against the specs with web-platform-tests as the referee (94,800+ DOM subtests passing at the swap, more fixed since). Parsing is parse5 and css-tree; selectors are nwsapi. Author-visible APIs follow one rule: spec-complete or absent. getComputedStyle resolved values now read real layout, styleEl.sheet returns the element's actual stylesheet, and ResizeObserver honors options.box.

Rendering changes to know about

  • Margin collapsing is now fully per CSS 2.2 §8.3.1 — including self-collapsing empty blocks and negative margins, which previously didn't parse. If a layout leaned on the old behavior, vertical gaps can shift. One knowing deviation: the body's edges stop the collapse.
  • Block containers are laid out by a real block algorithm instead of a flex emulation: gap and order no longer misapply to blocks, a wrapping flex container keeps its later lines inside its own box, and inline-flex establishes a formatting context.

Fixes

Around thirty rendering bugs found by a new differential fuzzer and property suite, among them: hidden (display: none) subtrees kept reporting geometry; content vanishing or misordering around blocks inside inlines and display: contents elements; nested inline-block content never laid out after edits; whitespace-only blocks under white-space: pre collapsing to nothing; hit-testing missing ::before content and dissolved boxes; a stray <svg> crashing style resolution; counter(x, lower-alpha) wrong past 26; vw/vh values stale across terminal resizes; multi-line pastes into a <textarea> arriving as one line (terminals send pasted newlines as CR); mouse coordinates disagreeing with painted cells in fixed and scrolled content.

Performance

Invalidation is targeted instead of global: a class flip on one row of a long list re-renders that row, not the document. Live-collection updates during bulk insertion went from quadratic to linear (a 5,000-item filter list: 1,243ms → 162ms per keystroke), and a heap leak that pinned removed nodes for the life of the process is fixed.

Examples and docs

examples/solitaire.ts is new and leads the README: full-keyboard Klondike (cursor, Tab, Enter), one- and three-card draw from a <dialog> menu, responsive card sizes via @media, fullscreen, a speedrun clock with per-deal bests — deals are seeded, and node examples/solitaire.ts 13 replays the demo GIF's game. The getting-started guide gains verified framework recipes: React 19, Vue 3.5, Svelte 5, and Crank each mount with a few lines of globals.

For contributors

npm test now carries a differential fuzzer regression net (incremental rendering must equal fresh rendering, byte for byte, over 31 historical seeds) and six fast-check properties covering rendering, computed styles, geometry/hit-testing agreement, resize round-trips, serialization fixpoints, and field editing against a reference model.