| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- import { pageMetadata } from "@/lib/page-metadata"
- export const metadata = pageMetadata("docs/api/next")
- # @json-render/next
- Next.js renderer. JSON becomes full Next.js applications with routes, layouts, metadata, and SSR.
- ## Installation
- ```bash
- npm install @json-render/core @json-render/react @json-render/next
- ```
- ## schema
- The Next.js app schema for multi-page specs. Use with `defineCatalog` from core.
- ```typescript
- import { defineCatalog } from '@json-render/core';
- import { schema } from '@json-render/next/server';
- import { z } from 'zod';
- const catalog = defineCatalog(schema, {
- components: {
- Card: {
- props: z.object({ title: z.string() }),
- description: 'Card container',
- },
- NavBar: {
- props: z.object({ links: z.array(z.object({ href: z.string(), label: z.string() })) }),
- description: 'Navigation bar',
- },
- },
- actions: {},
- });
- ```
- ## createNextApp
- Create all exports needed for a Next.js `[[...slug]]` catch-all route.
- ```typescript
- import { createNextApp } from '@json-render/next/server';
- const { Page, generateMetadata, generateStaticParams } = createNextApp({
- spec: myAppSpec,
- loaders: {
- loadPost: async ({ slug }) => {
- const post = await db.post.findUnique({ where: { slug } });
- return { post };
- },
- },
- });
- ```
- ### Options
- <table>
- <thead>
- <tr>
- <th>Option</th>
- <th>Type</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>spec</code></td>
- <td><code>{'NextAppSpec | (() => NextAppSpec | Promise<NextAppSpec>)'}</code></td>
- <td>The application spec (static or dynamic)</td>
- </tr>
- <tr>
- <td><code>loaders</code></td>
- <td><code>{'Record<string, LoaderFn>'}</code></td>
- <td>Server-side data loaders keyed by name</td>
- </tr>
- </tbody>
- </table>
- ### Returns
- <table>
- <thead>
- <tr>
- <th>Export</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>Page</code></td>
- <td>Async Server Component for <code>page.tsx</code></td>
- </tr>
- <tr>
- <td><code>generateMetadata</code></td>
- <td>Metadata generator for Next.js SEO</td>
- </tr>
- <tr>
- <td><code>generateStaticParams</code></td>
- <td>Static params for pre-rendering at build time</td>
- </tr>
- </tbody>
- </table>
- ## NextAppSpec
- The top-level spec defining an entire Next.js application.
- ```typescript
- interface NextAppSpec {
- metadata?: NextMetadata;
- routes: Record<string, NextRouteSpec>;
- layouts?: Record<string, Spec>;
- state?: Record<string, unknown>;
- }
- ```
- ### Route Patterns
- Routes use Next.js URL conventions:
- <table>
- <thead>
- <tr>
- <th>Pattern</th>
- <th>Example Match</th>
- <th>Params</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>/</code></td>
- <td><code>/</code></td>
- <td><code>{'{}'}</code></td>
- </tr>
- <tr>
- <td><code>/about</code></td>
- <td><code>/about</code></td>
- <td><code>{'{}'}</code></td>
- </tr>
- <tr>
- <td><code>/blog/[slug]</code></td>
- <td><code>/blog/hello</code></td>
- <td><code>{'{ slug: "hello" }'}</code></td>
- </tr>
- <tr>
- <td><code>/docs/[...path]</code></td>
- <td><code>/docs/a/b/c</code></td>
- <td><code>{'{ path: ["a","b","c"] }'}</code></td>
- </tr>
- <tr>
- <td><code>/app/[[...path]]</code></td>
- <td><code>/app</code> or <code>/app/x/y</code></td>
- <td><code>{'{ path: [] }'}</code> or <code>{'{ path: ["x","y"] }'}</code></td>
- </tr>
- </tbody>
- </table>
- ## NextAppProvider
- Client component that provides the component registry and action handlers to all pages.
- ```tsx
- import { NextAppProvider } from '@json-render/next';
- export default function Layout({ children }) {
- return (
- <NextAppProvider registry={registry} handlers={handlers}>
- {children}
- </NextAppProvider>
- );
- }
- ```
- ## Built-in Components
- ### Slot
- Placeholder in layouts where page content is rendered. Every layout MUST include a Slot.
- ```json
- { "type": "Slot", "props": {}, "children": [] }
- ```
- ### Link
- Client-side navigation wrapping `next/link`.
- ```json
- { "type": "Link", "props": { "href": "/about" }, "children": ["link-text"] }
- ```
- ## Built-in Actions
- <table>
- <thead>
- <tr>
- <th>Action</th>
- <th>Params</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>setState</code></td>
- <td><code>{'{ statePath, value }'}</code></td>
- <td>Update a value in state</td>
- </tr>
- <tr>
- <td><code>pushState</code></td>
- <td><code>{'{ statePath, value, clearStatePath? }'}</code></td>
- <td>Append to array in state</td>
- </tr>
- <tr>
- <td><code>removeState</code></td>
- <td><code>{'{ statePath, index }'}</code></td>
- <td>Remove from array by index</td>
- </tr>
- <tr>
- <td><code>navigate</code></td>
- <td><code>{'{ href }'}</code></td>
- <td>Client-side navigation</td>
- </tr>
- </tbody>
- </table>
- ## Server Utilities
- ### matchRoute
- Match a pathname against a spec's routes.
- ```typescript
- import { matchRoute } from '@json-render/next/server';
- const matched = matchRoute(spec, '/blog/hello-world');
- // { route: NextRouteSpec, pattern: '/blog/[slug]', params: { slug: 'hello-world' } }
- ```
- ### resolveMetadata
- Resolve merged metadata for a route.
- ```typescript
- import { resolveMetadata } from '@json-render/next/server';
- const metadata = resolveMetadata(spec, matchedRoute?.route);
- ```
- ### slugToPath
- Convert catch-all slug array to pathname.
- ```typescript
- import { slugToPath } from '@json-render/next/server';
- slugToPath(undefined); // "/"
- slugToPath(['blog', 'hello']); // "/blog/hello"
- ```
- ## Entry Points
- <table>
- <thead>
- <tr>
- <th>Import</th>
- <th>Contents</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>@json-render/next</code></td>
- <td>Client components (NextAppProvider, PageRenderer, Link)</td>
- </tr>
- <tr>
- <td><code>@json-render/next/server</code></td>
- <td>Server utilities (createNextApp, matchRoute, schema)</td>
- </tr>
- </tbody>
- </table>
|