freesail 0.0.1 → 0.1.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 (54) hide show
  1. package/README.md +190 -5
  2. package/docs/A2UX_Protocol.md +183 -0
  3. package/docs/Agents.md +218 -0
  4. package/docs/Architecture.md +285 -0
  5. package/docs/CatalogReference.md +377 -0
  6. package/docs/GettingStarted.md +230 -0
  7. package/examples/demo/package.json +21 -0
  8. package/examples/demo/public/index.html +381 -0
  9. package/examples/demo/server.js +253 -0
  10. package/package.json +38 -5
  11. package/packages/core/package.json +48 -0
  12. package/packages/core/src/functions.ts +403 -0
  13. package/packages/core/src/index.ts +214 -0
  14. package/packages/core/src/parser.ts +270 -0
  15. package/packages/core/src/protocol.ts +254 -0
  16. package/packages/core/src/store.ts +452 -0
  17. package/packages/core/src/transport.ts +439 -0
  18. package/packages/core/src/types.ts +209 -0
  19. package/packages/core/tsconfig.json +10 -0
  20. package/packages/lit-ui/package.json +44 -0
  21. package/packages/lit-ui/src/catalogs/standard/catalog.json +405 -0
  22. package/packages/lit-ui/src/catalogs/standard/elements/Badge.ts +96 -0
  23. package/packages/lit-ui/src/catalogs/standard/elements/Button.ts +147 -0
  24. package/packages/lit-ui/src/catalogs/standard/elements/Card.ts +78 -0
  25. package/packages/lit-ui/src/catalogs/standard/elements/Checkbox.ts +94 -0
  26. package/packages/lit-ui/src/catalogs/standard/elements/Column.ts +66 -0
  27. package/packages/lit-ui/src/catalogs/standard/elements/Divider.ts +59 -0
  28. package/packages/lit-ui/src/catalogs/standard/elements/Image.ts +54 -0
  29. package/packages/lit-ui/src/catalogs/standard/elements/Input.ts +125 -0
  30. package/packages/lit-ui/src/catalogs/standard/elements/Progress.ts +79 -0
  31. package/packages/lit-ui/src/catalogs/standard/elements/Row.ts +68 -0
  32. package/packages/lit-ui/src/catalogs/standard/elements/Select.ts +110 -0
  33. package/packages/lit-ui/src/catalogs/standard/elements/Spacer.ts +37 -0
  34. package/packages/lit-ui/src/catalogs/standard/elements/Spinner.ts +76 -0
  35. package/packages/lit-ui/src/catalogs/standard/elements/Text.ts +86 -0
  36. package/packages/lit-ui/src/catalogs/standard/elements/index.ts +18 -0
  37. package/packages/lit-ui/src/catalogs/standard/index.ts +17 -0
  38. package/packages/lit-ui/src/index.ts +84 -0
  39. package/packages/lit-ui/src/renderer.ts +211 -0
  40. package/packages/lit-ui/src/types.ts +49 -0
  41. package/packages/lit-ui/src/utils/define-props.ts +157 -0
  42. package/packages/lit-ui/src/utils/index.ts +2 -0
  43. package/packages/lit-ui/src/utils/registry.ts +139 -0
  44. package/packages/lit-ui/tsconfig.json +11 -0
  45. package/packages/server/package.json +61 -0
  46. package/packages/server/src/adapters/index.ts +5 -0
  47. package/packages/server/src/adapters/langchain.ts +175 -0
  48. package/packages/server/src/adapters/openai.ts +209 -0
  49. package/packages/server/src/catalog-loader.ts +311 -0
  50. package/packages/server/src/index.ts +142 -0
  51. package/packages/server/src/stream.ts +329 -0
  52. package/packages/server/tsconfig.json +11 -0
  53. package/tsconfig.base.json +23 -0
  54. package/index.js +0 -3
