extended-dynamic-forms 0.3.5 → 0.3.7

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
@@ -24,6 +24,14 @@ Extended Dynamic Forms is an extension library for React JSON Schema Form (RJSF)
24
24
  - **25+ Ant Design components** for professional UI
25
25
  - **TypeScript-first** development with full type safety
26
26
 
27
+ ### Ant Design Prop Pass-through
28
+
29
+ All custom widgets built on Ant Design components forward their props via `ui:options`. For example, Rate, Slider, DatePicker, Input, InputNumber, ColorPicker, and TimePicker can be configured using the same prop names from AntD. In addition, you can customize the containing `Form.Item` using `ui:options.formItem`. See docs/custom-widgets-configuration.md for details and examples.
30
+
31
+ - DatePicker notes:
32
+ - JSON-only flags: `disablePastDates`, `disableFutureDates`, `disableWeekends` (builds `disabledDate` internally)
33
+ - Range support: set `ui:options.range: true` to render AntD `RangePicker` (see examples below)
34
+
27
35
  ## Installation
28
36
 
29
37
  **Note:** This library currently requires local development setup and cannot be installed via npm due to local file dependencies.
@@ -145,6 +153,67 @@ const schema = {
145
153
  condition: { "==": [{ "var": "hasDriversLicense" }, true] }
146
154
  ```
147
155
 
156
+ Note on wizard detection:
157
+ - Wizard mode activates only when the root schema contains two or more properties whose keys start with `STEP_`.
158
+ - With a single `STEP_…` property, the form renders as a single-page form (no progress/navigation UI).
159
+ - To display steps UI, define at least two step objects (e.g., `STEP_PERSONAL`, `STEP_REVIEW`).
160
+
161
+ ### Step Layouts with LayoutGridField
162
+
163
+ Wizard steps can define their own grid layout using a custom object field (e.g., `LayoutGridField`). Place the layout at the step key in `uiSchema` and pass your custom field via `fields` to `WizardForm`.
164
+
165
+ ```tsx
166
+ import { WizardForm } from 'extended-dynamic-forms';
167
+
168
+ const schema = {
169
+ type: 'object',
170
+ properties: {
171
+ STEP_LAYOUT: {
172
+ type: 'object',
173
+ title: 'Personal Info',
174
+ properties: {
175
+ firstName: { type: 'string', title: 'First Name' },
176
+ lastName: { type: 'string', title: 'Last Name' },
177
+ age: { type: 'number', title: 'Age' },
178
+ gender: { type: 'string', enum: ['Male','Female','Other'] },
179
+ favoriteBook: { type: 'string' },
180
+ }
181
+ }
182
+ }
183
+ };
184
+
185
+ const uiSchema = {
186
+ STEP_LAYOUT: {
187
+ 'ui:field': 'LayoutGridField',
188
+ 'ui:layoutGrid': {
189
+ 'ui:row': [
190
+ { 'ui:row': { gutter: [16,16], children: [
191
+ { 'ui:col': { span: 12, children: ['firstName'] } },
192
+ { 'ui:col': { span: 12, children: ['lastName'] } }
193
+ ]}},
194
+ { 'ui:row': { gutter: [16,16], children: [
195
+ { 'ui:col': { span: 24, children: ['age'] } }
196
+ ]}},
197
+ { 'ui:row': { gutter: [16,16], children: [
198
+ { 'ui:col': { span: 24, children: ['gender'] } }
199
+ ]}},
200
+ { 'ui:row': { gutter: [16,16], children: [
201
+ { 'ui:col': { span: 24, children: ['favoriteBook'] } }
202
+ ]}}
203
+ ]
204
+ }
205
+ }
206
+ };
207
+
208
+ // LayoutGridField is included by default in EDF; no extra wiring needed
209
+ <WizardForm schema={schema} uiSchema={uiSchema} />
210
+ ```
211
+
212
+ Notes:
213
+ - EDF includes `LayoutGridField` out of the box. Just set `ui:field: 'LayoutGridField'` on the step object.
214
+ - EDF variant uses `'ui:layoutGrid'` with AntD gutter and 24-grid spans. The RJSF canonical layout (`'ui:layout'` with 12-grid widths) is also parsed.
215
+ - You can still override or extend via the `fields` prop if needed.
216
+
148
217
  ## Event System & Webhooks
149
218
 
150
219
  Central event orchestration for all form interactions:
@@ -191,6 +260,26 @@ export const CustomWidget: FC<WidgetProps> = ({ id, value, onChange, schema }) =
191
260
  };
192
261
  ```
193
262
 
263
+ ### Auto-registered by Default
264
+ - All EDF custom widgets are included by default; no wiring is required.
265
+ - Every widget is also exposed as a field, so you can use either `ui:widget` or `ui:field` with the same key.
266
+
267
+ Examples:
268
+
269
+ ```json
270
+ {
271
+ "schema": { "type": "string", "title": "First Name" },
272
+ "uiSchema": { "ui:widget": "text" }
273
+ }
274
+ ```
275
+
276
+ ```json
277
+ {
278
+ "schema": { "type": "string", "title": "First Name" },
279
+ "uiSchema": { "ui:field": "text" }
280
+ }
281
+ ```
282
+
194
283
  ## JsonLogic Migration Examples
195
284
 
196
285
  Common patterns for migrating from function-based conditions:
@@ -264,6 +353,88 @@ Common patterns for migrating from function-based conditions:
264
353
  }
