Quellcode durchsuchen

fix docs (#167)

* fix docs

* fix docs
Chris Tate vor 4 Monaten
Ursprung
Commit
9f58d8712c

+ 1 - 0
AGENTS.md

@@ -26,6 +26,7 @@ This ensures we don't install outdated versions that may have incompatible types
 
 - Do not use emojis in code or UI
 - Use shadcn CLI to add shadcn/ui components: `pnpm dlx shadcn@latest add <component>`
+- **Web app docs (`apps/web/`):** Never use Markdown table syntax (`| col | col |`). Always use HTML `<table>` with `<thead>`, `<tbody>`, `<tr>`, `<th>`, `<td>`. Markdown tables do not render correctly in the web app. Inside HTML table cells, curly braces must be escaped as JSX expressions (e.g. `<code>{'{ "$state": "/path" }'}</code>`) because MDX parses `{` as a JSX expression boundary.
 
 ## AI SDK / AI Gateway
 

+ 81 - 46
apps/web/app/(main)/docs/api/react-native/page.mdx

@@ -9,54 +9,79 @@ React Native renderer with standard components, providers, and hooks.
 
 ### Layout
 
-| Component | Props | Description |
-|-----------|-------|-------------|
-| `Container` | `padding`, `background`, `borderRadius`, `borderColor`, `flex` | Basic wrapper with styling |
-| `Row` | `gap`, `align`, `justify`, `flex`, `wrap` | Horizontal flex layout |
-| `Column` | `gap`, `align`, `justify`, `flex` | Vertical flex layout |
-| `ScrollContainer` | `direction` | Scrollable area (vertical or horizontal) |
-| `SafeArea` | `edges` | Safe area insets for notch/home indicator |
-| `Pressable` | `action`, `actionParams` | Touchable wrapper that triggers actions |
-| `Spacer` | `size`, `flex` | Fixed or flexible spacing |
-| `Divider` | `color`, `thickness` | Thin line separator |
+<table>
+<thead>
+<tr><th>Component</th><th>Props</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>Container</code></td><td><code>padding</code>, <code>background</code>, <code>borderRadius</code>, <code>borderColor</code>, <code>flex</code></td><td>Basic wrapper with styling</td></tr>
+<tr><td><code>Row</code></td><td><code>gap</code>, <code>align</code>, <code>justify</code>, <code>flex</code>, <code>wrap</code></td><td>Horizontal flex layout</td></tr>
+<tr><td><code>Column</code></td><td><code>gap</code>, <code>align</code>, <code>justify</code>, <code>flex</code></td><td>Vertical flex layout</td></tr>
+<tr><td><code>ScrollContainer</code></td><td><code>direction</code></td><td>Scrollable area (vertical or horizontal)</td></tr>
+<tr><td><code>SafeArea</code></td><td><code>edges</code></td><td>Safe area insets for notch/home indicator</td></tr>
+<tr><td><code>Pressable</code></td><td><code>action</code>, <code>actionParams</code></td><td>Touchable wrapper that triggers actions</td></tr>
+<tr><td><code>Spacer</code></td><td><code>size</code>, <code>flex</code></td><td>Fixed or flexible spacing</td></tr>
+<tr><td><code>Divider</code></td><td><code>color</code>, <code>thickness</code></td><td>Thin line separator</td></tr>
+</tbody>
+</table>
 
 ### Content
 
-| Component | Props | Description |
-|-----------|-------|-------------|
-| `Heading` | `text`, `level`, `align`, `color` | Heading text (levels 1-6) |
-| `Paragraph` | `text`, `align`, `color` | Body text |
-| `Label` | `text`, `color`, `bold` | Small label text |
-| `Image` | `uri`, `width`, `height`, `resizeMode`, `borderRadius` | Image display |
-| `Avatar` | `uri`, `size`, `fallback` | Circular avatar |
-| `Badge` | `label`, `color`, `textColor` | Status badge |
-| `Chip` | `label`, `selected`, `color` | Tag/chip |
+<table>
+<thead>
+<tr><th>Component</th><th>Props</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>Heading</code></td><td><code>text</code>, <code>level</code>, <code>align</code>, <code>color</code></td><td>Heading text (levels 1-6)</td></tr>
+<tr><td><code>Paragraph</code></td><td><code>text</code>, <code>align</code>, <code>color</code></td><td>Body text</td></tr>
+<tr><td><code>Label</code></td><td><code>text</code>, <code>color</code>, <code>bold</code></td><td>Small label text</td></tr>
+<tr><td><code>Image</code></td><td><code>uri</code>, <code>width</code>, <code>height</code>, <code>resizeMode</code>, <code>borderRadius</code></td><td>Image display</td></tr>
+<tr><td><code>Avatar</code></td><td><code>uri</code>, <code>size</code>, <code>fallback</code></td><td>Circular avatar</td></tr>
+<tr><td><code>Badge</code></td><td><code>label</code>, <code>color</code>, <code>textColor</code></td><td>Status badge</td></tr>
+<tr><td><code>Chip</code></td><td><code>label</code>, <code>selected</code>, <code>color</code></td><td>Tag/chip</td></tr>
+</tbody>
+</table>
 
 ### Input
 
-| Component | Props | Description |
-|-----------|-------|-------------|
-| `Button` | `label`, `variant`, `size`, `disabled`, `action`, `actionParams` | Pressable button |
-| `TextInput` | `placeholder`, `value` (use `$bindState`), `secure`, `keyboardType`, `multiline` | Text input field |
-| `Switch` | `checked` (use `$bindState`), `label` | Toggle switch |
-| `Checkbox` | `checked` (use `$bindState`), `label` | Checkbox with label |
-| `Slider` | `value` (use `$bindState`), `min`, `max`, `step` | Range slider |
-| `SearchBar` | `placeholder`, `value` (use `$bindState`) | Search input |
+<table>
+<thead>
+<tr><th>Component</th><th>Props</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>Button</code></td><td><code>label</code>, <code>variant</code>, <code>size</code>, <code>disabled</code>, <code>action</code>, <code>actionParams</code></td><td>Pressable button</td></tr>
+<tr><td><code>TextInput</code></td><td><code>placeholder</code>, <code>value</code> (use <code>$bindState</code>), <code>secure</code>, <code>keyboardType</code>, <code>multiline</code></td><td>Text input field</td></tr>
+<tr><td><code>Switch</code></td><td><code>checked</code> (use <code>$bindState</code>), <code>label</code></td><td>Toggle switch</td></tr>
+<tr><td><code>Checkbox</code></td><td><code>checked</code> (use <code>$bindState</code>), <code>label</code></td><td>Checkbox with label</td></tr>
+<tr><td><code>Slider</code></td><td><code>value</code> (use <code>$bindState</code>), <code>min</code>, <code>max</code>, <code>step</code></td><td>Range slider</td></tr>
+<tr><td><code>SearchBar</code></td><td><code>placeholder</code>, <code>value</code> (use <code>$bindState</code>)</td><td>Search input</td></tr>
+</tbody>
+</table>
 
 ### Feedback
 
-| Component | Props | Description |
-|-----------|-------|-------------|
-| `Spinner` | `size`, `color` | Loading indicator |
-| `ProgressBar` | `progress`, `color`, `trackColor` | Progress indicator |
+<table>
+<thead>
+<tr><th>Component</th><th>Props</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>Spinner</code></td><td><code>size</code>, <code>color</code></td><td>Loading indicator</td></tr>
+<tr><td><code>ProgressBar</code></td><td><code>progress</code>, <code>color</code>, <code>trackColor</code></td><td>Progress indicator</td></tr>
+</tbody>
+</table>
 
 ### Composite
 
-| Component | Props | Description |
-|-----------|-------|-------------|
-| `Card` | `title`, `subtitle`, `padding` | Card container |
-| `ListItem` | `title`, `subtitle`, `leading`, `trailing`, `action`, `actionParams` | List row |
-| `Modal` | `visible`, `title` | Bottom sheet modal |
+<table>
+<thead>
+<tr><th>Component</th><th>Props</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>Card</code></td><td><code>title</code>, <code>subtitle</code>, <code>padding</code></td><td>Card container</td></tr>
+<tr><td><code>ListItem</code></td><td><code>title</code>, <code>subtitle</code>, <code>leading</code>, <code>trailing</code>, <code>action</code>, <code>actionParams</code></td><td>List row</td></tr>
+<tr><td><code>Modal</code></td><td><code>visible</code>, <code>title</code></td><td>Bottom sheet modal</td></tr>
+</tbody>
+</table>
 
 ## Providers
 
@@ -68,11 +93,16 @@ React Native renderer with standard components, providers, and hooks.
 </StateProvider>
 ```
 
-| Prop | Type | Description |
-|------|------|-------------|
-| `store` | `StateStore` | External store (controlled mode). When provided, `initialState` and `onStateChange` are ignored. |
-| `initialState` | `Record<string, unknown>` | Initial state model (uncontrolled mode). |
-| `onStateChange` | `(changes: Array<{ path: string; value: unknown }>) => void` | Callback when state changes (uncontrolled mode). Called once per `set` or `update` with all changed entries. |
+<table>
+<thead>
+<tr><th>Prop</th><th>Type</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr><td><code>store</code></td><td><code>StateStore</code></td><td>External store (controlled mode). When provided, <code>initialState</code> and <code>onStateChange</code> are ignored.</td></tr>
+<tr><td><code>initialState</code></td><td><code>Record&lt;string, unknown&gt;</code></td><td>Initial state model (uncontrolled mode).</td></tr>
+<tr><td><code>onStateChange</code></td><td><code>{'(changes: Array<{ path: string; value: unknown }>) => void'}</code></td><td>Callback when state changes (uncontrolled mode). Called once per <code>set</code> or <code>update</code> with all changed entries.</td></tr>
+</tbody>
+</table>
 
 #### External Store (Controlled Mode)
 
@@ -190,8 +220,13 @@ import { standardComponentDefinitions, standardActionDefinitions } from "@json-r
 import { schema } from "@json-render/react-native/schema";
 ```
 
-| Export | Purpose |
-|--------|---------|
-| `standardComponentDefinitions` | Catalog definitions for all 25+ standard components |
-| `standardActionDefinitions` | Catalog definitions for standard actions (setState, navigate) |
-| `schema` | React Native element tree schema |
+<table>
+<thead>
+<tr><th>Export</th><th>Purpose</th></tr>
+</thead>
+<tbody>
+<tr><td><code>standardComponentDefinitions</code></td><td>Catalog definitions for all 25+ standard components</td></tr>
+<tr><td><code>standardActionDefinitions</code></td><td>Catalog definitions for standard actions (setState, navigate)</td></tr>
+<tr><td><code>schema</code></td><td>React Native element tree schema</td></tr>
+</tbody>
+</table>

+ 42 - 8
apps/web/app/(main)/docs/api/react/page.mdx

@@ -15,11 +15,32 @@ React components, providers, and hooks.
 </StateProvider>
 ```
 
-| Prop | Type | Description |
-|------|------|-------------|
-| `store` | `StateStore` | External store (controlled mode). When provided, `initialState` and `onStateChange` are ignored. |
-| `initialState` | `Record<string, unknown>` | Initial state model (uncontrolled mode). |
-| `onStateChange` | `(changes: Array<{ path: string; value: unknown }>) => void` | Callback when state changes (uncontrolled mode). Called once per `set` or `update` with all changed entries. |
+<table>
+  <thead>
+    <tr>
+      <th>Prop</th>
+      <th>Type</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>store</code></td>
+      <td><code>StateStore</code></td>
+      <td>External store (controlled mode). When provided, <code>initialState</code> and <code>onStateChange</code> are ignored.</td>
+    </tr>
+    <tr>
+      <td><code>initialState</code></td>
+      <td><code>Record&lt;string, unknown&gt;</code></td>
+      <td>Initial state model (uncontrolled mode).</td>
+    </tr>
+    <tr>
+      <td><code>onStateChange</code></td>
+      <td><code>{'(changes: Array<{ path: string; value: unknown }>) => void'}</code></td>
+      <td>Callback when state changes (uncontrolled mode). Called once per <code>set</code> or <code>update</code> with all changed entries.</td>
+    </tr>
+  </tbody>
+</table>
 
 #### External Store (Controlled Mode)
 
@@ -113,9 +134,22 @@ type Registry = Record<string, React.ComponentType<ComponentRenderProps>>;
 
 Convenience wrapper that combines `StateProvider`, `VisibilityProvider`, `ValidationProvider`, and `ActionProvider`. Accepts all their props plus:
 
-| Prop | Type | Description |
-|------|------|-------------|
-| `functions` | `Record<string, ComputedFunction>` | Named functions for `$computed` expressions in props |
+<table>
+  <thead>
+    <tr>
+      <th>Prop</th>
+      <th>Type</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>functions</code></td>
+      <td><code>Record&lt;string, ComputedFunction&gt;</code></td>
+      <td>Named functions for <code>$computed</code> expressions in props</td>
+    </tr>
+  </tbody>
+</table>
 
 ```tsx
 <JSONUIProvider

+ 225 - 52
apps/web/app/(main)/docs/api/shadcn/page.mdx

@@ -15,10 +15,27 @@ Your app must have Tailwind CSS configured.
 
 ## Entry Points
 
-| Entry Point | Exports | Use For |
-|-------------|---------|---------|
-| `@json-render/shadcn` | `shadcnComponents` | React implementations |
-| `@json-render/shadcn/catalog` | `shadcnComponentDefinitions` | Catalog schemas (no React dependency, safe for server) |
+<table>
+<thead>
+<tr>
+<th>Entry Point</th>
+<th>Exports</th>
+<th>Use For</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>@json-render/shadcn</code></td>
+<td><code>shadcnComponents</code></td>
+<td>React implementations</td>
+</tr>
+<tr>
+<td><code>@json-render/shadcn/catalog</code></td>
+<td><code>shadcnComponentDefinitions</code></td>
+<td>Catalog schemas (no React dependency, safe for server)</td>
+</tr>
+</tbody>
+</table>
 
 ## Usage
 
@@ -103,69 +120,225 @@ const { registry } = defineRegistry(catalog, {
 
 ### Layout
 
-| Component | Description |
-|-----------|-------------|
-| `Card` | Container card with optional title, description, maxWidth, centered |
-| `Stack` | Flex container with direction, gap, align, justify |
-| `Grid` | Grid layout with columns (1-6) and gap |
-| `Separator` | Visual separator line with orientation |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Card</code></td>
+<td>Container card with optional title, description, maxWidth, centered</td>
+</tr>
+<tr>
+<td><code>Stack</code></td>
+<td>Flex container with direction, gap, align, justify</td>
+</tr>
+<tr>
+<td><code>Grid</code></td>
+<td>Grid layout with columns (1-6) and gap</td>
+</tr>
+<tr>
+<td><code>Separator</code></td>
+<td>Visual separator line with orientation</td>
+</tr>
+</tbody>
+</table>
 
 ### Navigation
 
-| Component | Description |
-|-----------|-------------|
-| `Tabs` | Tabbed navigation with tabs array, defaultValue, value |
-| `Accordion` | Collapsible sections with items array and type (single/multiple) |
-| `Collapsible` | Single collapsible section with title and defaultOpen |
-| `Pagination` | Page navigation with totalPages and page |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Tabs</code></td>
+<td>Tabbed navigation with tabs array, defaultValue, value</td>
+</tr>
+<tr>
+<td><code>Accordion</code></td>
+<td>Collapsible sections with items array and type (single/multiple)</td>
+</tr>
+<tr>
+<td><code>Collapsible</code></td>
+<td>Single collapsible section with title and defaultOpen</td>
+</tr>
+<tr>
+<td><code>Pagination</code></td>
+<td>Page navigation with totalPages and page</td>
+</tr>
+</tbody>
+</table>
 
 ### Overlay
 
-| Component | Description |
-|-----------|-------------|
-| `Dialog` | Modal dialog with title, description, openPath |
-| `Drawer` | Bottom drawer with title, description, openPath |
-| `Tooltip` | Hover tooltip with content and text |
-| `Popover` | Click-triggered popover with trigger and content |
-| `DropdownMenu` | Dropdown menu with label and items array |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Dialog</code></td>
+<td>Modal dialog with title, description, openPath</td>
+</tr>
+<tr>
+<td><code>Drawer</code></td>
+<td>Bottom drawer with title, description, openPath</td>
+</tr>
+<tr>
+<td><code>Tooltip</code></td>
+<td>Hover tooltip with content and text</td>
+</tr>
+<tr>
+<td><code>Popover</code></td>
+<td>Click-triggered popover with trigger and content</td>
+</tr>
+<tr>
+<td><code>DropdownMenu</code></td>
+<td>Dropdown menu with label and items array</td>
+</tr>
+</tbody>
+</table>
 
 ### Content
 
-| Component | Description |
-|-----------|-------------|
-| `Heading` | Heading text with level (h1-h4) |
-| `Text` | Paragraph with variant (body, caption, muted, lead, code) |
-| `Image` | Image with alt, width, height |
-| `Avatar` | User avatar with src, name, size |
-| `Badge` | Status badge with text and variant |
-| `Alert` | Alert banner with title, message, type |
-| `Carousel` | Horizontally scrollable carousel with items |
-| `Table` | Data table with columns and rows |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Heading</code></td>
+<td>Heading text with level (h1-h4)</td>
+</tr>
+<tr>
+<td><code>Text</code></td>
+<td>Paragraph with variant (body, caption, muted, lead, code)</td>
+</tr>
+<tr>
+<td><code>Image</code></td>
+<td>Image with alt, width, height</td>
+</tr>
+<tr>
+<td><code>Avatar</code></td>
+<td>User avatar with src, name, size</td>
+</tr>
+<tr>
+<td><code>Badge</code></td>
+<td>Status badge with text and variant</td>
+</tr>
+<tr>
+<td><code>Alert</code></td>
+<td>Alert banner with title, message, type</td>
+</tr>
+<tr>
+<td><code>Carousel</code></td>
+<td>Horizontally scrollable carousel with items</td>
+</tr>
+<tr>
+<td><code>Table</code></td>
+<td>Data table with columns and rows</td>
+</tr>
+</tbody>
+</table>
 
 ### Feedback
 
-| Component | Description |
-|-----------|-------------|
-| `Progress` | Progress bar with value, max, label |
-| `Skeleton` | Loading placeholder with width, height, rounded |
-| `Spinner` | Loading spinner with size and label |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Progress</code></td>
+<td>Progress bar with value, max, label</td>
+</tr>
+<tr>
+<td><code>Skeleton</code></td>
+<td>Loading placeholder with width, height, rounded</td>
+</tr>
+<tr>
+<td><code>Spinner</code></td>
+<td>Loading spinner with size and label</td>
+</tr>
+</tbody>
+</table>
 
 ### Input
 
-| Component | Description |
-|-----------|-------------|
-| `Button` | Clickable button with label, variant, disabled |
-| `Link` | Anchor link with label and href |
-| `Input` | Text input with label, name, type, placeholder, value, checks |
-| `Textarea` | Multi-line text input with label, name, placeholder, rows, value, checks |
-| `Select` | Dropdown select with label, name, options, value, checks |
-| `Checkbox` | Checkbox with label, name, checked |
-| `Radio` | Radio button group with label, name, options, value |
-| `Switch` | Toggle switch with label, name, checked |
-| `Slider` | Range slider with label, min, max, step, value |
-| `Toggle` | Toggle button with label, pressed, variant |
-| `ToggleGroup` | Group of toggle buttons with items, type, value |
-| `ButtonGroup` | Group of buttons with buttons array and selected |
+<table>
+<thead>
+<tr>
+<th>Component</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>Button</code></td>
+<td>Clickable button with label, variant, disabled</td>
+</tr>
+<tr>
+<td><code>Link</code></td>
+<td>Anchor link with label and href</td>
+</tr>
+<tr>
+<td><code>Input</code></td>
+<td>Text input with label, name, type, placeholder, value, checks</td>
+</tr>
+<tr>
+<td><code>Textarea</code></td>
+<td>Multi-line text input with label, name, placeholder, rows, value, checks</td>
+</tr>
+<tr>
+<td><code>Select</code></td>
+<td>Dropdown select with label, name, options, value, checks</td>
+</tr>
+<tr>
+<td><code>Checkbox</code></td>
+<td>Checkbox with label, name, checked</td>
+</tr>
+<tr>
+<td><code>Radio</code></td>
+<td>Radio button group with label, name, options, value</td>
+</tr>
+<tr>
+<td><code>Switch</code></td>
+<td>Toggle switch with label, name, checked</td>
+</tr>
+<tr>
+<td><code>Slider</code></td>
+<td>Range slider with label, min, max, step, value</td>
+</tr>
+<tr>
+<td><code>Toggle</code></td>
+<td>Toggle button with label, pressed, variant</td>
+</tr>
+<tr>
+<td><code>ToggleGroup</code></td>
+<td>Group of toggle buttons with items, type, value</td>
+</tr>
+<tr>
+<td><code>ButtonGroup</code></td>
+<td>Group of buttons with buttons array and selected</td>
+</tr>
+</tbody>
+</table>
 
 ## Notes
 

+ 110 - 19
apps/web/app/(main)/docs/api/vue/page.mdx

@@ -15,11 +15,32 @@ Vue 3 components, providers, and composables.
 </StateProvider>
 ```
 
-| Prop | Type | Description |
-|------|------|-------------|
-| `store` | `StateStore` | External store (controlled mode). When provided, `initialState` and `onStateChange` are ignored. |
-| `initialState` | `Record<string, unknown>` | Initial state model (uncontrolled mode). |
-| `onStateChange` | `(changes: Array<{ path: string; value: unknown }>) => void` | Callback when state changes (uncontrolled mode). Called once per `set` or `update` with all changed entries. |
+<table>
+  <thead>
+    <tr>
+      <th>Prop</th>
+      <th>Type</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>store</code></td>
+      <td><code>StateStore</code></td>
+      <td>External store (controlled mode). When provided, <code>initialState</code> and <code>onStateChange</code> are ignored.</td>
+    </tr>
+    <tr>
+      <td><code>initialState</code></td>
+      <td><code>Record&lt;string, unknown&gt;</code></td>
+      <td>Initial state model (uncontrolled mode).</td>
+    </tr>
+    <tr>
+      <td><code>onStateChange</code></td>
+      <td><code>{'(changes: Array<{ path: string; value: unknown }>) => void'}</code></td>
+      <td>Callback when state changes (uncontrolled mode). Called once per <code>set</code> or <code>update</code> with all changed entries.</td>
+    </tr>
+  </tbody>
+</table>
 
 #### External Store (Controlled Mode)
 
@@ -230,17 +251,87 @@ const {
 
 ## Differences from `@json-render/react`
 
-| API | React | Vue | Note |
-|-----|-------|-----|------|
-| `useStateStore().state` | `StateModel` (plain object) | `ShallowRef<StateModel>` | Vue reactivity; use `state.value` |
-| `useStateValue()` | `T \| undefined` | `ComputedRef<T \| undefined>` | Vue reactivity; use `.value` |
-| `useStateBinding()` | `[T \| undefined, setter]` | `[ComputedRef<T \| undefined>, setter]` | Vue reactivity; use `value.value` |
-| `useAction().isLoading` | `boolean` | `ComputedRef<boolean>` | Vue reactivity; use `.value` |
-| `useFieldValidation().state` | `FieldValidationState` | `ComputedRef<FieldValidationState>` | Vue reactivity; use `.value` |
-| `useFieldValidation().errors` | `string[]` | `ComputedRef<string[]>` | Vue reactivity; use `.value` |
-| `useFieldValidation().isValid` | `boolean` | `ComputedRef<boolean>` | Vue reactivity; use `.value` |
-| `VisibilityContextValue.ctx` | `CoreVisibilityContext` | `ComputedRef<CoreVisibilityContext>` | Vue reactivity; use `ctx.value` |
-| `children` type | `React.ReactNode` | `VNode \| VNode[]` | Platform-specific |
-| `useBoundProp` | exported | exported | Same API; returns `[value, setValue]` |
-| `VisibilityProviderProps` | exported | not exported (no props) | Vue uses slot, no prop needed |
-| Streaming hooks | `useUIStream`, `useChatUI` | `useUIStream`, `useChatUI` | Same API; returns Vue `Ref` values |
+<table>
+  <thead>
+    <tr>
+      <th>API</th>
+      <th>React</th>
+      <th>Vue</th>
+      <th>Note</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>useStateStore().state</code></td>
+      <td><code>StateModel</code> (plain object)</td>
+      <td><code>ShallowRef&lt;StateModel&gt;</code></td>
+      <td>Vue reactivity; use <code>state.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useStateValue()</code></td>
+      <td><code>T | undefined</code></td>
+      <td><code>ComputedRef&lt;T | undefined&gt;</code></td>
+      <td>Vue reactivity; use <code>.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useStateBinding()</code></td>
+      <td><code>[T | undefined, setter]</code></td>
+      <td><code>[ComputedRef&lt;T | undefined&gt;, setter]</code></td>
+      <td>Vue reactivity; use <code>value.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useAction().isLoading</code></td>
+      <td><code>boolean</code></td>
+      <td><code>ComputedRef&lt;boolean&gt;</code></td>
+      <td>Vue reactivity; use <code>.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useFieldValidation().state</code></td>
+      <td><code>FieldValidationState</code></td>
+      <td><code>ComputedRef&lt;FieldValidationState&gt;</code></td>
+      <td>Vue reactivity; use <code>.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useFieldValidation().errors</code></td>
+      <td><code>string[]</code></td>
+      <td><code>ComputedRef&lt;string[]&gt;</code></td>
+      <td>Vue reactivity; use <code>.value</code></td>
+    </tr>
+    <tr>
+      <td><code>useFieldValidation().isValid</code></td>
+      <td><code>boolean</code></td>
+      <td><code>ComputedRef&lt;boolean&gt;</code></td>
+      <td>Vue reactivity; use <code>.value</code></td>
+    </tr>
+    <tr>
+      <td><code>VisibilityContextValue.ctx</code></td>
+      <td><code>CoreVisibilityContext</code></td>
+      <td><code>ComputedRef&lt;CoreVisibilityContext&gt;</code></td>
+      <td>Vue reactivity; use <code>ctx.value</code></td>
+    </tr>
+    <tr>
+      <td><code>children</code> type</td>
+      <td><code>React.ReactNode</code></td>
+      <td><code>VNode | VNode[]</code></td>
+      <td>Platform-specific</td>
+    </tr>
+    <tr>
+      <td><code>useBoundProp</code></td>
+      <td>exported</td>
+      <td>exported</td>
+      <td>Same API; returns <code>[value, setValue]</code></td>
+    </tr>
+    <tr>
+      <td><code>VisibilityProviderProps</code></td>
+      <td>exported</td>
+      <td>not exported (no props)</td>
+      <td>Vue uses slot, no prop needed</td>
+    </tr>
+    <tr>
+      <td>Streaming hooks</td>
+      <td><code>useUIStream</code>, <code>useChatUI</code></td>
+      <td><code>useUIStream</code>, <code>useChatUI</code></td>
+      <td>Same API; returns Vue <code>Ref</code> values</td>
+    </tr>
+  </tbody>
+</table>

+ 96 - 31
apps/web/app/(main)/docs/migration/page.mdx

@@ -31,15 +31,23 @@ import { StateProvider } from "@json-render/react";
 
 `StateProvider` now manages state internally. Use `useStateStore()` to access `get`, `set`, and `update`.
 
-| Before | After |
-|--------|-------|
-| `DataProvider` | `StateProvider` |
-| `data` prop | `initialState` prop |
-| `getValue` / `setValue` props | Removed (use `useStateStore()` hook for `get` / `set`) |
-| `useData` | `useStateStore` |
-| `useDataValue` | `useStateValue` |
-| `useDataBinding` | `useStateBinding` (deprecated, use `useBoundProp` instead) |
-| `DataModel` type | `StateModel` type |
+<table>
+<thead>
+<tr>
+<th>Before</th>
+<th>After</th>
+</tr>
+</thead>
+<tbody>
+<tr><td><code>DataProvider</code></td><td><code>StateProvider</code></td></tr>
+<tr><td><code>data</code> prop</td><td><code>initialState</code> prop</td></tr>
+<tr><td><code>getValue</code> / <code>setValue</code> props</td><td>Removed (use <code>useStateStore()</code> hook for <code>get</code> / <code>set</code>)</td></tr>
+<tr><td><code>useData</code></td><td><code>useStateStore</code></td></tr>
+<tr><td><code>useDataValue</code></td><td><code>useStateValue</code></td></tr>
+<tr><td><code>useDataBinding</code></td><td><code>useStateBinding</code> (deprecated, use <code>useBoundProp</code> instead)</td></tr>
+<tr><td><code>DataModel</code> type</td><td><code>StateModel</code> type</td></tr>
+</tbody>
+</table>
 
 ## Dynamic Expressions
 
@@ -81,10 +89,18 @@ Inside repeat scopes, use `$item` and `$index`:
 }
 ```
 
-| Before | After |
-|--------|-------|
-| `{ "$path": "/..." }` | `{ "$state": "/..." }` |
-| `{ "$data": "/..." }` | `{ "$state": "/..." }` |
+<table>
+<thead>
+<tr>
+<th>Before</th>
+<th>After</th>
+</tr>
+</thead>
+<tbody>
+<tr><td><code>{'{ "$path": "/..." }'}</code></td><td><code>{'{ "$state": "/..." }'}</code></td></tr>
+<tr><td><code>{'{ "$data": "/..." }'}</code></td><td><code>{'{ "$state": "/..." }'}</code></td></tr>
+</tbody>
+</table>
 
 ## Two-Way Binding
 
@@ -315,11 +331,19 @@ const chatPrompt = catalog.prompt({ mode: "chat" });
 { "type": "minLength", "args": { "min": 8 }, "message": "Too short" }
 ```
 
-| Before | After |
-|--------|-------|
-| `{ fn: "required" }` | `{ type: "required" }` |
-| `ValidationProvider functions={...}` | `ValidationProvider customFunctions={...}` |
-| `useFieldValidation(path, checks)` | `useFieldValidation(path, config)` where config is `{ checks, validateOn? }` |
+<table>
+<thead>
+<tr>
+<th>Before</th>
+<th>After</th>
+</tr>
+</thead>
+<tbody>
+<tr><td><code>{'{ fn: "required" }'}</code></td><td><code>{'{ type: "required" }'}</code></td></tr>
+<tr><td><code>{'ValidationProvider functions={...}'}</code></td><td><code>{'ValidationProvider customFunctions={...}'}</code></td></tr>
+<tr><td><code>useFieldValidation(path, checks)</code></td><td><code>useFieldValidation(path, config)</code> where config is <code>{'{ checks, validateOn? }'}</code></td></tr>
+</tbody>
+</table>
 
 ## Visibility Provider
 
@@ -398,16 +422,57 @@ Action params in specs now use `statePath` instead of `path`.
 
 The following exports have been removed from `@json-render/core`:
 
-| Removed | Replacement |
-|---------|-------------|
-| `createCatalog` | `defineCatalog(schema, config)` |
-| `generateCatalogPrompt` | `catalog.prompt()` |
-| `generateSystemPrompt` | `catalog.prompt()` |
-| `ComponentDefinition` | Use catalog component config directly |
-| `CatalogConfig` | Use `defineCatalog` parameters |
-| `SystemPromptOptions` | Use `PromptOptions` |
-| `LogicExpression` | Use `VisibilityCondition` |
-| `AuthState` | Model auth as regular state (e.g. `/auth/isSignedIn`) |
-| `evaluateLogicExpression` | Use `evaluateVisibility` |
-| `createRendererFromCatalog` | Use `defineRegistry` |
-| `traverseTree` (codegen) | Use `traverseSpec` |
+<table>
+  <thead>
+    <tr>
+      <th>Removed</th>
+      <th>Replacement</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>createCatalog</code></td>
+      <td><code>defineCatalog(schema, config)</code></td>
+    </tr>
+    <tr>
+      <td><code>generateCatalogPrompt</code></td>
+      <td><code>catalog.prompt()</code></td>
+    </tr>
+    <tr>
+      <td><code>generateSystemPrompt</code></td>
+      <td><code>catalog.prompt()</code></td>
+    </tr>
+    <tr>
+      <td><code>ComponentDefinition</code></td>
+      <td>Use catalog component config directly</td>
+    </tr>
+    <tr>
+      <td><code>CatalogConfig</code></td>
+      <td>Use <code>defineCatalog</code> parameters</td>
+    </tr>
+    <tr>
+      <td><code>SystemPromptOptions</code></td>
+      <td>Use <code>PromptOptions</code></td>
+    </tr>
+    <tr>
+      <td><code>LogicExpression</code></td>
+      <td>Use <code>VisibilityCondition</code></td>
+    </tr>
+    <tr>
+      <td><code>AuthState</code></td>
+      <td>Model auth as regular state (e.g. <code>/auth/isSignedIn</code>)</td>
+    </tr>
+    <tr>
+      <td><code>evaluateLogicExpression</code></td>
+      <td>Use <code>evaluateVisibility</code></td>
+    </tr>
+    <tr>
+      <td><code>createRendererFromCatalog</code></td>
+      <td>Use <code>defineRegistry</code></td>
+    </tr>
+    <tr>
+      <td><code>traverseTree</code> (codegen)</td>
+      <td>Use <code>traverseSpec</code></td>
+    </tr>
+  </tbody>
+</table>

+ 21 - 4
apps/web/app/(main)/docs/watchers/page.mdx

@@ -136,10 +136,27 @@ An element can watch multiple state paths. Each path maps to one or more action
 
 ## When to Use `watch` vs `on`
 
-| Mechanism | Trigger | Use Case |
-|-----------|---------|----------|
-| `on` | User interaction (press, change, blur) | Button clicks, input changes, form submissions |
-| `watch` | State value change (any source) | Cascading data, derived state, cross-field sync |
+<table>
+<thead>
+<tr>
+<th>Mechanism</th>
+<th>Trigger</th>
+<th>Use Case</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>on</code></td>
+<td>User interaction (press, change, blur)</td>
+<td>Button clicks, input changes, form submissions</td>
+</tr>
+<tr>
+<td><code>watch</code></td>
+<td>State value change (any source)</td>
+<td>Cascading data, derived state, cross-field sync</td>
+</tr>
+</tbody>
+</table>
 
 Use `on` when reacting to direct user actions. Use `watch` when a state change (from any source — user input, action handler, or external store update) should trigger side effects.