extended-dynamic-forms 0.3.6 → 0.3.8

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
@@ -1,8 +1,8 @@
1
1
  # Extended Dynamic Forms
2
2
 
3
- ## BREAKING CHANGE: v0.2.0
3
+ ## Declarative Configuration (JSON-only)
4
4
 
5
- All conditional logic now uses **JsonLogic rules only** for conditions. Function-based conditions have been removed for security and portability. Note that validation effects may still use functions. See migration examples below.
5
+ Conditional logic is configured with pure JSON via `x-edf:rules` in your `schema` and `uiSchema`. Function-based conditions and external hooks are not required and should not be used in app code.
6
6
 
7
7
  ## Project Status
8
8
 
@@ -18,12 +18,20 @@ All conditional logic now uses **JsonLogic rules only** for conditions. Function
18
18
 
19
19
  Extended Dynamic Forms is an extension library for React JSON Schema Form (RJSF) v6 that adds:
20
20
 
21
- - **Three Pillars Architecture** for conditional logic with O(N) performance (where N is the number of conditional rules/array items)
21
+ - **Declarative conditionals** with O(N) performance (rules + dynamic arrays)
22
22
  - **Multi-step wizard forms** with automatic step detection
23
23
  - **Central event orchestration** with webhook support
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.
@@ -43,71 +51,62 @@ npm run dev
43
51
 
44
52
  ## Core Architecture
45
53
 
46
- ### Three Pillars Conditional System
54
+ ### Declarative Conditionals (JSON-only)
47
55
 
48
- The conditional logic system is divided into three independent pillars:
56
+ Embed rules directly inside your configs. EDF evaluates JsonLogic `condition` and applies JSON Patch `effect` internally. No hooks, functions, or classes in user code.
49
57
 
50
- #### 1. UI Logic Pillar
51
- Controls form appearance using JsonLogic conditions and JSON Patch operations:
58
+ - UI rules → `uiSchema['x-edf:rules']`
59
+ - Schema rules → `schema['x-edf:rules']`
52
60
 
