Critical fixes: - Restructure pointers.md: move setNode prop-key writes section under its own heading (was incorrectly nested under selectNode) - Add Context/Density/Direction/RenderContext documentation section to host-config.md (was only a brief constraint bullet) - Advance all 5 ADRs from Status: Proposed → Accepted and frontmatter from status: draft → status: stable (decisions are driving implementation) - Add error handling philosophy section to README Warning/suggestion fixes: - Add isUElement null check (node !== null) to schema.md discriminator table - Add UjsxEnvelope convenience type documentation to events.md - Add Direction Unicode arrow naming note to transforms.md - Standardize all cross-references from absolute docs/research/ paths to relative ../research/ paths across all architecture docs - Fix schema.md ADR references to use relative paths - Reduce redundancy between transforms.md and host-config.md Direction notes - Update all architecture doc frontmatter from draft → stable Deferred: - Performance model section (reconciler not yet built) - Concepts/glossary document (low ROI at current scale) - Line counts in source references (would date quickly)
35 lines
2.1 KiB
Markdown
35 lines
2.1 KiB
Markdown
---
|
|
status: stable
|
|
last_updated: 2026-05-18
|
|
---
|
|
|
|
# ADR-003: Preact signals-core for reactivity
|
|
|
|
**Status**: Accepted
|
|
|
|
## Context
|
|
|
|
UJSX needs a reactive primitive for propagating changes through element trees. The reactive layer (ReactiveRoot, reactiveComponent, reactiveElement) needs signal, computed, effect, and batch operations.
|
|
|
|
## Alternatives Considered
|
|
|
|
- **Custom reactive implementation**: Write a signal/computed/effect system from scratch. Rejected because writing a correct implementation (cycle detection, batch scheduling, lazy evaluation) is non-trivial and Preact's implementation is battle-tested.
|
|
- **Solid.js reactive primitives**: Use Solid's reactive system. Rejected because they're coupled to Solid's render cycle and not published as a standalone package.
|
|
- **Vue reactivity**: Use Vue's reactive system. Rejected because it uses Proxy-based tracking which has different performance characteristics and isn't designed for tree-agnostic use.
|
|
- **RxJS**: Use observables for reactivity. Rejected because it's an observable/stream model, not a reactive state model. Different paradigm, much larger API surface.
|
|
|
|
## Decision
|
|
|
|
Use `@preact/signals-core` as the reactive layer. Re-export its primitives (`signal`, `computed`, `effect`, `batch`) and types (`Signal`, `ReadonlySignal`) from the UJSX reactive module.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- Proven implementation with ~800 lines of battle-tested code, used in Preact and adopted by other frameworks.
|
|
- Small dependency surface — `@preact/signals-core` has zero dependencies.
|
|
- Batch scheduling is built-in, matching the reconciliation model planned for the reconciler.
|
|
- Future consumers (flowgraph reactive host) can use the same signal/computed/effect primitives without a different reactive library.
|
|
|
|
### Negative
|
|
- UJSX re-exports Preact signals, creating a coupling. If Preact signals changes its scheduling model, UJSX is affected.
|
|
- The `effect` return value (dispose function) is currently discarded in reactiveComponent/reactiveElement — the dispose functions are no-ops. This is a known gap that the reconciler work addresses. |