@@ -0,0 +1,285 @@
1
+ # Freesail Architecture
2
+
3
+ This document describes the architectural design of Freesail, its core principles, and how the components work together.
4
+
5
+ ## Overview
6
+
7
+ Freesail follows a **Schema-Driven, Transport-Agnostic** architecture that separates concerns across three main layers:
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────────┐
11
+ │ AI Agent Layer │
12
+ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
13
+ │ │ LangChain │ │ LlamaIndex│ │ OpenAI │ │ Custom │ │
14
+ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
15
+ │ │ │ │ │ │
16
+ │ └──────────────┴──────────────┴──────────────┘ │
17
+ │ │ │
18
+ │ ┌─────────▼─────────┐ │
19
+ │ │ Adapter Layer │ │
20
+ │ │ (Tool Conversion) │ │
21
+ │ └─────────┬─────────┘ │
22
+ └──────────────────────────────┼──────────────────────────────────┘
23
+
24
+ ┌──────────────────────────────┼──────────────────────────────────┐
25
+ │ Protocol Layer │
26
+ │ ┌─────────▼─────────┐ │
27
+ │ │ A2UX Protocol │ │
28
+ │ │ (JSON Schema) │ │
29
+ │ └─────────┬─────────┘ │
30
+ └──────────────────────────────┼──────────────────────────────────┘
31
+
32
+ ┌──────────────────────────────┼──────────────────────────────────┐
33
+ │ Transport Layer │
34
+ │ ┌─────────▼─────────┐ │
35
+ │ │ SSE Stream │ │
36
+ │ │ (HTTP/2, retry) │ │
37
+ │ └─────────┬─────────┘ │
38
+ └──────────────────────────────┼──────────────────────────────────┘
39
+
40
+ ┌──────────────────────────────┼──────────────────────────────────┐
41
+ │ Client Layer │
42
+ │ ┌─────────▼─────────┐ │
43
+ │ │ Surface Store │ │
44
+ │ │ (State Manager) │ │
45
+ │ └─────────┬─────────┘ │
46
+ │ ┌─────────────────────┼─────────────────────┐ │
47
+ │ │ │ │ │
48
+ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │
49
+ │ │ React │ │ Lit │ │ Angular │ │
50
+ │ │ Adapter │ │ (Web) │ │ Adapter │ │
51
+ │ └───────────┘ └───────────┘ └───────────┘ │
52
+ └─────────────────────────────────────────────────────────────────┘
53
+ ```
54
+
55
+ ## Core Principles
56
+
57
+ ### 1. The Contract is the Code
58
+
59
+ The JSON Schema catalog is the **single source of truth** for:
60
+ - Component properties and types
61
+ - LLM tool definitions
62
+ - UI property validation
63
+
64
+ ```typescript
65
+ // BAD: Duplicating property definitions
66
+ class MyButton extends LitElement {
67
+ @property({ type: String }) label = 'Click'; // Duplicates schema
68
+ }
69
+
70
+ // GOOD: Deriving from catalog
71
+ class MyButton extends LitElement {
72
+ static properties = defineProps(catalog, 'Button'); // Single source
73
+ }
74
+ ```
75
+
76
+ ### 2. Orchestrator Agnosticism
77
+
78
+ Core logic never imports framework-specific code. Framework integration happens through **Adapters**:
79
+
80
+ ```
81
+ @freesail/server/src/
82
+ ├── catalog-loader.ts # Framework-agnostic tool generation
83
+ └── adapters/
84
+ ├── langchain.ts # LangChain DynamicStructuredTool
85
+ ├── openai.ts # OpenAI Function Calling
86
+ └── llamaindex.ts # LlamaIndex FunctionTool
87
+ ```
88
+
89
+ ### 3. Stateless Agent Communication
90
+
91
+ The agent is stateless. Every user action includes the **full context**:
92
+
93
+ ```json
94
+ {
95
+ "userAction": {
96
+ "surfaceId": "form_123",
97
+ "action": "submit",
98
+ "context": {
99
+ "user": { "name": "John", "email": "john@example.com" },
100
+ "form": { "valid": true, "touched": ["name", "email"] }
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### 4. Schema-First Components
107
+
108
+ UI components hydrate their properties directly from the catalog:
109
+
110
+ ```
111
+ /catalogs/standard/
112
+ ├── catalog.json # Component definitions
113
+ └── elements/
114
+ ├── Text.ts # Uses defineProps(catalog, 'Text')
115
+ └── Button.ts # Uses defineProps(catalog, 'Button')
116
+ ```
117
+
118
+ ## Package Architecture
119
+
120
+ ### @freesail/core
121
+
122
+ The "brain" of the SDK - handles protocol, transport, and state.
123
+
124
+ ```
125
+ src/
126
+ ├── types.ts # A2UX Protocol TypeScript definitions
127
+ ├── protocol.ts # Message processor and dispatcher
128
+ ├── parser.ts # JSON/SSE stream parsing
129
+ ├── transport.ts # SSE connection with retry/queue
130
+ ├── store.ts # Reactive surface state management
131
+ ├── functions.ts # Standard functions (formatCurrency, etc.)
132
+ └── index.ts # Public API exports
133
+ ```
134
+
135
+ **Key Classes:**
136
+ - `FreesailClient` - Main client entry point
137
+ - `A2UXProtocolHandler` - Message routing
138
+ - `FreesailTransport` - Connection management
139
+ - `SurfaceStore` - State container
140
+
141
+ ### @freesail/lit-ui
142
+
143
+ Web Components implementation using Lit.
144
+
145
+ ```
146
+ src/
147
+ ├── types.ts # Catalog type definitions
148
+ ├── renderer.ts # Dynamic DOM renderer
149
+ ├── utils/
150
+ │ ├── define-props.ts # Catalog → Lit properties
151
+ │ └── registry.ts # Component registration
152
+ └── catalogs/
153
+ └── standard/
154
+ ├── catalog.json # A2UI Standard definitions
155
+ └── elements/ # Lit implementations
156
+ ├── Text.ts
157
+ ├── Button.ts
158
+ └── ...
159
+ ```
160
+
161
+ **Key Functions:**
162
+ - `defineProps()` - Generate Lit properties from catalog
163
+ - `registerStandardCatalog()` - Register all standard components
164
+ - `createSurfaceRenderer()` - Create reactive renderer
165
+
166
+ ### @freesail/server
167
+
168
+ Server-side SSE streaming and framework adapters.
169
+
170
+ ```
171
+ src/
172
+ ├── stream.ts # SSE connection handler
173
+ ├── catalog-loader.ts # Catalog → Tool converter
174
+ └── adapters/
175
+ ├── langchain.ts # LangChain integration
176
+ ├── openai.ts # OpenAI integration
177
+ └── index.ts # Adapter exports
178
+ ```
179
+
180
+ **Key Classes:**
181
+ - `FreesailStream` - SSE message writer
182
+ - `CatalogToToolConverter` - Schema → LLM tools
183
+ - `OpenAIAdapter` - OpenAI tool handling
184
+
185
+ ## Data Flow
186
+
187
+ ### 1. Agent → UI (Downstream)
188
+
189
+ ```
190
+ Agent Decision
191
+
192
+
193
+ Tool Call: render_ui({ surfaceId, components })
194
+
195
+
196
+ Adapter converts to A2UX messages
197
+
198
+
199
+ FreesailStream.send() → SSE write
200
+
201
+
202
+ Client EventSource receives
203
+
204
+
205
+ A2UXProtocolHandler processes
206
+
207
+
208
+ SurfaceStore updates state
209
+
210
+
211
+ SurfaceRenderer re-renders DOM
212
+ ```
213
+
214
+ ### 2. UI → Agent (Upstream)
215
+
216
+ ```
217
+ User clicks Button
218
+
219
+
220
+ Component dispatches fs-action event
221
+
222
+
223
+ Client gathers full context from store
224
+
225
+
226
+ POST /api/action { userAction }
227
+
228
+
229
+ Server routes to agent
230
+
231
+
232
+ Agent processes and decides next action
233
+ ```
234
+
235
+ ## Transport Resilience
236
+
237
+ The transport layer handles:
238
+
239
+ 1. **Auto-Reconnection** - Exponential backoff on disconnect
240
+ 2. **Offline Queue** - IndexedDB-backed action queue
241
+ 3. **Idempotency** - Server handles duplicate messages
242
+ 4. **Keep-Alive** - Periodic heartbeats
243
+
244
+ ```typescript
245
+ const transport = new FreesailTransport({
246
+ url: '/api/stream',
247
+ autoReconnect: true,
248
+ reconnectDelay: 1000,
249
+ maxReconnectDelay: 30000,
250
+ offlineQueue: true,
251
+ });
252
+ ```
253
+
254
+ ## Multi-Catalog Support
255
+
256
+ Different surfaces can use different component catalogs:
257
+
258
+ ```typescript
259
+ // Finance dashboard with custom components
260
+ stream.createSurface('dashboard', 'finance_v1');
261
+
262
+ // Standard form
263
+ stream.createSurface('settings', 'standard_catalog_v1');
264
+ ```
265
+
266
+ The client registry maps catalog IDs to component bundles:
267
+
268
+ ```typescript
269
+ registry.registerCatalog('finance_v1', financeCatalog, financeComponents, 'fin');
270
+ // Components registered as: fin-ticker, fin-chart, etc.
271
+ ```
272
+
273
+ ## Security Considerations
274
+
275
+ 1. **Input Validation** - All properties validated against catalog schema
276
+ 2. **No innerHTML** - Rendering goes through component registry only
277
+ 3. **Action Context** - Full state ensures agent has context for decisions
278
+ 4. **Rate Limiting** - Implement at transport/server level
279
+
280
+ ## Performance Optimizations
281
+
282
+ 1. **Incremental Updates** - `updateDataModel` avoids full re-render
283
+ 2. **Component Caching** - Web Components are defined once
284
+ 3. **Stream Backpressure** - SSE handles flow control
285
+ 4. **Lazy Loading** - Catalogs can be loaded on demand
@@ -0,0 +1,377 @@
1
+ # Standard Catalog Reference
2
+
3
+ This document describes all components available in the Freesail Standard Catalog (`standard_catalog_v1`), which implements the A2UI Standard for cross-compatible generative UI.
4
+
5
+ ## Layout Components
6
+
7
+ ### Column
8
+
9
+ A vertical flex container that stacks children vertically.
10
+
11
+ **Tag:** `<fs-column>`
12
+
13
+ | Property | Type | Default | Description |
14
+ |----------|------|---------|-------------|
15
+ | `gap` | string | `"8px"` | Gap between child elements (CSS value) |
16
+ | `align` | string | `"stretch"` | Alignment: `start`, `center`, `end`, `stretch` |
17
+ | `justify` | string | `"start"` | Justification: `start`, `center`, `end`, `between`, `around` |
18
+ | `padding` | string | `"0"` | Padding inside the column |
19
+
20
+ **Example:**
21
+ ```json
22
+ {
23
+ "id": "container",
24
+ "component": "Column",
25
+ "gap": "16px",
26
+ "padding": "24px",
27
+ "children": ["header", "content", "footer"]
28
+ }
29
+ ```
30
+
31
+ ---
32
+
33
+ ### Row
34
+
35
+ A horizontal flex container that arranges children horizontally.
36
+
37
+ **Tag:** `<fs-row>`
38
+
39
+ | Property | Type | Default | Description |
40
+ |----------|------|---------|-------------|
41
+ | `gap` | string | `"8px"` | Gap between child elements |
42
+ | `align` | string | `"center"` | Alignment: `start`, `center`, `end`, `stretch` |
43
+ | `justify` | string | `"start"` | Justification: `start`, `center`, `end`, `between`, `around` |
44
+ | `wrap` | boolean | `false` | Whether children should wrap |
45
+ | `padding` | string | `"0"` | Padding inside the row |
46
+
47
+ ---
48
+
49
+ ### Card
50
+
51
+ A card container with optional title and elevation.
52
+
53
+ **Tag:** `<fs-card>`
54
+
55
+ | Property | Type | Default | Description |
56
+ |----------|------|---------|-------------|
57
+ | `title` | string | - | Card title |
58
+ | `subtitle` | string | - | Card subtitle |
59
+ | `padding` | string | `"16px"` | Content padding |
60
+ | `elevated` | boolean | `true` | Show elevation shadow |
61
+
62
+ **Example:**
63
+ ```json
64
+ {
65
+ "id": "profile-card",
66
+ "component": "Card",
67
+ "title": "User Profile",
68
+ "subtitle": "Manage your account settings",
69
+ "children": ["form-fields"]
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ### Spacer
76
+
77
+ A flexible space component for layout.
78
+
79
+ **Tag:** `<fs-spacer>`
80
+
81
+ | Property | Type | Default | Description |
82
+ |----------|------|---------|-------------|
83
+ | `size` | string | `"flex"` | Fixed size (CSS value) or `"flex"` for flexible |
84
+
85
+ ---
86
+
87
+ ### Divider
88
+
89
+ A horizontal or vertical divider line.
90
+
91
+ **Tag:** `<fs-divider>`
92
+
93
+ | Property | Type | Default | Description |
94
+ |----------|------|---------|-------------|
95
+ | `orientation` | string | `"horizontal"` | `horizontal` or `vertical` |
96
+ | `thickness` | string | `"1px"` | Line thickness |
97
+ | `color` | string | `"#e0e0e0"` | Line color |
98
+
99
+ ---
100
+
101
+ ## Text Components
102
+
103
+ ### Text
104
+
105
+ A text display component with variant styles.
106
+
107
+ **Tag:** `<fs-text>`
108
+
109
+ | Property | Type | Default | Description |
110
+ |----------|------|---------|-------------|
111
+ | `text` | string | `""` | **Required.** The text content |
112
+ | `variant` | string | `"body"` | Style: `h1`-`h6`, `body`, `caption`, `overline` |
113
+ | `color` | string | `"inherit"` | Text color |
114
+ | `weight` | string | `"normal"` | Weight: `light`, `normal`, `medium`, `semibold`, `bold` |
115
+ | `align` | string | `"left"` | Alignment: `left`, `center`, `right`, `justify` |
116
+
117
+ **Variant Sizes:**
118
+ - `h1`: 2.5rem
119
+ - `h2`: 2rem
120
+ - `h3`: 1.75rem
121
+ - `h4`: 1.5rem
122
+ - `h5`: 1.25rem
123
+ - `h6`: 1rem
124
+ - `body`: 1rem
125
+ - `caption`: 0.875rem
126
+ - `overline`: 0.75rem (uppercase)
127
+
128
+ ---
129
+
130
+ ## Input Components
131
+
132
+ ### Input
133
+
134
+ A text input field with label and validation.
135
+
136
+ **Tag:** `<fs-input>`
137
+
138
+ | Property | Type | Default | Description |
139
+ |----------|------|---------|-------------|
140
+ | `value` | string | `""` | Current value |
141
+ | `placeholder` | string | `""` | Placeholder text |
142
+ | `label` | string | - | Input label |
143
+ | `type` | string | `"text"` | Type: `text`, `email`, `password`, `number`, `tel`, `url` |
144
+ | `disabled` | boolean | `false` | Disabled state |
145
+ | `required` | boolean | `false` | Required state |
146
+ | `error` | string | - | Error message |
147
+ | `bindPath` | string | - | JSON Pointer path for data binding |
148
+
149
+ **Events:**
150
+ - `fs-change`: Fired when value changes. Detail: `{ value, bindPath, componentId }`
151
+
152
+ ---
153
+
154
+ ### Select
155
+
156
+ A dropdown select component.
157
+
158
+ **Tag:** `<fs-select>`
159
+
160
+ | Property | Type | Default | Description |
161
+ |----------|------|---------|-------------|
162
+ | `value` | string | - | Selected value |
163
+ | `options` | array | `[]` | Options: `[{ value, label }]` |
164
+ | `placeholder` | string | `"Select an option"` | Placeholder |
165
+ | `label` | string | - | Select label |
166
+ | `disabled` | boolean | `false` | Disabled state |
167
+ | `bindPath` | string | - | JSON Pointer for binding |
168
+
169
+ ---
170
+
171
+ ### Checkbox
172
+
173
+ A checkbox input with label.
174
+
175
+ **Tag:** `<fs-checkbox>`
176
+
177
+ | Property | Type | Default | Description |
178
+ |----------|------|---------|-------------|
179
+ | `checked` | boolean | `false` | Checked state |
180
+ | `label` | string | - | Checkbox label |
181
+ | `disabled` | boolean | `false` | Disabled state |
182
+ | `bindPath` | string | - | JSON Pointer for binding |
183
+
184
+ ---
185
+
186
+ ## Action Components
187
+
188
+ ### Button
189
+
190
+ An interactive button component.
191
+
192
+ **Tag:** `<fs-button>`
193
+
194
+ | Property | Type | Default | Description |
195
+ |----------|------|---------|-------------|
196
+ | `label` | string | `"Button"` | Button text |
197
+ | `variant` | string | `"primary"` | Style: `primary`, `secondary`, `outline`, `ghost`, `destructive` |
198
+ | `size` | string | `"medium"` | Size: `small`, `medium`, `large` |
199
+ | `disabled` | boolean | `false` | Disabled state |
200
+ | `action` | string | - | Action identifier sent on click |
201
+ | `fullWidth` | boolean | `false` | Full width button |
202
+
203
+ **Events:**
204
+ - `fs-action`: Fired on click. Detail: `{ action, componentId }`
205
+
206
+ **Variant Styles:**
207
+ - `primary`: Blue background, white text
208
+ - `secondary`: Gray background, white text
209
+ - `outline`: Transparent with blue border
210
+ - `ghost`: Transparent, dark text
211
+ - `destructive`: Red background, white text
212
+
213
+ ---
214
+
215
+ ## Feedback Components
216
+
217
+ ### Badge
218
+
219
+ A badge/chip component for status or labels.
220
+
221
+ **Tag:** `<fs-badge>`
222
+
223
+ | Property | Type | Default | Description |
224
+ |----------|------|---------|-------------|
225
+ | `text` | string | - | **Required.** Badge text |
226
+ | `variant` | string | `"default"` | Style: `default`, `primary`, `success`, `warning`, `error`, `info` |
227
+ | `size` | string | `"medium"` | Size: `small`, `medium`, `large` |
228
+
229
+ ---
230
+
231
+ ### Spinner
232
+
233
+ A loading spinner indicator.
234
+
235
+ **Tag:** `<fs-spinner>`
236
+
237
+ | Property | Type | Default | Description |
238
+ |----------|------|---------|-------------|
239
+ | `size` | string | `"medium"` | Size: `small`, `medium`, `large` |
240
+ | `color` | string | `"currentColor"` | Spinner color |
241
+
242
+ ---
243
+
244
+ ### Progress
245
+
246
+ A progress bar indicator.
247
+
248
+ **Tag:** `<fs-progress>`
249
+
250
+ | Property | Type | Default | Description |
251
+ |----------|------|---------|-------------|
252
+ | `value` | number | `0` | Current value (0-100) |
253
+ | `max` | number | `100` | Maximum value |
254
+ | `showLabel` | boolean | `false` | Show percentage label |
255
+ | `color` | string | `"#2563eb"` | Bar color |
256
+
257
+ ---
258
+
259
+ ## Media Components
260
+
261
+ ### Image
262
+
263
+ An image display component.
264
+
265
+ **Tag:** `<fs-image>`
266
+
267
+ | Property | Type | Default | Description |
268
+ |----------|------|---------|-------------|
269
+ | `src` | string | - | **Required.** Image source URL |
270
+ | `alt` | string | `""` | Alt text for accessibility |
271
+ | `width` | string | - | Image width (CSS) |
272
+ | `height` | string | - | Image height (CSS) |
273
+ | `fit` | string | `"cover"` | Object fit: `contain`, `cover`, `fill`, `none`, `scale-down` |
274
+ | `borderRadius` | string | `"0"` | Border radius |
275
+
276
+ ---
277
+
278
+ ## Usage Examples
279
+
280
+ ### Simple Form
281
+
282
+ ```json
283
+ {
284
+ "updateComponents": {
285
+ "surfaceId": "form",
286
+ "components": [
287
+ {
288
+ "id": "root",
289
+ "component": "Card",
290
+ "title": "Contact Us",
291
+ "children": ["form-fields", "actions"]
292
+ },
293
+ {
294
+ "id": "form-fields",
295
+ "component": "Column",
296
+ "gap": "16px",
297
+ "children": ["name-input", "email-input", "message-input"]
298
+ },
299
+ {
300
+ "id": "name-input",
301
+ "component": "Input",
302
+ "label": "Name",
303
+ "placeholder": "Your name",
304
+ "required": true,
305
+ "bindPath": "/form/name"
306
+ },
307
+ {
308
+ "id": "email-input",
309
+ "component": "Input",
310
+ "type": "email",
311
+ "label": "Email",
312
+ "placeholder": "your@email.com",
313
+ "required": true,
314
+ "bindPath": "/form/email"
315
+ },
316
+ {
317
+ "id": "message-input",
318
+ "component": "Input",
319
+ "label": "Message",
320
+ "placeholder": "Your message...",
321
+ "bindPath": "/form/message"
322
+ },
323
+ {
324
+ "id": "actions",
325
+ "component": "Row",
326
+ "justify": "end",
327
+ "gap": "12px",
328
+ "children": ["submit-btn"]
329
+ },
330
+ {
331
+ "id": "submit-btn",
332
+ "component": "Button",
333
+ "label": "Send Message",
334
+ "variant": "primary",
335
+ "action": "submit_contact"
336
+ }
337
+ ]
338
+ }
339
+ }
340
+ ```
341
+
342
+ ### Dashboard Card
343
+
344
+ ```json
345
+ {
346
+ "id": "stats-card",
347
+ "component": "Card",
348
+ "title": "Monthly Stats",
349
+ "children": ["stats-row"]
350
+ },
351
+ {
352
+ "id": "stats-row",
353
+ "component": "Row",
354
+ "justify": "between",
355
+ "children": ["users-stat", "revenue-stat", "orders-stat"]
356
+ },
357
+ {
358
+ "id": "users-stat",
359
+ "component": "Column",
360
+ "align": "center",
361
+ "children": ["users-value", "users-label"]
362
+ },
363
+ {
364
+ "id": "users-value",
365
+ "component": "Text",
366
+ "text": "1,234",
367
+ "variant": "h3",
368
+ "weight": "bold"
369
+ },
370
+ {
371
+ "id": "users-label",
372
+ "component": "Text",
373
+ "text": "Active Users",
374
+ "variant": "caption",
375
+ "color": "#6b7280"
376
+ }
377
+ ```