@easyops-cn/a2ui-react 0.0.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 (161) hide show
  1. package/.claude/commands/speckit.analyze.md +184 -0
  2. package/.claude/commands/speckit.checklist.md +294 -0
  3. package/.claude/commands/speckit.clarify.md +181 -0
  4. package/.claude/commands/speckit.constitution.md +82 -0
  5. package/.claude/commands/speckit.implement.md +135 -0
  6. package/.claude/commands/speckit.plan.md +89 -0
  7. package/.claude/commands/speckit.specify.md +256 -0
  8. package/.claude/commands/speckit.tasks.md +137 -0
  9. package/.claude/commands/speckit.taskstoissues.md +30 -0
  10. package/.github/workflows/deploy.yml +69 -0
  11. package/.husky/pre-commit +1 -0
  12. package/.prettierignore +4 -0
  13. package/.prettierrc +7 -0
  14. package/.specify/memory/constitution.md +73 -0
  15. package/.specify/scripts/bash/check-prerequisites.sh +166 -0
  16. package/.specify/scripts/bash/common.sh +156 -0
  17. package/.specify/scripts/bash/create-new-feature.sh +297 -0
  18. package/.specify/scripts/bash/setup-plan.sh +61 -0
  19. package/.specify/scripts/bash/update-agent-context.sh +799 -0
  20. package/.specify/templates/agent-file-template.md +28 -0
  21. package/.specify/templates/checklist-template.md +40 -0
  22. package/.specify/templates/plan-template.md +105 -0
  23. package/.specify/templates/spec-template.md +115 -0
  24. package/.specify/templates/tasks-template.md +250 -0
  25. package/CLAUDE.md +105 -0
  26. package/CONTRIBUTING.md +97 -0
  27. package/README.md +126 -0
  28. package/components.json +21 -0
  29. package/eslint.config.js +25 -0
  30. package/netlify.toml +50 -0
  31. package/package.json +94 -0
  32. package/playground/README.md +75 -0
  33. package/playground/index.html +22 -0
  34. package/playground/package.json +32 -0
  35. package/playground/public/favicon.svg +8 -0
  36. package/playground/src/App.css +256 -0
  37. package/playground/src/App.tsx +115 -0
  38. package/playground/src/assets/react.svg +1 -0
  39. package/playground/src/components/ErrorDisplay.tsx +13 -0
  40. package/playground/src/components/ExampleSelector.tsx +64 -0
  41. package/playground/src/components/Header.tsx +47 -0
  42. package/playground/src/components/JsonEditor.tsx +32 -0
  43. package/playground/src/components/Preview.tsx +78 -0
  44. package/playground/src/components/ThemeToggle.tsx +19 -0
  45. package/playground/src/data/examples.ts +1571 -0
  46. package/playground/src/hooks/useTheme.ts +55 -0
  47. package/playground/src/index.css +220 -0
  48. package/playground/src/main.tsx +10 -0
  49. package/playground/tsconfig.app.json +34 -0
  50. package/playground/tsconfig.json +13 -0
  51. package/playground/tsconfig.node.json +26 -0
  52. package/playground/vite.config.ts +31 -0
  53. package/specs/001-a2ui-renderer/checklists/requirements.md +41 -0
  54. package/specs/001-a2ui-renderer/data-model.md +140 -0
  55. package/specs/001-a2ui-renderer/plan.md +123 -0
  56. package/specs/001-a2ui-renderer/quickstart.md +141 -0
  57. package/specs/001-a2ui-renderer/research.md +140 -0
  58. package/specs/001-a2ui-renderer/spec.md +165 -0
  59. package/specs/001-a2ui-renderer/tasks.md +310 -0
  60. package/specs/002-playground/checklists/requirements.md +37 -0
  61. package/specs/002-playground/contracts/components.md +120 -0
  62. package/specs/002-playground/data-model.md +149 -0
  63. package/specs/002-playground/plan.md +73 -0
  64. package/specs/002-playground/quickstart.md +158 -0
  65. package/specs/002-playground/research.md +117 -0
  66. package/specs/002-playground/spec.md +109 -0
  67. package/specs/002-playground/tasks.md +224 -0
  68. package/src/0.8/A2UIRender.test.tsx +793 -0
  69. package/src/0.8/A2UIRender.tsx +142 -0
  70. package/src/0.8/components/ComponentRenderer.test.tsx +373 -0
  71. package/src/0.8/components/ComponentRenderer.tsx +163 -0
  72. package/src/0.8/components/UnknownComponent.tsx +49 -0
  73. package/src/0.8/components/display/AudioPlayerComponent.tsx +37 -0
  74. package/src/0.8/components/display/DividerComponent.tsx +23 -0
  75. package/src/0.8/components/display/IconComponent.tsx +137 -0
  76. package/src/0.8/components/display/ImageComponent.tsx +57 -0
  77. package/src/0.8/components/display/TextComponent.tsx +56 -0
  78. package/src/0.8/components/display/VideoComponent.tsx +31 -0
  79. package/src/0.8/components/display/display.test.tsx +660 -0
  80. package/src/0.8/components/display/index.ts +10 -0
  81. package/src/0.8/components/index.ts +14 -0
  82. package/src/0.8/components/interactive/ButtonComponent.tsx +44 -0
  83. package/src/0.8/components/interactive/CheckBoxComponent.tsx +45 -0
  84. package/src/0.8/components/interactive/DateTimeInputComponent.tsx +176 -0
  85. package/src/0.8/components/interactive/MultipleChoiceComponent.tsx +157 -0
  86. package/src/0.8/components/interactive/SliderComponent.tsx +53 -0
  87. package/src/0.8/components/interactive/TextFieldComponent.tsx +65 -0
  88. package/src/0.8/components/interactive/index.ts +10 -0
  89. package/src/0.8/components/interactive/interactive.test.tsx +618 -0
  90. package/src/0.8/components/layout/CardComponent.tsx +30 -0
  91. package/src/0.8/components/layout/ColumnComponent.tsx +93 -0
  92. package/src/0.8/components/layout/ListComponent.tsx +81 -0
  93. package/src/0.8/components/layout/ModalComponent.tsx +41 -0
  94. package/src/0.8/components/layout/RowComponent.tsx +94 -0
  95. package/src/0.8/components/layout/TabsComponent.tsx +59 -0
  96. package/src/0.8/components/layout/index.ts +10 -0
  97. package/src/0.8/components/layout/layout.test.tsx +558 -0
  98. package/src/0.8/contexts/A2UIProvider.test.tsx +226 -0
  99. package/src/0.8/contexts/A2UIProvider.tsx +54 -0
  100. package/src/0.8/contexts/ActionContext.test.tsx +242 -0
  101. package/src/0.8/contexts/ActionContext.tsx +105 -0
  102. package/src/0.8/contexts/ComponentsMapContext.tsx +125 -0
  103. package/src/0.8/contexts/DataModelContext.test.tsx +335 -0
  104. package/src/0.8/contexts/DataModelContext.tsx +184 -0
  105. package/src/0.8/contexts/SurfaceContext.test.tsx +339 -0
  106. package/src/0.8/contexts/SurfaceContext.tsx +197 -0
  107. package/src/0.8/hooks/useA2UIMessageHandler.test.tsx +399 -0
  108. package/src/0.8/hooks/useA2UIMessageHandler.ts +123 -0
  109. package/src/0.8/hooks/useComponent.test.tsx +148 -0
  110. package/src/0.8/hooks/useComponent.ts +39 -0
  111. package/src/0.8/hooks/useDataBinding.test.tsx +334 -0
  112. package/src/0.8/hooks/useDataBinding.ts +99 -0
  113. package/src/0.8/hooks/useDispatchAction.test.tsx +83 -0
  114. package/src/0.8/hooks/useDispatchAction.ts +35 -0
  115. package/src/0.8/hooks/useSurface.test.tsx +114 -0
  116. package/src/0.8/hooks/useSurface.ts +34 -0
  117. package/src/0.8/index.ts +38 -0
  118. package/src/0.8/schemas/client_to_server.json +50 -0
  119. package/src/0.8/schemas/server_to_client.json +148 -0
  120. package/src/0.8/schemas/standard_catalog_definition.json +661 -0
  121. package/src/0.8/types/index.ts +448 -0
  122. package/src/0.8/utils/dataBinding.test.ts +443 -0
  123. package/src/0.8/utils/dataBinding.ts +212 -0
  124. package/src/0.8/utils/pathUtils.test.ts +353 -0
  125. package/src/0.8/utils/pathUtils.ts +200 -0
  126. package/src/components/ui/button.tsx +62 -0
  127. package/src/components/ui/calendar.tsx +220 -0
  128. package/src/components/ui/card.tsx +92 -0
  129. package/src/components/ui/checkbox.tsx +30 -0
  130. package/src/components/ui/dialog.tsx +141 -0
  131. package/src/components/ui/input.tsx +21 -0
  132. package/src/components/ui/label.tsx +22 -0
  133. package/src/components/ui/native-select.tsx +53 -0
  134. package/src/components/ui/popover.tsx +46 -0
  135. package/src/components/ui/select.tsx +188 -0
  136. package/src/components/ui/separator.tsx +26 -0
  137. package/src/components/ui/slider.tsx +61 -0
  138. package/src/components/ui/tabs.tsx +64 -0
  139. package/src/components/ui/textarea.tsx +18 -0
  140. package/src/index.ts +1 -0
  141. package/src/lib/utils.ts +6 -0
  142. package/tsconfig.json +28 -0
  143. package/vite.config.ts +29 -0
  144. package/vitest.config.ts +22 -0
  145. package/vitest.setup.ts +8 -0
  146. package/website/README.md +4 -0
  147. package/website/assets/favicon.svg +8 -0
  148. package/website/content/.gitkeep +0 -0
  149. package/website/content/index.md +122 -0
  150. package/website/global.d.ts +9 -0
  151. package/website/package.json +17 -0
  152. package/website/plain.config.js +28 -0
  153. package/website/serve.json +6 -0
  154. package/website/src/client/color-mode-switch.css +47 -0
  155. package/website/src/client/index.js +61 -0
  156. package/website/src/client/moon.svg +1 -0
  157. package/website/src/client/sun.svg +1 -0
  158. package/website/src/components/Footer.jsx +9 -0
  159. package/website/src/components/Header.jsx +44 -0
  160. package/website/src/components/Page.jsx +28 -0
  161. package/website/src/global.css +423 -0
