@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,2277 @@
1
+ var __extends = (this && this.__extends) || (function () {
2
+ var extendStatics = function (d, b) {
3
+ extendStatics = Object.setPrototypeOf ||
4
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6
+ return extendStatics(d, b);
7
+ };
8
+ return function (d, b) {
9
+ extendStatics(d, b);
10
+ function __() { this.constructor = d; }
11
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12
+ };
13
+ })();
14
+ var __assign = (this && this.__assign) || function () {
15
+ __assign = Object.assign || function(t) {
16
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
17
+ s = arguments[i];
18
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
19
+ t[p] = s[p];
20
+ }
21
+ return t;
22
+ };
23
+ return __assign.apply(this, arguments);
24
+ };
25
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
26
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
27
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
28
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
29
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
30
+ };
31
+ import { Component, Property, Event, NotifyPropertyChanges, enableRipple, createElement, isNullOrUndefined, L10n, getComponent, addClass } from '@syncfusion/ej2-base';
32
+ import { Tab } from '@syncfusion/ej2-navigations';
33
+ import { Tooltip } from '@syncfusion/ej2-popups';
34
+ import { FormValidator } from '@syncfusion/ej2-inputs';
35
+ import { renderFormField } from './render-form-field';
36
+ import { mergeSchema } from '../common/json-converter';
37
+ import { UniversalJsonParser } from '../common/parser';
38
+ import { VALIDATION_REGEX, formatDateValues, splitWidths } from '../common/utils';
39
+ import StaticHtmlRenderer from '../common/static-html-renderer';
40
+ import { ConditionalRuleEngine } from '../common/conditional-rule-engine';
41
+ import { ExpressionEngine } from '../common/expressions/expression-engine';
42
+ import { MinMaxRuleEngine } from '../common/minmax-rule-engine';
43
+ import { CustomValidationEngine } from '../common/custom-validation-engine';
44
+ /**
45
+ * @private
46
+ *
47
+ * Internal input target types array to define a target.
48
+ */
49
+ var inputTargetTypes = [
50
+ 'textbox',
51
+ 'number',
52
+ 'checkbox',
53
+ 'dropdown',
54
+ 'multiselect',
55
+ 'date',
56
+ 'dateTime',
57
+ 'time',
58
+ 'dateRange',
59
+ 'switch',
60
+ 'rating',
61
+ 'colorPicker',
62
+ 'inputMask',
63
+ 'fileUpload'
64
+ ];
65
+ /**
66
+ * @private
67
+ */
68
+ export var defaultLocale = {
69
+ "unsupportedComponent": "Unsupported Component type"
70
+ };
71
+ /**
72
+ * The FormRenderer component consumes a JSON form schema and renders a fully functional, Syncfusion-based form. It handles field mapping, conditional visibility/disabling, expression evaluation, custom validation, and data submission.
73
+ *
74
+ * ```typescript
75
+ * let form: FormRenderer = new FormRenderer({
76
+ * schema: formSchema,
77
+ * submit: (args: SubmitEventArgs) => console.log(args)
78
+ * });
79
+ * form.appendTo('#container');
80
+ * ```
81
+ */
82
+ var FormRenderer = /** @class */ (function (_super) {
83
+ __extends(FormRenderer, _super);
84
+ /**
85
+ * Constructor for creating the widget
86
+ *
87
+ * @param {FormRendererModel} options - Specifies the form renderer model
88
+ * @param {string|HTMLDivElement} element - Specifies the target element
89
+ */
90
+ function FormRenderer(options, element) {
91
+ var _this = _super.call(this, options, element) || this;
92
+ _this.processedSchemaCache = { version: '1.0.0', components: [] };
93
+ /** Localization instance */
94
+ _this.l10n = new L10n('form-renderer', defaultLocale, _this.locale);
95
+ /**
96
+ * @private
97
+ *
98
+ * Minimal form-state container owned by the orchestrator. The previous
99
+ * vanilla-TS port delegated this to `FormStateBridge`; that bridge's
100
+ * `registeredFields` gate silently short-circuited every field to "no
101
+ * error" because the orchestrator never called `registerField`. The
102
+ * EJ2 native `FormValidator` (bound to `this.element`) now handles all
103
+ * rule evaluation, error-element placement, change/blur/submit wiring,
104
+ * and ARIA — exactly what `FormValidator` was designed for. This object
105
+ * is the orchestrator's authoritative values store; `errors` are
106
+ * mirrored from the FormValidator's `errorRules` for `renderField`'s
107
+ * initial-paint logic and for submit-time `isValid` checks.
108
+ */
109
+ _this.formState = { values: Object.create(null), errors: Object.create(null) };
110
+ /** EJ2 native FormValidator bound to `this.element` (replaces FormStateBridge). */
111
+ _this.validator = null;
112
+ /** Map of input component instances keyed by `name` (or `${name}_${idx}`). */
113
+ _this.inputRefs = {};
114
+ /** Conditional value applied tracker (per-field). */
115
+ _this.conditionalValueApplied = {};
116
+ /** Expression engine + dependency graph + computed-field set. */
117
+ _this.expressionEngine = null;
118
+ _this.expressionDependencyGraph = {};
119
+ _this.expressionEvaluationInProgress = false;
120
+ _this.previousFormValues = {};
121
+ _this.computedFieldNames = new Set();
122
+ /** Custom validation engine instance. */
123
+ _this.customValidationEngine = new CustomValidationEngine();
124
+ /** Latest form values snapshot for custom validation (named-key context). */
125
+ _this.currentFormValues = {};
126
+ /** Whether initial values have been seeded once. */
127
+ _this.isInitialized = false;
128
+ /** Cached layout detection result. */
129
+ _this.hasLayoutComponentsCache = false;
130
+ /** Cached id→label map. */
131
+ _this.idToLabelCache = {};
132
+ /** Cached initial values (recomputed on schema change). */
133
+ _this.initialValuesCache = {};
134
+ /** Rendered child EJ2 instances (for destroy cleanup). */
135
+ _this.renderedInstances = [];
136
+ /** Tooltip instances keyed by field id so stale tooltips can be replaced promptly. */
137
+ _this.tooltipRefs = {};
138
+ /** `created` fired-once guard. */
139
+ _this.createdFired = false;
140
+ /**
141
+ * Coalescing guard for `scheduleRerender`. Prevents redundant full-form
142
+ * re-renders within a single microtask — mirrors React's batched-state
143
+ * semantics so that a user keystroke + expression cascade fire one render.
144
+ */
145
+ _this.rerenderScheduled = false;
146
+ /**
147
+ * Set of `component.id`s that are referenced as the trigger field of any
148
+ * other component's `conditions` (`visibleWhen` / `hideWhen` /
149
+ * `disabledWhen` / `requiredWhen` / `readOnlyWhen` / `setValueWhen` /
150
+ * `choiceBasedField.primaryFieldId`). Only changes to these fields can
151
+ * affect visibility / disabled / required / valueWhen of any other
152
+ * field, so only they need to trigger a full-form re-render. Changes to
153
+ * fields *not* in this set are guaranteed to have no conditional side
154
+ * effects and safely skip the (expensive) full DOM teardown + rebuild.
155
+ * Built once per schema in `buildConditionalDependencyMap`.
156
+ */
157
+ _this.conditionalTriggerFieldIds = new Set();
158
+ /**
159
+ * Maps `component.id` → the previously-rendered DOM subtree (form-group)
160
+ * for "expensive" components (dataGrid, dropdown, multiselect,
161
+ * checkboxGroup) that support remote data. During a full-form re-render
162
+ * triggered by an *unrelated* conditional change, these subtrees are
163
+ * detached (not destroyed) and re-attached in place, avoiding a re-fetch
164
+ * of their remote data sources and preventing the visible blink/reload.
165
+ * A subtree is *invalidated* (dropped from this map, forcing a fresh
166
+ * render) when a field it depends on (via its own `conditions` or
167
+ * `conditionalData`) is the one that changed.
168
+ */
169
+ _this.preservedFields = new Map();
170
+ /**
171
+ * Per-consumer dependency map: `component.id` → set of trigger field ids
172
+ * that the consumer's own `conditions` / `conditionalData` /
173
+ * `choiceBasedField` reference. Used during `rerenderForm` to decide
174
+ * whether a preserved subtree must be invalidated (rebuilt) because the
175
+ * changed field is one of its own dependencies, or can be safely reused.
176
+ */
177
+ _this.consumerDependencyMap = new Map();
178
+ /**
179
+ * @private
180
+ *
181
+ * Coalesced full-form re-render. Multiple triggers within the same
182
+ * microtask drain into a single `rerenderForm()` call. The set of
183
+ * changed field ids is accumulated across the tick so `rerenderForm`
184
+ * can decide which preserved subtrees must be invalidated (because one
185
+ * of the changed fields is in their own dependency set).
186
+ */
187
+ _this.pendingChangedFieldIds = new Set();
188
+ return _this;
189
+ }
190
+ FormRenderer_1 = FormRenderer;
191
+ /**
192
+ * Returns the EJ2 component module name.
193
+ * @private
194
+ */
195
+ FormRenderer.prototype.getModuleName = function () {
196
+ return 'form-renderer';
197
+ };
198
+ /**
199
+ * Return the persisted-state payload. The base class declares this
200
+ * abstract; FormRenderer does not implement state persistence, so an
201
+ * empty object is returned (mirrors the EJ2 convention for
202
+ * non-persistent components).
203
+ * @private
204
+ */
205
+ FormRenderer.prototype.getPersistData = function () {
206
+ return this.addOnPersist(['formState', JSON.stringify(this.formState)]);
207
+ };
208
+ /**
209
+ * Pre-render wiring: enable ripple, init the expression engine + bridge.
210
+ * @private
211
+ */
212
+ FormRenderer.prototype.preRender = function () {
213
+ enableRipple(true);
214
+ this.createdFired = false;
215
+ this.expressionEngine = new ExpressionEngine();
216
+ };
217
+ /**
218
+ * Main render: normalize schema, build rules + initial values, render tree.
219
+ * @private
220
+ */
221
+ FormRenderer.prototype.render = function () {
222
+ var _this = this;
223
+ this.clearEngineCaches();
224
+ this.removePreviousRoot();
225
+ this.normalizeSchema();
226
+ this.element.classList.add('form-renderer-container');
227
+ if (this.className) {
228
+ addClass([this.element], this.className.replace(/\s+/g, ' ').trim().split(' '));
229
+ }
230
+ if (this.enableRtl) {
231
+ this.element.classList.add('e-rtl');
232
+ }
233
+ else {
234
+ this.element.classList.remove('e-rtl');
235
+ }
236
+ this.hasLayoutComponentsCache = this.computeHasLayoutComponents();
237
+ this.idToLabelCache = this.computeIdToLabel();
238
+ this.initialValuesCache = this.buildInitialValues();
239
+ this.buildValidationRulesAndBridge();
240
+ // Seed initial values into the form-state values map once.
241
+ if (!this.isInitialized) {
242
+ this.isInitialized = true;
243
+ }
244
+ if (this.formState && this.initialValuesCache) {
245
+ var initKeys = Object.keys(this.initialValuesCache);
246
+ for (var _i = 0, initKeys_1 = initKeys; _i < initKeys_1.length; _i++) {
247
+ var id = initKeys_1[_i];
248
+ var value = this.initialValuesCache[id];
249
+ if (!(this.formState).values[id]) {
250
+ (this.formState).values[id] = value;
251
+ }
252
+ }
253
+ }
254
+ this.currentFormValues = __assign({}, (this.formState ? this.formState.values : {}));
255
+ this.initExpressionEngine();
256
+ this.buildConditionalDependencyMap();
257
+ var root = createElement('form', {
258
+ className: "form-renderer " + this.layoutClass,
259
+ attrs: { role: 'region', 'aria-label': this.processedSchemaCache.settings ? (this.processedSchemaCache.settings.name || 'Form') : 'Form' }
260
+ });
261
+ this.element.appendChild(root);
262
+ this.inputRefs = {};
263
+ (this.processedSchemaCache.components || []).forEach(function (component) {
264
+ var rendered = _this.renderComponent(component);
265
+ if (rendered) {
266
+ root.appendChild(rendered);
267
+ }
268
+ if (component.type === 'richTextEditor') {
269
+ var rteElement = rendered.querySelector('.e-richtexteditor');
270
+ var rteInstance = getComponent(rteElement, 'richtexteditor');
271
+ rteInstance.refreshUI();
272
+ }
273
+ if (component.type === 'dataGrid') {
274
+ var toolbarElement = rendered.querySelector('.e-control.e-toolbar');
275
+ var rteInstance = getComponent(toolbarElement, 'toolbar');
276
+ rteInstance.refresh();
277
+ }
278
+ });
279
+ if (this.created && !this.createdFired) {
280
+ setTimeout(function () {
281
+ if (Object.keys(_this.inputRefs).length > 0) {
282
+ _this.createdFired = true;
283
+ _this.trigger('created', {});
284
+ }
285
+ }, 0);
286
+ }
287
+ };
288
+ /**
289
+ * @private
290
+ */
291
+ FormRenderer.prototype.normalizeSchema = function () {
292
+ var schema = this.schema;
293
+ try {
294
+ if (!schema) {
295
+ this.processedSchemaCache = { version: '1.0.0', components: [] };
296
+ return;
297
+ }
298
+ var parsedInput = schema;
299
+ if (typeof schema === 'string') {
300
+ try {
301
+ parsedInput = JSON.parse(schema);
302
+ }
303
+ catch (err) {
304
+ if (this.failure) {
305
+ this.trigger('failure', {
306
+ error: err
307
+ });
308
+ }
309
+ this.processedSchemaCache = { version: '1.0.0', components: [] };
310
+ return;
311
+ }
312
+ }
313
+ var isUnifiedSchema = parsedInput && typeof parsedInput === 'object' &&
314
+ parsedInput.properties && Array.isArray(parsedInput.layout);
315
+ if (isUnifiedSchema) {
316
+ this.processedSchemaCache = mergeSchema(parsedInput);
317
+ }
318
+ else {
319
+ var parser = new UniversalJsonParser();
320
+ var parseResult = parser.parse(typeof schema === 'string' ? schema : JSON.stringify(schema));
321
+ if (parseResult.success && parseResult.schema) {
322
+ this.processedSchemaCache = parseResult.schema;
323
+ }
324
+ else {
325
+ if (this.failure) {
326
+ this.trigger('failure', {
327
+ error: parseResult.errors
328
+ });
329
+ }
330
+ this.processedSchemaCache = { version: '1.0.0', components: [] };
331
+ }
332
+ }
333
+ }
334
+ catch (error) {
335
+ if (this.failure) {
336
+ this.trigger('failure', {
337
+ error: error
338
+ });
339
+ }
340
+ this.processedSchemaCache = { version: '1.0.0', components: [] };
341
+ }
342
+ };
343
+ // ----------------------------------------------------------------------
344
+ // G3 — layout detection + suppression map
345
+ // ----------------------------------------------------------------------
346
+ /**
347
+ * Recursively scan the schema for any `table`/`tabs`/`panel`/`card`
348
+ * (including inside table cells and tab content). Mirrors `hasLayoutComponents`.
349
+ * @private
350
+ */
351
+ FormRenderer.prototype.computeHasLayoutComponents = function () {
352
+ if (!this.processedSchemaCache.components) {
353
+ return false;
354
+ }
355
+ var checkForLayoutTypes = function (components) {
356
+ for (var _i = 0, components_1 = components; _i < components_1.length; _i++) {
357
+ var comp = components_1[_i];
358
+ if (['table', 'tabs', 'panel', 'card'].indexOf(comp.type) !== -1) {
359
+ return true;
360
+ }
361
+ if (comp.children && checkForLayoutTypes(comp.children)) {
362
+ return true;
363
+ }
364
+ if (comp.tableCells) {
365
+ for (var _a = 0, _b = comp.tableCells; _a < _b.length; _a++) {
366
+ var row = _b[_a];
367
+ for (var _c = 0, row_1 = row; _c < row_1.length; _c++) {
368
+ var cell = row_1[_c];
369
+ if (checkForLayoutTypes(cell)) {
370
+ return true;
371
+ }
372
+ }
373
+ }
374
+ }
375
+ if (comp.tabItems) {
376
+ for (var _d = 0, _e = comp.tabItems; _d < _e.length; _d++) {
377
+ var tab = _e[_d];
378
+ if (tab.content && checkForLayoutTypes(tab.content)) {
379
+ return true;
380
+ }
381
+ }
382
+ }
383
+ }
384
+ return false;
385
+ };
386
+ return checkForLayoutTypes(this.processedSchemaCache.components);
387
+ };
388
+ Object.defineProperty(FormRenderer.prototype, "layoutClass", {
389
+ /**
390
+ * The layout CSS class (suppressed when layout components are present).
391
+ * @private
392
+ */
393
+ get: function () {
394
+ if (this.hasLayoutComponentsCache) {
395
+ return '';
396
+ }
397
+ switch (this.layout) {
398
+ case 'TwoColumn':
399
+ return 'twolayout';
400
+ case 'ThreeColumn':
401
+ return 'threelayout';
402
+ case 'FourColumn':
403
+ return 'fourlayout';
404
+ case 'SingleColumn':
405
+ default:
406
+ return '';
407
+ }
408
+ },
409
+ enumerable: true,
410
+ configurable: true
411
+ });
412
+ // ----------------------------------------------------------------------
413
+ // G4 — collectAllComponents + idToLabel
414
+ // ----------------------------------------------------------------------
415
+ /**
416
+ * Recursively collect all components including nested ones.
417
+ * @private
418
+ */
419
+ FormRenderer.prototype.collectAllComponents = function (components) {
420
+ var all = [];
421
+ var traverse = function (comps) {
422
+ comps.forEach(function (comp) {
423
+ all.push(comp);
424
+ if (comp.children && comp.children.length > 0) {
425
+ traverse(comp.children);
426
+ }
427
+ if (comp.tableCells) {
428
+ comp.tableCells.forEach(function (row) {
429
+ row.forEach(function (cell) { return traverse(cell); });
430
+ });
431
+ }
432
+ if (comp.tabItems) {
433
+ comp.tabItems.forEach(function (tab) {
434
+ if (tab.content) {
435
+ traverse(tab.content);
436
+ }
437
+ });
438
+ }
439
+ });
440
+ };
441
+ traverse(components);
442
+ return all;
443
+ };
444
+ /**
445
+ * @private
446
+ */
447
+ FormRenderer.prototype.computeIdToLabel = function () {
448
+ var map = {};
449
+ var traverse = function (comps) {
450
+ comps.forEach(function (comp) {
451
+ if (comp.label && ['panel', 'table', 'tabs', 'card', 'button', 'message', 'splitButton'].indexOf(comp.type) === -1) {
452
+ if (comp.name) {
453
+ map[comp.id] = comp.name;
454
+ }
455
+ else if (comp.label) {
456
+ map[comp.id] = comp.label;
457
+ }
458
+ }
459
+ if (comp.children) {
460
+ traverse(comp.children);
461
+ }
462
+ if (comp.tableCells) {
463
+ comp.tableCells.forEach(function (row) { return row.forEach(function (cell) { return traverse(cell); }); });
464
+ }
465
+ if (comp.tabItems) {
466
+ comp.tabItems.forEach(function (tab) { if (tab.content) {
467
+ traverse(tab.content);
468
+ } });
469
+ }
470
+ });
471
+ };
472
+ traverse(this.processedSchemaCache.components);
473
+ return map;
474
+ };
475
+ // ----------------------------------------------------------------------
476
+ // G5 — buildValidationRules via FormStateBridge + ConditionalRuleEngine +
477
+ // EMAIL/URL auto-regex + customValidator closure
478
+ // ----------------------------------------------------------------------
479
+ /**
480
+ * @private
481
+ */
482
+ FormRenderer.prototype.buildValidationRulesAndBridge = function () {
483
+ var _this = this;
484
+ var rules = {};
485
+ var formValues = (this.formState && this.formState.values) || {};
486
+ var collectRules = function (components, parentVisible) {
487
+ if (parentVisible === void 0) { parentVisible = true; }
488
+ components.forEach(function (component) {
489
+ if (!component) {
490
+ return;
491
+ }
492
+ var componentRules = {};
493
+ var isVisible = parentVisible && (component.visible === false
494
+ ? false
495
+ : ConditionalRuleEngine.isFieldVisible(component.conditions, formValues));
496
+ var isHidden = parentVisible && ConditionalRuleEngine.isFieldHidden(component.conditions, formValues);
497
+ if (!isVisible || isHidden) {
498
+ return;
499
+ }
500
+ var conditionalRequired = ConditionalRuleEngine.isFieldRequired(component.conditions, formValues);
501
+ var conditionalDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
502
+ var conditionalReadOnly = ConditionalRuleEngine.isFieldReadOnly(component.conditions, formValues);
503
+ var finalRequired = !!component.required || conditionalRequired;
504
+ var finalDisabled = !!component.disabled || conditionalDisabled;
505
+ var finalReadOnly = !!component.readOnly || conditionalReadOnly;
506
+ if (component.customValidation &&
507
+ Array.isArray(component.customValidation) &&
508
+ component.customValidation.length > 0 &&
509
+ !finalDisabled && !finalReadOnly) {
510
+ var customValidationExpression = component.customValidation && component.customValidation[0] && component.customValidation[0].expression;
511
+ var validationMessage = customValidationExpression && customValidationExpression.match(/\?\s*true\s*:\s*['"](.+?)['"]/) ? customValidationExpression.match(/\?\s*true\s*:\s*['"](.+?)['"]/)[1] : undefined;
512
+ var customMessage = validationMessage ||
513
+ component.validationMessage ||
514
+ (component.label || component.id) + " is invalid";
515
+ var self_1 = _this;
516
+ componentRules.customValidation = [
517
+ function (args) {
518
+ var fieldValue = args.value;
519
+ if (finalRequired && (fieldValue === '' || fieldValue === null || fieldValue === undefined)) {
520
+ return true;
521
+ }
522
+ var idToNameMap = {};
523
+ var allComponents = self_1.collectAllComponents(self_1.processedSchemaCache.components);
524
+ allComponents.forEach(function (comp) {
525
+ if (comp.name) {
526
+ idToNameMap[comp.id] = comp.name;
527
+ }
528
+ });
529
+ var currentFormValues = __assign({}, (self_1.currentFormValues || {}));
530
+ var cfvKeys = Object.keys(__assign({}, currentFormValues));
531
+ for (var _i = 0, cfvKeys_1 = cfvKeys; _i < cfvKeys_1.length; _i++) {
532
+ var componentId = cfvKeys_1[_i];
533
+ var value = currentFormValues[componentId];
534
+ var fieldName = idToNameMap[componentId];
535
+ if (fieldName) {
536
+ currentFormValues[fieldName] = value;
537
+ delete currentFormValues[componentId];
538
+ }
539
+ }
540
+ for (var _a = 0, _b = component.customValidation; _a < _b.length; _a++) {
541
+ var rule = _b[_a];
542
+ if (!self_1.customValidationEngine) {
543
+ return true;
544
+ }
545
+ var result = self_1.customValidationEngine.validate(rule.expression, fieldValue, currentFormValues);
546
+ if (result !== true) {
547
+ return false;
548
+ }
549
+ }
550
+ return true;
551
+ },
552
+ customMessage
553
+ ];
554
+ }
555
+ if (finalRequired && !finalDisabled && !finalReadOnly) {
556
+ componentRules.required = [true, component.validationMessage || component.label + " is required"];
557
+ }
558
+ if (component.minLength && !finalDisabled && !finalReadOnly) {
559
+ componentRules.minLength = [component.minLength, "Minimum " + component.minLength + " characters allowed"];
560
+ }
561
+ if (component.maxLength && !finalDisabled && !finalReadOnly) {
562
+ componentRules.maxLength = [component.maxLength, "Maximum " + component.maxLength + " characters allowed"];
563
+ }
564
+ if (component.type === 'textbox' && component.textboxType && !component.regex &&
565
+ !componentRules.regex && !finalDisabled && !finalReadOnly) {
566
+ if (component.textboxType === 'email') {
567
+ componentRules.regex = [VALIDATION_REGEX['EMAIL'], component.validationMessage || 'Invalid format'];
568
+ }
569
+ else if (component.textboxType === 'url') {
570
+ componentRules.regex = [VALIDATION_REGEX['URL'], component.validationMessage || 'Invalid format'];
571
+ }
572
+ }
573
+ if (component.regex && !finalDisabled && !finalReadOnly) {
574
+ componentRules.regex = [component.regex, component.validationMessage || 'Invalid format'];
575
+ }
576
+ if (Object.keys(componentRules).length > 0) {
577
+ rules[component.id] = componentRules;
578
+ }
579
+ if (component.children) {
580
+ collectRules(component.children, isVisible && !isHidden);
581
+ }
582
+ if (component.tableCells) {
583
+ component.tableCells.forEach(function (row) { return row.forEach(function (cell) { return collectRules(cell, isVisible && !isHidden); }); });
584
+ }
585
+ if (component.tabItems) {
586
+ component.tabItems.forEach(function (tab) {
587
+ if (tab.content) {
588
+ collectRules(tab.content, isVisible && !isHidden);
589
+ }
590
+ });
591
+ }
592
+ });
593
+ };
594
+ collectRules(this.processedSchemaCache.components);
595
+ // Preserve previously-entered values across a re-render.
596
+ var previousValues = this.formState ? __assign({}, this.formState.values) : __assign({}, this.initialValuesCache);
597
+ this.formState = {
598
+ values: Object.assign(Object.create(null), this.initialValuesCache, previousValues),
599
+ errors: this.enablePersistence ? this.formState.errors : Object.create(null)
600
+ };
601
+ // Restore any previously-entered values that the merge above pruned.
602
+ if (previousValues) {
603
+ Object.keys(previousValues).forEach(function (id) {
604
+ if (!(id in _this.formState.values)) {
605
+ _this.formState.values[id] = previousValues[id];
606
+ }
607
+ });
608
+ }
609
+ // (Re)create the EJ2 native FormValidator bound to the host element.
610
+ if (this.validator) {
611
+ try {
612
+ this.validator.refresh();
613
+ this.validator.destroy();
614
+ }
615
+ catch (e) { /* swallow */ }
616
+ this.validator = null;
617
+ }
618
+ var self = this;
619
+ this.validator = new FormValidator(this.element, {
620
+ rules: rules,
621
+ locale: this.locale,
622
+ ignore: 'e-hidden',
623
+ errorClass: 'e-error',
624
+ validClass: 'e-valid',
625
+ errorElement: 'div',
626
+ errorContainer: 'div',
627
+ customPlacement: function (inputElement, errorElement) {
628
+ // Locate the per-field error-message slot rendered in
629
+ // `renderField` by its id (`error-<component.id>`). The
630
+ // input's `name` attribute matches `component.id`
631
+ // (set in renderField), so `getElementById('error-' + name)`
632
+ // resolves the slot and the validator's error element is
633
+ // appended into it (FormValidator sets
634
+ // `errorElement.style.display = 'block'` before invoking
635
+ // customPlacement, which makes the slot visible).
636
+ var name = inputElement.getAttribute('name');
637
+ if (!name) {
638
+ if (inputElement.parentElement) {
639
+ inputElement.parentElement.appendChild(errorElement);
640
+ }
641
+ return;
642
+ }
643
+ var slot = document.getElementById("error-" + name);
644
+ if (slot) {
645
+ while (slot.firstChild) {
646
+ slot.removeChild(slot.firstChild);
647
+ }
648
+ slot.appendChild(errorElement);
649
+ slot.style.display = 'block';
650
+ }
651
+ else if (inputElement.parentElement) {
652
+ inputElement.parentElement.appendChild(errorElement);
653
+ }
654
+ },
655
+ validationComplete: function (args) {
656
+ // Mirror the validator's error state into formState.errors so
657
+ // submit-time isValid and renderField's initial-paint logic
658
+ // (which read formState.errors[id]) continue to work.
659
+ self.syncFormStateErrors();
660
+ // Keep the per-field error slot's visibility in sync with
661
+ // the validator's outcome. On `success`, the FormValidator's
662
+ // `hideMessage` sets its own error element's `display: none`,
663
+ // but our slot (`error-<id>`) would otherwise keep the stale
664
+ // error element appended. Clear + hide the slot on success.
665
+ if (args && args.inputName) {
666
+ var slot = document.getElementById("error-" + args.inputName);
667
+ if (slot) {
668
+ if (args.status === 'success') {
669
+ while (slot.firstChild) {
670
+ slot.removeChild(slot.firstChild);
671
+ }
672
+ slot.style.display = 'none';
673
+ }
674
+ else if (args.status === 'failure') {
675
+ slot.style.display = 'block';
676
+ }
677
+ }
678
+ }
679
+ },
680
+ submit: function (event) {
681
+ if (!self.validator) {
682
+ return;
683
+ }
684
+ var isValid = self.validator.validate();
685
+ if (!isValid) {
686
+ if (event && typeof event.preventDefault === 'function') {
687
+ event.preventDefault();
688
+ }
689
+ return;
690
+ }
691
+ self.handleSubmitData(__assign({}, self.formState.values));
692
+ if (event && typeof event.preventDefault === 'function') {
693
+ event.preventDefault();
694
+ }
695
+ },
696
+ reset: function () {
697
+ }
698
+ });
699
+ // Apply cached previous values to the FormValidator's input elements.
700
+ // The validator reads live values from inputs at validate() time, but
701
+ // initial values seeded here ensure any pre-populated values are
702
+ // respected even if a field is never focused before submit.
703
+ if (previousValues) {
704
+ Object.keys(previousValues).forEach(function (id) {
705
+ var inputEl = _this.validator.getInputElement(id);
706
+ if (inputEl && previousValues[id] !== undefined && previousValues[id] !== null) {
707
+ try {
708
+ inputEl.value = String(previousValues[id]);
709
+ }
710
+ catch (e) { /* swallow */ }
711
+ }
712
+ });
713
+ }
714
+ };
715
+ /**
716
+ * @private
717
+ *
718
+ * Mirror the FormValidator's `errorRules` array into `this.formState.errors`
719
+ * keyed by field `name` (= `component.id`). Called after every
720
+ * `validationComplete` callback and from submit-time `isValid` reads.
721
+ */
722
+ FormRenderer.prototype.syncFormStateErrors = function () {
723
+ var errors = {};
724
+ if (this.validator) {
725
+ var errorRules = this.validator.errorRules || [];
726
+ for (var _i = 0, errorRules_1 = errorRules; _i < errorRules_1.length; _i++) {
727
+ var rule = errorRules_1[_i];
728
+ if (rule && rule.name) {
729
+ errors[rule.name] = rule.message;
730
+ }
731
+ }
732
+ }
733
+ this.formState.errors = errors;
734
+ };
735
+ /**
736
+ * @private
737
+ */
738
+ FormRenderer.prototype.buildInitialValues = function () {
739
+ var _this = this;
740
+ var values = {};
741
+ var allComponents = this.collectAllComponents(this.processedSchemaCache.components);
742
+ var componentIds = new Set();
743
+ allComponents.forEach(function (comp) {
744
+ if (comp.type === 'staticHtml') {
745
+ componentIds.add(comp.id);
746
+ return;
747
+ }
748
+ if (comp.type === 'dataGrid') {
749
+ values[comp.id] = Array.isArray(comp.dataSource)
750
+ ? comp.dataSource
751
+ : [];
752
+ }
753
+ if (comp.defaultValue !== undefined) {
754
+ values[comp.id] = comp.defaultValue;
755
+ }
756
+ else {
757
+ switch (comp.type) {
758
+ case 'checkbox':
759
+ case 'switch':
760
+ values[comp.id] = false;
761
+ break;
762
+ default:
763
+ break;
764
+ }
765
+ }
766
+ componentIds.add(comp.id);
767
+ });
768
+ if (this.formState) {
769
+ Object.keys(this.formState.values)
770
+ .filter(function (key) { return !componentIds.has(key); })
771
+ .forEach(function (key) {
772
+ delete (_this.formState).values[key];
773
+ });
774
+ }
775
+ return values;
776
+ };
777
+ // ----------------------------------------------------------------------
778
+ // Expression engine init (used by G9)
779
+ // ----------------------------------------------------------------------
780
+ /**
781
+ * Initialize the expression engine dependency graph + computed-field set.
782
+ * @private
783
+ */
784
+ FormRenderer.prototype.initExpressionEngine = function () {
785
+ if (!this.processedSchemaCache.components || this.processedSchemaCache.components.length === 0) {
786
+ return;
787
+ }
788
+ try {
789
+ var engine = this.expressionEngine;
790
+ var allComponents = this.collectAllComponents(this.processedSchemaCache.components);
791
+ var graph = engine.buildDependencyGraph(allComponents);
792
+ var cycles = engine.detectCircularDependencies(graph);
793
+ if (cycles.length > 0) {
794
+ }
795
+ this.expressionDependencyGraph = graph;
796
+ var computedFields_1 = new Set();
797
+ allComponents.forEach(function (comp) {
798
+ if (comp.expressionValue) {
799
+ computedFields_1.add(comp.id);
800
+ }
801
+ });
802
+ this.computedFieldNames = computedFields_1;
803
+ }
804
+ catch (error) {
805
+ if (this.failure) {
806
+ this.trigger('failure', {
807
+ error: error
808
+ });
809
+ }
810
+ }
811
+ };
812
+ /**
813
+ * @private
814
+ */
815
+ FormRenderer.prototype.disposeTooltipInstance = function (fieldId) {
816
+ var existingTooltip = this.tooltipRefs[fieldId] || null;
817
+ if (existingTooltip) {
818
+ try {
819
+ existingTooltip.destroy();
820
+ }
821
+ catch (e) {
822
+ this.trigger('failure', {
823
+ error: e
824
+ });
825
+ }
826
+ this.renderedInstances = this.renderedInstances.filter(function (inst) { return inst !== existingTooltip; });
827
+ this.tooltipRefs[fieldId] = null;
828
+ }
829
+ };
830
+ FormRenderer.prototype.renderField = function (component) {
831
+ var _this = this;
832
+ var formState = this.formState;
833
+ var formValues = formState ? formState.values : {};
834
+ if (['panel', 'table', 'tabs', 'card', 'message', 'button', 'splitButton', 'staticHtml'].indexOf(component.type) !== -1) {
835
+ return null;
836
+ }
837
+ var conditionalReadOnly = ConditionalRuleEngine.isFieldReadOnly(component.conditions, formValues);
838
+ var conditionalDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
839
+ var conditionalRequired = ConditionalRuleEngine.isFieldRequired(component.conditions, formValues);
840
+ var conditionalValue = ConditionalRuleEngine.getConditionalValue(component.conditions, formValues);
841
+ var computedReadOnly = !!component.readOnly || conditionalReadOnly;
842
+ var computedDisabled = !!component.disabled || conditionalDisabled;
843
+ var computedRequired = !!component.required || conditionalRequired;
844
+ var minMaxConstraints = MinMaxRuleEngine.getConstraints(component.minMaxRange, formValues, component.type);
845
+ if (component.type === 'dateTime') {
846
+ var dateConstraints = MinMaxRuleEngine.getConstraints(component.minMaxRange, formValues, 'date');
847
+ var timeConstraints = MinMaxRuleEngine.getConstraints(component.minMaxTimeRange, formValues, 'time');
848
+ minMaxConstraints = {
849
+ minValue: undefined,
850
+ maxValue: undefined,
851
+ minDate: dateConstraints.minDate,
852
+ maxDate: dateConstraints.maxDate,
853
+ minTime: timeConstraints.minTime,
854
+ maxTime: timeConstraints.maxTime
855
+ };
856
+ }
857
+ var labelPos = component.labelPosition || 'top';
858
+ var labelWidth = component.labelWidth || 'auto';
859
+ var showLabel = !component.hideLabel && !!component.label &&
860
+ ['checkbox', 'button', 'staticHtml'].indexOf(component.type) === -1;
861
+ var shouldShowError = !!(formState && formState.errors[component.id]);
862
+ var isRequiredError = shouldShowError && !!(formState && formState.errors[component.id].indexOf('required') !== -1);
863
+ var hasError = shouldShowError && !(isRequiredError && !computedRequired);
864
+ // setValueWhen false→true transition tracking.
865
+ var conditionIsActive = conditionalValue !== undefined;
866
+ var wasConditionActive = this.conditionalValueApplied[component.id] || false;
867
+ if (formState) {
868
+ if (conditionIsActive && !wasConditionActive) {
869
+ formState.values[component.id] = conditionalValue;
870
+ this.conditionalValueApplied[component.id] = true;
871
+ }
872
+ else if (!conditionIsActive && wasConditionActive) {
873
+ this.conditionalValueApplied[component.id] = false;
874
+ }
875
+ }
876
+ var formGroup = createElement('div', {
877
+ className: 'form-group',
878
+ attrs: { 'data-field-id': component.id, 'data-fr-field': component.id }
879
+ });
880
+ var fieldWrapper = createElement('div', {
881
+ className: "field-wrapper label-" + labelPos.toLowerCase()
882
+ });
883
+ if (showLabel) {
884
+ var labelEl = createElement('label', {
885
+ className: 'field-label'
886
+ });
887
+ if (inputTargetTypes.indexOf(component.type) !== -1 || component.type === 'textarea') {
888
+ labelEl.setAttribute('for', !isNullOrUndefined(this.element.id) ? this.element.id + '-' + component.name : component.name);
889
+ }
890
+ labelEl.style.width = labelPos.toLowerCase() === 'left' ? labelWidth + "%" : 'auto';
891
+ var span = createElement('span');
892
+ span.textContent = component.label;
893
+ labelEl.appendChild(span);
894
+ if (computedRequired) {
895
+ var asterisk = createElement('span', { className: 'required-asterisk' });
896
+ asterisk.textContent = '*';
897
+ labelEl.appendChild(asterisk);
898
+ }
899
+ this.disposeTooltipInstance(component.id);
900
+ if (component.tooltip) {
901
+ var tooltipHost = createElement('span', {
902
+ className: 'e-msg-icon e-icons e-circle-info tooltip-icon',
903
+ attrs: {
904
+ 'aria-label': component.tooltip,
905
+ title: component.tooltip,
906
+ tabindex: '0',
907
+ role: 'button',
908
+ 'aria-haspopup': 'true'
909
+ }
910
+ });
911
+ tooltipHost.style.cursor = 'pointer';
912
+ tooltipHost.style.display = 'flex';
913
+ tooltipHost.style.alignItems = 'center';
914
+ tooltipHost.style.justifyContent = 'center';
915
+ tooltipHost.style.flexShrink = '0';
916
+ labelEl.appendChild(tooltipHost);
917
+ var tooltip = new Tooltip({ content: component.tooltip, enableRtl: this.enableRtl });
918
+ tooltip.appendTo(tooltipHost);
919
+ this.tooltipRefs[component.id] = tooltip;
920
+ this.renderedInstances.push(tooltip);
921
+ }
922
+ fieldWrapper.appendChild(labelEl);
923
+ }
924
+ var fieldInput = createElement('div', {
925
+ className: 'field-input',
926
+ });
927
+ var isIndexedRef = (component.type === 'radio' || component.type === 'checkboxGroup') && Array.isArray(component.options);
928
+ var setInputRef = isIndexedRef
929
+ ? function (el, idx) {
930
+ if (el && typeof idx === 'number') {
931
+ _this.inputRefs[component.name + "_" + idx] = el;
932
+ }
933
+ }
934
+ : function (el) {
935
+ if (el) {
936
+ _this.inputRefs[component.name] = el;
937
+ }
938
+ };
939
+ var mergedComponent = __assign({}, component, { readOnly: computedReadOnly, disabled: computedDisabled, required: computedRequired }, (minMaxConstraints.minValue !== undefined && { minValue: minMaxConstraints.minValue }), (minMaxConstraints.maxValue !== undefined && { maxValue: minMaxConstraints.maxValue }), (minMaxConstraints.minDate !== undefined && { minDate: minMaxConstraints.minDate }), (minMaxConstraints.maxDate !== undefined && { maxDate: minMaxConstraints.maxDate }), (minMaxConstraints.minTime !== undefined && { minTime: minMaxConstraints.minTime }), (minMaxConstraints.maxTime !== undefined && { maxTime: minMaxConstraints.maxTime }));
940
+ var onChangeHandler = function (value) {
941
+ if (component.type !== 'staticHtml') {
942
+ if (component.type === 'signature') {
943
+ var ref = _this.inputRefs[value];
944
+ value = ref.getSignature();
945
+ }
946
+ if (component.type === 'imageEditor') {
947
+ var ref = _this.inputRefs[value];
948
+ var imageData = ref.getImageData();
949
+ var canvas = document.createElement('canvas');
950
+ canvas.width = imageData.width;
951
+ canvas.height = imageData.height;
952
+ var context = canvas.getContext('2d');
953
+ if (context) {
954
+ context.putImageData(imageData, 0, 0);
955
+ }
956
+ value = canvas.toDataURL();
957
+ }
958
+ if (component.type === 'radio' || component.type === 'checkboxGroup') {
959
+ var inputElement = _this.validator.getInputElement(component.id);
960
+ inputElement.value = value;
961
+ }
962
+ value = formatDateValues(component, value);
963
+ if (_this.formState && formState) {
964
+ _this.formState.values[component.id] = value;
965
+ formState.values[component.id] = value;
966
+ }
967
+ _this.trigger('change', { fieldName: component.name, label: component.label || component.id, value: value });
968
+ _this.afterValueChange(component.id);
969
+ }
970
+ };
971
+ var targetTag = inputTargetTypes.indexOf(component.type) !== -1
972
+ ? 'input' : component.type === 'textarea' ? 'textarea' : 'div';
973
+ var target = createElement(targetTag, {
974
+ attrs: { 'aria-label': component.label + " " + component.type }
975
+ });
976
+ if (component.type === 'radio' || component.type === 'checkboxGroup') {
977
+ var inputEl = createElement('input');
978
+ inputEl.id = !isNullOrUndefined(this.element.id) ? this.element.id + '-' + component.name : component.name;
979
+ inputEl.setAttribute('name', component.id);
980
+ inputEl.style.display = 'none';
981
+ inputEl.setAttribute('aria-hidden', 'true');
982
+ target.appendChild(inputEl);
983
+ }
984
+ else {
985
+ target.id = !isNullOrUndefined(this.element.id) ? this.element.id + '-' + component.name : component.name;
986
+ target.setAttribute('name', component.id);
987
+ }
988
+ fieldInput.appendChild(target);
989
+ var instance = renderFormField({
990
+ component: mergedComponent,
991
+ value: formState ? formState.values[component.id] : undefined,
992
+ onChange: onChangeHandler,
993
+ formState: formState,
994
+ settings: this.processedSchemaCache.settings,
995
+ onBlur: function () {
996
+ if (formState && component.type !== 'staticHtml') {
997
+ if (_this.validator) {
998
+ try {
999
+ _this.beforeValidate(component.id);
1000
+ _this.validator.validate(component.id);
1001
+ }
1002
+ catch (e) { /* swallow */ }
1003
+ _this.syncFormStateErrors();
1004
+ }
1005
+ }
1006
+ },
1007
+ ref: setInputRef,
1008
+ hasError: hasError,
1009
+ locale: this.locale,
1010
+ components: this.collectAllComponents(this.processedSchemaCache.components),
1011
+ enableRtl: this.enableRtl,
1012
+ target: target,
1013
+ l10n: this.l10n
1014
+ });
1015
+ if (Array.isArray(instance)) {
1016
+ instance.forEach(function (entry) {
1017
+ if (entry && typeof entry.destroy === 'function') {
1018
+ _this.renderedInstances.push(entry);
1019
+ }
1020
+ else if (entry instanceof HTMLElement) {
1021
+ for (var _i = 0, _a = Object.keys(_this.inputRefs); _i < _a.length; _i++) {
1022
+ var key = _a[_i];
1023
+ var inst = _this.inputRefs[key];
1024
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1025
+ if (hostEl && (hostEl === entry || entry.contains(hostEl))) {
1026
+ _this.renderedInstances.push(inst);
1027
+ }
1028
+ }
1029
+ }
1030
+ });
1031
+ }
1032
+ else if (instance) {
1033
+ if (typeof instance.destroy === 'function') {
1034
+ this.renderedInstances.push(instance);
1035
+ }
1036
+ else if (instance instanceof HTMLElement) {
1037
+ for (var _i = 0, _a = Object.keys(this.inputRefs); _i < _a.length; _i++) {
1038
+ var key = _a[_i];
1039
+ var inst = this.inputRefs[key];
1040
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1041
+ if (hostEl && (hostEl === instance || instance.contains(hostEl))) {
1042
+ this.renderedInstances.push(inst);
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+ var errorSlot = createElement('div', {
1048
+ id: 'error-' + (component.id || component.name || component.label),
1049
+ className: 'e-error-message',
1050
+ attrs: { role: 'alert', 'aria-live': 'assertive' }
1051
+ });
1052
+ errorSlot.style.display = 'none';
1053
+ if (hasError && formState && formState.errors[component.id]) {
1054
+ errorSlot.textContent = formState.errors[component.id];
1055
+ errorSlot.classList.add('e-error');
1056
+ errorSlot.style.display = 'block';
1057
+ }
1058
+ fieldInput.appendChild(errorSlot);
1059
+ fieldWrapper.appendChild(fieldInput);
1060
+ formGroup.appendChild(fieldWrapper);
1061
+ if (component.description) {
1062
+ var desc = createElement('div', {
1063
+ className: 'field-description',
1064
+ attrs: { 'aria-describedby': "description-" + component.label }
1065
+ });
1066
+ desc.textContent = component.description;
1067
+ formGroup.appendChild(desc);
1068
+ }
1069
+ return formGroup;
1070
+ };
1071
+ /**
1072
+ * @private
1073
+ */
1074
+ FormRenderer.prototype.renderComponent = function (component) {
1075
+ var _this = this;
1076
+ var formState = this.formState;
1077
+ var formValues = formState ? formState.values : {};
1078
+ var isVisible = component.visible === false
1079
+ ? false
1080
+ : ConditionalRuleEngine.isFieldVisible(component.conditions, formValues);
1081
+ var isHidden = ConditionalRuleEngine.isFieldHidden(component.conditions, formValues);
1082
+ if (!isVisible || isHidden) {
1083
+ if (formState && formState.values[component.id] !== undefined && formState.values[component.id] !== null) {
1084
+ formState.values[component.id] = null;
1085
+ }
1086
+ return null;
1087
+ }
1088
+ // Re-attach preserved subtree for expensive / remote-data components
1089
+ // (dataGrid / dropdown / multiselect / checkboxGroup / lookup). The
1090
+ // subtree was detached in `rerenderForm` before the rest of the tree
1091
+ // was destroyed; re-attaching it here avoids a re-fetch of remote
1092
+ // data sources and prevents the visible blink of a fresh render.
1093
+ if (FormRenderer_1.PRESERVABLE_TYPES.has(component.type) && this.preservedFields.has(component.id)) {
1094
+ var preservedNode = this.preservedFields.get(component.id);
1095
+ if (preservedNode) {
1096
+ this.preservedFields.delete(component.id);
1097
+ return preservedNode;
1098
+ }
1099
+ }
1100
+ switch (component.type) {
1101
+ case 'panel': {
1102
+ var fieldset = createElement('fieldset', {
1103
+ className: "form-panel-renderer " + (component.cssClass || '')
1104
+ });
1105
+ fieldset.style.minInlineSize = 'unset';
1106
+ if (component.label && !component.hideLabel) {
1107
+ var legend = createElement('legend', {
1108
+ className: !component.hideBorders ? 'panel-legend' : ''
1109
+ });
1110
+ legend.textContent = component.label;
1111
+ fieldset.appendChild(legend);
1112
+ }
1113
+ var content_1 = createElement('div', { className: 'panel-content' });
1114
+ (component.children || []).forEach(function (child) {
1115
+ var rendered = _this.renderComponent(child);
1116
+ if (rendered) {
1117
+ content_1.appendChild(rendered);
1118
+ }
1119
+ });
1120
+ fieldset.appendChild(content_1);
1121
+ return fieldset;
1122
+ }
1123
+ case 'table': {
1124
+ var tableRows = component.rows || (component.tableCells ? component.tableCells.length : 2);
1125
+ var tableCols = component.columns || (component.tableCells && component.tableCells[0] ? component.tableCells[0].length : 2);
1126
+ var defaultColSpan = Math.floor(12 / tableCols);
1127
+ var columnWidthsProp = component.columnWidths;
1128
+ var splittedWidths = columnWidthsProp ? splitWidths(columnWidthsProp.widths) : [];
1129
+ var tableDiv = createElement('div', {
1130
+ className: "form-table-renderer " + (component.hideBorders ? '' : 'table-border') + " " + (component.cssClass || ''),
1131
+ attrs: { role: 'group', 'aria-label': component.label || 'Table Layout' }
1132
+ });
1133
+ for (var rowIndex = 0; rowIndex < tableRows; rowIndex++) {
1134
+ var rowDiv = createElement('div', { className: 'e-form-table-row' });
1135
+ if (component.hideBorders) {
1136
+ rowDiv.style.display = 'flex';
1137
+ rowDiv.style.gap = '1.5rem';
1138
+ }
1139
+ var _loop_1 = function (colIndex) {
1140
+ var cellComponents = (component.tableCells && component.tableCells[rowIndex] &&
1141
+ component.tableCells[rowIndex][colIndex]) || [];
1142
+ var cellSpan = defaultColSpan;
1143
+ var colWidthValue = splittedWidths[colIndex];
1144
+ var isSingleColumn = tableCols === 1;
1145
+ var cellStyle = isSingleColumn ? { width: '100%' } : (colWidthValue ? { width: colWidthValue + "%" } : {});
1146
+ var allNullWidths = !columnWidthsProp || (Array.isArray(columnWidthsProp.widths) && columnWidthsProp.widths.every(function (w) { return w === null; }));
1147
+ var isFirstRow = rowIndex === 0;
1148
+ var cellDiv = createElement('div', {
1149
+ className: "e-form-table-cell " + (colWidthValue ? '' : allNullWidths ? "col-" + cellSpan : '')
1150
+ });
1151
+ if (component.hideBorders) {
1152
+ Object.assign(cellDiv.style, cellStyle, { padding: isFirstRow ? '0' : '12px 0 0 0' });
1153
+ }
1154
+ else {
1155
+ Object.assign(cellDiv.style, cellStyle);
1156
+ }
1157
+ cellComponents.forEach(function (comp) {
1158
+ var rendered = _this.renderComponent(comp);
1159
+ if (rendered) {
1160
+ cellDiv.appendChild(rendered);
1161
+ }
1162
+ });
1163
+ rowDiv.appendChild(cellDiv);
1164
+ };
1165
+ for (var colIndex = 0; colIndex < tableCols; colIndex++) {
1166
+ _loop_1(colIndex);
1167
+ }
1168
+ tableDiv.appendChild(rowDiv);
1169
+ }
1170
+ return tableDiv;
1171
+ }
1172
+ case 'tabs': {
1173
+ var tabsDiv = createElement('div', {
1174
+ className: "form-tabs-renderer " + (component.cssClass || '')
1175
+ });
1176
+ var tabHost = createElement('div', {
1177
+ className: 'e-tab'
1178
+ });
1179
+ tabHost.id = component.id;
1180
+ var tabHeader_1 = createElement('div', {
1181
+ className: 'e-tab-header'
1182
+ });
1183
+ var tabContent_1 = createElement('div', {
1184
+ className: 'e-content'
1185
+ });
1186
+ tabHost.appendChild(tabHeader_1);
1187
+ tabHost.appendChild(tabContent_1);
1188
+ tabsDiv.appendChild(tabHost);
1189
+ // Build the tab's host DOM up front so each `.e-content > .e-item`
1190
+ // wrapper exists during initialization. Using the JSON `items`
1191
+ // path causes EJ2 to lazily materialize only the active content
1192
+ // panel, which leaves the remaining rendered tab bodies missing
1193
+ // from the live DOM. By seeding the HTML markup structure and
1194
+ // inserting the already-rendered live child nodes into every
1195
+ // content item, the bound EJ2 instances stay attached and all
1196
+ // tabs render correctly.
1197
+ (component.tabItems || []).forEach(function (tab) {
1198
+ var headerItem = createElement('div');
1199
+ headerItem.textContent = tab.header;
1200
+ tabHeader_1.appendChild(headerItem);
1201
+ var contentItem = createElement('div');
1202
+ var contentDiv = createElement('div', { className: 'tab-content-renderer' });
1203
+ (tab.content || []).forEach(function (comp) {
1204
+ var rendered = _this.renderComponent(comp);
1205
+ if (rendered) {
1206
+ contentDiv.appendChild(rendered);
1207
+ }
1208
+ });
1209
+ contentItem.appendChild(contentDiv);
1210
+ tabContent_1.appendChild(contentItem);
1211
+ });
1212
+ var tab = new Tab({
1213
+ enableRtl: this.enableRtl,
1214
+ cssClass: component.cssClass,
1215
+ enablePersistence: true,
1216
+ animation: { previous: { effect: 'None' }, next: { effect: 'None' } },
1217
+ selected: function (args) {
1218
+ if (typeof window === 'undefined')
1219
+ return null;
1220
+ try {
1221
+ window.localStorage.setItem('tab' + component.id, JSON.stringify({
1222
+ selectedItem: args.selectedIndex
1223
+ }));
1224
+ }
1225
+ catch (_a) {
1226
+ }
1227
+ }
1228
+ });
1229
+ tab.appendTo(tabHost);
1230
+ this.renderedInstances.push(tab);
1231
+ return tabsDiv;
1232
+ }
1233
+ case 'card': {
1234
+ var fieldset = createElement('fieldset', {
1235
+ className: "e-card form-card-renderer " + (component.cssClass || '')
1236
+ });
1237
+ fieldset.style.minInlineSize = 'unset';
1238
+ fieldset.style.padding = '0';
1239
+ var header = createElement('div', { className: 'e-card-header' });
1240
+ var caption = createElement('div', { className: 'e-card-header-caption' });
1241
+ var title = createElement('div', { className: 'e-card-title' });
1242
+ title.textContent = component.cardTitle || component.label || 'Card Title';
1243
+ caption.appendChild(title);
1244
+ if (component.cardSubtitle) {
1245
+ var sub = createElement('div', { className: 'e-card-sub-title' });
1246
+ sub.textContent = component.cardSubtitle;
1247
+ caption.appendChild(sub);
1248
+ }
1249
+ header.appendChild(caption);
1250
+ fieldset.appendChild(header);
1251
+ var content_2 = createElement('div', { className: 'e-card-content card-content' });
1252
+ (component.children || []).forEach(function (child) {
1253
+ var rendered = _this.renderComponent(child);
1254
+ if (rendered) {
1255
+ content_2.appendChild(rendered);
1256
+ }
1257
+ });
1258
+ fieldset.appendChild(content_2);
1259
+ return fieldset;
1260
+ }
1261
+ case 'staticHtml': {
1262
+ var renderer = new StaticHtmlRenderer({
1263
+ content: component.defaultValue || '<p>HTML content</p>',
1264
+ id: component.id,
1265
+ enableHtmlSanitizer: component.enableHtmlSanitizer
1266
+ });
1267
+ var el = renderer.render();
1268
+ this.renderedInstances.push(renderer);
1269
+ return el;
1270
+ }
1271
+ case 'message': {
1272
+ var wrapper = createElement('div', { className: 'form-group' });
1273
+ var target = createElement('div');
1274
+ target.id = component.name;
1275
+ target.setAttribute('name', component.id);
1276
+ wrapper.appendChild(target);
1277
+ var instance = renderFormField({
1278
+ component: component,
1279
+ locale: this.locale,
1280
+ value: undefined,
1281
+ onChange: function () { },
1282
+ enableRtl: this.enableRtl,
1283
+ target: target,
1284
+ ref: function (el, idx) {
1285
+ if (idx !== undefined) {
1286
+ _this.inputRefs[component.name + "_" + idx] = el;
1287
+ }
1288
+ else {
1289
+ _this.inputRefs[component.name] = el;
1290
+ }
1291
+ },
1292
+ });
1293
+ if (Array.isArray(instance)) {
1294
+ instance.forEach(function (entry) {
1295
+ if (entry) {
1296
+ _this.renderedInstances.push(entry);
1297
+ }
1298
+ });
1299
+ }
1300
+ else if (instance) {
1301
+ this.renderedInstances.push(instance);
1302
+ }
1303
+ return wrapper;
1304
+ }
1305
+ case 'button': {
1306
+ var buttonlDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
1307
+ var buttonComputed = !!component.disabled || buttonlDisabled;
1308
+ var wrapper = createElement('div', { className: 'form-group' });
1309
+ var target = createElement('div');
1310
+ target.id = component.name;
1311
+ target.setAttribute('name', component.id);
1312
+ wrapper.appendChild(target);
1313
+ var handleButtonClick = function (event) {
1314
+ if (_this.buttonClick) {
1315
+ var label = component.buttonsGroups
1316
+ ? (event.target && event.target.ej2_instances ? event.target.ej2_instances[0].content : '')
1317
+ : component.label || '';
1318
+ _this.trigger('buttonClick', { fieldName: component.name, label: label, event: event });
1319
+ }
1320
+ var button = event.target;
1321
+ if (button.type && button.type === 'reset') {
1322
+ var form = button.closest('form');
1323
+ if (form) {
1324
+ form.querySelectorAll('input[type="checkbox"]').forEach(function (cb) {
1325
+ (cb.ej2_instances[0]).checked = false;
1326
+ });
1327
+ }
1328
+ _this.formState.values = {};
1329
+ form.reset();
1330
+ _this.rerenderForm();
1331
+ _this.validator.destroy();
1332
+ }
1333
+ };
1334
+ var instance = renderFormField({
1335
+ component: __assign({}, component, { disabled: buttonComputed }),
1336
+ value: undefined,
1337
+ onChange: function () { },
1338
+ locale: this.locale,
1339
+ onClick: handleButtonClick,
1340
+ ref: function (el, idx) {
1341
+ if (idx !== undefined) {
1342
+ _this.inputRefs[component.name + "_" + idx] = el;
1343
+ }
1344
+ else {
1345
+ _this.inputRefs[component.name] = el;
1346
+ }
1347
+ },
1348
+ enableRtl: this.enableRtl,
1349
+ target: target
1350
+ });
1351
+ if (Array.isArray(instance)) {
1352
+ instance.forEach(function (entry) {
1353
+ if (entry) {
1354
+ _this.renderedInstances.push(entry);
1355
+ }
1356
+ });
1357
+ }
1358
+ else if (instance) {
1359
+ this.renderedInstances.push(instance);
1360
+ }
1361
+ return wrapper;
1362
+ }
1363
+ case 'splitButton': {
1364
+ var splitButtonDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
1365
+ var computedDisabled = !!component.disabled || splitButtonDisabled;
1366
+ var wrapper = createElement('div', { className: 'form-group' });
1367
+ var target = createElement('div');
1368
+ target.id = component.name;
1369
+ target.setAttribute('name', component.id);
1370
+ wrapper.appendChild(target);
1371
+ var handleSplitButtonEvent = function (event) {
1372
+ if (_this.buttonClick) {
1373
+ _this.trigger('buttonClick', { fieldName: component.name, label: component.label || '', event: event });
1374
+ }
1375
+ };
1376
+ var instance = renderFormField({
1377
+ component: __assign({}, component, { disabled: computedDisabled }),
1378
+ value: undefined,
1379
+ locale: this.locale,
1380
+ onChange: function () { },
1381
+ onClick: handleSplitButtonEvent,
1382
+ ref: function (el) { if (el) {
1383
+ _this.inputRefs[component.name] = el;
1384
+ } },
1385
+ enableRtl: this.enableRtl,
1386
+ target: target
1387
+ });
1388
+ if (Array.isArray(instance)) {
1389
+ instance.forEach(function (entry) {
1390
+ if (entry) {
1391
+ _this.renderedInstances.push(entry);
1392
+ }
1393
+ });
1394
+ }
1395
+ else if (instance) {
1396
+ this.renderedInstances.push(instance);
1397
+ }
1398
+ return wrapper;
1399
+ }
1400
+ default:
1401
+ return this.renderField(component);
1402
+ }
1403
+ };
1404
+ /**
1405
+ * @private
1406
+ */
1407
+ FormRenderer.prototype.afterValueChange = function (changedFieldId) {
1408
+ if (!this.formState) {
1409
+ return;
1410
+ }
1411
+ this.currentFormValues = __assign({}, this.formState.values);
1412
+ this.evaluateExpressions();
1413
+ this.retriggerCustomValidation();
1414
+ this.beforeValidate(changedFieldId);
1415
+ this.validator.validate(changedFieldId);
1416
+ this.syncFormStateErrors();
1417
+ // Only schedule a full-form re-render when the changed field is a
1418
+ // conditional trigger (i.e. some other field's visibility/disabled/
1419
+ // required/readOnly/valueWhen references its id). Changes to fields
1420
+ // that nothing depends on skip the expensive DOM teardown + rebuild,
1421
+ // keeping keystroke latency low for non-conditional inputs.
1422
+ if (changedFieldId && this.isConditionalTrigger(changedFieldId)) {
1423
+ this.scheduleRerender(changedFieldId);
1424
+ }
1425
+ };
1426
+ /**
1427
+ * @private
1428
+ */
1429
+ FormRenderer.prototype.beforeValidate = function (fieldId) {
1430
+ var infoElement = this.element.querySelector("#" + fieldId + "-info");
1431
+ if (infoElement && infoElement.classList.contains('e-error')) {
1432
+ infoElement.classList.remove('e-error');
1433
+ }
1434
+ var inputElement = this.getInputElementByName(fieldId);
1435
+ var inputParent = inputElement.parentElement;
1436
+ var grandParent = inputParent.parentElement;
1437
+ if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
1438
+ (inputElement.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
1439
+ inputParent.classList.remove('e-error');
1440
+ }
1441
+ else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') || grandParent.classList.contains('e-wrapper'))) {
1442
+ grandParent.classList.remove('e-error');
1443
+ }
1444
+ else {
1445
+ inputElement.classList.remove('e-error');
1446
+ }
1447
+ if (this.validator) {
1448
+ this.validator.errorRules = [];
1449
+ }
1450
+ };
1451
+ FormRenderer.prototype.scheduleRerender = function (changedFieldId) {
1452
+ var _this = this;
1453
+ if (changedFieldId) {
1454
+ this.pendingChangedFieldIds.add(changedFieldId);
1455
+ }
1456
+ if (this.rerenderScheduled) {
1457
+ return;
1458
+ }
1459
+ this.rerenderScheduled = true;
1460
+ Promise.resolve().then(function () {
1461
+ _this.rerenderScheduled = false;
1462
+ var changedIds = new Set(_this.pendingChangedFieldIds);
1463
+ _this.pendingChangedFieldIds.clear();
1464
+ _this.rerenderForm(changedIds);
1465
+ });
1466
+ };
1467
+ /**
1468
+ * @private
1469
+ *
1470
+ * Recursively walk a `ConditionType` (a `ConditionalRule { field }` leaf
1471
+ * or a `CompositeConditionalRule { rules: [...] }` tree) and collect the
1472
+ * `field` ids of every leaf rule into the supplied `acc` set. These are
1473
+ * the trigger ids whose value changes can affect the visibility/disabled/
1474
+ * required/readOnly/valueWhen of the component that owns this `conditions`.
1475
+ */
1476
+ FormRenderer.prototype.collectConditionFieldIds = function (condition, acc) {
1477
+ if (!condition) {
1478
+ return;
1479
+ }
1480
+ if (typeof condition.field === 'string') {
1481
+ // Leaf rule.
1482
+ acc.add(condition.field);
1483
+ }
1484
+ else if (Array.isArray(condition.rules)) {
1485
+ // Composite (and/or) — recurse.
1486
+ for (var _i = 0, _a = condition.rules; _i < _a.length; _i++) {
1487
+ var sub = _a[_i];
1488
+ this.collectConditionFieldIds(sub, acc);
1489
+ }
1490
+ }
1491
+ };
1492
+ FormRenderer.prototype.collectDataSourceReferenceIds = function (value, allComps, target) {
1493
+ if (typeof value !== 'string') {
1494
+ return;
1495
+ }
1496
+ var matches = value.match(/\{([^}]+)\}/g);
1497
+ if (!matches) {
1498
+ return;
1499
+ }
1500
+ var _loop_2 = function (match) {
1501
+ var componentName = match.slice(1, -1);
1502
+ var referencedComp = allComps.find(function (c) { return c.name === componentName; });
1503
+ if (referencedComp && referencedComp.id) {
1504
+ target.add(referencedComp.id);
1505
+ }
1506
+ };
1507
+ for (var _i = 0, matches_1 = matches; _i < matches_1.length; _i++) {
1508
+ var match = matches_1[_i];
1509
+ _loop_2(match);
1510
+ }
1511
+ };
1512
+ /**
1513
+ * @private
1514
+ *
1515
+ * Build `this.conditionalTriggerFieldIds` — the set of every
1516
+ * `component.id` that is referenced by *any* other component's
1517
+ * `conditions` (visibleWhen / hideWhen / disabledWhen / requiredWhen /
1518
+ * readOnlyWhen / setValueWhen / choiceBasedField.primaryFieldId).
1519
+ * Only changes to ids in this set can affect another field's
1520
+ * visibility/enabled/required/value, so only they need to trigger a
1521
+ * full-form re-render. Called once per schema during `render()`.
1522
+ */
1523
+ FormRenderer.prototype.buildConditionalDependencyMap = function () {
1524
+ var triggers = new Set();
1525
+ // Per-consumer dependency set (rebuilt each pass).
1526
+ var consumerDeps = new Map();
1527
+ var allComps = this.collectAllComponents(this.processedSchemaCache.components);
1528
+ for (var _i = 0, allComps_1 = allComps; _i < allComps_1.length; _i++) {
1529
+ var comp = allComps_1[_i];
1530
+ var myDeps = new Set();
1531
+ consumerDeps.set(comp.id, myDeps);
1532
+ var conditions = comp.conditions;
1533
+ if (conditions) {
1534
+ var conditionKeys = [
1535
+ 'visibleWhen',
1536
+ 'hideWhen',
1537
+ 'disabledWhen',
1538
+ 'requiredWhen',
1539
+ 'readOnlyWhen',
1540
+ 'choiceBasedField',
1541
+ 'conditionalData'
1542
+ ];
1543
+ for (var _a = 0, conditionKeys_1 = conditionKeys; _a < conditionKeys_1.length; _a++) {
1544
+ var key = conditionKeys_1[_a];
1545
+ if (conditions[key]) {
1546
+ this.collectConditionFieldIds(conditions[key], triggers);
1547
+ this.collectConditionFieldIds(conditions[key], myDeps);
1548
+ }
1549
+ }
1550
+ if (Array.isArray(conditions.conditionalData)) {
1551
+ for (var _b = 0, _c = conditions.conditionalData; _b < _c.length; _b++) {
1552
+ var item = _c[_b];
1553
+ if (item && item.condition) {
1554
+ this.collectConditionFieldIds(item.condition, triggers);
1555
+ this.collectConditionFieldIds(item.condition, myDeps);
1556
+ }
1557
+ // DataGrid conditional columns
1558
+ if (item && Array.isArray(item.conditions)) {
1559
+ for (var _d = 0, _e = item.conditions; _d < _e.length; _d++) {
1560
+ var subCond = _e[_d];
1561
+ this.collectConditionFieldIds(subCond, triggers);
1562
+ this.collectConditionFieldIds(subCond, myDeps);
1563
+ }
1564
+ }
1565
+ }
1566
+ }
1567
+ if (conditions.setValueWhen &&
1568
+ conditions.setValueWhen.condition) {
1569
+ this.collectConditionFieldIds(conditions.setValueWhen.condition, triggers);
1570
+ this.collectConditionFieldIds(conditions.setValueWhen.condition, myDeps);
1571
+ }
1572
+ if (conditions.choiceBasedField &&
1573
+ typeof conditions.choiceBasedField.primaryFieldId === 'string') {
1574
+ triggers.add(conditions.choiceBasedField.primaryFieldId);
1575
+ myDeps.add(conditions.choiceBasedField.primaryFieldId);
1576
+ }
1577
+ }
1578
+ // ==========================================================
1579
+ // DataGrid remote datasource dependencies
1580
+ // Example:
1581
+ // search.key = "{combobox}"
1582
+ // filter.value = "{department}"
1583
+ // Resolve component by NAME and add its ID as dependency.
1584
+ // ==========================================================
1585
+ var ds = comp.dataSource;
1586
+ if ((comp.type === 'dataGrid') &&
1587
+ ds &&
1588
+ ds.type === 'url') {
1589
+ if (ds.search && typeof ds.search.key === 'string') {
1590
+ this.collectDataSourceReferenceIds(ds.search.key, allComps, triggers);
1591
+ this.collectDataSourceReferenceIds(ds.search.key, allComps, myDeps);
1592
+ }
1593
+ if (Array.isArray(ds.filters)) {
1594
+ for (var _f = 0, _g = ds.filters; _f < _g.length; _f++) {
1595
+ var filter = _g[_f];
1596
+ if (typeof filter.value === 'string') {
1597
+ this.collectDataSourceReferenceIds(filter.value, allComps, triggers);
1598
+ this.collectDataSourceReferenceIds(filter.value, allComps, myDeps);
1599
+ }
1600
+ }
1601
+ }
1602
+ }
1603
+ }
1604
+ this.conditionalTriggerFieldIds = triggers;
1605
+ this.consumerDependencyMap = consumerDeps;
1606
+ };
1607
+ /**
1608
+ * @private
1609
+ *
1610
+ * Returns `true` if a value change to `fieldId` can affect any other
1611
+ * field's conditional state (visibility/disabled/required/readOnly/
1612
+ * valueWhen/choiceBasedField) — i.e. `fieldId` is in the
1613
+ * `conditionalTriggerFieldIds` set built by
1614
+ * `buildConditionalDependencyMap`. Used by `afterValueChange` to skip
1615
+ * the expensive full-form re-render when the changed field is not a
1616
+ * conditional trigger.
1617
+ */
1618
+ FormRenderer.prototype.isConditionalTrigger = function (fieldId) {
1619
+ return this.conditionalTriggerFieldIds.has(fieldId);
1620
+ };
1621
+ /**
1622
+ * @private
1623
+ *
1624
+ * Tear down the rendered tree and re-render it, preserving user-entered
1625
+ * `formState.values` (carried through `buildValidationRulesAndBridge`'s
1626
+ * `previousValues` merge) and restoring keyboard focus to the field that
1627
+ * had it before re-render (so a user typing in a textbox is not
1628
+ * interrupted by a dependent field appearing/disappearing on the page).
1629
+ */
1630
+ FormRenderer.prototype.rerenderForm = function (changedFieldIds) {
1631
+ var _this = this;
1632
+ var changedIds = changedFieldIds || new Set();
1633
+ var activeEl = document.activeElement;
1634
+ var focusedName = activeEl && activeEl.getAttribute
1635
+ ? activeEl.getAttribute('name')
1636
+ : null;
1637
+ var selectionStart = null;
1638
+ var selectionEnd = null;
1639
+ if (focusedName && activeEl && activeEl.selectionStart !== undefined) {
1640
+ try {
1641
+ selectionStart = activeEl.selectionStart;
1642
+ selectionEnd = activeEl.selectionEnd;
1643
+ }
1644
+ catch (e) { /* not a text input — ignore */ }
1645
+ }
1646
+ var savedElementScrollTop = this.element.scrollTop;
1647
+ var savedElementScrollLeft = this.element.scrollLeft;
1648
+ var savedWindowScrollX = window.scrollX;
1649
+ var savedWindowScrollY = window.scrollY;
1650
+ this.preservedFields.clear();
1651
+ var allComps = this.collectAllComponents(this.processedSchemaCache.components);
1652
+ var _loop_3 = function (comp) {
1653
+ if (!FormRenderer_1.PRESERVABLE_TYPES.has(comp.type)) {
1654
+ return "continue";
1655
+ }
1656
+ var myDeps = this_1.consumerDependencyMap.get(comp.id);
1657
+ var dependsOnChanged = false;
1658
+ if (myDeps) {
1659
+ changedIds.forEach(function (changedId) {
1660
+ if (myDeps.has(changedId)) {
1661
+ dependsOnChanged = true;
1662
+ }
1663
+ });
1664
+ }
1665
+ if (dependsOnChanged) {
1666
+ return "continue";
1667
+ }
1668
+ var liveNode = this_1.element.querySelector("[data-field-id=\"" + comp.id + "\"]");
1669
+ if (liveNode && liveNode.parentElement) {
1670
+ liveNode.parentElement.removeChild(liveNode);
1671
+ this_1.preservedFields.set(comp.id, liveNode);
1672
+ }
1673
+ };
1674
+ var this_1 = this;
1675
+ for (var _i = 0, allComps_2 = allComps; _i < allComps_2.length; _i++) {
1676
+ var comp = allComps_2[_i];
1677
+ _loop_3(comp);
1678
+ }
1679
+ this.refreshing = true;
1680
+ this.destroyRenderedExcludingPreserved();
1681
+ this.removePreviousRoot();
1682
+ if (this.validator) {
1683
+ this.validator.destroy();
1684
+ }
1685
+ this.render();
1686
+ this.refreshing = false;
1687
+ try {
1688
+ this.element.scrollTop = savedElementScrollTop;
1689
+ this.element.scrollLeft = savedElementScrollLeft;
1690
+ window.scrollTo(savedWindowScrollX, savedWindowScrollY);
1691
+ }
1692
+ catch (e) { /* swallow */ }
1693
+ if (focusedName) {
1694
+ var elToFocus = this.getInputElementByName(focusedName);
1695
+ if (elToFocus && typeof elToFocus.focus === 'function') {
1696
+ try {
1697
+ elToFocus.focus();
1698
+ if (selectionStart !== null && selectionEnd !== null &&
1699
+ typeof elToFocus.setSelectionRange === 'function') {
1700
+ try {
1701
+ elToFocus.setSelectionRange(selectionStart, selectionEnd);
1702
+ }
1703
+ catch (e) { /* swallow — non-text input */ }
1704
+ }
1705
+ }
1706
+ catch (e) { /* swallow */ }
1707
+ }
1708
+ }
1709
+ // Drop preserved subtrees that were not re-attached (e.g. their
1710
+ // field became hidden during this re-render). Their EJ2 instances
1711
+ // are still in `renderedInstances`; destroy them now to avoid leaks.
1712
+ if (this.preservedFields.size > 0) {
1713
+ var stillKept_1 = [];
1714
+ this.preservedFields.forEach(function (node, id) {
1715
+ // If the node is no longer in the live document tree, the
1716
+ // field was not re-attached (hidden / removed). Destroy it
1717
+ // and remove the detached DOM node so it cannot be re-used.
1718
+ if (!_this.element.contains(node) && !document.body.contains(node)) {
1719
+ _this.destroyPreservedSubtree(node);
1720
+ try {
1721
+ if (node.parentNode) {
1722
+ node.parentNode.removeChild(node);
1723
+ }
1724
+ }
1725
+ catch (e) {
1726
+ // swallow
1727
+ }
1728
+ _this.preservedFields.delete(id);
1729
+ }
1730
+ else {
1731
+ stillKept_1.push(id);
1732
+ }
1733
+ });
1734
+ stillKept_1.forEach(function (id) { return _this.preservedFields.delete(id); });
1735
+ }
1736
+ };
1737
+ /**
1738
+ * @private
1739
+ */
1740
+ FormRenderer.prototype.removePreviousRoot = function () {
1741
+ if (this.element) {
1742
+ while (this.element.childNodes.length > 0) {
1743
+ this.element.removeChild(this.element.firstChild);
1744
+ }
1745
+ }
1746
+ };
1747
+ /**
1748
+ * @private
1749
+ */
1750
+ FormRenderer.prototype.destroyRenderedInstance = function (inst) {
1751
+ if (!inst || typeof inst.destroy !== 'function') {
1752
+ return;
1753
+ }
1754
+ var state = inst;
1755
+ if (state.isDestroyed || state.destroyed || state.disposed) {
1756
+ return;
1757
+ }
1758
+ var hostElement = inst.element || inst.target || (inst.hostElement && typeof inst.hostElement === 'function' ? inst.hostElement() : undefined);
1759
+ try {
1760
+ state.isDestroyed = true;
1761
+ state.destroyed = true;
1762
+ state.disposed = true;
1763
+ inst.destroy();
1764
+ }
1765
+ catch (e) {
1766
+ console.warn('FormRenderer: failed to destroy child instance.', e);
1767
+ }
1768
+ finally {
1769
+ if (hostElement && hostElement.parentNode) {
1770
+ try {
1771
+ hostElement.parentNode.removeChild(hostElement);
1772
+ }
1773
+ catch (e) {
1774
+ }
1775
+ }
1776
+ }
1777
+ };
1778
+ /**
1779
+ * @private
1780
+ *
1781
+ * Destroy all rendered EJ2 instances except those whose host element
1782
+ * lives inside a preserved subtree (those are kept alive for re-use in
1783
+ * the upcoming `render()` pass). Mirrors `destroyRendered` but skips
1784
+ * instances rooted in `preservedFields` nodes.
1785
+ */
1786
+ FormRenderer.prototype.destroyRenderedExcludingPreserved = function () {
1787
+ var survived = [];
1788
+ var preservedNodes = Array.from(this.preservedFields.values());
1789
+ var _loop_4 = function (inst) {
1790
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1791
+ var isPreserved = !!hostEl && preservedNodes.some(function (n) { return n === hostEl || n.contains(hostEl); });
1792
+ if (isPreserved) {
1793
+ survived.push(inst);
1794
+ }
1795
+ else {
1796
+ this_2.destroyRenderedInstance(inst);
1797
+ }
1798
+ };
1799
+ var this_2 = this;
1800
+ for (var _i = 0, _a = this.renderedInstances; _i < _a.length; _i++) {
1801
+ var inst = _a[_i];
1802
+ _loop_4(inst);
1803
+ }
1804
+ this.renderedInstances = survived;
1805
+ // Prune inputRefs whose host element lives in a destroyed subtree
1806
+ // (preserved ones stay).
1807
+ var inputRefKeys = Object.keys(this.inputRefs);
1808
+ var _loop_5 = function (key) {
1809
+ var inst = this_3.inputRefs[key];
1810
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1811
+ var isPreserved = !!hostEl && preservedNodes.some(function (n) { return n === hostEl || n.contains(hostEl); });
1812
+ if (!isPreserved) {
1813
+ delete this_3.inputRefs[key];
1814
+ }
1815
+ };
1816
+ var this_3 = this;
1817
+ for (var _b = 0, inputRefKeys_1 = inputRefKeys; _b < inputRefKeys_1.length; _b++) {
1818
+ var key = inputRefKeys_1[_b];
1819
+ _loop_5(key);
1820
+ }
1821
+ this.conditionalValueApplied = {};
1822
+ this.expressionDependencyGraph = {};
1823
+ this.computedFieldNames = new Set();
1824
+ this.previousFormValues = {};
1825
+ this.conditionalTriggerFieldIds = new Set();
1826
+ };
1827
+ /**
1828
+ * @private
1829
+ *
1830
+ * Destroy EJ2 instances whose host element lives inside a preserved
1831
+ * subtree that was NOT re-attached (field became hidden). Used during
1832
+ * the post-render cleanup pass in `rerenderForm`.
1833
+ */
1834
+ FormRenderer.prototype.destroyPreservedSubtree = function (rootNode) {
1835
+ var survived = [];
1836
+ for (var _i = 0, _a = this.renderedInstances; _i < _a.length; _i++) {
1837
+ var inst = _a[_i];
1838
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1839
+ if (hostEl && (hostEl === rootNode || rootNode.contains(hostEl))) {
1840
+ this.destroyRenderedInstance(inst);
1841
+ }
1842
+ else {
1843
+ survived.push(inst);
1844
+ }
1845
+ }
1846
+ this.renderedInstances = survived;
1847
+ };
1848
+ FormRenderer.prototype.getInputElementByName = function (name) {
1849
+ var inputEl = this.element.querySelector("[name=\"" + name + "\"]");
1850
+ if (!inputEl) {
1851
+ return null;
1852
+ }
1853
+ if (!inputEl.classList.contains('e-control')) {
1854
+ var eControl = inputEl.parentElement ? inputEl.parentElement.querySelector('.e-control') : null;
1855
+ if (eControl) {
1856
+ return eControl;
1857
+ }
1858
+ }
1859
+ return inputEl;
1860
+ };
1861
+ /**
1862
+ * Evaluate expressions in topological order with type coercion.
1863
+ * @private
1864
+ */
1865
+ FormRenderer.prototype.evaluateExpressions = function () {
1866
+ if (!this.formState || !this.expressionEngine) {
1867
+ return;
1868
+ }
1869
+ if (this.expressionEvaluationInProgress) {
1870
+ return;
1871
+ }
1872
+ try {
1873
+ this.expressionEvaluationInProgress = true;
1874
+ var engine = this.expressionEngine;
1875
+ var dependencyGraph = this.expressionDependencyGraph;
1876
+ var formValues = this.formState.values || {};
1877
+ var allComponents = this.collectAllComponents(this.processedSchemaCache.components);
1878
+ var previousValues = this.previousFormValues;
1879
+ var computedFieldNames = this.computedFieldNames;
1880
+ var idToNameMap_1 = {};
1881
+ allComponents.forEach(function (comp) {
1882
+ if (comp.name) {
1883
+ idToNameMap_1[comp.id] = comp.name;
1884
+ }
1885
+ });
1886
+ var contextValues = {};
1887
+ var fvKeys = Object.keys(formValues);
1888
+ for (var _i = 0, fvKeys_1 = fvKeys; _i < fvKeys_1.length; _i++) {
1889
+ var componentId = fvKeys_1[_i];
1890
+ var value = formValues[componentId];
1891
+ var fieldName = idToNameMap_1[componentId];
1892
+ if (fieldName) {
1893
+ contextValues[fieldName] = value;
1894
+ }
1895
+ }
1896
+ var previousContextValues = __assign({}, previousValues);
1897
+ Object.assign(previousValues, contextValues);
1898
+ var changedFields = new Set();
1899
+ var ctxKeys = Object.keys(contextValues);
1900
+ var _loop_6 = function (fieldName) {
1901
+ var fieldId = Object.keys(idToNameMap_1).find(function (id) { return idToNameMap_1[id] === fieldName; });
1902
+ if (fieldId && contextValues[fieldName] !== previousContextValues[fieldName] && !computedFieldNames.has(fieldId)) {
1903
+ changedFields.add(fieldName);
1904
+ }
1905
+ };
1906
+ for (var _a = 0, ctxKeys_1 = ctxKeys; _a < ctxKeys_1.length; _a++) {
1907
+ var fieldName = ctxKeys_1[_a];
1908
+ _loop_6(fieldName);
1909
+ }
1910
+ if (changedFields.size === 0) {
1911
+ return;
1912
+ }
1913
+ var evaluationOrder = engine.getTopologicalOrder(dependencyGraph);
1914
+ var _loop_7 = function (fieldName) {
1915
+ var component = allComponents.find(function (c) { return c.name === fieldName; });
1916
+ if (component && component.expressionValue) {
1917
+ computedFieldNames.add(component.id);
1918
+ try {
1919
+ var isVisible = component.visible !== false
1920
+ ? ConditionalRuleEngine.isFieldVisible(component.conditions, formValues)
1921
+ : false;
1922
+ if (isVisible) {
1923
+ var currentValues = {};
1924
+ var fvKeys2 = Object.keys(formValues);
1925
+ for (var _i = 0, fvKeys2_1 = fvKeys2; _i < fvKeys2_1.length; _i++) {
1926
+ var componentId = fvKeys2_1[_i];
1927
+ var value = formValues[componentId];
1928
+ var fn = idToNameMap_1[componentId];
1929
+ if (fn) {
1930
+ currentValues[fn] = value;
1931
+ }
1932
+ }
1933
+ var result = engine.evaluate(component.expressionValue, currentValues);
1934
+ result = (typeof result === 'string' && result.indexOf('undefined') !== -1)
1935
+ ? result.replace(/undefined/g, '')
1936
+ : result;
1937
+ if (result !== null && result !== undefined && result !== '') {
1938
+ switch (component.type) {
1939
+ case 'number': {
1940
+ var numResult = Number(result);
1941
+ result = isNaN(numResult) ? 0 : numResult;
1942
+ break;
1943
+ }
1944
+ case 'checkbox':
1945
+ case 'switch':
1946
+ result = Boolean(result);
1947
+ break;
1948
+ case 'textbox':
1949
+ case 'textarea':
1950
+ result = String(result);
1951
+ break;
1952
+ case 'dateRange':
1953
+ case 'checkboxGroup':
1954
+ case 'multiselect':
1955
+ break;
1956
+ default:
1957
+ result = String(result);
1958
+ break;
1959
+ }
1960
+ }
1961
+ if (result !== null && result !== undefined && result !== formValues[component.id] && this_4.formState) {
1962
+ this_4.formState.values[component.id] = result;
1963
+ // Sync the underlying input element so the
1964
+ // FormValidator reads the new value on its
1965
+ // next validate() pass.
1966
+ if (this_4.validator) {
1967
+ var inputEl = this_4.getInputElementByName(component.id);
1968
+ if (inputEl) {
1969
+ try {
1970
+ if (inputEl.ej2_instances[0]) {
1971
+ inputEl.ej2_instances[0].value = result;
1972
+ // (inputEl as any).ej2_instances[0].refresh();
1973
+ }
1974
+ else {
1975
+ (inputEl).value = String(result);
1976
+ }
1977
+ }
1978
+ catch (e) { /* swallow */ }
1979
+ }
1980
+ }
1981
+ }
1982
+ }
1983
+ }
1984
+ catch (error) {
1985
+ if (this_4.failure) {
1986
+ this_4.trigger('failure', {
1987
+ error: error
1988
+ });
1989
+ }
1990
+ }
1991
+ }
1992
+ };
1993
+ var this_4 = this;
1994
+ for (var _b = 0, evaluationOrder_1 = evaluationOrder; _b < evaluationOrder_1.length; _b++) {
1995
+ var fieldName = evaluationOrder_1[_b];
1996
+ _loop_7(fieldName);
1997
+ }
1998
+ Object.assign(previousValues, contextValues);
1999
+ }
2000
+ finally {
2001
+ this.expressionEvaluationInProgress = false;
2002
+ }
2003
+ };
2004
+ /**
2005
+ * Re-trigger custom validation for changed + dependent fields.
2006
+ * @private
2007
+ */
2008
+ FormRenderer.prototype.retriggerCustomValidation = function () {
2009
+ var _this = this;
2010
+ if (!this.formState) {
2011
+ return;
2012
+ }
2013
+ if (!this.customValidationEngine) {
2014
+ return;
2015
+ }
2016
+ try {
2017
+ var allComponents_1 = this.collectAllComponents(this.processedSchemaCache.components);
2018
+ var formValues_1 = this.formState.values || {};
2019
+ var previousValues_1 = this.previousFormValues;
2020
+ var changedFields_1 = new Set();
2021
+ Object.keys(formValues_1).forEach(function (fieldId) {
2022
+ if (formValues_1[fieldId] !== previousValues_1[fieldId]) {
2023
+ changedFields_1.add(fieldId);
2024
+ }
2025
+ });
2026
+ if (changedFields_1.size === 0) {
2027
+ return;
2028
+ }
2029
+ var fieldsToValidate_1 = new Set();
2030
+ changedFields_1.forEach(function (fieldId) {
2031
+ var component = allComponents_1.find(function (c) { return c.id === fieldId; });
2032
+ if (component && component.customValidation && Array.isArray(component.customValidation)) {
2033
+ fieldsToValidate_1.add(fieldId);
2034
+ }
2035
+ });
2036
+ allComponents_1.forEach(function (component) {
2037
+ if (component.customValidation && Array.isArray(component.customValidation)) {
2038
+ component.customValidation.forEach(function (rule) {
2039
+ var deps = _this.customValidationEngine.extractDependencies(rule.expression);
2040
+ deps.forEach(function (dep) {
2041
+ var depComponent = allComponents_1.find(function (c) { return c.id === dep || c.name === dep; });
2042
+ if (depComponent && changedFields_1.has(depComponent.id)) {
2043
+ fieldsToValidate_1.add(component.id);
2044
+ }
2045
+ });
2046
+ });
2047
+ }
2048
+ });
2049
+ this.previousFormValues = __assign({}, formValues_1);
2050
+ }
2051
+ catch (error) {
2052
+ if (this.failure) {
2053
+ this.trigger('failure', {
2054
+ error: error
2055
+ });
2056
+ }
2057
+ }
2058
+ };
2059
+ /**
2060
+ * @private
2061
+ */
2062
+ FormRenderer.prototype.handleSubmitData = function (data) {
2063
+ var formState = this.formState;
2064
+ var isValid = formState && formState.errors ? Object.keys(formState.errors).length === 0 : false;
2065
+ var transformedData = {};
2066
+ var formValues = formState ? formState.values : {};
2067
+ var excludedTypes = new Set(['button', 'message', 'panel', 'table', 'tabs']);
2068
+ var allComps = this.collectAllComponents(this.processedSchemaCache.components || []);
2069
+ var excludedIds = new Set(allComps.filter(function (c) { return excludedTypes.has(c.type); }).map(function (c) { return c.id; }));
2070
+ var hiddenFieldIds = new Set(allComps.filter(function (c) {
2071
+ if (c.visible === false) {
2072
+ return true;
2073
+ }
2074
+ if (c.conditions && c.conditions.visibleWhen) {
2075
+ if (!ConditionalRuleEngine.isFieldVisible(c.conditions, formValues)) {
2076
+ return true;
2077
+ }
2078
+ }
2079
+ if (c.conditions && c.conditions.hideWhen) {
2080
+ if (ConditionalRuleEngine.isFieldHidden(c.conditions, formValues)) {
2081
+ return true;
2082
+ }
2083
+ }
2084
+ return false;
2085
+ }).map(function (c) { return c.id; }));
2086
+ var disabledFieldIds = new Set(allComps.filter(function (c) {
2087
+ if (c.disabled) {
2088
+ return true;
2089
+ }
2090
+ if (c.conditions && c.conditions.disabledWhen) {
2091
+ return ConditionalRuleEngine.isFieldDisabled(c.conditions, formValues);
2092
+ }
2093
+ return false;
2094
+ }).map(function (c) { return c.id; }));
2095
+ var dataKeys = Object.keys(data);
2096
+ for (var _i = 0, dataKeys_1 = dataKeys; _i < dataKeys_1.length; _i++) {
2097
+ var id = dataKeys_1[_i];
2098
+ var val = data[id];
2099
+ if (excludedIds.has(id) || hiddenFieldIds.has(id) || disabledFieldIds.has(id)) {
2100
+ return;
2101
+ }
2102
+ var label = this.idToLabelCache[id] || id;
2103
+ transformedData[label] = val;
2104
+ }
2105
+ if (this.submit) {
2106
+ this.trigger('submit', { data: transformedData, isValid: isValid });
2107
+ }
2108
+ };
2109
+ /**
2110
+ * Retrieves the underlying Syncfusion form-input component instance by its field name. Use this to call Syncfusion component methods and properties.
2111
+ */
2112
+ FormRenderer.prototype.getComponent = function (name) {
2113
+ return this.inputRefs[name] || null;
2114
+ };
2115
+ /**
2116
+ * Re-normalize + re-render on `schema`/`locale`/`enableRtl` change.
2117
+ * @private
2118
+ */
2119
+ FormRenderer.prototype.onPropertyChanged = function (newProps, oldProps) {
2120
+ var reRender = false;
2121
+ if (newProps.schema !== oldProps.schema) {
2122
+ reRender = true;
2123
+ }
2124
+ if (newProps.locale !== oldProps.locale) {
2125
+ reRender = true;
2126
+ }
2127
+ if (newProps.enableRtl !== oldProps.enableRtl) {
2128
+ reRender = true;
2129
+ }
2130
+ if (newProps.layout !== oldProps.layout) {
2131
+ reRender = true;
2132
+ }
2133
+ if (newProps.locale !== oldProps.locale) {
2134
+ reRender = true;
2135
+ }
2136
+ if (!reRender) {
2137
+ return;
2138
+ }
2139
+ // Tear down rendered children and re-render.
2140
+ this.refreshing = true;
2141
+ this.destroyRendered();
2142
+ this.removePreviousRoot();
2143
+ this.isInitialized = false;
2144
+ this.render();
2145
+ this.refreshing = false;
2146
+ };
2147
+ /**
2148
+ * Destroy all child EJ2 instances, detach listeners, null refs.
2149
+ * @private
2150
+ */
2151
+ FormRenderer.prototype.destroyRendered = function () {
2152
+ var _this = this;
2153
+ if (this.validator) {
2154
+ try {
2155
+ this.validator.destroy();
2156
+ }
2157
+ catch (e) {
2158
+ this.trigger('failure', {
2159
+ error: e
2160
+ });
2161
+ }
2162
+ this.validator = null;
2163
+ }
2164
+ this.renderedInstances.forEach(function (inst) {
2165
+ _this.destroyRenderedInstance(inst);
2166
+ });
2167
+ this.renderedInstances = [];
2168
+ this.removePreviousRoot();
2169
+ this.inputRefs = {};
2170
+ this.tooltipRefs = {};
2171
+ this.conditionalValueApplied = {};
2172
+ this.expressionDependencyGraph = {};
2173
+ this.computedFieldNames = new Set();
2174
+ this.previousFormValues = {};
2175
+ this.conditionalTriggerFieldIds = new Set();
2176
+ this.consumerDependencyMap = new Map();
2177
+ this.preservedFields = new Map();
2178
+ this.pendingChangedFieldIds = new Set();
2179
+ };
2180
+ /**
2181
+ * Remove persisted tab selection state for this form when it is fully destroyed.
2182
+ * @private
2183
+ */
2184
+ FormRenderer.prototype.clearPersistedTabSelections = function () {
2185
+ if (typeof window === 'undefined')
2186
+ return null;
2187
+ try {
2188
+ var components = (this.processedSchemaCache && this.processedSchemaCache.components)
2189
+ ? this.processedSchemaCache.components
2190
+ : [];
2191
+ var allComps = this.collectAllComponents(components);
2192
+ allComps.forEach(function (component) {
2193
+ if (component.type === 'tabs' && component.id) {
2194
+ window.localStorage.removeItem('tab' + component.id);
2195
+ }
2196
+ });
2197
+ }
2198
+ catch (_a) {
2199
+ }
2200
+ };
2201
+ /**
2202
+ * Full component teardown.
2203
+ * @private
2204
+ */
2205
+ FormRenderer.prototype.destroy = function () {
2206
+ this.destroyRendered();
2207
+ this.formState = { values: {}, errors: {} };
2208
+ this.expressionEngine = null;
2209
+ this.customValidationEngine = null;
2210
+ this.clearEngineCaches();
2211
+ this.clearPersistedTabSelections();
2212
+ this.consumerDependencyMap = new Map();
2213
+ this.preservedFields = new Map();
2214
+ this.conditionalTriggerFieldIds = new Set();
2215
+ _super.prototype.destroy.call(this);
2216
+ };
2217
+ /**
2218
+ * @private
2219
+ */
2220
+ FormRenderer.prototype.clearEngineCaches = function () {
2221
+ if (this.expressionEngine) {
2222
+ try {
2223
+ this.expressionEngine.clearCache();
2224
+ }
2225
+ catch (e) { /* swallow */ }
2226
+ }
2227
+ if (this.customValidationEngine) {
2228
+ var inner = this.customValidationEngine.expressionEngine;
2229
+ if (inner && typeof inner.clearCache === 'function') {
2230
+ try {
2231
+ inner.clearCache();
2232
+ }
2233
+ catch (e) { /* swallow */ }
2234
+ }
2235
+ }
2236
+ };
2237
+ var FormRenderer_1;
2238
+ /**
2239
+ * Component types eligible for DOM preservation across re-renders.
2240
+ * These types either bind remote data (dataGrid, lookup-backed
2241
+ * dropdown/multiselect) or render many child options (checkboxGroup)
2242
+ * and are noticeably expensive / flicker-prone to rebuild.
2243
+ */
2244
+ FormRenderer.PRESERVABLE_TYPES = new Set([
2245
+ 'textbox', 'textarea', 'number', 'checkbox', 'checkboxGroup', 'radio', 'dropdown', 'multiselect', 'button', 'date', 'dateTime', 'time', 'dateRange', 'switch', 'signature', 'rating', 'imageEditor', 'fileUpload', 'rangeSlider', 'colorPicker', 'inputMask', 'message', 'panel', 'table', 'tabs', 'dataGrid', 'staticHtml', 'card', 'splitButton', 'richTextEditor'
2246
+ ]);
2247
+ __decorate([
2248
+ Property(null)
2249
+ ], FormRenderer.prototype, "schema", void 0);
2250
+ __decorate([
2251
+ Property('SingleColumn')
2252
+ ], FormRenderer.prototype, "layout", void 0);
2253
+ __decorate([
2254
+ Property('')
2255
+ ], FormRenderer.prototype, "className", void 0);
2256
+ __decorate([
2257
+ Event()
2258
+ ], FormRenderer.prototype, "submit", void 0);
2259
+ __decorate([
2260
+ Event()
2261
+ ], FormRenderer.prototype, "change", void 0);
2262
+ __decorate([
2263
+ Event()
2264
+ ], FormRenderer.prototype, "buttonClick", void 0);
2265
+ __decorate([
2266
+ Event()
2267
+ ], FormRenderer.prototype, "failure", void 0);
2268
+ __decorate([
2269
+ Event()
2270
+ ], FormRenderer.prototype, "created", void 0);
2271
+ FormRenderer = FormRenderer_1 = __decorate([
2272
+ NotifyPropertyChanges
2273
+ ], FormRenderer);
2274
+ return FormRenderer;
2275
+ }(Component));
2276
+ export { FormRenderer };
2277
+ export default FormRenderer;