Skip to content

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?

optional children?: readonly BarNode<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?

optional enabledWhen?: (inputs) => boolean

Defined in: modal/bar.ts:66

Rare override; default is the engine's derived canDispatch.

Parameters

inputs

BarInputs<Ctx>

Returns

boolean


hint

hint: KeyHint | ((inputs) => KeyHint | undefined)

Defined in: modal/bar.ts:62

Display row. RULE: the label must not vary with state (lit does).


hold?

optional hold?: 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?

optional kind?: "cap"

Defined in: modal/bar.ts:50


litWhen?

optional litWhen?: (inputs) => boolean

Defined in: modal/bar.ts:64

The cap renders highlighted (its mode/flag is engaged).

Parameters

inputs

BarInputs<Ctx>

Returns

boolean


oracle?

optional oracle?: 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?

optional payload?: unknown

Defined in: modal/bar.ts:54

Payload for the dispatch, when the command takes one.


remote?

optional remote?: 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?

optional showWhen?: (inputs) => boolean

Defined in: modal/bar.ts:68

The cap exists at all in this state (default: always).

Parameters

inputs

BarInputs<Ctx>

Returns

boolean