Interface: CapSpec<Ctx>
Defined in: modal/bar.ts:49
@habemus-papadum/aiui-viz/modal — the modal interaction kit.
The distilled shape of the retired dev overlay's modal system (armed modes, layered keymaps, mode-dependent surfaces, guarded async effects), extracted per handoff/modal-interaction-lessons.md so viz apps get the bug classes designed out instead of re-learned: modes as data with a mechanical Esc ladder, keymap layers whose claim-or-pass is exhaustive by construction, a reconciler that asserts surface invariants from state on every event, effects that re-validate at completion time under a ceiling, focus as tracked state, and the shared word-diff flash (one visual language, one tempo, for "this text changed in front of you").
The kit's modules do NOT own state — but the kit now also ships the composition layer both intent clients used to hand-roll: the mode engine (engine.ts — regions + a pure command reducer + mechanical esc/blur + atomic commit), claims (claims.ts — derived async operations with per-claim status; the end of hand-called sync* functions), and the bar projection (bar.ts — caps as renders of the spec). Apps that want the engine give it their state wholesale; apps with their own architecture keep using the modules à la carte. Design doc: the mode-engine spec (git history). The Solid adapter (solidModeEngine) lives in the package root, keeping this subpath framework-free.
Realm rules: no Solid import, no DOM access at module scope (DOM only inside install/render functions), so this subpath is safe to import from node (aiui-lowering-pipeline re-exports wordDiff to the channel) and from workers.
Type Parameters
Ctx
Ctx
Properties
children?
optionalchildren?: readonlyBarNode<Ctx>[]
Defined in: modal/bar.ts:88
Revealed one depth down while this cap is shown AND lit.
command
command:
string
Defined in: modal/bar.ts:52
The command a tap dispatches — the same resolver path as the key.
enabledWhen?
optionalenabledWhen?: (inputs) =>boolean
Defined in: modal/bar.ts:66
Rare override; default is the engine's derived canDispatch.
Parameters
inputs
BarInputs<Ctx>
Returns
boolean
hint
Defined in: modal/bar.ts:62
Display row. RULE: the label must not vary with state (lit does).
hold?
optionalhold?:object
Defined in: modal/bar.ts:60
A press-and-HOLD cap (push-to-talk): the host binds pointer down/up to these commands instead of click. command stays the identity/enabled probe (usually the same as hold.down).
down
down:
string
up
up:
string
kind?
optionalkind?:"cap"
Defined in: modal/bar.ts:50
litWhen?
optionallitWhen?: (inputs) =>boolean
Defined in: modal/bar.ts:64
The cap renders highlighted (its mode/flag is engaged).
Parameters
inputs
BarInputs<Ctx>
Returns
boolean
oracle?
optionaloracle?:boolean
Defined in: modal/bar.ts:86
This cap belongs to the ORACLE subset — a voice agent embedded in the host may press it. Static per node, exactly like remote: membership is a property of the affordance, not the moment, and the moment is already covered by the engine's own canDispatch.
Absent means no, which is the whole reason it is declared rather than deny-listed: a cap added later is excluded until someone deliberately opts it in. A deny-list is safe only until the next commit.
payload?
optionalpayload?:unknown
Defined in: modal/bar.ts:54
Payload for the dispatch, when the command takes one.
remote?
optionalremote?:boolean
Defined in: modal/bar.ts:75
This cap belongs to the REMOTE subset — carried onto the projected view so a remote-bar host can filter its projection to what a bar-only remote (the iPad) may see and tap. Static per node (not a predicate): membership is a property of the affordance, not the moment. Absent ⇒ desktop-only.
showWhen?
optionalshowWhen?: (inputs) =>boolean
Defined in: modal/bar.ts:68
The cap exists at all in this state (default: always).
Parameters
inputs
BarInputs<Ctx>
Returns
boolean