@snackbit/opendil 0.1.0 → 0.2.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.
Files changed (88) hide show
  1. package/README.md +74 -137
  2. package/bin/opendil.mjs +66 -11
  3. package/bin/publish-directory.d.mts +18 -0
  4. package/bin/publish-directory.mjs +173 -17
  5. package/dist/agent-spec.js +9 -0
  6. package/dist/chunk-RPZW4WVX.js +2 -0
  7. package/dist/chunk-ZSTXLIS6.js +2 -0
  8. package/dist/index.js +1 -10
  9. package/dist/runtime/frame.html +117 -44
  10. package/dist/runtime/frame.js +501 -505
  11. package/dist/spec/genui.agent.full.md +1927 -0
  12. package/dist/spec/genui.agent.md +479 -0
  13. package/dist/spec/genui.examples.md +836 -0
  14. package/dist/styled-renderer-PHI4MNPF.js +2441 -0
  15. package/dist/styles.css +115 -42
  16. package/dist/types/agent-spec.d.ts +12 -0
  17. package/dist/types/components/ui/controls/select.d.ts +14 -0
  18. package/dist/types/components/ui/controls/tabs.d.ts +7 -0
  19. package/dist/types/components/ui/controls/toggle-group.d.ts +3 -2
  20. package/dist/types/components/ui/display/chart.d.ts +6 -12
  21. package/dist/types/components/ui/media/carousel.d.ts +1 -1
  22. package/dist/types/components/ui/overlays/collapsible.d.ts +6 -0
  23. package/dist/types/components/ui/overlays/popover.d.ts +2 -1
  24. package/dist/types/components/ui/overlays/ui-scope.d.ts +16 -0
  25. package/dist/types/dil/custom-component.d.ts +1 -1
  26. package/dist/types/dil/dil-renderer.d.ts +58 -23
  27. package/dist/types/dil/isolation/frame-startup.d.ts +18 -0
  28. package/dist/types/dil/isolation/frame-theme.d.ts +14 -0
  29. package/dist/types/dil/isolation/frame-viewport.d.ts +30 -0
  30. package/dist/types/dil/isolation/isolated-renderer.d.ts +13 -7
  31. package/dist/types/dil/isolation/overlay-room.d.ts +29 -0
  32. package/dist/types/dil/isolation/viewport-scroll.d.ts +3 -2
  33. package/dist/types/dil/message-renderer.d.ts +6 -5
  34. package/dist/types/dil/parser/dil-parser.d.ts +44 -3
  35. package/dist/types/dil/parser/lexical.d.ts +13 -2
  36. package/dist/types/dil/parser/literal-tag.d.ts +16 -0
  37. package/dist/types/dil/parser/markdown-lexing.d.ts +41 -0
  38. package/dist/types/dil/parser/types.d.ts +22 -1
  39. package/dist/types/dil/parser/unfinished.d.ts +22 -0
  40. package/dist/types/dil/parser/vocabulary.d.ts +12 -0
  41. package/dist/types/dil/render-error.d.ts +47 -0
  42. package/dist/types/dil/renderer-environment.d.ts +19 -8
  43. package/dist/types/dil/runtime/document.d.ts +18 -6
  44. package/dist/types/dil/runtime/execution-queue.d.ts +2 -1
  45. package/dist/types/dil/runtime/expressions.d.ts +8 -5
  46. package/dist/types/dil/runtime/inline-worker.d.ts +33 -0
  47. package/dist/types/dil/runtime/view-cost.d.ts +2 -2
  48. package/dist/types/dil/styled-renderer.d.ts +39 -0
  49. package/dist/types/dil/view/conditional-view.d.ts +3 -3
  50. package/dist/types/dil/view/markdown-node.d.ts +3 -3
  51. package/dist/types/dil/view/node-children.d.ts +3 -3
  52. package/dist/types/dil/view/node-view.d.ts +2 -2
  53. package/dist/types/dil/view/progressive-reveal.d.ts +5 -4
  54. package/dist/types/dil/view/render-boundary.d.ts +13 -0
  55. package/dist/types/dil/view/render-limit.d.ts +1 -1
  56. package/dist/types/dil/view/repeated-nodes.d.ts +4 -4
  57. package/dist/types/dil/view/reveal/controller.d.ts +9 -2
  58. package/dist/types/dil/view/reveal/presentation.d.ts +1 -1
  59. package/dist/types/dil/view/scroll/controller.d.ts +16 -2
  60. package/dist/types/dil/view/scroll/host-viewport.d.ts +24 -0
  61. package/dist/types/dil/view/scroll/root-tracker.d.ts +17 -0
  62. package/dist/types/dil/view/scroll/scroll-root.d.ts +36 -0
  63. package/dist/types/dil/view/scroll-options.d.ts +15 -0
  64. package/dist/types/dil/view/stream-follow.d.ts +10 -3
  65. package/dist/types/dil/view/table-context.d.ts +1 -1
  66. package/dist/types/dil/view/virtual-flow.d.ts +3 -3
  67. package/dist/types/dil/widgets/action-feedback.d.ts +1 -1
  68. package/dist/types/dil/widgets/charts/chart-hover.d.ts +17 -0
  69. package/dist/types/dil/widgets/charts/chart-legend.d.ts +1 -1
  70. package/dist/types/dil/widgets/charts/chart-pie.d.ts +16 -0
  71. package/dist/types/dil/widgets/charts/chart-series.d.ts +10 -2
  72. package/dist/types/dil/widgets/charts/chart-snapping.d.ts +3 -5
  73. package/dist/types/dil/widgets/charts/snap-cursor.d.ts +3 -7
  74. package/dist/types/dil/widgets/charts/snap-tooltip.d.ts +6 -4
  75. package/dist/types/dil/widgets/code-block.d.ts +1 -1
  76. package/dist/types/dil/widgets/controls.d.ts +2 -2
  77. package/dist/types/dil/widgets/graphs/node-graph.d.ts +1 -1
  78. package/dist/types/dil/widgets/graphs/service-node.d.ts +1 -1
  79. package/dist/types/dil/widgets/primitives/primitive.d.ts +4 -4
  80. package/dist/types/index.d.ts +9 -8
  81. package/dist/types/ui.d.ts +11 -8
  82. package/dist/ui.js +1 -1
  83. package/package.json +13 -2
  84. package/styles/tailwind.css +53 -1
  85. package/styles/tokens.css +3 -0
  86. package/dist/chunk-ZWAN2JCV.js +0 -2
  87. package/dist/runtime/vm.js +0 -6
  88. package/dist/shadow-renderer-F25KL3C4.js +0 -2363
