@syncfusion/ej2-form-renderer 34.2.2

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.
Files changed (214) hide show
  1. package/README.md +60 -0
  2. package/common.d.ts +4 -0
  3. package/common.js +4 -0
  4. package/dist/ej2-form-renderer.umd.min.js +11 -0
  5. package/dist/ej2-form-renderer.umd.min.js.map +1 -0
  6. package/dist/es6/ej2-form-renderer.es2015.js +6787 -0
  7. package/dist/es6/ej2-form-renderer.es2015.js.map +1 -0
  8. package/dist/es6/ej2-form-renderer.es5.js +7055 -0
  9. package/dist/es6/ej2-form-renderer.es5.js.map +1 -0
  10. package/dist/global/ej2-form-renderer.min.js +11 -0
  11. package/dist/global/ej2-form-renderer.min.js.map +1 -0
  12. package/dist/global/index.d.ts +14 -0
  13. package/form-renderer.d.ts +4 -0
  14. package/form-renderer.js +4 -0
  15. package/index.d.ts +4 -0
  16. package/index.js +4 -0
  17. package/license +10 -0
  18. package/package.json +41 -0
  19. package/src/common/checkbox-group.d.ts +55 -0
  20. package/src/common/checkbox-group.js +241 -0
  21. package/src/common/conditional-rule-engine.d.ts +241 -0
  22. package/src/common/conditional-rule-engine.js +505 -0
  23. package/src/common/custom-validation-engine.d.ts +57 -0
  24. package/src/common/custom-validation-engine.js +152 -0
  25. package/src/common/datagrid-component.d.ts +156 -0
  26. package/src/common/datagrid-component.js +410 -0
  27. package/src/common/expressions/dependency-tracker.d.ts +29 -0
  28. package/src/common/expressions/dependency-tracker.js +137 -0
  29. package/src/common/expressions/expression-engine.d.ts +94 -0
  30. package/src/common/expressions/expression-engine.js +514 -0
  31. package/src/common/expressions/expression-parser.d.ts +40 -0
  32. package/src/common/expressions/expression-parser.js +270 -0
  33. package/src/common/expressions/grid-expressions.d.ts +24 -0
  34. package/src/common/expressions/grid-expressions.js +92 -0
  35. package/src/common/expressions/index.d.ts +4 -0
  36. package/src/common/expressions/index.js +4 -0
  37. package/src/common/index.d.ts +10 -0
  38. package/src/common/index.js +10 -0
  39. package/src/common/json-converter.d.ts +945 -0
  40. package/src/common/json-converter.js +1110 -0
  41. package/src/common/minmax-rule-engine.d.ts +105 -0
  42. package/src/common/minmax-rule-engine.js +380 -0
  43. package/src/common/option-fetcher.d.ts +30 -0
  44. package/src/common/option-fetcher.js +139 -0
  45. package/src/common/parser.d.ts +98 -0
  46. package/src/common/parser.js +788 -0
  47. package/src/common/static-html-renderer.d.ts +45 -0
  48. package/src/common/static-html-renderer.js +77 -0
  49. package/src/common/utils.d.ts +116 -0
  50. package/src/common/utils.js +484 -0
  51. package/src/form-renderer/form-renderer-model.d.ts +65 -0
  52. package/src/form-renderer/form-renderer.d.ts +425 -0
  53. package/src/form-renderer/form-renderer.js +2277 -0
  54. package/src/form-renderer/index.d.ts +6 -0
  55. package/src/form-renderer/index.js +5 -0
  56. package/src/form-renderer/render-form-field.d.ts +31 -0
  57. package/src/form-renderer/render-form-field.js +816 -0
  58. package/src/form-renderer/types/form-schema.d.ts +452 -0
  59. package/src/form-renderer/types/form-schema.js +32 -0
  60. package/src/global.js +1 -0
  61. package/src/index.d.ts +4 -0
  62. package/src/index.js +4 -0
  63. package/styles/bds-lite.css +599 -0
  64. package/styles/bds-lite.scss +2 -0
  65. package/styles/bds.css +599 -0
  66. package/styles/bds.scss +2 -0
  67. package/styles/bootstrap-dark-lite.css +608 -0
  68. package/styles/bootstrap-dark-lite.scss +2 -0
  69. package/styles/bootstrap-dark.css +608 -0
  70. package/styles/bootstrap-dark.scss +2 -0
  71. package/styles/bootstrap-lite.css +595 -0
  72. package/styles/bootstrap-lite.scss +2 -0
  73. package/styles/bootstrap.css +595 -0
  74. package/styles/bootstrap.scss +2 -0
  75. package/styles/bootstrap4-lite.css +595 -0
  76. package/styles/bootstrap4-lite.scss +2 -0
  77. package/styles/bootstrap4.css +595 -0
  78. package/styles/bootstrap4.scss +2 -0
  79. package/styles/bootstrap5-dark-lite.css +595 -0
  80. package/styles/bootstrap5-dark-lite.scss +2 -0
  81. package/styles/bootstrap5-dark.css +595 -0
  82. package/styles/bootstrap5-dark.scss +2 -0
  83. package/styles/bootstrap5-lite.css +595 -0
  84. package/styles/bootstrap5-lite.scss +2 -0
  85. package/styles/bootstrap5.3-lite.css +679 -0
  86. package/styles/bootstrap5.3-lite.scss +2 -0
  87. package/styles/bootstrap5.3.css +679 -0
  88. package/styles/bootstrap5.3.scss +2 -0
  89. package/styles/bootstrap5.css +595 -0
  90. package/styles/bootstrap5.scss +2 -0
  91. package/styles/fabric-dark-lite.css +608 -0
  92. package/styles/fabric-dark-lite.scss +2 -0
  93. package/styles/fabric-dark.css +608 -0
  94. package/styles/fabric-dark.scss +2 -0
  95. package/styles/fabric-lite.css +595 -0
  96. package/styles/fabric-lite.scss +2 -0
  97. package/styles/fabric.css +595 -0
  98. package/styles/fabric.scss +2 -0
  99. package/styles/fluent-dark-lite.css +595 -0
  100. package/styles/fluent-dark-lite.scss +2 -0
  101. package/styles/fluent-dark.css +595 -0
  102. package/styles/fluent-dark.scss +2 -0
  103. package/styles/fluent-lite.css +595 -0
  104. package/styles/fluent-lite.scss +2 -0
  105. package/styles/fluent.css +595 -0
  106. package/styles/fluent.scss +2 -0
  107. package/styles/fluent2-lite.css +681 -0
  108. package/styles/fluent2-lite.scss +2 -0
  109. package/styles/fluent2.css +681 -0
  110. package/styles/fluent2.scss +2 -0
  111. package/styles/form-renderer/_all.scss +2 -0
  112. package/styles/form-renderer/_bds-definition.scss +8 -0
  113. package/styles/form-renderer/_bootstrap-dark-definition.scss +8 -0
  114. package/styles/form-renderer/_bootstrap-definition.scss +8 -0
  115. package/styles/form-renderer/_bootstrap4-definition.scss +8 -0
  116. package/styles/form-renderer/_bootstrap5-dark-definition.scss +8 -0
  117. package/styles/form-renderer/_bootstrap5-definition.scss +8 -0
  118. package/styles/form-renderer/_bootstrap5.3-definition.scss +8 -0
  119. package/styles/form-renderer/_fabric-dark-definition.scss +8 -0
  120. package/styles/form-renderer/_fabric-definition.scss +8 -0
  121. package/styles/form-renderer/_fluent-dark-definition.scss +8 -0
  122. package/styles/form-renderer/_fluent-definition.scss +8 -0
  123. package/styles/form-renderer/_fluent2-definition.scss +8 -0
  124. package/styles/form-renderer/_highcontrast-definition.scss +8 -0
  125. package/styles/form-renderer/_highcontrast-light-definition.scss +8 -0
  126. package/styles/form-renderer/_layout.scss +480 -0
  127. package/styles/form-renderer/_material-dark-definition.scss +8 -0
  128. package/styles/form-renderer/_material-definition.scss +8 -0
  129. package/styles/form-renderer/_material3-dark-definition.scss +8 -0
  130. package/styles/form-renderer/_material3-definition.scss +8 -0
  131. package/styles/form-renderer/_mixin.scss +26 -0
  132. package/styles/form-renderer/_tailwind-dark-definition.scss +8 -0
  133. package/styles/form-renderer/_tailwind-definition.scss +8 -0
  134. package/styles/form-renderer/_tailwind3-definition.scss +8 -0
  135. package/styles/form-renderer/_theme.scss +69 -0
  136. package/styles/form-renderer/_variables.scss +2 -0
  137. package/styles/form-renderer/bds.css +599 -0
  138. package/styles/form-renderer/bds.scss +2 -0
  139. package/styles/form-renderer/bootstrap-dark.css +608 -0
  140. package/styles/form-renderer/bootstrap-dark.scss +2 -0
  141. package/styles/form-renderer/bootstrap.css +595 -0
  142. package/styles/form-renderer/bootstrap.scss +2 -0
  143. package/styles/form-renderer/bootstrap4.css +595 -0
  144. package/styles/form-renderer/bootstrap4.scss +2 -0
  145. package/styles/form-renderer/bootstrap5-dark.css +595 -0
  146. package/styles/form-renderer/bootstrap5-dark.scss +2 -0
  147. package/styles/form-renderer/bootstrap5.3.css +679 -0
  148. package/styles/form-renderer/bootstrap5.3.scss +2 -0
  149. package/styles/form-renderer/bootstrap5.css +595 -0
  150. package/styles/form-renderer/bootstrap5.scss +2 -0
  151. package/styles/form-renderer/fabric-dark.css +608 -0
  152. package/styles/form-renderer/fabric-dark.scss +2 -0
  153. package/styles/form-renderer/fabric.css +595 -0
  154. package/styles/form-renderer/fabric.scss +2 -0
  155. package/styles/form-renderer/fluent-dark.css +595 -0
  156. package/styles/form-renderer/fluent-dark.scss +2 -0
  157. package/styles/form-renderer/fluent.css +595 -0
  158. package/styles/form-renderer/fluent.scss +2 -0
  159. package/styles/form-renderer/fluent2.css +681 -0
  160. package/styles/form-renderer/fluent2.scss +2 -0
  161. package/styles/form-renderer/highcontrast-light.css +595 -0
  162. package/styles/form-renderer/highcontrast-light.scss +2 -0
  163. package/styles/form-renderer/highcontrast.css +608 -0
  164. package/styles/form-renderer/highcontrast.scss +2 -0
  165. package/styles/form-renderer/material-dark.css +608 -0
  166. package/styles/form-renderer/material-dark.scss +2 -0
  167. package/styles/form-renderer/material.css +595 -0
  168. package/styles/form-renderer/material.scss +2 -0
  169. package/styles/form-renderer/material3-dark.css +677 -0
  170. package/styles/form-renderer/material3-dark.scss +2 -0
  171. package/styles/form-renderer/material3.css +679 -0
  172. package/styles/form-renderer/material3.scss +2 -0
  173. package/styles/form-renderer/tailwind-dark.css +595 -0
  174. package/styles/form-renderer/tailwind-dark.scss +2 -0
  175. package/styles/form-renderer/tailwind.css +595 -0
  176. package/styles/form-renderer/tailwind.scss +2 -0
  177. package/styles/form-renderer/tailwind3.css +669 -0
  178. package/styles/form-renderer/tailwind3.scss +2 -0
  179. package/styles/highcontrast-light-lite.css +595 -0
  180. package/styles/highcontrast-light-lite.scss +2 -0
  181. package/styles/highcontrast-light.css +595 -0
  182. package/styles/highcontrast-light.scss +2 -0
  183. package/styles/highcontrast-lite.css +608 -0
  184. package/styles/highcontrast-lite.scss +2 -0
  185. package/styles/highcontrast.css +608 -0
  186. package/styles/highcontrast.scss +2 -0
  187. package/styles/material-dark-lite.css +608 -0
  188. package/styles/material-dark-lite.scss +2 -0
  189. package/styles/material-dark.css +608 -0
  190. package/styles/material-dark.scss +2 -0
  191. package/styles/material-lite.css +595 -0
  192. package/styles/material-lite.scss +2 -0
  193. package/styles/material.css +595 -0
  194. package/styles/material.scss +2 -0
  195. package/styles/material3-dark-lite.css +677 -0
  196. package/styles/material3-dark-lite.scss +2 -0
  197. package/styles/material3-dark.css +677 -0
  198. package/styles/material3-dark.scss +2 -0
  199. package/styles/material3-lite.css +679 -0
  200. package/styles/material3-lite.scss +2 -0
  201. package/styles/material3.css +679 -0
  202. package/styles/material3.scss +2 -0
  203. package/styles/tailwind-dark-lite.css +595 -0
  204. package/styles/tailwind-dark-lite.scss +2 -0
  205. package/styles/tailwind-dark.css +595 -0
  206. package/styles/tailwind-dark.scss +2 -0
  207. package/styles/tailwind-lite.css +595 -0
  208. package/styles/tailwind-lite.scss +2 -0
  209. package/styles/tailwind.css +595 -0
  210. package/styles/tailwind.scss +2 -0
  211. package/styles/tailwind3-lite.css +669 -0
  212. package/styles/tailwind3-lite.scss +2 -0
  213. package/styles/tailwind3.css +669 -0
  214. package/styles/tailwind3.scss +2 -0
