json-schema-builder-react 0.0.4 → 0.0.6
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 +56 -1
- package/dist-lib/components/JsonSchemaBuilder.d.ts +6 -1
- package/dist-lib/components/PropertyDocument.d.ts +2 -1
- package/dist-lib/components/PropertyEditDialog.d.ts +2 -1
- package/dist-lib/components/ui/button.d.ts +1 -1
- package/dist-lib/components/ui/dialog.d.ts +1 -1
- package/dist-lib/hooks/useChildManager.d.ts +60 -0
- package/dist-lib/hooks/useDialogManager.d.ts +75 -0
- package/dist-lib/hooks/useInlineEditor.d.ts +71 -0
- package/dist-lib/hooks/usePropertyEditor.d.ts +1 -1
- package/dist-lib/hooks/useTypeSelector.d.ts +49 -0
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.js +1077 -3232
- package/dist-lib/index.js.map +1 -1
- package/package.json +22 -12
- package/dist-lib/about.txt +0 -6
- package/dist-lib/android-chrome-192x192.png +0 -0
- package/dist-lib/android-chrome-512x512.png +0 -0
- package/dist-lib/apple-touch-icon.png +0 -0
- package/dist-lib/favicon-16x16.png +0 -0
- package/dist-lib/favicon-32x32.png +0 -0
- package/dist-lib/favicon.ico +0 -0
- package/dist-lib/site.webmanifest +0 -1
package/README.md
CHANGED
|
@@ -24,7 +24,29 @@ yarn add json-schema-builder-react
|
|
|
24
24
|
pnpm add json-schema-builder-react
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
This library requires the following peer dependencies to be installed in your project:
|
|
30
|
+
|
|
31
|
+
### 1. Install shadcn/ui Components
|
|
32
|
+
|
|
33
|
+
This library uses [shadcn/ui](https://ui.shadcn.com/) components. You'll need to set up shadcn/ui and install the required components:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Initialize shadcn/ui (if not already done)
|
|
37
|
+
npx shadcn@latest init
|
|
38
|
+
|
|
39
|
+
# Install required components
|
|
40
|
+
npx shadcn@latest add button dialog input select checkbox tooltip card label textarea
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Install Radix UI and Utility Libraries
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @radix-ui/react-checkbox @radix-ui/react-dialog @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot @radix-ui/react-tooltip lucide-react class-variance-authority clsx tailwind-merge
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 3. Tailwind CSS Setup
|
|
28
50
|
|
|
29
51
|
This library uses Tailwind CSS utility classes. You'll need Tailwind CSS configured in your project.
|
|
30
52
|
|
|
@@ -232,6 +254,38 @@ function App() {
|
|
|
232
254
|
}
|
|
233
255
|
```
|
|
234
256
|
|
|
257
|
+
### Editable Property Keys (Advanced)
|
|
258
|
+
|
|
259
|
+
By default, property keys are **immutable after creation** to prevent breaking existing references in your codebase. However, you can enable key editing with the `keyEditable` prop:
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import { useState } from 'react';
|
|
263
|
+
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
264
|
+
|
|
265
|
+
function App() {
|
|
266
|
+
const [schema, setSchema] = useState({
|
|
267
|
+
type: 'object',
|
|
268
|
+
properties: {
|
|
269
|
+
user_name: {
|
|
270
|
+
type: 'string',
|
|
271
|
+
title: 'User Name'
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
required: []
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<JsonSchemaBuilder
|
|
279
|
+
schema={schema}
|
|
280
|
+
onChange={setSchema}
|
|
281
|
+
keyEditable={true} // ⚠️ Allows changing keys after creation
|
|
282
|
+
/>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**⚠️ Warning:** Enabling `keyEditable` allows users to change property keys even after they've been created. This can break existing code that references these keys. Use with caution, primarily in development environments or when you have proper migration strategies in place.
|
|
288
|
+
|
|
235
289
|
## API Reference
|
|
236
290
|
|
|
237
291
|
### JsonSchemaBuilder Props
|
|
@@ -247,6 +301,7 @@ function App() {
|
|
|
247
301
|
| `showHeader` | `boolean` | `true` | Show header with action buttons |
|
|
248
302
|
| `showSummary` | `boolean` | `false` | Show summary at bottom |
|
|
249
303
|
| `showRegex` | `boolean` | `false` | Show regex pattern field for strings |
|
|
304
|
+
| `keyEditable` | `boolean` | `false` | Allow editing property keys after initialization (⚠️ may break references) |
|
|
250
305
|
| `className` | `string` | `"h-screen"` | Custom className for container |
|
|
251
306
|
| `typeLabels` | `TypeLabels` | Default labels | Custom labels for property types |
|
|
252
307
|
| `propertyLabel` | `{ singular: string, plural: string }` | `{ singular: 'property', plural: 'properties' }` | Custom labels for properties |
|
|
@@ -57,8 +57,13 @@ export interface JsonSchemaBuilderProps {
|
|
|
57
57
|
* @default false
|
|
58
58
|
*/
|
|
59
59
|
showRegex?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether to allow editing property keys after initialization
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
keyEditable?: boolean;
|
|
60
65
|
}
|
|
61
66
|
/**
|
|
62
67
|
* A visual JSON Schema builder component that allows building JSON schemas interactively
|
|
63
68
|
*/
|
|
64
|
-
export declare function JsonSchemaBuilder({ schema, onChange, showMetadata, showImport, showClear, showOutput, showHeader, className, showSummary, typeLabels, propertyLabel, showRegex, }: JsonSchemaBuilderProps): import("react/jsx-runtime").JSX.Element;
|
|
69
|
+
export declare function JsonSchemaBuilder({ schema, onChange, showMetadata, showImport, showClear, showOutput, showHeader, className, showSummary, typeLabels, propertyLabel, showRegex, keyEditable, }: JsonSchemaBuilderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,7 @@ interface PropertyDocumentProps {
|
|
|
6
6
|
level?: number;
|
|
7
7
|
isArrayItem?: boolean;
|
|
8
8
|
showRegex?: boolean;
|
|
9
|
+
keyEditable?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export default function PropertyDocument({ property, onUpdate, onDelete, level, isArrayItem, showRegex, }: PropertyDocumentProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default function PropertyDocument({ property, onUpdate, onDelete, level, isArrayItem, showRegex, keyEditable, }: PropertyDocumentProps): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -11,6 +11,7 @@ interface PropertyEditDialogProps {
|
|
|
11
11
|
plural: string;
|
|
12
12
|
};
|
|
13
13
|
showRegex?: boolean;
|
|
14
|
+
keyEditable?: boolean;
|
|
14
15
|
}
|
|
15
|
-
export default function PropertyEditDialog({ property, open, onOpenChange, onUpdate, isArrayItem, isNewProperty, propertyLabel, showRegex, }: PropertyEditDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export default function PropertyEditDialog({ property, open, onOpenChange, onUpdate, isArrayItem, isNewProperty, propertyLabel, showRegex, keyEditable, }: PropertyEditDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
16
17
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
5
|
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -16,4 +16,4 @@ declare const DialogFooter: {
|
|
|
16
16
|
};
|
|
17
17
|
declare const DialogTitle: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
|
|
18
18
|
declare const DialogDescription: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
19
|
-
export { Dialog, DialogPortal, DialogOverlay,
|
|
19
|
+
export { Dialog, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PropertyData } from "@/types/schema";
|
|
2
|
+
export interface UseChildManagerReturn {
|
|
3
|
+
/**
|
|
4
|
+
* Add a new child property (opens dialog)
|
|
5
|
+
*/
|
|
6
|
+
addChild: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Update an existing child property
|
|
9
|
+
*/
|
|
10
|
+
updateChild: (childId: string, updated: PropertyData) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Delete a child property
|
|
13
|
+
*/
|
|
14
|
+
deleteChild: (childId: string) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Dialog manager for adding new children
|
|
17
|
+
*/
|
|
18
|
+
addChildDialog: {
|
|
19
|
+
isOpen: boolean;
|
|
20
|
+
data: PropertyData | null;
|
|
21
|
+
setIsOpen: (isOpen: boolean) => void;
|
|
22
|
+
confirm: (data: PropertyData) => void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hook for managing child properties (nested properties within an object).
|
|
27
|
+
* Handles adding, updating, and deleting children with dialog state management.
|
|
28
|
+
*
|
|
29
|
+
* @param property - The parent property that contains children
|
|
30
|
+
* @param onUpdate - Callback to update the parent property
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* const childManager = useChildManager(property, onUpdate);
|
|
35
|
+
*
|
|
36
|
+
* // Add child button
|
|
37
|
+
* <Button onClick={childManager.addChild}>Add Child</Button>
|
|
38
|
+
*
|
|
39
|
+
* // Render children
|
|
40
|
+
* {property.children?.map((child) => (
|
|
41
|
+
* <PropertyDocument
|
|
42
|
+
* key={child.id}
|
|
43
|
+
* property={child}
|
|
44
|
+
* onUpdate={(updated) => childManager.updateChild(child.id, updated)}
|
|
45
|
+
* onDelete={() => childManager.deleteChild(child.id)}
|
|
46
|
+
* />
|
|
47
|
+
* ))}
|
|
48
|
+
*
|
|
49
|
+
* // Add child dialog
|
|
50
|
+
* {childManager.addChildDialog.isOpen && childManager.addChildDialog.data && (
|
|
51
|
+
* <PropertyEditDialog
|
|
52
|
+
* property={childManager.addChildDialog.data}
|
|
53
|
+
* open={childManager.addChildDialog.isOpen}
|
|
54
|
+
* onOpenChange={childManager.addChildDialog.setIsOpen}
|
|
55
|
+
* onUpdate={childManager.addChildDialog.confirm}
|
|
56
|
+
* />
|
|
57
|
+
* )}
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function useChildManager(property: PropertyData, onUpdate: (property: PropertyData) => void): UseChildManagerReturn;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export interface UseDialogManagerReturn<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Whether the dialog is currently open
|
|
4
|
+
*/
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The data associated with the dialog (e.g., the item being edited/created)
|
|
8
|
+
*/
|
|
9
|
+
data: T | null;
|
|
10
|
+
/**
|
|
11
|
+
* Open the dialog with optional data
|
|
12
|
+
*/
|
|
13
|
+
open: (data?: T) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Close the dialog without saving
|
|
16
|
+
*/
|
|
17
|
+
close: () => void;
|
|
18
|
+
/**
|
|
19
|
+
* Confirm and close the dialog (typically calls the onConfirm callback)
|
|
20
|
+
*/
|
|
21
|
+
confirm: (data: T) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Set the dialog open state directly
|
|
24
|
+
*/
|
|
25
|
+
setIsOpen: (isOpen: boolean) => void;
|
|
26
|
+
}
|
|
27
|
+
export interface UseDialogManagerOptions<T> {
|
|
28
|
+
/**
|
|
29
|
+
* Callback when dialog is confirmed/saved
|
|
30
|
+
*/
|
|
31
|
+
onConfirm?: (data: T) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Callback when dialog is cancelled/closed without saving
|
|
34
|
+
*/
|
|
35
|
+
onCancel?: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Factory function to create initial data when opening dialog
|
|
38
|
+
*/
|
|
39
|
+
createInitialData?: () => T;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generic hook for managing dialog state with associated data.
|
|
43
|
+
* Useful for dialogs that create/edit items with temporary state.
|
|
44
|
+
*
|
|
45
|
+
* @param options - Configuration options
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* // For adding a new property
|
|
50
|
+
* const addDialog = useDialogManager<PropertyData>({
|
|
51
|
+
* createInitialData: () => ({
|
|
52
|
+
* id: generateId(),
|
|
53
|
+
* key: "",
|
|
54
|
+
* type: "string",
|
|
55
|
+
* required: false
|
|
56
|
+
* }),
|
|
57
|
+
* onConfirm: (property) => {
|
|
58
|
+
* updateProperty(property.id, property);
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* // Usage in JSX
|
|
63
|
+
* <Button onClick={() => addDialog.open()}>Add Property</Button>
|
|
64
|
+
*
|
|
65
|
+
* {addDialog.isOpen && addDialog.data && (
|
|
66
|
+
* <PropertyEditDialog
|
|
67
|
+
* property={addDialog.data}
|
|
68
|
+
* open={addDialog.isOpen}
|
|
69
|
+
* onOpenChange={addDialog.setIsOpen}
|
|
70
|
+
* onUpdate={addDialog.confirm}
|
|
71
|
+
* />
|
|
72
|
+
* )}
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function useDialogManager<T>(options?: UseDialogManagerOptions<T>): UseDialogManagerReturn<T>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface UseInlineEditorOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Whether to allow empty values. If false, reverts to original value on blur when empty.
|
|
4
|
+
* @default false
|
|
5
|
+
*/
|
|
6
|
+
allowEmpty?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Callback when editing starts
|
|
9
|
+
*/
|
|
10
|
+
onEditStart?: () => void;
|
|
11
|
+
/**
|
|
12
|
+
* Callback when editing is cancelled
|
|
13
|
+
*/
|
|
14
|
+
onEditCancel?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export interface UseInlineEditorReturn {
|
|
17
|
+
/**
|
|
18
|
+
* Whether the field is currently being edited
|
|
19
|
+
*/
|
|
20
|
+
isEditing: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The current edited value
|
|
23
|
+
*/
|
|
24
|
+
value: string;
|
|
25
|
+
/**
|
|
26
|
+
* Start editing mode
|
|
27
|
+
*/
|
|
28
|
+
startEdit: () => void;
|
|
29
|
+
/**
|
|
30
|
+
* Handle value changes
|
|
31
|
+
*/
|
|
32
|
+
handleChange: (newValue: string) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Handle blur event - saves or reverts changes
|
|
35
|
+
*/
|
|
36
|
+
handleBlur: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Handle keyboard events (Enter to save, Escape to cancel)
|
|
39
|
+
*/
|
|
40
|
+
handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hook for managing inline editing state and behavior.
|
|
44
|
+
* Handles common patterns like Enter/Escape keys, blur to save, and syncing with external value changes.
|
|
45
|
+
*
|
|
46
|
+
* @param initialValue - The initial/current value from props
|
|
47
|
+
* @param onSave - Callback when value should be saved (on blur or Enter)
|
|
48
|
+
* @param options - Optional configuration
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* const titleEditor = useInlineEditor(
|
|
53
|
+
* property.title || "",
|
|
54
|
+
* (newValue) => onUpdate({ ...property, title: newValue }),
|
|
55
|
+
* { allowEmpty: false }
|
|
56
|
+
* );
|
|
57
|
+
*
|
|
58
|
+
* {titleEditor.isEditing ? (
|
|
59
|
+
* <Input
|
|
60
|
+
* value={titleEditor.value}
|
|
61
|
+
* onChange={(e) => titleEditor.handleChange(e.target.value)}
|
|
62
|
+
* onBlur={titleEditor.handleBlur}
|
|
63
|
+
* onKeyDown={titleEditor.handleKeyDown}
|
|
64
|
+
* autoFocus
|
|
65
|
+
* />
|
|
66
|
+
* ) : (
|
|
67
|
+
* <span onClick={titleEditor.startEdit}>{property.title}</span>
|
|
68
|
+
* )}
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function useInlineEditor(initialValue: string, onSave: (value: string) => void, options?: UseInlineEditorOptions): UseInlineEditorReturn;
|
|
@@ -6,4 +6,4 @@ export interface UsePropertyEditorReturn {
|
|
|
6
6
|
handleFieldChange: (field: keyof PropertyData, value: any) => void;
|
|
7
7
|
handleConstraintChange: (field: string, value: any) => void;
|
|
8
8
|
}
|
|
9
|
-
export declare const usePropertyEditor: (property: PropertyData, onUpdate: (property: PropertyData) => void, isNewProperty?: boolean) => UsePropertyEditorReturn;
|
|
9
|
+
export declare const usePropertyEditor: (property: PropertyData, onUpdate: (property: PropertyData) => void, isNewProperty?: boolean, keyEditable?: boolean) => UsePropertyEditorReturn;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PropertyData, PropertyType } from "@/types/schema";
|
|
2
|
+
export interface UseTypeSelectorReturn {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the type selector is currently open
|
|
5
|
+
*/
|
|
6
|
+
isChangingType: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Set whether the type selector is open
|
|
9
|
+
*/
|
|
10
|
+
setIsChangingType: (isOpen: boolean) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Handle type change with automatic cleanup of type-specific constraints
|
|
13
|
+
*/
|
|
14
|
+
handleTypeChange: (newType: PropertyType) => void;
|
|
15
|
+
/**
|
|
16
|
+
* List of available types that can be selected
|
|
17
|
+
*/
|
|
18
|
+
availableTypes: PropertyType[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Hook for managing property type selection with automatic constraint cleanup.
|
|
22
|
+
* When changing types, automatically removes constraints that don't apply to the new type.
|
|
23
|
+
*
|
|
24
|
+
* @param property - The property being edited
|
|
25
|
+
* @param onUpdate - Callback to update the property
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* const typeSelector = useTypeSelector(property, onUpdate);
|
|
30
|
+
*
|
|
31
|
+
* {typeSelector.isChangingType ? (
|
|
32
|
+
* <Select
|
|
33
|
+
* value={property.type}
|
|
34
|
+
* onValueChange={typeSelector.handleTypeChange}
|
|
35
|
+
* open={typeSelector.isChangingType}
|
|
36
|
+
* onOpenChange={typeSelector.setIsChangingType}
|
|
37
|
+
* >
|
|
38
|
+
* {typeSelector.availableTypes.map(type => (
|
|
39
|
+
* <SelectItem key={type} value={type}>{type}</SelectItem>
|
|
40
|
+
* ))}
|
|
41
|
+
* </Select>
|
|
42
|
+
* ) : (
|
|
43
|
+
* <button onClick={() => typeSelector.setIsChangingType(true)}>
|
|
44
|
+
* {property.type}
|
|
45
|
+
* </button>
|
|
46
|
+
* )}
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function useTypeSelector(property: PropertyData, onUpdate: (property: PropertyData) => void): UseTypeSelectorReturn;
|