265
354
  ```
266
355
 
356
+ #### Text Input with Variant and Auto-complete
357
+ ```json
358
+ {
359
+ "schema": { "type": "string", "title": "Username" },
360
+ "uiSchema": {
361
+ "ui:widget": "text",
362
+ "ui:options": {
363
+ "variant": "outlined",
364
+ "autoFocus": true,
365
+ "autoComplete": "username",
366
+ "allowClear": true
367
+ }
368
+ }
369
+ }
370
+ ```
371
+
372
+ #### Date Range (RangePicker)
373
+ ```json
374
+ {
375
+ "schema": {
376
+ "type": "array",
377
+ "title": "Date Range",
378
+ "items": { "type": "string" },
379
+ "minItems": 2,
380
+ "maxItems": 2
381
+ },
382
+ "uiSchema": {
383
+ "ui:widget": "date",
384
+ "ui:options": {
385
+ "range": true,
386
+ "format": "YYYY-MM-DD",
387
+ "placeholder": ["Start date", "End date"],
388
+ "picker": "date"
389
+ }
390
+ }
391
+ }
392
+ ```
393
+
394
+ With time selection:
395
+ ```json
396
+ {
397
+ "schema": {
398
+ "type": "array",
399
+ "title": "Date Range With Time",
400
+ "items": { "type": "string" },
401
+ "minItems": 2,
402
+ "maxItems": 2
403
+ },
404
+ "uiSchema": {
405
+ "ui:widget": "date",
406
+ "ui:options": {
407
+ "range": true,
408
+ "showTime": true,
409
+ "format": "YYYY-MM-DD HH:mm",
410
+ "placeholder": ["Start date/time", "End date/time"]
411
+ }
412
+ }
413
+ }
414
+ ```
415
+
416
+ Month range:
417
+ ```json
418
+ {
419
+ "schema": {
420
+ "type": "array",
421
+ "title": "Month Range",
422
+ "items": { "type": "string" },
423
+ "minItems": 2,
424
+ "maxItems": 2
425
+ },
426
+ "uiSchema": {
427
+ "ui:widget": "date",
428
+ "ui:options": {
429
+ "range": true,
430
+ "picker": "month",
431
+ "format": "YYYY-MM",
432
+ "placeholder": ["Start month", "End month"]
433
+ }
434
+ }
435
+ }
436
+ ```
437
+
267
438
  #### Number Input with Range
268
439
  ```json
269
440
  {
@@ -313,6 +484,25 @@ Common patterns for migrating from function-based conditions:
313
484
  }
314
485
  ```
315
486
 
487
+ #### Choice Widget with AntD props (Dropdown)
488
+ ```json
489
+ {
490
+ "schema": { "type": "string", "title": "Country" },
491
+ "uiSchema": {
492
+ "ui:widget": "choice",
493
+ "ui:options": {
494
+ "choiceConfig": {
495
+ "presentationMode": "dropdown",
496
+ "dataSource": { "type": "static", "options": [
497
+ { "label": "USA", "value": "us" }, { "label": "UK", "value": "uk" }
498
+ ]},
499
+ "antd": { "select": { "dropdownMatchSelectWidth": 280, "placement": "bottomLeft" } }
500
+ }
501
+ }
502
+ }
503
+ }
504
+ ```
505
+
316
506
  #### Choice Widget (Radio Group)
317
507
  ```json
318
508
  {
@@ -378,7 +568,7 @@ Common patterns for migrating from function-based conditions:
378
568
  "format": "data-url"
379
569
  },