53
- ```typescript
54
- import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
55
-
56
- const uiRules: UiRule[] = [{
57
- name: 'Show license number when has license',
58
- condition: { "==": [{ "var": "hasDriversLicense" }, true] },
59
- effect: [{ op: 'remove', path: '/licenseNumber/ui:widget' }]
60
- }];
61
-
62
- const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
63
- ```
64
-
65
- #### 2. Schema Logic Pillar
66
- Modifies JSON Schema structure dynamically (use sparingly):
67
-
68
- ```typescript
69
- const schemaRules: SchemaRule[] = [{
70
- name: 'Add premium fields',
71
- condition: { "==": [{ "var": "accountType" }, "premium"] },
72
- effect: [{ op: 'add', path: '/properties/premiumFeatures', value: {...} }]
73
- }];
61
+ Example (UI rules):
62
+ ```json
63
+ {
64
+ "x-edf:rules": [
65
+ {
66
+ "name": "Show license number when has license",
67
+ "condition": { "==": [{ "var": "hasDriversLicense" }, true] },
68
+ "effect": [{ "op": "remove", "path": "/licenseNumber/ui:widget" }]
69
+ }
70
+ ]
71
+ }
74
72
  ```
75
73
 
76
- #### 3. Validation Logic Pillar
77
- Adds conditional validation rules:
78
-
79
- ```typescript
80
- const validationRules: ValidationRule[] = [{
81
- name: 'Require consent for minors',
82
- condition: { "<": [{ "var": "age" }, 18] },
83
- effect: {
84
- name: 'Parent consent validation',
85
- isActive: { "<": [{ "var": "age" }, 18] },
86
- validate: (errors, formData) => {
87
- if (!formData.parentConsent) {
88
- errors.parentConsent.__errors = ['Parent consent required'];
89
- }
74
+ Example (Schema rules):
75
+ ```json
76
+ {
77
+ "x-edf:rules": [
78
+ {
79
+ "name": "Add premium fields",
80
+ "condition": { "==": [{ "var": "accountType" }, "premium"] },
81
+ "effect": [
82
+ { "op": "add", "path": "/properties/premiumFeatures", "value": { "type": "object" } }
83
+ ]
90
84
  }
91
- }
92
- }];
85
+ ]
86
+ }
93
87
  ```
94
88
 
95
89
  ### Dynamic Arrays with O(N) Performance
96
90
 
97
- Provides efficient handling of conditional logic within arrays, where N is the number of array items:
98
-
99
- ```typescript
100
- import { createDynamicArrayItemsUiSchema } from 'extended-dynamic-forms/conditionals/v2';
91
+ Use declarative `ui:dynamicItems` with per-item JsonLogic. No functions:
101
92
 
102
- const uiSchema = {
103
- directors: {
104
- items: createDynamicArrayItemsUiSchema((director, index) => ({
105
- shareholdingPercentage: {
106
- 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
93
+ ```json
94
+ {
95
+ "directors": {
96
+ "items": {
97
+ "ui:dynamicItems": {
98
+ "base": { "shareholdingPercentage": { "ui:widget": "hidden" } },
99
+ "rules": [
100
+ {
101
+ "condition": { "===": [{ "var": "hasShareholding" }, true] },
102
+ "ui": { "shareholdingPercentage": { "ui:widget": "updown" } },
103
+ "otherwise": { "shareholdingPercentage": { "ui:widget": "hidden" } }
104
+ }
105
+ ]
107
106
  }
108
- }))
107
+ }
109
108
  }
110
- };
109
+ }
111
110
  ```
112
111
 
113
112
  ## Multi-Step Wizard Forms
@@ -119,7 +118,7 @@ import { WizardForm } from 'extended-dynamic-forms';
119
118
 
120
119
  <WizardForm
121
120
  schema={wizardSchema}
122
- uiSchema={conditionalUiSchema}
121
+ uiSchema={uiSchema}
123
122
  formData={formData}
124
123
  onStepChange={(fromStep, toStep) => {
125
124
  console.log(`Step ${fromStep} → ${toStep}`);
@@ -141,8 +140,8 @@ const schema = {
141
140
  }
142
141
  };
143
142
 
144
- // Conditions use flat paths (no STEP_ prefix)
145
- condition: { "==": [{ "var": "hasDriversLicense" }, true] }
143
+ // Conditions refer to flattened form data (no STEP_ prefix)
144
+ // Example rule (in uiSchema.x-edf:rules): { "==": [{ "var": "hasDriversLicense" }, true] }
146
145
  ```
147
146
 
148
147
  Note on wizard detection:
@@ -345,6 +344,88 @@ Common patterns for migrating from function-based conditions:
345
344
  }
