json-schema-builder-react 0.0.3 → 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 +186 -138
- 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 +1182 -1045
- package/dist-lib/index.js.map +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -6,14 +6,13 @@ A beautiful, interactive React component for building and editing JSON schemas v
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🎨 **Visual Editor** - Build JSON schemas with an intuitive
|
|
9
|
+
- 🎨 **Visual Editor** - Build JSON schemas with an intuitive interface
|
|
10
10
|
- 📝 **Full JSON Schema Support** - Support for all JSON Schema types and constraints
|
|
11
11
|
- 🎯 **Type-Safe** - Written in TypeScript with full type definitions
|
|
12
|
-
- ✅ **
|
|
12
|
+
- ✅ **Controlled Component** - Full control over state management
|
|
13
13
|
- 🎨 **Customizable** - Flexible API with extensive customization options
|
|
14
|
-
- 📦 **Headless Options** - Use just the hooks and utilities without UI
|
|
15
14
|
- 🌗 **Theme Support** - Built-in dark mode support
|
|
16
|
-
- ⚡ **Lightweight** -
|
|
15
|
+
- ⚡ **Lightweight** - Minimal bundle size with focused API
|
|
17
16
|
|
|
18
17
|
## Installation
|
|
19
18
|
|
|
@@ -84,16 +83,20 @@ Add to your main CSS file (e.g., `src/index.css`):
|
|
|
84
83
|
### Basic Example
|
|
85
84
|
|
|
86
85
|
```tsx
|
|
86
|
+
import { useState } from 'react';
|
|
87
87
|
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
88
88
|
|
|
89
89
|
function App() {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const [schema, setSchema] = useState({
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {},
|
|
93
|
+
required: []
|
|
94
|
+
});
|
|
93
95
|
|
|
94
96
|
return (
|
|
95
97
|
<JsonSchemaBuilder
|
|
96
|
-
|
|
98
|
+
schema={schema}
|
|
99
|
+
onChange={setSchema}
|
|
97
100
|
/>
|
|
98
101
|
);
|
|
99
102
|
}
|
|
@@ -102,24 +105,35 @@ function App() {
|
|
|
102
105
|
### With Initial Schema
|
|
103
106
|
|
|
104
107
|
```tsx
|
|
108
|
+
import { useState } from 'react';
|
|
105
109
|
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
106
110
|
|
|
107
|
-
const initialSchema = {
|
|
108
|
-
type: 'object',
|
|
109
|
-
properties: {
|
|
110
|
-
name: { type: 'string' },
|
|
111
|
-
age: { type: 'number' }
|
|
112
|
-
},
|
|
113
|
-
required: ['name']
|
|
114
|
-
};
|
|
115
|
-
|
|
116
111
|
function App() {
|
|
112
|
+
const [schema, setSchema] = useState({
|
|
113
|
+
type: 'object',
|
|
114
|
+
title: 'User Profile',
|
|
115
|
+
properties: {
|
|
116
|
+
name: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
minLength: 2,
|
|
119
|
+
maxLength: 50
|
|
120
|
+
},
|
|
121
|
+
age: {
|
|
122
|
+
type: 'integer',
|
|
123
|
+
minimum: 0,
|
|
124
|
+
maximum: 120
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
required: ['name']
|
|
128
|
+
});
|
|
129
|
+
|
|
117
130
|
return (
|
|
118
131
|
<JsonSchemaBuilder
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
schema={schema}
|
|
133
|
+
onChange={(newSchema) => {
|
|
134
|
+
setSchema(newSchema);
|
|
121
135
|
// Save to backend, localStorage, etc.
|
|
122
|
-
|
|
136
|
+
localStorage.setItem('schema', JSON.stringify(newSchema));
|
|
123
137
|
}}
|
|
124
138
|
/>
|
|
125
139
|
);
|
|
@@ -129,14 +143,21 @@ function App() {
|
|
|
129
143
|
### Customized Layout
|
|
130
144
|
|
|
131
145
|
```tsx
|
|
146
|
+
import { useState } from 'react';
|
|
132
147
|
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
133
148
|
|
|
134
149
|
function App() {
|
|
150
|
+
const [schema, setSchema] = useState({
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {},
|
|
153
|
+
required: []
|
|
154
|
+
});
|
|
155
|
+
|
|
135
156
|
return (
|
|
136
157
|
<JsonSchemaBuilder
|
|
158
|
+
schema={schema}
|
|
159
|
+
onChange={setSchema}
|
|
137
160
|
showMetadata={true}
|
|
138
|
-
showImport={false}
|
|
139
|
-
showClear={true}
|
|
140
161
|
showOutput={true}
|
|
141
162
|
className="h-[600px]"
|
|
142
163
|
typeLabels={{
|
|
@@ -145,33 +166,130 @@ function App() {
|
|
|
145
166
|
object: 'Form',
|
|
146
167
|
array: 'List',
|
|
147
168
|
}}
|
|
169
|
+
propertyLabel={{
|
|
170
|
+
singular: 'field',
|
|
171
|
+
plural: 'fields'
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### With Undo/Redo
|
|
179
|
+
|
|
180
|
+
Since the component is fully controlled, you can implement undo/redo easily:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { useState } from 'react';
|
|
184
|
+
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
185
|
+
|
|
186
|
+
function App() {
|
|
187
|
+
const [history, setHistory] = useState([{
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {},
|
|
190
|
+
required: []
|
|
191
|
+
}]);
|
|
192
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
193
|
+
|
|
194
|
+
const currentSchema = history[currentIndex];
|
|
195
|
+
|
|
196
|
+
const handleChange = (newSchema) => {
|
|
197
|
+
const newHistory = history.slice(0, currentIndex + 1);
|
|
198
|
+
newHistory.push(newSchema);
|
|
199
|
+
setHistory(newHistory);
|
|
200
|
+
setCurrentIndex(currentIndex + 1);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const undo = () => {
|
|
204
|
+
if (currentIndex > 0) {
|
|
205
|
+
setCurrentIndex(currentIndex - 1);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const redo = () => {
|
|
210
|
+
if (currentIndex < history.length - 1) {
|
|
211
|
+
setCurrentIndex(currentIndex + 1);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<div>
|
|
217
|
+
<div className="toolbar">
|
|
218
|
+
<button onClick={undo} disabled={currentIndex === 0}>
|
|
219
|
+
Undo
|
|
220
|
+
</button>
|
|
221
|
+
<button onClick={redo} disabled={currentIndex === history.length - 1}>
|
|
222
|
+
Redo
|
|
223
|
+
</button>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<JsonSchemaBuilder
|
|
227
|
+
schema={currentSchema}
|
|
228
|
+
onChange={handleChange}
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
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
|
|
148
260
|
/>
|
|
149
261
|
);
|
|
150
262
|
}
|
|
151
263
|
```
|
|
152
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
|
+
|
|
153
267
|
## API Reference
|
|
154
268
|
|
|
155
269
|
### JsonSchemaBuilder Props
|
|
156
270
|
|
|
157
271
|
| Prop | Type | Default | Description |
|
|
158
272
|
|------|------|---------|-------------|
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `showMetadata` | `boolean` | `
|
|
273
|
+
| `schema` | `object` | **Required** | The JSON schema object (controlled) |
|
|
274
|
+
| `onChange` | `(schema: any) => void` | **Required** | Callback when schema changes |
|
|
275
|
+
| `showMetadata` | `boolean` | `false` | Show metadata fields (title, description, version) |
|
|
162
276
|
| `showImport` | `boolean` | `true` | Show import button |
|
|
163
277
|
| `showClear` | `boolean` | `true` | Show clear all button |
|
|
164
278
|
| `showOutput` | `boolean` | `true` | Show JSON output panel |
|
|
165
|
-
| `
|
|
279
|
+
| `showHeader` | `boolean` | `true` | Show header with action buttons |
|
|
280
|
+
| `showSummary` | `boolean` | `false` | Show summary at bottom |
|
|
281
|
+
| `showRegex` | `boolean` | `false` | Show regex pattern field for strings |
|
|
282
|
+
| `keyEditable` | `boolean` | `false` | Allow editing property keys after initialization (⚠️ may break references) |
|
|
166
283
|
| `className` | `string` | `"h-screen"` | Custom className for container |
|
|
167
|
-
| `typeLabels` | `TypeLabels` | Default labels | Custom labels for property types
|
|
168
|
-
| `propertyLabel` | `{ singular: string, plural: string }` | `{ singular: 'property', plural: 'properties' }` | Custom labels for
|
|
284
|
+
| `typeLabels` | `TypeLabels` | Default labels | Custom labels for property types |
|
|
285
|
+
| `propertyLabel` | `{ singular: string, plural: string }` | `{ singular: 'property', plural: 'properties' }` | Custom labels for properties |
|
|
169
286
|
|
|
170
287
|
### Customizing Type Labels
|
|
171
288
|
|
|
172
289
|
You can customize how property types are displayed to your users:
|
|
173
290
|
|
|
174
291
|
```tsx
|
|
292
|
+
import { useState } from 'react';
|
|
175
293
|
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
176
294
|
import type { TypeLabels } from 'json-schema-builder-react';
|
|
177
295
|
|
|
@@ -186,10 +304,17 @@ const customLabels: TypeLabels = {
|
|
|
186
304
|
};
|
|
187
305
|
|
|
188
306
|
function App() {
|
|
307
|
+
const [schema, setSchema] = useState({
|
|
308
|
+
type: 'object',
|
|
309
|
+
properties: {},
|
|
310
|
+
required: []
|
|
311
|
+
});
|
|
312
|
+
|
|
189
313
|
return (
|
|
190
314
|
<JsonSchemaBuilder
|
|
315
|
+
schema={schema}
|
|
316
|
+
onChange={setSchema}
|
|
191
317
|
typeLabels={customLabels}
|
|
192
|
-
onSchemaChange={(schema) => console.log(schema)}
|
|
193
318
|
/>
|
|
194
319
|
);
|
|
195
320
|
}
|
|
@@ -209,132 +334,55 @@ This affects:
|
|
|
209
334
|
- `array` - Default: "Array"
|
|
210
335
|
- `null` - Default: "Null"
|
|
211
336
|
|
|
212
|
-
## Headless Usage
|
|
213
|
-
|
|
214
|
-
Use just the hooks and utilities without the UI components:
|
|
215
|
-
|
|
216
|
-
```tsx
|
|
217
|
-
import { useSchemaBuilder, generateSchema } from 'json-schema-builder-react';
|
|
218
|
-
|
|
219
|
-
function MyCustomEditor() {
|
|
220
|
-
const {
|
|
221
|
-
properties,
|
|
222
|
-
metadata,
|
|
223
|
-
schema,
|
|
224
|
-
addProperty,
|
|
225
|
-
updateProperty,
|
|
226
|
-
deleteProperty,
|
|
227
|
-
} = useSchemaBuilder(true);
|
|
228
|
-
|
|
229
|
-
return (
|
|
230
|
-
<div>
|
|
231
|
-
{/* Build your own custom UI */}
|
|
232
|
-
<button onClick={() => {
|
|
233
|
-
const newProp = addProperty();
|
|
234
|
-
updateProperty(newProp.id, {
|
|
235
|
-
...newProp,
|
|
236
|
-
key: 'myProperty',
|
|
237
|
-
type: 'string'
|
|
238
|
-
});
|
|
239
|
-
}}>
|
|
240
|
-
Add Property
|
|
241
|
-
</button>
|
|
242
|
-
|
|
243
|
-
<pre>{JSON.stringify(schema, null, 2)}</pre>
|
|
244
|
-
</div>
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
337
|
## Available Exports
|
|
250
338
|
|
|
251
|
-
###
|
|
252
|
-
- `JsonSchemaBuilder` - Main builder component
|
|
253
|
-
- `PropertyDocument` - Individual property card
|
|
254
|
-
- `PropertyEditDialog` - Property edit modal
|
|
255
|
-
- `JsonOutput` - JSON output display
|
|
256
|
-
- `SchemaMetadataComponent` - Schema metadata fields
|
|
257
|
-
|
|
258
|
-
### Hooks
|
|
259
|
-
- `useSchemaBuilder` - Main schema builder logic
|
|
260
|
-
- `usePropertyEditor` - Property editing logic
|
|
261
|
-
|
|
262
|
-
### Utilities
|
|
263
|
-
- `generateSchema` - Generate JSON schema from properties
|
|
264
|
-
- `parseSchema` - Parse JSON schema into properties
|
|
265
|
-
- `downloadJsonFile` - Download schema as JSON file
|
|
266
|
-
- `importJsonFile` - Import schema from file
|
|
339
|
+
### Component
|
|
340
|
+
- `JsonSchemaBuilder` - Main builder component (controlled)
|
|
267
341
|
|
|
268
342
|
### Types
|
|
269
|
-
- `
|
|
270
|
-
- `
|
|
271
|
-
- `SchemaMetadata` - Schema metadata structure
|
|
272
|
-
- `JSONSchema7` - Official JSON Schema Draft 7 type (from `@types/json-schema`)
|
|
273
|
-
- `JSONSchema7TypeName` - JSON Schema type names (from `@types/json-schema`)
|
|
343
|
+
- `JsonSchemaBuilderProps` - Props for the main component
|
|
344
|
+
- `TypeLabels` - Type for customizing property type labels
|
|
274
345
|
|
|
275
|
-
|
|
346
|
+
## Advanced Usage
|
|
276
347
|
|
|
277
|
-
|
|
348
|
+
### Integration with State Management
|
|
278
349
|
|
|
279
|
-
|
|
350
|
+
The controlled component pattern makes it easy to integrate with any state management solution:
|
|
280
351
|
|
|
352
|
+
#### Redux
|
|
281
353
|
```tsx
|
|
282
|
-
import {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
} from 'json-schema-builder-react';
|
|
354
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
355
|
+
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
356
|
+
import { updateSchema } from './schemaSlice';
|
|
286
357
|
|
|
287
|
-
function
|
|
288
|
-
const
|
|
358
|
+
function App() {
|
|
359
|
+
const schema = useSelector(state => state.schema);
|
|
360
|
+
const dispatch = useDispatch();
|
|
289
361
|
|
|
290
362
|
return (
|
|
291
|
-
<
|
|
292
|
-
{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
property={property}
|
|
296
|
-
onUpdate={(updated) => updateProperty(property.id, updated)}
|
|
297
|
-
onDelete={() => deleteProperty(property.id)}
|
|
298
|
-
/>
|
|
299
|
-
))}
|
|
300
|
-
</div>
|
|
363
|
+
<JsonSchemaBuilder
|
|
364
|
+
schema={schema}
|
|
365
|
+
onChange={(newSchema) => dispatch(updateSchema(newSchema))}
|
|
366
|
+
/>
|
|
301
367
|
);
|
|
302
368
|
}
|
|
303
369
|
```
|
|
304
370
|
|
|
305
|
-
|
|
306
|
-
|
|
371
|
+
#### Zustand
|
|
307
372
|
```tsx
|
|
308
|
-
import {
|
|
309
|
-
import
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
{
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
id: '2',
|
|
324
|
-
key: 'email',
|
|
325
|
-
type: 'string',
|
|
326
|
-
required: true,
|
|
327
|
-
constraints: {
|
|
328
|
-
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$'
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
];
|
|
332
|
-
|
|
333
|
-
const schema = generateSchema(
|
|
334
|
-
properties,
|
|
335
|
-
{ title: 'User Schema', description: 'User registration', version: '1.0.0' },
|
|
336
|
-
true
|
|
337
|
-
);
|
|
373
|
+
import { useSchemaStore } from './store';
|
|
374
|
+
import { JsonSchemaBuilder } from 'json-schema-builder-react';
|
|
375
|
+
|
|
376
|
+
function App() {
|
|
377
|
+
const { schema, setSchema } = useSchemaStore();
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
<JsonSchemaBuilder
|
|
381
|
+
schema={schema}
|
|
382
|
+
onChange={setSchema}
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
338
386
|
```
|
|
339
387
|
|
|
340
388
|
## Development
|
|
@@ -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;
|