@davincidreams/dynamic-canvas-react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -297
- package/dist/RendererFrame-ri9awAzI.cjs +1 -0
- package/dist/RendererFrame-w1obQvoH.js +25 -0
- package/dist/core/CanvasContainer.d.ts +23 -0
- package/dist/core/CanvasContainer.d.ts.map +1 -0
- package/dist/core/CanvasContext.d.ts +45 -0
- package/dist/core/CanvasContext.d.ts.map +1 -0
- package/dist/core/ComponentRegistry.d.ts +36 -0
- package/dist/core/ComponentRegistry.d.ts.map +1 -0
- package/dist/core/ErrorBoundary.d.ts +18 -0
- package/dist/core/ErrorBoundary.d.ts.map +1 -0
- package/dist/core/RendererResolver.d.ts +14 -0
- package/dist/core/RendererResolver.d.ts.map +1 -0
- package/dist/core/StreamProcessor.d.ts +34 -0
- package/dist/core/StreamProcessor.d.ts.map +1 -0
- package/dist/core/SurfaceManager.d.ts +36 -0
- package/dist/core/SurfaceManager.d.ts.map +1 -0
- package/dist/hooks/useA2UISurface.d.ts +41 -0
- package/dist/hooks/useA2UISurface.d.ts.map +1 -0
- package/dist/hooks/useStreamingContent.d.ts +17 -0
- package/dist/hooks/useStreamingContent.d.ts.map +1 -0
- package/dist/index.cjs +38 -0
- package/dist/index.d.ts +28 -302
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1096 -0
- package/dist/renderers/ArtifactRenderer.d.ts +6 -0
- package/dist/renderers/ArtifactRenderer.d.ts.map +1 -0
- package/dist/renderers/ArtifactRenderer.test.d.ts +2 -0
- package/dist/renderers/ArtifactRenderer.test.d.ts.map +1 -0
- package/dist/renderers/ChartRenderer.d.ts +20 -0
- package/dist/renderers/ChartRenderer.d.ts.map +1 -0
- package/dist/renderers/CodeRenderer.d.ts +16 -0
- package/dist/renderers/CodeRenderer.d.ts.map +1 -0
- package/dist/renderers/CustomRenderer.d.ts +14 -0
- package/dist/renderers/CustomRenderer.d.ts.map +1 -0
- package/dist/renderers/DocumentRenderer.d.ts +15 -0
- package/dist/renderers/DocumentRenderer.d.ts.map +1 -0
- package/dist/renderers/KnowledgeGraphRenderer.d.ts +6 -0
- package/dist/renderers/KnowledgeGraphRenderer.d.ts.map +1 -0
- package/dist/renderers/MapRenderer.d.ts +6 -0
- package/dist/renderers/MapRenderer.d.ts.map +1 -0
- package/dist/renderers/MediaRenderer.d.ts +6 -0
- package/dist/renderers/MediaRenderer.d.ts.map +1 -0
- package/dist/renderers/MediaRenderer.test.d.ts +2 -0
- package/dist/renderers/MediaRenderer.test.d.ts.map +1 -0
- package/dist/renderers/TimelineRenderer.d.ts +16 -0
- package/dist/renderers/TimelineRenderer.d.ts.map +1 -0
- package/dist/renderers/artifact.cjs +2 -0
- package/dist/renderers/artifact.js +35 -0
- package/dist/renderers/chart.cjs +1 -0
- package/dist/renderers/chart.js +121 -0
- package/dist/renderers/code.cjs +2 -0
- package/dist/renderers/code.js +100 -0
- package/dist/renderers/document.cjs +1 -0
- package/dist/renderers/document.js +46 -0
- package/dist/renderers/index.d.ts +15 -0
- package/dist/renderers/index.d.ts.map +1 -0
- package/dist/renderers/knowledge-graph.cjs +1 -0
- package/dist/renderers/knowledge-graph.js +120 -0
- package/dist/renderers/map.cjs +1 -0
- package/dist/renderers/map.js +56 -0
- package/dist/renderers/media.cjs +1 -0
- package/dist/renderers/media.js +71 -0
- package/dist/renderers/shared/LazyWrapper.d.ts +9 -0
- package/dist/renderers/shared/LazyWrapper.d.ts.map +1 -0
- package/dist/renderers/shared/RendererFrame.d.ts +10 -0
- package/dist/renderers/shared/RendererFrame.d.ts.map +1 -0
- package/dist/renderers/timeline.cjs +1 -0
- package/dist/renderers/timeline.js +105 -0
- package/dist/schema/a2ui-envelope.d.ts +60 -0
- package/dist/schema/a2ui-envelope.d.ts.map +1 -0
- package/dist/schema/catalog-definition.d.ts +25 -0
- package/dist/schema/catalog-definition.d.ts.map +1 -0
- package/dist/schema/component-types.d.ts +28 -0
- package/dist/schema/component-types.d.ts.map +1 -0
- package/dist/schema/components/artifact.d.ts +18 -0
- package/dist/schema/components/artifact.d.ts.map +1 -0
- package/dist/schema/components/chart.d.ts +33 -0
- package/dist/schema/components/chart.d.ts.map +1 -0
- package/dist/schema/components/code.d.ts +15 -0
- package/dist/schema/components/code.d.ts.map +1 -0
- package/dist/schema/components/custom.d.ts +13 -0
- package/dist/schema/components/custom.d.ts.map +1 -0
- package/dist/schema/components/document.d.ts +13 -0
- package/dist/schema/components/document.d.ts.map +1 -0
- package/dist/schema/components/knowledge-graph.d.ts +35 -0
- package/dist/schema/components/knowledge-graph.d.ts.map +1 -0
- package/dist/schema/components/map.d.ts +35 -0
- package/dist/schema/components/map.d.ts.map +1 -0
- package/dist/schema/components/media.d.ts +20 -0
- package/dist/schema/components/media.d.ts.map +1 -0
- package/dist/schema/components/timeline.d.ts +28 -0
- package/dist/schema/components/timeline.d.ts.map +1 -0
- package/dist/schema/index.d.ts +12 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/validation.d.ts +15 -0
- package/dist/schema/validation.d.ts.map +1 -0
- package/dist/schema.cjs +1 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +194 -0
- package/dist/themes/darkTheme.d.ts +3 -0
- package/dist/themes/darkTheme.d.ts.map +1 -0
- package/dist/themes/defaultTheme.d.ts +3 -0
- package/dist/themes/defaultTheme.d.ts.map +1 -0
- package/dist/themes/index.d.ts +9 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/lightTheme.d.ts +3 -0
- package/dist/themes/lightTheme.d.ts.map +1 -0
- package/dist/themes/types.d.ts +8 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +164 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/contentAnalyzer.d.ts +46 -0
- package/dist/utils/contentAnalyzer.d.ts.map +1 -0
- package/dist/utils/jsonPointer.d.ts +15 -0
- package/dist/utils/jsonPointer.d.ts.map +1 -0
- package/dist/utils/streaming.d.ts +10 -0
- package/dist/utils/streaming.d.ts.map +1 -0
- package/package.json +97 -15
- package/dist/dynamic-canvas.cjs.js +0 -65
- package/dist/dynamic-canvas.es.js +0 -966
- package/dist/dynamic-canvas.umd.js +0 -65
package/README.md
CHANGED
|
@@ -1,399 +1,363 @@
|
|
|
1
|
-
# @dynamic-canvas
|
|
1
|
+
# @davincidreams/dynamic-canvas-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A2UI-native dynamic canvas component for React. Renders streaming, agent-driven visuals from any A2UI-speaking source — LangChain agents, 3dchat, Microsoft Agent Framework (Orleans), or direct JSON.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
7
|
+
- **A2UI Protocol**: Native support for the Agent-to-UI message protocol (createSurface, updateDataModel, updateComponents, etc.)
|
|
8
|
+
- **9 Renderers**: Chart, Timeline, KnowledgeGraph, Map, Media, Document, Code, Artifact, Custom
|
|
9
|
+
- **Streaming**: JSONL, SSE, WebSocket, and direct message ingestion with batched updates
|
|
10
|
+
- **Lazy Loading**: Heavy renderers (D3, Cesium, shiki) loaded on demand with SVG fallbacks
|
|
11
|
+
- **Schema-Only Export**: Zero-React-dependency `./schema` entry point for server-side / non-JS consumers
|
|
12
|
+
- **Multi-Entry Build**: Tree-shake individual renderers via `./renderers/chart`, `./renderers/map`, etc.
|
|
13
|
+
- **Theme System**: Built-in light/dark themes with full customization
|
|
14
|
+
- **Type Safe**: Full TypeScript support with discriminated union component types
|
|
15
|
+
- **Backward Compatible**: Legacy `CanvasProvider`, `useCanvas`, `useCanvasContent` hooks still work
|
|
13
16
|
|
|
14
17
|
## Installation
|
|
15
18
|
|
|
16
19
|
```bash
|
|
17
|
-
npm install @dynamic-canvas
|
|
18
|
-
# or
|
|
19
|
-
yarn add @dynamic-canvas/react
|
|
20
|
-
# or
|
|
21
|
-
pnpm add @dynamic-canvas/react
|
|
20
|
+
npm install @davincidreams/dynamic-canvas-react
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
### Optional Peer Dependencies
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
import { CanvasProvider, useCanvas, themes } from '@dynamic-canvas/react';
|
|
25
|
+
Install only the renderers you need:
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
```bash
|
|
28
|
+
# Charts (D3)
|
|
29
|
+
npm install d3
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
}
|
|
31
|
+
# Documents (Markdown)
|
|
32
|
+
npm install react-markdown remark-gfm
|
|
33
|
+
|
|
34
|
+
# Code (syntax highlighting)
|
|
35
|
+
npm install shiki
|
|
36
|
+
|
|
37
|
+
# Knowledge Graph (force-directed)
|
|
38
|
+
npm install react-force-graph-2d
|
|
39
|
+
# or for 3D:
|
|
40
|
+
npm install react-force-graph-3d
|
|
41
|
+
|
|
42
|
+
# Map (Cesium globe)
|
|
43
|
+
npm install @cesium/engine resium
|
|
47
44
|
```
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
All renderers include built-in SVG/HTML fallbacks when their optional deps are not installed.
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### A2UI Messages (recommended)
|
|
51
|
+
|
|
52
|
+
Feed A2UI JSON messages from your AI agent and the canvas renders automatically:
|
|
52
53
|
|
|
53
54
|
```tsx
|
|
54
|
-
import {
|
|
55
|
+
import { useA2UISurface, RendererResolver } from '@davincidreams/dynamic-canvas-react';
|
|
55
56
|
|
|
56
|
-
function
|
|
57
|
-
const {
|
|
57
|
+
function AgentCanvas() {
|
|
58
|
+
const { activeSurface, getComponents, resolveData, store } = useA2UISurface({
|
|
59
|
+
sseUrl: '/api/agent/stream',
|
|
60
|
+
});
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
const analyzed = ContentAnalyzer.analyze(response);
|
|
61
|
-
setContent(analyzed);
|
|
62
|
-
};
|
|
62
|
+
if (!activeSurface) return <div>Waiting for agent...</div>;
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
</div>
|
|
76
|
-
</CanvasProvider>
|
|
65
|
+
<div>
|
|
66
|
+
{getComponents(activeSurface.id).map((component) => (
|
|
67
|
+
<RendererResolver
|
|
68
|
+
key={component.id}
|
|
69
|
+
component={component}
|
|
70
|
+
data={resolveData(activeSurface.id, '/')}
|
|
71
|
+
theme="dark"
|
|
72
|
+
/>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
77
75
|
);
|
|
78
76
|
}
|
|
79
77
|
```
|
|
80
78
|
|
|
81
|
-
###
|
|
79
|
+
### Direct Messages
|
|
80
|
+
|
|
81
|
+
Process A2UI messages directly without a stream:
|
|
82
82
|
|
|
83
83
|
```tsx
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
import { useA2UISurface } from '@davincidreams/dynamic-canvas-react';
|
|
85
|
+
|
|
86
|
+
const messages = [
|
|
87
|
+
{ createSurface: { surfaceId: 's1' } },
|
|
88
|
+
{
|
|
89
|
+
updateDataModel: {
|
|
90
|
+
surfaceId: 's1',
|
|
91
|
+
path: '/chart',
|
|
92
|
+
value: { labels: ['Jan', 'Feb', 'Mar'], values: [10, 25, 18] },
|
|
93
|
+
},
|
|
90
94
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
{
|
|
96
|
+
updateComponents: {
|
|
97
|
+
surfaceId: 's1',
|
|
98
|
+
components: [
|
|
99
|
+
{
|
|
100
|
+
id: 'c1',
|
|
101
|
+
component: 'Chart',
|
|
102
|
+
chartType: 'bar',
|
|
103
|
+
data: '/chart',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
];
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
function App() {
|
|
111
|
+
const { activeSurface, getComponents } = useA2UISurface({ messages });
|
|
112
|
+
// ...render components
|
|
113
|
+
}
|
|
97
114
|
```
|
|
98
115
|
|
|
99
|
-
###
|
|
116
|
+
### WebSocket / Fetch Stream
|
|
100
117
|
|
|
101
118
|
```tsx
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
{
|
|
111
|
-
date: '2024-02-01',
|
|
112
|
-
title: 'Development Phase',
|
|
113
|
-
description: 'Core features implementation'
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
};
|
|
119
|
+
// WebSocket
|
|
120
|
+
const result = useA2UISurface({ wsUrl: 'wss://agent.example.com/stream' });
|
|
121
|
+
|
|
122
|
+
// Fetch (JSONL body)
|
|
123
|
+
const result = useA2UISurface({
|
|
124
|
+
streamUrl: '/api/agent/generate',
|
|
125
|
+
streamInit: { method: 'POST', body: JSON.stringify({ prompt: '...' }) },
|
|
126
|
+
});
|
|
117
127
|
```
|
|
118
128
|
|
|
119
|
-
###
|
|
129
|
+
### Legacy API
|
|
120
130
|
|
|
121
|
-
|
|
122
|
-
const codeContent = {
|
|
123
|
-
type: 'code',
|
|
124
|
-
code: 'console.log("Hello, World!");',
|
|
125
|
-
language: 'javascript',
|
|
126
|
-
filename: 'app.js'
|
|
127
|
-
};
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Document Content
|
|
131
|
+
The original `CanvasProvider` / `useCanvas` API still works:
|
|
131
132
|
|
|
132
133
|
```tsx
|
|
133
|
-
|
|
134
|
-
type: 'document',
|
|
135
|
-
content: '# Welcome\n\nThis is a document rendered in the canvas.',
|
|
136
|
-
format: 'markdown'
|
|
137
|
-
};
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## API Reference
|
|
141
|
-
|
|
142
|
-
### CanvasProvider
|
|
134
|
+
import { CanvasProvider, useCanvas, themes } from '@davincidreams/dynamic-canvas-react';
|
|
143
135
|
|
|
144
|
-
|
|
136
|
+
function App() {
|
|
137
|
+
return (
|
|
138
|
+
<CanvasProvider initialTheme={themes.dark}>
|
|
139
|
+
<MyApp />
|
|
140
|
+
</CanvasProvider>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
initialContent={initialContent}
|
|
151
|
-
>
|
|
152
|
-
{children}
|
|
153
|
-
</CanvasProvider>
|
|
144
|
+
function MyApp() {
|
|
145
|
+
const { content, setContent } = useCanvas();
|
|
146
|
+
// ...
|
|
147
|
+
}
|
|
154
148
|
```
|
|
155
149
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
150
|
+
## A2UI Protocol
|
|
151
|
+
|
|
152
|
+
The library speaks the A2UI (Agent-to-UI) protocol. Agents send JSON messages to create surfaces, populate data models, and attach components:
|
|
153
|
+
|
|
154
|
+
### Envelope Messages
|
|
155
|
+
|
|
156
|
+
| Message | Description |
|
|
157
|
+
|---------|-------------|
|
|
158
|
+
| `createSurface` | Create a new UI surface (canvas) |
|
|
159
|
+
| `destroySurface` | Remove a surface |
|
|
160
|
+
| `updateDataModel` | Set data at a JSON Pointer path |
|
|
161
|
+
| `updateComponents` | Set or replace components on a surface |
|
|
162
|
+
| `removeComponents` | Remove components by ID |
|
|
163
|
+
| `appendData` | Append items to an array (streaming convenience) |
|
|
164
|
+
| `patchDataModel` | JSON merge-patch the data model |
|
|
165
|
+
|
|
166
|
+
### Component Types
|
|
167
|
+
|
|
168
|
+
| Component | Description | Optional Dep |
|
|
169
|
+
|-----------|-------------|-------------|
|
|
170
|
+
| `Chart` | Bar, line, scatter, pie, area, donut charts | `d3` |
|
|
171
|
+
| `Timeline` | Events with alternating/grouped layouts | — |
|
|
172
|
+
| `KnowledgeGraph` | Force-directed node-edge graph | `react-force-graph-2d` |
|
|
173
|
+
| `Map` | Globe with markers | `@cesium/engine` + `resium` |
|
|
174
|
+
| `Media` | Image, video, audio | — |
|
|
175
|
+
| `Document` | Markdown/HTML documents | `react-markdown` |
|
|
176
|
+
| `Code` | Syntax-highlighted code blocks | `shiki` |
|
|
177
|
+
| `Artifact` | Sandboxed iframe (HTML/CSS/JS) | — |
|
|
178
|
+
| `Custom` | Registry-key based escape hatch | — |
|
|
179
|
+
|
|
180
|
+
### Example: Streaming a Chart
|
|
181
|
+
|
|
182
|
+
```jsonl
|
|
183
|
+
{"createSurface":{"surfaceId":"s1","title":"Sales Dashboard"}}
|
|
184
|
+
{"updateDataModel":{"surfaceId":"s1","path":"/sales","value":{"labels":["Q1","Q2","Q3","Q4"],"values":[120,340,250,410]}}}
|
|
185
|
+
{"updateComponents":{"surfaceId":"s1","components":[{"id":"chart1","component":"Chart","chartType":"bar","data":"/sales","title":"Quarterly Sales"}]}}
|
|
186
|
+
```
|
|
162
187
|
|
|
163
|
-
|
|
188
|
+
### Example: Streaming a Timeline
|
|
164
189
|
|
|
165
|
-
```
|
|
166
|
-
|
|
190
|
+
```jsonl
|
|
191
|
+
{"createSurface":{"surfaceId":"s1"}}
|
|
192
|
+
{"updateDataModel":{"surfaceId":"s1","path":"/events","value":[{"date":"2024-01-15","title":"Project Started","description":"Kickoff meeting"},{"date":"2024-06-01","title":"v1.0 Release","description":"First public release"}]}}
|
|
193
|
+
{"updateComponents":{"surfaceId":"s1","components":[{"id":"t1","component":"Timeline","events":"/events","layout":"alternating"}]}}
|
|
167
194
|
```
|
|
168
195
|
|
|
169
|
-
|
|
170
|
-
- `content`: Current canvas content
|
|
171
|
-
- `setContent`: Function to set content
|
|
172
|
-
- `theme`: Current theme
|
|
173
|
-
- `setTheme`: Function to set theme
|
|
196
|
+
## Schema-Only Import
|
|
174
197
|
|
|
175
|
-
|
|
198
|
+
For server-side validation or non-React consumers (Python, C#, etc.), import types and validation without React:
|
|
176
199
|
|
|
177
|
-
|
|
200
|
+
```ts
|
|
201
|
+
import {
|
|
202
|
+
validateMessage,
|
|
203
|
+
validateComponent,
|
|
204
|
+
isA2UIMessage,
|
|
205
|
+
DYNAMIC_CANVAS_CATALOG,
|
|
206
|
+
type A2UIMessage,
|
|
207
|
+
type A2UIComponent,
|
|
208
|
+
} from '@davincidreams/dynamic-canvas-react/schema';
|
|
178
209
|
|
|
179
|
-
|
|
180
|
-
const
|
|
210
|
+
const msg = { createSurface: { surfaceId: 's1' } };
|
|
211
|
+
const result = validateMessage(msg);
|
|
212
|
+
// { valid: true, messageType: 'createSurface' }
|
|
181
213
|
```
|
|
182
214
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
Hook for layout management.
|
|
215
|
+
## API Reference
|
|
186
216
|
|
|
187
|
-
|
|
188
|
-
const { layout, widthRatio, setLayout, setWidthRatio } = useCanvasLayout();
|
|
189
|
-
```
|
|
217
|
+
### Hooks
|
|
190
218
|
|
|
191
|
-
|
|
219
|
+
#### `useA2UISurface(options?)`
|
|
192
220
|
|
|
193
|
-
|
|
221
|
+
Primary hook — connects to a stream and manages surfaces.
|
|
194
222
|
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
223
|
+
```ts
|
|
224
|
+
interface UseA2UISurfaceOptions {
|
|
225
|
+
sseUrl?: string; // SSE endpoint
|
|
226
|
+
wsUrl?: string; // WebSocket endpoint
|
|
227
|
+
streamUrl?: string; // Fetch stream URL
|
|
228
|
+
streamInit?: RequestInit; // Fetch init options
|
|
229
|
+
messages?: A2UIMessage[]; // Direct messages
|
|
230
|
+
batchWindow?: number; // Batch window in ms (default: 50)
|
|
231
|
+
onError?: (error: Error) => void;
|
|
232
|
+
store?: StoreApi<SurfaceManagerStore>; // Shared store
|
|
233
|
+
}
|
|
200
234
|
```
|
|
201
235
|
|
|
202
|
-
|
|
236
|
+
Returns: `surfaces`, `activeSurface`, `setActiveSurface`, `processMessage`, `processMessages`, `resolveData`, `getComponents`, `store`
|
|
203
237
|
|
|
204
|
-
|
|
205
|
-
<TimelineRenderer
|
|
206
|
-
content={timelineContent}
|
|
207
|
-
theme={themes.dark}
|
|
208
|
-
/>
|
|
209
|
-
```
|
|
238
|
+
#### `useStreamingContent(options)`
|
|
210
239
|
|
|
211
|
-
|
|
240
|
+
Subscribe to a single surface's streaming updates.
|
|
212
241
|
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
242
|
+
```ts
|
|
243
|
+
const { surface, components, dataModel, resolveData, updatedAt } = useStreamingContent({
|
|
244
|
+
store, // from useA2UISurface
|
|
245
|
+
surfaceId, // surface to watch
|
|
246
|
+
});
|
|
218
247
|
```
|
|
219
248
|
|
|
220
|
-
|
|
249
|
+
### Individual Renderer Imports
|
|
221
250
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
251
|
+
Tree-shake by importing only what you need:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import ChartRenderer from '@davincidreams/dynamic-canvas-react/renderers/chart';
|
|
255
|
+
import TimelineRenderer from '@davincidreams/dynamic-canvas-react/renderers/timeline';
|
|
256
|
+
import KnowledgeGraphRenderer from '@davincidreams/dynamic-canvas-react/renderers/knowledge-graph';
|
|
257
|
+
import MapRenderer from '@davincidreams/dynamic-canvas-react/renderers/map';
|
|
258
|
+
import MediaRenderer from '@davincidreams/dynamic-canvas-react/renderers/media';
|
|
259
|
+
import DocumentRenderer from '@davincidreams/dynamic-canvas-react/renderers/document';
|
|
260
|
+
import CodeRenderer from '@davincidreams/dynamic-canvas-react/renderers/code';
|
|
261
|
+
import ArtifactRenderer from '@davincidreams/dynamic-canvas-react/renderers/artifact';
|
|
227
262
|
```
|
|
228
263
|
|
|
229
|
-
|
|
264
|
+
### Content Analyzer
|
|
230
265
|
|
|
231
|
-
|
|
232
|
-
const CustomComponent = ({ data }) => <div>{data}</div>;
|
|
266
|
+
Auto-detect content type from raw text and convert to A2UI messages:
|
|
233
267
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
component: CustomComponent,
|
|
237
|
-
props: { data: 'Hello' }
|
|
238
|
-
};
|
|
268
|
+
```ts
|
|
269
|
+
import { ContentAnalyzer } from '@davincidreams/dynamic-canvas-react';
|
|
239
270
|
|
|
240
|
-
|
|
271
|
+
// Detect content type
|
|
272
|
+
ContentAnalyzer.detectType('```js\nconsole.log("hi")\n```'); // 'code'
|
|
273
|
+
ContentAnalyzer.detectType('# Hello World'); // 'document'
|
|
274
|
+
ContentAnalyzer.detectType('2024-01-01 Project Start'); // 'timeline'
|
|
275
|
+
|
|
276
|
+
// Convert to A2UI messages
|
|
277
|
+
const messages = ContentAnalyzer.toA2UIMessages('```python\nprint("hello")\n```');
|
|
278
|
+
// Returns: [createSurface, updateComponents with Code component]
|
|
241
279
|
```
|
|
242
280
|
|
|
243
281
|
## Theming
|
|
244
282
|
|
|
245
|
-
### Default Themes
|
|
246
|
-
|
|
247
283
|
```tsx
|
|
248
|
-
import { themes } from '@dynamic-canvas
|
|
249
|
-
|
|
250
|
-
// Use built-in themes
|
|
251
|
-
<CanvasProvider theme={themes.light}>
|
|
252
|
-
{/* Light theme */}
|
|
253
|
-
</CanvasProvider>
|
|
284
|
+
import { themes } from '@davincidreams/dynamic-canvas-react';
|
|
254
285
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
### Custom Theme
|
|
286
|
+
// Built-in themes
|
|
287
|
+
themes.light
|
|
288
|
+
themes.dark
|
|
289
|
+
themes.default
|
|
261
290
|
|
|
262
|
-
|
|
263
|
-
const
|
|
291
|
+
// Custom theme
|
|
292
|
+
const myTheme = {
|
|
264
293
|
colors: {
|
|
265
|
-
background: '#
|
|
266
|
-
surface: '#
|
|
294
|
+
background: '#0a0a0a',
|
|
295
|
+
surface: '#1a1a2e',
|
|
267
296
|
primary: '#0ea5e9',
|
|
268
297
|
secondary: '#6366f1',
|
|
269
|
-
text: '#
|
|
298
|
+
text: '#e2e8f0',
|
|
270
299
|
muted: '#64748b',
|
|
271
|
-
border: '#
|
|
272
|
-
highlight: '#
|
|
300
|
+
border: '#334155',
|
|
301
|
+
highlight: '#1e293b',
|
|
273
302
|
},
|
|
274
|
-
spacing
|
|
275
|
-
xs: '4px',
|
|
276
|
-
sm: '8px',
|
|
277
|
-
md: '16px',
|
|
278
|
-
lg: '24px',
|
|
279
|
-
xl: '32px'
|
|
280
|
-
},
|
|
281
|
-
typography: {
|
|
282
|
-
font: 'Inter, sans-serif',
|
|
283
|
-
sizes: {
|
|
284
|
-
xs: '12px',
|
|
285
|
-
sm: '14px',
|
|
286
|
-
md: '16px',
|
|
287
|
-
lg: '18px',
|
|
288
|
-
xl: '20px'
|
|
289
|
-
},
|
|
290
|
-
weights: {
|
|
291
|
-
normal: 400,
|
|
292
|
-
medium: 500,
|
|
293
|
-
bold: 700
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
borderRadius: {
|
|
297
|
-
sm: '4px',
|
|
298
|
-
md: '8px',
|
|
299
|
-
lg: '12px',
|
|
300
|
-
xl: '16px'
|
|
301
|
-
},
|
|
302
|
-
shadows: {
|
|
303
|
-
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
304
|
-
md: '0 4px 6px rgba(0,0,0,0.1)',
|
|
305
|
-
lg: '0 10px 15px rgba(0,0,0,0.1)'
|
|
306
|
-
}
|
|
303
|
+
// ...spacing, typography, borderRadius, shadows
|
|
307
304
|
};
|
|
308
|
-
|
|
309
|
-
<CanvasProvider theme={customTheme}>
|
|
310
|
-
{/* Custom theme */}
|
|
311
|
-
</CanvasProvider>
|
|
312
305
|
```
|
|
313
306
|
|
|
314
|
-
##
|
|
307
|
+
## Custom Renderers
|
|
315
308
|
|
|
316
|
-
|
|
309
|
+
Register custom renderers by key:
|
|
317
310
|
|
|
318
311
|
```tsx
|
|
319
|
-
import {
|
|
312
|
+
import { ComponentRegistry } from '@davincidreams/dynamic-canvas-react';
|
|
320
313
|
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
// Returns: { type: 'chart', data: { labels: ['50', '25'], values: [] } }
|
|
324
|
-
```
|
|
314
|
+
const registry = new ComponentRegistry();
|
|
315
|
+
registry.register('MyWidget', () => import('./MyWidget'));
|
|
325
316
|
|
|
326
|
-
|
|
317
|
+
// Then in A2UI messages:
|
|
318
|
+
{
|
|
319
|
+
updateComponents: {
|
|
320
|
+
surfaceId: 's1',
|
|
321
|
+
components: [{ id: 'w1', component: 'Custom', rendererKey: 'MyWidget', props: { foo: 'bar' } }]
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
327
325
|
|
|
328
|
-
|
|
329
|
-
|------|-------------|----------|
|
|
330
|
-
| `chart` | Data visualizations | `ChartRenderer` |
|
|
331
|
-
| `timeline` | Timeline events | `TimelineRenderer` |
|
|
332
|
-
| `code` | Code snippets | `CodeRenderer` |
|
|
333
|
-
| `document` | Documents | `DocumentRenderer` |
|
|
334
|
-
| `custom` | Custom components | `CustomRenderer` |
|
|
326
|
+
## Architecture
|
|
335
327
|
|
|
336
|
-
|
|
328
|
+
```
|
|
329
|
+
AI Agent → A2UI JSON → StreamProcessor → SurfaceManager → RendererResolver → React Renderers
|
|
330
|
+
(JSONL/SSE/WS) (zustand store) (Suspense + ErrorBoundary)
|
|
331
|
+
↓
|
|
332
|
+
Chart | Timeline | Graph | Map | Media | Doc | Code | Artifact | Custom
|
|
333
|
+
```
|
|
337
334
|
|
|
338
|
-
**
|
|
339
|
-
-
|
|
340
|
-
-
|
|
341
|
-
-
|
|
342
|
-
- `lucide-react`: ^0.400.0
|
|
343
|
-
- `zustand`: ^5.0.0
|
|
335
|
+
- **StreamProcessor**: Parses JSONL, SSE, WebSocket, or direct JSON arrays
|
|
336
|
+
- **SurfaceManager**: Zustand store managing surfaces, data models, and components
|
|
337
|
+
- **RendererResolver**: Suspense + ErrorBoundary wrapper for lazy-loaded renderers
|
|
338
|
+
- **ComponentRegistry**: Maps component type strings to React renderer factories
|
|
344
339
|
|
|
345
|
-
|
|
346
|
-
- `d3`: ^7.9.0 (for enhanced charts)
|
|
347
|
-
- `react-syntax-highlighter`: ^15.5.0 (for code highlighting)
|
|
348
|
-
- `react-pdf`: ^7.7.0 (for PDF rendering)
|
|
349
|
-
- `markdown-it`: ^14.0.0 (for markdown rendering)
|
|
340
|
+
## Bundle Size
|
|
350
341
|
|
|
351
|
-
|
|
342
|
+
| Entry | Gzip |
|
|
343
|
+
|-------|------|
|
|
344
|
+
| Schema only (`./schema`) | ~2 KB |
|
|
345
|
+
| Core + all renderers (`.`) | ~8 KB |
|
|
346
|
+
| Individual renderers | 0.4–2.5 KB each |
|
|
352
347
|
|
|
353
|
-
|
|
348
|
+
Heavy dependencies (D3, Cesium, shiki) are loaded on demand when a component requires them.
|
|
354
349
|
|
|
355
|
-
|
|
356
|
-
// src/renderers/VideoRenderer.tsx
|
|
357
|
-
import React from 'react';
|
|
358
|
-
import type { Theme } from '../types';
|
|
350
|
+
## Development
|
|
359
351
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
<div style={{ color: theme.colors.text }}>
|
|
368
|
-
<video src={content.url} controls />
|
|
369
|
-
</div>
|
|
370
|
-
);
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
// Export and register
|
|
374
|
-
export { VideoRenderer };
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Adding a New Theme
|
|
378
|
-
|
|
379
|
-
```tsx
|
|
380
|
-
// src/themes/customTheme.ts
|
|
381
|
-
import type { Theme } from '../types';
|
|
382
|
-
import { defaultTheme } from './defaultTheme';
|
|
383
|
-
|
|
384
|
-
export const customTheme: Theme = {
|
|
385
|
-
...defaultTheme,
|
|
386
|
-
colors: {
|
|
387
|
-
...defaultTheme.colors,
|
|
388
|
-
primary: '#ff6b6b'
|
|
389
|
-
}
|
|
390
|
-
};
|
|
352
|
+
```bash
|
|
353
|
+
npm install
|
|
354
|
+
npm run dev # Start Vite dev server
|
|
355
|
+
npm run build # Build library (ES + CJS)
|
|
356
|
+
npm run type-check # TypeScript check
|
|
357
|
+
npm test # Run tests (124 tests)
|
|
358
|
+
npm run test:watch # Watch mode
|
|
391
359
|
```
|
|
392
360
|
|
|
393
361
|
## License
|
|
394
362
|
|
|
395
363
|
MIT
|
|
396
|
-
|
|
397
|
-
## Contributing
|
|
398
|
-
|
|
399
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=require("react/jsx-runtime"),n=({title:d,children:s,actions:r,style:i})=>e.jsxs("div",{style:{borderRadius:"8px",overflow:"hidden",border:"1px solid rgba(128,128,128,0.2)",...i},children:[(d||r)&&e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 12px",borderBottom:"1px solid rgba(128,128,128,0.2)",fontSize:"13px",fontWeight:500,background:"rgba(128,128,128,0.05)"},children:[e.jsx("span",{children:d}),r&&e.jsx("div",{style:{display:"flex",gap:"4px"},children:r})]}),e.jsx("div",{children:s})]});exports.RendererFrame=n;
|