@@ -0,0 +1,1571 @@
1
+ import type { A2UIMessage } from '@easyops-cn/a2ui-react/0.8'
2
+
3
+ export interface Example {
4
+ id: string
5
+ title: string
6
+ description: string
7
+ group?: string
8
+ messages: A2UIMessage[]
9
+ }
10
+
11
+ export const examples: Example[] = [
12
+ {
13
+ id: 'hello-world',
14
+ title: 'Hello World',
15
+ description: 'Basic Text component demonstration',
16
+ messages: [
17
+ {
18
+ surfaceUpdate: {
19
+ surfaceId: 'main',
20
+ components: [
21
+ {
22
+ id: 'root',
23
+ component: {
24
+ Column: {
25
+ children: { explicitList: ['heading', 'text', 'button'] },
26
+ alignment: 'start',
27
+ },
28
+ },
29
+ },
30
+ {
31
+ id: 'heading',
32
+ component: {
33
+ Text: {
34
+ text: { literalString: 'Hello, A2UI!' },
35
+ usageHint: 'h1',
36
+ },
37
+ },
38
+ },
39
+ {
40
+ id: 'text',
41
+ component: {
42
+ Text: {
43
+ text: {
44
+ literalString:
45
+ 'Welcome to the A2UI React Renderer Playground. Edit the JSON on the left to see changes in real-time.',
46
+ },
47
+ usageHint: 'body',
48
+ },
49
+ },
50
+ },
51
+ {
52
+ id: 'button',
53
+ component: {
54
+ Button: {
55
+ child: 'button-text',
56
+ primary: true,
57
+ action: {
58
+ name: 'hello-click',
59
+ },
60
+ },
61
+ },
62
+ },
63
+ {
64
+ id: 'button-text',
65
+ component: {
66
+ Text: {
67
+ text: { literalString: 'Get Started' },
68
+ },
69
+ },
70
+ },
71
+ ],
72
+ },
73
+ },
74
+ {
75
+ beginRendering: {
76
+ surfaceId: 'main',
77
+ root: 'root',
78
+ },
79
+ },
80
+ ],
81
+ },
82
+ {
83
+ id: 'button-actions',
84
+ title: 'Button Actions',
85
+ description: 'Interactive Button with action handling',
86
+ messages: [
87
+ {
88
+ surfaceUpdate: {
89
+ surfaceId: 'main',
90
+ components: [
91
+ {
92
+ id: 'root',
93
+ component: {
94
+ Column: {
95
+ children: {
96
+ explicitList: ['heading', 'description', 'buttons'],
97
+ },
98
+ },
99
+ },
100
+ },
101
+ {
102
+ id: 'heading',
103
+ component: {
104
+ Text: {
105
+ text: { literalString: 'Button Actions' },
106
+ usageHint: 'h2',
107
+ },
108
+ },
109
+ },
110
+ {
111
+ id: 'description',
112
+ component: {
113
+ Text: {
114
+ text: {
115
+ literalString:
116
+ 'Click the buttons below and check the browser console to see the dispatched actions.',
117
+ },
118
+ usageHint: 'body',
119
+ },
120
+ },
121
+ },
122
+ {
123
+ id: 'buttons',
124
+ component: {
125
+ Row: {
126
+ children: { explicitList: ['btn-primary', 'btn-secondary'] },
127
+ },
128
+ },
129
+ },
130
+ {
131
+ id: 'btn-primary',
132
+ component: {
133
+ Button: {
134
+ child: 'btn-primary-text',
135
+ primary: true,
136
+ action: {
137
+ name: 'button-click',
138
+ context: [
139
+ { key: 'button', value: { literalString: 'primary' } },
140
+ ],
141
+ },
142
+ },
143
+ },
144
+ },
145
+ {
146
+ id: 'btn-primary-text',
147
+ component: {
148
+ Text: {
149
+ text: { literalString: 'Primary' },
150
+ },
151
+ },
152
+ },
153
+ {
154
+ id: 'btn-secondary',
155
+ component: {
156
+ Button: {
157
+ child: 'btn-secondary-text',
158
+ primary: false,
159
+ action: {
160
+ name: 'button-click',
161
+ context: [
162
+ { key: 'button', value: { literalString: 'secondary' } },
163
+ ],
164
+ },
165
+ },
166
+ },
167
+ },
168
+ {
169
+ id: 'btn-secondary-text',
170
+ component: {
171
+ Text: {
172
+ text: { literalString: 'Secondary' },
173
+ },
174
+ },
175
+ },
176
+ ],
177
+ },
178
+ },
179
+ {
180
+ beginRendering: {
181
+ surfaceId: 'main',
182
+ root: 'root',
183
+ },
184
+ },
185
+ ],
186
+ },
187
+ {
188
+ id: 'form-inputs',
189
+ title: 'Form Inputs',
190
+ description: 'TextField and Checkbox components',
191
+ messages: [
192
+ {
193
+ surfaceUpdate: {
194
+ surfaceId: 'main',
195
+ components: [
196
+ {
197
+ id: 'root',
198
+ component: {
199
+ Column: {
200
+ children: { explicitList: ['heading', 'form'] },
201
+ },
202
+ },
203
+ },
204
+ {
205
+ id: 'heading',
206
+ component: {
207
+ Text: {
208
+ text: { literalString: 'Form Inputs' },
209
+ usageHint: 'h2',
210
+ },
211
+ },
212
+ },
213
+ {
214
+ id: 'form',
215
+ component: {
216
+ Column: {
217
+ children: {
218
+ explicitList: ['name-field', 'email-field', 'checkbox'],
219
+ },
220
+ },
221
+ },
222
+ },
223
+ {
224
+ id: 'name-field',
225
+ component: {
226
+ TextField: {
227
+ label: { literalString: 'Name' },
228
+ text: { path: 'form.name' },
229
+ },
230
+ },
231
+ },
232
+ {
233
+ id: 'email-field',
234
+ component: {
235
+ TextField: {
236
+ label: { literalString: 'Email' },
237
+ text: { path: 'form.email' },
238
+ },
239
+ },
240
+ },
241
+ {
242
+ id: 'checkbox',
243
+ component: {
244
+ CheckBox: {
245
+ label: { literalString: 'Subscribe to newsletter' },
246
+ value: { path: 'form.subscribe' },
247
+ },
248
+ },
249
+ },
250
+ ],
251
+ },
252
+ },
253
+ {
254
+ dataModelUpdate: {
255
+ surfaceId: 'main',
256
+ path: 'form',
257
+ contents: [
258
+ { key: 'name', valueString: '' },
259
+ { key: 'email', valueString: '' },
260
+ { key: 'subscribe', valueBoolean: false },
261
+ ],
262
+ },
263
+ },
264
+ {
265
+ beginRendering: {
266
+ surfaceId: 'main',
267
+ root: 'root',
268
+ },
269
+ },
270
+ ],
271
+ },
272
+ {
273
+ id: 'data-binding',
274
+ title: 'Data Binding',
275
+ description: 'Components with ValueSource path bindings',
276
+ messages: [
277
+ {
278
+ surfaceUpdate: {
279
+ surfaceId: 'main',
280
+ components: [
281
+ {
282
+ id: 'root',
283
+ component: {
284
+ Column: {
285
+ children: {
286
+ explicitList: ['heading', 'description', 'input', 'output'],
287
+ },
288
+ },
289
+ },
290
+ },
291
+ {
292
+ id: 'heading',
293
+ component: {
294
+ Text: {
295
+ text: { literalString: 'Data Binding Demo' },
296
+ usageHint: 'h2',
297
+ },
298
+ },
299
+ },
300
+ {
301
+ id: 'description',
302
+ component: {
303
+ Text: {
304
+ text: {
305
+ literalString:
306
+ 'Type in the input below and see the text update in real-time.',
307
+ },
308
+ usageHint: 'body',
309
+ },
310
+ },
311
+ },
312
+ {
313
+ id: 'input',
314
+ component: {
315
+ TextField: {
316
+ label: { literalString: 'Your message' },
317
+ text: { path: 'message' },
318
+ },
319
+ },
320
+ },
321
+ {
322
+ id: 'output',
323
+ component: {
324
+ Card: {
325
+ child: 'output-content',
326
+ },
327
+ },
328
+ },
329
+ {
330
+ id: 'output-content',
331
+ component: {
332
+ Column: {
333
+ children: { explicitList: ['output-label', 'output-text'] },
334
+ },
335
+ },
336
+ },
337
+ {
338
+ id: 'output-label',
339
+ component: {
340
+ Text: {
341
+ text: { literalString: 'You typed:' },
342
+ usageHint: 'caption',
343
+ },
344
+ },
345
+ },
346
+ {
347
+ id: 'output-text',
348
+ component: {
349
+ Text: {
350
+ text: { path: 'message' },
351
+ usageHint: 'body',
352
+ },
353
+ },
354
+ },
355
+ ],
356
+ },
357
+ },
358
+ {
359
+ dataModelUpdate: {
360
+ surfaceId: 'main',
361
+ contents: [
362
+ { key: 'message', valueString: 'Hello from data binding!' },
363
+ ],
364
+ },
365
+ },
366
+ {
367
+ beginRendering: {
368
+ surfaceId: 'main',
369
+ root: 'root',
370
+ },
371
+ },
372
+ ],
373
+ },
374
+ {
375
+ id: 'image',
376
+ title: 'Image',
377
+ description: 'Image component with different fit modes and usage hints',
378
+ group: 'Components',
379
+ messages: [
380
+ {
381
+ surfaceUpdate: {
382
+ surfaceId: 'main',
383
+ components: [
384
+ {
385
+ id: 'root',
386
+ component: {
387
+ Column: {
388
+ children: {
389
+ explicitList: ['heading', 'description', 'images-row'],
390
+ },
391
+ },
392
+ },
393
+ },
394
+ {
395
+ id: 'heading',
396
+ component: {
397
+ Text: {
398
+ text: { literalString: 'Image Component' },
399
+ usageHint: 'h2',
400
+ },
401
+ },
402
+ },
403
+ {
404
+ id: 'description',
405
+ component: {
406
+ Text: {
407
+ text: {
408
+ literalString:
409
+ 'Display images with various fit modes and usage hints.',
410
+ },
411
+ usageHint: 'body',
412
+ },
413
+ },
414
+ },
415
+ {
416
+ id: 'images-row',
417
+ component: {
418
+ Row: {
419
+ children: {
420
+ explicitList: ['image-contain', 'image-cover'],
421
+ },
422
+ distribution: 'spaceEvenly',
423
+ },
424
+ },
425
+ },
426
+ {
427
+ id: 'image-contain',
428
+ component: {
429
+ Image: {
430
+ url: {
431
+ literalString: 'https://picsum.photos/200/150',
432
+ },
433
+ fit: 'contain',
434
+ usageHint: 'smallFeature',
435
+ },
436
+ },
437
+ },
438
+ {
439
+ id: 'image-cover',
440
+ component: {
441
+ Image: {
442
+ url: {
443
+ literalString: 'https://picsum.photos/200/151',
444
+ },
445
+ fit: 'cover',
446
+ usageHint: 'smallFeature',
447
+ },
448
+ },
449
+ },
450
+ ],
451
+ },
452
+ },
453
+ {
454
+ beginRendering: {
455
+ surfaceId: 'main',
456
+ root: 'root',
457
+ },
458
+ },
459
+ ],
460
+ },
461
+ {
462
+ id: 'icon',
463
+ title: 'Icon',
464
+ description: 'Icon component displaying various icons',
465
+ group: 'Components',
466
+ messages: [
467
+ {
468
+ surfaceUpdate: {
469
+ surfaceId: 'main',
470
+ components: [
471
+ {
472
+ id: 'root',
473
+ component: {
474
+ Column: {
475
+ children: {
476
+ explicitList: ['heading', 'description', 'icons-row'],
477
+ },
478
+ },
479
+ },
480
+ },
481
+ {
482
+ id: 'heading',
483
+ component: {
484
+ Text: {
485
+ text: { literalString: 'Icon Component' },
486
+ usageHint: 'h2',
487
+ },
488
+ },
489
+ },
490
+ {
491
+ id: 'description',
492
+ component: {
493
+ Text: {
494
+ text: {
495
+ literalString:
496
+ 'Display icons by name from the icon library.',
497
+ },
498
+ usageHint: 'body',
499
+ },
500
+ },
501
+ },
502
+ {
503
+ id: 'icons-row',
504
+ component: {
505
+ Row: {
506
+ children: {
507
+ explicitList: [
508
+ 'icon-home',
509
+ 'icon-settings',
510
+ 'icon-user',
511
+ 'icon-search',
512
+ ],
513
+ },
514
+ distribution: 'spaceEvenly',
515
+ },
516
+ },
517
+ },
518
+ {
519
+ id: 'icon-home',
520
+ component: {
521
+ Icon: {
522
+ name: { literalString: 'home' },
523
+ },
524
+ },
525
+ },
526
+ {
527
+ id: 'icon-settings',
528
+ component: {
529
+ Icon: {
530
+ name: { literalString: 'settings' },
531
+ },
532
+ },
533
+ },
534
+ {
535
+ id: 'icon-user',
536
+ component: {
537
+ Icon: {
538
+ name: { literalString: 'user' },
539
+ },
540
+ },
541
+ },
542
+ {
543
+ id: 'icon-search',
544
+ component: {
545
+ Icon: {
546
+ name: { literalString: 'search' },
547
+ },
548
+ },
549
+ },
550
+ ],
551
+ },
552
+ },
553
+ {
554
+ beginRendering: {
555
+ surfaceId: 'main',
556
+ root: 'root',
557
+ },
558
+ },
559
+ ],
560
+ },
561
+ {
562
+ id: 'video',
563
+ title: 'Video',
564
+ description: 'Video component for embedding video content',
565
+ group: 'Components',
566
+ messages: [
567
+ {
568
+ surfaceUpdate: {
569
+ surfaceId: 'main',
570
+ components: [
571
+ {
572
+ id: 'root',
573
+ component: {
574
+ Column: {
575
+ children: {
576
+ explicitList: ['heading', 'description', 'video-player'],
577
+ },
578
+ },
579
+ },
580
+ },
581
+ {
582
+ id: 'heading',
583
+ component: {
584
+ Text: {
585
+ text: { literalString: 'Video Component' },
586
+ usageHint: 'h2',
587
+ },
588
+ },
589
+ },
590
+ {
591
+ id: 'description',
592
+ component: {
593
+ Text: {
594
+ text: {
595
+ literalString:
596
+ 'Embed video content with the Video component.',
597
+ },
598
+ usageHint: 'body',
599
+ },
600
+ },
601
+ },
602
+ {
603
+ id: 'video-player',
604
+ component: {
605
+ Video: {
606
+ url: {
607
+ literalString: 'https://www.w3schools.com/html/mov_bbb.mp4',
608
+ },
609
+ },
610
+ },
611
+ },
612
+ ],
613
+ },
614
+ },
615
+ {
616
+ beginRendering: {
617
+ surfaceId: 'main',
618
+ root: 'root',
619
+ },
620
+ },
621
+ ],
622
+ },
623
+ {
624
+ id: 'audio-player',
625
+ title: 'Audio Player',
626
+ description: 'AudioPlayer component for playing audio content',
627
+ group: 'Components',
628
+ messages: [
629
+ {
630
+ surfaceUpdate: {
631
+ surfaceId: 'main',
632
+ components: [
633
+ {
634
+ id: 'root',
635
+ component: {
636
+ Column: {
637
+ children: {
638
+ explicitList: ['heading', 'description', 'audio'],
639
+ },
640
+ },
641
+ },
642
+ },
643
+ {
644
+ id: 'heading',
645
+ component: {
646
+ Text: {
647
+ text: { literalString: 'Audio Player Component' },
648
+ usageHint: 'h2',
649
+ },
650
+ },
651
+ },
652
+ {
653
+ id: 'description',
654
+ component: {
655
+ Text: {
656
+ text: {
657
+ literalString: 'Play audio content with description.',
658
+ },
659
+ usageHint: 'body',
660
+ },
661
+ },
662
+ },
663
+ {
664
+ id: 'audio',
665
+ component: {
666
+ AudioPlayer: {
667
+ url: {
668
+ literalString: 'https://www.w3schools.com/html/horse.ogg',
669
+ },
670
+ description: { literalString: 'Sample audio clip' },
671
+ },
672
+ },
673
+ },
674
+ ],
675
+ },
676
+ },
677
+ {
678
+ beginRendering: {
679
+ surfaceId: 'main',
680
+ root: 'root',
681
+ },
682
+ },
683
+ ],
684
+ },
685
+ {
686
+ id: 'divider',
687
+ title: 'Divider',
688
+ description: 'Divider component for visual separation',
689
+ group: 'Components',
690
+ messages: [
691
+ {
692
+ surfaceUpdate: {
693
+ surfaceId: 'main',
694
+ components: [
695
+ {
696
+ id: 'root',
697
+ component: {
698
+ Column: {
699
+ children: {
700
+ explicitList: [
701
+ 'heading',
702
+ 'section1',
703
+ 'divider-h',
704
+ 'section2',
705
+ 'vertical-demo',
706
+ ],
707
+ },
708
+ },
709
+ },
710
+ },
711
+ {
712
+ id: 'heading',
713
+ component: {
714
+ Text: {
715
+ text: { literalString: 'Divider Component' },
716
+ usageHint: 'h2',
717
+ },
718
+ },
719
+ },
720
+ {
721
+ id: 'section1',
722
+ component: {
723
+ Text: {
724
+ text: { literalString: 'Content above horizontal divider' },
725
+ usageHint: 'body',
726
+ },
727
+ },
728
+ },
729
+ {
730
+ id: 'divider-h',
731
+ component: {
732
+ Divider: {
733
+ axis: 'horizontal',
734
+ },
735
+ },
736
+ },
737
+ {
738
+ id: 'section2',
739
+ component: {
740
+ Text: {
741
+ text: { literalString: 'Content below horizontal divider' },
742
+ usageHint: 'body',
743
+ },
744
+ },
745
+ },
746
+ {
747
+ id: 'vertical-demo',
748
+ component: {
749
+ Row: {
750
+ children: {
751
+ explicitList: ['left-text', 'divider-v', 'right-text'],
752
+ },
753
+ alignment: 'stretch',
754
+ },
755
+ },
756
+ },
757
+ {
758
+ id: 'left-text',
759
+ component: {
760
+ Text: {
761
+ text: { literalString: 'Left' },
762
+ usageHint: 'body',
763
+ },
764
+ },
765
+ },
766
+ {
767
+ id: 'divider-v',
768
+ component: {
769
+ Divider: {
770
+ axis: 'vertical',
771
+ },
772
+ },
773
+ },
774
+ {
775
+ id: 'right-text',
776
+ component: {
777
+ Text: {
778
+ text: { literalString: 'Right' },
779
+ usageHint: 'body',
780
+ },
781
+ },
782
+ },
783
+ ],
784
+ },
785
+ },
786
+ {
787
+ beginRendering: {
788
+ surfaceId: 'main',
789
+ root: 'root',
790
+ },
791
+ },
792
+ ],
793
+ },
794
+ {
795
+ id: 'list',
796
+ title: 'List',
797
+ description: 'List component with vertical and horizontal directions',
798
+ group: 'Components',
799
+ messages: [
800
+ {
801
+ surfaceUpdate: {
802
+ surfaceId: 'main',
803
+ components: [
804
+ {
805
+ id: 'root',
806
+ component: {
807
+ Column: {
808
+ children: {
809
+ explicitList: [
810
+ 'heading',
811
+ 'vertical-label',
812
+ 'vertical-list',
813
+ 'horizontal-label',
814
+ 'horizontal-list',
815
+ ],
816
+ },
817
+ },
818
+ },
819
+ },
820
+ {
821
+ id: 'heading',
822
+ component: {
823
+ Text: {
824
+ text: { literalString: 'List Component' },
825
+ usageHint: 'h2',
826
+ },
827
+ },
828
+ },
829
+ {
830
+ id: 'vertical-label',
831
+ component: {
832
+ Text: {
833
+ text: { literalString: 'Vertical List:' },
834
+ usageHint: 'caption',
835
+ },
836
+ },
837
+ },
838
+ {
839
+ id: 'vertical-list',
840
+ component: {
841
+ List: {
842
+ children: {
843
+ explicitList: ['v-item1', 'v-item2', 'v-item3'],
844
+ },
845
+ direction: 'vertical',
846
+ alignment: 'start',
847
+ },
848
+ },
849
+ },
850
+ {
851
+ id: 'v-item1',
852
+ component: {
853
+ Text: {
854
+ text: { literalString: '• First item' },
855
+ usageHint: 'body',
856
+ },
857
+ },
858
+ },
859
+ {
860
+ id: 'v-item2',
861
+ component: {
862
+ Text: {
863
+ text: { literalString: '• Second item' },
864
+ usageHint: 'body',
865
+ },
866
+ },
867
+ },
868
+ {
869
+ id: 'v-item3',
870
+ component: {
871
+ Text: {
872
+ text: { literalString: '• Third item' },
873
+ usageHint: 'body',
874
+ },
875
+ },
876
+ },
877
+ {
878
+ id: 'horizontal-label',
879
+ component: {
880
+ Text: {
881
+ text: { literalString: 'Horizontal List:' },
882
+ usageHint: 'caption',
883
+ },
884
+ },
885
+ },
886
+ {
887
+ id: 'horizontal-list',
888
+ component: {
889
+ List: {
890
+ children: {
891
+ explicitList: ['h-item1', 'h-item2', 'h-item3'],
892
+ },
893
+ direction: 'horizontal',
894
+ alignment: 'center',
895
+ },
896
+ },
897
+ },
898
+ {
899
+ id: 'h-item1',
900
+ component: {
901
+ Card: {
902
+ child: 'h-item1-text',
903
+ },
904
+ },
905
+ },
906
+ {
907
+ id: 'h-item1-text',
908
+ component: {
909
+ Text: {
910
+ text: { literalString: 'Card 1' },
911
+ usageHint: 'body',
912
+ },
913
+ },
914
+ },
915
+ {
916
+ id: 'h-item2',
917
+ component: {
918
+ Card: {
919
+ child: 'h-item2-text',
920
+ },
921
+ },
922
+ },
923
+ {
924
+ id: 'h-item2-text',
925
+ component: {
926
+ Text: {
927
+ text: { literalString: 'Card 2' },
928
+ usageHint: 'body',
929
+ },
930
+ },
931
+ },
932
+ {
933
+ id: 'h-item3',
934
+ component: {
935
+ Card: {
936
+ child: 'h-item3-text',
937
+ },
938
+ },
939
+ },
940
+ {
941
+ id: 'h-item3-text',
942
+ component: {
943
+ Text: {
944
+ text: { literalString: 'Card 3' },
945
+ usageHint: 'body',
946
+ },
947
+ },
948
+ },
949
+ ],
950
+ },
951
+ },
952
+ {
953
+ beginRendering: {
954
+ surfaceId: 'main',
955
+ root: 'root',
956
+ },
957
+ },
958
+ ],
959
+ },
960
+ {
961
+ id: 'tabs',
962
+ title: 'Tabs',
963
+ description: 'Tabs component for tabbed navigation',
964
+ group: 'Components',
965
+ messages: [
966
+ {
967
+ surfaceUpdate: {
968
+ surfaceId: 'main',
969
+ components: [
970
+ {
971
+ id: 'root',
972
+ component: {
973
+ Column: {
974
+ children: {
975
+ explicitList: ['heading', 'description', 'tabs'],
976
+ },
977
+ },
978
+ },
979
+ },
980
+ {
981
+ id: 'heading',
982
+ component: {
983
+ Text: {
984
+ text: { literalString: 'Tabs Component' },
985
+ usageHint: 'h2',
986
+ },
987
+ },
988
+ },
989
+ {
990
+ id: 'description',
991
+ component: {
992
+ Text: {
993
+ text: {
994
+ literalString:
995
+ 'Navigate between different content sections.',
996
+ },
997
+ usageHint: 'body',
998
+ },
999
+ },
1000
+ },
1001
+ {
1002
+ id: 'tabs',
1003
+ component: {
1004
+ Tabs: {
1005
+ tabItems: [
1006
+ {
1007
+ title: { literalString: 'Overview' },
1008
+ child: 'tab1-content',
1009
+ },
1010
+ {
1011
+ title: { literalString: 'Details' },
1012
+ child: 'tab2-content',
1013
+ },
1014
+ {
1015
+ title: { literalString: 'Settings' },
1016
+ child: 'tab3-content',
1017
+ },
1018
+ ],
1019
+ },
1020
+ },
1021
+ },
1022
+ {
1023
+ id: 'tab1-content',
1024
+ component: {
1025
+ Card: {
1026
+ child: 'tab1-text',
1027
+ },
1028
+ },
1029
+ },
1030
+ {
1031
+ id: 'tab1-text',
1032
+ component: {
1033
+ Text: {
1034
+ text: {
1035
+ literalString:
1036
+ 'This is the Overview tab content. It provides a high-level summary.',
1037
+ },
1038
+ usageHint: 'body',
1039
+ },
1040
+ },
1041
+ },
1042
+ {
1043
+ id: 'tab2-content',
1044
+ component: {
1045
+ Card: {
1046
+ child: 'tab2-text',
1047
+ },
1048
+ },
1049
+ },
1050
+ {
1051
+ id: 'tab2-text',
1052
+ component: {
1053
+ Text: {
1054
+ text: {
1055
+ literalString:
1056
+ 'This is the Details tab content. It shows more detailed information.',
1057
+ },
1058
+ usageHint: 'body',
1059
+ },
1060
+ },
1061
+ },
1062
+ {
1063
+ id: 'tab3-content',
1064
+ component: {
1065
+ Card: {
1066
+ child: 'tab3-text',
1067
+ },
1068
+ },
1069
+ },
1070
+ {
1071
+ id: 'tab3-text',
1072
+ component: {
1073
+ Text: {
1074
+ text: {
1075
+ literalString:
1076
+ 'This is the Settings tab content. Configure your preferences here.',
1077
+ },
1078
+ usageHint: 'body',
1079
+ },
1080
+ },
1081
+ },
1082
+ ],
1083
+ },
1084
+ },
1085
+ {
1086
+ beginRendering: {
1087
+ surfaceId: 'main',
1088
+ root: 'root',
1089
+ },
1090
+ },
1091
+ ],
1092
+ },
1093
+ {
1094
+ id: 'modal',
1095
+ title: 'Modal',
1096
+ description: 'Modal component for dialog overlays',
1097
+ group: 'Components',
1098
+ messages: [
1099
+ {
1100
+ surfaceUpdate: {
1101
+ surfaceId: 'main',
1102
+ components: [
1103
+ {
1104
+ id: 'root',
1105
+ component: {
1106
+ Column: {
1107
+ children: {
1108
+ explicitList: ['heading', 'description', 'modal'],
1109
+ },
1110
+ },
1111
+ },
1112
+ },
1113
+ {
1114
+ id: 'heading',
1115
+ component: {
1116
+ Text: {
1117
+ text: { literalString: 'Modal Component' },
1118
+ usageHint: 'h2',
1119
+ },
1120
+ },
1121
+ },
1122
+ {
1123
+ id: 'description',
1124
+ component: {
1125
+ Text: {
1126
+ text: {
1127
+ literalString:
1128
+ 'Click the button below to open a modal dialog.',
1129
+ },
1130
+ usageHint: 'body',
1131
+ },
1132
+ },
1133
+ },
1134
+ {
1135
+ id: 'modal',
1136
+ component: {
1137
+ Modal: {
1138
+ entryPointChild: 'modal-trigger',
1139
+ contentChild: 'modal-content',
1140
+ },
1141
+ },
1142
+ },
1143
+ {
1144
+ id: 'modal-trigger',
1145
+ component: {
1146
+ Button: {
1147
+ child: 'modal-trigger-text',
1148
+ primary: true,
1149
+ },
1150
+ },
1151
+ },
1152
+ {
1153
+ id: 'modal-trigger-text',
1154
+ component: {
1155
+ Text: {
1156
+ text: { literalString: 'Open Modal' },
1157
+ },
1158
+ },
1159
+ },
1160
+ {
1161
+ id: 'modal-content',
1162
+ component: {
1163
+ Column: {
1164
+ children: {
1165
+ explicitList: ['modal-title', 'modal-body'],
1166
+ },
1167
+ },
1168
+ },
1169
+ },
1170
+ {
1171
+ id: 'modal-title',
1172
+ component: {
1173
+ Text: {
1174
+ text: { literalString: 'Modal Title' },
1175
+ usageHint: 'h3',
1176
+ },
1177
+ },
1178
+ },
1179
+ {
1180
+ id: 'modal-body',
1181
+ component: {
1182
+ Text: {
1183
+ text: {
1184
+ literalString:
1185
+ 'This is the modal content. You can put any components here.',
1186
+ },
1187
+ usageHint: 'body',
1188
+ },
1189
+ },
1190
+ },
1191
+ ],
1192
+ },
1193
+ },
1194
+ {
1195
+ beginRendering: {
1196
+ surfaceId: 'main',
1197
+ root: 'root',
1198
+ },
1199
+ },
1200
+ ],
1201
+ },
1202
+ {
1203
+ id: 'datetime-input',
1204
+ title: 'DateTime Input',
1205
+ description: 'DateTimeInput component for date and time selection',
1206
+ group: 'Components',
1207
+ messages: [
1208
+ {
1209
+ surfaceUpdate: {
1210
+ surfaceId: 'main',
1211
+ components: [
1212
+ {
1213
+ id: 'root',
1214
+ component: {
1215
+ Column: {
1216
+ children: {
1217
+ explicitList: [
1218
+ 'heading',
1219
+ 'description',
1220
+ 'date-only-label',
1221
+ 'date-only',
1222
+ 'time-only-label',
1223
+ 'time-only',
1224
+ 'datetime-label',
1225
+ 'datetime',
1226
+ ],
1227
+ },
1228
+ },
1229
+ },
1230
+ },
1231
+ {
1232
+ id: 'heading',
1233
+ component: {
1234
+ Text: {
1235
+ text: { literalString: 'DateTime Input Component' },
1236
+ usageHint: 'h2',
1237
+ },
1238
+ },
1239
+ },
1240
+ {
1241
+ id: 'description',
1242
+ component: {
1243
+ Text: {
1244
+ text: {
1245
+ literalString:
1246
+ 'Select dates and times with different configurations.',
1247
+ },
1248
+ usageHint: 'body',
1249
+ },
1250
+ },
1251
+ },
1252
+ {
1253
+ id: 'date-only-label',
1254
+ component: {
1255
+ Text: {
1256
+ text: { literalString: 'Date Only:' },
1257
+ usageHint: 'caption',
1258
+ },
1259
+ },
1260
+ },
1261
+ {
1262
+ id: 'date-only',
1263
+ component: {
1264
+ DateTimeInput: {
1265
+ value: { path: 'dateOnly' },
1266
+ enableDate: true,
1267
+ enableTime: false,
1268
+ },
1269
+ },
1270
+ },
1271
+ {
1272
+ id: 'time-only-label',
1273
+ component: {
1274
+ Text: {
1275
+ text: { literalString: 'Time Only:' },
1276
+ usageHint: 'caption',
1277
+ },
1278
+ },
1279
+ },
1280
+ {
1281
+ id: 'time-only',
1282
+ component: {
1283
+ DateTimeInput: {
1284
+ value: { path: 'timeOnly' },
1285
+ enableDate: false,
1286
+ enableTime: true,
1287
+ },
1288
+ },
1289
+ },
1290
+ {
1291
+ id: 'datetime-label',
1292
+ component: {
1293
+ Text: {
1294
+ text: { literalString: 'Date and Time:' },
1295
+ usageHint: 'caption',
1296
+ },
1297
+ },
1298
+ },
1299
+ {
1300
+ id: 'datetime',
1301
+ component: {
1302
+ DateTimeInput: {
1303
+ value: { path: 'datetime' },
1304
+ enableDate: true,
1305
+ enableTime: true,
1306
+ },
1307
+ },
1308
+ },
1309
+ ],
1310
+ },
1311
+ },
1312
+ {
1313
+ dataModelUpdate: {
1314
+ surfaceId: 'main',
1315
+ contents: [
1316
+ { key: 'dateOnly', valueString: '' },
1317
+ { key: 'timeOnly', valueString: '' },
1318
+ { key: 'datetime', valueString: '' },
1319
+ ],
1320
+ },
1321
+ },
1322
+ {
1323
+ beginRendering: {
1324
+ surfaceId: 'main',
1325
+ root: 'root',
1326
+ },
1327
+ },
1328
+ ],
1329
+ },
1330
+ {
1331
+ id: 'multiple-choice',
1332
+ title: 'Multiple Choice',
1333
+ description: 'MultipleChoice component for selection from options',
1334
+ group: 'Components',
1335
+ messages: [
1336
+ {
1337
+ surfaceUpdate: {
1338
+ surfaceId: 'main',
1339
+ components: [
1340
+ {
1341
+ id: 'root',
1342
+ component: {
1343
+ Column: {
1344
+ children: {
1345
+ explicitList: [
1346
+ 'heading',
1347
+ 'description',
1348
+ 'single-label',
1349
+ 'single-select',
1350
+ 'multi-label',
1351
+ 'multi-select',
1352
+ ],
1353
+ },
1354
+ },
1355
+ },
1356
+ },
1357
+ {
1358
+ id: 'heading',
1359
+ component: {
1360
+ Text: {
1361
+ text: { literalString: 'Multiple Choice Component' },
1362
+ usageHint: 'h2',
1363
+ },
1364
+ },
1365
+ },
1366
+ {
1367
+ id: 'description',
1368
+ component: {
1369
+ Text: {
1370
+ text: {
1371
+ literalString:
1372
+ 'Select one or multiple options from a list.',
1373
+ },
1374
+ usageHint: 'body',
1375
+ },
1376
+ },
1377
+ },
1378
+ {
1379
+ id: 'single-label',
1380
+ component: {
1381
+ Text: {
1382
+ text: { literalString: 'Single Selection:' },
1383
+ usageHint: 'caption',
1384
+ },
1385
+ },
1386
+ },
1387
+ {
1388
+ id: 'single-select',
1389
+ component: {
1390
+ MultipleChoice: {
1391
+ selections: { path: 'singleSelection' },
1392
+ options: [
1393
+ { label: { literalString: 'Option A' }, value: 'a' },
1394
+ { label: { literalString: 'Option B' }, value: 'b' },
1395
+ { label: { literalString: 'Option C' }, value: 'c' },
1396
+ ],
1397
+ maxAllowedSelections: 1,
1398
+ },
1399
+ },
1400
+ },
1401
+ {
1402
+ id: 'multi-label',
1403
+ component: {
1404
+ Text: {
1405
+ text: { literalString: 'Multiple Selection (max 2):' },
1406
+ usageHint: 'caption',
1407
+ },
1408
+ },
1409
+ },
1410
+ {
1411
+ id: 'multi-select',
1412
+ component: {
1413
+ MultipleChoice: {
1414
+ selections: { path: 'multiSelection' },
1415
+ options: [
1416
+ { label: { literalString: 'Red' }, value: 'red' },
1417
+ { label: { literalString: 'Green' }, value: 'green' },
1418
+ { label: { literalString: 'Blue' }, value: 'blue' },
1419
+ { label: { literalString: 'Yellow' }, value: 'yellow' },
1420
+ ],
1421
+ maxAllowedSelections: 2,
1422
+ },
1423
+ },
1424
+ },
1425
+ ],
1426
+ },
1427
+ },
1428
+ {
1429
+ dataModelUpdate: {
1430
+ surfaceId: 'main',
1431
+ contents: [
1432
+ { key: 'singleSelection', valueString: '' },
1433
+ { key: 'multiSelection', valueString: '' },
1434
+ ],
1435
+ },
1436
+ },
1437
+ {
1438
+ beginRendering: {
1439
+ surfaceId: 'main',
1440
+ root: 'root',
1441
+ },
1442
+ },
1443
+ ],
1444
+ },
1445
+ {
1446
+ id: 'slider',
1447
+ title: 'Slider',
1448
+ description: 'Slider component for range value selection',
1449
+ group: 'Components',
1450
+ messages: [
1451
+ {
1452
+ surfaceUpdate: {
1453
+ surfaceId: 'main',
1454
+ components: [
1455
+ {
1456
+ id: 'root',
1457
+ component: {
1458
+ Column: {
1459
+ children: {
1460
+ explicitList: [
1461
+ 'heading',
1462
+ 'description',
1463
+ 'volume-label',
1464
+ 'volume-slider',
1465
+ 'volume-value',
1466
+ 'progress-label',
1467
+ 'progress-slider',
1468
+ 'progress-value',
1469
+ ],
1470
+ },
1471
+ },
1472
+ },
1473
+ },
1474
+ {
1475
+ id: 'heading',
1476
+ component: {
1477
+ Text: {
1478
+ text: { literalString: 'Slider Component' },
1479
+ usageHint: 'h2',
1480
+ },
1481
+ },
1482
+ },
1483
+ {
1484
+ id: 'description',
1485
+ component: {
1486
+ Text: {
1487
+ text: {
1488
+ literalString:
1489
+ 'Select values within a range using sliders.',
1490
+ },
1491
+ usageHint: 'body',
1492
+ },
1493
+ },
1494
+ },
1495
+ {
1496
+ id: 'volume-label',
1497
+ component: {
1498
+ Text: {
1499
+ text: { literalString: 'Volume (0-100):' },
1500
+ usageHint: 'caption',
1501
+ },
1502
+ },
1503
+ },
1504
+ {
1505
+ id: 'volume-slider',
1506
+ component: {
1507
+ Slider: {
1508
+ value: { path: 'volume' },
1509
+ minValue: 0,
1510
+ maxValue: 100,
1511
+ },
1512
+ },
1513
+ },
1514
+ {
1515
+ id: 'volume-value',
1516
+ component: {
1517
+ Text: {
1518
+ text: { path: 'volume' },
1519
+ usageHint: 'body',
1520
+ },
1521
+ },
1522
+ },
1523
+ {
1524
+ id: 'progress-label',
1525
+ component: {
1526
+ Text: {
1527
+ text: { literalString: 'Progress (0-10):' },
1528
+ usageHint: 'caption',
1529
+ },
1530
+ },
1531
+ },
1532
+ {
1533
+ id: 'progress-slider',
1534
+ component: {
1535
+ Slider: {
1536
+ value: { path: 'progress' },
1537
+ minValue: 0,
1538
+ maxValue: 10,
1539
+ },
1540
+ },
1541
+ },
1542
+ {
1543
+ id: 'progress-value',
1544
+ component: {
1545
+ Text: {
1546
+ text: { path: 'progress' },
1547
+ usageHint: 'body',
1548
+ },
1549
+ },
1550
+ },
1551
+ ],
1552
+ },
1553
+ },
1554
+ {
1555
+ dataModelUpdate: {
1556
+ surfaceId: 'main',
1557
+ contents: [
1558
+ { key: 'volume', valueNumber: 50 },
1559
+ { key: 'progress', valueNumber: 5 },
1560
+ ],
1561
+ },
1562
+ },
1563
+ {
1564
+ beginRendering: {
1565
+ surfaceId: 'main',
1566
+ root: 'root',
1567
+ },
1568
+ },
1569
+ ],
1570
+ },
1571
+ ]