346
345
  ```
347
346
 
347
+ #### Text Input with Variant and Auto-complete
348
+ ```json
349
+ {
350
+ "schema": { "type": "string", "title": "Username" },
351
+ "uiSchema": {
352
+ "ui:widget": "text",
353
+ "ui:options": {
354
+ "variant": "outlined",
355
+ "autoFocus": true,
356
+ "autoComplete": "username",
357
+ "allowClear": true
358
+ }
359
+ }
360
+ }
361
+ ```
362
+
363
+ #### Date Range (RangePicker)
364
+ ```json
365
+ {
366
+ "schema": {
367
+ "type": "array",
368
+ "title": "Date Range",
369
+ "items": { "type": "string" },
370
+ "minItems": 2,
371
+ "maxItems": 2
372
+ },
373
+ "uiSchema": {
374
+ "ui:widget": "date",
375
+ "ui:options": {
376
+ "range": true,
377
+ "format": "YYYY-MM-DD",
378
+ "placeholder": ["Start date", "End date"],
379
+ "picker": "date"
380
+ }
381
+ }
382
+ }
383
+ ```
384
+
385
+ With time selection:
386
+ ```json
387
+ {
388
+ "schema": {
389
+ "type": "array",
390
+ "title": "Date Range With Time",
391
+ "items": { "type": "string" },
392
+ "minItems": 2,
393
+ "maxItems": 2
394
+ },
395
+ "uiSchema": {
396
+ "ui:widget": "date",
397
+ "ui:options": {
398
+ "range": true,
399
+ "showTime": true,
400
+ "format": "YYYY-MM-DD HH:mm",
401
+ "placeholder": ["Start date/time", "End date/time"]
402
+ }
403
+ }
404
+ }
405
+ ```
406
+
407
+ Month range:
408
+ ```json
409
+ {
410
+ "schema": {
411
+ "type": "array",
412
+ "title": "Month Range",
413
+ "items": { "type": "string" },
414
+ "minItems": 2,
415
+ "maxItems": 2
416
+ },
417
+ "uiSchema": {
418
+ "ui:widget": "date",
419
+ "ui:options": {
420
+ "range": true,
421
+ "picker": "month",
422
+ "format": "YYYY-MM",
423
+ "placeholder": ["Start month", "End month"]
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
348
429
  #### Number Input with Range
349
430
  ```json
350
431
  {
@@ -394,6 +475,25 @@ Common patterns for migrating from function-based conditions:
394
475
  }
395
476
  ```
396
477
 
478
+ #### Choice Widget with AntD props (Dropdown)
479
+ ```json
480
+ {
481
+ "schema": { "type": "string", "title": "Country" },
482
+ "uiSchema": {
483
+ "ui:widget": "choice",
484
+ "ui:options": {
485
+ "choiceConfig": {
486
+ "presentationMode": "dropdown",
487
+ "dataSource": { "type": "static", "options": [
488
+ { "label": "USA", "value": "us" }, { "label": "UK", "value": "uk" }
489
+ ]},
490
+ "antd": { "select": { "dropdownMatchSelectWidth": 280, "placement": "bottomLeft" } }
491
+ }
492
+ }
493
+ }
494
+ }
495
+ ```
496
+
397
497
  #### Choice Widget (Radio Group)
398
498
  ```json
399
499
  {
@@ -459,7 +559,7 @@ Common patterns for migrating from function-based conditions:
459
559
  "format": "data-url"
460
560
  },
461
561
  "uiSchema": {
462
- "ui:widget": "FileUploadWidget",
562
+ "ui:widget": "fileUpload",
463
563
  "ui:options": {
464
564
  "accept": ".pdf,.doc,.docx",
465
565
  "maxSize": 5242880,
@@ -469,6 +569,23 @@ Common patterns for migrating from function-based conditions:
469
569
  }
470
570
  ```
471
571
 
572
+ #### File Upload (Ant Upload options)
573
+ ```json
574
+ {
575
+ "schema": { "type": "string", "title": "Profile Picture" },
576
+ "uiSchema": {
577
+ "ui:widget": "fileUpload",
578
+ "ui:options": {
579
+ "useAntUpload": true,
580
+ "listType": "picture-card",
581
+ "showUploadList": { "showPreviewIcon": true, "showRemoveIcon": true },
582
+ "maxCount": 1,
583
+ "accept": "image/*"
584
+ }
585
+ }
586
+ }
587
+ ```
588
+
472
589
  #### Color Picker
473
590
  ```json
474
591
  {
@@ -558,7 +675,7 @@ npm run format # Prettier
558
675
  ```
559
676
  src/
560
677
  ├── components/ # Core form components
561
- ├── conditionals/ # Three Pillars system
678
+ ├── conditionals/ # Declarative conditional engines (internal)
562
679
  │ └── v2/ # Current implementation
563
680
  ├── events/ # Event orchestration
564
681
  ├── layouts/ # Layout systems
@@ -592,16 +709,8 @@ Run `npm run dev` to explore examples.
592
709
  Full TypeScript support with exported types:
593
710
 
594
711
  ```typescript
595
- import {
596
- ExtendedForm,
597
- WizardForm,
598
- UiRule,
599
- SchemaRule,
600
- ValidationRule,
601
- JsonLogicRule,
602
- FormEvent,
603
- WebhookConfig
604
- } from 'extended-dynamic-forms';
712
+ import { ExtendedForm, WizardForm } from 'extended-dynamic-forms';
713
+ // Config is JSON-only; rules are embedded via x-edf:rules
605
714
  ```
606
715
 
607
716
  ## Contributing
@@ -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>;