@@ -0,0 +1,836 @@
1
+ # GenUI Examples
2
+
3
+ Search `Component: slider`, `Composition: table`, `SVG element: path`, or
4
+ `Task: controlled-counter`. Every `dil` fence is an independent complete document.
5
+ Do not concatenate examples without renaming their document-wide declarations.
6
+ Data is synthetic unless a recipe explicitly describes supplied records.
7
+
8
+ Lookup index:
9
+
10
+ - Text: text, title, caption, badge, label, CodeBlock.
11
+ - Media: AsyncImage.
12
+ - Layout: box, row, grid, grid-item, spacer, divider, table, table-row,
13
+ table-cell, popover, popover-trigger, popover-content, carousel, carousel-item.
14
+ - Inputs: button, pressable, input, slider, checkbox, radio-group, radio,
15
+ segmented-control.
16
+ - Visualizations: svg, Chart, NodeGraph, Mermaid; every allowed SVG descendant.
17
+ - Assets: icon and the complete supported-name gallery.
18
+ - Compositions: grid, table, popover, carousel, radio-group, SVG definitions,
19
+ inline icons, nested layouts, conditional/repeated named children.
20
+ - Tasks: static-card, controlled-counter, conditional-status, dynamic-list,
21
+ validation-form, host-action, external-data, incomplete-stream.
22
+
23
+ ## 1. Output format and safety
24
+
25
+ #### Task: static-card
26
+
27
+ Generate source directly. This fence is for lookup and verification; a generated
28
+ UI response normally omits the surrounding fence.
29
+
30
+ ```dil
31
+ <box border padding={4} radius="xl" gap={3} maxWidth={480}>
32
+ <title>Release review</title>
33
+ <text>Prepared for review.</text>
34
+ <badge color="success"><icon name="circle-check"/> Ready</badge>
35
+ </box>
36
+ ```
37
+
38
+ ## 2. Syntax and parsing
39
+
40
+ ### Markdown
41
+
42
+ #### Syntax: markdown-prose
43
+
44
+ ```dil
45
+ # Review notes
46
+
47
+ **Two records** are ready. Values below are synthetic.
48
+
49
+ - Alpha: 12 units
50
+ - Beta: 18 units
51
+
52
+ | Record | Units |
53
+ | --- | --- |
54
+ | Alpha | 12 |
55
+ | Beta | 18 |
56
+
57
+ > Verify the source before making a decision.
58
+ ```
59
+
60
+ #### Syntax: literal-code
61
+
62
+ CodeBlock, fenced code, and inline code spans protect braces and tags from DIL
63
+ parsing.
64
+
65
+ ```dil
66
+ <CodeBlock language="text">
67
+ {literal braces}
68
+ <unsupported-example>This is displayed source.</unsupported-example>
69
+ </CodeBlock>
70
+ <text>A literal opening brace: {"{"}</text>
71
+
72
+ Pass `{ leading: false }` to `debounce`, and wrap the chart in a `<div>`.
73
+ ```
74
+
75
+ ### JavaScript expressions
76
+
77
+ #### Syntax: expressions-and-attributes
78
+
79
+ ```dil
80
+ {@body const item = {name:"Alpha",amount:12}}
81
+ {@body const field = "name"}
82
+ <box border padding={{x:4,y:3}}>
83
+ <text>{item[field]}: {item.amount * 2}</text>
84
+ <caption>{`Original amount: ${item.amount.toFixed(1)}`}</caption>
85
+ </box>
86
+ ```
87
+
88
+ ### State declarations
89
+
90
+ #### Task: controlled-counter
91
+
92
+ Click Increment to update both the number and status. Reset restores zero.
93
+
94
+ ```dil
95
+ {@body const [count,setCount] = DIL.useState(0)}
96
+ {@body const increment = () => setCount(previous => previous + 1)}
97
+ <row gap={2} align="center" wrap="wrap">
98
+ <button onClick={increment}>Increment</button>
99
+ <button variant="outline" onClick={() => setCount(0)}>Reset</button>
100
+ <text tabularNums>Count: {count}</text>
101
+ </row>
102
+ {#if count > 0}<badge color="success">Started</badge>{:else}<caption>Waiting</caption>{/if}
103
+ ```
104
+
105
+ ### Conditional rendering
106
+
107
+ #### Task: conditional-status
108
+
109
+ ```dil
110
+ {@body const [status,setStatus] = DIL.useState("waiting")}
111
+ <segmented-control aria-label="Status" value={status} onChange={setStatus} options={[{value:"waiting",label:"Waiting"},{value:"ready",label:"Ready"},{value:"blocked",label:"Blocked"}]}/>
112
+ {#if status === "ready"}
113
+ <badge color="success">Ready</badge>
114
+ {:else if status === "blocked"}
115
+ <badge color="danger">Blocked</badge>
116
+ {:else}
117
+ <caption>Waiting</caption>
118
+ {/if}
119
+ ```
120
+
121
+ #### Task: dynamic-list
122
+
123
+ IDs remain unique after removal and addition. Counter-based IDs are separate
124
+ from the current array length.
125
+
126
+ ```dil
127
+ {@body const [items,setItems] = DIL.useState([{id:"item-1",name:"Item 1"}])}
128
+ {@body const [nextId,setNextId] = DIL.useState(2)}
129
+ <button onClick={() => { setItems(previous => [...previous,{id:`item-${nextId}`,name:`Item ${nextId}`}]); setNextId(previous => previous + 1); }}>Add item</button>
130
+ {#if items.length === 0}<caption>No items.</caption>{/if}
131
+ {#each items as item,index}
132
+ <row gap={2} align="center">
133
+ <text>{index + 1}. {item.name}</text>
134
+ <button variant="ghost" onClick={() => setItems(previous => previous.filter(entry => entry.id !== item.id))}>Remove {item.name}</button>
135
+ </row>
136
+ {/each}
137
+ ```
138
+
139
+ #### Syntax: nested-each-scopes
140
+
141
+ ```dil
142
+ {@body const groups = [{id:"review",name:"Review",items:[{id:"alpha",name:"Alpha"},{id:"beta",name:"Beta"}]}]}
143
+ {#each groups as group}
144
+ <box border padding={3} gap={2}>
145
+ <title>{group.name}</title>
146
+ {#each group.items as item,index}<text>{group.name}: {index + 1}. {item.name}</text>{/each}
147
+ </box>
148
+ {/each}
149
+ ```
150
+
151
+ #### Task: incomplete-stream
152
+
153
+ Send the following unfinished prefix without signalling completion:
154
+
155
+ ```text
156
+ <box padding={
157
+ ```
158
+
159
+ Append `4}><text>Ready</text></box>`. Complete only after the combined document is:
160
+
161
+ ```dil
162
+ <box padding={4}><text>Ready</text></box>
163
+ ```
164
+
165
+ #### Syntax: streaming-repeat
166
+
167
+ The repeat waits for its closing directive. A first chunk can end here:
168
+
169
+ ```text
170
+ {#each [{id:"a",name:"Alpha"}] as item}<text>{item.name}</text>
171
+ ```
172
+
173
+ Append `{/each}` to finish this executable source:
174
+
175
+ ```dil
176
+ {#each [{id:"a",name:"Alpha"}] as item}<text>{item.name}</text>{/each}
177
+ ```
178
+
179
+ ## 3. Component API
180
+
181
+ ### Text components
182
+
183
+ #### Component: text
184
+
185
+ ```dil
186
+ <text color="primary" size="lg" weight="medium" tabularNums>1,234 units</text>
187
+ ```
188
+
189
+ #### Component: title
190
+
191
+ ```dil
192
+ <title size="xl">Quarterly review</title>
193
+ ```
194
+
195
+ #### Component: caption
196
+
197
+ ```dil
198
+ <caption color="secondary">Synthetic values, shown in units.</caption>
199
+ ```
200
+
201
+ #### Component: badge
202
+
203
+ ```dil
204
+ <badge color="warning"><icon name="alert-triangle" size="xs"/> Needs review</badge>
205
+ ```
206
+
207
+ #### Component: label
208
+
209
+ The sibling input names itself explicitly; label has no association prop.
210
+
211
+ ```dil
212
+ {@body const [name,setName] = DIL.useState("")}
213
+ <label>Name</label>
214
+ <input aria-label="Name" value={name} onChange={setName}/>
215
+ ```
216
+
217
+ #### Component: CodeBlock
218
+
219
+ Editing changes this widget's draft only. It does not execute the source or
220
+ update an authored state binding.
221
+
222
+ ```dil
223
+ <CodeBlock language="javascript" editable>
224
+ const message = "Hello";
225
+ console.log(message);
226
+ </CodeBlock>
227
+ ```
228
+
229
+ ### Media components
230
+
231
+ #### Component: AsyncImage
232
+
233
+ ```dil
234
+ <box maxWidth={480}>
235
+ <AsyncImage query="Placeholder mountain landscape"/>
236
+ <caption>Offline illustration, not a photograph.</caption>
237
+ </box>
238
+ ```
239
+
240
+ ### Layout components
241
+
242
+ #### Component: box
243
+
244
+ ```dil
245
+ <box border={{size:1,color:"subtle"}} padding={{x:4,y:3}} radius="xl" background="surface-secondary" gap={2} maxWidth={480}>
246
+ <title>Review panel</title><text>Two records are ready.</text>
247
+ </box>
248
+ ```
249
+
250
+ #### Component: row
251
+
252
+ ```dil
253
+ <row gap={2} align="center" justify="between" wrap="wrap">
254
+ <text>Release status</text><badge color="success">Ready</badge>
255
+ </row>
256
+ ```
257
+
258
+ #### Component: grid
259
+
260
+ ```dil
261
+ <grid columns={2} gap={3}>
262
+ <box border padding={3}><title>Alpha</title><text>12 units</text></box>
263
+ <box border padding={3}><title>Beta</title><text>18 units</text></box>
264
+ </grid>
265
+ ```
266
+
267
+ #### Component: grid-item
268
+
269
+ #### Composition: grid > grid-item
270
+
271
+ ```dil
272
+ <grid columns={2} gap={3}>
273
+ <grid-item border padding={3} radius="lg"><title>Alpha</title></grid-item>
274
+ <grid-item border padding={3} radius="lg"><title>Beta</title></grid-item>
275
+ </grid>
276
+ ```
277
+
278
+ #### Component: spacer
279
+
280
+ ```dil
281
+ <row gap={2} align="center"><title>Review</title><spacer/><badge>Prepared</badge></row>
282
+ ```
283
+
284
+ #### Component: divider
285
+
286
+ ```dil
287
+ <box gap={3}><text>Overview</text><divider/><text>Details</text></box>
288
+ ```
289
+
290
+ #### Component: table
291
+
292
+ #### Composition: table > table-row > table-cell
293
+
294
+ ```dil
295
+ <table>
296
+ <table-row><table-cell><text weight="medium">Name</text></table-cell><table-cell><text weight="medium">Units</text></table-cell></table-row>
297
+ <table-row><table-cell>Alpha</table-cell><table-cell>12</table-cell></table-row>
298
+ </table>
299
+ ```
300
+
301
+ #### Component: table-row
302
+
303
+ #### Composition: table > each > table-row
304
+
305
+ ```dil
306
+ {@body const records = [{id:"a",name:"Alpha",amount:12},{id:"b",name:"Beta",amount:18}]}
307
+ <table>
308
+ {#each records as item}<table-row><table-cell>{item.name}</table-cell><table-cell>{item.amount}</table-cell></table-row>{/each}
309
+ </table>
310
+ ```
311
+
312
+ #### Component: table-cell
313
+
314
+ #### Composition: table-cell > generic content
315
+
316
+ ```dil
317
+ <table>
318
+ <table-row>
319
+ <table-cell padding={3}><row gap={2} align="center"><icon name="package-check"/><text>Alpha</text></row></table-cell>
320
+ <table-cell><badge color="success">Ready</badge></table-cell>
321
+ </table-row>
322
+ </table>
323
+ ```
324
+
325
+ #### Component: popover
326
+
327
+ #### Composition: popover > popover-trigger + popover-content
328
+
329
+ ```dil
330
+ <popover>
331
+ <popover-trigger><button variant="outline">Details</button></popover-trigger>
332
+ <popover-content><text>Additional review notes.</text></popover-content>
333
+ </popover>
334
+ ```
335
+
336
+ #### Component: popover-trigger
337
+
338
+ #### Composition: popover-trigger > button
339
+
340
+ ```dil
341
+ <popover>
342
+ <popover-trigger><button aria-label="Review details" variant="ghost"><icon name="info"/></button></popover-trigger>
343
+ <popover-content><caption>No additional action required.</caption></popover-content>
344
+ </popover>
345
+ ```
346
+
347
+ #### Component: popover-content
348
+
349
+ #### Composition: popover-content > generic content
350
+
351
+ ```dil
352
+ {@body const [showNotes,setShowNotes] = DIL.useState(true)}
353
+ <popover>
354
+ <popover-trigger><button variant="outline">Display options</button></popover-trigger>
355
+ <popover-content side="top" align="end">
356
+ <box gap={2}>
357
+ <checkbox checked={showNotes} onChange={setShowNotes} lineThrough={false}>Show notes</checkbox>
358
+ <caption>Selection: {showNotes ? "shown" : "hidden"}</caption>
359
+ </box>
360
+ </popover-content>
361
+ </popover>
362
+ {#if showNotes}<text>Review notes are visible.</text>{/if}
363
+ ```
364
+
365
+ #### Component: carousel
366
+
367
+ #### Composition: carousel > carousel-item
368
+
369
+ ```dil
370
+ <carousel>
371
+ <carousel-item><box border padding={4}><title>Alpha</title><text>First option.</text></box></carousel-item>
372
+ <carousel-item><box border padding={4}><title>Beta</title><text>Second option.</text></box></carousel-item>
373
+ </carousel>
374
+ ```
375
+
376
+ #### Component: carousel-item
377
+
378
+ #### Composition: carousel > each > carousel-item
379
+
380
+ ```dil
381
+ {@body const cards = [{id:"a",title:"Alpha"},{id:"b",title:"Beta"}]}
382
+ <carousel>
383
+ {#each cards as card}<carousel-item><box border padding={4}><title>{card.title}</title></box></carousel-item>{/each}
384
+ </carousel>
385
+ ```
386
+
387
+ #### Composition: box > grid > grid-item > row
388
+
389
+ ```dil
390
+ <box gap={3}>
391
+ <title>Sample overview</title>
392
+ <grid columns={2} gap={3}>
393
+ <grid-item border padding={3} radius="lg"><row gap={2} align="center"><icon name="wallet"/><text>12 units</text></row></grid-item>
394
+ <grid-item border padding={3} radius="lg"><row gap={2} align="center"><icon name="users"/><text>3 reviewers</text></row></grid-item>
395
+ </grid>
396
+ </box>
397
+ ```
398
+
399
+ #### Composition: table > if > table-row
400
+
401
+ ```dil
402
+ {@body const [showExtra,setShowExtra] = DIL.useState(false)}
403
+ <checkbox checked={showExtra} onChange={setShowExtra} lineThrough={false}>Show extra row</checkbox>
404
+ <table>
405
+ <table-row><table-cell>Alpha</table-cell><table-cell>12</table-cell></table-row>
406
+ {#if showExtra}<table-row><table-cell>Beta</table-cell><table-cell>18</table-cell></table-row>{/if}
407
+ </table>
408
+ ```
409
+
410
+ ### Input components
411
+
412
+ #### Component: button
413
+
414
+ ```dil
415
+ {@body const [count,setCount] = DIL.useState(0)}
416
+ <button variant="outline" size="sm" onClick={() => setCount(previous => previous + 1)}>Add one</button>
417
+ <text>Count: {count}</text>
418
+ ```
419
+
420
+ #### Component: pressable
421
+
422
+ #### Composition: pressable > noninteractive generic content
423
+
424
+ ```dil
425
+ {@body const [selected,setSelected] = DIL.useState(false)}
426
+ <pressable border padding={4} radius="xl" gap={2} onClick={() => setSelected(previous => !previous)}>
427
+ <title>Alpha option</title><text>Select this local option.</text>
428
+ <badge>{selected ? "Selected" : "Not selected"}</badge>
429
+ </pressable>
430
+ ```
431
+
432
+ #### Component: input
433
+
434
+ ```dil
435
+ {@body const [name,setName] = DIL.useState("")}
436
+ <input aria-label="Display name" placeholder="Your name" value={name} onChange={setName}/>
437
+ <text>Hello, {name.trim() || "reader"}.</text>
438
+ ```
439
+
440
+ #### Component: slider
441
+
442
+ ```dil
443
+ {@body const [level,setLevel] = DIL.useState(40)}
444
+ <slider aria-label="Level" min={0} max={100} step={5} value={level} onChange={setLevel} marks={[{label:"Low"},{label:"High"}]}/>
445
+ <text tabularNums>Level: {level}%</text>
446
+ ```
447
+
448
+ #### Component: checkbox
449
+
450
+ ```dil
451
+ {@body const [done,setDone] = DIL.useState(false)}
452
+ <checkbox checked={done} onChange={setDone}>Review Alpha</checkbox>
453
+ <caption>{done ? "Review complete" : "Review pending"}</caption>
454
+ ```
455
+
456
+ #### Component: radio-group
457
+
458
+ #### Composition: radio-group > radio
459
+
460
+ ```dil
461
+ {@body const [billing,setBilling] = DIL.useState("monthly")}
462
+ <radio-group aria-label="Billing" value={billing} onChange={setBilling} direction="row">
463
+ <radio value="monthly">Monthly</radio><radio value="annual">Annual</radio>
464
+ </radio-group>
465
+ <text>Billing: {billing}</text>
466
+ ```
467
+
468
+ #### Component: radio
469
+
470
+ #### Composition: radio-group > each > radio
471
+
472
+ ```dil
473
+ {@body const choices = [{id:"small",label:"Small"},{id:"large",label:"Large"}]}
474
+ {@body const [size,setSize] = DIL.useState("small")}
475
+ <radio-group aria-label="Size" value={size} onChange={setSize}>
476
+ {#each choices as choice}<radio value={choice.id}>{choice.label}</radio>{/each}
477
+ </radio-group>
478
+ <caption>Selected: {size}</caption>
479
+ ```
480
+
481
+ #### Component: segmented-control
482
+
483
+ ```dil
484
+ {@body const [view,setView] = DIL.useState("summary")}
485
+ <segmented-control aria-label="View" value={view} onChange={setView} options={[{value:"summary",label:"Summary"},{value:"details",label:"Details"}]}/>
486
+ {#if view === "summary"}<text>Summary content.</text>{:else}<text>Detailed content.</text>{/if}
487
+ ```
488
+
489
+ ## 4. Specialized components
490
+
491
+ ### Data-linked components
492
+
493
+ #### Task: external-data
494
+
495
+ These declarations represent records supplied in a prompt. The filter is local;
496
+ no provider, fetch, subscription, or write-back channel is created.
497
+
498
+ ```dil
499
+ {@body const records = [{id:"a",name:"Alpha",amount:12},{id:"b",name:"Beta",amount:18}]}
500
+ {@body const [query,setQuery] = DIL.useState("")}
501
+ {@body const visible = records.filter(item => item.name.toLowerCase().includes(query.toLowerCase()))}
502
+ <input aria-label="Filter supplied records" value={query} onChange={setQuery}/>
503
+ {#if visible.length > 0}
504
+ <table>{#each visible as item}<table-row><table-cell>{item["name"]}</table-cell><table-cell>{item.amount}</table-cell></table-row>{/each}</table>
505
+ {:else}
506
+ <caption>No matching records.</caption>
507
+ {/if}
508
+ ```
509
+
510
+ ### Links and citations
511
+
512
+ #### Task: visible-source-url
513
+
514
+ No citation or navigable-link component exists. Display supplied references as
515
+ text; the explicit action below copies the address.
516
+
517
+ ```dil
518
+ {@body const sourceUrl = "https://example.com/releases"}
519
+ <title>Supplied release notes</title>
520
+ <text>{sourceUrl}</text>
521
+ <button onClick={() => GenUI.copy(sourceUrl)}>Copy URL</button>
522
+ ```
523
+
524
+ ### Embedded application blocks
525
+
526
+ #### Task: local-application-panel
527
+
528
+ This is local UI composition. It does not embed or run another application.
529
+
530
+ ```dil
531
+ {@body const [view,setView] = DIL.useState("overview")}
532
+ <box border padding={4} gap={3}>
533
+ <title>Review workspace</title>
534
+ <segmented-control aria-label="Workspace view" value={view} onChange={setView} options={[{value:"overview",label:"Overview"},{value:"notes",label:"Notes"}]}/>
535
+ {#if view === "overview"}<text>Two records prepared.</text>{:else}<caption>Notes remain in this local document.</caption>{/if}
536
+ </box>
537
+ ```
538
+
539
+ ## 5. Visualizations
540
+
541
+ ### Images
542
+
543
+ #### Component: svg
544
+
545
+ #### Composition: svg > g > rect + circle + text
546
+
547
+ ```dil
548
+ <caption>Static sample status drawing.</caption>
549
+ <svg viewBox="0 0 240 100" width="100%" height={100}>
550
+ <g>
551
+ <rect x={5} y={5} width={230} height={90} rx={8} fill="#eeeeff"/>
552
+ <circle cx={35} cy={50} r={12} fill="#16794b"/>
553
+ <text x={60} y={56} fontSize={18} fill="#252838">Ready</text>
554
+ </g>
555
+ </svg>
556
+ ```
557
+
558
+ #### SVG element: defs
559
+
560
+ #### Composition: svg > defs > marker
561
+
562
+ ```dil
563
+ <svg viewBox="0 0 200 50" width={200} height={50}>
564
+ <defs><marker id="defs-arrow" markerWidth={10} markerHeight={10} refX={8} refY={3} orient="auto"><path d="M0 0 L8 3 L0 6 Z" fill="#5e4cff"/></marker></defs>
565
+ <path d="M10 25 L180 25" stroke="#5e4cff" strokeWidth={2} markerEnd="url(#defs-arrow)"/>
566
+ </svg>
567
+ ```
568
+
569
+ #### SVG element: marker
570
+
571
+ ```dil
572
+ <svg viewBox="0 0 200 50" width={200} height={50}>
573
+ <defs><marker id="marker-arrow" markerWidth={10} markerHeight={10} refX={8} refY={3} orient="auto"><path d="M0 0 L8 3 L0 6 Z" fill="currentColor"/></marker></defs>
574
+ <path d="M10 25 L180 25" stroke="currentColor" strokeWidth={2} markerEnd="url(#marker-arrow)"/>
575
+ </svg>
576
+ ```
577
+
578
+ #### SVG element: path
579
+
580
+ ```dil
581
+ <svg viewBox="0 0 120 80" width={120} height={80}><path d="M10 65 L60 10 L110 65 Z" fill="#eeeeff" stroke="#5e4cff" strokeWidth={2}/></svg>
582
+ ```
583
+
584
+ #### SVG element: rect
585
+
586
+ ```dil
587
+ <svg viewBox="0 0 120 80" width={120} height={80}><rect x={10} y={10} width={100} height={60} rx={8} fill="#5e4cff"/></svg>
588
+ ```
589
+
590
+ #### SVG element: circle
591
+
592
+ ```dil
593
+ <svg viewBox="0 0 80 80" width={80} height={80}><circle cx={40} cy={40} r={25} fill="#16794b"/></svg>
594
+ ```
595
+
596
+ #### SVG element: line
597
+
598
+ The element is recognized, but endpoint props x1/y1/x2/y2 are unavailable. Use
599
+ the path in this example for visible line geometry.
600
+
601
+ ```dil
602
+ <svg viewBox="0 0 120 50" width={120} height={50}><line stroke="#5e4cff"/><path d="M10 25 L110 25" stroke="#5e4cff" strokeWidth={2}/></svg>
603
+ ```
604
+
605
+ #### SVG element: polyline
606
+
607
+ Points is unavailable. The path shows the equivalent supported visible geometry.
608
+
609
+ ```dil
610
+ <svg viewBox="0 0 120 80" width={120} height={80}><polyline fill="none" stroke="#5e4cff"/><path d="M10 60 L50 20 L100 60" fill="none" stroke="#5e4cff" strokeWidth={2}/></svg>
611
+ ```
612
+
613
+ #### SVG element: polygon
614
+
615
+ Points is unavailable; use path for a visible closed polygon.
616
+
617
+ ```dil
618
+ <svg viewBox="0 0 120 80" width={120} height={80}><polygon fill="#eeeeff"/><path d="M10 65 L60 10 L110 65 Z" fill="#eeeeff" stroke="#5e4cff"/></svg>
619
+ ```
620
+
621
+ #### SVG element: g
622
+
623
+ ```dil
624
+ <svg viewBox="0 0 140 80" width={140} height={80}><g fill="#5e4cff"><circle cx={35} cy={40} r={20}/><rect x={75} y={20} width={40} height={40}/></g></svg>
625
+ ```
626
+
627
+ #### SVG element: ellipse
628
+
629
+ ```dil
630
+ <svg viewBox="0 0 140 80" width={140} height={80}><ellipse cx={70} cy={40} rx={50} ry={25} fill="#eeeeff" stroke="#5e4cff"/></svg>
631
+ ```
632
+
633
+ #### SVG element: text
634
+
635
+ Within SVG, text has SVG props and does not accept DIL color/size props.
636
+
637
+ ```dil
638
+ <svg viewBox="0 0 160 60" width={160} height={60}><text x={10} y={35} fontSize={18} fontWeight={500} fill="currentColor">Alpha</text></svg>
639
+ ```
640
+
641
+ #### SVG element: tspan
642
+
643
+ #### Composition: svg > text > tspan
644
+
645
+ ```dil
646
+ <svg viewBox="0 0 180 80" width={180} height={80}><text x={10} y={25} fontSize={16} fill="currentColor">Alpha<tspan x={10} y={55}>12 sample units</tspan></text></svg>
647
+ ```
648
+
649
+ #### SVG element: linearGradient
650
+
651
+ #### Composition: svg > defs > linearGradient > stop
652
+
653
+ The vocabulary recognizes gradient definitions, but offset/stopColor props are
654
+ unavailable. This demonstrates accepted composition only; use solid fills for
655
+ reliable authored color output.
656
+
657
+ ```dil
658
+ <svg viewBox="0 0 120 60" width={120} height={60}>
659
+ <defs><linearGradient id="limited-gradient"><stop/></linearGradient></defs>
660
+ <rect x={10} y={10} width={100} height={40} fill="#5e4cff"/>
661
+ </svg>
662
+ ```
663
+
664
+ #### SVG element: stop
665
+
666
+ ```dil
667
+ <svg viewBox="0 0 120 60" width={120} height={60}>
668
+ <defs><linearGradient id="limited-stop"><stop opacity={1}/></linearGradient></defs>
669
+ <rect x={10} y={10} width={100} height={40} fill="#5e4cff"/>
670
+ </svg>
671
+ ```
672
+
673
+ ### Charts
674
+
675
+ #### Component: Chart
676
+
677
+ #### Chart type: line
678
+
679
+ ```dil
680
+ <Chart content={{chartType:"line",data:[{month:"Jan",actual:10,plan:12},{month:"Feb",actual:15,plan:14}],xKey:"month",series:[{dataKey:"actual",label:"Actual"},{dataKey:"plan",label:"Plan"}]}}/>
681
+ <caption>Synthetic units. Actual rises from 10 to 15.</caption>
682
+ ```
683
+
684
+ #### Chart type: bar
685
+
686
+ ```dil
687
+ <Chart content={{chartType:"bar",data:[{name:"Alpha",amount:12},{name:"Beta",amount:18}],xKey:"name",series:[{dataKey:"amount",label:"Units"}]}}/>
688
+ <caption>Synthetic values: Alpha 12, Beta 18.</caption>
689
+ ```
690
+
691
+ #### Chart type: scatter
692
+
693
+ ```dil
694
+ <Chart content={{chartType:"scatter",data:[{hours:1,units:4},{hours:2,units:7},{hours:3,units:9}],xKey:"hours",series:[{dataKey:"units",label:"Units"}]}}/>
695
+ <caption>Synthetic relationship between hours and units.</caption>
696
+ ```
697
+
698
+ #### Chart type: pie
699
+
700
+ ```dil
701
+ <Chart content={{chartType:"pie",data:[{name:"Alpha",amount:30},{name:"Beta",amount:70}],nameKey:"name",valueKey:"amount"}}/>
702
+ <caption>Synthetic shares: Alpha 30%, Beta 70%.</caption>
703
+ ```
704
+
705
+ #### Component: NodeGraph
706
+
707
+ ```dil
708
+ {@body const [selectedId,setSelectedId] = DIL.useState("api")}
709
+ {@body const graph = {nodes:[{id:"api",label:"API",sub:"Entry",x:0,y:0},{id:"db",label:"Database",sub:"Storage",x:250,y:0}],edges:[{id:"api-db",source:"api",target:"db",label:"reads"}]}}
710
+ <NodeGraph content={graph} selectedId={selectedId} onSelect={setSelectedId}/>
711
+ <text>Selected service: {selectedId}</text>
712
+ ```
713
+
714
+ #### Component: Mermaid
715
+
716
+ ```dil
717
+ <Mermaid source={"flowchart LR\n Request --> Review\n Review --> Ready"}/>
718
+ ```
719
+
720
+ #### Syntax: mermaid-markdown-fence
721
+
722
+ This complete DIL example contains a Markdown Mermaid fence. The outer four-backtick
723
+ fence belongs to this reference only; copy its inner source to the renderer.
724
+
725
+ ````dil
726
+ ```mermaid
727
+ flowchart LR
728
+ Alpha --> Beta
729
+ ```
730
+ ````
731
+
732
+ ### Maps
733
+
734
+ #### Task: location-data-without-map
735
+
736
+ No map/geocoding adapter exists. Display coordinates as supplied.
737
+
738
+ ```dil
739
+ {@body const places = [{id:"berlin",name:"Berlin",lat:52.52,lon:13.405}]}
740
+ <table>{#each places as place}<table-row><table-cell>{place.name}</table-cell><table-cell>{place.lat}, {place.lon}</table-cell></table-row>{/each}</table>
741
+ <caption>No map or geocoding service is connected.</caption>
742
+ ```
743
+
744
+ ## 6. Interactivity
745
+
746
+ ### State management
747
+
748
+ #### Task: immutable-record-updates
749
+
750
+ ```dil
751
+ {@body const [tasks,setTasks] = DIL.useState([{id:"a",name:"Review Alpha",done:false},{id:"b",name:"Review Beta",done:false}])}
752
+ {@body const completeCount = tasks.filter(task => task.done).length}
753
+ <text>{completeCount} of {tasks.length} complete</text>
754
+ {#each tasks as task}
755
+ <checkbox checked={task.done} onChange={checked => setTasks(previous => previous.map(entry => entry.id === task.id ? {...entry,done:checked} : entry))}>{task.name}</checkbox>
756
+ {/each}
757
+ ```
758
+
759
+ ### Event callbacks
760
+
761
+ #### Task: validation-form
762
+
763
+ The handler guards the action as well as disabling the control. No form or
764
+ server submission is implied.
765
+
766
+ ```dil
767
+ {@body const [name,setName] = DIL.useState("")}
768
+ {@body const valid = name.trim().length >= 2 && name.trim().length <= 80}
769
+ <box gap={3} maxWidth={420}>
770
+ <label>Name</label>
771
+ <input aria-label="Name" value={name} onChange={setName} placeholder="At least two characters"/>
772
+ {#if !valid}<caption color="danger">Enter a name between 2 and 80 characters.</caption>{/if}
773
+ <button disabled={!valid} onClick={() => { if (valid) GenUI.copy(name.trim()); }}>Copy name</button>
774
+ </box>
775
+ ```
776
+
777
+ ### Data bindings
778
+
779
+ #### Task: computed-fields-and-derived-data
780
+
781
+ ```dil
782
+ {@body const records = [{id:"a",name:"Alpha",amount:12},{id:"b",name:"Beta",amount:18}]}
783
+ {@body const field = "name"}
784
+ {@body const total = records.reduce((sum,item) => sum + item.amount,0)}
785
+ <text>Total: {total}</text>
786
+ {#each records as item}<text>{item[field]}: {item.amount}</text>{/each}
787
+ ```
788
+
789
+ ### Host actions
790
+
791
+ #### Task: host-action
792
+
793
+ ```dil
794
+ {@body const report = "Review complete: Alpha and Beta checked."}
795
+ <button onClick={() => GenUI.copy(report)}><icon name="copy"/> Copy report</button>
796
+ ```
797
+
798
+ #### Task: pressable-copy
799
+
800
+ ```dil
801
+ <pressable border padding={4} radius="xl" gap={2} onClick={() => GenUI.copy("Alpha: 12 sample units")}>
802
+ <title>Alpha</title><text>12 sample units</text><caption>Copy this summary</caption>
803
+ </pressable>
804
+ ```
805
+
806
+ ## 7. Assets
807
+
808
+ ### Icons
809
+
810
+ #### Component: icon
811
+
812
+ #### Composition: button > icon + inline text
813
+
814
+ ```dil
815
+ <button onClick={() => GenUI.copy("Review complete")}><icon name="copy" size="xs"/> Copy review</button>
816
+ ```
817
+
818
+ #### Composition: button > icon with accessible action name
819
+
820
+ ```dil
821
+ {@body const [count,setCount] = DIL.useState(1)}
822
+ <button aria-label="Reset count" variant="ghost" onClick={() => setCount(0)}><icon name="rotate-ccw"/></button>
823
+ <text>Count: {count}</text>
824
+ ```
825
+
826
+ #### Assets: supported-icon-gallery
827
+
828
+ All supported names appear literally here for targeted searches. Icons are
829
+ decorative, so the gallery includes each name as visible text.
830
+
831
+ ```dil
832
+ {@body const names = ["chart-no-axes-combined","circle-check","check-circle-2","circle","wallet","trending-up","users","rotate-ccw","copy","sliders-horizontal","ellipsis","sparkles","mouse-pointer-click","x","git-merge","package-check","shield-check","settings-2","info","code-2","alert-triangle"]}
833
+ <grid columns={2} gap={3}>
834
+ {#each names as name}<row gap={2} align="center"><icon name={name} size="lg"/><text>{name}</text></row>{/each}
835
+ </grid>
836
+ ```