@json-render/react 0.1.0 → 0.4.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/LICENSE +201 -0
- package/README.md +253 -175
- package/dist/chunk-IGPI5WNB.mjs +52 -0
- package/dist/chunk-IGPI5WNB.mjs.map +1 -0
- package/dist/index.d.mts +139 -17
- package/dist/index.d.ts +139 -17
- package/dist/index.js +191 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -62
- package/dist/index.mjs.map +1 -1
- package/dist/schema.d.mts +106 -0
- package/dist/schema.d.ts +106 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.mjs +9 -0
- package/dist/schema.mjs.map +1 -0
- package/package.json +15 -10
package/README.md
CHANGED
|
@@ -1,238 +1,316 @@
|
|
|
1
1
|
# @json-render/react
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Visibility Filtering**: Components automatically show/hide based on visibility conditions
|
|
8
|
-
- **Action Handling**: Built-in action execution with confirmation dialogs
|
|
9
|
-
- **Validation**: Field validation with error display
|
|
10
|
-
- **Data Binding**: Two-way data binding between UI and data model
|
|
11
|
-
- **Streaming**: Progressive rendering from streamed UI trees
|
|
3
|
+
React renderer for json-render. Turn JSON specs into React components with data binding, visibility, and actions.
|
|
12
4
|
|
|
13
5
|
## Installation
|
|
14
6
|
|
|
15
7
|
```bash
|
|
16
|
-
npm install @json-render/react @json-render/core
|
|
17
|
-
# or
|
|
18
|
-
pnpm add @json-render/react @json-render/core
|
|
8
|
+
npm install @json-render/react @json-render/core zod
|
|
19
9
|
```
|
|
20
10
|
|
|
21
11
|
## Quick Start
|
|
22
12
|
|
|
23
|
-
###
|
|
13
|
+
### 1. Create a Catalog
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { defineCatalog } from "@json-render/core";
|
|
17
|
+
import { schema } from "@json-render/react";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
export const catalog = defineCatalog(schema, {
|
|
21
|
+
components: {
|
|
22
|
+
Card: {
|
|
23
|
+
props: z.object({
|
|
24
|
+
title: z.string(),
|
|
25
|
+
description: z.string().nullable(),
|
|
26
|
+
}),
|
|
27
|
+
description: "A card container",
|
|
28
|
+
},
|
|
29
|
+
Button: {
|
|
30
|
+
props: z.object({
|
|
31
|
+
label: z.string(),
|
|
32
|
+
action: z.string(),
|
|
33
|
+
}),
|
|
34
|
+
description: "A clickable button",
|
|
35
|
+
},
|
|
36
|
+
Input: {
|
|
37
|
+
props: z.object({
|
|
38
|
+
label: z.string(),
|
|
39
|
+
placeholder: z.string().nullable(),
|
|
40
|
+
}),
|
|
41
|
+
description: "Text input field",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
actions: {
|
|
45
|
+
submit: { description: "Submit the form" },
|
|
46
|
+
cancel: { description: "Cancel and close" },
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Define Component Implementations
|
|
24
52
|
|
|
25
53
|
```tsx
|
|
26
|
-
import {
|
|
54
|
+
import { defineComponents, useData } from "@json-render/react";
|
|
27
55
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Card: ({ element, children }) => (
|
|
56
|
+
export const components = defineComponents(catalog, {
|
|
57
|
+
Card: ({ props, children }) => (
|
|
31
58
|
<div className="card">
|
|
32
|
-
<h3>{
|
|
59
|
+
<h3>{props.title}</h3>
|
|
60
|
+
{props.description && <p>{props.description}</p>}
|
|
33
61
|
{children}
|
|
34
62
|
</div>
|
|
35
63
|
),
|
|
36
|
-
Button: ({
|
|
37
|
-
<button onClick={() => onAction?.(
|
|
38
|
-
{
|
|
64
|
+
Button: ({ props, onAction }) => (
|
|
65
|
+
<button onClick={() => onAction?.(props.action)}>
|
|
66
|
+
{props.label}
|
|
39
67
|
</button>
|
|
40
68
|
),
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
Input: ({ props }) => {
|
|
70
|
+
const { get, set } = useData();
|
|
71
|
+
return (
|
|
72
|
+
<label>
|
|
73
|
+
{props.label}
|
|
74
|
+
<input
|
|
75
|
+
placeholder={props.placeholder ?? ""}
|
|
76
|
+
value={get("/form/value") ?? ""}
|
|
77
|
+
onChange={(e) => set("/form/value", e.target.value)}
|
|
78
|
+
/>
|
|
79
|
+
</label>
|
|
80
|
+
);
|
|
50
81
|
},
|
|
51
|
-
};
|
|
82
|
+
});
|
|
83
|
+
```
|
|
52
84
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
85
|
+
### 3. Render Specs
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { Renderer, DataProvider, ActionProvider } from "@json-render/react";
|
|
89
|
+
|
|
90
|
+
function App({ spec }) {
|
|
91
|
+
const handleAction = (action: string) => {
|
|
92
|
+
console.log("Action triggered:", action);
|
|
93
|
+
};
|
|
57
94
|
|
|
58
95
|
return (
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/>
|
|
69
|
-
<Renderer tree={tree} registry={registry} loading={isStreaming} />
|
|
70
|
-
</JSONUIProvider>
|
|
96
|
+
<DataProvider initialData={{ form: { value: "" } }}>
|
|
97
|
+
<ActionProvider onAction={handleAction}>
|
|
98
|
+
<Renderer
|
|
99
|
+
spec={spec}
|
|
100
|
+
catalog={catalog}
|
|
101
|
+
components={components}
|
|
102
|
+
/>
|
|
103
|
+
</ActionProvider>
|
|
104
|
+
</DataProvider>
|
|
71
105
|
);
|
|
72
106
|
}
|
|
73
107
|
```
|
|
74
108
|
|
|
75
|
-
|
|
109
|
+
## Spec Format
|
|
76
110
|
|
|
77
|
-
|
|
78
|
-
import {
|
|
79
|
-
DataProvider,
|
|
80
|
-
VisibilityProvider,
|
|
81
|
-
ActionProvider,
|
|
82
|
-
ValidationProvider,
|
|
83
|
-
useData,
|
|
84
|
-
useVisibility,
|
|
85
|
-
useActions,
|
|
86
|
-
useFieldValidation,
|
|
87
|
-
} from '@json-render/react';
|
|
88
|
-
|
|
89
|
-
// Data context
|
|
90
|
-
function MyComponent() {
|
|
91
|
-
const { data, get, set } = useData();
|
|
92
|
-
const value = get('/user/name');
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<input
|
|
96
|
-
value={value}
|
|
97
|
-
onChange={(e) => set('/user/name', e.target.value)}
|
|
98
|
-
/>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
111
|
+
The React renderer uses an element tree format:
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (!isVisible(visible)) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return <div>Visible content</div>;
|
|
113
|
+
```typescript
|
|
114
|
+
interface Spec {
|
|
115
|
+
root: Element;
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<button
|
|
119
|
-
onClick={() => execute(action)}
|
|
120
|
-
disabled={loadingActions.has(action.name)}
|
|
121
|
-
>
|
|
122
|
-
{action.name}
|
|
123
|
-
</button>
|
|
124
|
-
);
|
|
118
|
+
interface Element {
|
|
119
|
+
type: string; // Component name from catalog
|
|
120
|
+
props: object; // Component props
|
|
121
|
+
children?: Element[]; // Nested elements
|
|
122
|
+
visible?: VisibilityCondition;
|
|
125
123
|
}
|
|
124
|
+
```
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
|
|
141
|
-
|
|
126
|
+
Example spec:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"root": {
|
|
131
|
+
"type": "Card",
|
|
132
|
+
"props": { "title": "Welcome" },
|
|
133
|
+
"children": [
|
|
134
|
+
{
|
|
135
|
+
"type": "Input",
|
|
136
|
+
"props": { "label": "Name", "placeholder": "Enter name" }
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"type": "Button",
|
|
140
|
+
"props": { "label": "Submit", "action": "submit" }
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
142
144
|
}
|
|
143
145
|
```
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
## Contexts
|
|
148
|
+
|
|
149
|
+
### DataProvider
|
|
150
|
+
|
|
151
|
+
Share data across components with JSON Pointer paths:
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
<DataProvider initialData={{ user: { name: "John" } }}>
|
|
155
|
+
{children}
|
|
156
|
+
</DataProvider>
|
|
157
|
+
|
|
158
|
+
// In components:
|
|
159
|
+
const { data, get, set } = useData();
|
|
160
|
+
const name = get("/user/name"); // "John"
|
|
161
|
+
set("/user/age", 25);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### ActionProvider
|
|
165
|
+
|
|
166
|
+
Handle actions from components:
|
|
146
167
|
|
|
147
168
|
```tsx
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
} = useUIStream({
|
|
158
|
-
api: '/api/generate',
|
|
159
|
-
onComplete: (tree) => console.log('Done:', tree),
|
|
160
|
-
onError: (err) => console.error('Error:', err),
|
|
161
|
-
});
|
|
169
|
+
<ActionProvider
|
|
170
|
+
onAction={(action) => {
|
|
171
|
+
if (action === "submit") handleSubmit();
|
|
172
|
+
if (action === "cancel") handleCancel();
|
|
173
|
+
}}
|
|
174
|
+
>
|
|
175
|
+
{children}
|
|
176
|
+
</ActionProvider>
|
|
177
|
+
```
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
179
|
+
### VisibilityProvider
|
|
180
|
+
|
|
181
|
+
Control element visibility based on data:
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
<VisibilityProvider>
|
|
185
|
+
{children}
|
|
186
|
+
</VisibilityProvider>
|
|
187
|
+
|
|
188
|
+
// Elements can use visibility conditions:
|
|
189
|
+
{
|
|
190
|
+
"type": "Alert",
|
|
191
|
+
"props": { "message": "Error!" },
|
|
192
|
+
"visible": { "path": "/form/hasError" }
|
|
172
193
|
}
|
|
173
194
|
```
|
|
174
195
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
### Providers
|
|
196
|
+
### ValidationProvider
|
|
178
197
|
|
|
179
|
-
|
|
180
|
-
- `DataProvider` - Data model context
|
|
181
|
-
- `VisibilityProvider` - Visibility evaluation context
|
|
182
|
-
- `ActionProvider` - Action execution context
|
|
183
|
-
- `ValidationProvider` - Validation context
|
|
198
|
+
Add field validation:
|
|
184
199
|
|
|
185
|
-
|
|
200
|
+
```tsx
|
|
201
|
+
<ValidationProvider>
|
|
202
|
+
{children}
|
|
203
|
+
</ValidationProvider>
|
|
204
|
+
|
|
205
|
+
// Use validation hooks:
|
|
206
|
+
const { errors, validate } = useFieldValidation("/form/email", {
|
|
207
|
+
checks: [
|
|
208
|
+
{ fn: "required", message: "Email required" },
|
|
209
|
+
{ fn: "email", message: "Invalid email" },
|
|
210
|
+
],
|
|
211
|
+
});
|
|
212
|
+
```
|
|
186
213
|
|
|
187
|
-
|
|
188
|
-
- `useDataValue(path)` - Get a single value
|
|
189
|
-
- `useDataBinding(path)` - Two-way binding like useState
|
|
190
|
-
- `useVisibility()` - Access visibility evaluation
|
|
191
|
-
- `useIsVisible(condition)` - Check if condition is visible
|
|
192
|
-
- `useActions()` - Access action execution
|
|
193
|
-
- `useAction(action)` - Execute a specific action
|
|
194
|
-
- `useValidation()` - Access validation context
|
|
195
|
-
- `useFieldValidation(path, config)` - Field-level validation
|
|
214
|
+
## Hooks
|
|
196
215
|
|
|
197
|
-
|
|
216
|
+
| Hook | Purpose |
|
|
217
|
+
|------|---------|
|
|
218
|
+
| `useData()` | Access data context (`data`, `get`, `set`) |
|
|
219
|
+
| `useDataValue(path)` | Get single value from data |
|
|
220
|
+
| `useVisibility()` | Access visibility evaluation |
|
|
221
|
+
| `useIsVisible(condition)` | Check if condition is met |
|
|
222
|
+
| `useActions()` | Access action context |
|
|
223
|
+
| `useFieldValidation(path, config)` | Field validation state |
|
|
198
224
|
|
|
199
|
-
|
|
200
|
-
- `ConfirmDialog` - Default confirmation dialog
|
|
225
|
+
## Visibility Conditions
|
|
201
226
|
|
|
202
|
-
|
|
227
|
+
```typescript
|
|
228
|
+
// Simple path check (truthy)
|
|
229
|
+
{ "path": "/user/isAdmin" }
|
|
230
|
+
|
|
231
|
+
// Auth state
|
|
232
|
+
{ "auth": "signedIn" }
|
|
233
|
+
|
|
234
|
+
// Comparisons
|
|
235
|
+
{ "eq": [{ "path": "/status" }, "active"] }
|
|
236
|
+
{ "gt": [{ "path": "/count" }, 10] }
|
|
237
|
+
|
|
238
|
+
// Logical operators
|
|
239
|
+
{
|
|
240
|
+
"and": [
|
|
241
|
+
{ "path": "/feature/enabled" },
|
|
242
|
+
{ "not": { "path": "/maintenance" } }
|
|
243
|
+
]
|
|
244
|
+
}
|
|
203
245
|
|
|
204
|
-
|
|
205
|
-
|
|
246
|
+
{
|
|
247
|
+
"or": [
|
|
248
|
+
{ "path": "/user/isAdmin" },
|
|
249
|
+
{ "path": "/user/isModerator" }
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
206
253
|
|
|
207
254
|
## Component Props
|
|
208
255
|
|
|
209
|
-
Components
|
|
256
|
+
Components receive these props:
|
|
210
257
|
|
|
211
258
|
```typescript
|
|
212
|
-
interface
|
|
213
|
-
|
|
214
|
-
children?: ReactNode;
|
|
215
|
-
onAction?: (action:
|
|
216
|
-
loading?: boolean; // Streaming in progress
|
|
259
|
+
interface ComponentProps<P> {
|
|
260
|
+
props: P; // Props from spec
|
|
261
|
+
children?: React.ReactNode; // Rendered children
|
|
262
|
+
onAction?: (action: string) => void;
|
|
217
263
|
}
|
|
218
264
|
```
|
|
219
265
|
|
|
220
|
-
##
|
|
266
|
+
## Generate AI Prompts
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const systemPrompt = catalog.prompt();
|
|
270
|
+
// Returns detailed prompt with component/action descriptions
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Full Example
|
|
221
274
|
|
|
222
275
|
```tsx
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
276
|
+
import { defineCatalog } from "@json-render/core";
|
|
277
|
+
import {
|
|
278
|
+
schema,
|
|
279
|
+
defineComponents,
|
|
280
|
+
Renderer,
|
|
281
|
+
DataProvider,
|
|
282
|
+
ActionProvider,
|
|
283
|
+
} from "@json-render/react";
|
|
284
|
+
import { z } from "zod";
|
|
285
|
+
|
|
286
|
+
const catalog = defineCatalog(schema, {
|
|
287
|
+
components: {
|
|
288
|
+
Greeting: {
|
|
289
|
+
props: z.object({ name: z.string() }),
|
|
290
|
+
description: "Displays a greeting",
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
actions: {},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const components = defineComponents(catalog, {
|
|
297
|
+
Greeting: ({ props }) => <h1>Hello, {props.name}!</h1>,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const spec = {
|
|
301
|
+
root: {
|
|
302
|
+
type: "Greeting",
|
|
303
|
+
props: { name: "World" },
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
function App() {
|
|
231
308
|
return (
|
|
232
|
-
<
|
|
233
|
-
<
|
|
234
|
-
|
|
235
|
-
|
|
309
|
+
<DataProvider initialData={{}}>
|
|
310
|
+
<ActionProvider onAction={() => {}}>
|
|
311
|
+
<Renderer spec={spec} catalog={catalog} components={components} />
|
|
312
|
+
</ActionProvider>
|
|
313
|
+
</DataProvider>
|
|
236
314
|
);
|
|
237
315
|
}
|
|
238
316
|
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/schema.ts
|
|
2
|
+
import { defineSchema } from "@json-render/core";
|
|
3
|
+
var schema = defineSchema((s) => ({
|
|
4
|
+
// What the AI-generated SPEC looks like
|
|
5
|
+
spec: s.object({
|
|
6
|
+
/** Root element key */
|
|
7
|
+
root: s.string(),
|
|
8
|
+
/** Flat map of elements by key */
|
|
9
|
+
elements: s.record(
|
|
10
|
+
s.object({
|
|
11
|
+
/** Unique key for this element */
|
|
12
|
+
key: s.string(),
|
|
13
|
+
/** Component type from catalog */
|
|
14
|
+
type: s.ref("catalog.components"),
|
|
15
|
+
/** Component props */
|
|
16
|
+
props: s.propsOf("catalog.components"),
|
|
17
|
+
/** Child element keys (flat reference) */
|
|
18
|
+
children: s.array(s.string()),
|
|
19
|
+
/** Parent element key (null for root) */
|
|
20
|
+
parentKey: s.string(),
|
|
21
|
+
/** Visibility condition */
|
|
22
|
+
visible: s.any()
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
}),
|
|
26
|
+
// What the CATALOG must provide
|
|
27
|
+
catalog: s.object({
|
|
28
|
+
/** Component definitions */
|
|
29
|
+
components: s.map({
|
|
30
|
+
/** Zod schema for component props */
|
|
31
|
+
props: s.zod(),
|
|
32
|
+
/** Slots for this component. Use ['default'] for children, or named slots like ['header', 'footer'] */
|
|
33
|
+
slots: s.array(s.string()),
|
|
34
|
+
/** Description for AI generation hints */
|
|
35
|
+
description: s.string()
|
|
36
|
+
}),
|
|
37
|
+
/** Action definitions (optional) */
|
|
38
|
+
actions: s.map({
|
|
39
|
+
/** Zod schema for action params */
|
|
40
|
+
params: s.zod(),
|
|
41
|
+
/** Description for AI generation hints */
|
|
42
|
+
description: s.string()
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}));
|
|
46
|
+
var elementTreeSchema = schema;
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
schema,
|
|
50
|
+
elementTreeSchema
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=chunk-IGPI5WNB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import { defineSchema } from \"@json-render/core\";\n\n/**\n * The schema for @json-render/react\n *\n * Defines:\n * - Spec: A flat tree of elements with keys, types, props, and children references\n * - Catalog: Components with props schemas, and optional actions\n */\nexport const schema = defineSchema((s) => ({\n // What the AI-generated SPEC looks like\n spec: s.object({\n /** Root element key */\n root: s.string(),\n /** Flat map of elements by key */\n elements: s.record(\n s.object({\n /** Unique key for this element */\n key: s.string(),\n /** Component type from catalog */\n type: s.ref(\"catalog.components\"),\n /** Component props */\n props: s.propsOf(\"catalog.components\"),\n /** Child element keys (flat reference) */\n children: s.array(s.string()),\n /** Parent element key (null for root) */\n parentKey: s.string(),\n /** Visibility condition */\n visible: s.any(),\n }),\n ),\n }),\n\n // What the CATALOG must provide\n catalog: s.object({\n /** Component definitions */\n components: s.map({\n /** Zod schema for component props */\n props: s.zod(),\n /** Slots for this component. Use ['default'] for children, or named slots like ['header', 'footer'] */\n slots: s.array(s.string()),\n /** Description for AI generation hints */\n description: s.string(),\n }),\n /** Action definitions (optional) */\n actions: s.map({\n /** Zod schema for action params */\n params: s.zod(),\n /** Description for AI generation hints */\n description: s.string(),\n }),\n }),\n}));\n\n/**\n * Type for the React schema\n */\nexport type ReactSchema = typeof schema;\n\n/**\n * Infer the spec type from a catalog\n */\nexport type ReactSpec<TCatalog> = typeof schema extends {\n createCatalog: (catalog: TCatalog) => { _specType: infer S };\n}\n ? S\n : never;\n\n// Backward compatibility aliases\n/** @deprecated Use `schema` instead */\nexport const elementTreeSchema = schema;\n/** @deprecated Use `ReactSchema` instead */\nexport type ElementTreeSchema = ReactSchema;\n/** @deprecated Use `ReactSpec` instead */\nexport type ElementTreeSpec<T> = ReactSpec<T>;\n"],"mappings":";AAAA,SAAS,oBAAoB;AAStB,IAAM,SAAS,aAAa,CAAC,OAAO;AAAA;AAAA,EAEzC,MAAM,EAAE,OAAO;AAAA;AAAA,IAEb,MAAM,EAAE,OAAO;AAAA;AAAA,IAEf,UAAU,EAAE;AAAA,MACV,EAAE,OAAO;AAAA;AAAA,QAEP,KAAK,EAAE,OAAO;AAAA;AAAA,QAEd,MAAM,EAAE,IAAI,oBAAoB;AAAA;AAAA,QAEhC,OAAO,EAAE,QAAQ,oBAAoB;AAAA;AAAA,QAErC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,QAE5B,WAAW,EAAE,OAAO;AAAA;AAAA,QAEpB,SAAS,EAAE,IAAI;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA;AAAA,EAGD,SAAS,EAAE,OAAO;AAAA;AAAA,IAEhB,YAAY,EAAE,IAAI;AAAA;AAAA,MAEhB,OAAO,EAAE,IAAI;AAAA;AAAA,MAEb,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,MAEzB,aAAa,EAAE,OAAO;AAAA,IACxB,CAAC;AAAA;AAAA,IAED,SAAS,EAAE,IAAI;AAAA;AAAA,MAEb,QAAQ,EAAE,IAAI;AAAA;AAAA,MAEd,aAAa,EAAE,OAAO;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AACH,EAAE;AAkBK,IAAM,oBAAoB;","names":[]}
|