@bimetal/headless-core
v0.35.0
Published
Domain-neutral headless controller core: identity-stable getSnapshot/subscribe (the useSyncExternalStore contract), a version bus, and an errors-as-state surface. The shared blueprint every component controller (Calendar, Kanban, …) composes — so the subt
Maintainers
Readme
@bimetal/headless-core
Domain-neutral controller core shared by the BIMETAL component family (Calendar, Kanban, …). Zero dependencies.
It owns the generic ~30% that every component controller needs and that is treacherous to copy correctly:
- Identity-stable
getSnapshot— returns the same reference until the version actually moves. This is theuseSyncExternalStorecontract; getting it wrong causes render loops or stale UI. - A version bus —
markChanged()bumps the version and notifies subscribers;subscribe(listener)/destroy(). - Errors-as-state —
setLastAction/getLastAction/dismissLastActionso rule violations and WIP rejections surface as a snapshot field (a toast) instead of throwing in the render path.
import { createControllerCore } from '@bimetal/headless-core';
const core = createControllerCore({ buildSnapshot: () => buildMySnapshot() });
// component intents mutate local state, then call core.markChanged()Component controllers (createCalendarController, createKanbanController)
compose one of these and add only their interaction semantics. Framework
bindings consume the SnapshotSource<TSnapshot> contract — { getSnapshot,
subscribe, destroy } — generically, so a single per-framework binding drives
every component.
