json-schema-builder-react 0.0.4 → 0.0.5

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 CHANGED
@@ -232,6 +232,38 @@ function App() {
232
232
  }
233
233
  ```
234
234
 
235
+ ### Editable Property Keys (Advanced)
236
+
237
+ 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:
238
+
239
+ ```tsx
240
+ import { useState } from 'react';
241
+ import { JsonSchemaBuilder } from 'json-schema-builder-react';
242
+
243
+ function App() {
244
+ const [schema, setSchema] = useState({
245
+ type: 'object',
246
+ properties: {
247
+ user_name: {
248
+ type: 'string',
249
+ title: 'User Name'
250
+ }
251
+ },
252
+ required: []
253
+ });
254
+
255
+ return (
256
+ <JsonSchemaBuilder
257
+ schema={schema}
258
+ onChange={setSchema}
259
+ keyEditable={true} // ⚠️ Allows changing keys after creation
260
+ />
261
+ );
262
+ }
263
+ ```
264
+
265
+ **⚠️ 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.
266
+
235
267
  ## API Reference
236
268
 
237
269
  ### JsonSchemaBuilder Props
@@ -247,6 +279,7 @@ function App() {
247
279
  | `showHeader` | `boolean` | `true` | Show header with action buttons |
248
280
  | `showSummary` | `boolean` | `false` | Show summary at bottom |
249
281
  | `showRegex` | `boolean` | `false` | Show regex pattern field for strings |
282
+ | `keyEditable` | `boolean` | `false` | Allow editing property keys after initialization (⚠️ may break references) |
250
283
  | `className` | `string` | `"h-screen"` | Custom className for container |
251
284
  | `typeLabels` | `TypeLabels` | Default labels | Custom labels for property types |
252
285
  | `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, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
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;