Chris Tate 3 months ago
parent
commit
519a538

+ 12 - 0
.changeset/v0-16-release.md

@@ -0,0 +1,12 @@
+---
+"@json-render/core": minor
+"@json-render/next": minor
+"@json-render/shadcn-svelte": minor
+---
+
+Add Next.js renderer and shadcn-svelte component library.
+
+### New:
+
+- **`@json-render/next`** -- Next.js renderer that turns JSON specs into full Next.js applications with routes, layouts, SSR, metadata, data loaders, and static generation. Client and server entry points at `@json-render/next` and `@json-render/next/server`. Includes built-in `Link`, `Slot`, error boundary, loading, and not-found components.
+- **`@json-render/shadcn-svelte`** -- Pre-built shadcn-svelte components for json-render Svelte apps. 36 components built on Svelte 5 + Tailwind CSS with state binding, validation, and action support. Server-safe catalog at `@json-render/shadcn-svelte/catalog`.

+ 75 - 0
README.md

@@ -127,6 +127,7 @@ function Dashboard({ spec }) {
 | `@json-render/svelte`       | Svelte 5 renderer with runes-based reactivity                          |
 | `@json-render/solid`        | SolidJS renderer with fine-grained reactive contexts                   |
 | `@json-render/shadcn`       | 36 pre-built shadcn/ui components (Radix UI + Tailwind CSS)            |
+| `@json-render/shadcn-svelte`| 36 pre-built shadcn-svelte components (Svelte 5 + Tailwind CSS)        |
 | `@json-render/react-three-fiber` | React Three Fiber renderer for 3D scenes (19 built-in components)  |
 | `@json-render/react-native` | React Native renderer with standard mobile components                  |
 | `@json-render/next`         | Next.js renderer — JSON becomes full apps with routes, layouts, SSR    |
@@ -485,6 +486,80 @@ const { registry } = defineRegistry(catalog, {
 />;
 ```
 
+### Next.js (Full Apps)
+
+```typescript
+import type { NextAppSpec } from "@json-render/next";
+import { createNextApp } from "@json-render/next/server";
+import { NextAppProvider } from "@json-render/next";
+
+const spec: NextAppSpec = {
+  metadata: { title: { default: "My App", template: "%s | My App" } },
+  layouts: {
+    main: {
+      root: "shell",
+      elements: {
+        shell: { type: "Container", props: {}, children: ["nav", "slot"] },
+        nav: { type: "NavBar", props: {}, children: [] },
+        slot: { type: "Slot", props: {}, children: [] },
+      },
+    },
+  },
+  routes: {
+    "/": {
+      layout: "main",
+      metadata: { title: "Home" },
+      page: {
+        root: "hero",
+        elements: {
+          hero: { type: "Card", props: { title: "Welcome" }, children: [] },
+        },
+      },
+    },
+  },
+};
+
+// Server: creates Page, generateMetadata, generateStaticParams
+const app = createNextApp({ spec });
+
+// Client: wrap your layout with NextAppProvider
+// <NextAppProvider registry={registry} handlers={handlers}>
+//   {children}
+// </NextAppProvider>
+```
+
+### shadcn-svelte (Svelte)
+
+```typescript
+import { defineCatalog } from "@json-render/core";
+import { schema } from "@json-render/svelte/schema";
+import { defineRegistry, Renderer } from "@json-render/svelte";
+import { shadcnComponentDefinitions } from "@json-render/shadcn-svelte/catalog";
+import { shadcnComponents } from "@json-render/shadcn-svelte";
+
+const catalog = defineCatalog(schema, {
+  components: {
+    Card: shadcnComponentDefinitions.Card,
+    Stack: shadcnComponentDefinitions.Stack,
+    Heading: shadcnComponentDefinitions.Heading,
+    Button: shadcnComponentDefinitions.Button,
+  },
+  actions: {},
+});
+
+const { registry } = defineRegistry(catalog, {
+  components: {
+    Card: shadcnComponents.Card,
+    Stack: shadcnComponents.Stack,
+    Heading: shadcnComponents.Heading,
+    Button: shadcnComponents.Button,
+  },
+});
+
+// In your Svelte component:
+// <Renderer spec={spec} registry={registry} />
+```
+
 ### Ink (Terminal)
 
 ```tsx

+ 320 - 0
apps/web/app/(main)/docs/api/shadcn-svelte/page.mdx

@@ -0,0 +1,320 @@
+import { pageMetadata } from "@/lib/page-metadata"
+export const metadata = pageMetadata("docs/api/shadcn-svelte")
+
+# @json-render/shadcn-svelte
+
+Pre-built [shadcn-svelte](https://www.shadcn-svelte.com/) components for json-render. 36 components built on Svelte 5 + Tailwind CSS, ready to use with `defineCatalog` and `defineRegistry`.
+
+## Installation
+
+```bash
+npm install @json-render/shadcn-svelte @json-render/core @json-render/svelte zod
+```
+
+Your app must have Tailwind CSS configured.
+
+## Entry Points
+
+<table>
+<thead>
+<tr>
+<th>Entry Point</th>
+<th>Exports</th>
+<th>Use For</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>@json-render/shadcn-svelte</code></td>
+<td><code>shadcnComponents</code>, <code>shadcnComponentDefinitions</code></td>
+<td>Svelte implementations + catalog schemas</td>
+</tr>
+<tr>
+<td><code>@json-render/shadcn-svelte/catalog</code></td>
+<td><code>shadcnComponentDefinitions</code></td>
+<td>Catalog schemas only (no Svelte dependency, safe for server)</td>
+</tr>
+</tbody>
+</table>
+
+## Usage
+
+Pick the components you need from the standard definitions:
+
+```typescript
+import { defineCatalog } from "@json-render/core";
+import { schema } from "@json-render/svelte/schema";
+import { shadcnComponentDefinitions } from "@json-render/shadcn-svelte/catalog";
+import { defineRegistry } from "@json-render/svelte";
+import { shadcnComponents } from "@json-render/shadcn-svelte";
+
+// Catalog: pick definitions
+const catalog = defineCatalog(schema, {
+  components: {
+    Card: shadcnComponentDefinitions.Card,
+    Stack: shadcnComponentDefinitions.Stack,
+    Heading: shadcnComponentDefinitions.Heading,
+    Button: shadcnComponentDefinitions.Button,
+    Input: shadcnComponentDefinitions.Input,
+  },
+  actions: {},
+});
+
+// Registry: pick matching implementations
+const { registry } = defineRegistry(catalog, {
+  components: {
+    Card: shadcnComponents.Card,
+    Stack: shadcnComponents.Stack,
+    Heading: shadcnComponents.Heading,
+    Button: shadcnComponents.Button,
+    Input: shadcnComponents.Input,
+  },
+});
+```
+
+Then render in your Svelte component:
+
+```svelte
+<script lang="ts">
+  import { Renderer, JsonUIProvider } from "@json-render/svelte";
+
+  export let spec;
+  export let registry;
+</script>
+
+<JsonUIProvider initialState={spec?.state ?? {}}>
+  <Renderer {spec} {registry} />
+</JsonUIProvider>
+```
+
+## Available Components
+
+### Layout
+
+<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
+
+<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
+
+<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
+
+<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
+
+<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
+
+<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
+
+- The `/catalog` entry point has no Svelte dependency -- use it for server-side prompt generation
+- Components use Tailwind CSS classes -- your app must have Tailwind configured
+- Component implementations use bundled shadcn-svelte primitives (not your app's `$lib/components/ui/`)
+- Form inputs support `checks` for validation (type + message pairs) and `validateOn` for timing
+- Events: inputs emit `change`/`submit`/`focus`/`blur`; buttons emit `press`; selects emit `change`/`select`

+ 2 - 2
apps/web/app/api/docs-chat/route.ts

@@ -16,8 +16,8 @@ const SYSTEM_PROMPT = `You are a helpful documentation assistant for json-render
 
 GitHub repository: https://github.com/vercel-labs/json-render
 Documentation: https://json-render.dev/docs
-npm packages: @json-render/core, @json-render/react, @json-render/next, @json-render/ink, @json-render/vue, @json-render/svelte, @json-render/solid, @json-render/shadcn, @json-render/react-three-fiber, @json-render/react-native, @json-render/react-email, @json-render/react-pdf, @json-render/image, @json-render/remotion, @json-render/codegen, @json-render/mcp, @json-render/redux, @json-render/zustand, @json-render/jotai, @json-render/xstate, @json-render/yaml
-Skills: json-render ships AI agent skills that teach coding agents how to use each package. Install with "npx skills add vercel-labs/json-render --skill <name>". Available skills: core, react, next, ink, react-pdf, react-email, react-native, shadcn, react-three-fiber, image, remotion, vue, svelte, solid, codegen, mcp, redux, zustand, jotai, xstate, yaml. See /docs/skills for details.
+npm packages: @json-render/core, @json-render/react, @json-render/next, @json-render/ink, @json-render/vue, @json-render/svelte, @json-render/solid, @json-render/shadcn, @json-render/shadcn-svelte, @json-render/react-three-fiber, @json-render/react-native, @json-render/react-email, @json-render/react-pdf, @json-render/image, @json-render/remotion, @json-render/codegen, @json-render/mcp, @json-render/redux, @json-render/zustand, @json-render/jotai, @json-render/xstate, @json-render/yaml
+Skills: json-render ships AI agent skills that teach coding agents how to use each package. Install with "npx skills add vercel-labs/json-render --skill <name>". Available skills: core, react, next, ink, react-pdf, react-email, react-native, shadcn, shadcn-svelte, react-three-fiber, image, remotion, vue, svelte, solid, codegen, mcp, redux, zustand, jotai, xstate, yaml. See /docs/skills for details.
 
 You have access to the full json-render documentation via the bash and readFile tools. The docs are available as markdown files in the /workspace/docs/ directory.
 

+ 1 - 0
apps/web/lib/docs-navigation.ts

@@ -73,6 +73,7 @@ export const docsNavigation: NavSection[] = [
       { title: "@json-render/react-pdf", href: "/docs/api/react-pdf" },
       { title: "@json-render/react-email", href: "/docs/api/react-email" },
       { title: "@json-render/shadcn", href: "/docs/api/shadcn" },
+      { title: "@json-render/shadcn-svelte", href: "/docs/api/shadcn-svelte" },
       { title: "@json-render/react-native", href: "/docs/api/react-native" },
       { title: "@json-render/image", href: "/docs/api/image" },
       { title: "@json-render/remotion", href: "/docs/api/remotion" },

+ 1 - 0
apps/web/lib/page-titles.ts

@@ -54,6 +54,7 @@ export const PAGE_TITLES: Record<string, string> = {
   "docs/api/image": "@json-render/image API",
   "docs/api/remotion": "@json-render/remotion API",
   "docs/api/shadcn": "@json-render/shadcn API",
+  "docs/api/shadcn-svelte": "@json-render/shadcn-svelte API",
   "docs/api/mcp": "@json-render/mcp API",
   "docs/api/redux": "@json-render/redux API",
   "docs/api/zustand": "@json-render/zustand API",

+ 130 - 0
skills/shadcn-svelte/SKILL.md

@@ -0,0 +1,130 @@
+---
+name: shadcn-svelte
+description: Pre-built shadcn-svelte components for json-render Svelte apps. Use when working with @json-render/shadcn-svelte, adding standard UI components to a Svelte catalog, or building Svelte web UIs with shadcn-svelte + Tailwind CSS components.
+---
+
+# @json-render/shadcn-svelte
+
+Pre-built shadcn-svelte component definitions and implementations for json-render. Provides 36 components built on Svelte 5 + Tailwind CSS.
+
+## Two Entry Points
+
+| Entry Point | Exports | Use For |
+|-------------|---------|---------|
+| `@json-render/shadcn-svelte/catalog` | `shadcnComponentDefinitions` | Catalog schemas (no Svelte dependency, safe for server) |
+| `@json-render/shadcn-svelte` | `shadcnComponents`, `shadcnComponentDefinitions` | Svelte implementations + catalog schemas |
+
+## Usage Pattern
+
+Pick the components you need from the standard definitions. Do not spread all definitions -- explicitly select what your app uses:
+
+```typescript
+import { defineCatalog } from "@json-render/core";
+import { schema } from "@json-render/svelte/schema";
+import { shadcnComponentDefinitions } from "@json-render/shadcn-svelte/catalog";
+import { defineRegistry } from "@json-render/svelte";
+import { shadcnComponents } from "@json-render/shadcn-svelte";
+
+// Catalog: pick definitions
+const catalog = defineCatalog(schema, {
+  components: {
+    Card: shadcnComponentDefinitions.Card,
+    Stack: shadcnComponentDefinitions.Stack,
+    Heading: shadcnComponentDefinitions.Heading,
+    Button: shadcnComponentDefinitions.Button,
+    Input: shadcnComponentDefinitions.Input,
+  },
+  actions: {},
+});
+
+// Registry: pick matching implementations
+const { registry } = defineRegistry(catalog, {
+  components: {
+    Card: shadcnComponents.Card,
+    Stack: shadcnComponents.Stack,
+    Heading: shadcnComponents.Heading,
+    Button: shadcnComponents.Button,
+    Input: shadcnComponents.Input,
+  },
+});
+```
+
+Then render in your Svelte component:
+
+```svelte
+<script lang="ts">
+  import { Renderer, JsonUIProvider } from "@json-render/svelte";
+
+  export let spec;
+  export let registry;
+</script>
+
+<JsonUIProvider initialState={spec?.state ?? {}}>
+  <Renderer {spec} {registry} />
+</JsonUIProvider>
+```
+
+## Available Components
+
+### Layout
+- **Card** - Container with optional title, description, maxWidth, centered
+- **Stack** - Flex container with direction, gap, align, justify
+- **Grid** - Grid layout with columns (number) and gap
+- **Separator** - Visual divider with orientation
+
+### Navigation
+- **Tabs** - Tabbed navigation with tabs array, defaultValue, value
+- **Accordion** - Collapsible sections with items array and type (single/multiple)
+- **Collapsible** - Single collapsible section with title
+- **Pagination** - Page navigation with totalPages and page
+
+### Overlay
+- **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 with label and items array
+
+### Content
+- **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 (default, secondary, destructive, outline)
+- **Alert** - Alert banner with title, message, type (success, warning, info, error)
+- **Carousel** - Scrollable carousel with items array
+- **Table** - Data table with columns (string[]) and rows (string[][])
+
+### Feedback
+- **Progress** - Progress bar with value, max, label
+- **Skeleton** - Loading placeholder with width, height, rounded
+- **Spinner** - Loading spinner with size and label
+
+### Input
+- **Button** - Button with label, variant (primary, secondary, danger), disabled
+- **Link** - Anchor link with label and href
+- **Input** - Text input with label, name, type, placeholder, value, checks
+- **Textarea** - Multi-line input with label, name, placeholder, rows, value, checks
+- **Select** - Dropdown select with label, name, options (string[]), value, checks
+- **Checkbox** - Checkbox with label, name, checked, checks, validateOn
+- **Radio** - Radio group with label, name, options (string[]), value, checks, validateOn
+- **Switch** - Toggle switch with label, name, checked, checks, validateOn
+- **Slider** - Range slider with label, min, max, step, value
+- **Toggle** - Toggle button with label, pressed, variant
+- **ToggleGroup** - Group of toggles with items, type, value
+- **ButtonGroup** - Button group with buttons array and selected
+
+## Validation Timing (`validateOn`)
+
+All form components support `validateOn` to control when validation runs:
+- `"change"` -- validate on every input change (default for Select, Checkbox, Radio, Switch)
+- `"blur"` -- validate when field loses focus (default for Input, Textarea)
+- `"submit"` -- validate only on form submission
+
+## Important Notes
+
+- The `/catalog` entry point has no Svelte dependency -- use it for server-side prompt generation
+- Components use Tailwind CSS classes -- your app must have Tailwind configured
+- Component implementations use bundled shadcn-svelte primitives (not your app's `$lib/components/ui/`)
+- All form inputs support `checks` for validation (type + message pairs) and `validateOn` for timing
+- Events: inputs emit `change`/`submit`/`focus`/`blur`; buttons emit `press`; selects emit `change`/`select`