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.
- package/README.md +190 -5
- package/docs/A2UX_Protocol.md +183 -0
- package/docs/Agents.md +218 -0
- package/docs/Architecture.md +285 -0
- package/docs/CatalogReference.md +377 -0
- package/docs/GettingStarted.md +230 -0
- package/examples/demo/package.json +21 -0
- package/examples/demo/public/index.html +381 -0
- package/examples/demo/server.js +253 -0
- package/package.json +38 -5
- package/packages/core/package.json +48 -0
- package/packages/core/src/functions.ts +403 -0
- package/packages/core/src/index.ts +214 -0
- package/packages/core/src/parser.ts +270 -0
- package/packages/core/src/protocol.ts +254 -0
- package/packages/core/src/store.ts +452 -0
- package/packages/core/src/transport.ts +439 -0
- package/packages/core/src/types.ts +209 -0
- package/packages/core/tsconfig.json +10 -0
- package/packages/lit-ui/package.json +44 -0
- package/packages/lit-ui/src/catalogs/standard/catalog.json +405 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Badge.ts +96 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Button.ts +147 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Card.ts +78 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Checkbox.ts +94 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Column.ts +66 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Divider.ts +59 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Image.ts +54 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Input.ts +125 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Progress.ts +79 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Row.ts +68 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Select.ts +110 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Spacer.ts +37 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Spinner.ts +76 -0
- package/packages/lit-ui/src/catalogs/standard/elements/Text.ts +86 -0
- package/packages/lit-ui/src/catalogs/standard/elements/index.ts +18 -0
- package/packages/lit-ui/src/catalogs/standard/index.ts +17 -0
- package/packages/lit-ui/src/index.ts +84 -0
- package/packages/lit-ui/src/renderer.ts +211 -0
- package/packages/lit-ui/src/types.ts +49 -0
- package/packages/lit-ui/src/utils/define-props.ts +157 -0
- package/packages/lit-ui/src/utils/index.ts +2 -0
- package/packages/lit-ui/src/utils/registry.ts +139 -0
- package/packages/lit-ui/tsconfig.json +11 -0
- package/packages/server/package.json +61 -0
- package/packages/server/src/adapters/index.ts +5 -0
- package/packages/server/src/adapters/langchain.ts +175 -0
- package/packages/server/src/adapters/openai.ts +209 -0
- package/packages/server/src/catalog-loader.ts +311 -0
- package/packages/server/src/index.ts +142 -0
- package/packages/server/src/stream.ts +329 -0
- package/packages/server/tsconfig.json +11 -0
- package/tsconfig.base.json +23 -0
- 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
|
+
```
|