380
570
  "uiSchema": {
381
- "ui:widget": "FileUploadWidget",
571
+ "ui:widget": "fileUpload",
382
572
  "ui:options": {
383
573
  "accept": ".pdf,.doc,.docx",
384
574
  "maxSize": 5242880,
@@ -388,6 +578,23 @@ Common patterns for migrating from function-based conditions:
388
578
  }
389
579
  ```
390
580
 
581
+ #### File Upload (Ant Upload options)
582
+ ```json
583
+ {
584
+ "schema": { "type": "string", "title": "Profile Picture" },
585
+ "uiSchema": {
586
+ "ui:widget": "fileUpload",
587
+ "ui:options": {
588
+ "useAntUpload": true,
589
+ "listType": "picture-card",
590
+ "showUploadList": { "showPreviewIcon": true, "showRemoveIcon": true },
591
+ "maxCount": 1,
592
+ "accept": "image/*"
593
+ }
594
+ }
595
+ }
596
+ ```
597
+
391
598
  #### Color Picker
392
599
  ```json
393
600
  {
@@ -437,21 +644,14 @@ Common patterns for migrating from function-based conditions:
437
644
  }
438
645
  ```
439
646
 
440
- ### Widget Registration
647
+ ### Widget Registration (optional)
441
648
 
442
- Register custom widgets with ExtendedForm:
649
+ Widgets are auto-registered. You can still override or pass a subset if needed:
443
650
 
444
651
  ```typescript
445
652
  import { ExtendedForm, customWidgets } from 'extended-dynamic-forms';
446
653
 
447
- // Use all built-in widgets
448
- <ExtendedForm
449
- widgets={customWidgets}
450
- schema={schema}
451
- uiSchema={uiSchema}
452
- />
453
-
454
- // Or register specific widgets
654
+ // Override or register specific widgets
455
655
  <ExtendedForm
456
656
  widgets={{
457
657
  text: customWidgets.text,
@@ -540,4 +740,4 @@ import {
540
740
 
541
741
  ## License
542
742
 
543
- MIT License - see LICENSE file for details.
743
+ MIT License - see LICENSE file for details.
@@ -24,5 +24,8 @@ export interface WizardFormProps {
24
24
  onWebhookStart?: (webhook: WebhookConfig, event: any) => void;
25
25
  onWebhookComplete?: (webhook: WebhookConfig, event: any, response: any) => void;
26
26
  onWebhookError?: (webhook: WebhookConfig, event: any, error: Error) => void;
27
+ widgets?: any;
28
+ fields?: any;
29
+ templates?: any;
27
30
  }
28
- export declare function WizardForm({ schema, uiSchema, webhooks, formData: initialFormData, onSubmit, onStepChange, onFieldFocus, onFieldBlur, onFieldChange, onLiveChange, showProgressBar, showStepDescription, submitButtonText, liveValidate, showErrorList, onWebhookStart, onWebhookComplete, onWebhookError, }: WizardFormProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function WizardForm({ schema, uiSchema, webhooks, formData: initialFormData, onSubmit, onStepChange, onFieldFocus, onFieldBlur, onFieldChange, onLiveChange, showProgressBar, showStepDescription, submitButtonText, liveValidate, showErrorList, onWebhookStart, onWebhookComplete, onWebhookError, widgets, fields, templates, }: WizardFormProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { FieldProps, RJSFSchema, StrictRJSFSchema, FormContextType } from '@rjsf/utils';
2
+
3
+ export declare const LayoutGridField: <T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(props: FieldProps<T, S, F>) => import("react/jsx-runtime").JSX.Element;
4
+ export default LayoutGridField;
@@ -1,24 +1,28 @@
1
+ import { default as React } from 'react';
1
2
  import { AddressField } from './fields/AddressField';
2
3
  import { PhoneField } from './fields/PhoneField';
3
4
  import { CurrencyField } from './fields/CurrencyField';
5
+ import { LayoutGridField } from './fields/LayoutGridField';
4
6
  import { ArrayFieldTemplate, ArrayFieldItemTemplate } from './arrays';
5
7
  import { WizardObjectFieldTemplate, WizardSectionTemplate } from '../layouts/wizard';
6
8
  import { SubmitButton } from './templates/SubmitButton';
7
9
  import { FieldTemplate } from './templates/FieldTemplate';
10
+ import { FieldProps } from '@rjsf/utils';
8
11
 
9
12
  export declare const customFields: {
10
- address: import('react').FC<import('@rjsf/utils').FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
11
- phone: import('react').FC<import('@rjsf/utils').FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
12
- currency: import('react').FC<import('@rjsf/utils').FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
13
+ address: React.FC<FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
14
+ phone: React.FC<FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
15
+ currency: React.FC<FieldProps<any, import('@rjsf/utils').RJSFSchema, any>>;
16
+ LayoutGridField: <T = any, S extends import('@rjsf/utils').StrictRJSFSchema = import('@rjsf/utils').RJSFSchema, F extends import('@rjsf/utils').FormContextType = any>(props: FieldProps<T, S, F>) => import("react/jsx-runtime").JSX.Element;
13
17
  };
14
18
  export declare const customTemplates: {
15
- FieldTemplate: import('react').FC<import('@rjsf/utils').FieldTemplateProps>;
19
+ FieldTemplate: React.FC<import('@rjsf/utils').FieldTemplateProps>;
16
20
  ArrayFieldTemplate: (props: import('@rjsf/utils').ArrayFieldTemplateProps) => import("react/jsx-runtime").JSX.Element;
17
21
  ArrayFieldItemTemplate: (props: import('@rjsf/utils').ArrayFieldItemTemplateType) => import("react/jsx-runtime").JSX.Element;
18
- WizardObjectFieldTemplate: import('react').FC<import('@rjsf/utils').ObjectFieldTemplateProps>;
19
- WizardSectionTemplate: import('react').FC<import('../layouts/wizard/WizardSectionTemplate').WizardSectionTemplateProps>;
22
+ WizardObjectFieldTemplate: React.FC<import('@rjsf/utils').ObjectFieldTemplateProps>;
23
+ WizardSectionTemplate: React.FC<import('../layouts/wizard/WizardSectionTemplate').WizardSectionTemplateProps>;
20
24
  ButtonTemplates: {
21
- SubmitButton: import('react').FC<import('@rjsf/utils').SubmitButtonProps>;
25
+ SubmitButton: React.FC<import('@rjsf/utils').SubmitButtonProps>;
22
26
  };
23
27
  };
24
- export { AddressField, PhoneField, CurrencyField, FieldTemplate, ArrayFieldTemplate, ArrayFieldItemTemplate, WizardObjectFieldTemplate, WizardSectionTemplate, SubmitButton, };
28
+ export { AddressField, PhoneField, CurrencyField, LayoutGridField, FieldTemplate, ArrayFieldTemplate, ArrayFieldItemTemplate, WizardObjectFieldTemplate, WizardSectionTemplate, SubmitButton, };
@@ -3,7 +3,7 @@ export type { Rule, EngineConfig, ConditionalEngineHook, UiEffect, SchemaEffect,
3
3
  export { useConditionalUi, type UiRule } from './hooks/useConditionalUi';
4
4
  export { useConditionalSchema, type SchemaRule, } from './hooks/useConditionalSchema';
5
5
  export { useConditionalValidation, type ValidationRule, } from './hooks/useConditionalValidation';
6
- export { createDynamicArrayItemsUiSchema, mergeItemUiSchema, arrayItemPatterns, type ArrayItemsFunction, type ArrayItemConditionalFn, } from './utils/dynamicArrayItems';
6
+ export { createDynamicArrayItemsUiSchema, mergeItemUiSchema, arrayItemPatterns, normalizeUiSchemaDynamicItems, compileDynamicItems, type ArrayItemsFunction, type ArrayItemConditionalFn, type DynamicItemsConfig, type DynamicItemsRule, } from './utils/dynamicArrayItems';
7
7
  export { uiEngineConfig } from './engines/uiEngineConfig';
8
8
  export { schemaEngineConfig } from './engines/schemaEngineConfig';
9
9
  export { validationEngineConfig, createCustomValidate, } from './engines/validationEngineConfig';
@@ -40,6 +40,31 @@ export declare function createDynamicArrayItemsUiSchema(baseItemUiSchema: UiSche
40
40
  * @returns Merged UI schema
41
41
  */
42
42
  export declare function mergeItemUiSchema(base: UiSchema, overrides: Partial<UiSchema>): UiSchema;
43
+ /**
44
+ * Declarative JSON config for dynamic array items (compiled to a function at runtime)
45
+ */
46
+ export type DynamicItemsRule = {
47
+ condition: any;
48
+ ui?: Partial<UiSchema>;
49
+ otherwise?: Partial<UiSchema>;
50
+ };
51
+ export type DynamicItemsConfig = {
52
+ base?: UiSchema;
53
+ rules: DynamicItemsRule[];
54
+ };
55
+ /**
56
+ * Compile a declarative JSON config into an ArrayItemsFunction
57
+ * - Supports single-rule shorthand and multi-rule configs
58
+ * - JsonLogic context = itemData extended with {$index, $formContext}
59
+ */
60
+ export declare function compileDynamicItems(def: {
61
+ 'ui:dynamicItems': DynamicItemsConfig;
62
+ }): ArrayItemsFunction;
63
+ /**
64
+ * Recursively scan a UiSchema and convert declarative dynamic items into functions
65
+ * - Looks for items: { ui:dynamicItems: { ... } }
66
+ */
67
+ export declare function normalizeUiSchemaDynamicItems(uiSchema: UiSchema): UiSchema;
43
68
  /**
44
69
  * Helper to create common conditional patterns
45
70
  */
@@ -0,0 +1,11 @@
1
+ import { default as React } from 'react';
2
+
3
+ export interface LucideIconProps {
4
+ name: string;
5
+ size?: number;
6
+ color?: string;
7
+ strokeWidth?: number;
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ }
11
+ export declare const LucideIcon: React.FC<LucideIconProps>;