@@ -0,0 +1,505 @@
1
+ import { Internationalization } from '@syncfusion/ej2-base';
2
+ /**
3
+ * ConditionalRuleEngine class
4
+ * @private
5
+ */
6
+ var ConditionalRuleEngine = /** @class */ (function () {
7
+ function ConditionalRuleEngine() {
8
+ }
9
+ /**
10
+ * Evaluate a conditional rule against form values
11
+ *
12
+ * Handles both simple rules (field operator value) and composite rules (AND/OR).
13
+ * Returns false for malformed rules.
14
+ *
15
+ * @param rule - ConditionalRule or CompositeConditionalRule
16
+ * @param formValues - Current form field values (key = field name, value = field value)
17
+ * @returns true if condition met, false otherwise
18
+ * @private
19
+ * @example
20
+ * ```typescript
21
+ * const rule = { field: 'age', operator: 'greaterThan', value: 18 };
22
+ * const isAdult = ConditionalRuleEngine.evaluateCondition(rule, { age: 25 });
23
+ * // isAdult = true
24
+ * ```
25
+ */
26
+ ConditionalRuleEngine.evaluateCondition = function (rule, formValues) {
27
+ try {
28
+ // Handle simple rule (field operator value)
29
+ if ('field' in rule && 'operator' in rule && 'value' in rule) {
30
+ return this.evaluateSimpleRule(rule, formValues);
31
+ }
32
+ // Handle composite rule (AND/OR)
33
+ if ('condition' in rule && 'rules' in rule) {
34
+ return this.evaluateCompositeRule(rule, formValues);
35
+ }
36
+ return false;
37
+ }
38
+ catch (error) {
39
+ return false; // Safe default on error
40
+ }
41
+ };
42
+ /**
43
+ * Evaluate simple field comparison rule
44
+ *
45
+ * Supports operators: equal, notEqual, greaterThan, lessThan, greaterThanOrEqual,
46
+ * lessThanOrEqual, in, notIn, contains, notContains.
47
+ *
48
+ * Handles both camelCase (greaterThan) and lowercase (greaterthan) operator formats
49
+ * for compatibility with QueryBuilder output.
50
+ *
51
+ * @param rule - Simple conditional rule with field, operator, value
52
+ * @param formValues - Current form field values
53
+ * @returns true if comparison is true, false otherwise
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const rule = { field: 'email', operator: 'contains', value: '@' };
58
+ * const hasAt = evaluateSimpleRule(rule, { email: 'test@example.com' });
59
+ * // hasAt = true
60
+ * ```
61
+ */
62
+ ConditionalRuleEngine.evaluateSimpleRule = function (rule, formValues) {
63
+ try {
64
+ var fieldValue_1 = formValues[rule.field];
65
+ var operator = rule.operator.toLowerCase();
66
+ // Allow evaluation for operators that make sense when value is undefined/empty
67
+ if (fieldValue_1 === undefined) {
68
+ var allowedForUndefined = ['equal', 'equals', 'notequal', 'notequals', 'isempty', 'isnotempty'];
69
+ if (allowedForUndefined.indexOf(operator) === -1) {
70
+ return false;
71
+ }
72
+ }
73
+ // Check if field value is an array (for multiselect, checkboxGroup)
74
+ var isFieldArray = Array.isArray(fieldValue_1);
75
+ var intl = new Internationalization();
76
+ switch (operator) {
77
+ case 'equal':
78
+ case 'equals':
79
+ return fieldValue_1 === rule.value;
80
+ case 'notequal':
81
+ case 'notequals':
82
+ return fieldValue_1 !== rule.value;
83
+ case 'startswith': return fieldValue_1.startsWith(rule.value);
84
+ case 'doesnotstartswith': return !fieldValue_1.startsWith(rule.value);
85
+ case 'greaterthan':
86
+ case 'lessthan':
87
+ case 'greaterthanorequal':
88
+ case 'lessthanorequal': {
89
+ var ln = Number(fieldValue_1);
90
+ var rn = Number(rule.value);
91
+ if (!Number.isNaN(ln) && !Number.isNaN(rn)) {
92
+ if (operator === 'greaterthan')
93
+ return ln > rn;
94
+ if (operator === 'lessthan')
95
+ return ln < rn;
96
+ if (operator === 'greaterthanorequal')
97
+ return ln >= rn;
98
+ return ln <= rn;
99
+ }
100
+ return false;
101
+ }
102
+ case 'dategreaterthan':
103
+ case 'datelessthan': {
104
+ // try date comparison first
105
+ var leftTs = intl.parseDate(fieldValue_1, { format: 'MM/dd/yyyy' });
106
+ var rightTs = intl.parseDate(rule.value, { format: 'MM/dd/yyyy' });
107
+ if (leftTs !== null && rightTs !== null) {
108
+ if (operator === 'dategreaterthan')
109
+ return leftTs > rightTs;
110
+ if (operator === 'datelessthan')
111
+ return leftTs < rightTs;
112
+ return leftTs <= rightTs;
113
+ }
114
+ return false;
115
+ }
116
+ case 'timegreaterthan':
117
+ case 'timelessthan': {
118
+ // Parse time strings (format: hh:mm a)
119
+ var leftTime = intl.parseDate(fieldValue_1, { format: 'hh:mm a', type: 'time' });
120
+ var rightTime = intl.parseDate(rule.value, { format: 'hh:mm a', type: 'time' });
121
+ if (leftTime !== null && rightTime !== null) {
122
+ if (operator === 'timegreaterthan')
123
+ return leftTime > rightTime;
124
+ if (operator === 'timelessthan')
125
+ return leftTime < rightTime;
126
+ }
127
+ return false;
128
+ }
129
+ case 'datetimegreaterthan':
130
+ case 'datetimelessthan': {
131
+ // Parse datetime strings (format: MM/dd/yyyy hh:mm a)
132
+ var leftDateTime = intl.parseDate(fieldValue_1, { format: 'MM/dd/yyyy hh:mm a', type: 'dateTime' });
133
+ var rightDateTime = intl.parseDate(rule.value, { format: 'MM/dd/yyyy hh:mm a', type: 'dateTime' });
134
+ if (leftDateTime !== null && rightDateTime !== null) {
135
+ if (operator === 'datetimegreaterthan')
136
+ return leftDateTime > rightDateTime;
137
+ if (operator === 'datetimelessthan')
138
+ return leftDateTime < rightDateTime;
139
+ }
140
+ return false;
141
+ }
142
+ case 'contains':
143
+ // If field value is array, check if array contains the specific value(s)
144
+ if (isFieldArray) {
145
+ // Parse comma-separated values in rule.value if it's a string
146
+ if (typeof rule.value === 'string' && rule.value.indexOf(',') !== -1) {
147
+ var searchValues = rule.value.split(',').map(function (v) { return v.trim(); });
148
+ // Check if array contains ANY of the search values
149
+ return searchValues.some(function (searchVal) { return fieldValue_1.indexOf(searchVal) !== -1; });
150
+ }
151
+ return fieldValue_1.indexOf(rule.value) !== -1;
152
+ }
153
+ // Otherwise, check string contains
154
+ return String(fieldValue_1).indexOf(String(rule.value)) !== -1;
155
+ case 'notcontains':
156
+ // If field value is array, check if array does NOT contain the specific value(s)
157
+ if (isFieldArray) {
158
+ // Parse comma-separated values in rule.value if it's a string
159
+ if (typeof rule.value === 'string' && rule.value.indexOf(',') !== -1) {
160
+ var searchValues = rule.value.split(',').map(function (v) { return v.trim(); });
161
+ // Check if array contains NONE of the search values
162
+ return !searchValues.some(function (searchVal) { return fieldValue_1.indexOf(searchVal) !== -1; });
163
+ }
164
+ return fieldValue_1.indexOf(rule.value) === -1;
165
+ }
166
+ // Otherwise, check string does not contain
167
+ return String(fieldValue_1).indexOf(String(rule.value)) === -1;
168
+ case 'isempty':
169
+ // Check if array is empty
170
+ if (isFieldArray) {
171
+ return fieldValue_1.length === 0;
172
+ }
173
+ // For non-arrays, check if falsy or empty string
174
+ return !fieldValue_1 || String(fieldValue_1).length === 0;
175
+ case 'isnotempty':
176
+ // Check if array has items
177
+ if (isFieldArray) {
178
+ return fieldValue_1.length > 0;
179
+ }
180
+ // For non-arrays, check if truthy and not empty string
181
+ return !!fieldValue_1 && String(fieldValue_1).length > 0;
182
+ default:
183
+ return false;
184
+ }
185
+ }
186
+ catch (error) {
187
+ return false;
188
+ }
189
+ };
190
+ /**
191
+ * Evaluate composite rule with AND/OR logic
192
+ *
193
+ * Recursively evaluates nested rules with AND (all must be true) or OR
194
+ * (at least one must be true) logic.
195
+ *
196
+ * @param rule - Composite rule with condition ('and'|'or') and rules array
197
+ * @param formValues - Current form field values
198
+ * @returns true if composite condition met, false otherwise
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const rule = {
203
+ * condition: 'and',
204
+ * rules: [
205
+ * { field: 'age', operator: 'greaterThan', value: 18 },
206
+ * { field: 'country', operator: 'equal', value: 'US' }
207
+ * ]
208
+ * };
209
+ * const isEligible = evaluateCompositeRule(rule, { age: 25, country: 'US' });
210
+ * // isEligible = true
211
+ * ```
212
+ */
213
+ ConditionalRuleEngine.evaluateCompositeRule = function (rule, formValues) {
214
+ var _this = this;
215
+ try {
216
+ if (!Array.isArray(rule.rules) || rule.rules.length === 0) {
217
+ return false;
218
+ }
219
+ var condition = rule.condition.toLowerCase();
220
+ if (condition === 'and') {
221
+ // All rules must be true
222
+ return rule.rules.every(function (childRule) {
223
+ return _this.evaluateCondition(childRule, formValues);
224
+ });
225
+ }
226
+ else if (condition === 'or') {
227
+ // At least one rule must be true
228
+ return rule.rules.some(function (childRule) {
229
+ return _this.evaluateCondition(childRule, formValues);
230
+ });
231
+ }
232
+ else {
233
+ return false;
234
+ }
235
+ }
236
+ catch (error) {
237
+ return false;
238
+ }
239
+ };
240
+ /**
241
+ * Check if field should be visible
242
+ *
243
+ * Evaluates visibleWhen condition. Defaults to true (visible) if no condition
244
+ * is defined or on error.
245
+ *
246
+ * @param conditions - FormComponentConditions containing visibleWhen rule
247
+ * @param formValues - Current form field values
248
+ * @returns true if field should be visible, false if hidden
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * const conditions = {
253
+ * visibleWhen: { field: 'showEmail', operator: 'equal', value: true }
254
+ * };
255
+ * const visible = isFieldVisible(conditions, { showEmail: true });
256
+ * // visible = true
257
+ * ```
258
+ */
259
+ ConditionalRuleEngine.isFieldVisible = function (conditions, formValues) {
260
+ try {
261
+ if (!conditions || !conditions.visibleWhen) {
262
+ return true; // Default: visible if no condition
263
+ }
264
+ return this.evaluateCondition(conditions.visibleWhen, formValues);
265
+ }
266
+ catch (error) {
267
+ return true; // Safe default: visible on error
268
+ }
269
+ };
270
+ /**
271
+ * Check if field should be read-only
272
+ *
273
+ * Evaluates readOnlyWhen condition. Defaults to false (editable) if no
274
+ * condition is defined or on error.
275
+ *
276
+ * @param conditions - FormComponentConditions containing readOnlyWhen rule
277
+ * @param formValues - Current form field values
278
+ * @returns true if field should be read-only, false if editable
279
+ *
280
+ * @example
281
+ * ```typescript
282
+ * const conditions = {
283
+ * readOnlyWhen: { field: 'isVerified', operator: 'equal', value: true }
284
+ * };
285
+ * const readOnly = isFieldReadOnly(conditions, { isVerified: true });
286
+ * // readOnly = true
287
+ * ```
288
+ */
289
+ ConditionalRuleEngine.isFieldReadOnly = function (conditions, formValues) {
290
+ try {
291
+ if (!conditions || !conditions.readOnlyWhen) {
292
+ return false; // Default: not read-only if no condition
293
+ }
294
+ return this.evaluateCondition(conditions.readOnlyWhen, formValues);
295
+ }
296
+ catch (error) {
297
+ return false; // Safe default: not read-only on error
298
+ }
299
+ };
300
+ /**
301
+ * Check if field should be disabled
302
+ *
303
+ * Evaluates disabledWhen condition. Defaults to false (enabled) if no
304
+ * condition is defined or on error.
305
+ *
306
+ * @param conditions - FormComponentConditions containing disabledWhen rule
307
+ * @param formValues - Current form field values
308
+ * @returns true if field should be disabled, false if enabled
309
+ *
310
+ * @example
311
+ * ```typescript
312
+ * const conditions = {
313
+ * disabledWhen: { field: 'orderStatus', operator: 'equal', value: 'completed' }
314
+ * };
315
+ * const disabled = isFieldDisabled(conditions, { orderStatus: 'completed' });
316
+ * // disabled = true
317
+ * ```
318
+ */
319
+ ConditionalRuleEngine.isFieldDisabled = function (conditions, formValues) {
320
+ try {
321
+ if (!conditions || !conditions.disabledWhen) {
322
+ return false; // Default: not disabled if no condition
323
+ }
324
+ return this.evaluateCondition(conditions.disabledWhen, formValues);
325
+ }
326
+ catch (error) {
327
+ return false; // Safe default: not disabled on error
328
+ }
329
+ };
330
+ /**
331
+ * Check if field should be hidden
332
+ *
333
+ * Evaluates hideWhen condition. Defaults to false (visible) if no condition
334
+ * is defined or on error.
335
+ *
336
+ * @param conditions - FormComponentConditions containing hideWhen rule
337
+ * @param formValues - Current form field values
338
+ * @returns true if field should be hidden, false if visible
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * const conditions = {
343
+ * hideWhen: { field: 'hideEmail', operator: 'equal', value: true }
344
+ * };
345
+ * const hidden = isFieldHidden(conditions, { hideEmail: true });
346
+ * // hidden = true
347
+ * ```
348
+ */
349
+ ConditionalRuleEngine.isFieldHidden = function (conditions, formValues) {
350
+ try {
351
+ if (!conditions || !conditions.hideWhen) {
352
+ return false; // Default: not hidden if no condition
353
+ }
354
+ return this.evaluateCondition(conditions.hideWhen, formValues);
355
+ }
356
+ catch (error) {
357
+ return false; // Safe default: not hidden on error
358
+ }
359
+ };
360
+ /**
361
+ * Check if field should be required
362
+ *
363
+ * Evaluates requiredWhen condition. Defaults to false (not required) if no condition
364
+ * is defined or on error.
365
+ *
366
+ * @param conditions - FormComponentConditions containing requiredWhen rule
367
+ * @param formValues - Current form field values
368
+ * @returns true if field should be required, false if optional
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * const conditions = {
373
+ * requiredWhen: { field: 'requireDetails', operator: 'equal', value: true }
374
+ * };
375
+ * const required = isFieldRequired(conditions, { requireDetails: true });
376
+ * // required = true
377
+ * ```
378
+ */
379
+ ConditionalRuleEngine.isFieldRequired = function (conditions, formValues) {
380
+ try {
381
+ if (!conditions || !conditions.requiredWhen) {
382
+ return false; // Default: not required if no condition
383
+ }
384
+ return this.evaluateCondition(conditions.requiredWhen, formValues);
385
+ }
386
+ catch (error) {
387
+ return false; // Safe default: not required on error
388
+ }
389
+ };
390
+ /**
391
+ * Get value to set for field if condition is met
392
+ *
393
+ * Evaluates setValueWhen condition and returns the value to assign if true.
394
+ * Returns undefined if no condition is defined, condition not met, or on error.
395
+ *
396
+ * @param conditions - FormComponentConditions containing setValueWhen rule
397
+ * @param formValues - Current form field values
398
+ * @returns The value to set if condition met, undefined otherwise
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * const conditions = {
403
+ * setValueWhen: {
404
+ * condition: { field: 'country', operator: 'equal', value: 'US' },
405
+ * value: 'United States'
406
+ * }
407
+ * };
408
+ * const value = getConditionalValue(conditions, { country: 'US' });
409
+ * // value = 'United States'
410
+ * ```
411
+ */
412
+ ConditionalRuleEngine.getConditionalValue = function (conditions, formValues) {
413
+ try {
414
+ if (!conditions || !conditions.setValueWhen) {
415
+ return undefined;
416
+ }
417
+ var isMet = this.evaluateCondition(conditions.setValueWhen.condition, formValues);
418
+ if (isMet) {
419
+ return conditions.setValueWhen.value;
420
+ }
421
+ return undefined;
422
+ }
423
+ catch (error) {
424
+ return undefined;
425
+ }
426
+ };
427
+ /**
428
+ * Evaluate conditional data availability
429
+ * Returns true if any conditional data rule's condition is met
430
+ *
431
+ * @param conditionalDataRules - Array of ConditionalDataRule objects
432
+ * @param formValues - Current form field values
433
+ * @returns Index of first matching rule, or -1 if none match
434
+ */
435
+ ConditionalRuleEngine.evaluateConditionalDataRules = function (conditionalDataRules, formValues) {
436
+ if (!conditionalDataRules || !Array.isArray(conditionalDataRules)) {
437
+ return -1;
438
+ }
439
+ for (var i = 0; i < conditionalDataRules.length; i++) {
440
+ var rule = conditionalDataRules[i];
441
+ if (this.evaluateCondition(rule.condition, formValues)) {
442
+ return i; // Return index of first matching rule
443
+ }
444
+ }
445
+ return -1;
446
+ };
447
+ /**
448
+ * Get filtered options for a dependent dropdown based on choice-based field rule
449
+ *
450
+ * If choiceBasedField rule exists and primary field has a value,
451
+ * return only the mapped dependent options for that primary value.
452
+ * Otherwise return all options.
453
+ *
454
+ * @param rule - ChoiceBasedFieldRule configuration
455
+ * @param allDependentOptions - Complete list of dependent field options
456
+ * @param formValues - Current form values
457
+ * @param primaryFieldId - ID of primary field
458
+ * @returns Filtered options array
459
+ *
460
+ * @example
461
+ * ```typescript
462
+ * const rule = {
463
+ * primaryFieldId: 'dept-id',
464
+ * choiceMapping: {
465
+ * 'Marketing': ['Markers', 'Sticky Notes'],
466
+ * 'Finance': ['Calculator']
467
+ * }
468
+ * };
469
+ *
470
+ * const filtered = ConditionalRuleEngine.getChoiceBasedOptions(
471
+ * rule,
472
+ * ['Markers', 'Sticky Notes', 'Calculator'],
473
+ * { 'dept-id': 'Marketing' },
474
+ * 'dept-id'
475
+ * );
476
+ * // Returns: ['Markers', 'Sticky Notes']
477
+ * ```
478
+ */
479
+ ConditionalRuleEngine.getChoiceBasedOptions = function (rule, allDependentOptions, formValues, primaryFieldId) {
480
+ try {
481
+ // Get primary field value from form
482
+ var primaryValue = formValues && formValues[primaryFieldId];
483
+ if (primaryValue === null || primaryValue === undefined) {
484
+ // No primary value selected - return all or empty based on rule config
485
+ return rule.showAllWhenNotMapped ? allDependentOptions : [];
486
+ }
487
+ // Ensure primary value is treated as string for comparison
488
+ var primaryValueStr = String(primaryValue);
489
+ // Check if this primary value is mapped in the rule
490
+ if (primaryValueStr in rule.choiceMapping) {
491
+ var mappedOptions = rule.choiceMapping[primaryValueStr];
492
+ // Validate mapped options exist in all options (safety check)
493
+ return mappedOptions.filter(function (opt) { return allDependentOptions.indexOf(opt) !== -1; });
494
+ }
495
+ // Primary value not mapped - return all or empty based on rule config
496
+ return rule.showAllWhenNotMapped ? allDependentOptions : [];
497
+ }
498
+ catch (error) {
499
+ // Safe default - return all options
500
+ return allDependentOptions;
501
+ }
502
+ };
503
+ return ConditionalRuleEngine;
504
+ }());
505
+ export { ConditionalRuleEngine };
@@ -0,0 +1,57 @@
1
+ import { FormValueType } from './expressions/expression-engine';
2
+ /**
3
+ * Custom Validation Engine
4
+ *
5
+ * Evaluates FormIO-style custom validation expressions:
6
+ * valid = (condition) ? true : 'error message';
7
+ *
8
+ * Reuses ExpressionEngine for dependency extraction and expression parsing
9
+ * @private
10
+ */
11
+ export declare class CustomValidationEngine {
12
+ private expressionEngine;
13
+ constructor();
14
+ /**
15
+ * Validate field using custom validation expression
16
+ *
17
+ * @param expression - FormIO-style validation expression (generated by UI)
18
+ * @param fieldValue - Current field value (as 'input')
19
+ * @param formValues - All form values for cross-field references
20
+ * @returns true if valid, error message string if invalid
21
+ */
22
+ validate(expression: string, fieldValue: any, formValues: Record<string, FormValueType>): true | string;
23
+ /**
24
+ * Extract field dependencies from validation expression
25
+ *
26
+ * @param expression - Custom validation expression (or just condition)
27
+ * @returns Array of field names referenced in expression
28
+ */
29
+ extractDependencies(expression: string): string[];
30
+ /**
31
+ * Validate condition syntax (simplified - no need for "valid =" check)
32
+ *
33
+ * @param condition - Validation condition (without "valid =" prefix)
34
+ * @param availableFields - Available field names for reference validation
35
+ * @returns Array of validation error messages
36
+ */
37
+ validateConditionSyntax(condition: string, availableFields: string[]): string[];
38
+ /**
39
+ * Build full FormIO expression from condition and error message
40
+ *
41
+ * @param condition - Validation condition (e.g., "(input === {password})")
42
+ * @param errorMessage - Error message to show when validation fails
43
+ * @returns Full FormIO expression
44
+ */
45
+ buildExpression(condition: string, errorMessage: string): string;
46
+ /**
47
+ * Extract condition and error message from full FormIO expression
48
+ * For editing existing rules
49
+ *
50
+ * @param expression - Full FormIO expression
51
+ * @returns { condition, errorMessage } or null if invalid
52
+ */
53
+ parseExpression(expression: string): {
54
+ condition: string;
55
+ errorMessage: string;
56
+ } | null;
57
+ }