@petrarca/sonnet-forms 0.1.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.md +190 -0
- package/dist/index.d.ts +1148 -0
- package/dist/index.js +3593 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1148 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React$1 from 'react';
|
|
3
|
+
import React__default, { ComponentType } from 'react';
|
|
4
|
+
import { Input, Textarea, badgeVariants } from '@petrarca/sonnet-ui';
|
|
5
|
+
import { JsonSchemaProperty, UILayoutConfig, JsonSchema, UISchema, UISchemaOptions, FormDiff } from '@petrarca/sonnet-core/schema';
|
|
6
|
+
export { UISchema, UISchemaOptions } from '@petrarca/sonnet-core/schema';
|
|
7
|
+
import { VariantProps } from 'class-variance-authority';
|
|
8
|
+
|
|
9
|
+
interface FormFieldWrapperProps {
|
|
10
|
+
/** Field id -- wired to the label's htmlFor */
|
|
11
|
+
inputId: string;
|
|
12
|
+
/** Visible label text (false = explicitly hidden) */
|
|
13
|
+
label?: string | false;
|
|
14
|
+
/** Helper text shown below the control */
|
|
15
|
+
description?: string;
|
|
16
|
+
/** Validation error message (takes precedence over description for aria-describedby) */
|
|
17
|
+
error?: string;
|
|
18
|
+
/** Shows a required asterisk next to the label */
|
|
19
|
+
required?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Compact mode -- suppresses label, description, and error text so the
|
|
22
|
+
* cell height stays fixed in horizontal grid layouts. Error state is
|
|
23
|
+
* still communicated via the control's own styling (e.g. red border).
|
|
24
|
+
*/
|
|
25
|
+
compact?: boolean;
|
|
26
|
+
/** Additional class name for the outer wrapper div */
|
|
27
|
+
className?: string;
|
|
28
|
+
/** The form control(s) */
|
|
29
|
+
children: React__default.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* FormFieldWrapper renders label, children (the control), description, and
|
|
33
|
+
* error in the standard vertical layout used by all form field components.
|
|
34
|
+
*/
|
|
35
|
+
declare function FormFieldWrapper({ inputId, label, description, error, required, compact, className, children, }: FormFieldWrapperProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Shared utility functions for form field components.
|
|
39
|
+
* Kept separate from FormFieldWrapper so the wrapper file exports only
|
|
40
|
+
* components (required for React fast-refresh).
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Returns the correct aria-describedby id for a form control:
|
|
44
|
+
* - error id when there is an error (screen readers announce errors immediately)
|
|
45
|
+
* - description id when there is only a description
|
|
46
|
+
* - undefined when neither is present
|
|
47
|
+
*/
|
|
48
|
+
declare function getAriaDescribedBy(inputId: string, error: string | undefined, description: string | undefined): string | undefined;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* FormInput - Input wrapper with label, description, and error support
|
|
52
|
+
*
|
|
53
|
+
* Wraps shadcn Input with form field features to match Mantine TextInput API:
|
|
54
|
+
* - Label with required indicator
|
|
55
|
+
* - Description text
|
|
56
|
+
* - Error message display
|
|
57
|
+
* - Proper accessibility attributes
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
interface FormInputProps extends React__default.ComponentPropsWithoutRef<typeof Input> {
|
|
61
|
+
/** Input label (false = hide label) */
|
|
62
|
+
label?: string | false;
|
|
63
|
+
/** Description text shown below label */
|
|
64
|
+
description?: string;
|
|
65
|
+
/** Error message to display */
|
|
66
|
+
error?: string;
|
|
67
|
+
/** Whether the field is required */
|
|
68
|
+
required?: boolean;
|
|
69
|
+
/** Additional class name for the wrapper */
|
|
70
|
+
wrapperClassName?: string;
|
|
71
|
+
/** Right section content (e.g., icons, buttons) */
|
|
72
|
+
rightSection?: React__default.ReactNode;
|
|
73
|
+
/** Width of the right section in pixels (for padding adjustment) */
|
|
74
|
+
rightSectionWidth?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Compact mode -- suppresses label, description, and error text so the
|
|
77
|
+
* cell height stays fixed in horizontal grid layouts. Error state is
|
|
78
|
+
* still communicated via a red border on the input.
|
|
79
|
+
*/
|
|
80
|
+
compact?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* FormInput component with label, description, and error handling
|
|
84
|
+
*/
|
|
85
|
+
declare const FormInput: React__default.ForwardRefExoticComponent<FormInputProps & React__default.RefAttributes<HTMLInputElement>>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* FormTextarea - Textarea wrapper with label, description, error, and autosize support
|
|
89
|
+
*
|
|
90
|
+
* Wraps shadcn Textarea with form field features to match Mantine Textarea API:
|
|
91
|
+
* - Label with required indicator
|
|
92
|
+
* - Description text
|
|
93
|
+
* - Error message display
|
|
94
|
+
* - Auto-resize functionality (via useEffect)
|
|
95
|
+
* - Proper accessibility attributes
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
interface FormTextareaProps extends React__default.ComponentPropsWithoutRef<typeof Textarea> {
|
|
99
|
+
/** Textarea label (false = hide label) */
|
|
100
|
+
label?: string | false;
|
|
101
|
+
/** Description text shown below label */
|
|
102
|
+
description?: string;
|
|
103
|
+
/** Error message to display */
|
|
104
|
+
error?: string;
|
|
105
|
+
/** Whether the field is required */
|
|
106
|
+
required?: boolean;
|
|
107
|
+
/** Additional class name for the wrapper */
|
|
108
|
+
wrapperClassName?: string;
|
|
109
|
+
/** Enable auto-resize behavior (default: false) */
|
|
110
|
+
autosize?: boolean;
|
|
111
|
+
/** Minimum number of rows when autosize is enabled (default: 3) */
|
|
112
|
+
minRows?: number;
|
|
113
|
+
/** Right section content (e.g., action buttons) */
|
|
114
|
+
rightSection?: React__default.ReactNode;
|
|
115
|
+
/** Width of the right section in pixels (for padding adjustment) */
|
|
116
|
+
rightSectionWidth?: number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* FormTextarea component with label, description, error, and autosize handling
|
|
120
|
+
*/
|
|
121
|
+
declare const FormTextarea: React__default.ForwardRefExoticComponent<FormTextareaProps & React__default.RefAttributes<HTMLTextAreaElement>>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* FormNumberInput - Number input wrapper with label, description, error, and numeric constraints.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
interface FormNumberInputProps {
|
|
128
|
+
/** Input value */
|
|
129
|
+
value?: number | string;
|
|
130
|
+
/** Input label */
|
|
131
|
+
label?: string;
|
|
132
|
+
/** Description text shown below input */
|
|
133
|
+
description?: string;
|
|
134
|
+
/** Error message to display */
|
|
135
|
+
error?: string;
|
|
136
|
+
/** Placeholder text */
|
|
137
|
+
placeholder?: string;
|
|
138
|
+
/** Whether the field is required */
|
|
139
|
+
required?: boolean;
|
|
140
|
+
/** Whether the input is disabled */
|
|
141
|
+
disabled?: boolean;
|
|
142
|
+
/** Whether the input is read-only */
|
|
143
|
+
readOnly?: boolean;
|
|
144
|
+
/** Minimum value */
|
|
145
|
+
min?: number;
|
|
146
|
+
/** Maximum value */
|
|
147
|
+
max?: number;
|
|
148
|
+
/** Step increment/decrement value */
|
|
149
|
+
step?: number;
|
|
150
|
+
/** Allow decimal values (if false, only integers) */
|
|
151
|
+
allowDecimal?: boolean;
|
|
152
|
+
/** Change handler - receives number or undefined */
|
|
153
|
+
onChange?: (value: number | undefined) => void;
|
|
154
|
+
/** Blur handler */
|
|
155
|
+
onBlur?: React__default.FocusEventHandler<HTMLInputElement>;
|
|
156
|
+
/** Auto-focus on mount */
|
|
157
|
+
autoFocus?: boolean;
|
|
158
|
+
/** Additional class name for the wrapper */
|
|
159
|
+
wrapperClassName?: string;
|
|
160
|
+
/** Additional class name for the input */
|
|
161
|
+
className?: string;
|
|
162
|
+
/** Input ID */
|
|
163
|
+
id?: string;
|
|
164
|
+
/** Input name */
|
|
165
|
+
name?: string;
|
|
166
|
+
}
|
|
167
|
+
declare const FormNumberInput: React__default.ForwardRefExoticComponent<FormNumberInputProps & React__default.RefAttributes<HTMLInputElement>>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* FormCheckbox - Checkbox wrapper with label, description, error, and indeterminate support
|
|
171
|
+
*
|
|
172
|
+
* Wraps shadcn Checkbox with form field features to match Mantine Checkbox API:
|
|
173
|
+
* - Inline label (checkbox + label on same line)
|
|
174
|
+
* - Description text
|
|
175
|
+
* - Error message display
|
|
176
|
+
* - Indeterminate state support (tri-state)
|
|
177
|
+
* - Proper accessibility attributes
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
interface FormCheckboxProps {
|
|
181
|
+
/** Checkbox checked state (boolean or 'indeterminate') */
|
|
182
|
+
checked?: boolean | "indeterminate";
|
|
183
|
+
/** Checkbox label (displayed inline, false = hide label) */
|
|
184
|
+
label?: string | false;
|
|
185
|
+
/** Description text shown below checkbox */
|
|
186
|
+
description?: string;
|
|
187
|
+
/** Error message to display */
|
|
188
|
+
error?: string;
|
|
189
|
+
/** Whether the field is required */
|
|
190
|
+
required?: boolean;
|
|
191
|
+
/** Whether the checkbox is disabled */
|
|
192
|
+
disabled?: boolean;
|
|
193
|
+
/** Whether the checkbox is read-only */
|
|
194
|
+
readOnly?: boolean;
|
|
195
|
+
/** Change handler */
|
|
196
|
+
onChange?: (checked: boolean | "indeterminate") => void;
|
|
197
|
+
/** Blur handler */
|
|
198
|
+
onBlur?: React__default.FocusEventHandler<HTMLButtonElement>;
|
|
199
|
+
/** Auto-focus on mount */
|
|
200
|
+
autoFocus?: boolean;
|
|
201
|
+
/** Additional class name for the wrapper */
|
|
202
|
+
wrapperClassName?: string;
|
|
203
|
+
/** Additional class name for the checkbox */
|
|
204
|
+
className?: string;
|
|
205
|
+
/** Input ID */
|
|
206
|
+
id?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Compact mode -- suppresses label, description, and error text so the
|
|
209
|
+
* cell height stays fixed in horizontal grid layouts. Error state is
|
|
210
|
+
* still communicated via a red border on the checkbox.
|
|
211
|
+
*/
|
|
212
|
+
compact?: boolean;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* FormCheckbox component with label, description, error, and indeterminate handling
|
|
216
|
+
*/
|
|
217
|
+
declare const FormCheckbox: React__default.ForwardRefExoticComponent<FormCheckboxProps & React__default.RefAttributes<HTMLButtonElement>>;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Widget Type System
|
|
221
|
+
*
|
|
222
|
+
* Type definitions for the JSON Schema Form widget architecture.
|
|
223
|
+
* Based on react-jsonschema-form patterns with simplified Mantine-focused implementation.
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* WidgetRegistry - Map of widget name to component
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const registry: WidgetRegistry = {
|
|
232
|
+
* TextWidget: TextWidget,
|
|
233
|
+
* SelectWidget: SelectWidget,
|
|
234
|
+
* CustomWidget: MyCustomWidget
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
type WidgetRegistry = {
|
|
239
|
+
[widgetName: string]: Widget;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* WidgetProps - Props passed to every widget
|
|
243
|
+
*
|
|
244
|
+
* Widgets receive comprehensive context to make intelligent decisions.
|
|
245
|
+
* All widgets must accept these props.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* export function MyWidget({
|
|
250
|
+
* id,
|
|
251
|
+
* value,
|
|
252
|
+
* onChange,
|
|
253
|
+
* label,
|
|
254
|
+
* propertySchema,
|
|
255
|
+
* options
|
|
256
|
+
* }: WidgetProps) {
|
|
257
|
+
* const customOption = options?.myCustomOption ?? 'default';
|
|
258
|
+
* // ...
|
|
259
|
+
* }
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
interface WidgetProps {
|
|
263
|
+
/** Unique field ID */
|
|
264
|
+
id: string;
|
|
265
|
+
/** Field name */
|
|
266
|
+
name: string;
|
|
267
|
+
/** Full form schema */
|
|
268
|
+
schema: JsonSchema;
|
|
269
|
+
/** This field's schema */
|
|
270
|
+
propertySchema: JsonSchemaProperty;
|
|
271
|
+
/** UI configuration for this field */
|
|
272
|
+
uiSchema?: UISchema;
|
|
273
|
+
/** Access to all widgets */
|
|
274
|
+
registry: WidgetRegistry;
|
|
275
|
+
/** Current field value */
|
|
276
|
+
value: unknown;
|
|
277
|
+
/** Called when value changes */
|
|
278
|
+
onChange: (value: unknown) => void;
|
|
279
|
+
/** Called when field loses focus */
|
|
280
|
+
onBlur?: (id: string, value: unknown) => void;
|
|
281
|
+
/** Called when field gains focus */
|
|
282
|
+
onFocus?: (id: string, value: unknown) => void;
|
|
283
|
+
/** Current form data - all field values (for dependent/cascading widgets) */
|
|
284
|
+
formData?: Record<string, unknown>;
|
|
285
|
+
/** Field label (empty string = hidden) */
|
|
286
|
+
label: string;
|
|
287
|
+
/** Field description */
|
|
288
|
+
description?: string;
|
|
289
|
+
/** Placeholder text */
|
|
290
|
+
placeholder?: string;
|
|
291
|
+
/** Is field required */
|
|
292
|
+
required?: boolean;
|
|
293
|
+
/** Is field disabled */
|
|
294
|
+
disabled?: boolean;
|
|
295
|
+
/** Is field readonly */
|
|
296
|
+
readonly?: boolean;
|
|
297
|
+
/** Should field autofocus */
|
|
298
|
+
autofocus?: boolean;
|
|
299
|
+
/** Raw validation errors */
|
|
300
|
+
rawErrors?: string[];
|
|
301
|
+
/** Widget-specific options from x-ui-options */
|
|
302
|
+
options?: UISchemaOptions;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Widget - React component type for form widgets
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* const TextWidget: Widget = ({ id, value, onChange, label }) => (
|
|
310
|
+
* <TextInput id={id} value={value} onChange={e => onChange(e.target.value)} label={label} />
|
|
311
|
+
* );
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
type Widget = ComponentType<WidgetProps>;
|
|
315
|
+
/**
|
|
316
|
+
* WidgetDescriptor - Extended information for widget registration
|
|
317
|
+
*
|
|
318
|
+
* Allows providing metadata along with the widget component.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```typescript
|
|
322
|
+
* const descriptor: WidgetDescriptor = {
|
|
323
|
+
* component: MyWidget,
|
|
324
|
+
* displayName: 'My Custom Widget',
|
|
325
|
+
* description: 'A widget for custom input',
|
|
326
|
+
* defaultOptions: { rows: 3 }
|
|
327
|
+
* }
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
interface WidgetDescriptor {
|
|
331
|
+
/** The widget component */
|
|
332
|
+
component: Widget;
|
|
333
|
+
/** Display name for debugging */
|
|
334
|
+
displayName?: string;
|
|
335
|
+
/** Description of what the widget does */
|
|
336
|
+
description?: string;
|
|
337
|
+
/** Default options to apply */
|
|
338
|
+
defaultOptions?: UISchemaOptions;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* WidgetMap - Type/format to widget name mapping
|
|
342
|
+
*
|
|
343
|
+
* Defines the default widget to use for each schema type and format.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```typescript
|
|
347
|
+
* const map: WidgetMap = {
|
|
348
|
+
* string: {
|
|
349
|
+
* default: 'TextWidget',
|
|
350
|
+
* email: 'EmailWidget',
|
|
351
|
+
* textarea: 'TextareaWidget'
|
|
352
|
+
* }
|
|
353
|
+
* }
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
type WidgetMap = {
|
|
357
|
+
[schemaType: string]: {
|
|
358
|
+
[variantOrFormat: string]: string;
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Return the first validation error message, or undefined if there are none.
|
|
363
|
+
* Avoids repeating `rawErrors && rawErrors.length > 0 ? rawErrors[0] : undefined`
|
|
364
|
+
* in every widget.
|
|
365
|
+
*/
|
|
366
|
+
declare function firstError(rawErrors?: string[]): string | undefined;
|
|
367
|
+
/**
|
|
368
|
+
* SelectOption - Single option in a select dropdown
|
|
369
|
+
*/
|
|
370
|
+
interface SelectOption {
|
|
371
|
+
value: string;
|
|
372
|
+
label: string;
|
|
373
|
+
}
|
|
374
|
+
/** Props passed to an ArrayItemTemplate */
|
|
375
|
+
interface ArrayItemTemplateProps {
|
|
376
|
+
children: React.ReactNode;
|
|
377
|
+
index: number;
|
|
378
|
+
total: number;
|
|
379
|
+
canRemove: boolean;
|
|
380
|
+
orderable: boolean;
|
|
381
|
+
disabled?: boolean;
|
|
382
|
+
layout: UILayoutConfig;
|
|
383
|
+
fieldCount: number;
|
|
384
|
+
onRemove: () => void;
|
|
385
|
+
onMoveUp?: () => void;
|
|
386
|
+
onMoveDown?: () => void;
|
|
387
|
+
}
|
|
388
|
+
/** Props passed to an ArrayHeaderTemplate */
|
|
389
|
+
interface ArrayHeaderTemplateProps {
|
|
390
|
+
itemSchema: JsonSchemaProperty;
|
|
391
|
+
layout: UILayoutConfig;
|
|
392
|
+
canRemove: boolean;
|
|
393
|
+
orderable: boolean;
|
|
394
|
+
fieldCount: number;
|
|
395
|
+
}
|
|
396
|
+
/** Props passed to an ObjectContainerTemplate */
|
|
397
|
+
interface ObjectContainerTemplateProps {
|
|
398
|
+
children: React.ReactNode;
|
|
399
|
+
label: string;
|
|
400
|
+
description?: string;
|
|
401
|
+
variant?: string;
|
|
402
|
+
defaultOpen?: boolean;
|
|
403
|
+
}
|
|
404
|
+
type ArrayItemTemplate = (props: ArrayItemTemplateProps) => React.ReactElement;
|
|
405
|
+
type ArrayHeaderTemplate = (props: ArrayHeaderTemplateProps) => React.ReactElement | null;
|
|
406
|
+
type ObjectContainerTemplate = (props: ObjectContainerTemplateProps) => React.ReactElement;
|
|
407
|
+
/**
|
|
408
|
+
* TemplateRegistry -- named rendering functions for structural layout.
|
|
409
|
+
*
|
|
410
|
+
* Built-in keys: ArrayItemTemplate, ArrayHeaderTemplate, ObjectContainerTemplate.
|
|
411
|
+
* Custom keys are allowed for per-field template overrides (looked up by name).
|
|
412
|
+
* The index signature uses `unknown` to avoid TypeScript variance conflicts with
|
|
413
|
+
* the specifically-typed named properties.
|
|
414
|
+
*/
|
|
415
|
+
type TemplateRegistry = {
|
|
416
|
+
ArrayItemTemplate?: ArrayItemTemplate;
|
|
417
|
+
HorizontalArrayItemTemplate?: ArrayItemTemplate;
|
|
418
|
+
ArrayHeaderTemplate?: ArrayHeaderTemplate;
|
|
419
|
+
ObjectContainerTemplate?: ObjectContainerTemplate;
|
|
420
|
+
[templateName: string]: unknown;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
interface FormSelectProps {
|
|
424
|
+
label?: string | false;
|
|
425
|
+
description?: string;
|
|
426
|
+
error?: string;
|
|
427
|
+
required?: boolean;
|
|
428
|
+
wrapperClassName?: string;
|
|
429
|
+
/**
|
|
430
|
+
* Compact mode -- suppresses label, description, and error text so the
|
|
431
|
+
* cell height stays fixed in horizontal grid layouts. Error state is
|
|
432
|
+
* still communicated via a red border on the trigger button.
|
|
433
|
+
*/
|
|
434
|
+
compact?: boolean;
|
|
435
|
+
options: SelectOption[];
|
|
436
|
+
value?: string | null;
|
|
437
|
+
onChange?: (value: string | null) => void;
|
|
438
|
+
onBlur?: () => void;
|
|
439
|
+
placeholder?: string;
|
|
440
|
+
searchPlaceholder?: string;
|
|
441
|
+
emptyMessage?: string;
|
|
442
|
+
clearable?: boolean;
|
|
443
|
+
disabled?: boolean;
|
|
444
|
+
readOnly?: boolean;
|
|
445
|
+
loading?: boolean;
|
|
446
|
+
className?: string;
|
|
447
|
+
id?: string;
|
|
448
|
+
name?: string;
|
|
449
|
+
autoFocus?: boolean;
|
|
450
|
+
}
|
|
451
|
+
declare function FormSelect(props: FormSelectProps): react_jsx_runtime.JSX.Element;
|
|
452
|
+
|
|
453
|
+
type BadgeColor = NonNullable<VariantProps<typeof badgeVariants>["badgeColor"]>;
|
|
454
|
+
|
|
455
|
+
interface FormMultiSelectProps {
|
|
456
|
+
label?: string | false;
|
|
457
|
+
description?: string;
|
|
458
|
+
error?: string;
|
|
459
|
+
required?: boolean;
|
|
460
|
+
wrapperClassName?: string;
|
|
461
|
+
options: SelectOption[];
|
|
462
|
+
value?: string[];
|
|
463
|
+
onChange?: (value: string[]) => void;
|
|
464
|
+
onBlur?: () => void;
|
|
465
|
+
placeholder?: string;
|
|
466
|
+
searchPlaceholder?: string;
|
|
467
|
+
emptyMessage?: string;
|
|
468
|
+
clearable?: boolean;
|
|
469
|
+
disabled?: boolean;
|
|
470
|
+
readOnly?: boolean;
|
|
471
|
+
loading?: boolean;
|
|
472
|
+
className?: string;
|
|
473
|
+
id?: string;
|
|
474
|
+
name?: string;
|
|
475
|
+
autoFocus?: boolean;
|
|
476
|
+
maxDisplay?: number;
|
|
477
|
+
badgeColor?: BadgeColor;
|
|
478
|
+
}
|
|
479
|
+
declare function FormMultiSelect(props: FormMultiSelectProps): react_jsx_runtime.JSX.Element;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* FormTagsInput - Input field for managing tags with badges
|
|
483
|
+
*
|
|
484
|
+
* Allows adding tags by pressing Enter or comma, removing tags via X button
|
|
485
|
+
* or backspace. Displays tags as badges. Follows Form wrapper pattern with
|
|
486
|
+
* label, description, error support.
|
|
487
|
+
*/
|
|
488
|
+
|
|
489
|
+
interface FormTagsInputProps {
|
|
490
|
+
label?: string | false;
|
|
491
|
+
description?: string;
|
|
492
|
+
error?: string;
|
|
493
|
+
required?: boolean;
|
|
494
|
+
wrapperClassName?: string;
|
|
495
|
+
id?: string;
|
|
496
|
+
name?: string;
|
|
497
|
+
value: string[];
|
|
498
|
+
onChange?: (tags: string[]) => void;
|
|
499
|
+
placeholder?: string;
|
|
500
|
+
disabled?: boolean;
|
|
501
|
+
readOnly?: boolean;
|
|
502
|
+
maxTags?: number;
|
|
503
|
+
splitKeys?: string[];
|
|
504
|
+
allowDuplicates?: boolean;
|
|
505
|
+
}
|
|
506
|
+
declare const FormTagsInput: React$1.ForwardRefExoticComponent<FormTagsInputProps & React$1.RefAttributes<HTMLInputElement>>;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* FormQuantityInput - Compound input for a numeric value paired with a unit selector.
|
|
510
|
+
*
|
|
511
|
+
* Renders as a single visual control using InputGroup: the numeric input fills
|
|
512
|
+
* the left side; the unit selector (or static text) sits inside the right (or
|
|
513
|
+
* left) edge of the same border as an inline addon.
|
|
514
|
+
*
|
|
515
|
+
* Value shape: { value: number | undefined, unit: string }
|
|
516
|
+
*
|
|
517
|
+
* Decimal handling: uses inputMode="decimal" with type="text" to support
|
|
518
|
+
* international decimal separators (comma and period). Input is validated and
|
|
519
|
+
* normalized on blur, not on every keystroke, to allow intermediate states
|
|
520
|
+
* such as "37." or "-".
|
|
521
|
+
*
|
|
522
|
+
* NOTE on precision: toFixed() uses IEEE 754 rounding. For values where exact
|
|
523
|
+
* decimal representation matters (e.g. financial amounts), the caller should
|
|
524
|
+
* round the emitted number independently before storing it.
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
/** Compound quantity value: numeric value + unit code */
|
|
528
|
+
interface QuantityValue {
|
|
529
|
+
value: number | undefined;
|
|
530
|
+
unit: string;
|
|
531
|
+
}
|
|
532
|
+
/** Where the unit label renders relative to the numeric input */
|
|
533
|
+
type UnitPosition = "prefix" | "suffix";
|
|
534
|
+
/** A unit option with optional per-unit validation constraints and position */
|
|
535
|
+
interface UnitOption extends SelectOption {
|
|
536
|
+
/** Minimum allowed value for this unit */
|
|
537
|
+
min?: number;
|
|
538
|
+
/** Maximum allowed value for this unit */
|
|
539
|
+
max?: number;
|
|
540
|
+
/** Where to render this unit relative to the value (default: "suffix") */
|
|
541
|
+
position?: UnitPosition;
|
|
542
|
+
}
|
|
543
|
+
interface FormQuantityInputProps {
|
|
544
|
+
/** Controlled compound value */
|
|
545
|
+
value?: QuantityValue;
|
|
546
|
+
/** Change handler -- receives the updated quantity */
|
|
547
|
+
onChange?: (value: QuantityValue) => void;
|
|
548
|
+
/** Blur handler */
|
|
549
|
+
onBlur?: () => void;
|
|
550
|
+
/** Available unit options. Single = static text, 2+ = dropdown, none = no addon. */
|
|
551
|
+
units?: UnitOption[];
|
|
552
|
+
/**
|
|
553
|
+
* Default position for all units. Individual UnitOption.position overrides
|
|
554
|
+
* this. Default: "suffix".
|
|
555
|
+
*/
|
|
556
|
+
unitPosition?: UnitPosition;
|
|
557
|
+
/**
|
|
558
|
+
* Decimal places to format on blur (undefined = no formatting).
|
|
559
|
+
* Uses toFixed() -- see IEEE 754 note in file header.
|
|
560
|
+
*/
|
|
561
|
+
precision?: number;
|
|
562
|
+
/** Arrow-key step increment */
|
|
563
|
+
step?: number;
|
|
564
|
+
/** Global minimum (overridden by per-unit min when present) */
|
|
565
|
+
min?: number;
|
|
566
|
+
/** Global maximum (overridden by per-unit max when present) */
|
|
567
|
+
max?: number;
|
|
568
|
+
/** Visible label */
|
|
569
|
+
label?: string;
|
|
570
|
+
/** Helper text shown below the control */
|
|
571
|
+
description?: string;
|
|
572
|
+
/** Validation error message */
|
|
573
|
+
error?: string;
|
|
574
|
+
/** Placeholder for the numeric input */
|
|
575
|
+
placeholder?: string;
|
|
576
|
+
/** Shows a required asterisk */
|
|
577
|
+
required?: boolean;
|
|
578
|
+
disabled?: boolean;
|
|
579
|
+
readOnly?: boolean;
|
|
580
|
+
autoFocus?: boolean;
|
|
581
|
+
/** Additional class name for the outer wrapper */
|
|
582
|
+
wrapperClassName?: string;
|
|
583
|
+
/** Additional class name for the numeric input */
|
|
584
|
+
className?: string;
|
|
585
|
+
id?: string;
|
|
586
|
+
name?: string;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* FormQuantityInput -- controlled compound numeric + unit input in a single
|
|
590
|
+
* InputGroup border. See file header for behavioural notes.
|
|
591
|
+
*/
|
|
592
|
+
declare const FormQuantityInput: React__default.ForwardRefExoticComponent<FormQuantityInputProps & React__default.RefAttributes<HTMLInputElement>>;
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* FormActions - Save / Cancel button row for buffered forms
|
|
596
|
+
*
|
|
597
|
+
* Rendered only when the parent JsonSchemaFormRenderer is in buffered mode
|
|
598
|
+
* (showActions=true). Keeps button logic out of the orchestrator.
|
|
599
|
+
*
|
|
600
|
+
* @module components/Forms/FormActions
|
|
601
|
+
*/
|
|
602
|
+
interface FormActionsProps {
|
|
603
|
+
onSave: () => void;
|
|
604
|
+
onCancel: () => void;
|
|
605
|
+
disabled?: boolean;
|
|
606
|
+
hasChanges: boolean;
|
|
607
|
+
isValid: boolean;
|
|
608
|
+
saveLabel?: string;
|
|
609
|
+
cancelLabel?: string;
|
|
610
|
+
showCancel?: boolean;
|
|
611
|
+
}
|
|
612
|
+
declare function FormActions({ onSave, onCancel, disabled, hasChanges, isValid, saveLabel, cancelLabel, showCancel, }: FormActionsProps): react_jsx_runtime.JSX.Element;
|
|
613
|
+
|
|
614
|
+
type Props = {
|
|
615
|
+
properties: Record<string, any>;
|
|
616
|
+
schema: JsonSchema | null;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Displays properties that are not defined in the JSON Schema.
|
|
620
|
+
* Shown as a collapsible card, closed by default.
|
|
621
|
+
*
|
|
622
|
+
* This is a generic component that can be used anywhere a schema and properties
|
|
623
|
+
* need to be compared to show additional/extra properties.
|
|
624
|
+
*/
|
|
625
|
+
declare function ExtraPropertiesCard({ properties, schema }: Props): react_jsx_runtime.JSX.Element | null;
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* TextInputWidget - Standard text input widget
|
|
629
|
+
*
|
|
630
|
+
* Renders a single-line text input field using FormInput.
|
|
631
|
+
* Supports various input types via format (email, url, text).
|
|
632
|
+
*/
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* TextInputWidget renders a standard text input field.
|
|
636
|
+
*
|
|
637
|
+
* Supports:
|
|
638
|
+
* - Basic string input
|
|
639
|
+
* - Email input (format: 'email')
|
|
640
|
+
* - URL input (format: 'uri' or 'url')
|
|
641
|
+
* - Validation constraints (minLength, maxLength, pattern)
|
|
642
|
+
*/
|
|
643
|
+
declare function TextInputWidget({ id, name, value, onChange, onBlur, propertySchema, required, disabled, readonly, rawErrors, label, description, placeholder, autofocus, options, }: WidgetProps): React.ReactElement;
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* TextareaWidget renders a multi-line text input field.
|
|
647
|
+
*
|
|
648
|
+
* Supports:
|
|
649
|
+
* - Multi-line text input
|
|
650
|
+
* - Autosize functionality
|
|
651
|
+
* - Configurable minimum rows via x-ui-options
|
|
652
|
+
* - Validation constraints (minLength, maxLength)
|
|
653
|
+
*
|
|
654
|
+
* @param props - WidgetProps
|
|
655
|
+
*/
|
|
656
|
+
declare function TextareaWidget({ id, name, value, onChange, onBlur, propertySchema, required, disabled, readonly, rawErrors, label, description, placeholder, autofocus, options, }: WidgetProps): react_jsx_runtime.JSX.Element;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* NumberWidget renders a number input field.
|
|
660
|
+
*
|
|
661
|
+
* Supports:
|
|
662
|
+
* - Number input (decimal allowed)
|
|
663
|
+
* - Integer input (step = 1, no decimals)
|
|
664
|
+
* - Min/max constraints from schema
|
|
665
|
+
* - Step configuration via x-ui-options
|
|
666
|
+
*
|
|
667
|
+
* @param props - WidgetProps
|
|
668
|
+
*/
|
|
669
|
+
declare function NumberWidget({ id, name, value, onChange, onBlur, propertySchema, required, disabled, readonly, rawErrors, label, description, placeholder, autofocus, options, }: WidgetProps): react_jsx_runtime.JSX.Element;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* CheckboxWidget - Boolean checkbox widget
|
|
673
|
+
*
|
|
674
|
+
* Renders a checkbox input using FormCheckbox.
|
|
675
|
+
* Used for boolean type fields.
|
|
676
|
+
*
|
|
677
|
+
* Supports tri-state behavior for nullable boolean fields (anyOf[boolean, null]):
|
|
678
|
+
* - null (indeterminate) -> true (checked) -> false (unchecked) -> null
|
|
679
|
+
*/
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* CheckboxWidget renders a checkbox for boolean values.
|
|
683
|
+
*
|
|
684
|
+
* Supports:
|
|
685
|
+
* - Boolean true/false values (standard checkbox)
|
|
686
|
+
* - Tri-state true/false/null values (indeterminate checkbox)
|
|
687
|
+
* - Custom labels from schema or UISchema
|
|
688
|
+
* - Description text
|
|
689
|
+
*
|
|
690
|
+
* Tri-state behavior (when anyOf[boolean, null] is detected):
|
|
691
|
+
* - Click on null -> becomes true
|
|
692
|
+
* - Click on true -> becomes false
|
|
693
|
+
* - Click on false -> becomes null
|
|
694
|
+
*/
|
|
695
|
+
declare function CheckboxWidget({ id, value, onChange, onBlur, disabled, readonly, rawErrors, label, description, autofocus, propertySchema, options, }: WidgetProps): React.ReactElement;
|
|
696
|
+
|
|
697
|
+
declare function SelectWidget(props: WidgetProps): react_jsx_runtime.JSX.Element;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* TagsInputWidget - Free-text tag input widget
|
|
701
|
+
*
|
|
702
|
+
* Renders FormTagsInput for array-of-string fields where the user types
|
|
703
|
+
* free-text values (no predefined enum). Tags are entered by pressing
|
|
704
|
+
* Enter or comma and displayed as dismissible badges. Duplicates are
|
|
705
|
+
* rejected by default.
|
|
706
|
+
*
|
|
707
|
+
* Use via x-ui-widget: "tags" in a JSON Schema or Zod .meta().
|
|
708
|
+
*/
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* TagsInputWidget renders a free-text tag input field.
|
|
712
|
+
*
|
|
713
|
+
* Supports:
|
|
714
|
+
* - Free-text tag creation (Enter or comma)
|
|
715
|
+
* - Duplicate rejection (default)
|
|
716
|
+
* - Max tags limit (via x-ui-options.maxTags)
|
|
717
|
+
* - Custom split keys (via x-ui-options.splitKeys)
|
|
718
|
+
*/
|
|
719
|
+
declare function TagsInputWidget({ id, name, value, onChange, required, disabled, readonly, rawErrors, label, description, placeholder, options, }: WidgetProps): React__default.ReactElement;
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* JsonEditorWidget - JSON document editor widget.
|
|
723
|
+
*
|
|
724
|
+
* Renders JsonEditor for object/any fields where the user authors raw JSON.
|
|
725
|
+
* The full document is editable. Invalid JSON is not propagated -- the last
|
|
726
|
+
* valid value is retained until the user fixes the syntax error.
|
|
727
|
+
*
|
|
728
|
+
* Use via x-ui-widget: "json-editor" in a JSON Schema or Zod .meta().
|
|
729
|
+
*/
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* JsonEditorWidget renders a full-document JSON editor.
|
|
733
|
+
*
|
|
734
|
+
* Supports:
|
|
735
|
+
* - Full document editing (no readonly regions)
|
|
736
|
+
* - Invalid JSON is silently retained until fixed
|
|
737
|
+
* - Height configurable via x-ui-options.height (default: "240px")
|
|
738
|
+
*/
|
|
739
|
+
declare function JsonEditorWidget({ id, value, onChange, label, description, required, options, }: WidgetProps): React__default.ReactElement;
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* EntitySelectWidget -- form widget for async entity reference selection.
|
|
743
|
+
*
|
|
744
|
+
* Wraps EntitySelect and adapts it to the WidgetProps contract. Reads
|
|
745
|
+
* x-ui-options for fetcher configuration (REST or GraphQL) and uses the
|
|
746
|
+
* FetcherProvider context to create the appropriate fetcher.
|
|
747
|
+
*
|
|
748
|
+
* Schema usage:
|
|
749
|
+
* x-ui-widget: "entity-select"
|
|
750
|
+
* x-ui-options: {
|
|
751
|
+
* endpoint: "/organizations", // REST: relative to API base
|
|
752
|
+
* valueKey: "org_id",
|
|
753
|
+
* labelKey: "name",
|
|
754
|
+
* }
|
|
755
|
+
* -- or --
|
|
756
|
+
* x-ui-options: {
|
|
757
|
+
* query: "query Orgs($search: String, $limit: Int) { ... }",
|
|
758
|
+
* dataPath: "organizations",
|
|
759
|
+
* valueKey: "org_id",
|
|
760
|
+
* labelKey: "name",
|
|
761
|
+
* }
|
|
762
|
+
*/
|
|
763
|
+
|
|
764
|
+
declare function EntitySelectWidget({ id, name, value, onChange, onBlur, label, description, placeholder, required, disabled, readonly, rawErrors, options, }: WidgetProps): React__default.ReactElement;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* ObjectWidget -- renders a nested sub-form for type: "object" properties.
|
|
768
|
+
*
|
|
769
|
+
* Composes a JsonSchemaFormRenderer scoped to the sub-schema. The renderer
|
|
770
|
+
* is injected via NestedFormContext so there is no circular import.
|
|
771
|
+
*
|
|
772
|
+
* Presentation is delegated to ObjectContainerTemplate (resolved from context,
|
|
773
|
+
* defaulting to DefaultObjectContainerTemplate). The variant passed via
|
|
774
|
+
* options controls which container is used (section, card, collapsible,
|
|
775
|
+
* inline, borderless).
|
|
776
|
+
*
|
|
777
|
+
* When options.displayContents is true (set by ArrayWidget in horizontal mode)
|
|
778
|
+
* the sub-renderer uses display:contents so its field divs become direct grid
|
|
779
|
+
* cells in the parent row grid.
|
|
780
|
+
*
|
|
781
|
+
* When options.globalOptions is set, it is forwarded to the sub-renderer so
|
|
782
|
+
* compact / label suppression propagates to all nested widgets.
|
|
783
|
+
*/
|
|
784
|
+
|
|
785
|
+
declare function ObjectWidget({ propertySchema, value, onChange, registry, uiSchema, disabled, readonly, label, description, options, }: WidgetProps): React.ReactElement | null;
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* ArrayWidget -- renders a repeatable list of sub-forms for
|
|
789
|
+
* type: "array" properties whose items have type: "object".
|
|
790
|
+
*
|
|
791
|
+
* Layout is template-driven. The active templates are resolved from
|
|
792
|
+
* NestedFormContext (injected by JsonSchemaFormRenderer):
|
|
793
|
+
* - ArrayItemTemplate -- how each item is wrapped (default: vertical card)
|
|
794
|
+
* - ArrayHeaderTemplate -- column headers for horizontal mode (default: none)
|
|
795
|
+
*
|
|
796
|
+
* Horizontal layout is activated by x-ui-layout.direction: "horizontal" on
|
|
797
|
+
* the array property or UISchema. The HorizontalArrayItemTemplate renders a
|
|
798
|
+
* CSS grid row; ObjectWidget sets displayContents=true on the sub-renderer so
|
|
799
|
+
* field divs become direct grid cells.
|
|
800
|
+
*
|
|
801
|
+
* Each item carries a stable form-internal ID (_fid) assigned via generateId().
|
|
802
|
+
* IDs are used as React keys and for structural diffing at save time. They
|
|
803
|
+
* never leave the renderer boundary.
|
|
804
|
+
*/
|
|
805
|
+
|
|
806
|
+
declare function ArrayWidget({ propertySchema, value, onChange, registry, uiSchema, disabled, readonly, label, description, options, schema, name, }: WidgetProps): React.ReactElement;
|
|
807
|
+
|
|
808
|
+
declare function QuantityWidget({ id, name, value, onChange, onBlur, propertySchema, required, disabled, readonly, rawErrors, label, description, placeholder, autofocus, options, }: WidgetProps): react_jsx_runtime.JSX.Element;
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Widget Resolution Algorithm
|
|
812
|
+
*
|
|
813
|
+
* Determines which widget to use for a given field based on:
|
|
814
|
+
* 0. Schema x-ui-widget and x-ui-options (merged with uiSchema if present)
|
|
815
|
+
* 1. UISchema x-ui-widget (highest priority - overrides x-ui-widget)
|
|
816
|
+
* 2. Schema x-ui-widget (for widget name)
|
|
817
|
+
* 3. Schema enum (uses SelectWidget)
|
|
818
|
+
* 4. Schema format (email, date, color, etc.)
|
|
819
|
+
* 5. Schema type (string, number, boolean, etc.)
|
|
820
|
+
* 6. Fallback to TextWidget
|
|
821
|
+
*
|
|
822
|
+
* x-ui-widget is a simple string: 'textarea', 'select', etc.
|
|
823
|
+
* x-ui-options is an object with configuration: { rows: 5, etc. }
|
|
824
|
+
*/
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Default widget mapping: schema type → format/variant → widget name
|
|
828
|
+
*
|
|
829
|
+
* This defines which widget to use for each combination of schema type and format.
|
|
830
|
+
* Follows the pattern established by react-jsonschema-form.
|
|
831
|
+
*
|
|
832
|
+
* Currently implemented widgets:
|
|
833
|
+
* - TextInputWidget: Basic text input (email, url formats supported)
|
|
834
|
+
* - TextareaWidget: Multi-line text input
|
|
835
|
+
* - NumberWidget: Number and integer input
|
|
836
|
+
* - CheckboxWidget: Boolean checkbox
|
|
837
|
+
* - SelectWidget: Dropdown for enum values
|
|
838
|
+
*/
|
|
839
|
+
declare const DEFAULT_WIDGET_MAP: WidgetMap;
|
|
840
|
+
declare function resolveWidget(propertySchema: JsonSchemaProperty, uiSchema: UISchema | undefined, registry: WidgetRegistry): Widget;
|
|
841
|
+
/**
|
|
842
|
+
* Get the default widget name for a schema type
|
|
843
|
+
*
|
|
844
|
+
* Helper function to determine the default widget for a given type
|
|
845
|
+
* without considering format or other factors.
|
|
846
|
+
*
|
|
847
|
+
* @param type - The JSON schema type
|
|
848
|
+
* @returns The default widget name for that type
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* getDefaultWidgetForType('string'); // 'TextInputWidget'
|
|
853
|
+
* getDefaultWidgetForType('number'); // 'NumberWidget'
|
|
854
|
+
* getDefaultWidgetForType('boolean'); // 'CheckboxWidget'
|
|
855
|
+
* ```
|
|
856
|
+
*/
|
|
857
|
+
declare function getDefaultWidgetForType(type: string): string;
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Form Widgets - Index and Registry
|
|
861
|
+
*
|
|
862
|
+
* Each widget is imported once and re-exported. The same binding is used in
|
|
863
|
+
* DEFAULT_WIDGETS to avoid the double-import anti-pattern.
|
|
864
|
+
*/
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* DEFAULT_WIDGETS - The default widget registry.
|
|
868
|
+
*
|
|
869
|
+
* Contains all built-in widgets mapped by their names.
|
|
870
|
+
* Use this as the base registry or extend it with custom widgets.
|
|
871
|
+
*
|
|
872
|
+
* @example
|
|
873
|
+
* ```typescript
|
|
874
|
+
* import { DEFAULT_WIDGETS } from './widgets';
|
|
875
|
+
* import MyCustomWidget from './MyCustomWidget';
|
|
876
|
+
*
|
|
877
|
+
* const registry = { ...DEFAULT_WIDGETS, MyCustomWidget };
|
|
878
|
+
* ```
|
|
879
|
+
*/
|
|
880
|
+
declare const DEFAULT_WIDGETS: WidgetRegistry;
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* JsonSchemaFormRenderer - Generic form renderer based on JSON Schema
|
|
884
|
+
*
|
|
885
|
+
* Thin orchestrator: composes useFormEngine, FormFieldRenderer, and FormActions.
|
|
886
|
+
*
|
|
887
|
+
* Supports three update modes:
|
|
888
|
+
* 1. Real-time (default) — onChange on every field change
|
|
889
|
+
* 2. Deferred (deferChanges=true) — onChange on blur for text fields
|
|
890
|
+
* 3. Buffered (showActions=true) — Save/Cancel managed by form; onUpdate on Save
|
|
891
|
+
*
|
|
892
|
+
* When rendered inside a HorizontalArrayItemTemplate (via ObjectWidget in an
|
|
893
|
+
* array row), the caller sets `displayContents=true` so this renderer's
|
|
894
|
+
* wrapper uses `display: contents`, making each field div a direct grid cell
|
|
895
|
+
* in the parent row grid.
|
|
896
|
+
*
|
|
897
|
+
* @module components/Forms/JsonSchemaFormRenderer
|
|
898
|
+
*/
|
|
899
|
+
|
|
900
|
+
type JsonSchemaFormRendererProps = {
|
|
901
|
+
/** JSON Schema defining the form fields */
|
|
902
|
+
schema: JsonSchema;
|
|
903
|
+
/** Current form data */
|
|
904
|
+
data: Record<string, any>;
|
|
905
|
+
/** Callback when any field changes (real-time updates) */
|
|
906
|
+
onChange?: (data: Record<string, any>) => void;
|
|
907
|
+
/** Callback when a field loses focus */
|
|
908
|
+
onBlur?: (fieldName: string, data: Record<string, any>) => void;
|
|
909
|
+
/** Optional callback for validation state changes */
|
|
910
|
+
onValidationChange?: (errors: string[], isValid: boolean) => void;
|
|
911
|
+
/**
|
|
912
|
+
* Defer onChange to blur for text fields (default: false).
|
|
913
|
+
* Checkboxes and selects always trigger immediately.
|
|
914
|
+
*/
|
|
915
|
+
deferChanges?: boolean;
|
|
916
|
+
/**
|
|
917
|
+
* Defer internal state updates to blur for text fields (default: false).
|
|
918
|
+
* Only applies when showActions=true. The Save button enables only after
|
|
919
|
+
* leaving a modified text field.
|
|
920
|
+
*/
|
|
921
|
+
deferStateUpdates?: boolean;
|
|
922
|
+
/**
|
|
923
|
+
* Callback when user saves changes -- only fired if data actually changed.
|
|
924
|
+
*
|
|
925
|
+
* - `data`: complete form data (all fields, _fid stripped)
|
|
926
|
+
* - `changedFields`: only fields that differ from the original baseline,
|
|
927
|
+
* useful for PATCH-style APIs with exclude_unset semantics (_fid stripped)
|
|
928
|
+
* - `diff`: structured diff classifying each change as value/array add/remove/move/modify.
|
|
929
|
+
* Array item changes carry `fid` tokens for correlation; these are form-internal
|
|
930
|
+
* and are never sent to the server.
|
|
931
|
+
*/
|
|
932
|
+
onUpdate?: (data: Record<string, any>, changedFields: Record<string, any>, diff: FormDiff) => void;
|
|
933
|
+
/** Callback when user clicks Cancel */
|
|
934
|
+
onCancel?: () => void;
|
|
935
|
+
/** Disable all fields */
|
|
936
|
+
disabled?: boolean;
|
|
937
|
+
/** Read-only mode — fields are not editable */
|
|
938
|
+
readOnly?: boolean;
|
|
939
|
+
/** Show Save/Cancel action buttons */
|
|
940
|
+
showActions?: boolean;
|
|
941
|
+
/** Label for Save button (default: "Save") */
|
|
942
|
+
saveLabel?: string;
|
|
943
|
+
/** Label for Cancel button (default: "Cancel") */
|
|
944
|
+
cancelLabel?: string;
|
|
945
|
+
/** Show the Cancel button (default: true) */
|
|
946
|
+
showCancel?: boolean;
|
|
947
|
+
/** Show extra properties card (default: true) */
|
|
948
|
+
showExtraProperties?: boolean;
|
|
949
|
+
/** Widget registry for custom widgets (default: DEFAULT_WIDGETS) */
|
|
950
|
+
widgets?: WidgetRegistry;
|
|
951
|
+
/**
|
|
952
|
+
* Template registry for custom layout templates (default: DEFAULT_TEMPLATES).
|
|
953
|
+
*
|
|
954
|
+
* Templates control structural rendering (array item rows, object containers).
|
|
955
|
+
* Widgets control input rendering. Override specific templates by providing
|
|
956
|
+
* a partial registry -- unspecified keys fall back to DEFAULT_TEMPLATES.
|
|
957
|
+
*/
|
|
958
|
+
templates?: TemplateRegistry;
|
|
959
|
+
/**
|
|
960
|
+
* When true, renders with `display: contents` instead of a SimpleStack.
|
|
961
|
+
*
|
|
962
|
+
* Used by ObjectWidget when it is a direct child of a HorizontalArrayItemTemplate
|
|
963
|
+
* row grid. `display: contents` makes this renderer's wrapper invisible to the
|
|
964
|
+
* layout algorithm so each field div becomes a direct grid cell in the row.
|
|
965
|
+
*/
|
|
966
|
+
displayContents?: boolean;
|
|
967
|
+
/**
|
|
968
|
+
* UISchema for customizing widget behavior and appearance.
|
|
969
|
+
*
|
|
970
|
+
* @example
|
|
971
|
+
* ```typescript
|
|
972
|
+
* uiSchema={{
|
|
973
|
+
* 'x-ui-globalOptions': { label: false },
|
|
974
|
+
* 'x-ui-order': ['email', 'name'],
|
|
975
|
+
* name: { 'x-ui-widget': 'textarea' },
|
|
976
|
+
* }}
|
|
977
|
+
* ```
|
|
978
|
+
*/
|
|
979
|
+
uiSchema?: {
|
|
980
|
+
[fieldName: string]: UISchema;
|
|
981
|
+
};
|
|
982
|
+
};
|
|
983
|
+
declare function JsonSchemaFormRenderer(props: JsonSchemaFormRendererProps): React__default.ReactElement;
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* FormFieldRenderer - Renders a single form field via the widget system
|
|
987
|
+
*
|
|
988
|
+
* Replaces the `renderField` free function that previously lived in
|
|
989
|
+
* JsonSchemaFormRenderer. Moving it to a proper component ensures the `key`
|
|
990
|
+
* prop is set at the call site (in the parent's `.map()`), not buried inside
|
|
991
|
+
* the function, which is the idiomatic React pattern.
|
|
992
|
+
*
|
|
993
|
+
* @module components/Forms/FormFieldRenderer
|
|
994
|
+
*/
|
|
995
|
+
|
|
996
|
+
interface FormFieldRendererProps {
|
|
997
|
+
fieldName: string;
|
|
998
|
+
property: JsonSchemaProperty;
|
|
999
|
+
value: unknown;
|
|
1000
|
+
onChange: (value: unknown) => void;
|
|
1001
|
+
onBlur?: (id: string, value: unknown) => void;
|
|
1002
|
+
required: boolean;
|
|
1003
|
+
disabled: boolean;
|
|
1004
|
+
readOnly: boolean;
|
|
1005
|
+
schema: JsonSchema;
|
|
1006
|
+
uiSchema?: UISchema;
|
|
1007
|
+
registry: WidgetRegistry;
|
|
1008
|
+
globalOptions?: UISchemaOptions;
|
|
1009
|
+
formData?: Record<string, unknown>;
|
|
1010
|
+
}
|
|
1011
|
+
declare function FormFieldRenderer({ fieldName, property, value, onChange, onBlur, required, disabled, readOnly, schema, uiSchema, registry, globalOptions, formData, }: FormFieldRendererProps): React__default.ReactElement | null;
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* useFormEngine - Core form state, schema resolution, and update-mode logic
|
|
1015
|
+
*
|
|
1016
|
+
* Owns:
|
|
1017
|
+
* - formData state (internal working copy)
|
|
1018
|
+
* - resolvedSchema / orderedProperties (conditional schema + field ordering)
|
|
1019
|
+
* - originalData baseline for dirty-tracking
|
|
1020
|
+
* - nonSchemaData (fields not in the schema, preserved on save)
|
|
1021
|
+
* - pendingChanges (deferred-state-update buffer)
|
|
1022
|
+
* - isValid / validation errors
|
|
1023
|
+
* - handleFieldChange, handleFieldBlur, handleSave, handleCancel
|
|
1024
|
+
*
|
|
1025
|
+
* Supports all three update modes:
|
|
1026
|
+
* 1. Real-time — onChange on every keystroke
|
|
1027
|
+
* 2. Deferred — onChange on blur for text fields (deferChanges)
|
|
1028
|
+
* 3. Buffered — Save/Cancel flow (showActions + onUpdate)
|
|
1029
|
+
*
|
|
1030
|
+
* @module components/Forms/hooks/useFormEngine
|
|
1031
|
+
*/
|
|
1032
|
+
|
|
1033
|
+
interface UseFormEngineOptions {
|
|
1034
|
+
schema: JsonSchema;
|
|
1035
|
+
data: Record<string, any>;
|
|
1036
|
+
uiSchema: {
|
|
1037
|
+
[fieldName: string]: UISchema;
|
|
1038
|
+
};
|
|
1039
|
+
onChange?: (data: Record<string, any>) => void;
|
|
1040
|
+
onBlur?: (fieldName: string, data: Record<string, any>) => void;
|
|
1041
|
+
onValidationChange?: (errors: string[], isValid: boolean) => void;
|
|
1042
|
+
onUpdate?: (data: Record<string, any>, changedFields: Record<string, any>, diff: FormDiff) => void;
|
|
1043
|
+
onCancel?: () => void;
|
|
1044
|
+
readOnly?: boolean;
|
|
1045
|
+
showActions?: boolean;
|
|
1046
|
+
deferChanges?: boolean;
|
|
1047
|
+
deferStateUpdates?: boolean;
|
|
1048
|
+
}
|
|
1049
|
+
interface UseFormEngineResult {
|
|
1050
|
+
/** The current working form data (for controlled field values) */
|
|
1051
|
+
formData: Record<string, any>;
|
|
1052
|
+
/**
|
|
1053
|
+
* Display data — formData merged with pending deferred changes.
|
|
1054
|
+
* Always use this for rendering field values.
|
|
1055
|
+
*/
|
|
1056
|
+
displayData: Record<string, any>;
|
|
1057
|
+
/** Schema resolved against the current formData (conditional fields evaluated) */
|
|
1058
|
+
resolvedSchema: JsonSchema;
|
|
1059
|
+
/** Properties ordered by x-ui-order, ready for rendering */
|
|
1060
|
+
orderedProperties: [string, JsonSchemaProperty][];
|
|
1061
|
+
hasChanges: boolean;
|
|
1062
|
+
isValid: boolean;
|
|
1063
|
+
handleFieldChange: (fieldName: string, value: any) => void;
|
|
1064
|
+
handleFieldBlur: (fieldName: string) => void;
|
|
1065
|
+
handleSave: () => void;
|
|
1066
|
+
handleCancel: () => void;
|
|
1067
|
+
}
|
|
1068
|
+
declare function useFormEngine({ schema, data, uiSchema, onChange, onBlur, onValidationChange, onUpdate, onCancel, readOnly, showActions, deferChanges, deferStateUpdates, }: UseFormEngineOptions): UseFormEngineResult;
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* useResolvedSchema - Schema resolution and property ordering
|
|
1072
|
+
*
|
|
1073
|
+
* Resolves conditional schemas (if-then-else, allOf) based on the current
|
|
1074
|
+
* form data, and applies x-ui-order to produce a stable ordered list of
|
|
1075
|
+
* [fieldName, property] pairs for rendering.
|
|
1076
|
+
*
|
|
1077
|
+
* ## Relationship to useFormEngine
|
|
1078
|
+
*
|
|
1079
|
+
* `useFormEngine` already performs this same resolution internally so that
|
|
1080
|
+
* validation and field-cleanup effects have access to the live schema.
|
|
1081
|
+
* This hook exists as a **standalone composable** for consumers that need
|
|
1082
|
+
* schema resolution without the full form-state machinery — for example:
|
|
1083
|
+
*
|
|
1084
|
+
* - A read-only schema viewer that renders fields without tracking changes
|
|
1085
|
+
* - A field-count or schema-diff preview component
|
|
1086
|
+
* - A future form builder that needs to inspect the resolved structure
|
|
1087
|
+
* before mounting a full form engine
|
|
1088
|
+
*
|
|
1089
|
+
* Do **not** import both this hook and `useFormEngine` in the same component
|
|
1090
|
+
* for the same schema/data pair — that would resolve the schema twice.
|
|
1091
|
+
* Prefer the values returned by `useFormEngine` when the engine is already
|
|
1092
|
+
* in use.
|
|
1093
|
+
*
|
|
1094
|
+
* @module components/Forms/hooks/useResolvedSchema
|
|
1095
|
+
*/
|
|
1096
|
+
|
|
1097
|
+
interface UseResolvedSchemaOptions {
|
|
1098
|
+
schema: JsonSchema;
|
|
1099
|
+
formData: Record<string, any>;
|
|
1100
|
+
uiSchema: {
|
|
1101
|
+
[fieldName: string]: UISchema;
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
interface UseResolvedSchemaResult {
|
|
1105
|
+
resolvedSchema: JsonSchema;
|
|
1106
|
+
orderedProperties: [string, JsonSchemaProperty][];
|
|
1107
|
+
}
|
|
1108
|
+
declare function useResolvedSchema({ schema, formData, uiSchema, }: UseResolvedSchemaOptions): UseResolvedSchemaResult;
|
|
1109
|
+
|
|
1110
|
+
type NestedRenderer = (props: Omit<JsonSchemaFormRendererProps, "onUpdate" | "onCancel" | "showActions" | "showExtraProperties">) => React.ReactElement | null;
|
|
1111
|
+
interface NestedFormContextValue {
|
|
1112
|
+
renderer: NestedRenderer;
|
|
1113
|
+
templates: TemplateRegistry;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* useNestedFormContext -- returns the renderer and templates injected by
|
|
1118
|
+
* the nearest JsonSchemaFormRenderer via NestedFormContext.
|
|
1119
|
+
*
|
|
1120
|
+
* Used by ObjectWidget and ArrayWidget to render nested sub-forms and
|
|
1121
|
+
* resolve layout templates without a circular import.
|
|
1122
|
+
*
|
|
1123
|
+
* Throws if called outside a JsonSchemaFormRenderer tree. This is
|
|
1124
|
+
* intentional: ObjectWidget and ArrayWidget cannot function without
|
|
1125
|
+
* the renderer context, and a clear error is better than a silent null.
|
|
1126
|
+
*/
|
|
1127
|
+
|
|
1128
|
+
declare function useNestedFormContext(): NestedFormContextValue;
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* Default templates for structural layout rendering.
|
|
1132
|
+
*
|
|
1133
|
+
* These are the pre-built implementations used by ArrayWidget and
|
|
1134
|
+
* ObjectWidget when no custom template is injected. Callers override
|
|
1135
|
+
* specific templates by passing a partial TemplateRegistry to the
|
|
1136
|
+
* `templates` prop on JsonSchemaFormRenderer.
|
|
1137
|
+
*/
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* DEFAULT_TEMPLATES -- the built-in template implementations.
|
|
1141
|
+
*
|
|
1142
|
+
* Pass a partial override to JsonSchemaFormRenderer's `templates` prop
|
|
1143
|
+
* to replace specific templates globally, or use x-ui-options on a
|
|
1144
|
+
* schema property for per-field overrides.
|
|
1145
|
+
*/
|
|
1146
|
+
declare const DEFAULT_TEMPLATES: TemplateRegistry;
|
|
1147
|
+
|
|
1148
|
+
export { type ArrayHeaderTemplate, type ArrayHeaderTemplateProps, type ArrayItemTemplate, type ArrayItemTemplateProps, ArrayWidget, CheckboxWidget, DEFAULT_TEMPLATES, DEFAULT_WIDGETS, DEFAULT_WIDGET_MAP, EntitySelectWidget, ExtraPropertiesCard, FormActions, FormCheckbox, FormFieldRenderer, FormFieldWrapper, type FormFieldWrapperProps, FormInput, FormMultiSelect, FormNumberInput, FormQuantityInput, FormSelect, FormTagsInput, FormTextarea, JsonEditorWidget, JsonSchemaFormRenderer, type JsonSchemaFormRendererProps, type NestedFormContextValue, type NestedRenderer, NumberWidget, type ObjectContainerTemplate, type ObjectContainerTemplateProps, ObjectWidget, type QuantityValue, QuantityWidget, type SelectOption, SelectWidget, TagsInputWidget, type TemplateRegistry, TextInputWidget, TextareaWidget, type UnitOption, type UnitPosition, type Widget, type WidgetDescriptor, type WidgetMap, type WidgetProps, type WidgetRegistry, firstError, getAriaDescribedBy, getDefaultWidgetForType, resolveWidget, useFormEngine, useNestedFormContext, useResolvedSchema };
|