@ht-rnd/json-schema-editor 1.0.7 → 2.0.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/README.md +318 -240
- package/dist/lib/main.es.js +9083 -18895
- package/dist/lib/main.umd.js +38 -70
- package/dist/types/index.d.ts +137 -25
- package/dist/types/lib/index.d.ts +1 -1
- package/package.json +33 -28
- package/dist/json-schema-editor.css +0 -1
package/README.md
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
# @ht-rnd/json-schema-editor
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A headless JSON Schema editor library for React. This package provides the core logic, hooks, and utilities for building JSON Schema editors, while allowing complete control over the UI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Architecture
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This library follows the **headless UI pattern**:
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **Deeply Nested Schemas:** Full support for nested `object` and `array` types with recursion.
|
|
12
|
-
- **Advanced Settings:** A detailed settings dialog for each property type (string, number, boolean, object, array).
|
|
13
|
-
- **Real-time Output:** Instantly see the generated JSON Schema as you build.
|
|
14
|
-
- **Live Schema Validation:** Integrated `ajv` validator provides real-time feedback and inline errors if your schema violates the JSON Schema specification.
|
|
15
|
-
- **Highly Configurable:** Control the root type (`object` or `array`) and layout via props.
|
|
16
|
-
- **Themeable:** Supports dark/light themes and custom styling.
|
|
17
|
-
- **Read-Only Mode:** A prop to disable all interactions for display purposes.
|
|
9
|
+
- **NPM Package**: Contains only the headless core - hooks, types, validation, and utilities
|
|
10
|
+
- **Components Folder**: Contains copy-paste shadcn-style React components for the UI
|
|
18
11
|
|
|
19
12
|
## Installation
|
|
20
13
|
|
|
@@ -22,283 +15,368 @@ This component provides a clean, intuitive interface for visually building and e
|
|
|
22
15
|
npm install @ht-rnd/json-schema-editor
|
|
23
16
|
```
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
### For UI Components
|
|
26
19
|
|
|
27
|
-
|
|
20
|
+
Copy the `components/json-schema-editor/` folder from this repository into your project. These components are designed to be customized and follow [shadcn/ui](https://ui.shadcn.com/) principles.
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
**Required peer dependencies for UI components:**
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npm install @radix-ui/react-alert-dialog @radix-ui/react-checkbox @radix-ui/react-dialog \
|
|
26
|
+
@radix-ui/react-label @radix-ui/react-radio-group @radix-ui/react-select \
|
|
27
|
+
@radix-ui/react-separator @radix-ui/react-slot @radix-ui/react-tooltip \
|
|
28
|
+
class-variance-authority clsx lucide-react tailwind-merge tailwindcss-animate
|
|
29
|
+
```
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
## Features
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
/** @type {import('tailwindcss').Config} */
|
|
37
|
-
module.exports = {
|
|
38
|
-
content: [
|
|
39
|
-
"./src/**/*.{js,ts,jsx,tsx}", // Your app's files
|
|
33
|
+
### Core Capabilities
|
|
40
34
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
- **JSON Schema 2020-12** - Full support for draft 2020-12 specification
|
|
36
|
+
- **Multiple Data Types** - string, number, integer, boolean, object, array, and $ref
|
|
37
|
+
- **Nested Schemas** - Support for nested objects and arrays with unlimited depth
|
|
38
|
+
- **Definitions ($defs)** - Create reusable schema definitions with $ref support
|
|
39
|
+
- **Validation Constraints** - min/max, length, format, pattern, enum, and more
|
|
40
|
+
- **Boolean Combinators** - allOf, anyOf, oneOf, not for complex schema logic
|
|
41
|
+
- **Real-time Validation** - AJV-based validation with inline error messages
|
|
42
|
+
- **Type Safety** - Full TypeScript support with comprehensive type definitions
|
|
43
|
+
|
|
44
|
+
### UI Features (Pre-built Components)
|
|
45
|
+
|
|
46
|
+
- **Responsive Layout** - Configurable form and output positioning (top/bottom/left/right)
|
|
47
|
+
- **Customizable Sizing** - Flexible width and height options (sm/md/lg/full)
|
|
48
|
+
- **Dark Mode Ready** - Theme prop support for dark/light mode
|
|
49
|
+
- **Read-only Mode** - View-only mode for displaying schemas
|
|
50
|
+
- **Settings Dialogs** - Rich settings for each field type with type-specific options
|
|
51
|
+
- **Inline Editing** - Direct field manipulation with instant feedback
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Option 1: Using the Headless Hook (Full Control)
|
|
56
|
+
|
|
57
|
+
Use the `useJsonSchemaEditor` hook directly for complete control over the UI:
|
|
52
58
|
|
|
53
59
|
```tsx
|
|
54
|
-
import {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
},
|
|
63
|
-
required: ["name"],
|
|
64
|
-
};
|
|
60
|
+
import { useJsonSchemaEditor } from "@ht-rnd/json-schema-editor";
|
|
61
|
+
import { FormProvider } from "react-hook-form";
|
|
62
|
+
|
|
63
|
+
function MyCustomEditor() {
|
|
64
|
+
const editor = useJsonSchemaEditor({
|
|
65
|
+
rootType: "object",
|
|
66
|
+
onChange: (schema) => console.log("Schema changed:", schema),
|
|
67
|
+
});
|
|
65
68
|
|
|
66
69
|
return (
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
<FormProvider {...editor.form}>
|
|
71
|
+
<div>
|
|
72
|
+
{/* Your custom UI here */}
|
|
73
|
+
<pre>{JSON.stringify(editor.schema, null, 2)}</pre>
|
|
74
|
+
|
|
75
|
+
<button onClick={editor.addField}>Add Field</button>
|
|
76
|
+
<button onClick={editor.addDefinition}>Add Definition</button>
|
|
77
|
+
|
|
78
|
+
{editor.fields.map((field, index) => (
|
|
79
|
+
<div key={field.id}>
|
|
80
|
+
{/* Render your custom field UI */}
|
|
81
|
+
<input value={field.key} />
|
|
82
|
+
<button onClick={() => editor.removeField(index)}>Remove</button>
|
|
83
|
+
<button onClick={() => editor.openSettings(`properties.${index}`)}>Settings</button>
|
|
84
|
+
</div>
|
|
85
|
+
))}
|
|
86
|
+
|
|
87
|
+
{editor.definitions.map((def, index) => (
|
|
88
|
+
<div key={def.id}>
|
|
89
|
+
<input value={def.key} />
|
|
90
|
+
<button onClick={() => editor.removeDefinition(index)}>Remove</button>
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
|
|
94
|
+
{editor.errors && (
|
|
95
|
+
<div>
|
|
96
|
+
{editor.errors.map((error, i) => (
|
|
97
|
+
<p key={i}>{error.message}</p>
|
|
98
|
+
))}
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
</FormProvider>
|
|
78
103
|
);
|
|
79
104
|
}
|
|
80
|
-
export default MySchema;
|
|
81
105
|
```
|
|
82
106
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
This library is built on the `shadcn/ui` theming architecture, which relies on CSS variables for colors, borders, spacing, and radius. You can easily override these variables in your own project to match your application's design system.
|
|
86
|
-
|
|
87
|
-
1. In your project's global CSS file (e.g., `src/index.css`), define your custom theme variables inside a `@layer base` block.
|
|
88
|
-
2. Your definitions will automatically override the library's default theme.
|
|
89
|
-
|
|
90
|
-
When you pass the `theme="dark"` prop to the JsonSchemaEditor, it will apply a `.dark` class to its root element, causing the browser to use the variables defined in your `.dark { ... }` block.
|
|
91
|
-
|
|
92
|
-
### Example `index.css`:
|
|
93
|
-
|
|
94
|
-
```css
|
|
95
|
-
@tailwind base;
|
|
96
|
-
@tailwind components;
|
|
97
|
-
@tailwind utilities;
|
|
98
|
-
|
|
99
|
-
@layer base {
|
|
100
|
-
:root {
|
|
101
|
-
--background: 0 0% 100%;
|
|
102
|
-
--foreground: 240 10% 3.9%;
|
|
103
|
-
--primary: 329 100% 44%;
|
|
104
|
-
--primary-hover: 329 100% 38%;
|
|
105
|
-
--primary-pressed: 329 100% 31%;
|
|
106
|
-
--primary-foreground: 0 0% 100%;
|
|
107
|
-
--secondary: 240 4.8% 95.9%;
|
|
108
|
-
--secondary-foreground: 240 5.9% 10%;
|
|
109
|
-
--muted: 240 3.8% 80%;
|
|
110
|
-
--muted-foreground: 240 3.8% 46.1%;
|
|
111
|
-
--accent: 240 4.8% 95.9%;
|
|
112
|
-
--accent-foreground: 240 5.9% 10%;
|
|
113
|
-
--destructive: 0 100% 50%;
|
|
114
|
-
--destructive-foreground: 0 0% 98%;
|
|
115
|
-
--border: 240 5.9% 90%;
|
|
116
|
-
--input: 240 5.9% 90%;
|
|
117
|
-
--radius: 0.75rem;
|
|
118
|
-
}
|
|
107
|
+
### Option 2: Using the Pre-built Components
|
|
119
108
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
--primary-hover: 330 96% 41%;
|
|
125
|
-
--primary-pressed: 330 96% 48%;
|
|
126
|
-
--primary-foreground: 240 17.1% 92%;
|
|
127
|
-
--secondary: 240 3.7% 15.9%;
|
|
128
|
-
--secondary-foreground: 0 0% 92%;
|
|
129
|
-
--muted: 240 3.8% 40%;
|
|
130
|
-
--muted-foreground: 240 5% 64.9%;
|
|
131
|
-
--accent: 240 3.7% 15.9%;
|
|
132
|
-
--accent-foreground: 0 0% 92%;
|
|
133
|
-
--destructive: 0 100% 60%;
|
|
134
|
-
--destructive-foreground: 0 0% 98%;
|
|
135
|
-
--border: 240 3.7% 30%;
|
|
136
|
-
--input: 240 3.7% 30%;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
109
|
+
Copy the components from `components/json-schema-editor/` and use them directly:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { JsonSchemaEditor } from "@/components/json-schema-editor";
|
|
139
113
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
function App() {
|
|
115
|
+
return (
|
|
116
|
+
<JsonSchemaEditor
|
|
117
|
+
rootType="object"
|
|
118
|
+
theme="light"
|
|
119
|
+
readOnly={false}
|
|
120
|
+
showOutput={true}
|
|
121
|
+
onChange={(schema) => console.log(schema)}
|
|
122
|
+
styles={{
|
|
123
|
+
form: { width: "full", height: "md" },
|
|
124
|
+
output: { position: "bottom", showJson: true, width: "full", height: "md" },
|
|
125
|
+
settings: { width: "md" },
|
|
126
|
+
spacing: "md",
|
|
127
|
+
}}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
143
130
|
}
|
|
144
131
|
```
|
|
145
132
|
|
|
146
|
-
###
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
DEFAULT: "hsl(var(--card))",
|
|
199
|
-
foreground: "hsl(var(--card-foreground))",
|
|
200
|
-
},
|
|
201
|
-
sidebar: {
|
|
202
|
-
DEFAULT: "hsl(var(--sidebar-background))",
|
|
203
|
-
foreground: "hsl(var(--sidebar-foreground))",
|
|
204
|
-
primary: "hsl(var(--sidebar-primary))",
|
|
205
|
-
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
|
206
|
-
accent: "hsl(var(--sidebar-accent))",
|
|
207
|
-
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
|
208
|
-
border: "hsl(var(--sidebar-border))",
|
|
209
|
-
ring: "hsl(var(--sidebar-ring))",
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
borderRadius: {
|
|
213
|
-
"2xl": "calc(var(--radius) + 6px)",
|
|
214
|
-
xl: "calc(var(--radius) + 4px)",
|
|
215
|
-
lg: "var(--radius)",
|
|
216
|
-
md: "calc(var(--radius) - 2px)",
|
|
217
|
-
sm: "calc(var(--radius) - 4px)",
|
|
218
|
-
xs: "calc(var(--radius) - 5px)",
|
|
219
|
-
"2xs": "calc(var(--radius) - 7px)",
|
|
220
|
-
},
|
|
133
|
+
### Option 3: Mix and Match
|
|
134
|
+
|
|
135
|
+
Use the headless hook with some pre-built components:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import { useJsonSchemaEditor } from "@ht-rnd/json-schema-editor";
|
|
139
|
+
import { Root, FieldList, SettingsDialog } from "@/components/json-schema-editor";
|
|
140
|
+
import { FormProvider } from "react-hook-form";
|
|
141
|
+
|
|
142
|
+
function HybridEditor() {
|
|
143
|
+
const editor = useJsonSchemaEditor({ rootType: "object" });
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<FormProvider {...editor.form}>
|
|
147
|
+
<div className="space-y-4">
|
|
148
|
+
<Root
|
|
149
|
+
rootType="object"
|
|
150
|
+
onAddField={editor.addField}
|
|
151
|
+
onOpenSettings={editor.openSettings}
|
|
152
|
+
/>
|
|
153
|
+
|
|
154
|
+
<FieldList
|
|
155
|
+
fields={editor.fields}
|
|
156
|
+
onRemove={editor.removeField}
|
|
157
|
+
onOpenSettings={editor.openSettings}
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
{/* Add definitions support */}
|
|
161
|
+
{editor.definitions.length > 0 && (
|
|
162
|
+
<div className="mt-4">
|
|
163
|
+
<h3>Definitions ($defs)</h3>
|
|
164
|
+
{editor.definitions.map((def, index) => (
|
|
165
|
+
<div key={def.id}>
|
|
166
|
+
<span>{def.key}</span>
|
|
167
|
+
<button onClick={() => editor.removeDefinition(index)}>Remove</button>
|
|
168
|
+
</div>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
{/* Your custom JSON output */}
|
|
174
|
+
<textarea value={JSON.stringify(editor.schema, null, 2)} readOnly />
|
|
175
|
+
|
|
176
|
+
<SettingsDialog
|
|
177
|
+
isOpen={editor.settingsState.isOpen}
|
|
178
|
+
fieldPath={editor.settingsState.fieldPath}
|
|
179
|
+
onClose={editor.closeSettings}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</FormProvider>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
221
185
|
```
|
|
222
186
|
|
|
223
187
|
## API Reference
|
|
224
188
|
|
|
225
|
-
###
|
|
189
|
+
### `JsonSchemaEditor` Component (Pre-built)
|
|
226
190
|
|
|
227
|
-
|
|
228
|
-
| :------------- | :------------------------------ | :--------- | :----------------------------------------------------------------------------------------------------------- |
|
|
229
|
-
| `rootType` | `'object'` \| `'array'` | `'object'` | Sets the root type of the schema. |
|
|
230
|
-
| `readOnly` | `boolean` | `false` | Disables all user interactions, making the editor a display-only component. |
|
|
231
|
-
| `theme` | `string` (e.g., `'dark'`) | `''` | A class name to apply for theming (e.g., pass `"dark"` for dark mode). |
|
|
232
|
-
| `styles` | `Styles` | `{...}` | An object to control the layout, width, and spacing of the editor panels. |
|
|
233
|
-
| `onChange` | `(schema: JSONSchema) => void` | `none` | A callback function that is invoked with the final schema object on any change. |
|
|
234
|
-
| `defaultValue` | `JSONSchema` | `none` | An existing JSON Schema object to load into the editor. When provided, this will override the rootType prop. |
|
|
191
|
+
The pre-built React component with full UI implementation.
|
|
235
192
|
|
|
236
|
-
|
|
193
|
+
#### Props
|
|
237
194
|
|
|
238
|
-
|
|
195
|
+
| Property | Type | Default | Description |
|
|
196
|
+
|----------|------|---------|-------------|
|
|
197
|
+
| `rootType` | `"object" \| "array"` | `"object"` | Root schema type |
|
|
198
|
+
| `defaultValue` | `JSONSchema` | - | Initial schema value |
|
|
199
|
+
| `onChange` | `(schema: JSONSchema) => void` | - | Callback when schema changes |
|
|
200
|
+
| `readOnly` | `boolean` | `false` | Make all inputs read-only |
|
|
201
|
+
| `showOutput` | `boolean` | `true` | Show/hide output panel |
|
|
202
|
+
| `theme` | `string` | `"light"` | Theme class for styling |
|
|
203
|
+
| `styles` | `Partial<Styles>` | - | Layout and sizing configuration |
|
|
204
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
239
205
|
|
|
240
|
-
|
|
206
|
+
#### Styles Configuration
|
|
241
207
|
|
|
242
|
-
```
|
|
208
|
+
```typescript
|
|
243
209
|
interface Styles {
|
|
244
|
-
form: {
|
|
245
|
-
width: "sm" | "md" | "lg" | "full";
|
|
246
|
-
height: "sm" | "md" | "lg" | "full";
|
|
247
|
-
};
|
|
210
|
+
form: { width: "sm" | "md" | "lg" | "full"; height: "sm" | "md" | "lg" | "full" };
|
|
248
211
|
output: {
|
|
249
212
|
position: "top" | "bottom" | "left" | "right";
|
|
250
213
|
showJson: boolean;
|
|
251
214
|
width: "sm" | "md" | "lg" | "full";
|
|
252
215
|
height: "sm" | "md" | "lg" | "full";
|
|
253
216
|
};
|
|
254
|
-
settings: {
|
|
255
|
-
width: "sm" | "md" | "lg" | "full";
|
|
256
|
-
};
|
|
217
|
+
settings: { width: "sm" | "md" | "lg" | "full" };
|
|
257
218
|
spacing: "sm" | "md" | "lg";
|
|
258
219
|
}
|
|
259
220
|
```
|
|
260
221
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
222
|
+
### `useJsonSchemaEditor(options)`
|
|
223
|
+
|
|
224
|
+
The main headless hook for managing JSON Schema editor state.
|
|
225
|
+
|
|
226
|
+
#### Options
|
|
227
|
+
|
|
228
|
+
| Property | Type | Default | Description |
|
|
229
|
+
|----------|------|---------|-------------|
|
|
230
|
+
| `rootType` | `"object" \| "array"` | `"object"` | Root schema type |
|
|
231
|
+
| `defaultValue` | `JSONSchema` | - | Initial schema value |
|
|
232
|
+
| `onChange` | `(schema: JSONSchema) => void` | - | Callback when schema changes |
|
|
233
|
+
|
|
234
|
+
#### Returns
|
|
235
|
+
|
|
236
|
+
| Property | Type | Description |
|
|
237
|
+
|----------|------|-------------|
|
|
238
|
+
| `schema` | `JSONSchema` | Current JSON Schema output |
|
|
239
|
+
| `errors` | `ErrorObject[] \| null` | AJV validation errors |
|
|
240
|
+
| `fields` | `FieldItem[]` | Field array for iteration |
|
|
241
|
+
| `definitions` | `DefinitionItem[]` | Definition array for $defs |
|
|
242
|
+
| `form` | `UseFormReturn` | React Hook Form methods |
|
|
243
|
+
| `settingsState` | `{ isOpen, fieldPath }` | Settings dialog state |
|
|
244
|
+
| `addField()` | `() => void` | Add a new field |
|
|
245
|
+
| `removeField(index)` | `(index: number) => void` | Remove field by index |
|
|
246
|
+
| `addDefinition()` | `() => void` | Add a new definition to $defs |
|
|
247
|
+
| `removeDefinition(index)` | `(index: number) => void` | Remove definition by index |
|
|
248
|
+
| `updateReferences(oldKey, newKey)` | `(oldKey: string, newKey: string \| null) => void` | Update $ref references when definition key changes |
|
|
249
|
+
| `openSettings(path)` | `(path: string) => void` | Open settings for a field |
|
|
250
|
+
| `closeSettings()` | `() => void` | Close settings dialog |
|
|
251
|
+
| `handleTypeChange(path, type)` | `(path: string, type: string) => void` | Change field type |
|
|
252
|
+
| `addNestedField(parentPath)` | `(parentPath: string) => void` | Add a nested field to an object |
|
|
253
|
+
| `reset()` | `() => void` | Reset to default state |
|
|
254
|
+
|
|
255
|
+
### Exports
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Main hook
|
|
259
|
+
export { useJsonSchemaEditor } from "@ht-rnd/json-schema-editor";
|
|
260
|
+
|
|
261
|
+
// Types
|
|
262
|
+
export type {
|
|
263
|
+
JSONSchema,
|
|
264
|
+
FormSchema,
|
|
265
|
+
JsonSchemaEditorOptions,
|
|
266
|
+
SettingsState,
|
|
267
|
+
FieldItem,
|
|
268
|
+
DefinitionItem,
|
|
269
|
+
SchemaType,
|
|
270
|
+
SchemaTypeValue,
|
|
271
|
+
SchemaTypeWithRefValue,
|
|
272
|
+
UseJsonSchemaEditorReturn,
|
|
273
|
+
} from "@ht-rnd/json-schema-editor";
|
|
274
|
+
|
|
275
|
+
// Validation
|
|
276
|
+
export { validateSchema } from "@ht-rnd/json-schema-editor";
|
|
277
|
+
export { jsonSchemaZod } from "@ht-rnd/json-schema-editor";
|
|
278
|
+
|
|
279
|
+
// Constants
|
|
280
|
+
export {
|
|
281
|
+
SCHEMA_TYPES,
|
|
282
|
+
SCHEMA_TYPES_WITH_REF,
|
|
283
|
+
INTEGER_FORMATS,
|
|
284
|
+
NUMBER_FORMATS,
|
|
285
|
+
STRING_FORMATS,
|
|
286
|
+
DEFAULT_SCHEMA_URI,
|
|
287
|
+
} from "@ht-rnd/json-schema-editor";
|
|
288
|
+
|
|
289
|
+
// Transforms and utilities
|
|
290
|
+
export { formToSchema, schemaToForm } from "@ht-rnd/json-schema-editor";
|
|
291
|
+
export {
|
|
292
|
+
createDefaultObjectSchema,
|
|
293
|
+
createDefaultArraySchema,
|
|
294
|
+
createDefaultField,
|
|
295
|
+
} from "@ht-rnd/json-schema-editor";
|
|
270
296
|
```
|
|
271
297
|
|
|
298
|
+
## Component Architecture
|
|
299
|
+
|
|
300
|
+
### Available Components
|
|
301
|
+
|
|
302
|
+
The `components/json-schema-editor/` folder includes these ready-to-use components:
|
|
303
|
+
|
|
304
|
+
#### Form Components
|
|
305
|
+
- `JsonSchemaEditor` - Complete editor with form and output
|
|
306
|
+
- `Root` - Root field component with type selector
|
|
307
|
+
- `FieldList` - List of field rows
|
|
308
|
+
- `FieldRow` - Individual field row with controls
|
|
309
|
+
- `Field` - Recursive field component for nested schemas
|
|
310
|
+
|
|
311
|
+
#### Settings Components
|
|
312
|
+
- `SettingsDialog` - Modal dialog for field settings
|
|
313
|
+
- `Settings` - Main settings router component
|
|
314
|
+
- `StringSettings`, `NumberSettings`, `IntegerSettings`, `BooleanSettings` - Type-specific settings
|
|
315
|
+
- `ObjectSettings`, `ArraySettings` - Complex type settings
|
|
316
|
+
- `BoolCombSettings` - allOf/anyOf/oneOf/not settings
|
|
317
|
+
- `DefinitionsSettings` - $defs management
|
|
318
|
+
- `RootSettings` - Root schema settings
|
|
319
|
+
|
|
320
|
+
#### UI Primitives
|
|
321
|
+
All based on [shadcn/ui](https://ui.shadcn.com/): `Button`, `Input`, `Select`, `Checkbox`, `Dialog`, `Badge`, `Tooltip`, etc.
|
|
322
|
+
|
|
323
|
+
## Customizing Components
|
|
324
|
+
|
|
325
|
+
The components in `components/json-schema-editor/` follow shadcn/ui patterns:
|
|
326
|
+
|
|
327
|
+
1. **`cn()` utility**: All components use the `cn()` function to merge Tailwind classes
|
|
328
|
+
2. **`className` prop**: Every component accepts a `className` prop for customization
|
|
329
|
+
3. **`forwardRef`**: Components forward refs for DOM access
|
|
330
|
+
4. **Composable**: Use individual components or compose your own
|
|
331
|
+
5. **Copy & Modify**: Copy components into your project and customize as needed
|
|
332
|
+
|
|
333
|
+
### Example: Customizing the FieldRow
|
|
334
|
+
|
|
272
335
|
```tsx
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
336
|
+
import { FieldRow } from "@/components/json-schema-editor";
|
|
337
|
+
|
|
338
|
+
<FieldRow
|
|
339
|
+
className="bg-slate-50 dark:bg-slate-900 rounded-lg"
|
|
340
|
+
fieldPath="properties.0"
|
|
341
|
+
theme="dark"
|
|
342
|
+
// ... other props
|
|
279
343
|
/>
|
|
280
344
|
```
|
|
281
345
|
|
|
346
|
+
### Example: Creating a Custom Field Component
|
|
347
|
+
|
|
282
348
|
```tsx
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
349
|
+
import * as React from "react";
|
|
350
|
+
import { Controller, useFormContext } from "react-hook-form";
|
|
351
|
+
import { cn } from "./lib/utils";
|
|
352
|
+
import { Input } from "./ui/input";
|
|
353
|
+
|
|
354
|
+
interface MyCustomFieldProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
355
|
+
fieldPath: string;
|
|
356
|
+
}
|
|
290
357
|
|
|
291
|
-
|
|
358
|
+
const MyCustomField = React.forwardRef<HTMLDivElement, MyCustomFieldProps>(
|
|
359
|
+
({ className, fieldPath, ...props }, ref) => {
|
|
360
|
+
const { control } = useFormContext();
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
<div ref={ref} className={cn("flex gap-2", className)} {...props}>
|
|
364
|
+
<Controller
|
|
365
|
+
control={control}
|
|
366
|
+
name={`${fieldPath}.key`}
|
|
367
|
+
render={({ field }) => (
|
|
368
|
+
<Input {...field} placeholder="Field name" />
|
|
369
|
+
)}
|
|
370
|
+
/>
|
|
371
|
+
</div>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
MyCustomField.displayName = "MyCustomField";
|
|
292
376
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
- React Hook Form for powerful and performant form state management.
|
|
296
|
-
- Zod for schema validation and type inference.
|
|
297
|
-
- AJV for real-time validation against the JSON Schema specification.
|
|
298
|
-
- Tailwind CSS for utility-first styling.
|
|
299
|
-
- shadcn/ui for the base component primitives.
|
|
300
|
-
- Vite for the build tooling.
|
|
377
|
+
export { MyCustomField };
|
|
378
|
+
```
|
|
301
379
|
|
|
302
380
|
## License
|
|
303
381
|
|
|
304
|
-
|
|
382
|
+
Apache-2.0
|