@snackbit/opendil 0.0.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.
- package/LICENSE +201 -0
- package/README.md +137 -2
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/bin/opendil.mjs +75 -0
- package/bin/publish-directory.d.mts +18 -0
- package/bin/publish-directory.mjs +188 -0
- package/dist/agent-spec.js +9 -0
- package/dist/chunk-RPZW4WVX.js +2 -0
- package/dist/chunk-ZSTXLIS6.js +2 -0
- package/dist/index.js +2 -0
- package/dist/mermaid-diagram-GFWD4Y2X.js +2 -0
- package/dist/runtime/frame.html +2435 -0
- package/dist/runtime/frame.js +4621 -0
- package/dist/spec/genui.agent.full.md +1927 -0
- package/dist/spec/genui.agent.md +479 -0
- package/dist/spec/genui.examples.md +836 -0
- package/dist/styled-renderer-PHI4MNPF.js +2441 -0
- package/dist/styles.css +2434 -0
- package/dist/types/agent-spec.d.ts +12 -0
- package/dist/types/components/ui/controls/button.d.ts +10 -0
- package/dist/types/components/ui/controls/checkbox.d.ts +4 -0
- package/dist/types/components/ui/controls/input.d.ts +3 -0
- package/dist/types/components/ui/controls/radio-group.d.ts +5 -0
- package/dist/types/components/ui/controls/select.d.ts +14 -0
- package/dist/types/components/ui/controls/slider.d.ts +4 -0
- package/dist/types/components/ui/controls/tabs.d.ts +7 -0
- package/dist/types/components/ui/controls/textarea.d.ts +3 -0
- package/dist/types/components/ui/controls/toggle-group.d.ts +10 -0
- package/dist/types/components/ui/controls/toggle.d.ts +9 -0
- package/dist/types/components/ui/display/badge.d.ts +9 -0
- package/dist/types/components/ui/display/card.d.ts +9 -0
- package/dist/types/components/ui/display/chart.d.ts +39 -0
- package/dist/types/components/ui/display/separator.d.ts +4 -0
- package/dist/types/components/ui/display/skeleton.d.ts +2 -0
- package/dist/types/components/ui/display/table.d.ts +10 -0
- package/dist/types/components/ui/media/carousel.d.ts +19 -0
- package/dist/types/components/ui/overlays/collapsible.d.ts +6 -0
- package/dist/types/components/ui/overlays/popover.d.ts +11 -0
- package/dist/types/components/ui/overlays/tooltip.d.ts +8 -0
- package/dist/types/components/ui/overlays/ui-scope.d.ts +27 -0
- package/dist/types/dil/custom-component.d.ts +14 -0
- package/dist/types/dil/customization.d.ts +21 -0
- package/dist/types/dil/dil-renderer.d.ts +90 -0
- package/dist/types/dil/isolation/frame-startup.d.ts +18 -0
- package/dist/types/dil/isolation/frame-theme.d.ts +14 -0
- package/dist/types/dil/isolation/frame-viewport.d.ts +30 -0
- package/dist/types/dil/isolation/frame.d.ts +1 -0
- package/dist/types/dil/isolation/isolated-renderer.d.ts +28 -0
- package/dist/types/dil/isolation/overlay-room.d.ts +29 -0
- package/dist/types/dil/isolation/shadow-renderer.d.ts +7 -0
- package/dist/types/dil/isolation/shadow-styles.d.ts +2 -0
- package/dist/types/dil/isolation/viewport-scroll.d.ts +7 -0
- package/dist/types/dil/isolation/vm-worker.d.ts +1 -0
- package/dist/types/dil/message-renderer.d.ts +17 -0
- package/dist/types/dil/parser/dil-parser.d.ts +74 -0
- package/dist/types/dil/parser/lexical.d.ts +27 -0
- package/dist/types/dil/parser/literal-tag.d.ts +16 -0
- package/dist/types/dil/parser/markdown-lexing.d.ts +41 -0
- package/dist/types/dil/parser/stream-worker.d.ts +1 -0
- package/dist/types/dil/parser/types.d.ts +53 -0
- package/dist/types/dil/parser/unfinished.d.ts +22 -0
- package/dist/types/dil/parser/vocabulary.d.ts +12 -0
- package/dist/types/dil/render-error.d.ts +47 -0
- package/dist/types/dil/renderer-environment.d.ts +33 -0
- package/dist/types/dil/renderer-handle.d.ts +4 -0
- package/dist/types/dil/runtime/action-receipt.d.ts +5 -0
- package/dist/types/dil/runtime/child-list.d.ts +8 -0
- package/dist/types/dil/runtime/document.d.ts +54 -0
- package/dist/types/dil/runtime/evaluation-cache.d.ts +24 -0
- package/dist/types/dil/runtime/execution-queue.d.ts +56 -0
- package/dist/types/dil/runtime/expressions.d.ts +62 -0
- package/dist/types/dil/runtime/inline-worker.d.ts +33 -0
- package/dist/types/dil/runtime/markdown-stream.d.ts +17 -0
- package/dist/types/dil/runtime/presentation-history.d.ts +14 -0
- package/dist/types/dil/runtime/presentation-scheduler.d.ts +16 -0
- package/dist/types/dil/runtime/render-budget.d.ts +10 -0
- package/dist/types/dil/runtime/view-cost.d.ts +10 -0
- package/dist/types/dil/styled-renderer.d.ts +39 -0
- package/dist/types/dil/view/conditional-view.d.ts +12 -0
- package/dist/types/dil/view/loading-block.d.ts +7 -0
- package/dist/types/dil/view/markdown-node.d.ts +12 -0
- package/dist/types/dil/view/node-children.d.ts +13 -0
- package/dist/types/dil/view/node-view.d.ts +11 -0
- package/dist/types/dil/view/progressive-reveal.d.ts +7 -0
- package/dist/types/dil/view/render-boundary.d.ts +35 -0
- package/dist/types/dil/view/render-limit.d.ts +14 -0
- package/dist/types/dil/view/repeated-nodes.d.ts +15 -0
- package/dist/types/dil/view/reveal/controller.d.ts +32 -0
- package/dist/types/dil/view/reveal/presentation.d.ts +13 -0
- package/dist/types/dil/view/reveal-options.d.ts +11 -0
- package/dist/types/dil/view/scroll/controller.d.ts +42 -0
- package/dist/types/dil/view/scroll/host-viewport.d.ts +24 -0
- package/dist/types/dil/view/scroll/root-tracker.d.ts +17 -0
- package/dist/types/dil/view/scroll/scroll-root.d.ts +36 -0
- package/dist/types/dil/view/scroll-options.d.ts +25 -0
- package/dist/types/dil/view/stream-follow.d.ts +15 -0
- package/dist/types/dil/view/table-context.d.ts +15 -0
- package/dist/types/dil/view/virtual-flow.d.ts +15 -0
- package/dist/types/dil/widgets/action-feedback.d.ts +11 -0
- package/dist/types/dil/widgets/async-image.d.ts +6 -0
- package/dist/types/dil/widgets/charts/chart-hover.d.ts +17 -0
- package/dist/types/dil/widgets/charts/chart-legend.d.ts +10 -0
- package/dist/types/dil/widgets/charts/chart-pie.d.ts +16 -0
- package/dist/types/dil/widgets/charts/chart-selection.d.ts +8 -0
- package/dist/types/dil/widgets/charts/chart-series.d.ts +19 -0
- package/dist/types/dil/widgets/charts/chart-snapping.d.ts +13 -0
- package/dist/types/dil/widgets/charts/dil-chart.d.ts +5 -0
- package/dist/types/dil/widgets/charts/snap-cursor.d.ts +12 -0
- package/dist/types/dil/widgets/charts/snap-tooltip.d.ts +12 -0
- package/dist/types/dil/widgets/code/code-editor.d.ts +9 -0
- package/dist/types/dil/widgets/code/highlighted-code.d.ts +25 -0
- package/dist/types/dil/widgets/code-block.d.ts +11 -0
- package/dist/types/dil/widgets/control-revision.d.ts +1 -0
- package/dist/types/dil/widgets/control-state.d.ts +8 -0
- package/dist/types/dil/widgets/controls.d.ts +25 -0
- package/dist/types/dil/widgets/graphs/graph-model.d.ts +13 -0
- package/dist/types/dil/widgets/graphs/node-graph.d.ts +6 -0
- package/dist/types/dil/widgets/graphs/service-node.d.ts +3 -0
- package/dist/types/dil/widgets/mermaid-diagram.d.ts +5 -0
- package/dist/types/dil/widgets/primitives/attribute-values.d.ts +12 -0
- package/dist/types/dil/widgets/primitives/primitive.d.ts +17 -0
- package/dist/types/dil/widgets/primitives/vocabulary.d.ts +5 -0
- package/dist/types/dil/widgets/use-control-value.d.ts +2 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/lib/cn.d.ts +2 -0
- package/dist/types/ui.d.ts +11 -0
- package/dist/ui.js +2 -0
- package/package.json +85 -4
- package/styles/tailwind.css +443 -0
- package/styles/tokens.css +32 -0
|
@@ -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
|
+
```
|