@lynx-js/genui 0.0.1 → 0.0.2
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/a2ui/dist/catalog/Button/{index.js → index.jsx} +12 -8
- package/a2ui/dist/catalog/Button/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Card/{index.js → index.jsx} +5 -4
- package/a2ui/dist/catalog/Card/index.jsx.map +1 -0
- package/a2ui/dist/catalog/CheckBox/{index.js → index.jsx} +11 -6
- package/a2ui/dist/catalog/CheckBox/index.jsx.map +1 -0
- package/a2ui/dist/catalog/ChoicePicker/index.jsx +98 -0
- package/a2ui/dist/catalog/ChoicePicker/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Column/{index.js → index.jsx} +10 -7
- package/a2ui/dist/catalog/Column/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/DateTimeInput/index.jsx +258 -0
- package/a2ui/dist/catalog/DateTimeInput/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Divider/index.jsx +7 -0
- package/a2ui/dist/catalog/Divider/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Icon/{index.js → index.jsx} +4 -3
- package/a2ui/dist/catalog/Icon/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/Image/{index.js → index.jsx} +2 -3
- package/a2ui/dist/catalog/Image/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/LineChart/{index.js → index.jsx} +50 -13
- package/a2ui/dist/catalog/LineChart/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/List/{index.js → index.jsx} +9 -6
- package/a2ui/dist/catalog/List/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/Modal/{index.js → index.jsx} +18 -9
- package/a2ui/dist/catalog/Modal/index.jsx.map +1 -0
- package/a2ui/dist/catalog/PieChart/{index.js → index.jsx} +41 -15
- package/a2ui/dist/catalog/PieChart/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/RadioGroup/{index.js → index.jsx} +18 -5
- package/a2ui/dist/catalog/RadioGroup/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Row/{index.js → index.jsx} +10 -7
- package/a2ui/dist/catalog/Row/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Slider/{index.js → index.jsx} +22 -7
- package/a2ui/dist/catalog/Slider/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/Tabs/index.jsx +40 -0
- package/a2ui/dist/catalog/Tabs/index.jsx.map +1 -0
- package/a2ui/dist/catalog/Text/catalog.json +6 -2
- package/a2ui/dist/catalog/Text/index.d.ts +1 -1
- package/a2ui/dist/catalog/Text/index.jsx +16 -0
- package/a2ui/dist/catalog/Text/index.jsx.map +1 -0
- package/a2ui/dist/catalog/TextField/{index.js → index.jsx} +8 -5
- package/a2ui/dist/catalog/TextField/{index.js.map → index.jsx.map} +1 -1
- package/a2ui/dist/catalog/index.d.ts +19 -19
- package/a2ui/dist/catalog/index.js +25 -21
- package/a2ui/dist/catalog/index.js.map +1 -1
- package/a2ui/dist/react/A2UI.d.ts +1 -1
- package/a2ui/dist/react/{A2UI.js → A2UI.jsx} +6 -5
- package/a2ui/dist/react/{A2UI.js.map → A2UI.jsx.map} +1 -1
- package/a2ui/dist/react/{A2UIProvider.js → A2UIProvider.jsx} +2 -3
- package/a2ui/dist/react/{A2UIProvider.js.map → A2UIProvider.jsx.map} +1 -1
- package/a2ui/dist/react/{A2UIRenderer.js → A2UIRenderer.jsx} +33 -23
- package/a2ui/dist/react/A2UIRenderer.jsx.map +1 -0
- package/a2ui/dist/react/index.d.ts +3 -3
- package/a2ui/dist/react/index.js +2 -2
- package/a2ui/dist/react/index.js.map +1 -1
- package/a2ui/dist/react/useA2UIContext.d.ts +1 -1
- package/a2ui/dist/react/useA2UIContext.js +1 -1
- package/a2ui/dist/react/useA2UIContext.js.map +1 -1
- package/a2ui/dist/tsconfig.build.tsbuildinfo +1 -1
- package/a2ui/styles/catalog/Modal.css +1 -0
- package/a2ui/styles/catalog/Text.css +2 -6
- package/a2ui-prompt/dist/index.js +101 -101
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/a2ui/dist/catalog/Button/index.js.map +0 -1
- package/a2ui/dist/catalog/Card/index.js.map +0 -1
- package/a2ui/dist/catalog/CheckBox/index.js.map +0 -1
- package/a2ui/dist/catalog/ChoicePicker/index.js +0 -66
- package/a2ui/dist/catalog/ChoicePicker/index.js.map +0 -1
- package/a2ui/dist/catalog/DateTimeInput/index.js +0 -147
- package/a2ui/dist/catalog/DateTimeInput/index.js.map +0 -1
- package/a2ui/dist/catalog/Divider/index.js +0 -8
- package/a2ui/dist/catalog/Divider/index.js.map +0 -1
- package/a2ui/dist/catalog/Modal/index.js.map +0 -1
- package/a2ui/dist/catalog/RadioGroup/index.js.map +0 -1
- package/a2ui/dist/catalog/Row/index.js.map +0 -1
- package/a2ui/dist/catalog/Tabs/index.js +0 -32
- package/a2ui/dist/catalog/Tabs/index.js.map +0 -1
- package/a2ui/dist/catalog/Text/index.js +0 -27
- package/a2ui/dist/catalog/Text/index.js.map +0 -1
- package/a2ui/dist/react/A2UIRenderer.js.map +0 -1
|
@@ -13,6 +13,18 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
13
13
|
catalogId: BASIC_CATALOG_ID
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
+
{
|
|
17
|
+
version: 'v0.9',
|
|
18
|
+
updateDataModel: {
|
|
19
|
+
surfaceId: 'main',
|
|
20
|
+
value: {
|
|
21
|
+
form: {
|
|
22
|
+
email: '',
|
|
23
|
+
password: ''
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
16
28
|
{
|
|
17
29
|
version: 'v0.9',
|
|
18
30
|
updateComponents: {
|
|
@@ -82,18 +94,6 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
82
94
|
}
|
|
83
95
|
]
|
|
84
96
|
}
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
version: 'v0.9',
|
|
88
|
-
updateDataModel: {
|
|
89
|
-
surfaceId: 'main',
|
|
90
|
-
value: {
|
|
91
|
-
form: {
|
|
92
|
-
email: '',
|
|
93
|
-
password: ''
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
97
|
}
|
|
98
98
|
]
|
|
99
99
|
},
|
|
@@ -108,6 +108,27 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
108
108
|
catalogId: BASIC_CATALOG_ID
|
|
109
109
|
}
|
|
110
110
|
},
|
|
111
|
+
{
|
|
112
|
+
version: 'v0.9',
|
|
113
|
+
updateDataModel: {
|
|
114
|
+
surfaceId: 'main',
|
|
115
|
+
path: '/items',
|
|
116
|
+
value: [
|
|
117
|
+
{
|
|
118
|
+
name: 'Canal walk',
|
|
119
|
+
detail: 'Morning coffee and quiet bridges'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'Museum loop',
|
|
123
|
+
detail: 'Design exhibits plus lunch nearby'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'Sunset hill',
|
|
127
|
+
detail: 'Short climb with skyline views'
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
},
|
|
111
132
|
{
|
|
112
133
|
version: 'v0.9',
|
|
113
134
|
updateComponents: {
|
|
@@ -176,27 +197,6 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
176
197
|
}
|
|
177
198
|
]
|
|
178
199
|
}
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
version: 'v0.9',
|
|
182
|
-
updateDataModel: {
|
|
183
|
-
surfaceId: 'main',
|
|
184
|
-
path: '/items',
|
|
185
|
-
value: [
|
|
186
|
-
{
|
|
187
|
-
name: 'Canal walk',
|
|
188
|
-
detail: 'Morning coffee and quiet bridges'
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
name: 'Museum loop',
|
|
192
|
-
detail: 'Design exhibits plus lunch nearby'
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
name: 'Sunset hill',
|
|
196
|
-
detail: 'Short climb with skyline views'
|
|
197
|
-
}
|
|
198
|
-
]
|
|
199
|
-
}
|
|
200
200
|
}
|
|
201
201
|
]
|
|
202
202
|
},
|
|
@@ -211,6 +211,35 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
211
211
|
catalogId: BASIC_CATALOG_ID
|
|
212
212
|
}
|
|
213
213
|
},
|
|
214
|
+
{
|
|
215
|
+
version: 'v0.9',
|
|
216
|
+
updateDataModel: {
|
|
217
|
+
surfaceId: 'main',
|
|
218
|
+
value: {
|
|
219
|
+
chart: {
|
|
220
|
+
labels: [
|
|
221
|
+
'Mon',
|
|
222
|
+
'Tue',
|
|
223
|
+
'Wed',
|
|
224
|
+
'Thu',
|
|
225
|
+
'Fri'
|
|
226
|
+
],
|
|
227
|
+
series: [
|
|
228
|
+
{
|
|
229
|
+
name: 'Users',
|
|
230
|
+
values: [
|
|
231
|
+
120,
|
|
232
|
+
148,
|
|
233
|
+
132,
|
|
234
|
+
171,
|
|
235
|
+
190
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
214
243
|
{
|
|
215
244
|
version: 'v0.9',
|
|
216
245
|
updateComponents: {
|
|
@@ -251,35 +280,6 @@ const BASIC_CATALOG_EXAMPLES = [
|
|
|
251
280
|
}
|
|
252
281
|
]
|
|
253
282
|
}
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
version: 'v0.9',
|
|
257
|
-
updateDataModel: {
|
|
258
|
-
surfaceId: 'main',
|
|
259
|
-
value: {
|
|
260
|
-
chart: {
|
|
261
|
-
labels: [
|
|
262
|
-
'Mon',
|
|
263
|
-
'Tue',
|
|
264
|
-
'Wed',
|
|
265
|
-
'Thu',
|
|
266
|
-
'Fri'
|
|
267
|
-
],
|
|
268
|
-
series: [
|
|
269
|
-
{
|
|
270
|
-
name: 'Users',
|
|
271
|
-
values: [
|
|
272
|
-
120,
|
|
273
|
-
148,
|
|
274
|
-
132,
|
|
275
|
-
171,
|
|
276
|
-
190
|
|
277
|
-
]
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
283
|
}
|
|
284
284
|
]
|
|
285
285
|
},
|
|
@@ -351,7 +351,7 @@ var RadioGroup_catalog_namespaceObject = JSON.parse('{"RadioGroup":{"properties"
|
|
|
351
351
|
var Row_catalog_namespaceObject = JSON.parse('{"Row":{"properties":{"children":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"componentId":{"type":"string"},"path":{"type":"string"}},"required":["componentId","path"],"additionalProperties":false}],"description":"Static child IDs array or template object."},"justify":{"type":"string","enum":["start","center","end","stretch","spaceBetween","spaceAround","spaceEvenly"]},"align":{"type":"string","enum":["start","center","end","stretch"]}},"required":["children"]}}');
|
|
352
352
|
var Slider_catalog_namespaceObject = JSON.parse('{"Slider":{"properties":{"label":{"oneOf":[{"type":"string"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":true},"returnType":{"type":"string","enum":["string","number","boolean","object","array","any","void"]}},"required":["call","args"],"additionalProperties":false}],"description":"The label for the slider."},"min":{"type":"number","description":"The minimum value of the slider."},"max":{"type":"number","description":"The maximum value of the slider."},"value":{"oneOf":[{"type":"number"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":true},"returnType":{"type":"string","enum":["string","number","boolean","object","array","any","void"]}},"required":["call","args"],"additionalProperties":false}],"description":"The current value of the slider."},"checks":{"type":"array","items":{"type":"object","properties":{"condition":{"oneOf":[{"type":"boolean"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":true},"returnType":{"type":"string","enum":["string","number","boolean","object","array","any","void"]}},"required":["call","args"],"additionalProperties":false}],"description":"The condition that indicates whether the check passes."},"message":{"type":"string","description":"The error message to display if the check fails."}},"required":["condition","message"],"additionalProperties":false},"description":"A list of checks to perform."}},"required":["max","value"]}}');
|
|
353
353
|
var Tabs_catalog_namespaceObject = JSON.parse('{"Tabs":{"properties":{"tabs":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"child":{"type":"string"}},"required":["title","child"],"additionalProperties":false}}},"required":["tabs"]}}');
|
|
354
|
-
var Text_catalog_namespaceObject = JSON.parse('{"Text":{"properties":{"text":{"oneOf":[{"type":"string"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":true},"returnType":{"type":"string","enum":["string","number","boolean","object","array","any","void"]}},"required":["call","args"],"additionalProperties":false}],"description":"Literal text, path binding, or function call."},"variant":{"type":"string","enum":["h1","h2","h3","h4","h5","caption","body","markdown"]},"
|
|
354
|
+
var Text_catalog_namespaceObject = JSON.parse('{"Text":{"properties":{"text":{"oneOf":[{"type":"string"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":true},"returnType":{"type":"string","enum":["string","number","boolean","object","array","any","void"]}},"required":["call","args"],"additionalProperties":false}],"description":"Literal text, path binding, or function call."},"variant":{"type":"string","enum":["h1","h2","h3","h4","h5","caption","body","markdown"]},"emphasis":{"type":"string","enum":["medium","strong"]}},"required":["text"]}}');
|
|
355
355
|
var TextField_catalog_namespaceObject = JSON.parse('{"TextField":{"properties":{"label":{"oneOf":[{"type":"string"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false}],"description":"The text label for the input field."},"value":{"oneOf":[{"type":"string"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false}],"description":"The value of the text field."},"variant":{"type":"string","enum":["number","longText","shortText","obscured"],"description":"The type of input field to display."},"validationRegexp":{"type":"string","description":"A regular expression used for client-side validation of the input."},"checks":{"type":"array","items":{"type":"object","properties":{"condition":{"oneOf":[{"type":"boolean"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false},{"type":"object","properties":{"call":{"type":"string"},"args":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"object","properties":{"path":{"type":"string"}},"required":["path"],"additionalProperties":false}]}},"returnType":{"type":"string","enum":["boolean"]}},"required":["call"],"additionalProperties":false}],"description":"The condition that indicates whether the check passes."},"message":{"type":"string","description":"The error message to display if the check fails."}},"required":["condition","message"],"additionalProperties":false},"description":"A list of checks to perform."}},"required":["label"]}}');
|
|
356
356
|
const a2ui_catalog_BASIC_CATALOG_ID = 'https://a2ui.org/specification/v0_9/basic_catalog.json';
|
|
357
357
|
const CATALOG_MANIFESTS = [
|
|
@@ -568,21 +568,23 @@ and exactly ONE of the following keys:
|
|
|
568
568
|
|
|
569
569
|
## Required ordering for a fresh response
|
|
570
570
|
1. createSurface (with surfaceId + catalogId)
|
|
571
|
-
2.
|
|
572
|
-
|
|
573
|
-
|
|
571
|
+
2. updateDataModel for every initial value referenced by a { "path": ... }
|
|
572
|
+
binding. Send this before the first component that reads those paths.
|
|
573
|
+
3. updateComponents (the FIRST one MUST contain a component whose id is "root")
|
|
574
|
+
4. (optional) further updateDataModel / updateComponents for incremental UI.
|
|
575
|
+
For each incremental bound component, send its data model value first, then
|
|
576
|
+
send the component that binds to it.
|
|
574
577
|
|
|
575
578
|
## Envelope semantics
|
|
576
579
|
- createSurface creates a surface. Once created, its surfaceId and catalogId are
|
|
577
580
|
fixed. To change catalog/theme, delete and recreate the surface.
|
|
578
581
|
- updateComponents adds or replaces component definitions for that surface. It
|
|
579
|
-
may reference data paths
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
Its fields MUST be nested inside "updateDataModel":
|
|
582
|
+
may reference data paths, but for smooth streaming those paths SHOULD already
|
|
583
|
+
be populated by an earlier updateDataModel in the same response.
|
|
584
|
+
- updateDataModel has shape:
|
|
583
585
|
{ "version": "v0.9",
|
|
584
|
-
"updateDataModel": { "surfaceId":
|
|
585
|
-
|
|
586
|
+
"updateDataModel": { "surfaceId": string, "path"?: string, "value"?: any } }
|
|
587
|
+
"path" defaults to "/" and "value" may be any JSON value.
|
|
586
588
|
- deleteSurface removes a surface when the UI is no longer needed.
|
|
587
589
|
|
|
588
590
|
## Component model
|
|
@@ -637,50 +639,48 @@ function buildHardRules(catalogId) {
|
|
|
637
639
|
5. For a fresh non-action response, the first message MUST be createSurface with
|
|
638
640
|
catalogId = "${catalogId}". Use surfaceId "main" unless the user specifies
|
|
639
641
|
otherwise.
|
|
640
|
-
6. For
|
|
641
|
-
updateComponents
|
|
642
|
-
|
|
643
|
-
|
|
642
|
+
6. For "{path:...}" bindings, send updateDataModel before the first
|
|
643
|
+
updateComponents message that contains components reading those paths. After
|
|
644
|
+
createSurface, either send a literal root/skeleton updateComponents first, or
|
|
645
|
+
send updateDataModel first when the first visible components use bindings.
|
|
646
|
+
7. For a fresh non-action response, the first updateComponents message MUST
|
|
647
|
+
contain exactly one component with id "root".
|
|
648
|
+
8. Use property-based component discriminators: "component": "Text", not
|
|
644
649
|
wrapper objects such as { "Text": {...} }.
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
650
|
+
9. Children are referenced by id only. NEVER inline a child component.
|
|
651
|
+
10. Container references MUST point to components present in the same response.
|
|
652
|
+
11. Card.child is exactly one id; wrap multiple elements in Row/Column/List.
|
|
653
|
+
12. Buttons MUST include a dispatchable "action": either non-empty
|
|
654
|
+
"action.event.name" or non-empty "action.functionCall.call". Button has NO
|
|
655
|
+
"label" prop – provide the label via a child Text component
|
|
656
|
+
("child": "<text-id>").
|
|
657
|
+
13. When using Modal for a confirmation flow, do NOT put the server action on
|
|
651
658
|
the Modal trigger. The trigger only opens the modal. Put a separate confirm
|
|
652
659
|
Button inside Modal.content, and attach the action to that confirm Button.
|
|
653
|
-
|
|
660
|
+
14. Render a Modal by placing the Modal component itself where the trigger
|
|
654
661
|
should appear. Do NOT also list the trigger component as a sibling in the
|
|
655
662
|
parent container, because Modal renders its trigger internally.
|
|
656
|
-
|
|
663
|
+
15. The "weight" prop is only a small Row/Column child layout ratio, not CSS
|
|
657
664
|
font-weight. Do NOT use values like 400, 500, 600, or 700 for typography.
|
|
658
|
-
Use
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
{ "version": "v0.9", "updateDataModel": { "surfaceId": "main", "path": "/", "value": {} } }
|
|
665
|
-
Wrong:
|
|
666
|
-
{ "version": "v0.9", "updateDataModel": { "surfaceId": "main", "value": {} }, "path": "/" }
|
|
667
|
-
17. Ids are kebab-case, unique per surface ("root", "title-text", "submit-btn").
|
|
668
|
-
18. Do not invent components outside the catalog.
|
|
669
|
-
19. No comments, trailing commas or unknown fields.
|
|
670
|
-
20. If the user asks for impossible, unsafe, or unsupported UI, render a concise
|
|
665
|
+
Use Text.variant for base typography and Text.emphasis ("medium" or
|
|
666
|
+
"strong") for extra text emphasis.
|
|
667
|
+
16. Ids are kebab-case, unique per surface ("root", "title-text", "submit-btn").
|
|
668
|
+
17. Do not invent components outside the catalog.
|
|
669
|
+
18. No comments, trailing commas or unknown fields.
|
|
670
|
+
19. If the user asks for impossible, unsafe, or unsupported UI, render a concise
|
|
671
671
|
explanatory A2UI surface using supported components rather than prose.
|
|
672
|
-
|
|
672
|
+
20. If the latest user message starts with "A2UI_USER_ACTION:", this is an
|
|
673
673
|
action response for an existing surface. Return a non-empty JSON array with
|
|
674
674
|
updateDataModel and/or updateComponents for that same surfaceId. Do NOT
|
|
675
675
|
return [] and do NOT create a new surface unless the action explicitly asks
|
|
676
676
|
to replace the whole UI.
|
|
677
|
-
|
|
677
|
+
21. For action responses, prefer the smallest valid patch: one updateDataModel
|
|
678
678
|
for changed data, plus one updateComponents only if the visible structure
|
|
679
679
|
needs to change.
|
|
680
|
-
|
|
680
|
+
22. For UI that should change after a button tap, keep the initial response in
|
|
681
681
|
the pre-action state. Put confirmation, success, or result details in the
|
|
682
682
|
action response instead of showing them before the action happens.
|
|
683
|
-
|
|
683
|
+
23. For Image.url, provide a short English image search query such as
|
|
684
684
|
"fresh pasta on a table" or "city skyline at night". Do NOT invent photo
|
|
685
685
|
CDN URLs. The server resolves Image.url values through its image provider.
|
|
686
686
|
`;
|