@streetui/dsl 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +112 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -1
- package/dist/index.d.ts +78 -1
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ function applyA11yProps(props, options) {
|
|
|
60
60
|
if (options.ariaCurrent !== void 0) props["aria-current"] = String(options.ariaCurrent);
|
|
61
61
|
if (options.ariaInvalid !== void 0) props["aria-invalid"] = String(options.ariaInvalid);
|
|
62
62
|
if (options.ariaRequired !== void 0) props["aria-required"] = String(options.ariaRequired);
|
|
63
|
+
if (options.ariaModal !== void 0) props["aria-modal"] = String(options.ariaModal);
|
|
63
64
|
}
|
|
64
65
|
function containerProps(options) {
|
|
65
66
|
const props = {};
|
|
@@ -91,6 +92,49 @@ function reactiveListItemSignature(item) {
|
|
|
91
92
|
function reactiveListItemKey(item, index) {
|
|
92
93
|
return itemIdentity(item, index);
|
|
93
94
|
}
|
|
95
|
+
var OVERLAY_KINDS = {
|
|
96
|
+
dialog: {
|
|
97
|
+
role: "dialog",
|
|
98
|
+
modal: true,
|
|
99
|
+
takesFocus: true,
|
|
100
|
+
ariaModal: true,
|
|
101
|
+
defaultCloseOnEscape: true,
|
|
102
|
+
defaultRestoreFocus: true
|
|
103
|
+
},
|
|
104
|
+
popover: {
|
|
105
|
+
role: "dialog",
|
|
106
|
+
modal: false,
|
|
107
|
+
takesFocus: true,
|
|
108
|
+
ariaModal: false,
|
|
109
|
+
defaultCloseOnEscape: true,
|
|
110
|
+
defaultRestoreFocus: true
|
|
111
|
+
},
|
|
112
|
+
tooltip: {
|
|
113
|
+
role: "tooltip",
|
|
114
|
+
modal: false,
|
|
115
|
+
takesFocus: false,
|
|
116
|
+
ariaModal: false,
|
|
117
|
+
defaultCloseOnEscape: false,
|
|
118
|
+
defaultRestoreFocus: false
|
|
119
|
+
},
|
|
120
|
+
dropdown: {
|
|
121
|
+
role: "menu",
|
|
122
|
+
modal: false,
|
|
123
|
+
takesFocus: true,
|
|
124
|
+
ariaModal: false,
|
|
125
|
+
defaultCloseOnEscape: true,
|
|
126
|
+
defaultRestoreFocus: true
|
|
127
|
+
},
|
|
128
|
+
toast: {
|
|
129
|
+
role: "status",
|
|
130
|
+
modal: false,
|
|
131
|
+
takesFocus: false,
|
|
132
|
+
ariaModal: false,
|
|
133
|
+
ariaLive: "polite",
|
|
134
|
+
defaultCloseOnEscape: false,
|
|
135
|
+
defaultRestoreFocus: false
|
|
136
|
+
}
|
|
137
|
+
};
|
|
94
138
|
var ContentBuilderBase = class {
|
|
95
139
|
constructor(_node, _graph) {
|
|
96
140
|
this._node = _node;
|
|
@@ -363,6 +407,74 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
363
407
|
);
|
|
364
408
|
}, { id });
|
|
365
409
|
}
|
|
410
|
+
// ── Portals & overlays ──────────────────────────────────────────────────────
|
|
411
|
+
portal(key, builder, options = {}) {
|
|
412
|
+
const node = this._graph.createNode("portal", {
|
|
413
|
+
key,
|
|
414
|
+
parent: this._node,
|
|
415
|
+
props: containerProps(options)
|
|
416
|
+
});
|
|
417
|
+
builder(new ContainerBuilderImpl(node, this._graph));
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
421
|
+
* is a `when(open, panel)` conditional. The panel container carries the
|
|
422
|
+
* kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`
|
|
423
|
+
* descriptor is registered so the renderer wires focus/keyboard behavior to
|
|
424
|
+
* the same `open` signal that drives the panel. Reuses existing primitives
|
|
425
|
+
* (portal + when + container) — no new render path.
|
|
426
|
+
*/
|
|
427
|
+
_overlay(kind, key, options, builder) {
|
|
428
|
+
const graph = this._graph;
|
|
429
|
+
const portalNode = graph.createNode("portal", {
|
|
430
|
+
key,
|
|
431
|
+
parent: this._node,
|
|
432
|
+
props: { key }
|
|
433
|
+
});
|
|
434
|
+
const openBindable = options.open;
|
|
435
|
+
const openSignal = isSignal(openBindable) ? openBindable : (0, import_state.signal)(openBindable);
|
|
436
|
+
const panelOptions = {
|
|
437
|
+
role: options.role ?? kind.role,
|
|
438
|
+
...kind.ariaModal ? { ariaModal: true } : {},
|
|
439
|
+
...kind.ariaLive !== void 0 ? { ariaLive: kind.ariaLive } : {},
|
|
440
|
+
...options.class !== void 0 ? { class: options.class } : {},
|
|
441
|
+
...options.ariaLabel !== void 0 ? { ariaLabel: options.ariaLabel } : {},
|
|
442
|
+
...options.ariaLabelledBy !== void 0 ? { ariaLabelledBy: options.ariaLabelledBy } : {},
|
|
443
|
+
...options.ariaDescribedBy !== void 0 ? { ariaDescribedBy: options.ariaDescribedBy } : {}
|
|
444
|
+
};
|
|
445
|
+
const portalBuilder = new ContainerBuilderImpl(portalNode, graph);
|
|
446
|
+
portalBuilder.when(openSignal, (panelHost) => {
|
|
447
|
+
panelHost.container(`${key}__panel`, builder, panelOptions);
|
|
448
|
+
});
|
|
449
|
+
const descriptor = {
|
|
450
|
+
open: openSignal,
|
|
451
|
+
modal: kind.modal,
|
|
452
|
+
takesFocus: kind.takesFocus,
|
|
453
|
+
closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,
|
|
454
|
+
restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,
|
|
455
|
+
...options.initialFocusId !== void 0 ? { initialFocusId: options.initialFocusId } : {},
|
|
456
|
+
...options.onClose !== void 0 ? { onClose: options.onClose } : {}
|
|
457
|
+
};
|
|
458
|
+
graph.registerHandler(
|
|
459
|
+
`__overlay__${portalNode.id}`,
|
|
460
|
+
() => descriptor
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
dialog(key, options, builder) {
|
|
464
|
+
this._overlay(OVERLAY_KINDS.dialog, key, options, builder);
|
|
465
|
+
}
|
|
466
|
+
popover(key, options, builder) {
|
|
467
|
+
this._overlay(OVERLAY_KINDS.popover, key, options, builder);
|
|
468
|
+
}
|
|
469
|
+
tooltip(key, options, builder) {
|
|
470
|
+
this._overlay(OVERLAY_KINDS.tooltip, key, options, builder);
|
|
471
|
+
}
|
|
472
|
+
dropdown(key, options, builder) {
|
|
473
|
+
this._overlay(OVERLAY_KINDS.dropdown, key, options, builder);
|
|
474
|
+
}
|
|
475
|
+
toast(key, options, builder) {
|
|
476
|
+
this._overlay(OVERLAY_KINDS.toast, key, options, builder);
|
|
477
|
+
}
|
|
366
478
|
};
|
|
367
479
|
var SectionBuilderImpl = class extends ContainerBuilderBase {
|
|
368
480
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/builders.ts","../src/dsl.ts"],"sourcesContent":["export * from './dsl-types.js';\nexport * from './builders.js';\nexport * from './dsl.js';\n","/**\n * DSL builder implementations.\n *\n * Each builder wraps a GraphNode and provides the fluent API\n * for constructing the Semantic Application Graph via the DSL.\n *\n * Builders do NOT render anything — they only build the graph.\n */\n\nimport { ApplicationGraph, GraphNode, type Props } from '@streetui/graph';\nimport type {\n ContentDSL,\n ContainerDSL,\n SectionDSL,\n PageDSL,\n FormDSL,\n ListDSL,\n AppDSL,\n HeadingOptions,\n TextOptions,\n ButtonOptions,\n InputOptions,\n LinkOptions,\n ImageOptions,\n ContainerOptions,\n SectionOptions,\n FormOptions,\n ListOptions,\n A11yOptions,\n Bindable,\n BindableText,\n TextValue,\n ErrorBoundaryOptions,\n ErrorSource,\n PageBuilder,\n SectionBuilder,\n ContainerBuilder as ContainerBuilderFn,\n FormBuilder,\n ListBuilder,\n} from './dsl-types.js';\nimport { signal, derived, type Signal, type ReadonlySignal } from '@streetui/state';\n\n/**\n * A single reactive-list reconciliation descriptor (spec §15).\n *\n * Emitted by the `__listplan__<nodeId>` handler on every list change. `key` is\n * the item's identity-only reconciliation key (cheap to compute); `item` is the\n * source value *reference* used for identity short-circuiting; `sig()` computes\n * the content signature on demand (only when the reference changed); `build()`\n * materialises the full item subtree on demand (only for new/changed rows).\n */\nexport interface ListPlanEntry {\n readonly key: string;\n readonly item: unknown;\n readonly sig: () => string;\n readonly build: () => GraphNode;\n}\n\n// ── Signal helpers ────────────────────────────────────────────────────────────\n\nfunction isSignal(v: unknown): v is Signal<unknown> | ReadonlySignal<unknown> {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>)['get'] === 'function' &&\n typeof (v as Record<string, unknown>)['subscribe'] === 'function'\n );\n}\n\n/** Register a signal binding on the node and return the current static value. */\nfunction bindValue<T>(\n graph: ApplicationGraph,\n node: GraphNode,\n propKey: string,\n value: Bindable<T>,\n): T {\n if (isSignal(value)) {\n const signalId = `${node.id}:${propKey}`;\n node.stateRefs.push({ signalId, propKey });\n graph.registerHandler(`__signal__${signalId}`, value as unknown as () => unknown);\n return (value as ReadonlySignal<T>).peek();\n }\n return value as T;\n}\n\n// ── Helper to build Props from ContainerOptions ───────────────────────────────\n\n/**\n * Copy accessibility options onto a props bag as their corresponding HTML/ARIA\n * attribute names. Values are written as strings (booleans become \"true\"/\"false\"\n * rather than being dropped) so ARIA state attributes render literally. These\n * flow to the DOM via the renderer's generic attribute pass — no ARIA-specific\n * renderer code is involved.\n */\nfunction applyA11yProps(props: Props, options: A11yOptions): void {\n if (options.role !== undefined) props['role'] = options.role;\n if (options.tabIndex !== undefined) props['tabindex'] = String(options.tabIndex);\n if (options.ariaLabel !== undefined) props['aria-label'] = options.ariaLabel;\n if (options.ariaLabelledBy !== undefined) props['aria-labelledby'] = options.ariaLabelledBy;\n if (options.ariaDescribedBy !== undefined) props['aria-describedby'] = options.ariaDescribedBy;\n if (options.ariaExpanded !== undefined) props['aria-expanded'] = String(options.ariaExpanded);\n if (options.ariaControls !== undefined) props['aria-controls'] = options.ariaControls;\n if (options.ariaHidden !== undefined) props['aria-hidden'] = String(options.ariaHidden);\n if (options.ariaLive !== undefined) props['aria-live'] = options.ariaLive;\n if (options.ariaCurrent !== undefined) props['aria-current'] = String(options.ariaCurrent);\n if (options.ariaInvalid !== undefined) props['aria-invalid'] = String(options.ariaInvalid);\n if (options.ariaRequired !== undefined) props['aria-required'] = String(options.ariaRequired);\n}\n\nfunction containerProps(options: ContainerOptions): Props {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n if (options.key !== undefined) props['key'] = options.key;\n applyA11yProps(props, options);\n return props;\n}\n\n// ── Reactive-list item keying ──────────────────────────────────────────────────\n//\n// The `listOf` DSL signature does not take an explicit key extractor, so we\n// derive a stable reconciliation key from each item. The key combines an\n// *identity* part (so reordering the same items reuses their DOM nodes) with a\n// *value signature* (so an item whose data changed is treated as a fresh node\n// and re-rendered rather than silently kept stale by the shallow reconciler).\n\nfunction itemIdentity(item: unknown, index: number): string {\n if (item !== null && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('id' in obj) return `id:${String(obj['id'])}`;\n if ('key' in obj) return `key:${String(obj['key'])}`;\n return `idx:${index}`;\n }\n return `val:${String(item)}`;\n}\n\nfunction itemValueSignature(item: unknown): string {\n try {\n return JSON.stringify(item) ?? String(item);\n } catch {\n return String(item);\n }\n}\n\n/** Content signature used to detect in-place data changes of a stable item. */\nexport function reactiveListItemSignature(item: unknown): string {\n return itemValueSignature(item);\n}\n\n/** Stable, identity-only reconciliation key for a reactive-list item. */\nexport function reactiveListItemKey(item: unknown, index: number): string {\n return itemIdentity(item, index);\n}\n\n// ── Base content builder ──────────────────────────────────────────────────────\n\nclass ContentBuilderBase implements ContentDSL {\n constructor(\n protected readonly _node: GraphNode,\n protected readonly _graph: ApplicationGraph,\n ) {}\n\n heading(text: BindableText, options: HeadingOptions = {}): void {\n const props: Props = { level: options.level ?? 1 };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('heading', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', text);\n node.setProp('text', resolved);\n }\n\n text(content: BindableText, options: TextOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('text', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', content);\n node.setProp('text', resolved);\n }\n\n button(label: BindableText, options: ButtonOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('button', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.disabled !== undefined) {\n const resolvedDisabled = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolvedDisabled);\n }\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n\n input(options: InputOptions = {}): void {\n const props: Props = {};\n props['inputType'] = options.type ?? 'text';\n if (options.placeholder !== undefined) props['placeholder'] = options.placeholder;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n const node = this._graph.createNode('input', nodeOpts);\n\n // Two-way `bind` expands to a value binding + an input write-back. The type\n // system (BoundInputOptions vs ControlledInputOptions) guarantees `bind` is\n // never combined with explicit `value`/`onInput`, so there is no ambiguity.\n const bindSignal = options.bind;\n const valueBindable: Bindable<string> | undefined =\n bindSignal !== undefined ? bindSignal : options.value;\n const inputHandler: ((value: string) => void) | undefined =\n bindSignal !== undefined ? (v: string) => bindSignal.set(v) : options.onInput;\n\n if (valueBindable !== undefined) {\n const resolved = bindValue(this._graph, node, 'value', valueBindable);\n node.setProp('value', resolved);\n }\n if (options.disabled !== undefined) {\n const resolved = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolved);\n }\n if (inputHandler !== undefined) {\n const handlerKey = `input:${node.id}`;\n this._graph.registerHandler(handlerKey, inputHandler as () => unknown);\n node.addEvent({ type: 'input', handlerKey });\n }\n if (options.onChange !== undefined) {\n const handlerKey = `change:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onChange as () => unknown);\n node.addEvent({ type: 'change', handlerKey });\n }\n }\n\n image(options: ImageOptions): void {\n const props: Props = {\n src: options.src,\n alt: options.alt,\n };\n if (options.width !== undefined) props['width'] = options.width;\n if (options.height !== undefined) props['height'] = options.height;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n this._graph.createNode('image', nodeOpts);\n }\n\n link(label: BindableText, options: LinkOptions): void {\n const props: Props = {\n href: options.href,\n external: options.external ?? false,\n };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('link', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n}\n\n// ── Container builder ─────────────────────────────────────────────────────────\n\nclass ContainerBuilderBase extends ContentBuilderBase implements ContainerDSL {\n section(key: string, builder: SectionBuilder, options: SectionOptions = {}): void {\n const node = this._graph.createNode('section', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new SectionBuilderImpl(node, this._graph));\n }\n\n container(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('container', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n list(key: string, builder: ListBuilder, options: ListOptions = {}): void {\n const node = this._graph.createNode('list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ListBuilderImpl(node, this._graph));\n }\n\n listOf<T>(\n key: string,\n items: Signal<T[]> | ReadonlySignal<T[]>,\n renderItem: (item: T, index: number, content: ContentDSL) => void,\n options: ListOptions = {},\n ): void {\n const graph = this._graph;\n const node = graph.createNode('reactive-list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n\n // Register the driving signal so the runtime/renderer can subscribe to it.\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, items as unknown as () => unknown);\n\n // Build a single detached list-item subtree for one item. The item's\n // reconciliation `key` is identity-only, and its value signature is stored\n // in the internal `_sig` prop so the renderer can detect (and apply a\n // targeted update for) a data change on an item whose identity is stable.\n const buildItem = (item: T, index: number): GraphNode => {\n const itemKey = reactiveListItemKey(item, index);\n const itemNode = graph.createNode('list-item', {\n key: itemKey,\n // `_item` records the source item *reference* so the reconciler can\n // short-circuit unchanged rows by identity (no signature hashing); `_sig`\n // is the content signature used to detect an in-place data change when the\n // reference differs. Both are internal metadata (leading `_`) and never\n // reach the DOM.\n props: {\n key: itemKey,\n _sig: reactiveListItemSignature(item),\n // The item reference is stored as opaque internal metadata (never\n // rendered); cast through `unknown` since `T` is not a `PropValue`.\n _item: item as unknown as Props[string],\n },\n });\n renderItem(item, index, new ContainerBuilderImpl(itemNode, graph));\n return itemNode;\n };\n\n // Lazy reconciliation plan (spec §15 — the measured keyed-list hot path).\n //\n // Instead of eagerly rebuilding all N item GraphNodes (and hashing every item\n // with JSON.stringify) on *every* emission — the dominant cost of the old\n // `buildAll` path — the renderer receives lightweight descriptors and only\n // materialises a subtree for rows that are genuinely new or whose data\n // actually changed. `key` is cheap (identity only); `sig()` and `build()` are\n // thunks the reconciler calls on demand.\n const buildPlan = (raw: unknown): ListPlanEntry[] => {\n const arr = Array.isArray(raw) ? (raw as T[]) : [];\n const plan: ListPlanEntry[] = new Array(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i]!;\n const index = i;\n plan[i] = {\n key: reactiveListItemKey(item, index),\n item,\n sig: () => reactiveListItemSignature(item),\n build: () => buildItem(item, index),\n };\n }\n return plan;\n };\n graph.registerHandler(`__listplan__${node.id}`, buildPlan as unknown as () => unknown);\n\n // Build the initial children into the graph so the first mount renders them.\n const current = isSignal(items)\n ? (items as ReadonlySignal<T[]>).peek()\n : (items as unknown as T[]);\n const initial = Array.isArray(current) ? current : [];\n initial.forEach((item, i) => {\n node.appendChild(buildItem(item, i));\n });\n }\n\n form(key: string, builder: FormBuilder, options: FormOptions = {}): void {\n const props: Props = containerProps(options);\n const node = this._graph.createNode('form', {\n key,\n parent: this._node,\n props,\n });\n if (options.onSubmit !== undefined) {\n const handlerKey = `submit:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onSubmit as () => unknown);\n node.addEvent({ type: 'submit', handlerKey });\n }\n builder(new FormBuilderImpl(node, this._graph));\n }\n\n when(\n condition: Bindable<boolean>,\n builder: ContainerBuilderFn,\n elseBuilder?: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n // A dedicated 'conditional' node reuses the reactive-list reconciliation\n // machinery (same signal subscription + keyed reconcile) but renders as a\n // neutral <div> rather than a <ul>. It holds zero or one child branch.\n const node = graph.createNode('conditional', {\n parent: this._node,\n props: containerProps({}),\n });\n\n // Build the active branch as a single keyed container. Distinct keys for the\n // then/else branches make a flip a clean swap under the keyed reconciler.\n const buildBranch = (build: ContainerBuilderFn, tag: 'then' | 'else'): GraphNode => {\n const branchKey = `when-${tag}:${node.id}`;\n const branch = graph.createNode('container', {\n key: branchKey,\n props: { key: branchKey },\n });\n build(new ContainerBuilderImpl(branch, graph));\n return branch;\n };\n\n const buildAll = (raw: unknown): GraphNode[] => {\n if (raw) return [buildBranch(builder, 'then')];\n return elseBuilder !== undefined ? [buildBranch(elseBuilder, 'else')] : [];\n };\n\n if (isSignal(condition)) {\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, condition as unknown as () => unknown);\n graph.registerHandler(`__listbuild__${node.id}`, buildAll as unknown as () => unknown);\n const current = (condition as ReadonlySignal<boolean>).peek();\n for (const child of buildAll(current)) node.appendChild(child);\n } else {\n // Static condition — resolve once at build time, no reactive wiring.\n for (const child of buildAll(condition)) node.appendChild(child);\n }\n }\n\n errorBoundary(\n id: string,\n builder: ContainerBuilderFn,\n options: ErrorBoundaryOptions,\n ): void {\n // Normalise the observed error source(s) into an array.\n const sources: ErrorSource[] =\n options.source === undefined\n ? []\n : Array.isArray(options.source)\n ? [...options.source]\n : [options.source];\n\n // The boundary's own captured error (from a synchronous build throw) and a\n // retry nonce that forces a re-evaluation even when the boolean is unchanged.\n const localError = signal<unknown>(undefined);\n const retryNonce = signal<number>(0);\n\n const readError = (): unknown => {\n const local = localError.peek();\n if (local !== undefined && local !== null) return local;\n for (const s of sources) {\n const e = s.peek();\n if (e !== undefined && e !== null) return e;\n }\n return undefined;\n };\n\n // Reactive condition: true while an error is present. Reads every input so a\n // change in any source (or a retry) re-runs the conditional.\n const hasError = derived<boolean>(() => {\n retryNonce.get();\n localError.get();\n for (const s of sources) s.get();\n return readError() !== undefined;\n });\n\n const retry = (): void => {\n localError.set(undefined);\n options.onRetry?.();\n // Force the body branch to re-attempt even if no observed value changed.\n retryNonce.update((n) => n + 1);\n };\n\n // Wrap in a container so the whole boundary is addressable and disposes as a\n // unit. `when` provides the reactive body↔fallback swap (and its cleanup).\n this.container(id, (c) => {\n c.when(\n hasError,\n // Error state → fallback.\n (fb) => options.fallback(fb, readError(), retry),\n // Healthy state → body, guarded against synchronous build throws.\n (body) => {\n try {\n builder(body);\n } catch (err) {\n // Surface the throw as the boundary's error on the next microtask\n // (deferred to avoid re-entrant reconciliation during this build).\n queueMicrotask(() => localError.set(err));\n }\n },\n );\n }, { id });\n }\n}\n\n// ── Concrete builder implementations ─────────────────────────────────────────\n\nexport class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {}\nexport class ContainerBuilderImpl extends ContainerBuilderBase implements ContainerDSL {}\nexport class FormBuilderImpl extends ContainerBuilderBase implements FormDSL {}\n\nexport class ListBuilderImpl extends ContentBuilderBase implements ListDSL {\n item(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('list-item', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n}\n\nexport class PageBuilderImpl extends ContainerBuilderBase implements PageDSL {}\n\n// ── App builder ───────────────────────────────────────────────────────────────\n\nexport class AppBuilder implements AppDSL {\n constructor(private readonly _graph: ApplicationGraph) {}\n\n page(key: string, builder: PageBuilder): void {\n const node = this._graph.createNode('page', {\n key,\n parent: this._graph.root,\n props: { key },\n });\n builder(new PageBuilderImpl(node, this._graph));\n }\n}\n","/**\n * StreetUI DSL entry point.\n *\n * Usage:\n * import { streetui } from '@streetui/dsl';\n *\n * const app = streetui.app({ name: 'My App' });\n * app.page('home', page => {\n * page.section('hero', section => {\n * section.heading('Welcome');\n * section.button('Click me', { onClick: () => {} });\n * });\n * });\n *\n * const graph = app.build();\n */\n\nimport { ApplicationGraph } from '@streetui/graph';\nimport { AppBuilder } from './builders.js';\n\nexport interface AppOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport class StreetApp {\n private readonly _graph: ApplicationGraph;\n private readonly _builder: AppBuilder;\n\n constructor(options: AppOptions) {\n const graphOpts: { name: string; version?: string } = { name: options.name };\n if (options.version !== undefined) graphOpts.version = options.version;\n this._graph = new ApplicationGraph(graphOpts);\n this._builder = new AppBuilder(this._graph);\n }\n\n page(key: string, builder: Parameters<AppBuilder['page']>[1]): this {\n this._builder.page(key, builder);\n return this;\n }\n\n /** Compile to ApplicationGraph — validates and returns the graph. */\n build(): ApplicationGraph {\n const dc = this._graph.validate();\n dc.throwIfErrors();\n return this._graph;\n }\n\n /** Access graph before building (useful for inspection). */\n get graph(): ApplicationGraph {\n return this._graph;\n }\n}\n\nexport interface StreetUI {\n app(options: AppOptions): StreetApp;\n}\n\nexport const streetui: StreetUI = {\n app(options: AppOptions): StreetApp {\n return new StreetApp(options);\n },\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/builders.ts","../src/dsl.ts"],"sourcesContent":["export * from './dsl-types.js';\nexport * from './builders.js';\nexport * from './dsl.js';\n","/**\n * DSL builder implementations.\n *\n * Each builder wraps a GraphNode and provides the fluent API\n * for constructing the Semantic Application Graph via the DSL.\n *\n * Builders do NOT render anything — they only build the graph.\n */\n\nimport { ApplicationGraph, GraphNode, type Props } from '@streetui/graph';\nimport type {\n ContentDSL,\n ContainerDSL,\n SectionDSL,\n PageDSL,\n FormDSL,\n ListDSL,\n AppDSL,\n HeadingOptions,\n TextOptions,\n ButtonOptions,\n InputOptions,\n LinkOptions,\n ImageOptions,\n ContainerOptions,\n SectionOptions,\n FormOptions,\n ListOptions,\n PortalOptions,\n OverlayOptions,\n A11yOptions,\n Bindable,\n BindableText,\n TextValue,\n ErrorBoundaryOptions,\n ErrorSource,\n PageBuilder,\n SectionBuilder,\n ContainerBuilder as ContainerBuilderFn,\n FormBuilder,\n ListBuilder,\n} from './dsl-types.js';\nimport { signal, derived, type Signal, type ReadonlySignal } from '@streetui/state';\n\n/**\n * A single reactive-list reconciliation descriptor (spec §15).\n *\n * Emitted by the `__listplan__<nodeId>` handler on every list change. `key` is\n * the item's identity-only reconciliation key (cheap to compute); `item` is the\n * source value *reference* used for identity short-circuiting; `sig()` computes\n * the content signature on demand (only when the reference changed); `build()`\n * materialises the full item subtree on demand (only for new/changed rows).\n */\nexport interface ListPlanEntry {\n readonly key: string;\n readonly item: unknown;\n readonly sig: () => string;\n readonly build: () => GraphNode;\n}\n\n// ── Signal helpers ────────────────────────────────────────────────────────────\n\nfunction isSignal(v: unknown): v is Signal<unknown> | ReadonlySignal<unknown> {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>)['get'] === 'function' &&\n typeof (v as Record<string, unknown>)['subscribe'] === 'function'\n );\n}\n\n/** Register a signal binding on the node and return the current static value. */\nfunction bindValue<T>(\n graph: ApplicationGraph,\n node: GraphNode,\n propKey: string,\n value: Bindable<T>,\n): T {\n if (isSignal(value)) {\n const signalId = `${node.id}:${propKey}`;\n node.stateRefs.push({ signalId, propKey });\n graph.registerHandler(`__signal__${signalId}`, value as unknown as () => unknown);\n return (value as ReadonlySignal<T>).peek();\n }\n return value as T;\n}\n\n// ── Helper to build Props from ContainerOptions ───────────────────────────────\n\n/**\n * Copy accessibility options onto a props bag as their corresponding HTML/ARIA\n * attribute names. Values are written as strings (booleans become \"true\"/\"false\"\n * rather than being dropped) so ARIA state attributes render literally. These\n * flow to the DOM via the renderer's generic attribute pass — no ARIA-specific\n * renderer code is involved.\n */\nfunction applyA11yProps(props: Props, options: A11yOptions): void {\n if (options.role !== undefined) props['role'] = options.role;\n if (options.tabIndex !== undefined) props['tabindex'] = String(options.tabIndex);\n if (options.ariaLabel !== undefined) props['aria-label'] = options.ariaLabel;\n if (options.ariaLabelledBy !== undefined) props['aria-labelledby'] = options.ariaLabelledBy;\n if (options.ariaDescribedBy !== undefined) props['aria-describedby'] = options.ariaDescribedBy;\n if (options.ariaExpanded !== undefined) props['aria-expanded'] = String(options.ariaExpanded);\n if (options.ariaControls !== undefined) props['aria-controls'] = options.ariaControls;\n if (options.ariaHidden !== undefined) props['aria-hidden'] = String(options.ariaHidden);\n if (options.ariaLive !== undefined) props['aria-live'] = options.ariaLive;\n if (options.ariaCurrent !== undefined) props['aria-current'] = String(options.ariaCurrent);\n if (options.ariaInvalid !== undefined) props['aria-invalid'] = String(options.ariaInvalid);\n if (options.ariaRequired !== undefined) props['aria-required'] = String(options.ariaRequired);\n if (options.ariaModal !== undefined) props['aria-modal'] = String(options.ariaModal);\n}\n\nfunction containerProps(options: ContainerOptions): Props {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n if (options.key !== undefined) props['key'] = options.key;\n applyA11yProps(props, options);\n return props;\n}\n\n// ── Reactive-list item keying ──────────────────────────────────────────────────\n//\n// The `listOf` DSL signature does not take an explicit key extractor, so we\n// derive a stable reconciliation key from each item. The key combines an\n// *identity* part (so reordering the same items reuses their DOM nodes) with a\n// *value signature* (so an item whose data changed is treated as a fresh node\n// and re-rendered rather than silently kept stale by the shallow reconciler).\n\nfunction itemIdentity(item: unknown, index: number): string {\n if (item !== null && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('id' in obj) return `id:${String(obj['id'])}`;\n if ('key' in obj) return `key:${String(obj['key'])}`;\n return `idx:${index}`;\n }\n return `val:${String(item)}`;\n}\n\nfunction itemValueSignature(item: unknown): string {\n try {\n return JSON.stringify(item) ?? String(item);\n } catch {\n return String(item);\n }\n}\n\n/** Content signature used to detect in-place data changes of a stable item. */\nexport function reactiveListItemSignature(item: unknown): string {\n return itemValueSignature(item);\n}\n\n/** Stable, identity-only reconciliation key for a reactive-list item. */\nexport function reactiveListItemKey(item: unknown, index: number): string {\n return itemIdentity(item, index);\n}\n\n// ── Overlay kind configuration ──────────────────────────────────────────────────\n//\n// Each overlay builder (dialog/popover/tooltip/dropdown/toast) is the same\n// portal + `when(open, …)` panel + focus/keyboard behavior, differing only in\n// ARIA role, modality, whether it takes focus, and its escape/restore defaults.\n// This table captures those differences; `_overlay` does the shared assembly.\n\ninterface OverlayKindConfig {\n /** Default ARIA role for the panel. */\n readonly role: string;\n /** Trap + contain focus (modal semantics). */\n readonly modal: boolean;\n /** Move focus into the panel when it opens. */\n readonly takesFocus: boolean;\n /** Emit `aria-modal=\"true\"` on the panel. */\n readonly ariaModal: boolean;\n /** Emit an `aria-live` region on the panel (announcements). */\n readonly ariaLive?: 'polite' | 'assertive';\n /** Default for `closeOnEscape` when the caller does not specify it. */\n readonly defaultCloseOnEscape: boolean;\n /** Default for `restoreFocus` when the caller does not specify it. */\n readonly defaultRestoreFocus: boolean;\n}\n\nconst OVERLAY_KINDS = {\n dialog: {\n role: 'dialog', modal: true, takesFocus: true, ariaModal: true,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n popover: {\n role: 'dialog', modal: false, takesFocus: true, ariaModal: false,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n tooltip: {\n role: 'tooltip', modal: false, takesFocus: false, ariaModal: false,\n defaultCloseOnEscape: false, defaultRestoreFocus: false,\n },\n dropdown: {\n role: 'menu', modal: false, takesFocus: true, ariaModal: false,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n toast: {\n role: 'status', modal: false, takesFocus: false, ariaModal: false,\n ariaLive: 'polite', defaultCloseOnEscape: false, defaultRestoreFocus: false,\n },\n} as const satisfies Record<string, OverlayKindConfig>;\n\n/** The opaque descriptor the renderer reads from `__overlay__<portalId>`. */\ninterface OverlayBehaviorDescriptor {\n readonly open: ReadonlySignal<boolean>;\n readonly modal: boolean;\n readonly takesFocus: boolean;\n readonly closeOnEscape: boolean;\n readonly restoreFocus: boolean;\n readonly initialFocusId?: string;\n readonly onClose?: () => void;\n}\n\n// ── Base content builder ──────────────────────────────────────────────────────\n\nclass ContentBuilderBase implements ContentDSL {\n constructor(\n protected readonly _node: GraphNode,\n protected readonly _graph: ApplicationGraph,\n ) {}\n\n heading(text: BindableText, options: HeadingOptions = {}): void {\n const props: Props = { level: options.level ?? 1 };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('heading', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', text);\n node.setProp('text', resolved);\n }\n\n text(content: BindableText, options: TextOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('text', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', content);\n node.setProp('text', resolved);\n }\n\n button(label: BindableText, options: ButtonOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('button', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.disabled !== undefined) {\n const resolvedDisabled = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolvedDisabled);\n }\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n\n input(options: InputOptions = {}): void {\n const props: Props = {};\n props['inputType'] = options.type ?? 'text';\n if (options.placeholder !== undefined) props['placeholder'] = options.placeholder;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n const node = this._graph.createNode('input', nodeOpts);\n\n // Two-way `bind` expands to a value binding + an input write-back. The type\n // system (BoundInputOptions vs ControlledInputOptions) guarantees `bind` is\n // never combined with explicit `value`/`onInput`, so there is no ambiguity.\n const bindSignal = options.bind;\n const valueBindable: Bindable<string> | undefined =\n bindSignal !== undefined ? bindSignal : options.value;\n const inputHandler: ((value: string) => void) | undefined =\n bindSignal !== undefined ? (v: string) => bindSignal.set(v) : options.onInput;\n\n if (valueBindable !== undefined) {\n const resolved = bindValue(this._graph, node, 'value', valueBindable);\n node.setProp('value', resolved);\n }\n if (options.disabled !== undefined) {\n const resolved = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolved);\n }\n if (inputHandler !== undefined) {\n const handlerKey = `input:${node.id}`;\n this._graph.registerHandler(handlerKey, inputHandler as () => unknown);\n node.addEvent({ type: 'input', handlerKey });\n }\n if (options.onChange !== undefined) {\n const handlerKey = `change:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onChange as () => unknown);\n node.addEvent({ type: 'change', handlerKey });\n }\n }\n\n image(options: ImageOptions): void {\n const props: Props = {\n src: options.src,\n alt: options.alt,\n };\n if (options.width !== undefined) props['width'] = options.width;\n if (options.height !== undefined) props['height'] = options.height;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n this._graph.createNode('image', nodeOpts);\n }\n\n link(label: BindableText, options: LinkOptions): void {\n const props: Props = {\n href: options.href,\n external: options.external ?? false,\n };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('link', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n}\n\n// ── Container builder ─────────────────────────────────────────────────────────\n\nclass ContainerBuilderBase extends ContentBuilderBase implements ContainerDSL {\n section(key: string, builder: SectionBuilder, options: SectionOptions = {}): void {\n const node = this._graph.createNode('section', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new SectionBuilderImpl(node, this._graph));\n }\n\n container(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('container', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n list(key: string, builder: ListBuilder, options: ListOptions = {}): void {\n const node = this._graph.createNode('list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ListBuilderImpl(node, this._graph));\n }\n\n listOf<T>(\n key: string,\n items: Signal<T[]> | ReadonlySignal<T[]>,\n renderItem: (item: T, index: number, content: ContentDSL) => void,\n options: ListOptions = {},\n ): void {\n const graph = this._graph;\n const node = graph.createNode('reactive-list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n\n // Register the driving signal so the runtime/renderer can subscribe to it.\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, items as unknown as () => unknown);\n\n // Build a single detached list-item subtree for one item. The item's\n // reconciliation `key` is identity-only, and its value signature is stored\n // in the internal `_sig` prop so the renderer can detect (and apply a\n // targeted update for) a data change on an item whose identity is stable.\n const buildItem = (item: T, index: number): GraphNode => {\n const itemKey = reactiveListItemKey(item, index);\n const itemNode = graph.createNode('list-item', {\n key: itemKey,\n // `_item` records the source item *reference* so the reconciler can\n // short-circuit unchanged rows by identity (no signature hashing); `_sig`\n // is the content signature used to detect an in-place data change when the\n // reference differs. Both are internal metadata (leading `_`) and never\n // reach the DOM.\n props: {\n key: itemKey,\n _sig: reactiveListItemSignature(item),\n // The item reference is stored as opaque internal metadata (never\n // rendered); cast through `unknown` since `T` is not a `PropValue`.\n _item: item as unknown as Props[string],\n },\n });\n renderItem(item, index, new ContainerBuilderImpl(itemNode, graph));\n return itemNode;\n };\n\n // Lazy reconciliation plan (spec §15 — the measured keyed-list hot path).\n //\n // Instead of eagerly rebuilding all N item GraphNodes (and hashing every item\n // with JSON.stringify) on *every* emission — the dominant cost of the old\n // `buildAll` path — the renderer receives lightweight descriptors and only\n // materialises a subtree for rows that are genuinely new or whose data\n // actually changed. `key` is cheap (identity only); `sig()` and `build()` are\n // thunks the reconciler calls on demand.\n const buildPlan = (raw: unknown): ListPlanEntry[] => {\n const arr = Array.isArray(raw) ? (raw as T[]) : [];\n const plan: ListPlanEntry[] = new Array(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i]!;\n const index = i;\n plan[i] = {\n key: reactiveListItemKey(item, index),\n item,\n sig: () => reactiveListItemSignature(item),\n build: () => buildItem(item, index),\n };\n }\n return plan;\n };\n graph.registerHandler(`__listplan__${node.id}`, buildPlan as unknown as () => unknown);\n\n // Build the initial children into the graph so the first mount renders them.\n const current = isSignal(items)\n ? (items as ReadonlySignal<T[]>).peek()\n : (items as unknown as T[]);\n const initial = Array.isArray(current) ? current : [];\n initial.forEach((item, i) => {\n node.appendChild(buildItem(item, i));\n });\n }\n\n form(key: string, builder: FormBuilder, options: FormOptions = {}): void {\n const props: Props = containerProps(options);\n const node = this._graph.createNode('form', {\n key,\n parent: this._node,\n props,\n });\n if (options.onSubmit !== undefined) {\n const handlerKey = `submit:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onSubmit as () => unknown);\n node.addEvent({ type: 'submit', handlerKey });\n }\n builder(new FormBuilderImpl(node, this._graph));\n }\n\n when(\n condition: Bindable<boolean>,\n builder: ContainerBuilderFn,\n elseBuilder?: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n // A dedicated 'conditional' node reuses the reactive-list reconciliation\n // machinery (same signal subscription + keyed reconcile) but renders as a\n // neutral <div> rather than a <ul>. It holds zero or one child branch.\n const node = graph.createNode('conditional', {\n parent: this._node,\n props: containerProps({}),\n });\n\n // Build the active branch as a single keyed container. Distinct keys for the\n // then/else branches make a flip a clean swap under the keyed reconciler.\n const buildBranch = (build: ContainerBuilderFn, tag: 'then' | 'else'): GraphNode => {\n const branchKey = `when-${tag}:${node.id}`;\n const branch = graph.createNode('container', {\n key: branchKey,\n props: { key: branchKey },\n });\n build(new ContainerBuilderImpl(branch, graph));\n return branch;\n };\n\n const buildAll = (raw: unknown): GraphNode[] => {\n if (raw) return [buildBranch(builder, 'then')];\n return elseBuilder !== undefined ? [buildBranch(elseBuilder, 'else')] : [];\n };\n\n if (isSignal(condition)) {\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, condition as unknown as () => unknown);\n graph.registerHandler(`__listbuild__${node.id}`, buildAll as unknown as () => unknown);\n const current = (condition as ReadonlySignal<boolean>).peek();\n for (const child of buildAll(current)) node.appendChild(child);\n } else {\n // Static condition — resolve once at build time, no reactive wiring.\n for (const child of buildAll(condition)) node.appendChild(child);\n }\n }\n\n errorBoundary(\n id: string,\n builder: ContainerBuilderFn,\n options: ErrorBoundaryOptions,\n ): void {\n // Normalise the observed error source(s) into an array.\n const sources: ErrorSource[] =\n options.source === undefined\n ? []\n : Array.isArray(options.source)\n ? [...options.source]\n : [options.source];\n\n // The boundary's own captured error (from a synchronous build throw) and a\n // retry nonce that forces a re-evaluation even when the boolean is unchanged.\n const localError = signal<unknown>(undefined);\n const retryNonce = signal<number>(0);\n\n const readError = (): unknown => {\n const local = localError.peek();\n if (local !== undefined && local !== null) return local;\n for (const s of sources) {\n const e = s.peek();\n if (e !== undefined && e !== null) return e;\n }\n return undefined;\n };\n\n // Reactive condition: true while an error is present. Reads every input so a\n // change in any source (or a retry) re-runs the conditional.\n const hasError = derived<boolean>(() => {\n retryNonce.get();\n localError.get();\n for (const s of sources) s.get();\n return readError() !== undefined;\n });\n\n const retry = (): void => {\n localError.set(undefined);\n options.onRetry?.();\n // Force the body branch to re-attempt even if no observed value changed.\n retryNonce.update((n) => n + 1);\n };\n\n // Wrap in a container so the whole boundary is addressable and disposes as a\n // unit. `when` provides the reactive body↔fallback swap (and its cleanup).\n this.container(id, (c) => {\n c.when(\n hasError,\n // Error state → fallback.\n (fb) => options.fallback(fb, readError(), retry),\n // Healthy state → body, guarded against synchronous build throws.\n (body) => {\n try {\n builder(body);\n } catch (err) {\n // Surface the throw as the boundary's error on the next microtask\n // (deferred to avoid re-entrant reconciliation during this build).\n queueMicrotask(() => localError.set(err));\n }\n },\n );\n }, { id });\n }\n\n // ── Portals & overlays ──────────────────────────────────────────────────────\n\n portal(key: string, builder: ContainerBuilderFn, options: PortalOptions = {}): void {\n const node = this._graph.createNode('portal', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n /**\n * Shared assembly for every overlay kind: a `portal` node whose single child\n * is a `when(open, panel)` conditional. The panel container carries the\n * kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`\n * descriptor is registered so the renderer wires focus/keyboard behavior to\n * the same `open` signal that drives the panel. Reuses existing primitives\n * (portal + when + container) — no new render path.\n */\n private _overlay(\n kind: OverlayKindConfig,\n key: string,\n options: OverlayOptions,\n builder: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n const portalNode = graph.createNode('portal', {\n key,\n parent: this._node,\n props: { key },\n });\n\n // Resolve `open` to a signal we can both bind (drives the panel's `when`)\n // and hand to the renderer (drives focus behavior). A literal is wrapped so\n // the panel still mounts/unmounts through the same reactive path.\n const openBindable = options.open;\n const openSignal: ReadonlySignal<boolean> = isSignal(openBindable)\n ? (openBindable as ReadonlySignal<boolean>)\n : signal(openBindable as boolean);\n\n // Panel a11y semantics (kind defaults, overridable via options).\n const panelOptions: ContainerOptions = {\n role: options.role ?? kind.role,\n ...(kind.ariaModal ? { ariaModal: true } : {}),\n ...(kind.ariaLive !== undefined ? { ariaLive: kind.ariaLive } : {}),\n ...(options.class !== undefined ? { class: options.class } : {}),\n ...(options.ariaLabel !== undefined ? { ariaLabel: options.ariaLabel } : {}),\n ...(options.ariaLabelledBy !== undefined ? { ariaLabelledBy: options.ariaLabelledBy } : {}),\n ...(options.ariaDescribedBy !== undefined ? { ariaDescribedBy: options.ariaDescribedBy } : {}),\n };\n\n const portalBuilder = new ContainerBuilderImpl(portalNode, graph);\n portalBuilder.when(openSignal, (panelHost) => {\n panelHost.container(`${key}__panel`, builder, panelOptions);\n });\n\n const descriptor: OverlayBehaviorDescriptor = {\n open: openSignal,\n modal: kind.modal,\n takesFocus: kind.takesFocus,\n closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,\n restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,\n ...(options.initialFocusId !== undefined ? { initialFocusId: options.initialFocusId } : {}),\n ...(options.onClose !== undefined ? { onClose: options.onClose } : {}),\n };\n graph.registerHandler(\n `__overlay__${portalNode.id}`,\n (() => descriptor) as unknown as () => unknown,\n );\n }\n\n dialog(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.dialog, key, options, builder);\n }\n\n popover(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.popover, key, options, builder);\n }\n\n tooltip(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.tooltip, key, options, builder);\n }\n\n dropdown(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.dropdown, key, options, builder);\n }\n\n toast(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.toast, key, options, builder);\n }\n}\n\n// ── Concrete builder implementations ─────────────────────────────────────────\n\nexport class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {}\nexport class ContainerBuilderImpl extends ContainerBuilderBase implements ContainerDSL {}\nexport class FormBuilderImpl extends ContainerBuilderBase implements FormDSL {}\n\nexport class ListBuilderImpl extends ContentBuilderBase implements ListDSL {\n item(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('list-item', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n}\n\nexport class PageBuilderImpl extends ContainerBuilderBase implements PageDSL {}\n\n// ── App builder ───────────────────────────────────────────────────────────────\n\nexport class AppBuilder implements AppDSL {\n constructor(private readonly _graph: ApplicationGraph) {}\n\n page(key: string, builder: PageBuilder): void {\n const node = this._graph.createNode('page', {\n key,\n parent: this._graph.root,\n props: { key },\n });\n builder(new PageBuilderImpl(node, this._graph));\n }\n}\n","/**\n * StreetUI DSL entry point.\n *\n * Usage:\n * import { streetui } from '@streetui/dsl';\n *\n * const app = streetui.app({ name: 'My App' });\n * app.page('home', page => {\n * page.section('hero', section => {\n * section.heading('Welcome');\n * section.button('Click me', { onClick: () => {} });\n * });\n * });\n *\n * const graph = app.build();\n */\n\nimport { ApplicationGraph } from '@streetui/graph';\nimport { AppBuilder } from './builders.js';\n\nexport interface AppOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport class StreetApp {\n private readonly _graph: ApplicationGraph;\n private readonly _builder: AppBuilder;\n\n constructor(options: AppOptions) {\n const graphOpts: { name: string; version?: string } = { name: options.name };\n if (options.version !== undefined) graphOpts.version = options.version;\n this._graph = new ApplicationGraph(graphOpts);\n this._builder = new AppBuilder(this._graph);\n }\n\n page(key: string, builder: Parameters<AppBuilder['page']>[1]): this {\n this._builder.page(key, builder);\n return this;\n }\n\n /** Compile to ApplicationGraph — validates and returns the graph. */\n build(): ApplicationGraph {\n const dc = this._graph.validate();\n dc.throwIfErrors();\n return this._graph;\n }\n\n /** Access graph before building (useful for inspection). */\n get graph(): ApplicationGraph {\n return this._graph;\n }\n}\n\nexport interface StreetUI {\n app(options: AppOptions): StreetApp;\n}\n\nexport const streetui: StreetUI = {\n app(options: AppOptions): StreetApp {\n return new StreetApp(options);\n },\n};\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -45,6 +45,8 @@ interface A11yOptions {
|
|
|
45
45
|
readonly ariaInvalid?: boolean;
|
|
46
46
|
/** aria-required — mark a form field as required. */
|
|
47
47
|
readonly ariaRequired?: boolean;
|
|
48
|
+
/** aria-modal — mark a dialog as modal (content outside is inert to AT). */
|
|
49
|
+
readonly ariaModal?: boolean;
|
|
48
50
|
}
|
|
49
51
|
interface TextOptions extends A11yOptions {
|
|
50
52
|
readonly class?: string;
|
|
@@ -116,6 +118,30 @@ interface FormOptions extends ContainerOptions {
|
|
|
116
118
|
}
|
|
117
119
|
interface ListOptions extends ContainerOptions {
|
|
118
120
|
}
|
|
121
|
+
/** Options for a plain portal (mount children into `document.body`). */
|
|
122
|
+
interface PortalOptions extends ContainerOptions {
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Options shared by every overlay (dialog/popover/tooltip/dropdown/toast).
|
|
126
|
+
*
|
|
127
|
+
* An overlay is a portal + a reactive `when(open, …)` panel + focus/keyboard
|
|
128
|
+
* behavior. `open` drives visibility; the framework never mutates it — closing
|
|
129
|
+
* is cooperative: `onClose` fires on Escape (when `closeOnEscape`) and the app
|
|
130
|
+
* flips its own `open` signal there. Per-kind defaults (role, modality, focus,
|
|
131
|
+
* escape, restore) apply unless overridden here.
|
|
132
|
+
*/
|
|
133
|
+
interface OverlayOptions extends ContainerOptions {
|
|
134
|
+
/** Reactive open/visibility state. When it flips, the panel mounts/unmounts. */
|
|
135
|
+
readonly open: Bindable<boolean>;
|
|
136
|
+
/** Requested-close callback (fired on Escape when `closeOnEscape`). Flip `open` here. */
|
|
137
|
+
readonly onClose?: () => void;
|
|
138
|
+
/** Restore focus to the previously-focused element on close. Default: per-kind. */
|
|
139
|
+
readonly restoreFocus?: boolean;
|
|
140
|
+
/** id of the element to focus first when the overlay opens (else first focusable). */
|
|
141
|
+
readonly initialFocusId?: string;
|
|
142
|
+
/** Escape key invokes `onClose`. Default: per-kind. */
|
|
143
|
+
readonly closeOnEscape?: boolean;
|
|
144
|
+
}
|
|
119
145
|
type SectionBuilder = (section: SectionDSL) => void;
|
|
120
146
|
type ContainerBuilder = (container: ContainerDSL) => void;
|
|
121
147
|
type PageBuilder = (page: PageDSL) => void;
|
|
@@ -175,6 +201,42 @@ interface ContainerDSL extends ContentDSL {
|
|
|
175
201
|
* removal. It does NOT trap arbitrary global errors; errors remain observable.
|
|
176
202
|
*/
|
|
177
203
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
204
|
+
/**
|
|
205
|
+
* Render `builder`'s subtree into `document.body` instead of inline at this
|
|
206
|
+
* position (a neutral inline anchor is left behind). On the server there is no
|
|
207
|
+
* body, so the content renders inline; hydration relocates it to a body
|
|
208
|
+
* container to match the browser. Use for content that must escape overflow/
|
|
209
|
+
* stacking contexts (overlays, toasts). Cleanup removes the body container.
|
|
210
|
+
*/
|
|
211
|
+
portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
|
|
212
|
+
/**
|
|
213
|
+
* Modal dialog: portal + `when(open, …)` panel with `role="dialog"`,
|
|
214
|
+
* `aria-modal="true"`, focus trap + containment, Escape-to-close, and focus
|
|
215
|
+
* restore on close. `builder` fills the dialog panel.
|
|
216
|
+
*/
|
|
217
|
+
dialog(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
218
|
+
/**
|
|
219
|
+
* Non-modal popover: portal + `when(open, …)` panel with `role="dialog"`.
|
|
220
|
+
* Moves focus into the panel on open and restores it on close, but does not
|
|
221
|
+
* trap or contain focus. Escape closes by default.
|
|
222
|
+
*/
|
|
223
|
+
popover(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
224
|
+
/**
|
|
225
|
+
* Tooltip: portal + `when(open, …)` panel with `role="tooltip"`. Non-modal
|
|
226
|
+
* and does not steal focus (tooltips describe another element); no Escape
|
|
227
|
+
* handling by default.
|
|
228
|
+
*/
|
|
229
|
+
tooltip(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
230
|
+
/**
|
|
231
|
+
* Dropdown menu: portal + `when(open, …)` panel with `role="menu"`. Non-modal;
|
|
232
|
+
* moves focus into the menu on open, Escape closes, focus restored on close.
|
|
233
|
+
*/
|
|
234
|
+
dropdown(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
235
|
+
/**
|
|
236
|
+
* Toast: portal + `when(open, …)` panel with `role="status"` and
|
|
237
|
+
* `aria-live="polite"`. Non-modal and never steals focus; no Escape handling.
|
|
238
|
+
*/
|
|
239
|
+
toast(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
178
240
|
}
|
|
179
241
|
interface SectionDSL extends ContainerDSL {
|
|
180
242
|
}
|
|
@@ -236,6 +298,21 @@ declare class ContainerBuilderBase extends ContentBuilderBase implements Contain
|
|
|
236
298
|
form(key: string, builder: FormBuilder, options?: FormOptions): void;
|
|
237
299
|
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder): void;
|
|
238
300
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
301
|
+
portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
|
|
302
|
+
/**
|
|
303
|
+
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
304
|
+
* is a `when(open, panel)` conditional. The panel container carries the
|
|
305
|
+
* kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`
|
|
306
|
+
* descriptor is registered so the renderer wires focus/keyboard behavior to
|
|
307
|
+
* the same `open` signal that drives the panel. Reuses existing primitives
|
|
308
|
+
* (portal + when + container) — no new render path.
|
|
309
|
+
*/
|
|
310
|
+
private _overlay;
|
|
311
|
+
dialog(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
312
|
+
popover(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
313
|
+
tooltip(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
314
|
+
dropdown(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
315
|
+
toast(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
239
316
|
}
|
|
240
317
|
declare class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {
|
|
241
318
|
}
|
|
@@ -290,4 +367,4 @@ interface StreetUI {
|
|
|
290
367
|
}
|
|
291
368
|
declare const streetui: StreetUI;
|
|
292
369
|
|
|
293
|
-
export { type A11yOptions, AppBuilder, type AppDSL, type AppOptions, type Bindable, type BindableText, type BoundInputOptions, type ButtonOptions, type ContainerBuilder, ContainerBuilderImpl, type ContainerDSL, type ContainerOptions, type ContentDSL, type ControlledInputOptions, type ErrorBoundaryOptions, type ErrorFallbackBuilder, type ErrorSource, type FormBuilder, FormBuilderImpl, type FormDSL, type FormOptions, type HeadingOptions, type ImageOptions, type InputOptions, type InputOptionsBase, type LinkOptions, type ListBuilder, ListBuilderImpl, type ListDSL, type ListOptions, type ListPlanEntry, type PageBuilder, PageBuilderImpl, type PageDSL, type SectionBuilder, SectionBuilderImpl, type SectionDSL, type SectionOptions, StreetApp, type StreetUI, type TextOptions, type TextValue, reactiveListItemKey, reactiveListItemSignature, streetui };
|
|
370
|
+
export { type A11yOptions, AppBuilder, type AppDSL, type AppOptions, type Bindable, type BindableText, type BoundInputOptions, type ButtonOptions, type ContainerBuilder, ContainerBuilderImpl, type ContainerDSL, type ContainerOptions, type ContentDSL, type ControlledInputOptions, type ErrorBoundaryOptions, type ErrorFallbackBuilder, type ErrorSource, type FormBuilder, FormBuilderImpl, type FormDSL, type FormOptions, type HeadingOptions, type ImageOptions, type InputOptions, type InputOptionsBase, type LinkOptions, type ListBuilder, ListBuilderImpl, type ListDSL, type ListOptions, type ListPlanEntry, type OverlayOptions, type PageBuilder, PageBuilderImpl, type PageDSL, type PortalOptions, type SectionBuilder, SectionBuilderImpl, type SectionDSL, type SectionOptions, StreetApp, type StreetUI, type TextOptions, type TextValue, reactiveListItemKey, reactiveListItemSignature, streetui };
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ interface A11yOptions {
|
|
|
45
45
|
readonly ariaInvalid?: boolean;
|
|
46
46
|
/** aria-required — mark a form field as required. */
|
|
47
47
|
readonly ariaRequired?: boolean;
|
|
48
|
+
/** aria-modal — mark a dialog as modal (content outside is inert to AT). */
|
|
49
|
+
readonly ariaModal?: boolean;
|
|
48
50
|
}
|
|
49
51
|
interface TextOptions extends A11yOptions {
|
|
50
52
|
readonly class?: string;
|
|
@@ -116,6 +118,30 @@ interface FormOptions extends ContainerOptions {
|
|
|
116
118
|
}
|
|
117
119
|
interface ListOptions extends ContainerOptions {
|
|
118
120
|
}
|
|
121
|
+
/** Options for a plain portal (mount children into `document.body`). */
|
|
122
|
+
interface PortalOptions extends ContainerOptions {
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Options shared by every overlay (dialog/popover/tooltip/dropdown/toast).
|
|
126
|
+
*
|
|
127
|
+
* An overlay is a portal + a reactive `when(open, …)` panel + focus/keyboard
|
|
128
|
+
* behavior. `open` drives visibility; the framework never mutates it — closing
|
|
129
|
+
* is cooperative: `onClose` fires on Escape (when `closeOnEscape`) and the app
|
|
130
|
+
* flips its own `open` signal there. Per-kind defaults (role, modality, focus,
|
|
131
|
+
* escape, restore) apply unless overridden here.
|
|
132
|
+
*/
|
|
133
|
+
interface OverlayOptions extends ContainerOptions {
|
|
134
|
+
/** Reactive open/visibility state. When it flips, the panel mounts/unmounts. */
|
|
135
|
+
readonly open: Bindable<boolean>;
|
|
136
|
+
/** Requested-close callback (fired on Escape when `closeOnEscape`). Flip `open` here. */
|
|
137
|
+
readonly onClose?: () => void;
|
|
138
|
+
/** Restore focus to the previously-focused element on close. Default: per-kind. */
|
|
139
|
+
readonly restoreFocus?: boolean;
|
|
140
|
+
/** id of the element to focus first when the overlay opens (else first focusable). */
|
|
141
|
+
readonly initialFocusId?: string;
|
|
142
|
+
/** Escape key invokes `onClose`. Default: per-kind. */
|
|
143
|
+
readonly closeOnEscape?: boolean;
|
|
144
|
+
}
|
|
119
145
|
type SectionBuilder = (section: SectionDSL) => void;
|
|
120
146
|
type ContainerBuilder = (container: ContainerDSL) => void;
|
|
121
147
|
type PageBuilder = (page: PageDSL) => void;
|
|
@@ -175,6 +201,42 @@ interface ContainerDSL extends ContentDSL {
|
|
|
175
201
|
* removal. It does NOT trap arbitrary global errors; errors remain observable.
|
|
176
202
|
*/
|
|
177
203
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
204
|
+
/**
|
|
205
|
+
* Render `builder`'s subtree into `document.body` instead of inline at this
|
|
206
|
+
* position (a neutral inline anchor is left behind). On the server there is no
|
|
207
|
+
* body, so the content renders inline; hydration relocates it to a body
|
|
208
|
+
* container to match the browser. Use for content that must escape overflow/
|
|
209
|
+
* stacking contexts (overlays, toasts). Cleanup removes the body container.
|
|
210
|
+
*/
|
|
211
|
+
portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
|
|
212
|
+
/**
|
|
213
|
+
* Modal dialog: portal + `when(open, …)` panel with `role="dialog"`,
|
|
214
|
+
* `aria-modal="true"`, focus trap + containment, Escape-to-close, and focus
|
|
215
|
+
* restore on close. `builder` fills the dialog panel.
|
|
216
|
+
*/
|
|
217
|
+
dialog(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
218
|
+
/**
|
|
219
|
+
* Non-modal popover: portal + `when(open, …)` panel with `role="dialog"`.
|
|
220
|
+
* Moves focus into the panel on open and restores it on close, but does not
|
|
221
|
+
* trap or contain focus. Escape closes by default.
|
|
222
|
+
*/
|
|
223
|
+
popover(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
224
|
+
/**
|
|
225
|
+
* Tooltip: portal + `when(open, …)` panel with `role="tooltip"`. Non-modal
|
|
226
|
+
* and does not steal focus (tooltips describe another element); no Escape
|
|
227
|
+
* handling by default.
|
|
228
|
+
*/
|
|
229
|
+
tooltip(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
230
|
+
/**
|
|
231
|
+
* Dropdown menu: portal + `when(open, …)` panel with `role="menu"`. Non-modal;
|
|
232
|
+
* moves focus into the menu on open, Escape closes, focus restored on close.
|
|
233
|
+
*/
|
|
234
|
+
dropdown(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
235
|
+
/**
|
|
236
|
+
* Toast: portal + `when(open, …)` panel with `role="status"` and
|
|
237
|
+
* `aria-live="polite"`. Non-modal and never steals focus; no Escape handling.
|
|
238
|
+
*/
|
|
239
|
+
toast(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
178
240
|
}
|
|
179
241
|
interface SectionDSL extends ContainerDSL {
|
|
180
242
|
}
|
|
@@ -236,6 +298,21 @@ declare class ContainerBuilderBase extends ContentBuilderBase implements Contain
|
|
|
236
298
|
form(key: string, builder: FormBuilder, options?: FormOptions): void;
|
|
237
299
|
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder): void;
|
|
238
300
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
301
|
+
portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
|
|
302
|
+
/**
|
|
303
|
+
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
304
|
+
* is a `when(open, panel)` conditional. The panel container carries the
|
|
305
|
+
* kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`
|
|
306
|
+
* descriptor is registered so the renderer wires focus/keyboard behavior to
|
|
307
|
+
* the same `open` signal that drives the panel. Reuses existing primitives
|
|
308
|
+
* (portal + when + container) — no new render path.
|
|
309
|
+
*/
|
|
310
|
+
private _overlay;
|
|
311
|
+
dialog(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
312
|
+
popover(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
313
|
+
tooltip(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
314
|
+
dropdown(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
315
|
+
toast(key: string, options: OverlayOptions, builder: ContainerBuilder): void;
|
|
239
316
|
}
|
|
240
317
|
declare class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {
|
|
241
318
|
}
|
|
@@ -290,4 +367,4 @@ interface StreetUI {
|
|
|
290
367
|
}
|
|
291
368
|
declare const streetui: StreetUI;
|
|
292
369
|
|
|
293
|
-
export { type A11yOptions, AppBuilder, type AppDSL, type AppOptions, type Bindable, type BindableText, type BoundInputOptions, type ButtonOptions, type ContainerBuilder, ContainerBuilderImpl, type ContainerDSL, type ContainerOptions, type ContentDSL, type ControlledInputOptions, type ErrorBoundaryOptions, type ErrorFallbackBuilder, type ErrorSource, type FormBuilder, FormBuilderImpl, type FormDSL, type FormOptions, type HeadingOptions, type ImageOptions, type InputOptions, type InputOptionsBase, type LinkOptions, type ListBuilder, ListBuilderImpl, type ListDSL, type ListOptions, type ListPlanEntry, type PageBuilder, PageBuilderImpl, type PageDSL, type SectionBuilder, SectionBuilderImpl, type SectionDSL, type SectionOptions, StreetApp, type StreetUI, type TextOptions, type TextValue, reactiveListItemKey, reactiveListItemSignature, streetui };
|
|
370
|
+
export { type A11yOptions, AppBuilder, type AppDSL, type AppOptions, type Bindable, type BindableText, type BoundInputOptions, type ButtonOptions, type ContainerBuilder, ContainerBuilderImpl, type ContainerDSL, type ContainerOptions, type ContentDSL, type ControlledInputOptions, type ErrorBoundaryOptions, type ErrorFallbackBuilder, type ErrorSource, type FormBuilder, FormBuilderImpl, type FormDSL, type FormOptions, type HeadingOptions, type ImageOptions, type InputOptions, type InputOptionsBase, type LinkOptions, type ListBuilder, ListBuilderImpl, type ListDSL, type ListOptions, type ListPlanEntry, type OverlayOptions, type PageBuilder, PageBuilderImpl, type PageDSL, type PortalOptions, type SectionBuilder, SectionBuilderImpl, type SectionDSL, type SectionOptions, StreetApp, type StreetUI, type TextOptions, type TextValue, reactiveListItemKey, reactiveListItemSignature, streetui };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ function applyA11yProps(props, options) {
|
|
|
25
25
|
if (options.ariaCurrent !== void 0) props["aria-current"] = String(options.ariaCurrent);
|
|
26
26
|
if (options.ariaInvalid !== void 0) props["aria-invalid"] = String(options.ariaInvalid);
|
|
27
27
|
if (options.ariaRequired !== void 0) props["aria-required"] = String(options.ariaRequired);
|
|
28
|
+
if (options.ariaModal !== void 0) props["aria-modal"] = String(options.ariaModal);
|
|
28
29
|
}
|
|
29
30
|
function containerProps(options) {
|
|
30
31
|
const props = {};
|
|
@@ -56,6 +57,49 @@ function reactiveListItemSignature(item) {
|
|
|
56
57
|
function reactiveListItemKey(item, index) {
|
|
57
58
|
return itemIdentity(item, index);
|
|
58
59
|
}
|
|
60
|
+
var OVERLAY_KINDS = {
|
|
61
|
+
dialog: {
|
|
62
|
+
role: "dialog",
|
|
63
|
+
modal: true,
|
|
64
|
+
takesFocus: true,
|
|
65
|
+
ariaModal: true,
|
|
66
|
+
defaultCloseOnEscape: true,
|
|
67
|
+
defaultRestoreFocus: true
|
|
68
|
+
},
|
|
69
|
+
popover: {
|
|
70
|
+
role: "dialog",
|
|
71
|
+
modal: false,
|
|
72
|
+
takesFocus: true,
|
|
73
|
+
ariaModal: false,
|
|
74
|
+
defaultCloseOnEscape: true,
|
|
75
|
+
defaultRestoreFocus: true
|
|
76
|
+
},
|
|
77
|
+
tooltip: {
|
|
78
|
+
role: "tooltip",
|
|
79
|
+
modal: false,
|
|
80
|
+
takesFocus: false,
|
|
81
|
+
ariaModal: false,
|
|
82
|
+
defaultCloseOnEscape: false,
|
|
83
|
+
defaultRestoreFocus: false
|
|
84
|
+
},
|
|
85
|
+
dropdown: {
|
|
86
|
+
role: "menu",
|
|
87
|
+
modal: false,
|
|
88
|
+
takesFocus: true,
|
|
89
|
+
ariaModal: false,
|
|
90
|
+
defaultCloseOnEscape: true,
|
|
91
|
+
defaultRestoreFocus: true
|
|
92
|
+
},
|
|
93
|
+
toast: {
|
|
94
|
+
role: "status",
|
|
95
|
+
modal: false,
|
|
96
|
+
takesFocus: false,
|
|
97
|
+
ariaModal: false,
|
|
98
|
+
ariaLive: "polite",
|
|
99
|
+
defaultCloseOnEscape: false,
|
|
100
|
+
defaultRestoreFocus: false
|
|
101
|
+
}
|
|
102
|
+
};
|
|
59
103
|
var ContentBuilderBase = class {
|
|
60
104
|
constructor(_node, _graph) {
|
|
61
105
|
this._node = _node;
|
|
@@ -328,6 +372,74 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
328
372
|
);
|
|
329
373
|
}, { id });
|
|
330
374
|
}
|
|
375
|
+
// ── Portals & overlays ──────────────────────────────────────────────────────
|
|
376
|
+
portal(key, builder, options = {}) {
|
|
377
|
+
const node = this._graph.createNode("portal", {
|
|
378
|
+
key,
|
|
379
|
+
parent: this._node,
|
|
380
|
+
props: containerProps(options)
|
|
381
|
+
});
|
|
382
|
+
builder(new ContainerBuilderImpl(node, this._graph));
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
386
|
+
* is a `when(open, panel)` conditional. The panel container carries the
|
|
387
|
+
* kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`
|
|
388
|
+
* descriptor is registered so the renderer wires focus/keyboard behavior to
|
|
389
|
+
* the same `open` signal that drives the panel. Reuses existing primitives
|
|
390
|
+
* (portal + when + container) — no new render path.
|
|
391
|
+
*/
|
|
392
|
+
_overlay(kind, key, options, builder) {
|
|
393
|
+
const graph = this._graph;
|
|
394
|
+
const portalNode = graph.createNode("portal", {
|
|
395
|
+
key,
|
|
396
|
+
parent: this._node,
|
|
397
|
+
props: { key }
|
|
398
|
+
});
|
|
399
|
+
const openBindable = options.open;
|
|
400
|
+
const openSignal = isSignal(openBindable) ? openBindable : signal(openBindable);
|
|
401
|
+
const panelOptions = {
|
|
402
|
+
role: options.role ?? kind.role,
|
|
403
|
+
...kind.ariaModal ? { ariaModal: true } : {},
|
|
404
|
+
...kind.ariaLive !== void 0 ? { ariaLive: kind.ariaLive } : {},
|
|
405
|
+
...options.class !== void 0 ? { class: options.class } : {},
|
|
406
|
+
...options.ariaLabel !== void 0 ? { ariaLabel: options.ariaLabel } : {},
|
|
407
|
+
...options.ariaLabelledBy !== void 0 ? { ariaLabelledBy: options.ariaLabelledBy } : {},
|
|
408
|
+
...options.ariaDescribedBy !== void 0 ? { ariaDescribedBy: options.ariaDescribedBy } : {}
|
|
409
|
+
};
|
|
410
|
+
const portalBuilder = new ContainerBuilderImpl(portalNode, graph);
|
|
411
|
+
portalBuilder.when(openSignal, (panelHost) => {
|
|
412
|
+
panelHost.container(`${key}__panel`, builder, panelOptions);
|
|
413
|
+
});
|
|
414
|
+
const descriptor = {
|
|
415
|
+
open: openSignal,
|
|
416
|
+
modal: kind.modal,
|
|
417
|
+
takesFocus: kind.takesFocus,
|
|
418
|
+
closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,
|
|
419
|
+
restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,
|
|
420
|
+
...options.initialFocusId !== void 0 ? { initialFocusId: options.initialFocusId } : {},
|
|
421
|
+
...options.onClose !== void 0 ? { onClose: options.onClose } : {}
|
|
422
|
+
};
|
|
423
|
+
graph.registerHandler(
|
|
424
|
+
`__overlay__${portalNode.id}`,
|
|
425
|
+
() => descriptor
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
dialog(key, options, builder) {
|
|
429
|
+
this._overlay(OVERLAY_KINDS.dialog, key, options, builder);
|
|
430
|
+
}
|
|
431
|
+
popover(key, options, builder) {
|
|
432
|
+
this._overlay(OVERLAY_KINDS.popover, key, options, builder);
|
|
433
|
+
}
|
|
434
|
+
tooltip(key, options, builder) {
|
|
435
|
+
this._overlay(OVERLAY_KINDS.tooltip, key, options, builder);
|
|
436
|
+
}
|
|
437
|
+
dropdown(key, options, builder) {
|
|
438
|
+
this._overlay(OVERLAY_KINDS.dropdown, key, options, builder);
|
|
439
|
+
}
|
|
440
|
+
toast(key, options, builder) {
|
|
441
|
+
this._overlay(OVERLAY_KINDS.toast, key, options, builder);
|
|
442
|
+
}
|
|
331
443
|
};
|
|
332
444
|
var SectionBuilderImpl = class extends ContainerBuilderBase {
|
|
333
445
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builders.ts","../src/dsl.ts"],"sourcesContent":["/**\n * DSL builder implementations.\n *\n * Each builder wraps a GraphNode and provides the fluent API\n * for constructing the Semantic Application Graph via the DSL.\n *\n * Builders do NOT render anything — they only build the graph.\n */\n\nimport { ApplicationGraph, GraphNode, type Props } from '@streetui/graph';\nimport type {\n ContentDSL,\n ContainerDSL,\n SectionDSL,\n PageDSL,\n FormDSL,\n ListDSL,\n AppDSL,\n HeadingOptions,\n TextOptions,\n ButtonOptions,\n InputOptions,\n LinkOptions,\n ImageOptions,\n ContainerOptions,\n SectionOptions,\n FormOptions,\n ListOptions,\n A11yOptions,\n Bindable,\n BindableText,\n TextValue,\n ErrorBoundaryOptions,\n ErrorSource,\n PageBuilder,\n SectionBuilder,\n ContainerBuilder as ContainerBuilderFn,\n FormBuilder,\n ListBuilder,\n} from './dsl-types.js';\nimport { signal, derived, type Signal, type ReadonlySignal } from '@streetui/state';\n\n/**\n * A single reactive-list reconciliation descriptor (spec §15).\n *\n * Emitted by the `__listplan__<nodeId>` handler on every list change. `key` is\n * the item's identity-only reconciliation key (cheap to compute); `item` is the\n * source value *reference* used for identity short-circuiting; `sig()` computes\n * the content signature on demand (only when the reference changed); `build()`\n * materialises the full item subtree on demand (only for new/changed rows).\n */\nexport interface ListPlanEntry {\n readonly key: string;\n readonly item: unknown;\n readonly sig: () => string;\n readonly build: () => GraphNode;\n}\n\n// ── Signal helpers ────────────────────────────────────────────────────────────\n\nfunction isSignal(v: unknown): v is Signal<unknown> | ReadonlySignal<unknown> {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>)['get'] === 'function' &&\n typeof (v as Record<string, unknown>)['subscribe'] === 'function'\n );\n}\n\n/** Register a signal binding on the node and return the current static value. */\nfunction bindValue<T>(\n graph: ApplicationGraph,\n node: GraphNode,\n propKey: string,\n value: Bindable<T>,\n): T {\n if (isSignal(value)) {\n const signalId = `${node.id}:${propKey}`;\n node.stateRefs.push({ signalId, propKey });\n graph.registerHandler(`__signal__${signalId}`, value as unknown as () => unknown);\n return (value as ReadonlySignal<T>).peek();\n }\n return value as T;\n}\n\n// ── Helper to build Props from ContainerOptions ───────────────────────────────\n\n/**\n * Copy accessibility options onto a props bag as their corresponding HTML/ARIA\n * attribute names. Values are written as strings (booleans become \"true\"/\"false\"\n * rather than being dropped) so ARIA state attributes render literally. These\n * flow to the DOM via the renderer's generic attribute pass — no ARIA-specific\n * renderer code is involved.\n */\nfunction applyA11yProps(props: Props, options: A11yOptions): void {\n if (options.role !== undefined) props['role'] = options.role;\n if (options.tabIndex !== undefined) props['tabindex'] = String(options.tabIndex);\n if (options.ariaLabel !== undefined) props['aria-label'] = options.ariaLabel;\n if (options.ariaLabelledBy !== undefined) props['aria-labelledby'] = options.ariaLabelledBy;\n if (options.ariaDescribedBy !== undefined) props['aria-describedby'] = options.ariaDescribedBy;\n if (options.ariaExpanded !== undefined) props['aria-expanded'] = String(options.ariaExpanded);\n if (options.ariaControls !== undefined) props['aria-controls'] = options.ariaControls;\n if (options.ariaHidden !== undefined) props['aria-hidden'] = String(options.ariaHidden);\n if (options.ariaLive !== undefined) props['aria-live'] = options.ariaLive;\n if (options.ariaCurrent !== undefined) props['aria-current'] = String(options.ariaCurrent);\n if (options.ariaInvalid !== undefined) props['aria-invalid'] = String(options.ariaInvalid);\n if (options.ariaRequired !== undefined) props['aria-required'] = String(options.ariaRequired);\n}\n\nfunction containerProps(options: ContainerOptions): Props {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n if (options.key !== undefined) props['key'] = options.key;\n applyA11yProps(props, options);\n return props;\n}\n\n// ── Reactive-list item keying ──────────────────────────────────────────────────\n//\n// The `listOf` DSL signature does not take an explicit key extractor, so we\n// derive a stable reconciliation key from each item. The key combines an\n// *identity* part (so reordering the same items reuses their DOM nodes) with a\n// *value signature* (so an item whose data changed is treated as a fresh node\n// and re-rendered rather than silently kept stale by the shallow reconciler).\n\nfunction itemIdentity(item: unknown, index: number): string {\n if (item !== null && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('id' in obj) return `id:${String(obj['id'])}`;\n if ('key' in obj) return `key:${String(obj['key'])}`;\n return `idx:${index}`;\n }\n return `val:${String(item)}`;\n}\n\nfunction itemValueSignature(item: unknown): string {\n try {\n return JSON.stringify(item) ?? String(item);\n } catch {\n return String(item);\n }\n}\n\n/** Content signature used to detect in-place data changes of a stable item. */\nexport function reactiveListItemSignature(item: unknown): string {\n return itemValueSignature(item);\n}\n\n/** Stable, identity-only reconciliation key for a reactive-list item. */\nexport function reactiveListItemKey(item: unknown, index: number): string {\n return itemIdentity(item, index);\n}\n\n// ── Base content builder ──────────────────────────────────────────────────────\n\nclass ContentBuilderBase implements ContentDSL {\n constructor(\n protected readonly _node: GraphNode,\n protected readonly _graph: ApplicationGraph,\n ) {}\n\n heading(text: BindableText, options: HeadingOptions = {}): void {\n const props: Props = { level: options.level ?? 1 };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('heading', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', text);\n node.setProp('text', resolved);\n }\n\n text(content: BindableText, options: TextOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('text', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', content);\n node.setProp('text', resolved);\n }\n\n button(label: BindableText, options: ButtonOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('button', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.disabled !== undefined) {\n const resolvedDisabled = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolvedDisabled);\n }\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n\n input(options: InputOptions = {}): void {\n const props: Props = {};\n props['inputType'] = options.type ?? 'text';\n if (options.placeholder !== undefined) props['placeholder'] = options.placeholder;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n const node = this._graph.createNode('input', nodeOpts);\n\n // Two-way `bind` expands to a value binding + an input write-back. The type\n // system (BoundInputOptions vs ControlledInputOptions) guarantees `bind` is\n // never combined with explicit `value`/`onInput`, so there is no ambiguity.\n const bindSignal = options.bind;\n const valueBindable: Bindable<string> | undefined =\n bindSignal !== undefined ? bindSignal : options.value;\n const inputHandler: ((value: string) => void) | undefined =\n bindSignal !== undefined ? (v: string) => bindSignal.set(v) : options.onInput;\n\n if (valueBindable !== undefined) {\n const resolved = bindValue(this._graph, node, 'value', valueBindable);\n node.setProp('value', resolved);\n }\n if (options.disabled !== undefined) {\n const resolved = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolved);\n }\n if (inputHandler !== undefined) {\n const handlerKey = `input:${node.id}`;\n this._graph.registerHandler(handlerKey, inputHandler as () => unknown);\n node.addEvent({ type: 'input', handlerKey });\n }\n if (options.onChange !== undefined) {\n const handlerKey = `change:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onChange as () => unknown);\n node.addEvent({ type: 'change', handlerKey });\n }\n }\n\n image(options: ImageOptions): void {\n const props: Props = {\n src: options.src,\n alt: options.alt,\n };\n if (options.width !== undefined) props['width'] = options.width;\n if (options.height !== undefined) props['height'] = options.height;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n this._graph.createNode('image', nodeOpts);\n }\n\n link(label: BindableText, options: LinkOptions): void {\n const props: Props = {\n href: options.href,\n external: options.external ?? false,\n };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('link', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n}\n\n// ── Container builder ─────────────────────────────────────────────────────────\n\nclass ContainerBuilderBase extends ContentBuilderBase implements ContainerDSL {\n section(key: string, builder: SectionBuilder, options: SectionOptions = {}): void {\n const node = this._graph.createNode('section', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new SectionBuilderImpl(node, this._graph));\n }\n\n container(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('container', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n list(key: string, builder: ListBuilder, options: ListOptions = {}): void {\n const node = this._graph.createNode('list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ListBuilderImpl(node, this._graph));\n }\n\n listOf<T>(\n key: string,\n items: Signal<T[]> | ReadonlySignal<T[]>,\n renderItem: (item: T, index: number, content: ContentDSL) => void,\n options: ListOptions = {},\n ): void {\n const graph = this._graph;\n const node = graph.createNode('reactive-list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n\n // Register the driving signal so the runtime/renderer can subscribe to it.\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, items as unknown as () => unknown);\n\n // Build a single detached list-item subtree for one item. The item's\n // reconciliation `key` is identity-only, and its value signature is stored\n // in the internal `_sig` prop so the renderer can detect (and apply a\n // targeted update for) a data change on an item whose identity is stable.\n const buildItem = (item: T, index: number): GraphNode => {\n const itemKey = reactiveListItemKey(item, index);\n const itemNode = graph.createNode('list-item', {\n key: itemKey,\n // `_item` records the source item *reference* so the reconciler can\n // short-circuit unchanged rows by identity (no signature hashing); `_sig`\n // is the content signature used to detect an in-place data change when the\n // reference differs. Both are internal metadata (leading `_`) and never\n // reach the DOM.\n props: {\n key: itemKey,\n _sig: reactiveListItemSignature(item),\n // The item reference is stored as opaque internal metadata (never\n // rendered); cast through `unknown` since `T` is not a `PropValue`.\n _item: item as unknown as Props[string],\n },\n });\n renderItem(item, index, new ContainerBuilderImpl(itemNode, graph));\n return itemNode;\n };\n\n // Lazy reconciliation plan (spec §15 — the measured keyed-list hot path).\n //\n // Instead of eagerly rebuilding all N item GraphNodes (and hashing every item\n // with JSON.stringify) on *every* emission — the dominant cost of the old\n // `buildAll` path — the renderer receives lightweight descriptors and only\n // materialises a subtree for rows that are genuinely new or whose data\n // actually changed. `key` is cheap (identity only); `sig()` and `build()` are\n // thunks the reconciler calls on demand.\n const buildPlan = (raw: unknown): ListPlanEntry[] => {\n const arr = Array.isArray(raw) ? (raw as T[]) : [];\n const plan: ListPlanEntry[] = new Array(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i]!;\n const index = i;\n plan[i] = {\n key: reactiveListItemKey(item, index),\n item,\n sig: () => reactiveListItemSignature(item),\n build: () => buildItem(item, index),\n };\n }\n return plan;\n };\n graph.registerHandler(`__listplan__${node.id}`, buildPlan as unknown as () => unknown);\n\n // Build the initial children into the graph so the first mount renders them.\n const current = isSignal(items)\n ? (items as ReadonlySignal<T[]>).peek()\n : (items as unknown as T[]);\n const initial = Array.isArray(current) ? current : [];\n initial.forEach((item, i) => {\n node.appendChild(buildItem(item, i));\n });\n }\n\n form(key: string, builder: FormBuilder, options: FormOptions = {}): void {\n const props: Props = containerProps(options);\n const node = this._graph.createNode('form', {\n key,\n parent: this._node,\n props,\n });\n if (options.onSubmit !== undefined) {\n const handlerKey = `submit:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onSubmit as () => unknown);\n node.addEvent({ type: 'submit', handlerKey });\n }\n builder(new FormBuilderImpl(node, this._graph));\n }\n\n when(\n condition: Bindable<boolean>,\n builder: ContainerBuilderFn,\n elseBuilder?: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n // A dedicated 'conditional' node reuses the reactive-list reconciliation\n // machinery (same signal subscription + keyed reconcile) but renders as a\n // neutral <div> rather than a <ul>. It holds zero or one child branch.\n const node = graph.createNode('conditional', {\n parent: this._node,\n props: containerProps({}),\n });\n\n // Build the active branch as a single keyed container. Distinct keys for the\n // then/else branches make a flip a clean swap under the keyed reconciler.\n const buildBranch = (build: ContainerBuilderFn, tag: 'then' | 'else'): GraphNode => {\n const branchKey = `when-${tag}:${node.id}`;\n const branch = graph.createNode('container', {\n key: branchKey,\n props: { key: branchKey },\n });\n build(new ContainerBuilderImpl(branch, graph));\n return branch;\n };\n\n const buildAll = (raw: unknown): GraphNode[] => {\n if (raw) return [buildBranch(builder, 'then')];\n return elseBuilder !== undefined ? [buildBranch(elseBuilder, 'else')] : [];\n };\n\n if (isSignal(condition)) {\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, condition as unknown as () => unknown);\n graph.registerHandler(`__listbuild__${node.id}`, buildAll as unknown as () => unknown);\n const current = (condition as ReadonlySignal<boolean>).peek();\n for (const child of buildAll(current)) node.appendChild(child);\n } else {\n // Static condition — resolve once at build time, no reactive wiring.\n for (const child of buildAll(condition)) node.appendChild(child);\n }\n }\n\n errorBoundary(\n id: string,\n builder: ContainerBuilderFn,\n options: ErrorBoundaryOptions,\n ): void {\n // Normalise the observed error source(s) into an array.\n const sources: ErrorSource[] =\n options.source === undefined\n ? []\n : Array.isArray(options.source)\n ? [...options.source]\n : [options.source];\n\n // The boundary's own captured error (from a synchronous build throw) and a\n // retry nonce that forces a re-evaluation even when the boolean is unchanged.\n const localError = signal<unknown>(undefined);\n const retryNonce = signal<number>(0);\n\n const readError = (): unknown => {\n const local = localError.peek();\n if (local !== undefined && local !== null) return local;\n for (const s of sources) {\n const e = s.peek();\n if (e !== undefined && e !== null) return e;\n }\n return undefined;\n };\n\n // Reactive condition: true while an error is present. Reads every input so a\n // change in any source (or a retry) re-runs the conditional.\n const hasError = derived<boolean>(() => {\n retryNonce.get();\n localError.get();\n for (const s of sources) s.get();\n return readError() !== undefined;\n });\n\n const retry = (): void => {\n localError.set(undefined);\n options.onRetry?.();\n // Force the body branch to re-attempt even if no observed value changed.\n retryNonce.update((n) => n + 1);\n };\n\n // Wrap in a container so the whole boundary is addressable and disposes as a\n // unit. `when` provides the reactive body↔fallback swap (and its cleanup).\n this.container(id, (c) => {\n c.when(\n hasError,\n // Error state → fallback.\n (fb) => options.fallback(fb, readError(), retry),\n // Healthy state → body, guarded against synchronous build throws.\n (body) => {\n try {\n builder(body);\n } catch (err) {\n // Surface the throw as the boundary's error on the next microtask\n // (deferred to avoid re-entrant reconciliation during this build).\n queueMicrotask(() => localError.set(err));\n }\n },\n );\n }, { id });\n }\n}\n\n// ── Concrete builder implementations ─────────────────────────────────────────\n\nexport class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {}\nexport class ContainerBuilderImpl extends ContainerBuilderBase implements ContainerDSL {}\nexport class FormBuilderImpl extends ContainerBuilderBase implements FormDSL {}\n\nexport class ListBuilderImpl extends ContentBuilderBase implements ListDSL {\n item(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('list-item', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n}\n\nexport class PageBuilderImpl extends ContainerBuilderBase implements PageDSL {}\n\n// ── App builder ───────────────────────────────────────────────────────────────\n\nexport class AppBuilder implements AppDSL {\n constructor(private readonly _graph: ApplicationGraph) {}\n\n page(key: string, builder: PageBuilder): void {\n const node = this._graph.createNode('page', {\n key,\n parent: this._graph.root,\n props: { key },\n });\n builder(new PageBuilderImpl(node, this._graph));\n }\n}\n","/**\n * StreetUI DSL entry point.\n *\n * Usage:\n * import { streetui } from '@streetui/dsl';\n *\n * const app = streetui.app({ name: 'My App' });\n * app.page('home', page => {\n * page.section('hero', section => {\n * section.heading('Welcome');\n * section.button('Click me', { onClick: () => {} });\n * });\n * });\n *\n * const graph = app.build();\n */\n\nimport { ApplicationGraph } from '@streetui/graph';\nimport { AppBuilder } from './builders.js';\n\nexport interface AppOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport class StreetApp {\n private readonly _graph: ApplicationGraph;\n private readonly _builder: AppBuilder;\n\n constructor(options: AppOptions) {\n const graphOpts: { name: string; version?: string } = { name: options.name };\n if (options.version !== undefined) graphOpts.version = options.version;\n this._graph = new ApplicationGraph(graphOpts);\n this._builder = new AppBuilder(this._graph);\n }\n\n page(key: string, builder: Parameters<AppBuilder['page']>[1]): this {\n this._builder.page(key, builder);\n return this;\n }\n\n /** Compile to ApplicationGraph — validates and returns the graph. */\n build(): ApplicationGraph {\n const dc = this._graph.validate();\n dc.throwIfErrors();\n return this._graph;\n }\n\n /** Access graph before building (useful for inspection). */\n get graph(): ApplicationGraph {\n return this._graph;\n }\n}\n\nexport interface StreetUI {\n app(options: AppOptions): StreetApp;\n}\n\nexport const streetui: StreetUI = {\n app(options: AppOptions): StreetApp {\n return new StreetApp(options);\n },\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/builders.ts","../src/dsl.ts"],"sourcesContent":["/**\n * DSL builder implementations.\n *\n * Each builder wraps a GraphNode and provides the fluent API\n * for constructing the Semantic Application Graph via the DSL.\n *\n * Builders do NOT render anything — they only build the graph.\n */\n\nimport { ApplicationGraph, GraphNode, type Props } from '@streetui/graph';\nimport type {\n ContentDSL,\n ContainerDSL,\n SectionDSL,\n PageDSL,\n FormDSL,\n ListDSL,\n AppDSL,\n HeadingOptions,\n TextOptions,\n ButtonOptions,\n InputOptions,\n LinkOptions,\n ImageOptions,\n ContainerOptions,\n SectionOptions,\n FormOptions,\n ListOptions,\n PortalOptions,\n OverlayOptions,\n A11yOptions,\n Bindable,\n BindableText,\n TextValue,\n ErrorBoundaryOptions,\n ErrorSource,\n PageBuilder,\n SectionBuilder,\n ContainerBuilder as ContainerBuilderFn,\n FormBuilder,\n ListBuilder,\n} from './dsl-types.js';\nimport { signal, derived, type Signal, type ReadonlySignal } from '@streetui/state';\n\n/**\n * A single reactive-list reconciliation descriptor (spec §15).\n *\n * Emitted by the `__listplan__<nodeId>` handler on every list change. `key` is\n * the item's identity-only reconciliation key (cheap to compute); `item` is the\n * source value *reference* used for identity short-circuiting; `sig()` computes\n * the content signature on demand (only when the reference changed); `build()`\n * materialises the full item subtree on demand (only for new/changed rows).\n */\nexport interface ListPlanEntry {\n readonly key: string;\n readonly item: unknown;\n readonly sig: () => string;\n readonly build: () => GraphNode;\n}\n\n// ── Signal helpers ────────────────────────────────────────────────────────────\n\nfunction isSignal(v: unknown): v is Signal<unknown> | ReadonlySignal<unknown> {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>)['get'] === 'function' &&\n typeof (v as Record<string, unknown>)['subscribe'] === 'function'\n );\n}\n\n/** Register a signal binding on the node and return the current static value. */\nfunction bindValue<T>(\n graph: ApplicationGraph,\n node: GraphNode,\n propKey: string,\n value: Bindable<T>,\n): T {\n if (isSignal(value)) {\n const signalId = `${node.id}:${propKey}`;\n node.stateRefs.push({ signalId, propKey });\n graph.registerHandler(`__signal__${signalId}`, value as unknown as () => unknown);\n return (value as ReadonlySignal<T>).peek();\n }\n return value as T;\n}\n\n// ── Helper to build Props from ContainerOptions ───────────────────────────────\n\n/**\n * Copy accessibility options onto a props bag as their corresponding HTML/ARIA\n * attribute names. Values are written as strings (booleans become \"true\"/\"false\"\n * rather than being dropped) so ARIA state attributes render literally. These\n * flow to the DOM via the renderer's generic attribute pass — no ARIA-specific\n * renderer code is involved.\n */\nfunction applyA11yProps(props: Props, options: A11yOptions): void {\n if (options.role !== undefined) props['role'] = options.role;\n if (options.tabIndex !== undefined) props['tabindex'] = String(options.tabIndex);\n if (options.ariaLabel !== undefined) props['aria-label'] = options.ariaLabel;\n if (options.ariaLabelledBy !== undefined) props['aria-labelledby'] = options.ariaLabelledBy;\n if (options.ariaDescribedBy !== undefined) props['aria-describedby'] = options.ariaDescribedBy;\n if (options.ariaExpanded !== undefined) props['aria-expanded'] = String(options.ariaExpanded);\n if (options.ariaControls !== undefined) props['aria-controls'] = options.ariaControls;\n if (options.ariaHidden !== undefined) props['aria-hidden'] = String(options.ariaHidden);\n if (options.ariaLive !== undefined) props['aria-live'] = options.ariaLive;\n if (options.ariaCurrent !== undefined) props['aria-current'] = String(options.ariaCurrent);\n if (options.ariaInvalid !== undefined) props['aria-invalid'] = String(options.ariaInvalid);\n if (options.ariaRequired !== undefined) props['aria-required'] = String(options.ariaRequired);\n if (options.ariaModal !== undefined) props['aria-modal'] = String(options.ariaModal);\n}\n\nfunction containerProps(options: ContainerOptions): Props {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n if (options.key !== undefined) props['key'] = options.key;\n applyA11yProps(props, options);\n return props;\n}\n\n// ── Reactive-list item keying ──────────────────────────────────────────────────\n//\n// The `listOf` DSL signature does not take an explicit key extractor, so we\n// derive a stable reconciliation key from each item. The key combines an\n// *identity* part (so reordering the same items reuses their DOM nodes) with a\n// *value signature* (so an item whose data changed is treated as a fresh node\n// and re-rendered rather than silently kept stale by the shallow reconciler).\n\nfunction itemIdentity(item: unknown, index: number): string {\n if (item !== null && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('id' in obj) return `id:${String(obj['id'])}`;\n if ('key' in obj) return `key:${String(obj['key'])}`;\n return `idx:${index}`;\n }\n return `val:${String(item)}`;\n}\n\nfunction itemValueSignature(item: unknown): string {\n try {\n return JSON.stringify(item) ?? String(item);\n } catch {\n return String(item);\n }\n}\n\n/** Content signature used to detect in-place data changes of a stable item. */\nexport function reactiveListItemSignature(item: unknown): string {\n return itemValueSignature(item);\n}\n\n/** Stable, identity-only reconciliation key for a reactive-list item. */\nexport function reactiveListItemKey(item: unknown, index: number): string {\n return itemIdentity(item, index);\n}\n\n// ── Overlay kind configuration ──────────────────────────────────────────────────\n//\n// Each overlay builder (dialog/popover/tooltip/dropdown/toast) is the same\n// portal + `when(open, …)` panel + focus/keyboard behavior, differing only in\n// ARIA role, modality, whether it takes focus, and its escape/restore defaults.\n// This table captures those differences; `_overlay` does the shared assembly.\n\ninterface OverlayKindConfig {\n /** Default ARIA role for the panel. */\n readonly role: string;\n /** Trap + contain focus (modal semantics). */\n readonly modal: boolean;\n /** Move focus into the panel when it opens. */\n readonly takesFocus: boolean;\n /** Emit `aria-modal=\"true\"` on the panel. */\n readonly ariaModal: boolean;\n /** Emit an `aria-live` region on the panel (announcements). */\n readonly ariaLive?: 'polite' | 'assertive';\n /** Default for `closeOnEscape` when the caller does not specify it. */\n readonly defaultCloseOnEscape: boolean;\n /** Default for `restoreFocus` when the caller does not specify it. */\n readonly defaultRestoreFocus: boolean;\n}\n\nconst OVERLAY_KINDS = {\n dialog: {\n role: 'dialog', modal: true, takesFocus: true, ariaModal: true,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n popover: {\n role: 'dialog', modal: false, takesFocus: true, ariaModal: false,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n tooltip: {\n role: 'tooltip', modal: false, takesFocus: false, ariaModal: false,\n defaultCloseOnEscape: false, defaultRestoreFocus: false,\n },\n dropdown: {\n role: 'menu', modal: false, takesFocus: true, ariaModal: false,\n defaultCloseOnEscape: true, defaultRestoreFocus: true,\n },\n toast: {\n role: 'status', modal: false, takesFocus: false, ariaModal: false,\n ariaLive: 'polite', defaultCloseOnEscape: false, defaultRestoreFocus: false,\n },\n} as const satisfies Record<string, OverlayKindConfig>;\n\n/** The opaque descriptor the renderer reads from `__overlay__<portalId>`. */\ninterface OverlayBehaviorDescriptor {\n readonly open: ReadonlySignal<boolean>;\n readonly modal: boolean;\n readonly takesFocus: boolean;\n readonly closeOnEscape: boolean;\n readonly restoreFocus: boolean;\n readonly initialFocusId?: string;\n readonly onClose?: () => void;\n}\n\n// ── Base content builder ──────────────────────────────────────────────────────\n\nclass ContentBuilderBase implements ContentDSL {\n constructor(\n protected readonly _node: GraphNode,\n protected readonly _graph: ApplicationGraph,\n ) {}\n\n heading(text: BindableText, options: HeadingOptions = {}): void {\n const props: Props = { level: options.level ?? 1 };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('heading', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', text);\n node.setProp('text', resolved);\n }\n\n text(content: BindableText, options: TextOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('text', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'text', content);\n node.setProp('text', resolved);\n }\n\n button(label: BindableText, options: ButtonOptions = {}): void {\n const props: Props = {};\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('button', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.disabled !== undefined) {\n const resolvedDisabled = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolvedDisabled);\n }\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n\n input(options: InputOptions = {}): void {\n const props: Props = {};\n props['inputType'] = options.type ?? 'text';\n if (options.placeholder !== undefined) props['placeholder'] = options.placeholder;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n const node = this._graph.createNode('input', nodeOpts);\n\n // Two-way `bind` expands to a value binding + an input write-back. The type\n // system (BoundInputOptions vs ControlledInputOptions) guarantees `bind` is\n // never combined with explicit `value`/`onInput`, so there is no ambiguity.\n const bindSignal = options.bind;\n const valueBindable: Bindable<string> | undefined =\n bindSignal !== undefined ? bindSignal : options.value;\n const inputHandler: ((value: string) => void) | undefined =\n bindSignal !== undefined ? (v: string) => bindSignal.set(v) : options.onInput;\n\n if (valueBindable !== undefined) {\n const resolved = bindValue(this._graph, node, 'value', valueBindable);\n node.setProp('value', resolved);\n }\n if (options.disabled !== undefined) {\n const resolved = bindValue(this._graph, node, 'disabled', options.disabled);\n node.setProp('disabled', resolved);\n }\n if (inputHandler !== undefined) {\n const handlerKey = `input:${node.id}`;\n this._graph.registerHandler(handlerKey, inputHandler as () => unknown);\n node.addEvent({ type: 'input', handlerKey });\n }\n if (options.onChange !== undefined) {\n const handlerKey = `change:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onChange as () => unknown);\n node.addEvent({ type: 'change', handlerKey });\n }\n }\n\n image(options: ImageOptions): void {\n const props: Props = {\n src: options.src,\n alt: options.alt,\n };\n if (options.width !== undefined) props['width'] = options.width;\n if (options.height !== undefined) props['height'] = options.height;\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const nodeOpts: { key?: string; props: Props; parent: GraphNode } = {\n props,\n parent: this._node,\n };\n if (options.id !== undefined) nodeOpts.key = options.id;\n this._graph.createNode('image', nodeOpts);\n }\n\n link(label: BindableText, options: LinkOptions): void {\n const props: Props = {\n href: options.href,\n external: options.external ?? false,\n };\n if (options.class !== undefined) props['class'] = options.class;\n if (options.id !== undefined) props['id'] = options.id;\n applyA11yProps(props, options);\n const node = this._graph.createNode('link', { parent: this._node, props });\n const resolved = bindValue<TextValue>(this._graph, node, 'label', label);\n node.setProp('label', resolved);\n if (options.onClick !== undefined) {\n const handlerKey = `click:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onClick as () => unknown);\n node.addEvent({ type: 'click', handlerKey });\n }\n }\n}\n\n// ── Container builder ─────────────────────────────────────────────────────────\n\nclass ContainerBuilderBase extends ContentBuilderBase implements ContainerDSL {\n section(key: string, builder: SectionBuilder, options: SectionOptions = {}): void {\n const node = this._graph.createNode('section', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new SectionBuilderImpl(node, this._graph));\n }\n\n container(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('container', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n list(key: string, builder: ListBuilder, options: ListOptions = {}): void {\n const node = this._graph.createNode('list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ListBuilderImpl(node, this._graph));\n }\n\n listOf<T>(\n key: string,\n items: Signal<T[]> | ReadonlySignal<T[]>,\n renderItem: (item: T, index: number, content: ContentDSL) => void,\n options: ListOptions = {},\n ): void {\n const graph = this._graph;\n const node = graph.createNode('reactive-list', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n\n // Register the driving signal so the runtime/renderer can subscribe to it.\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, items as unknown as () => unknown);\n\n // Build a single detached list-item subtree for one item. The item's\n // reconciliation `key` is identity-only, and its value signature is stored\n // in the internal `_sig` prop so the renderer can detect (and apply a\n // targeted update for) a data change on an item whose identity is stable.\n const buildItem = (item: T, index: number): GraphNode => {\n const itemKey = reactiveListItemKey(item, index);\n const itemNode = graph.createNode('list-item', {\n key: itemKey,\n // `_item` records the source item *reference* so the reconciler can\n // short-circuit unchanged rows by identity (no signature hashing); `_sig`\n // is the content signature used to detect an in-place data change when the\n // reference differs. Both are internal metadata (leading `_`) and never\n // reach the DOM.\n props: {\n key: itemKey,\n _sig: reactiveListItemSignature(item),\n // The item reference is stored as opaque internal metadata (never\n // rendered); cast through `unknown` since `T` is not a `PropValue`.\n _item: item as unknown as Props[string],\n },\n });\n renderItem(item, index, new ContainerBuilderImpl(itemNode, graph));\n return itemNode;\n };\n\n // Lazy reconciliation plan (spec §15 — the measured keyed-list hot path).\n //\n // Instead of eagerly rebuilding all N item GraphNodes (and hashing every item\n // with JSON.stringify) on *every* emission — the dominant cost of the old\n // `buildAll` path — the renderer receives lightweight descriptors and only\n // materialises a subtree for rows that are genuinely new or whose data\n // actually changed. `key` is cheap (identity only); `sig()` and `build()` are\n // thunks the reconciler calls on demand.\n const buildPlan = (raw: unknown): ListPlanEntry[] => {\n const arr = Array.isArray(raw) ? (raw as T[]) : [];\n const plan: ListPlanEntry[] = new Array(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i]!;\n const index = i;\n plan[i] = {\n key: reactiveListItemKey(item, index),\n item,\n sig: () => reactiveListItemSignature(item),\n build: () => buildItem(item, index),\n };\n }\n return plan;\n };\n graph.registerHandler(`__listplan__${node.id}`, buildPlan as unknown as () => unknown);\n\n // Build the initial children into the graph so the first mount renders them.\n const current = isSignal(items)\n ? (items as ReadonlySignal<T[]>).peek()\n : (items as unknown as T[]);\n const initial = Array.isArray(current) ? current : [];\n initial.forEach((item, i) => {\n node.appendChild(buildItem(item, i));\n });\n }\n\n form(key: string, builder: FormBuilder, options: FormOptions = {}): void {\n const props: Props = containerProps(options);\n const node = this._graph.createNode('form', {\n key,\n parent: this._node,\n props,\n });\n if (options.onSubmit !== undefined) {\n const handlerKey = `submit:${node.id}`;\n this._graph.registerHandler(handlerKey, options.onSubmit as () => unknown);\n node.addEvent({ type: 'submit', handlerKey });\n }\n builder(new FormBuilderImpl(node, this._graph));\n }\n\n when(\n condition: Bindable<boolean>,\n builder: ContainerBuilderFn,\n elseBuilder?: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n // A dedicated 'conditional' node reuses the reactive-list reconciliation\n // machinery (same signal subscription + keyed reconcile) but renders as a\n // neutral <div> rather than a <ul>. It holds zero or one child branch.\n const node = graph.createNode('conditional', {\n parent: this._node,\n props: containerProps({}),\n });\n\n // Build the active branch as a single keyed container. Distinct keys for the\n // then/else branches make a flip a clean swap under the keyed reconciler.\n const buildBranch = (build: ContainerBuilderFn, tag: 'then' | 'else'): GraphNode => {\n const branchKey = `when-${tag}:${node.id}`;\n const branch = graph.createNode('container', {\n key: branchKey,\n props: { key: branchKey },\n });\n build(new ContainerBuilderImpl(branch, graph));\n return branch;\n };\n\n const buildAll = (raw: unknown): GraphNode[] => {\n if (raw) return [buildBranch(builder, 'then')];\n return elseBuilder !== undefined ? [buildBranch(elseBuilder, 'else')] : [];\n };\n\n if (isSignal(condition)) {\n const signalId = `${node.id}:items`;\n node.stateRefs.push({ signalId, propKey: 'items' });\n graph.registerHandler(`__signal__${signalId}`, condition as unknown as () => unknown);\n graph.registerHandler(`__listbuild__${node.id}`, buildAll as unknown as () => unknown);\n const current = (condition as ReadonlySignal<boolean>).peek();\n for (const child of buildAll(current)) node.appendChild(child);\n } else {\n // Static condition — resolve once at build time, no reactive wiring.\n for (const child of buildAll(condition)) node.appendChild(child);\n }\n }\n\n errorBoundary(\n id: string,\n builder: ContainerBuilderFn,\n options: ErrorBoundaryOptions,\n ): void {\n // Normalise the observed error source(s) into an array.\n const sources: ErrorSource[] =\n options.source === undefined\n ? []\n : Array.isArray(options.source)\n ? [...options.source]\n : [options.source];\n\n // The boundary's own captured error (from a synchronous build throw) and a\n // retry nonce that forces a re-evaluation even when the boolean is unchanged.\n const localError = signal<unknown>(undefined);\n const retryNonce = signal<number>(0);\n\n const readError = (): unknown => {\n const local = localError.peek();\n if (local !== undefined && local !== null) return local;\n for (const s of sources) {\n const e = s.peek();\n if (e !== undefined && e !== null) return e;\n }\n return undefined;\n };\n\n // Reactive condition: true while an error is present. Reads every input so a\n // change in any source (or a retry) re-runs the conditional.\n const hasError = derived<boolean>(() => {\n retryNonce.get();\n localError.get();\n for (const s of sources) s.get();\n return readError() !== undefined;\n });\n\n const retry = (): void => {\n localError.set(undefined);\n options.onRetry?.();\n // Force the body branch to re-attempt even if no observed value changed.\n retryNonce.update((n) => n + 1);\n };\n\n // Wrap in a container so the whole boundary is addressable and disposes as a\n // unit. `when` provides the reactive body↔fallback swap (and its cleanup).\n this.container(id, (c) => {\n c.when(\n hasError,\n // Error state → fallback.\n (fb) => options.fallback(fb, readError(), retry),\n // Healthy state → body, guarded against synchronous build throws.\n (body) => {\n try {\n builder(body);\n } catch (err) {\n // Surface the throw as the boundary's error on the next microtask\n // (deferred to avoid re-entrant reconciliation during this build).\n queueMicrotask(() => localError.set(err));\n }\n },\n );\n }, { id });\n }\n\n // ── Portals & overlays ──────────────────────────────────────────────────────\n\n portal(key: string, builder: ContainerBuilderFn, options: PortalOptions = {}): void {\n const node = this._graph.createNode('portal', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n\n /**\n * Shared assembly for every overlay kind: a `portal` node whose single child\n * is a `when(open, panel)` conditional. The panel container carries the\n * kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`\n * descriptor is registered so the renderer wires focus/keyboard behavior to\n * the same `open` signal that drives the panel. Reuses existing primitives\n * (portal + when + container) — no new render path.\n */\n private _overlay(\n kind: OverlayKindConfig,\n key: string,\n options: OverlayOptions,\n builder: ContainerBuilderFn,\n ): void {\n const graph = this._graph;\n const portalNode = graph.createNode('portal', {\n key,\n parent: this._node,\n props: { key },\n });\n\n // Resolve `open` to a signal we can both bind (drives the panel's `when`)\n // and hand to the renderer (drives focus behavior). A literal is wrapped so\n // the panel still mounts/unmounts through the same reactive path.\n const openBindable = options.open;\n const openSignal: ReadonlySignal<boolean> = isSignal(openBindable)\n ? (openBindable as ReadonlySignal<boolean>)\n : signal(openBindable as boolean);\n\n // Panel a11y semantics (kind defaults, overridable via options).\n const panelOptions: ContainerOptions = {\n role: options.role ?? kind.role,\n ...(kind.ariaModal ? { ariaModal: true } : {}),\n ...(kind.ariaLive !== undefined ? { ariaLive: kind.ariaLive } : {}),\n ...(options.class !== undefined ? { class: options.class } : {}),\n ...(options.ariaLabel !== undefined ? { ariaLabel: options.ariaLabel } : {}),\n ...(options.ariaLabelledBy !== undefined ? { ariaLabelledBy: options.ariaLabelledBy } : {}),\n ...(options.ariaDescribedBy !== undefined ? { ariaDescribedBy: options.ariaDescribedBy } : {}),\n };\n\n const portalBuilder = new ContainerBuilderImpl(portalNode, graph);\n portalBuilder.when(openSignal, (panelHost) => {\n panelHost.container(`${key}__panel`, builder, panelOptions);\n });\n\n const descriptor: OverlayBehaviorDescriptor = {\n open: openSignal,\n modal: kind.modal,\n takesFocus: kind.takesFocus,\n closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,\n restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,\n ...(options.initialFocusId !== undefined ? { initialFocusId: options.initialFocusId } : {}),\n ...(options.onClose !== undefined ? { onClose: options.onClose } : {}),\n };\n graph.registerHandler(\n `__overlay__${portalNode.id}`,\n (() => descriptor) as unknown as () => unknown,\n );\n }\n\n dialog(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.dialog, key, options, builder);\n }\n\n popover(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.popover, key, options, builder);\n }\n\n tooltip(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.tooltip, key, options, builder);\n }\n\n dropdown(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.dropdown, key, options, builder);\n }\n\n toast(key: string, options: OverlayOptions, builder: ContainerBuilderFn): void {\n this._overlay(OVERLAY_KINDS.toast, key, options, builder);\n }\n}\n\n// ── Concrete builder implementations ─────────────────────────────────────────\n\nexport class SectionBuilderImpl extends ContainerBuilderBase implements SectionDSL {}\nexport class ContainerBuilderImpl extends ContainerBuilderBase implements ContainerDSL {}\nexport class FormBuilderImpl extends ContainerBuilderBase implements FormDSL {}\n\nexport class ListBuilderImpl extends ContentBuilderBase implements ListDSL {\n item(key: string, builder: ContainerBuilderFn, options: ContainerOptions = {}): void {\n const node = this._graph.createNode('list-item', {\n key,\n parent: this._node,\n props: containerProps(options),\n });\n builder(new ContainerBuilderImpl(node, this._graph));\n }\n}\n\nexport class PageBuilderImpl extends ContainerBuilderBase implements PageDSL {}\n\n// ── App builder ───────────────────────────────────────────────────────────────\n\nexport class AppBuilder implements AppDSL {\n constructor(private readonly _graph: ApplicationGraph) {}\n\n page(key: string, builder: PageBuilder): void {\n const node = this._graph.createNode('page', {\n key,\n parent: this._graph.root,\n props: { key },\n });\n builder(new PageBuilderImpl(node, this._graph));\n }\n}\n","/**\n * StreetUI DSL entry point.\n *\n * Usage:\n * import { streetui } from '@streetui/dsl';\n *\n * const app = streetui.app({ name: 'My App' });\n * app.page('home', page => {\n * page.section('hero', section => {\n * section.heading('Welcome');\n * section.button('Click me', { onClick: () => {} });\n * });\n * });\n *\n * const graph = app.build();\n */\n\nimport { ApplicationGraph } from '@streetui/graph';\nimport { AppBuilder } from './builders.js';\n\nexport interface AppOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport class StreetApp {\n private readonly _graph: ApplicationGraph;\n private readonly _builder: AppBuilder;\n\n constructor(options: AppOptions) {\n const graphOpts: { name: string; version?: string } = { name: options.name };\n if (options.version !== undefined) graphOpts.version = options.version;\n this._graph = new ApplicationGraph(graphOpts);\n this._builder = new AppBuilder(this._graph);\n }\n\n page(key: string, builder: Parameters<AppBuilder['page']>[1]): this {\n this._builder.page(key, builder);\n return this;\n }\n\n /** Compile to ApplicationGraph — validates and returns the graph. */\n build(): ApplicationGraph {\n const dc = this._graph.validate();\n dc.throwIfErrors();\n return this._graph;\n }\n\n /** Access graph before building (useful for inspection). */\n get graph(): ApplicationGraph {\n return this._graph;\n }\n}\n\nexport interface StreetUI {\n app(options: AppOptions): StreetApp;\n}\n\nexport const streetui: StreetUI = {\n app(options: AppOptions): StreetApp {\n return new StreetApp(options);\n },\n};\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streetui/dsl",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "StreetUI semantic TypeScript DSL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"clean": "rm -rf dist"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@streetui/core": "1.
|
|
29
|
-
"@streetui/graph": "1.
|
|
30
|
-
"@streetui/state": "1.
|
|
28
|
+
"@streetui/core": "1.7.0",
|
|
29
|
+
"@streetui/graph": "1.7.0",
|
|
30
|
+
"@streetui/state": "1.7.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "*",
|