@maxhealth.tech/prefab 0.1.2 → 0.1.4

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 CHANGED
@@ -1,340 +1,340 @@
1
- # prefab
2
-
3
- [![CI](https://github.com/Max-Health-Inc/prefab-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/Max-Health-Inc/prefab-ui/actions/workflows/ci.yml)
4
- [![npm](https://img.shields.io/npm/v/@maxhealth.tech/prefab)](https://www.npmjs.com/package/@maxhealth.tech/prefab)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-6.0-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
-
8
- TypeScript declarative UI component library for MCP apps. Wire-compatible with PrefectHQ's Python [prefab-ui](https://github.com/PrefectHQ/prefab) — **same `$prefab` JSON, two languages**.
9
-
10
- Write MCP servers in **TypeScript/Bun** and generate the exact same wire format that Python servers produce. Render the output in **any web app** with the included vanilla DOM renderer. Full circle: server-side DSL → JSON → browser UI.
11
-
12
- - **55+ components** — layout, form, data, charts, media, interactive, control flow
13
- - **Reactive state** — `rx()` expressions, `SetState`/`ToggleState`/`AppendState` actions
14
- - **MCP-native** — `display()`, `display_form()`, `CallTool`, `SendMessage` built in
15
- - **Browser renderer** — zero dependencies, vanilla DOM (optional separate import)
16
- - **ext-apps bridge** — `app()` factory with PostMessage transport, host theme, lifecycle hooks
17
- - **Auto-renderers** — `autoTable()`, `autoChart()`, `autoForm()`, `autoMetrics()` and more
18
-
19
- ## Works Everywhere
20
-
21
- The renderer is **vanilla DOM** — no framework dependency. Drop it into any web app:
22
-
23
- - **React** — mount into a `ref` div
24
- - **Vue / Svelte / Angular** — same, it's just DOM
25
- - **Plain HTML** — single `<script>` tag
26
- - **Electron / Tauri** — desktop apps with web views
27
- - **Any iframe** — ext-apps, embedded widgets, sandboxed UIs
28
-
29
- Any app that connects to MCP servers can render `$prefab` tool output as rich interactive UI — tables, charts, forms, badges — with zero custom code.
30
-
31
- ## Install
32
-
33
- ```bash
34
- npm install @maxhealth.tech/prefab
35
- # or
36
- bun add @maxhealth.tech/prefab
37
- ```
38
-
39
- ## Quick Start
40
-
41
- ### Server-side (MCP tool handler)
42
-
43
- ```ts
44
- import { display, autoTable, H1, Column } from '@maxhealth.tech/prefab'
45
-
46
- async function listUsers(args: any) {
47
- const users = await db.query('SELECT * FROM users')
48
- return display(
49
- Column({ children: [
50
- H1('Users'),
51
- autoTable(users),
52
- ]}),
53
- { title: 'User List' }
54
- )
55
- }
56
- ```
57
-
58
- ### Client-side (browser ext-app)
59
-
60
- ```html
61
- <script src="https://cdn.jsdelivr.net/npm/@maxhealth.tech/prefab/dist/renderer.min.js"></script>
62
- <script>
63
- const ui = await prefab.app();
64
-
65
- ui.onToolInput((args) => {
66
- // Render wire-format JSON received from the MCP host
67
- ui.mount('#root', args);
68
- });
69
- </script>
70
- ```
71
-
72
- ## Components
73
-
74
- ### Layout
75
- `Column`, `Row`, `Grid`, `GridItem`, `Container`, `Div`, `Span`, `Dashboard`, `DashboardItem`, `Pages`, `Page`
76
-
77
- ### Typography
78
- `Heading`, `H1`–`H4`, `Text`, `P`, `Lead`, `Large`, `Small`, `Muted`, `BlockQuote`, `Label`, `Link`, `Code`, `Markdown`, `Kbd`
79
-
80
- ### Card
81
- `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`
82
-
83
- ### Data Display
84
- `DataTable`, `col`, `Badge`, `Dot`, `Metric`, `Ring`, `Progress`, `Separator`, `Loader`, `Icon`
85
-
86
- ### Table
87
- `Table`, `TableHead`, `TableBody`, `TableFooter`, `TableRow`, `TableHeader`, `TableCell`, `TableCaption`, `ExpandableRow`
88
-
89
- ### Form
90
- `Form`, `Input`, `Textarea`, `Button`, `ButtonGroup`, `Select`, `SelectOption`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `Checkbox`, `Switch`, `Slider`, `Radio`, `RadioGroup`, `Combobox`, `ComboboxOption`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxSeparator`, `Calendar`, `DatePicker`, `Field`, `FieldTitle`, `FieldDescription`, `FieldContent`, `FieldError`, `ChoiceCard`
91
-
92
- ### Interactive
93
- `Tabs`, `Tab`, `Accordion`, `AccordionItem`, `Dialog`, `Popover`, `Tooltip`, `HoverCard`, `Carousel`
94
-
95
- ### Charts
96
- `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`, `ScatterChart`, `Sparkline`, `RadialChart`, `Histogram`
97
-
98
- ### Media
99
- `Image`, `Audio`, `Video`, `Embed`, `Svg`, `DropZone`, `Mermaid`
100
-
101
- ### Alert
102
- `Alert`, `AlertTitle`, `AlertDescription`
103
-
104
- ### Control Flow
105
- `ForEach`, `If`, `Elif`, `Else`, `Define`, `Use`, `Slot`
106
-
107
- ## Reactive Expressions
108
-
109
- Use `rx()` to create reactive expressions that update when state changes:
110
-
111
- ```ts
112
- import { rx, STATE } from '@maxhealth.tech/prefab'
113
-
114
- // Simple state reference
115
- Text(rx('count')) // → "{{ count }}"
116
-
117
- // Arithmetic
118
- Text(rx('count').add(1)) // → "{{ count + 1 }}"
119
-
120
- // Dot-path access
121
- Text(rx('user').dot('name')) // → "{{ user.name }}"
122
-
123
- // Direct template string
124
- Text('Hello, {{ user.name }}!') // interpolated at render time
125
-
126
- // Ternary
127
- Badge(rx('status').eq('active').then('Online', 'Offline'))
128
-
129
- // Pipes (filters)
130
- Text(rx('amount').currency()) // → "{{ amount | currency }}"
131
- Text(rx('items').length()) // → "{{ items | length }}"
132
- Text(rx('name').upper().truncate(20)) // → "{{ name | upper | truncate:20 }}"
133
-
134
- // STATE proxy (single-level shorthand: STATE.key → rx('key'))
135
- Text(STATE.count) // → "{{ count }}"
136
- ```
137
-
138
- **Built-in pipes:** `upper`, `lower`, `capitalize`, `truncate`, `currency`, `number`, `percent`, `date`, `time`, `datetime`, `length`, `default`, `json`, `keys`, `values`, `first`, `last`
139
-
140
- ## Actions
141
-
142
- Actions are triggered by user interactions (`onClick`, `onChange`, `onSubmit`) or lifecycle events (`onMount`):
143
-
144
- ```ts
145
- import { SetState, ToggleState, CallTool, ShowToast, OpenLink, rx } from '@maxhealth.tech/prefab'
146
-
147
- // Client-side state mutation
148
- Button('Increment', { onClick: new SetState('count', rx('count').add(1)) })
149
-
150
- // Toggle boolean
151
- Button('Toggle', { onClick: new ToggleState('expanded') })
152
-
153
- // MCP tool call
154
- Button('Refresh', { onClick: new CallTool('get_data', { arguments: { id: '{{ selectedId }}' } }) })
155
-
156
- // Toast notification
157
- Button('Save', { onClick: new ShowToast('Saved!', { variant: 'success' }) })
158
- ```
159
-
160
- **Client actions:** `SetState`, `ToggleState`, `AppendState`, `PopState`, `ShowToast`, `CloseOverlay`, `OpenLink`, `SetInterval`, `Fetch`, `OpenFilePicker`, `CallHandler`
161
-
162
- **MCP actions:** `CallTool`, `SendMessage`, `UpdateContext`, `RequestDisplayMode`
163
-
164
- ## Auto-Renderers
165
-
166
- Generate complete UIs from raw data — no manual component wiring:
167
-
168
- ```ts
169
- import { autoTable, autoChart, autoForm, autoMetrics } from '@maxhealth.tech/prefab'
170
-
171
- // Table from array of objects
172
- autoTable(users, { title: 'Users', search: true })
173
-
174
- // Chart from data + series definitions
175
- autoChart(
176
- salesData,
177
- [{ dataKey: 'revenue', label: 'Revenue', color: '#3b82f6' }],
178
- { title: 'Revenue', chartType: 'bar', xAxis: 'month' },
179
- )
180
-
181
- // Form that submits to an MCP tool
182
- autoForm(
183
- [
184
- { name: 'email', type: 'email', required: true },
185
- { name: 'name', label: 'Full Name', required: true },
186
- ],
187
- 'create_user',
188
- { title: 'New User', submitLabel: 'Create' },
189
- )
190
-
191
- // KPI metric cards
192
- autoMetrics([
193
- { label: 'Revenue', value: '$42K', delta: '+12%', trend: 'up', trendSentiment: 'positive' },
194
- { label: 'Users', value: '3,420', delta: '+5%', trend: 'up', trendSentiment: 'positive' },
195
- ])
196
- ```
197
-
198
- **Auto-renderers:** `autoDetail`, `autoTable`, `autoChart`, `autoForm`, `autoComparison`, `autoMetrics`, `autoTimeline`, `autoProgress`
199
-
200
- ## MCP Display Helpers
201
-
202
- Return UIs from MCP tool handlers:
203
-
204
- ```ts
205
- import { display, display_form, display_update, display_error } from '@maxhealth.tech/prefab'
206
- import { Column, H1 } from '@maxhealth.tech/prefab'
207
-
208
- // Full UI
209
- return display(Column({ children: [H1('Dashboard'), autoMetrics(kpis)] }), { title: 'Dashboard' })
210
-
211
- // Form that submits back to a tool (fields, toolName, options)
212
- return display_form(
213
- [
214
- { name: 'name', type: 'text', required: true },
215
- { name: 'email', type: 'email' },
216
- ],
217
- 'update_user',
218
- { title: 'Edit User' },
219
- )
220
-
221
- // Partial state update (no full re-render)
222
- return display_update({ count: 42, status: 'complete' })
223
-
224
- // Error display
225
- return display_error('User not found', { code: 404 })
226
- ```
227
-
228
- ## Browser Renderer
229
-
230
- The renderer is a 54KB IIFE bundle with zero external dependencies:
231
-
232
- ```html
233
- <script src="renderer.min.js"></script>
234
- <script>
235
- // Mount from wire format data
236
- const app = PrefabRenderer.mount(document.getElementById('root'), wireData);
237
-
238
- // Or auto-mount from embedded data
239
- // (set window.__PREFAB_DATA__ before loading the script)
240
- </script>
241
- ```
242
-
243
- ### ext-apps Bridge
244
-
245
- For MCP ext-apps running in iframes:
246
-
247
- ```js
248
- const ui = await prefab.app();
249
-
250
- // Receive tool input from host
251
- ui.onToolInput((args) => {
252
- ui.render('#root', buildUI(args));
253
- });
254
-
255
- // Call tools on the host
256
- const result = await ui.callTool('get_data', { query: 'active users' });
257
-
258
- // Request display mode change
259
- ui.requestMode('fullscreen');
260
-
261
- // Access host context
262
- console.log(ui.host); // { name, version, ... }
263
- console.log(ui.capabilities); // { toast, clipboard, ... }
264
- console.log(ui.theme); // host CSS variables
265
- ```
266
-
267
- ## Wire Format
268
-
269
- All UIs serialize to the `$prefab` wire format (JSON):
270
-
271
- ```json
272
- {
273
- "$prefab": { "version": "0.2" },
274
- "view": {
275
- "type": "Column",
276
- "children": [
277
- { "type": "H1", "content": "Hello" },
278
- { "type": "Text", "content": "{{ message }}" }
279
- ]
280
- },
281
- "state": {
282
- "message": "Welcome to prefab"
283
- },
284
- "theme": {
285
- "light": { "primary": "#3b82f6" },
286
- "dark": { "primary": "#60a5fa" }
287
- }
288
- }
289
- ```
290
-
291
- ### Wire Format Fields
292
-
293
- | Field | Type | Description |
294
- |---|---|---|
295
- | `$prefab` | `{ version: string }` | Format identifier and version |
296
- | `view` | `ComponentJSON` | Root component tree |
297
- | `state` | `Record<string, unknown>` | Initial reactive state |
298
- | `theme` | `{ light?, dark? }` | CSS custom property overrides |
299
- | `defs` | `Record<string, ComponentJSON>` | Reusable component templates |
300
- | `keyBindings` | `Record<string, ActionJSON>` | Keyboard shortcut → action mappings |
301
-
302
- ### Component JSON Shape
303
-
304
- ```json
305
- {
306
- "type": "Button",
307
- "content": "Click me",
308
- "variant": "default",
309
- "onClick": {
310
- "action": "setState",
311
- "key": "count",
312
- "value": "{{ count + 1 }}"
313
- }
314
- }
315
- ```
316
-
317
- ## Subpath Exports
318
-
319
- ```ts
320
- import { ... } from '@maxhealth.tech/prefab' // Everything
321
- import { ... } from '@maxhealth.tech/prefab/actions' // Actions only
322
- import { ... } from '@maxhealth.tech/prefab/rx' // Rx expressions only
323
- import { ... } from '@maxhealth.tech/prefab/charts' // Chart components only
324
- import { ... } from '@maxhealth.tech/prefab/mcp' // MCP display helpers
325
- import { ... } from '@maxhealth.tech/prefab/renderer' // Browser renderer
326
- ```
327
-
328
- ## Development
329
-
330
- ```bash
331
- bun install # Install dependencies
332
- bun test # Run tests (362 passing)
333
- bun run build # TypeScript compile + IIFE bundle
334
- bun run lint # ESLint
335
- bun run typecheck # Type check without emitting
336
- ```
337
-
338
- ## License
339
-
340
- MIT
1
+ # prefab
2
+
3
+ [![CI](https://github.com/Max-Health-Inc/prefab-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/Max-Health-Inc/prefab-ui/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/@maxhealth.tech/prefab)](https://www.npmjs.com/package/@maxhealth.tech/prefab)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-6.0-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ TypeScript declarative UI component library for MCP apps. Wire-compatible with PrefectHQ's Python [prefab-ui](https://github.com/PrefectHQ/prefab) — **same `$prefab` JSON, two languages**.
9
+
10
+ Write MCP servers in **TypeScript/Bun** and generate the exact same wire format that Python servers produce. Render the output in **any web app** with the included vanilla DOM renderer. Full circle: server-side DSL → JSON → browser UI.
11
+
12
+ - **55+ components** — layout, form, data, charts, media, interactive, control flow
13
+ - **Reactive state** — `rx()` expressions, `SetState`/`ToggleState`/`AppendState` actions
14
+ - **MCP-native** — `display()`, `display_form()`, `CallTool`, `SendMessage` built in
15
+ - **Browser renderer** — zero dependencies, vanilla DOM (optional separate import)
16
+ - **ext-apps bridge** — `app()` factory with PostMessage transport, host theme, lifecycle hooks
17
+ - **Auto-renderers** — `autoTable()`, `autoChart()`, `autoForm()`, `autoMetrics()` and more
18
+
19
+ ## Works Everywhere
20
+
21
+ The renderer is **vanilla DOM** — no framework dependency. Drop it into any web app:
22
+
23
+ - **React** — mount into a `ref` div
24
+ - **Vue / Svelte / Angular** — same, it's just DOM
25
+ - **Plain HTML** — single `<script>` tag
26
+ - **Electron / Tauri** — desktop apps with web views
27
+ - **Any iframe** — ext-apps, embedded widgets, sandboxed UIs
28
+
29
+ Any app that connects to MCP servers can render `$prefab` tool output as rich interactive UI — tables, charts, forms, badges — with zero custom code.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ npm install @maxhealth.tech/prefab
35
+ # or
36
+ bun add @maxhealth.tech/prefab
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ### Server-side (MCP tool handler)
42
+
43
+ ```ts
44
+ import { display, autoTable, H1, Column } from '@maxhealth.tech/prefab'
45
+
46
+ async function listUsers(args: any) {
47
+ const users = await db.query('SELECT * FROM users')
48
+ return display(
49
+ Column({ children: [
50
+ H1('Users'),
51
+ autoTable(users),
52
+ ]}),
53
+ { title: 'User List' }
54
+ )
55
+ }
56
+ ```
57
+
58
+ ### Client-side (browser ext-app)
59
+
60
+ ```html
61
+ <script src="https://cdn.jsdelivr.net/npm/@maxhealth.tech/prefab/dist/renderer.min.js"></script>
62
+ <script>
63
+ const ui = await prefab.app();
64
+
65
+ ui.onToolInput((args) => {
66
+ // Render wire-format JSON received from the MCP host
67
+ ui.mount('#root', args);
68
+ });
69
+ </script>
70
+ ```
71
+
72
+ ## Components
73
+
74
+ ### Layout
75
+ `Column`, `Row`, `Grid`, `GridItem`, `Container`, `Div`, `Span`, `Dashboard`, `DashboardItem`, `Pages`, `Page`
76
+
77
+ ### Typography
78
+ `Heading`, `H1`–`H4`, `Text`, `P`, `Lead`, `Large`, `Small`, `Muted`, `BlockQuote`, `Label`, `Link`, `Code`, `Markdown`, `Kbd`
79
+
80
+ ### Card
81
+ `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`
82
+
83
+ ### Data Display
84
+ `DataTable`, `col`, `Badge`, `Dot`, `Metric`, `Ring`, `Progress`, `Separator`, `Loader`, `Icon`
85
+
86
+ ### Table
87
+ `Table`, `TableHead`, `TableBody`, `TableFooter`, `TableRow`, `TableHeader`, `TableCell`, `TableCaption`, `ExpandableRow`
88
+
89
+ ### Form
90
+ `Form`, `Input`, `Textarea`, `Button`, `ButtonGroup`, `Select`, `SelectOption`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `Checkbox`, `Switch`, `Slider`, `Radio`, `RadioGroup`, `Combobox`, `ComboboxOption`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxSeparator`, `Calendar`, `DatePicker`, `Field`, `FieldTitle`, `FieldDescription`, `FieldContent`, `FieldError`, `ChoiceCard`
91
+
92
+ ### Interactive
93
+ `Tabs`, `Tab`, `Accordion`, `AccordionItem`, `Dialog`, `Popover`, `Tooltip`, `HoverCard`, `Carousel`
94
+
95
+ ### Charts
96
+ `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`, `ScatterChart`, `Sparkline`, `RadialChart`, `Histogram`
97
+
98
+ ### Media
99
+ `Image`, `Audio`, `Video`, `Embed`, `Svg`, `DropZone`, `Mermaid`
100
+
101
+ ### Alert
102
+ `Alert`, `AlertTitle`, `AlertDescription`
103
+
104
+ ### Control Flow
105
+ `ForEach`, `If`, `Elif`, `Else`, `Define`, `Use`, `Slot`
106
+
107
+ ## Reactive Expressions
108
+
109
+ Use `rx()` to create reactive expressions that update when state changes:
110
+
111
+ ```ts
112
+ import { rx, STATE } from '@maxhealth.tech/prefab'
113
+
114
+ // Simple state reference
115
+ Text(rx('count')) // → "{{ count }}"
116
+
117
+ // Arithmetic
118
+ Text(rx('count').add(1)) // → "{{ count + 1 }}"
119
+
120
+ // Dot-path access
121
+ Text(rx('user').dot('name')) // → "{{ user.name }}"
122
+
123
+ // Direct template string
124
+ Text('Hello, {{ user.name }}!') // interpolated at render time
125
+
126
+ // Ternary
127
+ Badge(rx('status').eq('active').then('Online', 'Offline'))
128
+
129
+ // Pipes (filters)
130
+ Text(rx('amount').currency()) // → "{{ amount | currency }}"
131
+ Text(rx('items').length()) // → "{{ items | length }}"
132
+ Text(rx('name').upper().truncate(20)) // → "{{ name | upper | truncate:20 }}"
133
+
134
+ // STATE proxy (single-level shorthand: STATE.key → rx('key'))
135
+ Text(STATE.count) // → "{{ count }}"
136
+ ```
137
+
138
+ **Built-in pipes:** `upper`, `lower`, `capitalize`, `truncate`, `currency`, `number`, `percent`, `date`, `time`, `datetime`, `length`, `default`, `json`, `keys`, `values`, `first`, `last`
139
+
140
+ ## Actions
141
+
142
+ Actions are triggered by user interactions (`onClick`, `onChange`, `onSubmit`) or lifecycle events (`onMount`):
143
+
144
+ ```ts
145
+ import { SetState, ToggleState, CallTool, ShowToast, OpenLink, rx } from '@maxhealth.tech/prefab'
146
+
147
+ // Client-side state mutation
148
+ Button('Increment', { onClick: new SetState('count', rx('count').add(1)) })
149
+
150
+ // Toggle boolean
151
+ Button('Toggle', { onClick: new ToggleState('expanded') })
152
+
153
+ // MCP tool call
154
+ Button('Refresh', { onClick: new CallTool('get_data', { arguments: { id: '{{ selectedId }}' } }) })
155
+
156
+ // Toast notification
157
+ Button('Save', { onClick: new ShowToast('Saved!', { variant: 'success' }) })
158
+ ```
159
+
160
+ **Client actions:** `SetState`, `ToggleState`, `AppendState`, `PopState`, `ShowToast`, `CloseOverlay`, `OpenLink`, `SetInterval`, `Fetch`, `OpenFilePicker`, `CallHandler`
161
+
162
+ **MCP actions:** `CallTool`, `SendMessage`, `UpdateContext`, `RequestDisplayMode`
163
+
164
+ ## Auto-Renderers
165
+
166
+ Generate complete UIs from raw data — no manual component wiring:
167
+
168
+ ```ts
169
+ import { autoTable, autoChart, autoForm, autoMetrics } from '@maxhealth.tech/prefab'
170
+
171
+ // Table from array of objects
172
+ autoTable(users, { title: 'Users', search: true })
173
+
174
+ // Chart from data + series definitions
175
+ autoChart(
176
+ salesData,
177
+ [{ dataKey: 'revenue', label: 'Revenue', color: '#3b82f6' }],
178
+ { title: 'Revenue', chartType: 'bar', xAxis: 'month' },
179
+ )
180
+
181
+ // Form that submits to an MCP tool
182
+ autoForm(
183
+ [
184
+ { name: 'email', type: 'email', required: true },
185
+ { name: 'name', label: 'Full Name', required: true },
186
+ ],
187
+ 'create_user',
188
+ { title: 'New User', submitLabel: 'Create' },
189
+ )
190
+
191
+ // KPI metric cards
192
+ autoMetrics([
193
+ { label: 'Revenue', value: '$42K', delta: '+12%', trend: 'up', trendSentiment: 'positive' },
194
+ { label: 'Users', value: '3,420', delta: '+5%', trend: 'up', trendSentiment: 'positive' },
195
+ ])
196
+ ```
197
+
198
+ **Auto-renderers:** `autoDetail`, `autoTable`, `autoChart`, `autoForm`, `autoComparison`, `autoMetrics`, `autoTimeline`, `autoProgress`
199
+
200
+ ## MCP Display Helpers
201
+
202
+ Return UIs from MCP tool handlers:
203
+
204
+ ```ts
205
+ import { display, display_form, display_update, display_error } from '@maxhealth.tech/prefab'
206
+ import { Column, H1 } from '@maxhealth.tech/prefab'
207
+
208
+ // Full UI
209
+ return display(Column({ children: [H1('Dashboard'), autoMetrics(kpis)] }), { title: 'Dashboard' })
210
+
211
+ // Form that submits back to a tool (fields, toolName, options)
212
+ return display_form(
213
+ [
214
+ { name: 'name', type: 'text', required: true },
215
+ { name: 'email', type: 'email' },
216
+ ],
217
+ 'update_user',
218
+ { title: 'Edit User' },
219
+ )
220
+
221
+ // Partial state update (no full re-render)
222
+ return display_update({ count: 42, status: 'complete' })
223
+
224
+ // Error display
225
+ return display_error('User not found', { code: 404 })
226
+ ```
227
+
228
+ ## Browser Renderer
229
+
230
+ The renderer is a 54KB IIFE bundle with zero external dependencies:
231
+
232
+ ```html
233
+ <script src="renderer.min.js"></script>
234
+ <script>
235
+ // Mount from wire format data
236
+ const app = PrefabRenderer.mount(document.getElementById('root'), wireData);
237
+
238
+ // Or auto-mount from embedded data
239
+ // (set window.__PREFAB_DATA__ before loading the script)
240
+ </script>
241
+ ```
242
+
243
+ ### ext-apps Bridge
244
+
245
+ For MCP ext-apps running in iframes:
246
+
247
+ ```js
248
+ const ui = await prefab.app();
249
+
250
+ // Receive tool input from host
251
+ ui.onToolInput((args) => {
252
+ ui.render('#root', buildUI(args));
253
+ });
254
+
255
+ // Call tools on the host
256
+ const result = await ui.callTool('get_data', { query: 'active users' });
257
+
258
+ // Request display mode change
259
+ ui.requestMode('fullscreen');
260
+
261
+ // Access host context
262
+ console.log(ui.host); // { name, version, ... }
263
+ console.log(ui.capabilities); // { toast, clipboard, ... }
264
+ console.log(ui.theme); // host CSS variables
265
+ ```
266
+
267
+ ## Wire Format
268
+
269
+ All UIs serialize to the `$prefab` wire format (JSON):
270
+
271
+ ```json
272
+ {
273
+ "$prefab": { "version": "0.2" },
274
+ "view": {
275
+ "type": "Column",
276
+ "children": [
277
+ { "type": "H1", "content": "Hello" },
278
+ { "type": "Text", "content": "{{ message }}" }
279
+ ]
280
+ },
281
+ "state": {
282
+ "message": "Welcome to prefab"
283
+ },
284
+ "theme": {
285
+ "light": { "primary": "#3b82f6" },
286
+ "dark": { "primary": "#60a5fa" }
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Wire Format Fields
292
+
293
+ | Field | Type | Description |
294
+ |---|---|---|
295
+ | `$prefab` | `{ version: string }` | Format identifier and version |
296
+ | `view` | `ComponentJSON` | Root component tree |
297
+ | `state` | `Record<string, unknown>` | Initial reactive state |
298
+ | `theme` | `{ light?, dark? }` | CSS custom property overrides |
299
+ | `defs` | `Record<string, ComponentJSON>` | Reusable component templates |
300
+ | `keyBindings` | `Record<string, ActionJSON>` | Keyboard shortcut → action mappings |
301
+
302
+ ### Component JSON Shape
303
+
304
+ ```json
305
+ {
306
+ "type": "Button",
307
+ "content": "Click me",
308
+ "variant": "default",
309
+ "onClick": {
310
+ "action": "setState",
311
+ "key": "count",
312
+ "value": "{{ count + 1 }}"
313
+ }
314
+ }
315
+ ```
316
+
317
+ ## Subpath Exports
318
+
319
+ ```ts
320
+ import { ... } from '@maxhealth.tech/prefab' // Everything
321
+ import { ... } from '@maxhealth.tech/prefab/actions' // Actions only
322
+ import { ... } from '@maxhealth.tech/prefab/rx' // Rx expressions only
323
+ import { ... } from '@maxhealth.tech/prefab/charts' // Chart components only
324
+ import { ... } from '@maxhealth.tech/prefab/mcp' // MCP display helpers
325
+ import { ... } from '@maxhealth.tech/prefab/renderer' // Browser renderer
326
+ ```
327
+
328
+ ## Development
329
+
330
+ ```bash
331
+ bun install # Install dependencies
332
+ bun test # Run tests (362 passing)
333
+ bun run build # TypeScript compile + IIFE bundle
334
+ bun run lint # ESLint
335
+ bun run typecheck # Type check without emitting
336
+ ```
337
+
338
+ ## License
339
+
340
+ MIT