@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.
- package/.claude/commands/speckit.analyze.md +184 -0
- package/.claude/commands/speckit.checklist.md +294 -0
- package/.claude/commands/speckit.clarify.md +181 -0
- package/.claude/commands/speckit.constitution.md +82 -0
- package/.claude/commands/speckit.implement.md +135 -0
- package/.claude/commands/speckit.plan.md +89 -0
- package/.claude/commands/speckit.specify.md +256 -0
- package/.claude/commands/speckit.tasks.md +137 -0
- package/.claude/commands/speckit.taskstoissues.md +30 -0
- package/.github/workflows/deploy.yml +69 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc +7 -0
- package/.specify/memory/constitution.md +73 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +156 -0
- package/.specify/scripts/bash/create-new-feature.sh +297 -0
- package/.specify/scripts/bash/setup-plan.sh +61 -0
- package/.specify/scripts/bash/update-agent-context.sh +799 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/plan-template.md +105 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +250 -0
- package/CLAUDE.md +105 -0
- package/CONTRIBUTING.md +97 -0
- package/README.md +126 -0
- package/components.json +21 -0
- package/eslint.config.js +25 -0
- package/netlify.toml +50 -0
- package/package.json +94 -0
- package/playground/README.md +75 -0
- package/playground/index.html +22 -0
- package/playground/package.json +32 -0
- package/playground/public/favicon.svg +8 -0
- package/playground/src/App.css +256 -0
- package/playground/src/App.tsx +115 -0
- package/playground/src/assets/react.svg +1 -0
- package/playground/src/components/ErrorDisplay.tsx +13 -0
- package/playground/src/components/ExampleSelector.tsx +64 -0
- package/playground/src/components/Header.tsx +47 -0
- package/playground/src/components/JsonEditor.tsx +32 -0
- package/playground/src/components/Preview.tsx +78 -0
- package/playground/src/components/ThemeToggle.tsx +19 -0
- package/playground/src/data/examples.ts +1571 -0
- package/playground/src/hooks/useTheme.ts +55 -0
- package/playground/src/index.css +220 -0
- package/playground/src/main.tsx +10 -0
- package/playground/tsconfig.app.json +34 -0
- package/playground/tsconfig.json +13 -0
- package/playground/tsconfig.node.json +26 -0
- package/playground/vite.config.ts +31 -0
- package/specs/001-a2ui-renderer/checklists/requirements.md +41 -0
- package/specs/001-a2ui-renderer/data-model.md +140 -0
- package/specs/001-a2ui-renderer/plan.md +123 -0
- package/specs/001-a2ui-renderer/quickstart.md +141 -0
- package/specs/001-a2ui-renderer/research.md +140 -0
- package/specs/001-a2ui-renderer/spec.md +165 -0
- package/specs/001-a2ui-renderer/tasks.md +310 -0
- package/specs/002-playground/checklists/requirements.md +37 -0
- package/specs/002-playground/contracts/components.md +120 -0
- package/specs/002-playground/data-model.md +149 -0
- package/specs/002-playground/plan.md +73 -0
- package/specs/002-playground/quickstart.md +158 -0
- package/specs/002-playground/research.md +117 -0
- package/specs/002-playground/spec.md +109 -0
- package/specs/002-playground/tasks.md +224 -0
- package/src/0.8/A2UIRender.test.tsx +793 -0
- package/src/0.8/A2UIRender.tsx +142 -0
- package/src/0.8/components/ComponentRenderer.test.tsx +373 -0
- package/src/0.8/components/ComponentRenderer.tsx +163 -0
- package/src/0.8/components/UnknownComponent.tsx +49 -0
- package/src/0.8/components/display/AudioPlayerComponent.tsx +37 -0
- package/src/0.8/components/display/DividerComponent.tsx +23 -0
- package/src/0.8/components/display/IconComponent.tsx +137 -0
- package/src/0.8/components/display/ImageComponent.tsx +57 -0
- package/src/0.8/components/display/TextComponent.tsx +56 -0
- package/src/0.8/components/display/VideoComponent.tsx +31 -0
- package/src/0.8/components/display/display.test.tsx +660 -0
- package/src/0.8/components/display/index.ts +10 -0
- package/src/0.8/components/index.ts +14 -0
- package/src/0.8/components/interactive/ButtonComponent.tsx +44 -0
- package/src/0.8/components/interactive/CheckBoxComponent.tsx +45 -0
- package/src/0.8/components/interactive/DateTimeInputComponent.tsx +176 -0
- package/src/0.8/components/interactive/MultipleChoiceComponent.tsx +157 -0
- package/src/0.8/components/interactive/SliderComponent.tsx +53 -0
- package/src/0.8/components/interactive/TextFieldComponent.tsx +65 -0
- package/src/0.8/components/interactive/index.ts +10 -0
- package/src/0.8/components/interactive/interactive.test.tsx +618 -0
- package/src/0.8/components/layout/CardComponent.tsx +30 -0
- package/src/0.8/components/layout/ColumnComponent.tsx +93 -0
- package/src/0.8/components/layout/ListComponent.tsx +81 -0
- package/src/0.8/components/layout/ModalComponent.tsx +41 -0
- package/src/0.8/components/layout/RowComponent.tsx +94 -0
- package/src/0.8/components/layout/TabsComponent.tsx +59 -0
- package/src/0.8/components/layout/index.ts +10 -0
- package/src/0.8/components/layout/layout.test.tsx +558 -0
- package/src/0.8/contexts/A2UIProvider.test.tsx +226 -0
- package/src/0.8/contexts/A2UIProvider.tsx +54 -0
- package/src/0.8/contexts/ActionContext.test.tsx +242 -0
- package/src/0.8/contexts/ActionContext.tsx +105 -0
- package/src/0.8/contexts/ComponentsMapContext.tsx +125 -0
- package/src/0.8/contexts/DataModelContext.test.tsx +335 -0
- package/src/0.8/contexts/DataModelContext.tsx +184 -0
- package/src/0.8/contexts/SurfaceContext.test.tsx +339 -0
- package/src/0.8/contexts/SurfaceContext.tsx +197 -0
- package/src/0.8/hooks/useA2UIMessageHandler.test.tsx +399 -0
- package/src/0.8/hooks/useA2UIMessageHandler.ts +123 -0
- package/src/0.8/hooks/useComponent.test.tsx +148 -0
- package/src/0.8/hooks/useComponent.ts +39 -0
- package/src/0.8/hooks/useDataBinding.test.tsx +334 -0
- package/src/0.8/hooks/useDataBinding.ts +99 -0
- package/src/0.8/hooks/useDispatchAction.test.tsx +83 -0
- package/src/0.8/hooks/useDispatchAction.ts +35 -0
- package/src/0.8/hooks/useSurface.test.tsx +114 -0
- package/src/0.8/hooks/useSurface.ts +34 -0
- package/src/0.8/index.ts +38 -0
- package/src/0.8/schemas/client_to_server.json +50 -0
- package/src/0.8/schemas/server_to_client.json +148 -0
- package/src/0.8/schemas/standard_catalog_definition.json +661 -0
- package/src/0.8/types/index.ts +448 -0
- package/src/0.8/utils/dataBinding.test.ts +443 -0
- package/src/0.8/utils/dataBinding.ts +212 -0
- package/src/0.8/utils/pathUtils.test.ts +353 -0
- package/src/0.8/utils/pathUtils.ts +200 -0
- package/src/components/ui/button.tsx +62 -0
- package/src/components/ui/calendar.tsx +220 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/dialog.tsx +141 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +22 -0
- package/src/components/ui/native-select.tsx +53 -0
- package/src/components/ui/popover.tsx +46 -0
- package/src/components/ui/select.tsx +188 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/slider.tsx +61 -0
- package/src/components/ui/tabs.tsx +64 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/index.ts +1 -0
- package/src/lib/utils.ts +6 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +29 -0
- package/vitest.config.ts +22 -0
- package/vitest.setup.ts +8 -0
- package/website/README.md +4 -0
- package/website/assets/favicon.svg +8 -0
- package/website/content/.gitkeep +0 -0
- package/website/content/index.md +122 -0
- package/website/global.d.ts +9 -0
- package/website/package.json +17 -0
- package/website/plain.config.js +28 -0
- package/website/serve.json +6 -0
- package/website/src/client/color-mode-switch.css +47 -0
- package/website/src/client/index.js +61 -0
- package/website/src/client/moon.svg +1 -0
- package/website/src/client/sun.svg +1 -0
- package/website/src/components/Footer.jsx +9 -0
- package/website/src/components/Header.jsx +44 -0
- package/website/src/components/Page.jsx +28 -0
- package/website/src/global.css +423 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Tasks: A2UIRenderer Component Library
|
|
2
|
+
|
|
3
|
+
**Input**: Design documents from `/specs/001-a2ui-renderer/`
|
|
4
|
+
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, quickstart.md
|
|
5
|
+
|
|
6
|
+
**Tests**: Tests are included as the existing codebase has test coverage patterns established.
|
|
7
|
+
|
|
8
|
+
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
|
9
|
+
|
|
10
|
+
## Format: `[ID] [P?] [Story] Description`
|
|
11
|
+
|
|
12
|
+
- **[P]**: Can run in parallel (different files, no dependencies)
|
|
13
|
+
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
|
14
|
+
- Include exact file paths in descriptions
|
|
15
|
+
|
|
16
|
+
## Path Conventions
|
|
17
|
+
|
|
18
|
+
- **Single library project**: `src/0.8/` at repository root
|
|
19
|
+
- Tests co-located with source files (e.g., `A2UIRender.test.tsx`)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Phase 1: Setup (Shared Infrastructure)
|
|
24
|
+
|
|
25
|
+
**Purpose**: Create the public API entry point and foundational exports
|
|
26
|
+
|
|
27
|
+
- [x] T001 Create index.ts public API exports file in src/0.8/index.ts
|
|
28
|
+
- [x] T002 Export A2UIMessage type from src/0.8/index.ts
|
|
29
|
+
- [x] T003 Export ActionPayload as A2UIAction type alias from src/0.8/index.ts
|
|
30
|
+
- [x] T004 [P] Export useDispatchAction hook from src/0.8/index.ts
|
|
31
|
+
- [x] T005 [P] Export useDataBinding hook from src/0.8/index.ts
|
|
32
|
+
- [x] T006 [P] Export useFormBinding hook from src/0.8/index.ts
|
|
33
|
+
- [x] T007 [P] Export ComponentRenderer component from src/0.8/index.ts
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Phase 2: Foundational (Blocking Prerequisites)
|
|
38
|
+
|
|
39
|
+
**Purpose**: Create ComponentsMap context for custom component support
|
|
40
|
+
|
|
41
|
+
**⚠️ CRITICAL**: User stories 3-4 depend on this phase for custom component support
|
|
42
|
+
|
|
43
|
+
- [x] T008 Create ComponentsMapContext in src/0.8/contexts/ComponentsMapContext.tsx
|
|
44
|
+
- [x] T009 Add ComponentsMapProvider to wrap component rendering
|
|
45
|
+
- [x] T010 Update ComponentRenderer to use ComponentsMapContext for component lookup in src/0.8/components/ComponentRenderer.tsx
|
|
46
|
+
- [x] T011 Add dev-mode placeholder component for unknown types in src/0.8/components/UnknownComponent.tsx
|
|
47
|
+
- [x] T012 Update ComponentRenderer to render UnknownComponent in dev mode, skip in production
|
|
48
|
+
|
|
49
|
+
**Checkpoint**: Foundation ready - A2UIRender component can now be implemented
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Phase 3: User Story 1 - Basic Message Rendering (Priority: P1) 🎯 MVP
|
|
54
|
+
|
|
55
|
+
**Goal**: Render A2UI messages using the A2UIRender component
|
|
56
|
+
|
|
57
|
+
**Independent Test**: Pass an array of A2UIMessage objects to A2UIRender and verify the UI renders correctly
|
|
58
|
+
|
|
59
|
+
### Tests for User Story 1
|
|
60
|
+
|
|
61
|
+
- [x] T013 [P] [US1] Create test file src/0.8/A2UIRender.test.tsx with test setup
|
|
62
|
+
- [x] T014 [P] [US1] Add test: renders nothing for empty messages array
|
|
63
|
+
- [x] T015 [P] [US1] Add test: renders components from valid A2UIMessage objects
|
|
64
|
+
- [x] T016 [P] [US1] Add test: renders nested components correctly
|
|
65
|
+
|
|
66
|
+
### Implementation for User Story 1
|
|
67
|
+
|
|
68
|
+
- [x] T017 [US1] Create A2UIRender component in src/0.8/A2UIRender.tsx
|
|
69
|
+
- [x] T018 [US1] Implement messages prop handling with useA2UIMessageHandler
|
|
70
|
+
- [x] T019 [US1] Implement surface rendering loop (render all surfaces from context)
|
|
71
|
+
- [x] T020 [US1] Add null/undefined messages handling (graceful empty render)
|
|
72
|
+
- [x] T021 [US1] Export A2UIRender from src/0.8/index.ts
|
|
73
|
+
|
|
74
|
+
**Checkpoint**: User Story 1 complete - basic rendering works independently
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Phase 4: User Story 2 - Action Handling (Priority: P1)
|
|
79
|
+
|
|
80
|
+
**Goal**: Receive action callbacks when users interact with components
|
|
81
|
+
|
|
82
|
+
**Independent Test**: Click interactive components and verify onAction callback receives correct A2UIAction payload
|
|
83
|
+
|
|
84
|
+
### Tests for User Story 2
|
|
85
|
+
|
|
86
|
+
- [x] T022 [P] [US2] Add test: onAction callback invoked when button clicked
|
|
87
|
+
- [x] T023 [P] [US2] Add test: action payload contains surfaceId, componentId, and context
|
|
88
|
+
- [x] T024 [P] [US2] Add test: multiple components dispatch unique actions
|
|
89
|
+
|
|
90
|
+
### Implementation for User Story 2
|
|
91
|
+
|
|
92
|
+
- [x] T025 [US2] Add onAction prop to A2UIRender component in src/0.8/A2UIRender.tsx
|
|
93
|
+
- [x] T026 [US2] Pass onAction to A2UIProvider in A2UIRender
|
|
94
|
+
- [x] T027 [US2] Add test: no error when action dispatched without onAction callback
|
|
95
|
+
|
|
96
|
+
**Checkpoint**: User Stories 1 AND 2 complete - rendering and actions work
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Phase 5: User Story 3 - Custom Component Override (Priority: P2)
|
|
101
|
+
|
|
102
|
+
**Goal**: Override default components with custom implementations via ComponentsMap
|
|
103
|
+
|
|
104
|
+
**Independent Test**: Provide ComponentsMap with custom Button and verify it renders instead of default
|
|
105
|
+
|
|
106
|
+
### Tests for User Story 3
|
|
107
|
+
|
|
108
|
+
- [x] T028 [P] [US3] Add test: custom Button component renders instead of default
|
|
109
|
+
- [x] T029 [P] [US3] Add test: multiple custom components render correctly
|
|
110
|
+
- [x] T030 [P] [US3] Add test: non-overridden components use defaults
|
|
111
|
+
|
|
112
|
+
### Implementation for User Story 3
|
|
113
|
+
|
|
114
|
+
- [x] T031 [US3] Add components prop (ComponentsMap) to A2UIRender in src/0.8/A2UIRender.tsx
|
|
115
|
+
- [x] T032 [US3] Wrap rendering with ComponentsMapProvider passing custom components
|
|
116
|
+
- [x] T033 [US3] Merge custom components with defaults in ComponentsMapContext
|
|
117
|
+
|
|
118
|
+
**Checkpoint**: User Story 3 complete - custom component overrides work
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Phase 6: User Story 4 - Custom Component Creation (Priority: P2)
|
|
123
|
+
|
|
124
|
+
**Goal**: Add new custom component types that don't exist in defaults
|
|
125
|
+
|
|
126
|
+
**Independent Test**: Add new "Switch" component type to ComponentsMap and verify it renders
|
|
127
|
+
|
|
128
|
+
### Tests for User Story 4
|
|
129
|
+
|
|
130
|
+
- [x] T034 [P] [US4] Add test: new component type "Switch" renders from ComponentsMap
|
|
131
|
+
- [x] T035 [P] [US4] Add test: custom component can use useDispatchAction hook
|
|
132
|
+
|
|
133
|
+
### Implementation for User Story 4
|
|
134
|
+
|
|
135
|
+
- [x] T036 [US4] Ensure ComponentsMapContext supports adding new types (not just overrides)
|
|
136
|
+
- [x] T037 [US4] Verify useDispatchAction works in custom components (integration test)
|
|
137
|
+
|
|
138
|
+
**Checkpoint**: User Story 4 complete - extensibility works
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Phase 7: User Story 5 - Data Binding in Custom Components (Priority: P3)
|
|
143
|
+
|
|
144
|
+
**Goal**: Use useDataBinding hook in custom components to read dynamic values
|
|
145
|
+
|
|
146
|
+
**Independent Test**: Create custom component using useDataBinding and verify it displays bound value
|
|
147
|
+
|
|
148
|
+
### Tests for User Story 5
|
|
149
|
+
|
|
150
|
+
- [x] T038 [P] [US5] Add test: custom component with useDataBinding displays bound value
|
|
151
|
+
- [x] T039 [P] [US5] Add test: useDataBinding returns default when path not found
|
|
152
|
+
|
|
153
|
+
### Implementation for User Story 5
|
|
154
|
+
|
|
155
|
+
- [x] T040 [US5] Verify useDataBinding is exported from index.ts (already done in T005)
|
|
156
|
+
- [x] T041 [US5] Add integration test with custom component using useDataBinding
|
|
157
|
+
|
|
158
|
+
**Checkpoint**: User Story 5 complete - data binding works in custom components
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Phase 8: User Story 6 - Form Binding in Custom Components (Priority: P3)
|
|
163
|
+
|
|
164
|
+
**Goal**: Use useFormBinding hook for two-way data binding in form inputs
|
|
165
|
+
|
|
166
|
+
**Independent Test**: Create custom Switch component using useFormBinding and verify value changes
|
|
167
|
+
|
|
168
|
+
### Tests for User Story 6
|
|
169
|
+
|
|
170
|
+
- [x] T042 [P] [US6] Add test: custom component with useFormBinding displays current value
|
|
171
|
+
- [x] T043 [P] [US6] Add test: useFormBinding setValue updates the bound value
|
|
172
|
+
- [x] T044 [P] [US6] Add test: useFormBinding returns default when path not found
|
|
173
|
+
|
|
174
|
+
### Implementation for User Story 6
|
|
175
|
+
|
|
176
|
+
- [x] T045 [US6] Verify useFormBinding is exported from index.ts (already done in T006)
|
|
177
|
+
- [x] T046 [US6] Add integration test with custom Switch component using useFormBinding
|
|
178
|
+
|
|
179
|
+
**Checkpoint**: User Story 6 complete - form binding works in custom components
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Phase 9: Polish & Cross-Cutting Concerns
|
|
184
|
+
|
|
185
|
+
**Purpose**: Final validation and documentation
|
|
186
|
+
|
|
187
|
+
- [x] T047 [P] Verify all exports match README.md usage examples
|
|
188
|
+
- [x] T048 [P] Run full test suite and ensure all tests pass
|
|
189
|
+
- [ ] T049 [P] Verify build succeeds with `npm run build`
|
|
190
|
+
- [ ] T050 Run quickstart.md validation - test all code examples work
|
|
191
|
+
- [ ] T051 Update README.md if any API changes needed
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Dependencies & Execution Order
|
|
196
|
+
|
|
197
|
+
### Phase Dependencies
|
|
198
|
+
|
|
199
|
+
- **Setup (Phase 1)**: No dependencies - can start immediately
|
|
200
|
+
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS user stories 3-4
|
|
201
|
+
- **User Story 1 (Phase 3)**: Depends on Setup (Phase 1) only
|
|
202
|
+
- **User Story 2 (Phase 4)**: Depends on User Story 1 (needs A2UIRender component)
|
|
203
|
+
- **User Story 3 (Phase 5)**: Depends on Foundational (Phase 2) for ComponentsMapContext
|
|
204
|
+
- **User Story 4 (Phase 6)**: Depends on User Story 3 (extends ComponentsMap support)
|
|
205
|
+
- **User Story 5 (Phase 7)**: Depends on Setup (Phase 1) - hooks already exist
|
|
206
|
+
- **User Story 6 (Phase 8)**: Depends on Setup (Phase 1) - hooks already exist
|
|
207
|
+
- **Polish (Phase 9)**: Depends on all user stories being complete
|
|
208
|
+
|
|
209
|
+
### User Story Dependencies
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
Phase 1 (Setup)
|
|
213
|
+
│
|
|
214
|
+
├──────────────────────────────────┐
|
|
215
|
+
│ │
|
|
216
|
+
▼ ▼
|
|
217
|
+
Phase 2 (Foundational) Phase 3 (US1: Basic Rendering)
|
|
218
|
+
│ │
|
|
219
|
+
│ ▼
|
|
220
|
+
│ Phase 4 (US2: Action Handling)
|
|
221
|
+
│ │
|
|
222
|
+
▼ │
|
|
223
|
+
Phase 5 (US3: Custom Override) ◄───────┘
|
|
224
|
+
│
|
|
225
|
+
▼
|
|
226
|
+
Phase 6 (US4: Custom Creation)
|
|
227
|
+
│
|
|
228
|
+
├──────────────────────────────────┐
|
|
229
|
+
│ │
|
|
230
|
+
▼ ▼
|
|
231
|
+
Phase 7 (US5: Data Binding) Phase 8 (US6: Form Binding)
|
|
232
|
+
│ │
|
|
233
|
+
└──────────────────────────────────┘
|
|
234
|
+
│
|
|
235
|
+
▼
|
|
236
|
+
Phase 9 (Polish)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Parallel Opportunities
|
|
240
|
+
|
|
241
|
+
**Within Phase 1 (Setup)**:
|
|
242
|
+
|
|
243
|
+
- T004, T005, T006, T007 can run in parallel (different exports)
|
|
244
|
+
|
|
245
|
+
**Within Phase 3 (US1)**:
|
|
246
|
+
|
|
247
|
+
- T013, T014, T015, T016 can run in parallel (different test cases)
|
|
248
|
+
|
|
249
|
+
**Within Phase 4 (US2)**:
|
|
250
|
+
|
|
251
|
+
- T022, T023, T024 can run in parallel (different test cases)
|
|
252
|
+
|
|
253
|
+
**Within Phase 5 (US3)**:
|
|
254
|
+
|
|
255
|
+
- T028, T029, T030 can run in parallel (different test cases)
|
|
256
|
+
|
|
257
|
+
**Within Phase 7 & 8 (US5 & US6)**:
|
|
258
|
+
|
|
259
|
+
- These phases can run in parallel with each other (independent hooks)
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Parallel Example: Phase 1 Setup
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Launch all export tasks together:
|
|
267
|
+
Task: "Export useDispatchAction hook from src/0.8/index.ts"
|
|
268
|
+
Task: "Export useDataBinding hook from src/0.8/index.ts"
|
|
269
|
+
Task: "Export useFormBinding hook from src/0.8/index.ts"
|
|
270
|
+
Task: "Export ComponentRenderer component from src/0.8/index.ts"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Implementation Strategy
|
|
276
|
+
|
|
277
|
+
### MVP First (User Stories 1 + 2 Only)
|
|
278
|
+
|
|
279
|
+
1. Complete Phase 1: Setup (index.ts exports)
|
|
280
|
+
2. Complete Phase 3: User Story 1 (basic rendering)
|
|
281
|
+
3. Complete Phase 4: User Story 2 (action handling)
|
|
282
|
+
4. **STOP and VALIDATE**: Test basic rendering with actions
|
|
283
|
+
5. Deploy/demo if ready - this covers the primary README.md example
|
|
284
|
+
|
|
285
|
+
### Incremental Delivery
|
|
286
|
+
|
|
287
|
+
1. Setup → US1 → US2 → **MVP Ready** (basic usage works)
|
|
288
|
+
2. Add Foundational → US3 → US4 → **Customization Ready** (ComponentsMap works)
|
|
289
|
+
3. Add US5 → US6 → **Full Feature Set** (all hooks work in custom components)
|
|
290
|
+
4. Polish → **Production Ready**
|
|
291
|
+
|
|
292
|
+
### Parallel Team Strategy
|
|
293
|
+
|
|
294
|
+
With multiple developers:
|
|
295
|
+
|
|
296
|
+
1. Developer A: Phase 1 + Phase 3 + Phase 4 (core rendering path)
|
|
297
|
+
2. Developer B: Phase 2 + Phase 5 + Phase 6 (customization path)
|
|
298
|
+
3. Developer C: Phase 7 + Phase 8 (hook integration tests)
|
|
299
|
+
4. All: Phase 9 (polish)
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Notes
|
|
304
|
+
|
|
305
|
+
- [P] tasks = different files, no dependencies
|
|
306
|
+
- [Story] label maps task to specific user story for traceability
|
|
307
|
+
- Most infrastructure already exists - tasks focus on integration and public API
|
|
308
|
+
- Existing tests provide patterns to follow
|
|
309
|
+
- Commit after each task or logical group
|
|
310
|
+
- Stop at any checkpoint to validate story independently
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Specification Quality Checklist: A2UI Playground
|
|
2
|
+
|
|
3
|
+
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
|
4
|
+
**Created**: 2026-01-10
|
|
5
|
+
**Feature**: [spec.md](../spec.md)
|
|
6
|
+
|
|
7
|
+
## Content Quality
|
|
8
|
+
|
|
9
|
+
- [x] No implementation details (languages, frameworks, APIs)
|
|
10
|
+
- [x] Focused on user value and business needs
|
|
11
|
+
- [x] Written for non-technical stakeholders
|
|
12
|
+
- [x] All mandatory sections completed
|
|
13
|
+
|
|
14
|
+
## Requirement Completeness
|
|
15
|
+
|
|
16
|
+
- [x] No [NEEDS CLARIFICATION] markers remain
|
|
17
|
+
- [x] Requirements are testable and unambiguous
|
|
18
|
+
- [x] Success criteria are measurable
|
|
19
|
+
- [x] Success criteria are technology-agnostic (no implementation details)
|
|
20
|
+
- [x] All acceptance scenarios are defined
|
|
21
|
+
- [x] Edge cases are identified
|
|
22
|
+
- [x] Scope is clearly bounded
|
|
23
|
+
- [x] Dependencies and assumptions identified
|
|
24
|
+
|
|
25
|
+
## Feature Readiness
|
|
26
|
+
|
|
27
|
+
- [x] All functional requirements have clear acceptance criteria
|
|
28
|
+
- [x] User scenarios cover primary flows
|
|
29
|
+
- [x] Feature meets measurable outcomes defined in Success Criteria
|
|
30
|
+
- [x] No implementation details leak into specification
|
|
31
|
+
|
|
32
|
+
## Notes
|
|
33
|
+
|
|
34
|
+
- All checklist items pass validation
|
|
35
|
+
- Spec is ready for `/speckit.clarify` or `/speckit.plan`
|
|
36
|
+
- The specification assumes desktop-first design (1024px+) as documented in Assumptions
|
|
37
|
+
- JSON editor library choice is intentionally left as implementation detail
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Component Contracts: A2UI Playground
|
|
2
|
+
|
|
3
|
+
**Feature**: 002-playground
|
|
4
|
+
**Date**: 2026-01-10
|
|
5
|
+
|
|
6
|
+
This is a client-side only application with no external API contracts. This document defines the internal component interfaces.
|
|
7
|
+
|
|
8
|
+
## Component Props Interfaces
|
|
9
|
+
|
|
10
|
+
### Header
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
interface HeaderProps {
|
|
14
|
+
title: string
|
|
15
|
+
children?: React.ReactNode // For theme toggle slot
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### ThemeToggle
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
interface ThemeToggleProps {
|
|
23
|
+
theme: 'light' | 'dark'
|
|
24
|
+
onToggle: () => void
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### JsonEditor
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
interface JsonEditorProps {
|
|
32
|
+
value: string
|
|
33
|
+
onChange: (value: string) => void
|
|
34
|
+
theme?: 'light' | 'dark'
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Preview
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface PreviewProps {
|
|
42
|
+
messages: A2UIMessage[] | null
|
|
43
|
+
error: string | null
|
|
44
|
+
onAction?: (action: A2UIAction) => void
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### ExampleSelector
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
interface ExampleSelectorProps {
|
|
52
|
+
examples: Example[]
|
|
53
|
+
selectedId: string
|
|
54
|
+
onSelect: (id: string) => void
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### ErrorDisplay
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
interface ErrorDisplayProps {
|
|
62
|
+
title?: string
|
|
63
|
+
message: string
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Hook Interfaces
|
|
68
|
+
|
|
69
|
+
### useTheme
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
function useTheme(): {
|
|
73
|
+
theme: 'light' | 'dark'
|
|
74
|
+
toggleTheme: () => void
|
|
75
|
+
setTheme: (theme: 'light' | 'dark') => void
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Data Interfaces
|
|
80
|
+
|
|
81
|
+
### Example
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
interface Example {
|
|
85
|
+
id: string
|
|
86
|
+
title: string
|
|
87
|
+
description: string
|
|
88
|
+
messages: A2UIMessage[]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Event Contracts
|
|
93
|
+
|
|
94
|
+
### Editor Change Event
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Triggered when user edits JSON in editor
|
|
98
|
+
type EditorChangeHandler = (newValue: string) => void
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Example Select Event
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Triggered when user selects an example from dropdown
|
|
105
|
+
type ExampleSelectHandler = (exampleId: string) => void
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Theme Toggle Event
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Triggered when user clicks theme toggle
|
|
112
|
+
type ThemeToggleHandler = () => void
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Action Dispatch Event
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Triggered when A2UIRender dispatches an action
|
|
119
|
+
type ActionHandler = (action: A2UIAction) => void
|
|
120
|
+
```
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Data Model: A2UI Playground
|
|
2
|
+
|
|
3
|
+
**Feature**: 002-playground
|
|
4
|
+
**Date**: 2026-01-10
|
|
5
|
+
|
|
6
|
+
## Entities
|
|
7
|
+
|
|
8
|
+
### Example
|
|
9
|
+
|
|
10
|
+
Represents a pre-built A2UI message configuration that users can select.
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
interface Example {
|
|
14
|
+
id: string // Unique identifier (e.g., "hello-world")
|
|
15
|
+
title: string // Display name (e.g., "Hello World")
|
|
16
|
+
description: string // Brief explanation of what the example demonstrates
|
|
17
|
+
messages: A2UIMessage[] // The A2UI messages to render
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Validation Rules**:
|
|
22
|
+
|
|
23
|
+
- `id` must be unique across all examples
|
|
24
|
+
- `title` must be non-empty
|
|
25
|
+
- `messages` must be a valid A2UIMessage array
|
|
26
|
+
|
|
27
|
+
### Theme
|
|
28
|
+
|
|
29
|
+
User's color scheme preference.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
type Theme = 'light' | 'dark'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Storage**: localStorage key `'theme'`
|
|
36
|
+
|
|
37
|
+
**Default**: System preference via `prefers-color-scheme` media query
|
|
38
|
+
|
|
39
|
+
### EditorState
|
|
40
|
+
|
|
41
|
+
Current state of the playground editor.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
interface EditorState {
|
|
45
|
+
jsonContent: string // Raw JSON string in editor
|
|
46
|
+
parsedMessages: A2UIMessage[] | null // Parsed messages (null if invalid JSON)
|
|
47
|
+
parseError: string | null // Error message if JSON is invalid
|
|
48
|
+
selectedExampleId: string // Currently selected example ID
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Validation Rules**:
|
|
53
|
+
|
|
54
|
+
- `jsonContent` can be any string (including invalid JSON)
|
|
55
|
+
- `parsedMessages` is null when JSON parsing fails
|
|
56
|
+
- `parseError` contains the error message when parsing fails
|
|
57
|
+
|
|
58
|
+
## State Transitions
|
|
59
|
+
|
|
60
|
+
### Editor Content Flow
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
User types in editor
|
|
64
|
+
↓
|
|
65
|
+
jsonContent updated
|
|
66
|
+
↓
|
|
67
|
+
JSON.parse() attempted
|
|
68
|
+
↓
|
|
69
|
+
┌─────────────────────────────────────┐
|
|
70
|
+
│ Success │ Failure
|
|
71
|
+
│ ↓ │ ↓
|
|
72
|
+
│ parsedMessages = result │ parsedMessages = null
|
|
73
|
+
│ parseError = null │ parseError = error.message
|
|
74
|
+
│ ↓ │ ↓
|
|
75
|
+
│ A2UIRender receives messages │ ErrorDisplay shown
|
|
76
|
+
└─────────────────────────────────────┘
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Example Selection Flow
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
User selects example from dropdown
|
|
83
|
+
↓
|
|
84
|
+
selectedExampleId updated
|
|
85
|
+
↓
|
|
86
|
+
jsonContent = JSON.stringify(example.messages, null, 2)
|
|
87
|
+
↓
|
|
88
|
+
parsedMessages = example.messages
|
|
89
|
+
parseError = null
|
|
90
|
+
↓
|
|
91
|
+
Editor and Preview both update
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Theme Toggle Flow
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
User clicks theme toggle
|
|
98
|
+
↓
|
|
99
|
+
Current theme read from state
|
|
100
|
+
↓
|
|
101
|
+
New theme = (current === 'dark') ? 'light' : 'dark'
|
|
102
|
+
↓
|
|
103
|
+
document.documentElement.dataset.theme = newTheme
|
|
104
|
+
localStorage.setItem('theme', newTheme)
|
|
105
|
+
↓
|
|
106
|
+
UI re-renders with new theme
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Relationships
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
┌─────────────┐ selects ┌─────────────┐
|
|
113
|
+
│ Example │◄─────────────────│ EditorState │
|
|
114
|
+
└─────────────┘ └─────────────┘
|
|
115
|
+
│ │
|
|
116
|
+
│ provides │ contains
|
|
117
|
+
▼ ▼
|
|
118
|
+
┌─────────────┐ ┌─────────────┐
|
|
119
|
+
│ A2UIMessage │ │ jsonContent │
|
|
120
|
+
│ Array │ │ (string) │
|
|
121
|
+
└─────────────┘ └─────────────┘
|
|
122
|
+
│ │
|
|
123
|
+
└───────────┬───────────────────┘
|
|
124
|
+
│ renders
|
|
125
|
+
▼
|
|
126
|
+
┌─────────────┐
|
|
127
|
+
│ A2UIRender │
|
|
128
|
+
└─────────────┘
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## A2UIMessage Structure (Reference)
|
|
132
|
+
|
|
133
|
+
From the main library, A2UIMessage is a union type:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
type A2UIMessage =
|
|
137
|
+
| { beginRendering: { surfaceId: string; root: string; styles?: string } }
|
|
138
|
+
| { surfaceUpdate: { surfaceId: string; components: ComponentUpdate[] } }
|
|
139
|
+
| {
|
|
140
|
+
dataModelUpdate: {
|
|
141
|
+
surfaceId: string
|
|
142
|
+
path: string
|
|
143
|
+
contents: DataContent[]
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
| { deleteSurface: { surfaceId: string } }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Examples must conform to this structure to render correctly.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Implementation Plan: A2UI Playground
|
|
2
|
+
|
|
3
|
+
**Branch**: `002-playground` | **Date**: 2026-01-10 | **Spec**: [spec.md](./spec.md)
|
|
4
|
+
**Input**: Feature specification from `/specs/002-playground/spec.md`
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
Implement an interactive playground for the A2UI React library that allows developers to edit A2UI JSON messages in a code editor and see real-time rendered previews. The playground includes a header matching the website design (with theme toggle), a split-panel layout (editor left, preview right), and pre-built examples selectable via dropdown.
|
|
9
|
+
|
|
10
|
+
## Technical Context
|
|
11
|
+
|
|
12
|
+
**Language/Version**: TypeScript 5.9, React 19
|
|
13
|
+
**Primary Dependencies**: @uiw/react-codemirror (CodeMirror 6), @codemirror/lang-json, @easyops-cn/a2ui-react, Tailwind CSS 4
|
|
14
|
+
**Storage**: localStorage (theme preference only)
|
|
15
|
+
**Testing**: Vitest + React Testing Library (inherited from root)
|
|
16
|
+
**Target Platform**: Modern browsers (Chrome, Firefox, Safari, Edge), desktop 1024px+
|
|
17
|
+
**Project Type**: Web application (playground workspace within monorepo)
|
|
18
|
+
**Performance Goals**: Preview updates within 500ms, initial load under 3 seconds
|
|
19
|
+
**Constraints**: Desktop-only (1024px minimum width), client-side only
|
|
20
|
+
**Scale/Scope**: Single-page application, 5-6 pre-built examples
|
|
21
|
+
|
|
22
|
+
## Constitution Check
|
|
23
|
+
|
|
24
|
+
_GATE: Must pass before Phase 0 research. Re-check after Phase 1 design._
|
|
25
|
+
|
|
26
|
+
The project constitution is a template without specific rules defined. No gates to enforce.
|
|
27
|
+
|
|
28
|
+
**Status**: PASS (no violations)
|
|
29
|
+
|
|
30
|
+
## Project Structure
|
|
31
|
+
|
|
32
|
+
### Documentation (this feature)
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
specs/002-playground/
|
|
36
|
+
├── plan.md # This file
|
|
37
|
+
├── research.md # Phase 0 output - technology decisions
|
|
38
|
+
├── data-model.md # Phase 1 output - data structures
|
|
39
|
+
├── quickstart.md # Phase 1 output - development guide
|
|
40
|
+
└── tasks.md # Phase 2 output (created by /speckit.tasks)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Source Code (repository root)
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
playground/
|
|
47
|
+
├── src/
|
|
48
|
+
│ ├── components/
|
|
49
|
+
│ │ ├── Header.tsx # Header with title and theme toggle
|
|
50
|
+
│ │ ├── ThemeToggle.tsx # Sun/moon theme switch component
|
|
51
|
+
│ │ ├── JsonEditor.tsx # CodeMirror-based JSON editor
|
|
52
|
+
│ │ ├── Preview.tsx # A2UIRender wrapper with error boundary
|
|
53
|
+
│ │ ├── ExampleSelector.tsx # Dropdown for example selection
|
|
54
|
+
│ │ └── ErrorDisplay.tsx # Error state display component
|
|
55
|
+
│ ├── data/
|
|
56
|
+
│ │ └── examples.ts # Pre-built A2UI message examples
|
|
57
|
+
│ ├── hooks/
|
|
58
|
+
│ │ └── useTheme.ts # Theme state management with localStorage
|
|
59
|
+
│ ├── App.tsx # Main app with split-panel layout
|
|
60
|
+
│ ├── App.css # Layout and theme styles
|
|
61
|
+
│ ├── main.tsx # Entry point
|
|
62
|
+
│ └── index.css # Global styles (Tailwind)
|
|
63
|
+
├── index.html
|
|
64
|
+
├── package.json
|
|
65
|
+
├── vite.config.ts
|
|
66
|
+
└── tsconfig.app.json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Structure Decision**: Single workspace application within the existing monorepo. The playground is a standalone Vite React app that imports the main library as a workspace dependency.
|
|
70
|
+
|
|
71
|
+
## Complexity Tracking
|
|
72
|
+
|
|
73
|
+
No constitution violations to justify.
|