@form-eng/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4361 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ CheckAsyncFieldValidationRules: () => CheckAsyncFieldValidationRules,
34
+ CheckDefaultValues: () => CheckDefaultValues,
35
+ CheckFieldValidationRules: () => CheckFieldValidationRules,
36
+ CheckValidDropdownOptions: () => CheckValidDropdownOptions,
37
+ ComponentTypes: () => ComponentTypes,
38
+ ConfirmInputsModal: () => ConfirmInputsModal_default,
39
+ ExecuteComputedValue: () => ExecuteComputedValue,
40
+ FIELD_PARENT_PREFIX: () => FIELD_PARENT_PREFIX,
41
+ FieldArray: () => FieldArray,
42
+ FieldWrapper: () => FieldWrapper,
43
+ FormConstants: () => FormConstants,
44
+ FormDevTools: () => FormDevTools,
45
+ FormEngine: () => FormEngine,
46
+ FormErrorBoundary: () => FormErrorBoundary,
47
+ FormFields: () => FormFields,
48
+ FormStrings: () => FormStrings,
49
+ GetChildEntity: () => GetChildEntity,
50
+ GetComputedValuesOnCreate: () => GetComputedValuesOnCreate,
51
+ GetComputedValuesOnDirtyFields: () => GetComputedValuesOnDirtyFields,
52
+ GetConfirmInputModalProps: () => GetConfirmInputModalProps,
53
+ GetFieldsToRender: () => GetFieldsToRender,
54
+ InitOnCreateFormState: () => InitOnCreateFormState,
55
+ InitOnEditFormState: () => InitOnEditFormState,
56
+ InjectedFieldProvider: () => InjectedFieldProvider,
57
+ IsExpandVisible: () => IsExpandVisible,
58
+ RenderField: () => RenderField_default,
59
+ RulesEngineActionType: () => RulesEngineActionType,
60
+ RulesEngineProvider: () => RulesEngineProvider,
61
+ ShowField: () => ShowField,
62
+ SortDropdownOptions: () => SortOptions2,
63
+ SortOptions: () => SortOptions,
64
+ UseInjectedFieldContext: () => UseInjectedFieldContext,
65
+ UseRulesEngineContext: () => UseRulesEngineContext,
66
+ WizardForm: () => WizardForm,
67
+ buildDefaultFieldStates: () => buildDefaultFieldStates,
68
+ buildDependencyGraph: () => buildDependencyGraph,
69
+ clearRuleTraceLog: () => clearRuleTraceLog,
70
+ clearTimeline: () => clearTimeline,
71
+ convertBooleanToYesOrNoText: () => convertBooleanToYesOrNoText,
72
+ createLazyFieldRegistry: () => createLazyFieldRegistry,
73
+ createMaxLengthRule: () => createMaxLengthRule,
74
+ createMinLengthRule: () => createMinLengthRule,
75
+ createNumericRangeRule: () => createNumericRangeRule,
76
+ createOption: () => createOption,
77
+ createPatternRule: () => createPatternRule,
78
+ createRequiredIfRule: () => createRequiredIfRule,
79
+ deepCopy: () => deepCopy,
80
+ defineFormConfig: () => defineFormConfig,
81
+ deserializeFormState: () => deserializeFormState,
82
+ detectDependencyCycles: () => detectDependencyCycles,
83
+ detectSelfDependencies: () => detectSelfDependencies,
84
+ disableRuleTracing: () => disableRuleTracing,
85
+ enableRuleTracing: () => enableRuleTracing,
86
+ evaluateAffectedFields: () => evaluateAffectedFields,
87
+ evaluateAllRules: () => evaluateAllRules,
88
+ evaluateCondition: () => evaluateCondition,
89
+ evaluateExpression: () => evaluateExpression,
90
+ executeValueFunction: () => executeValueFunction,
91
+ extractConditionDependencies: () => extractConditionDependencies,
92
+ extractExpressionDependencies: () => extractExpressionDependencies,
93
+ extractFunctionDependencies: () => extractFunctionDependencies,
94
+ flushRenderCycle: () => flushRenderCycle,
95
+ fromRjsfSchema: () => fromRjsfSchema,
96
+ getCurrentLocale: () => getCurrentLocale,
97
+ getLastRenderedFields: () => getLastRenderedFields,
98
+ getLocaleString: () => getLocaleString,
99
+ getRenderCounts: () => getRenderCounts,
100
+ getRuleTraceLog: () => getRuleTraceLog,
101
+ getStepFieldOrder: () => getStepFieldOrder,
102
+ getStepFields: () => getStepFields,
103
+ getStepIndex: () => getStepIndex,
104
+ getTimeline: () => getTimeline,
105
+ getTotalFormRenders: () => getTotalFormRenders,
106
+ getValidator: () => getValidator,
107
+ getValidatorRegistry: () => getValidatorRegistry,
108
+ getValueFunction: () => getValueFunction,
109
+ getVisibleSteps: () => getVisibleSteps,
110
+ isEmpty: () => isEmpty,
111
+ isFieldCondition: () => isFieldCondition,
112
+ isLogicalCondition: () => isLogicalCondition,
113
+ isNull: () => isNull,
114
+ isRuleTracingEnabled: () => isRuleTracingEnabled,
115
+ isStepValid: () => isStepValid,
116
+ isStringEmpty: () => isStringEmpty,
117
+ logEvent: () => logEvent,
118
+ registerLocale: () => registerLocale,
119
+ registerValidators: () => registerValidators,
120
+ registerValueFunctions: () => registerValueFunctions,
121
+ resetLocale: () => resetLocale,
122
+ resetRenderTracker: () => resetRenderTracker,
123
+ resetValidatorRegistry: () => resetValidatorRegistry,
124
+ resetValueFunctionRegistry: () => resetValueFunctionRegistry,
125
+ runSyncValidations: () => runSyncValidations,
126
+ runValidations: () => runValidations,
127
+ serializeFormState: () => serializeFormState,
128
+ sortDropdownOptions: () => sortDropdownOptions,
129
+ toRjsfSchema: () => toRjsfSchema,
130
+ topologicalSort: () => topologicalSort,
131
+ traceRuleEvent: () => traceRuleEvent,
132
+ trackRender: () => trackRender,
133
+ useBeforeUnload: () => useBeforeUnload,
134
+ useDraftPersistence: () => useDraftPersistence,
135
+ useFormAnalytics: () => useFormAnalytics,
136
+ validateDependencyGraph: () => validateDependencyGraph,
137
+ validateFieldConfigs: () => validateFieldConfigs,
138
+ validateStepFields: () => validateStepFields,
139
+ zodSchemaToFieldConfig: () => zodSchemaToFieldConfig
140
+ });
141
+ module.exports = __toCommonJS(index_exports);
142
+
143
+ // src/types/ICondition.ts
144
+ function isLogicalCondition(condition) {
145
+ const op = condition.operator;
146
+ return op === "and" || op === "or" || op === "not";
147
+ }
148
+ function isFieldCondition(condition) {
149
+ return "field" in condition;
150
+ }
151
+
152
+ // src/types/IRulesEngineAction.ts
153
+ var RulesEngineActionType = /* @__PURE__ */ ((RulesEngineActionType2) => {
154
+ RulesEngineActionType2["SET"] = "RULES_ENGINE_SET";
155
+ RulesEngineActionType2["UPDATE"] = "RULES_ENGINE_UPDATE";
156
+ RulesEngineActionType2["CLEAR"] = "RULES_ENGINE_CLEAR";
157
+ return RulesEngineActionType2;
158
+ })(RulesEngineActionType || {});
159
+
160
+ // src/types/TypedFieldConfig.ts
161
+ function defineFormConfig(fields) {
162
+ return fields;
163
+ }
164
+
165
+ // src/utils/index.ts
166
+ function isEmpty(value) {
167
+ if (value == null) return true;
168
+ if (typeof value === "string") return value.trim() === "";
169
+ if (Array.isArray(value)) return value.length === 0;
170
+ if (typeof value === "object") return Object.keys(value).length === 0;
171
+ return false;
172
+ }
173
+ function isNull(value) {
174
+ return value == null;
175
+ }
176
+ function isStringEmpty(value) {
177
+ return value == null || value.trim() === "";
178
+ }
179
+ function deepCopy(obj) {
180
+ return structuredClone(obj);
181
+ }
182
+ function convertBooleanToYesOrNoText(value) {
183
+ if (value === true) return "Yes";
184
+ if (value === false) return "No";
185
+ return "";
186
+ }
187
+ function sortDropdownOptions(a, b) {
188
+ const aText = a.label ? a.label.toLowerCase() : "";
189
+ const bText = b.label ? b.label.toLowerCase() : "";
190
+ return aText < bText ? -1 : aText > bText ? 1 : 0;
191
+ }
192
+ function createOption(value) {
193
+ return { value, label: value };
194
+ }
195
+
196
+ // src/constants.ts
197
+ var FIELD_PARENT_PREFIX = "Parent.";
198
+ var ComponentTypes = {
199
+ Textbox: "Textbox",
200
+ Dropdown: "Dropdown",
201
+ Toggle: "Toggle",
202
+ Number: "Number",
203
+ MultiSelect: "Multiselect",
204
+ DateControl: "DateControl",
205
+ Slider: "Slider",
206
+ Fragment: "DynamicFragment",
207
+ SimpleDropdown: "SimpleDropdown",
208
+ MultiSelectSearch: "MultiSelectSearch",
209
+ PopOutEditor: "PopOutEditor",
210
+ RichText: "RichText",
211
+ Textarea: "Textarea",
212
+ DocumentLinks: "DocumentLinks",
213
+ StatusDropdown: "StatusDropdown",
214
+ ReadOnly: "ReadOnly",
215
+ ReadOnlyArray: "ReadOnlyArray",
216
+ ReadOnlyDateTime: "ReadOnlyDateTime",
217
+ ReadOnlyCumulativeNumber: "ReadOnlyCumulativeNumber",
218
+ ReadOnlyRichText: "ReadOnlyRichText",
219
+ ReadOnlyWithButton: "ReadOnlyWithButton",
220
+ ChoiceSet: "ChoiceSet",
221
+ FieldArray: "FieldArray"
222
+ };
223
+ var FormConstants = {
224
+ defaultExpandCutoffCount: 12,
225
+ loadingShimmerCount: 12,
226
+ loadingFieldShimmerHeight: 32,
227
+ na: "n/a",
228
+ panelActionKeys: {
229
+ cancel: "Cancel",
230
+ close: "Close",
231
+ create: "Create",
232
+ update: "Update"
233
+ },
234
+ urlRegex: /(http(s?)):\/\//i,
235
+ errorColor: "#a4262c"
236
+ };
237
+
238
+ // src/helpers/LocaleRegistry.ts
239
+ var defaultStrings = {
240
+ // Form status
241
+ autoSavePending: "AutoSave Pending, please check for errors...",
242
+ savePending: "Save Pending, please check for errors...",
243
+ saving: "Saving...",
244
+ saveError: "Error saving form",
245
+ // Actions
246
+ save: "Save",
247
+ cancel: "Cancel",
248
+ create: "Create",
249
+ update: "Update",
250
+ confirm: "Confirm",
251
+ add: "Add",
252
+ edit: "Edit",
253
+ deleteLabel: "Delete",
254
+ remove: "Remove",
255
+ close: "Close",
256
+ clear: "Clear",
257
+ // Field labels
258
+ required: "Required",
259
+ remaining: "remaining",
260
+ na: "N/A",
261
+ unknown: "Unknown",
262
+ loading: "Loading",
263
+ noResultsFound: "No results found",
264
+ clickToClear: "Click here to Clear",
265
+ // Document links
266
+ linkTitleLabel: "Link Title",
267
+ linkUrlLabel: "Link URL",
268
+ urlRequired: "Invalid Url (http/https required)",
269
+ // Expand/collapse
270
+ seeLess: "See less",
271
+ expand: "Expand",
272
+ // Rich text editor
273
+ openExpandedTextEditor: "Open Expanded Editor",
274
+ closeExpandedTextEditor: "Close Expanded Editor",
275
+ // Unsaved changes
276
+ unsavedChanges: "Unsaved Changes",
277
+ returnToEditing: "Return to Editing",
278
+ dontSave: "Don't save",
279
+ overview: "Overview",
280
+ by: "by",
281
+ // Accessibility
282
+ filterFields: "Filter form fields",
283
+ saved: "Saved successfully",
284
+ saveFailed: "Save failed",
285
+ validating: "Validating...",
286
+ stepOf: (current, total) => `Step ${current} of ${total}`,
287
+ formWizard: "Form wizard",
288
+ itemOfTotal: (index, total, label) => `${label} item ${index} of ${total}`,
289
+ // Dynamic functions
290
+ saveChangesTo: (title) => `Do you want to save your changes to ${title}?`,
291
+ // Validation error messages
292
+ invalidUrl: "Invalid URL",
293
+ invalidEmail: "Invalid email address",
294
+ invalidPhoneNumber: "Invalid phone number",
295
+ invalidYear: "Invalid year",
296
+ contentExceedsMaxSize: (maxKb2) => `Content exceeds maximum size of ${maxKb2}KB`,
297
+ noSpecialCharacters: "Special characters are not allowed",
298
+ invalidCurrencyFormat: "Invalid currency format",
299
+ duplicateValue: (value) => `Duplicate value: ${value}`,
300
+ mustBeAtLeastChars: (min) => `Must be at least ${min} characters`,
301
+ mustBeAtMostChars: (max) => `Must be at most ${max} characters`,
302
+ mustBeANumber: "Must be a number",
303
+ mustBeBetween: (min, max) => `Must be between ${min} and ${max}`,
304
+ thisFieldIsRequired: "This field is required",
305
+ // Reliability / save status
306
+ saveRetrying: "Retrying save...",
307
+ saveTimeout: "Save timed out",
308
+ // Draft persistence
309
+ draftRecovered: "Draft recovered",
310
+ discardDraft: "Discard draft",
311
+ unsavedChangesWarning: "You have unsaved changes. Are you sure you want to leave?"
312
+ };
313
+ var currentLocale = { ...defaultStrings };
314
+ function registerLocale(partial) {
315
+ currentLocale = { ...currentLocale, ...partial };
316
+ }
317
+ function getLocaleString(key) {
318
+ return currentLocale[key];
319
+ }
320
+ function resetLocale() {
321
+ currentLocale = { ...defaultStrings };
322
+ }
323
+ function getCurrentLocale() {
324
+ return { ...currentLocale };
325
+ }
326
+
327
+ // src/strings.ts
328
+ var FormStrings = {
329
+ get autoSavePending() {
330
+ return getLocaleString("autoSavePending");
331
+ },
332
+ get savePending() {
333
+ return getLocaleString("savePending");
334
+ },
335
+ get remaining() {
336
+ return getLocaleString("remaining");
337
+ },
338
+ get saving() {
339
+ return getLocaleString("saving");
340
+ },
341
+ get seeLess() {
342
+ return getLocaleString("seeLess");
343
+ },
344
+ get expand() {
345
+ return getLocaleString("expand");
346
+ },
347
+ get required() {
348
+ return getLocaleString("required");
349
+ },
350
+ get save() {
351
+ return getLocaleString("save");
352
+ },
353
+ get cancel() {
354
+ return getLocaleString("cancel");
355
+ },
356
+ get create() {
357
+ return getLocaleString("create");
358
+ },
359
+ get update() {
360
+ return getLocaleString("update");
361
+ },
362
+ get na() {
363
+ return getLocaleString("na");
364
+ },
365
+ get saveError() {
366
+ return getLocaleString("saveError");
367
+ },
368
+ get confirm() {
369
+ return getLocaleString("confirm");
370
+ },
371
+ get linkTitleLabel() {
372
+ return getLocaleString("linkTitleLabel");
373
+ },
374
+ get linkUrlLabel() {
375
+ return getLocaleString("linkUrlLabel");
376
+ },
377
+ get add() {
378
+ return getLocaleString("add");
379
+ },
380
+ get edit() {
381
+ return getLocaleString("edit");
382
+ },
383
+ get deleteLabel() {
384
+ return getLocaleString("deleteLabel");
385
+ },
386
+ get remove() {
387
+ return getLocaleString("remove");
388
+ },
389
+ get unknown() {
390
+ return getLocaleString("unknown");
391
+ },
392
+ get close() {
393
+ return getLocaleString("close");
394
+ },
395
+ get loading() {
396
+ return getLocaleString("loading");
397
+ },
398
+ get noResultsFound() {
399
+ return getLocaleString("noResultsFound");
400
+ },
401
+ get clickToClear() {
402
+ return getLocaleString("clickToClear");
403
+ },
404
+ get clear() {
405
+ return getLocaleString("clear");
406
+ },
407
+ get urlRequired() {
408
+ return getLocaleString("urlRequired");
409
+ },
410
+ get openExpandedTextEditor() {
411
+ return getLocaleString("openExpandedTextEditor");
412
+ },
413
+ get closeExpandedTextEditor() {
414
+ return getLocaleString("closeExpandedTextEditor");
415
+ },
416
+ get unsavedChanges() {
417
+ return getLocaleString("unsavedChanges");
418
+ },
419
+ get returnToEditing() {
420
+ return getLocaleString("returnToEditing");
421
+ },
422
+ get dontSave() {
423
+ return getLocaleString("dontSave");
424
+ },
425
+ get overview() {
426
+ return getLocaleString("overview");
427
+ },
428
+ get by() {
429
+ return getLocaleString("by");
430
+ },
431
+ get filterFields() {
432
+ return getLocaleString("filterFields");
433
+ },
434
+ get saved() {
435
+ return getLocaleString("saved");
436
+ },
437
+ get saveFailed() {
438
+ return getLocaleString("saveFailed");
439
+ },
440
+ get validating() {
441
+ return getLocaleString("validating");
442
+ },
443
+ get stepOf() {
444
+ return getLocaleString("stepOf");
445
+ },
446
+ get formWizard() {
447
+ return getLocaleString("formWizard");
448
+ },
449
+ get itemOfTotal() {
450
+ return getLocaleString("itemOfTotal");
451
+ },
452
+ get saveChangesTo() {
453
+ return getLocaleString("saveChangesTo");
454
+ },
455
+ get draftRecovered() {
456
+ return getLocaleString("draftRecovered");
457
+ },
458
+ get discardDraft() {
459
+ return getLocaleString("discardDraft");
460
+ },
461
+ get unsavedChangesWarning() {
462
+ return getLocaleString("unsavedChangesWarning");
463
+ },
464
+ get saveRetrying() {
465
+ return getLocaleString("saveRetrying");
466
+ },
467
+ get saveTimeout() {
468
+ return getLocaleString("saveTimeout");
469
+ }
470
+ };
471
+
472
+ // src/providers/BusinessRulesProvider.tsx
473
+ var import_react = __toESM(require("react"));
474
+
475
+ // src/helpers/ConditionEvaluator.ts
476
+ function evaluateCondition(condition, values) {
477
+ if (isLogicalCondition(condition)) {
478
+ return evaluateLogicalCondition(condition, values);
479
+ }
480
+ return evaluateFieldCondition(condition, values);
481
+ }
482
+ function evaluateLogicalCondition(condition, values) {
483
+ switch (condition.operator) {
484
+ case "and":
485
+ return condition.conditions.every((c) => evaluateCondition(c, values));
486
+ case "or":
487
+ return condition.conditions.some((c) => evaluateCondition(c, values));
488
+ case "not":
489
+ return condition.conditions.length > 0 ? !evaluateCondition(condition.conditions[0], values) : false;
490
+ default:
491
+ return false;
492
+ }
493
+ }
494
+ function evaluateFieldCondition(condition, values) {
495
+ const fieldValue = getNestedValue(values, condition.field);
496
+ switch (condition.operator) {
497
+ case "equals":
498
+ return looseEquals(fieldValue, condition.value);
499
+ case "notEquals":
500
+ return !looseEquals(fieldValue, condition.value);
501
+ case "greaterThan":
502
+ return toNumber(fieldValue) > toNumber(condition.value);
503
+ case "lessThan":
504
+ return toNumber(fieldValue) < toNumber(condition.value);
505
+ case "greaterThanOrEqual":
506
+ return toNumber(fieldValue) >= toNumber(condition.value);
507
+ case "lessThanOrEqual":
508
+ return toNumber(fieldValue) <= toNumber(condition.value);
509
+ case "contains":
510
+ return toString(fieldValue).includes(toString(condition.value));
511
+ case "notContains":
512
+ return !toString(fieldValue).includes(toString(condition.value));
513
+ case "startsWith":
514
+ return toString(fieldValue).startsWith(toString(condition.value));
515
+ case "endsWith":
516
+ return toString(fieldValue).endsWith(toString(condition.value));
517
+ case "in":
518
+ return Array.isArray(condition.value) ? condition.value.some((v) => looseEquals(fieldValue, v)) : false;
519
+ case "notIn":
520
+ return Array.isArray(condition.value) ? !condition.value.some((v) => looseEquals(fieldValue, v)) : false;
521
+ case "isEmpty":
522
+ return isValueEmpty(fieldValue);
523
+ case "isNotEmpty":
524
+ return !isValueEmpty(fieldValue);
525
+ case "matches":
526
+ try {
527
+ return new RegExp(toString(condition.value)).test(toString(fieldValue));
528
+ } catch {
529
+ return false;
530
+ }
531
+ default:
532
+ return false;
533
+ }
534
+ }
535
+ function extractConditionDependencies(condition) {
536
+ const deps = /* @__PURE__ */ new Set();
537
+ collectDependencies(condition, deps);
538
+ return [...deps];
539
+ }
540
+ function collectDependencies(condition, deps) {
541
+ if (isLogicalCondition(condition)) {
542
+ condition.conditions.forEach((c) => collectDependencies(c, deps));
543
+ } else {
544
+ const fieldRef = condition.field;
545
+ deps.add(fieldRef.includes(".") ? fieldRef.split(".")[0] : fieldRef);
546
+ }
547
+ }
548
+ function getNestedValue(obj, path) {
549
+ const parts = path.split(".");
550
+ let current = obj;
551
+ for (const part of parts) {
552
+ if (current === null || current === void 0) return void 0;
553
+ current = current[part];
554
+ }
555
+ return current;
556
+ }
557
+ function looseEquals(a, b) {
558
+ if (a === b) return true;
559
+ if (a == null && b == null) return true;
560
+ if (a == null || b == null) return false;
561
+ return String(a) === String(b);
562
+ }
563
+ function toNumber(value) {
564
+ if (typeof value === "number") return value;
565
+ if (typeof value === "string") {
566
+ const n = Number(value);
567
+ return isNaN(n) ? 0 : n;
568
+ }
569
+ if (value instanceof Date) return value.getTime();
570
+ return 0;
571
+ }
572
+ function toString(value) {
573
+ if (value === null || value === void 0) return "";
574
+ if (typeof value === "string") return value;
575
+ return String(value);
576
+ }
577
+ function isValueEmpty(value) {
578
+ if (value === null || value === void 0) return true;
579
+ if (typeof value === "string") return value.trim() === "";
580
+ if (Array.isArray(value)) return value.length === 0;
581
+ if (typeof value === "object") return Object.keys(value).length === 0;
582
+ return false;
583
+ }
584
+
585
+ // src/helpers/ValueFunctionRegistry.ts
586
+ var defaultValueFunctions = {
587
+ setDate: () => /* @__PURE__ */ new Date(),
588
+ setDateIfNull: ({ fieldValue }) => fieldValue ? fieldValue : /* @__PURE__ */ new Date(),
589
+ setLoggedInUser: ({ currentUserId }) => currentUserId ? { id: currentUserId } : void 0,
590
+ inheritFromParent: ({ fieldName, values }) => {
591
+ const parent = values?.Parent;
592
+ return parent ? parent[fieldName] : void 0;
593
+ }
594
+ };
595
+ var valueFunctionRegistry = { ...defaultValueFunctions };
596
+ function registerValueFunctions(custom) {
597
+ valueFunctionRegistry = { ...valueFunctionRegistry, ...custom };
598
+ }
599
+ function getValueFunction(name) {
600
+ return valueFunctionRegistry[name];
601
+ }
602
+ function executeValueFunction(fieldName, functionName, values, fieldValue, parentEntity, currentUserId) {
603
+ const fn = valueFunctionRegistry[functionName];
604
+ if (fn) {
605
+ return fn({ fieldName, fieldValue, values, parentEntity, currentUserId });
606
+ }
607
+ return void 0;
608
+ }
609
+ function resetValueFunctionRegistry() {
610
+ valueFunctionRegistry = { ...defaultValueFunctions };
611
+ }
612
+
613
+ // src/helpers/ExpressionEngine.ts
614
+ function evaluateExpression(expression, values, fieldName, parentEntity, currentUserId) {
615
+ let resolved = expression.replace(
616
+ /\$fn\.([a-zA-Z_][a-zA-Z0-9_]*)\(\)/g,
617
+ (_, fnName) => {
618
+ const fn = getValueFunction(fnName);
619
+ if (fn) {
620
+ const result = fn({
621
+ fieldName: fieldName ?? "",
622
+ fieldValue: fieldName ? values[fieldName] : void 0,
623
+ values,
624
+ parentEntity,
625
+ currentUserId
626
+ });
627
+ if (result === null || result === void 0) return "undefined";
628
+ if (typeof result === "string") return JSON.stringify(result);
629
+ if (result instanceof Date) return `new Date(${result.getTime()})`;
630
+ return String(result);
631
+ }
632
+ return "undefined";
633
+ }
634
+ );
635
+ resolved = resolved.replace(
636
+ /\$parent\.([a-zA-Z_][a-zA-Z0-9_.]*)/g,
637
+ (_, fieldPath) => {
638
+ const value = getNestedValue2(parentEntity ?? {}, fieldPath);
639
+ if (value === null || value === void 0) return "undefined";
640
+ if (typeof value === "string") return JSON.stringify(value);
641
+ return String(value);
642
+ }
643
+ );
644
+ resolved = resolved.replace(
645
+ /\$root\.([a-zA-Z_][a-zA-Z0-9_.]*)/g,
646
+ (_, fieldPath) => {
647
+ const value = getNestedValue2(values, fieldPath);
648
+ if (value === null || value === void 0) return "undefined";
649
+ if (typeof value === "string") return JSON.stringify(value);
650
+ return String(value);
651
+ }
652
+ );
653
+ resolved = resolved.replace(
654
+ /\$values\.([a-zA-Z_][a-zA-Z0-9_.]*)/g,
655
+ (_, fieldPath) => {
656
+ const value = getNestedValue2(values, fieldPath);
657
+ if (value === null || value === void 0) return "undefined";
658
+ if (typeof value === "string") return JSON.stringify(value);
659
+ return String(value);
660
+ }
661
+ );
662
+ try {
663
+ const safeEval = new Function(
664
+ "Math",
665
+ "Date",
666
+ `"use strict"; return (${resolved});`
667
+ );
668
+ return safeEval(Math, Date);
669
+ } catch {
670
+ return void 0;
671
+ }
672
+ }
673
+ function getNestedValue2(obj, path) {
674
+ const parts = path.split(".");
675
+ let current = obj;
676
+ for (const part of parts) {
677
+ if (current === null || current === void 0) return void 0;
678
+ current = current[part];
679
+ }
680
+ return current;
681
+ }
682
+ function extractExpressionDependencies(expression) {
683
+ const deps = /* @__PURE__ */ new Set();
684
+ const valuesRegex = /\$(?:values|root)\.([a-zA-Z_][a-zA-Z0-9_]*)/g;
685
+ let match;
686
+ while ((match = valuesRegex.exec(expression)) !== null) {
687
+ deps.add(match[1]);
688
+ }
689
+ return [...deps];
690
+ }
691
+ function extractFunctionDependencies(expression) {
692
+ const fns = /* @__PURE__ */ new Set();
693
+ const fnRegex = /\$fn\.([a-zA-Z_][a-zA-Z0-9_]*)\(\)/g;
694
+ let match;
695
+ while ((match = fnRegex.exec(expression)) !== null) {
696
+ fns.add(match[1]);
697
+ }
698
+ return [...fns];
699
+ }
700
+
701
+ // src/helpers/EventTimeline.ts
702
+ var timeline = [];
703
+ var MAX_EVENTS = 500;
704
+ function logEvent(type, fieldName, details) {
705
+ timeline.push({ timestamp: Date.now(), type, fieldName, details });
706
+ if (timeline.length > MAX_EVENTS) {
707
+ timeline.splice(0, timeline.length - MAX_EVENTS);
708
+ }
709
+ }
710
+ function getTimeline() {
711
+ return [...timeline];
712
+ }
713
+ function clearTimeline() {
714
+ timeline.length = 0;
715
+ }
716
+
717
+ // src/helpers/RuleEngine.ts
718
+ function buildDependencyGraph(fields) {
719
+ const graph = {};
720
+ const fieldNames = Object.keys(fields);
721
+ for (const name of fieldNames) {
722
+ graph[name] = /* @__PURE__ */ new Set();
723
+ }
724
+ for (const [fieldName, config] of Object.entries(fields)) {
725
+ if (config.rules) {
726
+ for (const rule of config.rules) {
727
+ const condDeps = extractConditionDependencies(rule.when);
728
+ for (const dep of condDeps) {
729
+ if (dep in graph) {
730
+ graph[dep].add(fieldName);
731
+ }
732
+ }
733
+ collectEffectTargets(rule.then, fieldName, graph);
734
+ if (rule.else) {
735
+ collectEffectTargets(rule.else, fieldName, graph);
736
+ }
737
+ }
738
+ }
739
+ if (config.computedValue) {
740
+ const exprDeps = extractExpressionDependencies(config.computedValue);
741
+ for (const dep of exprDeps) {
742
+ if (dep in graph) {
743
+ graph[dep].add(fieldName);
744
+ }
745
+ }
746
+ }
747
+ }
748
+ return graph;
749
+ }
750
+ function collectEffectTargets(effect, ownerField, graph) {
751
+ if (effect.fields) {
752
+ for (const targetField of Object.keys(effect.fields)) {
753
+ if (targetField in graph) {
754
+ graph[ownerField]?.add(targetField);
755
+ }
756
+ }
757
+ }
758
+ }
759
+ function topologicalSort(graph) {
760
+ const inDegree = {};
761
+ const adjacency = {};
762
+ const fields = Object.keys(graph);
763
+ for (const f of fields) {
764
+ inDegree[f] = 0;
765
+ adjacency[f] = [...graph[f]];
766
+ }
767
+ for (const f of fields) {
768
+ for (const dep of adjacency[f]) {
769
+ if (dep in inDegree) {
770
+ inDegree[dep]++;
771
+ }
772
+ }
773
+ }
774
+ const queue = [];
775
+ for (const f of fields) {
776
+ if (inDegree[f] === 0) queue.push(f);
777
+ }
778
+ const sorted = [];
779
+ while (queue.length > 0) {
780
+ const current = queue.shift();
781
+ sorted.push(current);
782
+ for (const neighbor of adjacency[current]) {
783
+ if (neighbor in inDegree) {
784
+ inDegree[neighbor]--;
785
+ if (inDegree[neighbor] === 0) queue.push(neighbor);
786
+ }
787
+ }
788
+ }
789
+ const hasCycle = sorted.length < fields.length;
790
+ const cycleFields = hasCycle ? fields.filter((f) => !sorted.includes(f)) : [];
791
+ return { sorted, hasCycle, cycleFields };
792
+ }
793
+ function buildDefaultFieldStates(fields, areAllFieldsReadonly) {
794
+ const states = {};
795
+ const graph = buildDependencyGraph(fields);
796
+ for (const [fieldName, config] of Object.entries(fields)) {
797
+ states[fieldName] = {
798
+ type: config.type,
799
+ required: config.required,
800
+ hidden: config.hidden || config.type === "DynamicFragment",
801
+ readOnly: areAllFieldsReadonly ? true : config.readOnly,
802
+ validate: config.validate,
803
+ computedValue: config.computedValue,
804
+ confirmInput: config.confirmInput,
805
+ options: config.options,
806
+ label: config.label,
807
+ defaultValue: config.defaultValue,
808
+ computeOnCreateOnly: config.computeOnCreateOnly,
809
+ dependentFields: [...graph[fieldName] ?? []],
810
+ dependsOnFields: [],
811
+ activeRuleIds: []
812
+ };
813
+ }
814
+ for (const [fieldName, state] of Object.entries(states)) {
815
+ for (const dep of state.dependentFields ?? []) {
816
+ if (states[dep]) {
817
+ states[dep].dependsOnFields = states[dep].dependsOnFields ?? [];
818
+ states[dep].dependsOnFields.push(fieldName);
819
+ }
820
+ }
821
+ }
822
+ return states;
823
+ }
824
+ function evaluateAllRules(fields, values, areAllFieldsReadonly) {
825
+ const fieldStates = buildDefaultFieldStates(fields, areAllFieldsReadonly);
826
+ const fieldOrder = Object.keys(fields);
827
+ const graph = buildDependencyGraph(fields);
828
+ const { sorted } = topologicalSort(graph);
829
+ const evalOrder = sorted.length > 0 ? sorted : fieldOrder;
830
+ let currentOrder = [...fieldOrder];
831
+ for (const fieldName of evalOrder) {
832
+ const config = fields[fieldName];
833
+ if (!config?.rules) continue;
834
+ const ruleResults = evaluateFieldRules(config.rules, values);
835
+ if (fieldStates[fieldName]) {
836
+ fieldStates[fieldName].activeRuleIds = ruleResults.activeRuleIds;
837
+ }
838
+ logEvent("rule_evaluated", fieldName, `${config.rules.length} rule(s) evaluated`);
839
+ applyEffectToState(fieldStates, fieldName, ruleResults.selfEffect);
840
+ for (const [targetField, effect] of Object.entries(ruleResults.crossEffects)) {
841
+ if (fieldStates[targetField]) {
842
+ applyEffectToState(fieldStates, targetField, effect);
843
+ }
844
+ }
845
+ if (ruleResults.fieldOrder) {
846
+ currentOrder = ruleResults.fieldOrder;
847
+ }
848
+ }
849
+ return { fieldStates, fieldOrder: currentOrder };
850
+ }
851
+ function evaluateAffectedFields(changedField, fields, values, currentState) {
852
+ const affected = getTransitivelyAffectedFields(changedField, currentState.fieldStates);
853
+ logEvent("field_change", changedField, `${affected.size} affected field(s)`);
854
+ if (affected.size === 0) {
855
+ return currentState;
856
+ }
857
+ const updatedStates = { ...currentState.fieldStates };
858
+ let updatedOrder = [...currentState.fieldOrder];
859
+ for (const fieldName of affected) {
860
+ const config = fields[fieldName];
861
+ if (!config) continue;
862
+ updatedStates[fieldName] = {
863
+ ...updatedStates[fieldName],
864
+ type: config.type,
865
+ required: config.required,
866
+ hidden: config.hidden || config.type === "DynamicFragment",
867
+ readOnly: config.readOnly,
868
+ validate: config.validate,
869
+ computedValue: config.computedValue,
870
+ confirmInput: config.confirmInput,
871
+ options: config.options,
872
+ label: config.label,
873
+ defaultValue: config.defaultValue,
874
+ computeOnCreateOnly: config.computeOnCreateOnly,
875
+ activeRuleIds: []
876
+ };
877
+ }
878
+ for (const [ownerField, config] of Object.entries(fields)) {
879
+ if (!config.rules) continue;
880
+ const ruleResults = evaluateFieldRules(config.rules, values);
881
+ if (affected.has(ownerField) || ownerField === changedField) {
882
+ applyEffectToState(updatedStates, ownerField, ruleResults.selfEffect);
883
+ }
884
+ for (const [targetField, effect] of Object.entries(ruleResults.crossEffects)) {
885
+ if (affected.has(targetField) && updatedStates[targetField]) {
886
+ applyEffectToState(updatedStates, targetField, effect);
887
+ }
888
+ }
889
+ if (ruleResults.fieldOrder) {
890
+ updatedOrder = ruleResults.fieldOrder;
891
+ }
892
+ }
893
+ return { fieldStates: updatedStates, fieldOrder: updatedOrder };
894
+ }
895
+ function getTransitivelyAffectedFields(changedField, fieldStates) {
896
+ const affected = /* @__PURE__ */ new Set();
897
+ const queue = [changedField];
898
+ while (queue.length > 0) {
899
+ const current = queue.shift();
900
+ const deps = fieldStates[current]?.dependentFields ?? [];
901
+ for (const dep of deps) {
902
+ if (!affected.has(dep)) {
903
+ affected.add(dep);
904
+ queue.push(dep);
905
+ }
906
+ }
907
+ }
908
+ return affected;
909
+ }
910
+ function evaluateFieldRules(rules, values) {
911
+ const sorted = [...rules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
912
+ const selfEffect = {};
913
+ const crossEffects = {};
914
+ let fieldOrder;
915
+ const activeRuleIds = [];
916
+ for (let i = 0; i < sorted.length; i++) {
917
+ const rule = sorted[i];
918
+ const conditionMet = evaluateCondition(rule.when, values);
919
+ if (conditionMet) {
920
+ activeRuleIds.push(rule.id ?? `rule_${i}`);
921
+ }
922
+ const effect = conditionMet ? rule.then : rule.else;
923
+ if (!effect) continue;
924
+ mergeEffect(selfEffect, effect);
925
+ if (effect.fields) {
926
+ for (const [targetField, targetEffect] of Object.entries(effect.fields)) {
927
+ if (!crossEffects[targetField]) {
928
+ crossEffects[targetField] = {};
929
+ }
930
+ mergeEffect(crossEffects[targetField], targetEffect);
931
+ }
932
+ }
933
+ if (effect.fieldOrder && !fieldOrder) {
934
+ fieldOrder = effect.fieldOrder;
935
+ }
936
+ }
937
+ return { selfEffect, crossEffects, fieldOrder, activeRuleIds };
938
+ }
939
+ function mergeEffect(target, source) {
940
+ if (source.required !== void 0 && target.required === void 0) {
941
+ target.required = source.required;
942
+ }
943
+ if (source.hidden !== void 0 && target.hidden === void 0) {
944
+ target.hidden = source.hidden;
945
+ }
946
+ if (source.readOnly !== void 0 && target.readOnly === void 0) {
947
+ target.readOnly = source.readOnly;
948
+ }
949
+ if (source.label !== void 0 && target.label === void 0) {
950
+ target.label = source.label;
951
+ }
952
+ const sourceType = source.type ?? source.component;
953
+ const targetType = target.type ?? target.component;
954
+ if (sourceType !== void 0 && targetType === void 0) {
955
+ target.type = sourceType;
956
+ }
957
+ if (source.options !== void 0 && target.options === void 0) {
958
+ target.options = source.options;
959
+ }
960
+ if (source.validate !== void 0 && target.validate === void 0) {
961
+ target.validate = source.validate;
962
+ }
963
+ if (source.computedValue !== void 0 && target.computedValue === void 0) {
964
+ target.computedValue = source.computedValue;
965
+ }
966
+ }
967
+ function applyEffectToState(states, fieldName, effect) {
968
+ const state = states[fieldName];
969
+ if (!state) return;
970
+ if (effect.required !== void 0) state.required = effect.required;
971
+ if (effect.hidden !== void 0) state.hidden = effect.hidden;
972
+ if (effect.readOnly !== void 0) state.readOnly = effect.readOnly;
973
+ if (effect.label !== void 0) state.label = effect.label;
974
+ const effectType = effect.type ?? effect.component;
975
+ if (effectType !== void 0) state.type = effectType;
976
+ if (effect.options !== void 0) state.options = effect.options;
977
+ if (effect.validate !== void 0) state.validate = effect.validate;
978
+ if (effect.computedValue !== void 0) state.computedValue = effect.computedValue;
979
+ }
980
+
981
+ // src/reducers/BusinessRulesReducer.ts
982
+ var defaultRulesEngineState = {
983
+ configs: {}
984
+ };
985
+ var rulesEngineReducer = (state = defaultRulesEngineState, action) => {
986
+ switch (action.type) {
987
+ case "RULES_ENGINE_SET" /* SET */: {
988
+ const configName = action.payload.configName;
989
+ return {
990
+ configs: {
991
+ ...state.configs,
992
+ [configName]: { ...action.payload.formState }
993
+ }
994
+ };
995
+ }
996
+ case "RULES_ENGINE_UPDATE" /* UPDATE */: {
997
+ const configName = action.payload.configName;
998
+ const existing = state.configs[configName];
999
+ if (!existing) return state;
1000
+ const updatedFieldStates = { ...existing.fieldStates };
1001
+ Object.keys(action.payload.formState.fieldStates).forEach((fieldName) => {
1002
+ updatedFieldStates[fieldName] = {
1003
+ ...updatedFieldStates[fieldName],
1004
+ ...action.payload.formState.fieldStates[fieldName]
1005
+ };
1006
+ });
1007
+ return {
1008
+ configs: {
1009
+ ...state.configs,
1010
+ [configName]: {
1011
+ fieldStates: updatedFieldStates,
1012
+ fieldOrder: action.payload.formState.fieldOrder
1013
+ }
1014
+ }
1015
+ };
1016
+ }
1017
+ case "RULES_ENGINE_CLEAR" /* CLEAR */: {
1018
+ if (action.payload.configName) {
1019
+ const { [action.payload.configName]: _, ...remaining } = state.configs;
1020
+ return { configs: remaining };
1021
+ }
1022
+ return defaultRulesEngineState;
1023
+ }
1024
+ default:
1025
+ return state;
1026
+ }
1027
+ };
1028
+ var BusinessRulesReducer_default = rulesEngineReducer;
1029
+
1030
+ // src/providers/BusinessRulesProvider.tsx
1031
+ var import_jsx_runtime = require("react/jsx-runtime");
1032
+ var RulesEngineContext = import_react.default.createContext(
1033
+ void 0
1034
+ );
1035
+ function UseRulesEngineContext() {
1036
+ const context = import_react.default.useContext(RulesEngineContext);
1037
+ if (context === void 0) {
1038
+ throw new Error(
1039
+ "UseRulesEngineContext() was called outside of <RulesEngineProvider>. Required hierarchy: <RulesEngineProvider> > <InjectedFieldProvider> > <FormEngine>"
1040
+ );
1041
+ }
1042
+ return context;
1043
+ }
1044
+ var RulesEngineProvider = (props) => {
1045
+ const [rulesState, dispatch] = import_react.default.useReducer(BusinessRulesReducer_default, defaultRulesEngineState);
1046
+ const rulesStateRef = import_react.default.useRef(rulesState);
1047
+ import_react.default.useEffect(() => {
1048
+ rulesStateRef.current = rulesState;
1049
+ }, [rulesState]);
1050
+ const initFormState = import_react.default.useCallback((configName, defaultValues, fields, areAllFieldsReadonly) => {
1051
+ const formState = evaluateAllRules(fields, defaultValues, areAllFieldsReadonly);
1052
+ dispatch({
1053
+ type: "RULES_ENGINE_SET" /* SET */,
1054
+ payload: { configName, formState }
1055
+ });
1056
+ return formState;
1057
+ }, []);
1058
+ const clearFormState = import_react.default.useCallback((configName) => {
1059
+ dispatch({
1060
+ type: "RULES_ENGINE_CLEAR" /* CLEAR */,
1061
+ payload: { configName }
1062
+ });
1063
+ }, []);
1064
+ const processFieldChange = import_react.default.useCallback((entityData, configName, fieldName, fields) => {
1065
+ const currentState = rulesStateRef.current.configs[configName];
1066
+ if (!currentState) return;
1067
+ const hasAnyDeps = (currentState.fieldStates[fieldName]?.dependentFields?.length ?? 0) > 0 || (currentState.fieldStates[fieldName]?.dependsOnFields?.length ?? 0) > 0;
1068
+ if (!hasAnyDeps) return;
1069
+ const updatedState = evaluateAffectedFields(fieldName, fields, entityData, currentState);
1070
+ dispatch({
1071
+ type: "RULES_ENGINE_UPDATE" /* UPDATE */,
1072
+ payload: { configName, formState: updatedState }
1073
+ });
1074
+ }, []);
1075
+ const providerValue = import_react.default.useMemo(() => ({
1076
+ rulesState,
1077
+ initFormState,
1078
+ processFieldChange,
1079
+ clearFormState
1080
+ }), [rulesState, initFormState, processFieldChange, clearFormState]);
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RulesEngineContext.Provider, { value: providerValue, children: props.children });
1082
+ };
1083
+
1084
+ // src/providers/InjectedHookFieldProvider.tsx
1085
+ var import_react2 = __toESM(require("react"));
1086
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1087
+ var InjectedFieldContext = import_react2.default.createContext(
1088
+ void 0
1089
+ );
1090
+ function UseInjectedFieldContext() {
1091
+ const context = import_react2.default.useContext(InjectedFieldContext);
1092
+ if (context === void 0) {
1093
+ throw new Error(
1094
+ "UseInjectedFieldContext() was called outside of <InjectedFieldProvider>. Required hierarchy: <RulesEngineProvider> > <InjectedFieldProvider> > <FormEngine>"
1095
+ );
1096
+ }
1097
+ return context;
1098
+ }
1099
+ var InjectedFieldProvider = (props) => {
1100
+ const [injectedFields, setInjectedFields] = import_react2.default.useState(
1101
+ props.injectedFields ?? void 0
1102
+ );
1103
+ const providerValue = import_react2.default.useMemo(() => ({
1104
+ injectedFields,
1105
+ setInjectedFields
1106
+ }), [injectedFields]);
1107
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InjectedFieldContext.Provider, { value: providerValue, children: props.children });
1108
+ };
1109
+
1110
+ // src/helpers/ValidationRegistry.ts
1111
+ var required = (value) => {
1112
+ if (value === null || value === void 0 || typeof value === "string" && value.trim() === "") {
1113
+ return "This field is required";
1114
+ }
1115
+ return void 0;
1116
+ };
1117
+ var email = (value) => {
1118
+ if (!value || typeof value !== "string") return void 0;
1119
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1120
+ return emailRegex.test(value) ? void 0 : "Invalid email address";
1121
+ };
1122
+ var phone = (value) => {
1123
+ if (!value || typeof value !== "string") return void 0;
1124
+ const phoneRegex = /^[+]?[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/;
1125
+ return phoneRegex.test(value) ? void 0 : "Invalid phone number";
1126
+ };
1127
+ var url = (value) => {
1128
+ if (!value || typeof value !== "string") return void 0;
1129
+ return /(http(s?)):\/\//i.test(value) ? void 0 : "Invalid URL";
1130
+ };
1131
+ var year = (value) => {
1132
+ if (!value || typeof value !== "string") return void 0;
1133
+ const y = parseInt(value, 10);
1134
+ if (isNaN(y) || y < 1900 || y > 2100) return "Invalid year";
1135
+ return void 0;
1136
+ };
1137
+ var noSpecialCharacters = (value) => {
1138
+ if (!value || typeof value !== "string") return void 0;
1139
+ return /[^a-zA-Z0-9\s\-_.]/.test(value) ? "Special characters are not allowed" : void 0;
1140
+ };
1141
+ var currency = (value) => {
1142
+ if (!value && value !== 0) return void 0;
1143
+ const str = typeof value === "string" ? value : String(value);
1144
+ return /^-?\d{1,}(\.\d{1,2})?$/.test(str) ? void 0 : "Invalid currency format";
1145
+ };
1146
+ var uniqueInArray = (value) => {
1147
+ if (!value || !Array.isArray(value)) return void 0;
1148
+ const seen = /* @__PURE__ */ new Set();
1149
+ for (const item of value) {
1150
+ const str = String(item);
1151
+ if (seen.has(str)) return `Duplicate value: ${str}`;
1152
+ seen.add(str);
1153
+ }
1154
+ return void 0;
1155
+ };
1156
+ var minLength = (value, params) => {
1157
+ if (value === null || value === void 0 || typeof value !== "string") return void 0;
1158
+ const min = Number(params?.min ?? 0);
1159
+ return value.length < min ? `Must be at least ${min} characters` : void 0;
1160
+ };
1161
+ var maxLength = (value, params) => {
1162
+ if (!value || typeof value !== "string") return void 0;
1163
+ const max = Number(params?.max ?? Infinity);
1164
+ return value.length > max ? `Must be at most ${max} characters` : void 0;
1165
+ };
1166
+ var numericRange = (value, params) => {
1167
+ if (value == null || value === "") return void 0;
1168
+ const num = typeof value === "number" ? value : Number(value);
1169
+ if (isNaN(num)) return "Must be a number";
1170
+ const min = Number(params?.min ?? -Infinity);
1171
+ const max = Number(params?.max ?? Infinity);
1172
+ if (num < min || num > max) return `Must be between ${min} and ${max}`;
1173
+ return void 0;
1174
+ };
1175
+ var pattern = (value, params) => {
1176
+ if (!value || typeof value !== "string") return void 0;
1177
+ const regex = params?.pattern;
1178
+ const message = params?.message ?? "Invalid format";
1179
+ if (!regex) return void 0;
1180
+ try {
1181
+ return new RegExp(regex).test(value) ? void 0 : message;
1182
+ } catch {
1183
+ return void 0;
1184
+ }
1185
+ };
1186
+ var maxKb = (value, params) => {
1187
+ if (!value || typeof value !== "string") return void 0;
1188
+ const maxKbValue = Number(params?.maxKb ?? 150);
1189
+ const sizeKb = Math.ceil(new Blob([value]).size / 1e3);
1190
+ return sizeKb > maxKbValue ? `Content exceeds maximum size of ${maxKbValue}KB` : void 0;
1191
+ };
1192
+ var exclusiveNumericRange = (value, params) => {
1193
+ if (value == null || value === "") return void 0;
1194
+ const num = typeof value === "number" ? value : Number(value);
1195
+ if (isNaN(num)) return "Must be a number";
1196
+ const exclMin = params?.exclusiveMin != null ? Number(params.exclusiveMin) : void 0;
1197
+ const exclMax = params?.exclusiveMax != null ? Number(params.exclusiveMax) : void 0;
1198
+ const min = params?.min != null ? Number(params.min) : void 0;
1199
+ const max = params?.max != null ? Number(params.max) : void 0;
1200
+ if (exclMin !== void 0 && num <= exclMin) return `Must be greater than ${exclMin}`;
1201
+ if (exclMax !== void 0 && num >= exclMax) return `Must be less than ${exclMax}`;
1202
+ if (min !== void 0 && num < min) return `Must be at least ${min}`;
1203
+ if (max !== void 0 && num > max) return `Must be at most ${max}`;
1204
+ return void 0;
1205
+ };
1206
+ var multipleOf = (value, params) => {
1207
+ if (value == null || value === "") return void 0;
1208
+ const num = typeof value === "number" ? value : Number(value);
1209
+ if (isNaN(num)) return "Must be a number";
1210
+ const factor = Number(params?.factor ?? 1);
1211
+ if (factor === 0) return void 0;
1212
+ const remainder = Math.abs(num % factor);
1213
+ const tolerance = 1e-10;
1214
+ if (remainder > tolerance && Math.abs(remainder - Math.abs(factor)) > tolerance) {
1215
+ return `Must be a multiple of ${factor}`;
1216
+ }
1217
+ return void 0;
1218
+ };
1219
+ var requiredIf = (value, params, context) => {
1220
+ if (!params?.field || !params?.values) return void 0;
1221
+ const depValue = context.values[params.field];
1222
+ const allowedValues = params.values;
1223
+ if (allowedValues.includes(String(depValue)) && (value == null || value === "")) {
1224
+ return "This field is required";
1225
+ }
1226
+ return void 0;
1227
+ };
1228
+ var defaultValidators = {
1229
+ required,
1230
+ email,
1231
+ phone,
1232
+ url,
1233
+ year,
1234
+ noSpecialCharacters,
1235
+ currency,
1236
+ uniqueInArray,
1237
+ minLength,
1238
+ maxLength,
1239
+ numericRange,
1240
+ pattern,
1241
+ maxKb,
1242
+ exclusiveNumericRange,
1243
+ multipleOf,
1244
+ requiredIf,
1245
+ // Legacy name aliases
1246
+ EmailValidation: email,
1247
+ PhoneNumberValidation: phone,
1248
+ YearValidation: year,
1249
+ isValidUrl: url,
1250
+ NoSpecialCharactersValidation: noSpecialCharacters,
1251
+ CurrencyValidation: currency,
1252
+ UniqueInArrayValidation: uniqueInArray,
1253
+ Max150KbValidation: (v, _p, c) => maxKb(v, { maxKb: 150 }, c),
1254
+ Max32KbValidation: (v, _p, c) => maxKb(v, { maxKb: 32 }, c)
1255
+ };
1256
+ var validatorRegistry = { ...defaultValidators };
1257
+ function registerValidators(custom) {
1258
+ validatorRegistry = { ...validatorRegistry, ...custom };
1259
+ }
1260
+ function getValidator(name) {
1261
+ return validatorRegistry[name];
1262
+ }
1263
+ function getValidatorRegistry() {
1264
+ return { ...validatorRegistry };
1265
+ }
1266
+ function resetValidatorRegistry() {
1267
+ validatorRegistry = { ...defaultValidators };
1268
+ }
1269
+ async function runValidations(value, rules, context) {
1270
+ for (const rule of rules) {
1271
+ if (context.signal?.aborted) return void 0;
1272
+ if (rule.when) {
1273
+ if (!evaluateCondition(rule.when, context.values)) continue;
1274
+ }
1275
+ const validator = getValidator(rule.name);
1276
+ if (!validator) continue;
1277
+ const result = validator(value, rule.params, context);
1278
+ const message = result instanceof Promise ? await result : result;
1279
+ if (message) {
1280
+ return rule.message ?? message;
1281
+ }
1282
+ }
1283
+ return void 0;
1284
+ }
1285
+ function runSyncValidations(value, rules, context) {
1286
+ for (const rule of rules) {
1287
+ if (rule.async) continue;
1288
+ if (rule.when) {
1289
+ if (!evaluateCondition(rule.when, context.values)) continue;
1290
+ }
1291
+ const validator = getValidator(rule.name);
1292
+ if (!validator) continue;
1293
+ const result = validator(value, rule.params, context);
1294
+ if (typeof result === "string") {
1295
+ return rule.message ?? result;
1296
+ }
1297
+ }
1298
+ return void 0;
1299
+ }
1300
+ function createMinLengthRule(min, message) {
1301
+ return { name: "minLength", params: { min }, message };
1302
+ }
1303
+ function createMaxLengthRule(max, message) {
1304
+ return { name: "maxLength", params: { max }, message };
1305
+ }
1306
+ function createNumericRangeRule(min, max, message) {
1307
+ return { name: "numericRange", params: { min, max }, message };
1308
+ }
1309
+ function createPatternRule(pattern2, message) {
1310
+ return { name: "pattern", params: { pattern: pattern2, message } };
1311
+ }
1312
+ function createRequiredIfRule(field, values, message) {
1313
+ return { name: "requiredIf", params: { field, values }, message };
1314
+ }
1315
+
1316
+ // src/helpers/InlineFormHelper.ts
1317
+ var GetChildEntity = (entityId, entity, entityPath, idField = "id") => {
1318
+ if (!entity || !entityPath) return void 0;
1319
+ const childValues = entity[entityPath]?.filter((child) => child[idField] === entityId);
1320
+ return childValues?.length === 1 ? { ...childValues[0], Parent: { ...entity } } : void 0;
1321
+ };
1322
+ var IsExpandVisible = (fieldStates, expandCutoffCount = 12) => {
1323
+ let count = 0;
1324
+ Object.keys(fieldStates).forEach((field) => {
1325
+ if (!fieldStates[field].hidden) count += 1;
1326
+ });
1327
+ return count > expandCutoffCount;
1328
+ };
1329
+ var GetConfirmInputModalProps = (dirtyFieldNames, fieldStates) => {
1330
+ const confirmInputModalProps = {};
1331
+ dirtyFieldNames?.forEach((fieldName) => {
1332
+ fieldStates[fieldName]?.dependentFields?.forEach((dependentFieldName) => {
1333
+ if (fieldStates[dependentFieldName]?.confirmInput) {
1334
+ if (confirmInputModalProps.confirmInputsTriggeredBy === void 0) {
1335
+ confirmInputModalProps.confirmInputsTriggeredBy = fieldName;
1336
+ confirmInputModalProps.dependentFieldNames = [dependentFieldName];
1337
+ } else {
1338
+ confirmInputModalProps.dependentFieldNames.push(dependentFieldName);
1339
+ }
1340
+ }
1341
+ });
1342
+ });
1343
+ confirmInputModalProps.otherDirtyFields = dirtyFieldNames?.filter(
1344
+ (fieldName) => !confirmInputModalProps.dependentFieldNames?.includes(fieldName) && fieldName !== confirmInputModalProps.confirmInputsTriggeredBy
1345
+ );
1346
+ return confirmInputModalProps;
1347
+ };
1348
+ var GetComputedValuesOnDirtyFields = (dirtyFieldNames, fieldStates) => {
1349
+ const computedValues = [];
1350
+ dirtyFieldNames?.forEach((fieldName) => {
1351
+ fieldStates[fieldName]?.dependentFields?.forEach((dependentFieldName) => {
1352
+ const state = fieldStates[dependentFieldName];
1353
+ if (state?.computedValue && !state.computeOnCreateOnly && !dirtyFieldNames.includes(dependentFieldName)) {
1354
+ computedValues.push({
1355
+ fieldName: dependentFieldName,
1356
+ expression: state.computedValue
1357
+ });
1358
+ }
1359
+ });
1360
+ });
1361
+ return computedValues;
1362
+ };
1363
+ var GetComputedValuesOnCreate = (fieldStates) => {
1364
+ const computedValues = [];
1365
+ Object.keys(fieldStates).forEach((fieldName) => {
1366
+ const state = fieldStates[fieldName];
1367
+ if (state.computedValue && state.computeOnCreateOnly) {
1368
+ computedValues.push({
1369
+ fieldName,
1370
+ expression: state.computedValue
1371
+ });
1372
+ }
1373
+ });
1374
+ return computedValues;
1375
+ };
1376
+ var ExecuteComputedValue = (expression, values, fieldName, parentEntity, currentUserId) => {
1377
+ return evaluateExpression(expression, values, fieldName, parentEntity, currentUserId);
1378
+ };
1379
+ var CheckFieldValidationRules = (value, fieldName, entityData, state) => {
1380
+ if (!state.validate || state.validate.length === 0) return void 0;
1381
+ const context = { fieldName, values: entityData };
1382
+ const result = runSyncValidations(value, state.validate, context);
1383
+ logEvent("validation_run", fieldName, result ? `failed: ${result}` : "passed");
1384
+ return result;
1385
+ };
1386
+ var CheckAsyncFieldValidationRules = async (value, fieldName, entityData, state, signal) => {
1387
+ if (!state.validate || state.validate.length === 0) return void 0;
1388
+ const context = { fieldName, values: entityData, signal };
1389
+ return runValidations(value, state.validate, context);
1390
+ };
1391
+ var CheckValidDropdownOptions = (fieldStates, formValues, setValue) => {
1392
+ if (isEmpty(fieldStates) || isEmpty(formValues)) return;
1393
+ Object.keys(fieldStates).forEach((fieldName) => {
1394
+ const { type, options } = fieldStates[fieldName];
1395
+ if ((type === "Dropdown" || type === "StatusDropdown") && !isNull(formValues[fieldName]) && options && options.findIndex((o) => String(o.value) === String(formValues[fieldName])) === -1) {
1396
+ setValue(`${fieldName}`, null, { shouldDirty: false });
1397
+ } else if (type === "Multiselect" && !isNull(formValues[fieldName]) && options) {
1398
+ const filteredValues = formValues[fieldName]?.filter(
1399
+ (val) => options.some((o) => String(o.value) === val)
1400
+ );
1401
+ if (filteredValues?.length !== formValues[fieldName]?.length) {
1402
+ setValue(`${fieldName}`, filteredValues, { shouldDirty: false });
1403
+ }
1404
+ }
1405
+ });
1406
+ };
1407
+ var CheckDefaultValues = (fieldStates, formValues, setValue) => {
1408
+ if (isEmpty(fieldStates) || isEmpty(formValues)) return;
1409
+ Object.keys(fieldStates).forEach((fieldName) => {
1410
+ const { defaultValue, hidden } = fieldStates[fieldName];
1411
+ if (!isNull(defaultValue) && isNull(formValues[fieldName]) && !hidden) {
1412
+ setValue(`${fieldName}`, defaultValue, { shouldDirty: true });
1413
+ }
1414
+ });
1415
+ };
1416
+ var InitOnCreateFormState = (configName, fields, defaultValues, parentEntity, userId, setValue, initFormState) => {
1417
+ const initEntityData = { ...defaultValues, Parent: { ...parentEntity } };
1418
+ for (const [fieldName, config] of Object.entries(fields)) {
1419
+ if (config.computedValue && config.computeOnCreateOnly) {
1420
+ const result = ExecuteComputedValue(
1421
+ config.computedValue,
1422
+ initEntityData,
1423
+ fieldName,
1424
+ parentEntity,
1425
+ userId
1426
+ );
1427
+ if (result !== void 0) {
1428
+ setValue(`${fieldName}`, result);
1429
+ initEntityData[fieldName] = result;
1430
+ }
1431
+ }
1432
+ if (config.defaultValue !== void 0 && isNull(initEntityData[fieldName])) {
1433
+ setValue(`${fieldName}`, config.defaultValue);
1434
+ initEntityData[fieldName] = config.defaultValue;
1435
+ }
1436
+ }
1437
+ return {
1438
+ formState: initFormState(configName, initEntityData, fields, false),
1439
+ initEntityData
1440
+ };
1441
+ };
1442
+ var InitOnEditFormState = (configName, fields, defaultValues, areAllFieldsReadonly, initFormState) => {
1443
+ return {
1444
+ formState: initFormState(configName, defaultValues, fields, areAllFieldsReadonly),
1445
+ initEntityData: defaultValues
1446
+ };
1447
+ };
1448
+ var ShowField = (filterText, value, label) => {
1449
+ if (!filterText) return true;
1450
+ const valueStr = JSON.stringify(value)?.toLowerCase();
1451
+ const labelStr = label?.toLowerCase();
1452
+ return (valueStr?.includes(filterText.toLowerCase()) ?? false) || (labelStr?.includes(filterText.toLowerCase()) ?? false);
1453
+ };
1454
+ var GetFieldsToRender = (fieldRenderLimit, fieldOrder, fieldStates) => {
1455
+ if (fieldRenderLimit) {
1456
+ const fieldsToRender = [];
1457
+ let count = 0;
1458
+ fieldOrder.forEach((fieldName) => {
1459
+ if (fieldStates?.[fieldName]?.hidden) return;
1460
+ if (count === fieldRenderLimit) {
1461
+ fieldsToRender.push({ fieldName, softHidden: true });
1462
+ } else {
1463
+ fieldsToRender.push({ fieldName, softHidden: false });
1464
+ count += 1;
1465
+ }
1466
+ });
1467
+ return fieldsToRender;
1468
+ }
1469
+ return fieldOrder?.map((fieldName) => ({ fieldName, softHidden: false }));
1470
+ };
1471
+ var SortOptions = (options) => {
1472
+ return [...options].sort((a, b) => {
1473
+ const aLabel = a.label?.toLowerCase() ?? "";
1474
+ const bLabel = b.label?.toLowerCase() ?? "";
1475
+ return aLabel < bLabel ? -1 : aLabel > bLabel ? 1 : 0;
1476
+ });
1477
+ };
1478
+
1479
+ // src/helpers/FieldHelper.ts
1480
+ function SortOptions2(options) {
1481
+ return [...options].sort((a, b) => {
1482
+ const aLabel = a.label?.toLowerCase() ?? "";
1483
+ const bLabel = b.label?.toLowerCase() ?? "";
1484
+ return aLabel < bLabel ? -1 : aLabel > bLabel ? 1 : 0;
1485
+ });
1486
+ }
1487
+
1488
+ // src/helpers/DependencyGraphValidator.ts
1489
+ function detectDependencyCycles(fields) {
1490
+ const errors = [];
1491
+ const graph = buildDependencyGraph(fields);
1492
+ const { hasCycle, cycleFields } = topologicalSort(graph);
1493
+ if (hasCycle) {
1494
+ errors.push({
1495
+ type: "dependency",
1496
+ fields: cycleFields,
1497
+ message: `Circular dependency detected among fields: ${cycleFields.join(", ")}`
1498
+ });
1499
+ }
1500
+ return errors;
1501
+ }
1502
+ function detectSelfDependencies(fields) {
1503
+ const errors = [];
1504
+ for (const [fieldName, config] of Object.entries(fields)) {
1505
+ if (!config.rules) continue;
1506
+ for (const rule of config.rules) {
1507
+ const condDeps = extractConditionDependencies(rule.when);
1508
+ const selfInCondition = condDeps.includes(fieldName);
1509
+ if (selfInCondition && rule.then.fields?.[fieldName]) {
1510
+ errors.push({
1511
+ type: "self",
1512
+ fields: [fieldName],
1513
+ message: `Field "${fieldName}" has a rule that both depends on and modifies itself`
1514
+ });
1515
+ }
1516
+ }
1517
+ }
1518
+ return errors;
1519
+ }
1520
+ function validateDependencyGraph(fields) {
1521
+ const errors = [];
1522
+ errors.push(...detectDependencyCycles(fields));
1523
+ errors.push(...detectSelfDependencies(fields));
1524
+ try {
1525
+ if (typeof globalThis !== "undefined" && globalThis.__DEV__ !== false) {
1526
+ for (const error of errors) {
1527
+ console.warn(`[dynamic-forms] ${error.message}`);
1528
+ }
1529
+ }
1530
+ } catch {
1531
+ }
1532
+ return errors;
1533
+ }
1534
+
1535
+ // src/helpers/ConfigValidator.ts
1536
+ function validateFieldConfigs(fields, registeredComponents) {
1537
+ const errors = [];
1538
+ const fieldNames = new Set(Object.keys(fields));
1539
+ for (const [fieldName, config] of Object.entries(fields)) {
1540
+ if (config.rules) {
1541
+ for (const rule of config.rules) {
1542
+ const condDeps = extractConditionDependencies(rule.when);
1543
+ for (const dep of condDeps) {
1544
+ if (!fieldNames.has(dep)) {
1545
+ errors.push({
1546
+ type: "missing_rule_target",
1547
+ fieldName,
1548
+ message: `Field "${fieldName}" has a rule condition referencing non-existent field "${dep}"`,
1549
+ details: dep
1550
+ });
1551
+ }
1552
+ }
1553
+ if (rule.then.fields) {
1554
+ for (const target of Object.keys(rule.then.fields)) {
1555
+ if (!fieldNames.has(target)) {
1556
+ errors.push({
1557
+ type: "missing_rule_target",
1558
+ fieldName,
1559
+ message: `Field "${fieldName}" has a rule effect targeting non-existent field "${target}"`,
1560
+ details: target
1561
+ });
1562
+ }
1563
+ }
1564
+ }
1565
+ if (rule.else?.fields) {
1566
+ for (const target of Object.keys(rule.else.fields)) {
1567
+ if (!fieldNames.has(target)) {
1568
+ errors.push({
1569
+ type: "missing_rule_target",
1570
+ fieldName,
1571
+ message: `Field "${fieldName}" has a rule else-effect targeting non-existent field "${target}"`,
1572
+ details: target
1573
+ });
1574
+ }
1575
+ }
1576
+ }
1577
+ }
1578
+ }
1579
+ if (registeredComponents && config.type && !registeredComponents.has(config.type)) {
1580
+ errors.push({
1581
+ type: "unregistered_component",
1582
+ fieldName,
1583
+ message: `Field "${fieldName}" uses unregistered component type "${config.type}". Available: ${[...registeredComponents].join(", ")}`,
1584
+ details: config.type
1585
+ });
1586
+ }
1587
+ if (config.validate) {
1588
+ for (const rule of config.validate) {
1589
+ if (!getValidator(rule.name)) {
1590
+ errors.push({
1591
+ type: "unregistered_validator",
1592
+ fieldName,
1593
+ message: `Field "${fieldName}" references unregistered validator "${rule.name}"`,
1594
+ details: rule.name
1595
+ });
1596
+ }
1597
+ }
1598
+ }
1599
+ if ((config.type === "Dropdown" || config.type === "StatusDropdown" || config.type === "Multiselect") && (!config.options || config.options.length === 0) && !hasRuleProvidingOptions(fieldName, fields)) {
1600
+ errors.push({
1601
+ type: "missing_options",
1602
+ fieldName,
1603
+ message: `Field "${fieldName}" is a ${config.type} but has no options configured and no rules providing options`
1604
+ });
1605
+ }
1606
+ }
1607
+ const cycleErrors = detectDependencyCycles(fields);
1608
+ for (const cycleError of cycleErrors) {
1609
+ errors.push({
1610
+ type: "circular_dependency",
1611
+ fieldName: cycleError.fields[0] ?? "",
1612
+ message: cycleError.message
1613
+ });
1614
+ }
1615
+ const selfErrors = detectSelfDependencies(fields);
1616
+ for (const selfError of selfErrors) {
1617
+ errors.push({
1618
+ type: "self_dependency",
1619
+ fieldName: selfError.fields[0] ?? "",
1620
+ message: selfError.message
1621
+ });
1622
+ }
1623
+ return errors;
1624
+ }
1625
+ function hasRuleProvidingOptions(targetFieldName, fields) {
1626
+ for (const config of Object.values(fields)) {
1627
+ if (config.rules) {
1628
+ for (const rule of config.rules) {
1629
+ if (rule.then.fields?.[targetFieldName]?.options) return true;
1630
+ if (rule.else?.fields?.[targetFieldName]?.options) return true;
1631
+ }
1632
+ }
1633
+ }
1634
+ return false;
1635
+ }
1636
+
1637
+ // src/components/WizardForm.tsx
1638
+ var import_react3 = __toESM(require("react"));
1639
+
1640
+ // src/helpers/WizardHelper.ts
1641
+ function getVisibleSteps(steps, entityData) {
1642
+ return steps.filter((step) => {
1643
+ if (!step.visibleWhen) return true;
1644
+ return evaluateCondition(step.visibleWhen, entityData);
1645
+ });
1646
+ }
1647
+ function getStepFields(step, fieldStates) {
1648
+ if (!fieldStates) return step.fields;
1649
+ return step.fields.filter((fieldName) => {
1650
+ const state = fieldStates[fieldName];
1651
+ return !state?.hidden;
1652
+ });
1653
+ }
1654
+ function getStepFieldOrder(steps, entityData) {
1655
+ const visibleSteps = getVisibleSteps(steps, entityData);
1656
+ return visibleSteps.flatMap((step) => step.fields);
1657
+ }
1658
+ function validateStepFields(step, errors) {
1659
+ return step.fields.filter((fieldName) => fieldName in errors);
1660
+ }
1661
+ function isStepValid(step, errors) {
1662
+ return validateStepFields(step, errors).length === 0;
1663
+ }
1664
+ function getStepIndex(steps, stepId) {
1665
+ return steps.findIndex((s) => s.id === stepId);
1666
+ }
1667
+
1668
+ // src/components/WizardForm.tsx
1669
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1670
+ var WizardForm = (props) => {
1671
+ const {
1672
+ wizardConfig,
1673
+ entityData,
1674
+ fieldStates,
1675
+ errors,
1676
+ renderStepContent,
1677
+ renderStepNavigation,
1678
+ renderStepHeader,
1679
+ onStepChange,
1680
+ onAnalyticsStepChange
1681
+ } = props;
1682
+ const [currentStepIndex, setCurrentStepIndex] = import_react3.default.useState(0);
1683
+ const visibleSteps = import_react3.default.useMemo(
1684
+ () => getVisibleSteps(wizardConfig.steps, entityData),
1685
+ [wizardConfig.steps, entityData]
1686
+ );
1687
+ const currentStep = visibleSteps[currentStepIndex];
1688
+ const currentFields = currentStep ? getStepFields(currentStep, fieldStates) : [];
1689
+ const canGoNext = currentStepIndex < visibleSteps.length - 1;
1690
+ const canGoPrev = currentStepIndex > 0;
1691
+ const goToStep = import_react3.default.useCallback((index) => {
1692
+ if (index >= 0 && index < visibleSteps.length) {
1693
+ if (wizardConfig.validateOnStepChange && errors && currentStep) {
1694
+ if (!isStepValid(currentStep, errors)) return;
1695
+ }
1696
+ const prevIndex = currentStepIndex;
1697
+ setCurrentStepIndex(index);
1698
+ onStepChange?.(prevIndex, index);
1699
+ onAnalyticsStepChange?.(prevIndex, index);
1700
+ }
1701
+ }, [visibleSteps.length, currentStepIndex, wizardConfig.validateOnStepChange, errors, currentStep, onStepChange, onAnalyticsStepChange]);
1702
+ const goNext = import_react3.default.useCallback(() => {
1703
+ if (canGoNext) goToStep(currentStepIndex + 1);
1704
+ }, [canGoNext, currentStepIndex, goToStep]);
1705
+ const goPrev = import_react3.default.useCallback(() => {
1706
+ if (canGoPrev) goToStep(currentStepIndex - 1);
1707
+ }, [canGoPrev, currentStepIndex, goToStep]);
1708
+ const stepAnnouncement = currentStep ? `${FormStrings.stepOf(currentStepIndex + 1, visibleSteps.length)}${currentStep.title ? `: ${currentStep.title}` : ""}` : "";
1709
+ if (!currentStep) return null;
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "wizard-form", role: "group", "aria-label": FormStrings.formWizard, children: [
1711
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "status", "aria-live": "polite", className: "sr-only", style: { position: "absolute", width: "1px", height: "1px", padding: 0, margin: "-1px", overflow: "hidden", clip: "rect(0, 0, 0, 0)", whiteSpace: "nowrap", border: 0 }, "data-testid": "wizard-step-live-region", children: stepAnnouncement }),
1712
+ renderStepHeader?.({ step: currentStep, stepIndex: currentStepIndex, totalSteps: visibleSteps.length }),
1713
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "wizard-step-content", "aria-current": "step", children: renderStepContent(currentFields) }),
1714
+ renderStepNavigation?.({ steps: visibleSteps, currentStepIndex, goToStep, canGoNext, canGoPrev, goNext, goPrev })
1715
+ ] });
1716
+ };
1717
+
1718
+ // src/components/FieldArray.tsx
1719
+ var import_react4 = __toESM(require("react"));
1720
+ var import_react_hook_form = require("react-hook-form");
1721
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1722
+ var FieldArray = (props) => {
1723
+ const { fieldName, config, renderItem, renderAddButton } = props;
1724
+ const { control } = (0, import_react_hook_form.useFormContext)();
1725
+ const { fields, append, remove } = (0, import_react_hook_form.useFieldArray)({ control, name: fieldName });
1726
+ const canAdd = config.maxItems ? fields.length < config.maxItems : true;
1727
+ const canRemove = config.minItems ? fields.length > config.minItems : true;
1728
+ const handleAppend = import_react4.default.useCallback(() => {
1729
+ if (canAdd) append({});
1730
+ }, [canAdd, append]);
1731
+ const handleRemove = import_react4.default.useCallback((index) => {
1732
+ if (canRemove) remove(index);
1733
+ }, [canRemove, remove]);
1734
+ const itemFieldNames = import_react4.default.useMemo(
1735
+ () => config.items ? Object.keys(config.items) : [],
1736
+ [config.items]
1737
+ );
1738
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "field-array", role: "group", "aria-label": config.label || fieldName, children: [
1739
+ fields.map((field, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "field-array-item", role: "group", "aria-label": FormStrings.itemOfTotal(index + 1, fields.length, config.label || fieldName), children: renderItem(
1740
+ itemFieldNames.map((name) => `${fieldName}.${index}.${name}`),
1741
+ index,
1742
+ () => handleRemove(index)
1743
+ ) }, field.id)),
1744
+ renderAddButton?.(handleAppend, canAdd)
1745
+ ] });
1746
+ };
1747
+
1748
+ // src/components/InlineForm.tsx
1749
+ var import_react11 = __toESM(require("react"));
1750
+ var import_react_hook_form4 = require("react-hook-form");
1751
+
1752
+ // src/hooks/useFormAnalytics.ts
1753
+ var import_react5 = require("react");
1754
+ function useFormAnalytics(callbacks) {
1755
+ const formStartTime = (0, import_react5.useRef)(Date.now()).current;
1756
+ const focusTimes = (0, import_react5.useRef)({});
1757
+ const callbacksRef = (0, import_react5.useRef)(callbacks);
1758
+ callbacksRef.current = callbacks;
1759
+ return (0, import_react5.useMemo)(() => ({
1760
+ formStartTime,
1761
+ trackFieldFocus(fieldName) {
1762
+ focusTimes.current[fieldName] = Date.now();
1763
+ callbacksRef.current?.onFieldFocus?.(fieldName);
1764
+ },
1765
+ trackFieldBlur(fieldName) {
1766
+ const start = focusTimes.current[fieldName];
1767
+ const timeSpentMs = start ? Date.now() - start : 0;
1768
+ delete focusTimes.current[fieldName];
1769
+ callbacksRef.current?.onFieldBlur?.(fieldName, timeSpentMs);
1770
+ },
1771
+ trackFieldChange(fieldName, oldValue, newValue) {
1772
+ callbacksRef.current?.onFieldChange?.(fieldName, oldValue, newValue);
1773
+ },
1774
+ trackValidationError(fieldName, errors) {
1775
+ callbacksRef.current?.onValidationError?.(fieldName, errors);
1776
+ },
1777
+ trackFormSubmit(values) {
1778
+ const durationMs = Date.now() - formStartTime;
1779
+ callbacksRef.current?.onFormSubmit?.(values, durationMs);
1780
+ },
1781
+ trackFormAbandonment(filledFields, emptyRequiredFields) {
1782
+ callbacksRef.current?.onFormAbandonment?.(filledFields, emptyRequiredFields);
1783
+ },
1784
+ trackWizardStepChange(fromStep, toStep) {
1785
+ callbacksRef.current?.onWizardStepChange?.(fromStep, toStep);
1786
+ },
1787
+ trackRuleTriggered(event) {
1788
+ callbacksRef.current?.onRuleTriggered?.(event);
1789
+ }
1790
+ }), [formStartTime]);
1791
+ }
1792
+
1793
+ // src/components/ConfirmInputsModal.tsx
1794
+ var import_react8 = __toESM(require("react"));
1795
+ var import_react_hook_form3 = require("react-hook-form");
1796
+
1797
+ // src/components/RenderField.tsx
1798
+ var import_react7 = __toESM(require("react"));
1799
+ var import_react_hook_form2 = require("react-hook-form");
1800
+
1801
+ // src/components/FieldWrapper.tsx
1802
+ var import_react6 = __toESM(require("react"));
1803
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1804
+ var FieldWrapper = import_react6.default.memo((props) => {
1805
+ const {
1806
+ id,
1807
+ required: required2,
1808
+ error,
1809
+ errorCount,
1810
+ savePending,
1811
+ saving,
1812
+ labelClassName,
1813
+ fieldClassName,
1814
+ showControlonSide,
1815
+ label,
1816
+ ariaLabel,
1817
+ ariaDescription,
1818
+ containerClassName,
1819
+ additionalInfo,
1820
+ additionalInfoComponent,
1821
+ isManualSave,
1822
+ renderLabel,
1823
+ renderError,
1824
+ renderStatus
1825
+ } = props;
1826
+ const labelId = `${id}_label`;
1827
+ const errorMessageId = `${id}_error`;
1828
+ const children = Array.isArray(props.children) ? props.children : [props.children];
1829
+ const defaultLabel = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: labelClassName || "", children: [
1830
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { id: labelId, htmlFor: id, className: "field-label", children: [
1831
+ label,
1832
+ required2 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1833
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "required-indicator", "aria-hidden": "true", style: { color: "var(--form-required-color, #d13438)" }, children: " *" }),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "sr-only", style: { position: "absolute", width: "1px", height: "1px", padding: 0, margin: "-1px", overflow: "hidden", clip: "rect(0, 0, 0, 0)", whiteSpace: "nowrap", border: 0 }, children: " (required)" })
1835
+ ] })
1836
+ ] }),
1837
+ additionalInfoComponent,
1838
+ !additionalInfoComponent && additionalInfo && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "additional-info", title: additionalInfo, children: "\u24D8" })
1839
+ ] });
1840
+ const defaultErrorAndStatus = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message", children: error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "error-icon", "aria-hidden": "true", style: { color: "var(--form-error-color, #d13438)" }, children: "\u2716" }),
1842
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "error-message", id: errorMessageId, role: "alert", style: { color: "var(--form-error-color, #d13438)" }, children: error.message || "Error" })
1843
+ ] }) : savePending ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1844
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "warning-icon", "aria-hidden": "true", style: { color: "var(--form-warning-color, #ffb900)" }, children: "\u26A0" }),
1845
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "warning-message", id: errorMessageId, role: "status", style: { color: "var(--form-warning-color, #ffb900)" }, children: [
1846
+ !isManualSave ? FormStrings.autoSavePending : FormStrings.savePending,
1847
+ " (",
1848
+ `${errorCount} ${FormStrings.remaining}`,
1849
+ ")"
1850
+ ] })
1851
+ ] }) : saving ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1852
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "save-spinner", "aria-hidden": "true", style: { color: "var(--form-saving-color, #0078d4)" }, children: "\u231B" }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "save-message", id: errorMessageId, role: "status", style: { color: "var(--form-saving-color, #0078d4)" }, children: FormStrings.saving })
1854
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {}) });
1855
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1856
+ "div",
1857
+ {
1858
+ className: `form-field ${showControlonSide ? "flexBox" : ""} ${containerClassName || ""} ${saving ? "saving" : ""}`,
1859
+ "aria-busy": saving ? "true" : void 0,
1860
+ children: [
1861
+ renderLabel ? renderLabel({ id: id || "", labelId, label, required: required2 }) : defaultLabel,
1862
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `flexBox-Direction-column field-container ${fieldClassName || ""}`, children: children.map((child, index) => {
1863
+ if (child && child.props) {
1864
+ const childProps = {
1865
+ id,
1866
+ "aria-labelledby": ariaLabel ? void 0 : labelId,
1867
+ "aria-label": ariaLabel || void 0,
1868
+ "aria-required": required2,
1869
+ "aria-invalid": !!error,
1870
+ "aria-describedby": errorMessageId,
1871
+ key: index,
1872
+ className: child.props.className
1873
+ };
1874
+ if (ariaDescription && !error) {
1875
+ childProps["aria-description"] = ariaDescription;
1876
+ }
1877
+ if (index === 0) {
1878
+ return import_react6.default.cloneElement(child, childProps);
1879
+ }
1880
+ const siblingProps = {
1881
+ key: index,
1882
+ "aria-labelledby": childProps["aria-labelledby"],
1883
+ "aria-label": childProps["aria-label"],
1884
+ "aria-required": childProps["aria-required"],
1885
+ "aria-invalid": childProps["aria-invalid"],
1886
+ "aria-describedby": childProps["aria-describedby"],
1887
+ className: child.props.className
1888
+ };
1889
+ if (childProps["aria-description"]) {
1890
+ siblingProps["aria-description"] = childProps["aria-description"];
1891
+ }
1892
+ return import_react6.default.cloneElement(child, siblingProps);
1893
+ }
1894
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react6.default.Fragment, {}, index);
1895
+ }) }),
1896
+ renderError ? renderError({ id: id || "", error, errorCount }) : renderStatus ? renderStatus({ id: id || "", saving, savePending, errorCount, isManualSave }) : defaultErrorAndStatus
1897
+ ]
1898
+ }
1899
+ );
1900
+ });
1901
+
1902
+ // src/helpers/RenderTracker.ts
1903
+ var renderCounts = /* @__PURE__ */ new Map();
1904
+ var lastRenderedFields = /* @__PURE__ */ new Set();
1905
+ var pendingRenderedFields = /* @__PURE__ */ new Set();
1906
+ var totalFormRenders = 0;
1907
+ function trackRender(fieldName) {
1908
+ renderCounts.set(fieldName, (renderCounts.get(fieldName) ?? 0) + 1);
1909
+ pendingRenderedFields.add(fieldName);
1910
+ }
1911
+ function flushRenderCycle() {
1912
+ lastRenderedFields = pendingRenderedFields;
1913
+ pendingRenderedFields = /* @__PURE__ */ new Set();
1914
+ totalFormRenders++;
1915
+ }
1916
+ function getRenderCounts() {
1917
+ return new Map(renderCounts);
1918
+ }
1919
+ function getLastRenderedFields() {
1920
+ return new Set(lastRenderedFields);
1921
+ }
1922
+ function getTotalFormRenders() {
1923
+ return totalFormRenders;
1924
+ }
1925
+ function resetRenderTracker() {
1926
+ renderCounts.clear();
1927
+ lastRenderedFields.clear();
1928
+ pendingRenderedFields.clear();
1929
+ totalFormRenders = 0;
1930
+ }
1931
+
1932
+ // src/components/RenderField.tsx
1933
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1934
+ var RenderField = (props) => {
1935
+ const {
1936
+ type,
1937
+ fieldName,
1938
+ entityId,
1939
+ entityType,
1940
+ programName,
1941
+ hidden,
1942
+ required: required2,
1943
+ readOnly,
1944
+ disabled,
1945
+ options,
1946
+ validate,
1947
+ parentEntityId,
1948
+ parentEntityType,
1949
+ isManualSave,
1950
+ setFieldValue,
1951
+ isCreate,
1952
+ filterText,
1953
+ softHidden,
1954
+ label,
1955
+ skipLayoutReadOnly,
1956
+ hideOnCreate,
1957
+ config,
1958
+ description,
1959
+ placeholder,
1960
+ helpText,
1961
+ renderLabel,
1962
+ renderError,
1963
+ renderStatus,
1964
+ analytics
1965
+ } = props;
1966
+ const { injectedFields } = UseInjectedFieldContext();
1967
+ const { control, getValues } = (0, import_react_hook_form2.useFormContext)();
1968
+ const previousValueRef = import_react7.default.useRef(void 0);
1969
+ import_react7.default.useEffect(() => {
1970
+ trackRender(fieldName);
1971
+ });
1972
+ const isDisabled = disabled ?? false;
1973
+ const fieldNameConst = `${fieldName}`;
1974
+ const FieldComponent = import_react7.default.useMemo(() => {
1975
+ const isReadOnly = readOnly || isDisabled && (isNull(skipLayoutReadOnly) || !isNull(skipLayoutReadOnly) && !skipLayoutReadOnly);
1976
+ if (isCreate && hideOnCreate || hidden) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
1977
+ if (!isEmpty(injectedFields) && injectedFields[type]) {
1978
+ const Comp = injectedFields[type];
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1980
+ import_react_hook_form2.Controller,
1981
+ {
1982
+ name: fieldNameConst,
1983
+ control,
1984
+ rules: {
1985
+ required: required2 && type !== ComponentTypes.Toggle && !isReadOnly ? { value: true, message: FormStrings.required } : void 0,
1986
+ validate: async (value) => {
1987
+ if (!validate || validate.length === 0 || isReadOnly || !value) return void 0;
1988
+ const fieldState = { validate };
1989
+ const syncError = CheckFieldValidationRules(value, fieldName, getValues(), fieldState);
1990
+ if (syncError) return syncError;
1991
+ return CheckAsyncFieldValidationRules(value, fieldName, getValues(), fieldState);
1992
+ }
1993
+ },
1994
+ render: ({
1995
+ field: { value },
1996
+ fieldState: { error, isDirty },
1997
+ formState: { isSubmitting, isSubmitSuccessful, errors }
1998
+ }) => {
1999
+ const errorCount = errors ? Object.keys(errors).length : 0;
2000
+ const saving = isDirty && (isSubmitting || isSubmitSuccessful);
2001
+ const savePending = isDirty && errorCount > 0 && !isSubmitting && !isSubmitSuccessful;
2002
+ if (error && analytics) {
2003
+ analytics.trackValidationError(fieldName, [error.message || "Error"]);
2004
+ }
2005
+ if (previousValueRef.current !== void 0 && previousValueRef.current !== value && analytics) {
2006
+ analytics.trackFieldChange(fieldName, previousValueRef.current, value);
2007
+ }
2008
+ previousValueRef.current = value;
2009
+ return type === "DynamicFragment" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: import_react7.default.cloneElement(Comp, { value }) }) : ShowField(filterText, value, label) && !softHidden ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2010
+ FieldWrapper,
2011
+ {
2012
+ id: fieldName,
2013
+ required: required2,
2014
+ label,
2015
+ error,
2016
+ errorCount,
2017
+ saving,
2018
+ savePending,
2019
+ labelClassName: "form-label",
2020
+ isManualSave,
2021
+ renderLabel,
2022
+ renderError,
2023
+ renderStatus,
2024
+ children: import_react7.default.cloneElement(Comp, {
2025
+ fieldName,
2026
+ entityId,
2027
+ entityType,
2028
+ parentEntityId,
2029
+ parentEntityType,
2030
+ programName,
2031
+ value,
2032
+ readOnly: isReadOnly,
2033
+ required: required2,
2034
+ error,
2035
+ errorCount,
2036
+ saving,
2037
+ savePending,
2038
+ config,
2039
+ options,
2040
+ label,
2041
+ type,
2042
+ description,
2043
+ placeholder,
2044
+ helpText,
2045
+ setFieldValue,
2046
+ onFocus: analytics ? () => analytics.trackFieldFocus(fieldName) : void 0,
2047
+ onBlur: analytics ? () => analytics.trackFieldBlur(fieldName) : void 0
2048
+ })
2049
+ }
2050
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
2051
+ }
2052
+ }
2053
+ );
2054
+ }
2055
+ const available = !isEmpty(injectedFields) ? Object.keys(injectedFields).join(", ") : "none";
2056
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { color: "red", fontSize: "0.85em", padding: "4px" }, children: [
2057
+ 'Missing component "',
2058
+ type,
2059
+ '" for field "',
2060
+ fieldName,
2061
+ '". Available: [',
2062
+ available,
2063
+ "]"
2064
+ ] });
2065
+ }, [
2066
+ type,
2067
+ hidden,
2068
+ required2,
2069
+ readOnly,
2070
+ disabled,
2071
+ options,
2072
+ softHidden,
2073
+ renderLabel,
2074
+ renderError,
2075
+ renderStatus,
2076
+ fieldName,
2077
+ fieldNameConst,
2078
+ label,
2079
+ validate,
2080
+ config,
2081
+ description,
2082
+ placeholder,
2083
+ helpText,
2084
+ isCreate,
2085
+ hideOnCreate,
2086
+ isManualSave,
2087
+ skipLayoutReadOnly,
2088
+ entityId,
2089
+ entityType,
2090
+ programName,
2091
+ parentEntityId,
2092
+ parentEntityType,
2093
+ injectedFields,
2094
+ analytics,
2095
+ control,
2096
+ getValues,
2097
+ setFieldValue
2098
+ ]);
2099
+ return FieldComponent;
2100
+ };
2101
+ var RenderField_default = import_react7.default.memo(RenderField);
2102
+
2103
+ // src/components/ConfirmInputsModal.tsx
2104
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2105
+ function getFocusableElements(container) {
2106
+ const selector = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
2107
+ return Array.from(container.querySelectorAll(selector));
2108
+ }
2109
+ var ConfirmInputsModal = (props) => {
2110
+ const {
2111
+ isOpen,
2112
+ configName,
2113
+ entityId,
2114
+ entityType,
2115
+ programName,
2116
+ fields,
2117
+ confirmInputFields,
2118
+ saveConfirmInputFields,
2119
+ cancelConfirmInputFields,
2120
+ renderDialog
2121
+ } = props;
2122
+ const { setValue, trigger } = (0, import_react_hook_form3.useFormContext)();
2123
+ const { rulesState } = UseRulesEngineContext();
2124
+ const dialogRef = import_react8.default.useRef(null);
2125
+ const previouslyFocusedRef = import_react8.default.useRef(null);
2126
+ const saveButtonRef = import_react8.default.useRef(null);
2127
+ import_react8.default.useEffect(() => {
2128
+ if (isOpen && dialogRef.current && !dialogRef.current.open) {
2129
+ previouslyFocusedRef.current = document.activeElement;
2130
+ dialogRef.current.showModal();
2131
+ saveButtonRef.current?.focus();
2132
+ } else if (!isOpen && dialogRef.current?.open) {
2133
+ dialogRef.current.close();
2134
+ if (previouslyFocusedRef.current instanceof HTMLElement) previouslyFocusedRef.current.focus();
2135
+ previouslyFocusedRef.current = null;
2136
+ }
2137
+ }, [isOpen]);
2138
+ import_react8.default.useEffect(() => {
2139
+ const dialog = dialogRef.current;
2140
+ if (!dialog) return;
2141
+ const handleCancel = (e) => {
2142
+ e.preventDefault();
2143
+ cancelConfirmInputFields();
2144
+ };
2145
+ dialog.addEventListener("cancel", handleCancel);
2146
+ return () => {
2147
+ dialog.removeEventListener("cancel", handleCancel);
2148
+ };
2149
+ }, [cancelConfirmInputFields]);
2150
+ const handleKeyDown = import_react8.default.useCallback((e) => {
2151
+ if (e.key !== "Tab" || !dialogRef.current) return;
2152
+ const focusableElements = getFocusableElements(dialogRef.current);
2153
+ if (focusableElements.length === 0) return;
2154
+ const first = focusableElements[0];
2155
+ const last = focusableElements[focusableElements.length - 1];
2156
+ if (e.shiftKey) {
2157
+ if (document.activeElement === first) {
2158
+ e.preventDefault();
2159
+ last.focus();
2160
+ }
2161
+ } else {
2162
+ if (document.activeElement === last) {
2163
+ e.preventDefault();
2164
+ first.focus();
2165
+ }
2166
+ }
2167
+ }, []);
2168
+ const setValueFunctionFieldValue = (fieldName, fieldValue) => {
2169
+ trigger();
2170
+ setValue(`${fieldName}`, fieldValue, { shouldDirty: true });
2171
+ };
2172
+ const content = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dynamic-form-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dynamic-form-container", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("form", { className: "dynamic-form modal", children: confirmInputFields?.map((confirmInputField) => {
2173
+ const fieldState = rulesState.configs[configName]?.fieldStates[confirmInputField];
2174
+ const fieldConfig = fields[confirmInputField];
2175
+ if (!fieldState || !fieldConfig) return null;
2176
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2177
+ RenderField_default,
2178
+ {
2179
+ fieldName: confirmInputField,
2180
+ entityId,
2181
+ entityType,
2182
+ programName,
2183
+ type: fieldState.type ?? "",
2184
+ required: true,
2185
+ options: fieldState.options,
2186
+ validate: fieldState.validate,
2187
+ isManualSave: true,
2188
+ setFieldValue: setValueFunctionFieldValue,
2189
+ label: fieldConfig.label,
2190
+ skipLayoutReadOnly: true,
2191
+ hideOnCreate: fieldConfig.hideOnCreate,
2192
+ config: fieldConfig.config
2193
+ },
2194
+ `${confirmInputField}-${entityId}-modal`
2195
+ );
2196
+ }) }) }) });
2197
+ if (renderDialog) {
2198
+ return renderDialog({ isOpen: !!isOpen, onSave: saveConfirmInputFields, onCancel: cancelConfirmInputFields, children: content });
2199
+ }
2200
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("dialog", { ref: dialogRef, className: "dynamic-form-modal", role: "dialog", "aria-modal": "true", "aria-label": FormStrings.confirm, onKeyDown: handleKeyDown, children: [
2201
+ content,
2202
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dynamic-form-modal-actions", children: [
2203
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", ref: saveButtonRef, onClick: saveConfirmInputFields, children: FormStrings.save }),
2204
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", onClick: cancelConfirmInputFields, children: FormStrings.cancel })
2205
+ ] })
2206
+ ] });
2207
+ };
2208
+ var ConfirmInputsModal_default = ConfirmInputsModal;
2209
+
2210
+ // src/components/InlineFormFields.tsx
2211
+ var import_react10 = __toESM(require("react"));
2212
+
2213
+ // src/components/FormErrorBoundary.tsx
2214
+ var import_react9 = __toESM(require("react"));
2215
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2216
+ var FormErrorBoundary = class extends import_react9.default.Component {
2217
+ constructor(props) {
2218
+ super(props);
2219
+ this.resetError = () => {
2220
+ this.setState({ hasError: false, error: null });
2221
+ };
2222
+ this.state = { hasError: false, error: null };
2223
+ }
2224
+ static getDerivedStateFromError(error) {
2225
+ return { hasError: true, error };
2226
+ }
2227
+ componentDidCatch(error, errorInfo) {
2228
+ this.props.onError?.(error, errorInfo);
2229
+ }
2230
+ render() {
2231
+ if (this.state.hasError && this.state.error) {
2232
+ if (this.props.fallback) return this.props.fallback(this.state.error, this.resetError);
2233
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "form-error-boundary", role: "alert", children: [
2234
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "error-boundary-message", children: [
2235
+ "Something went wrong: ",
2236
+ this.state.error.message
2237
+ ] }),
2238
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "error-boundary-retry", onClick: this.resetError, type: "button", children: "Retry" })
2239
+ ] });
2240
+ }
2241
+ return this.props.children;
2242
+ }
2243
+ };
2244
+
2245
+ // src/components/InlineFormFields.tsx
2246
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2247
+ var FormFields = (props) => {
2248
+ const {
2249
+ entityId,
2250
+ entityType,
2251
+ programName,
2252
+ parentEntityId,
2253
+ parentEntityType,
2254
+ isExpanded,
2255
+ expandEnabled,
2256
+ fieldOrder,
2257
+ inPanel,
2258
+ collapsedMaxHeight,
2259
+ formState,
2260
+ fields,
2261
+ setFieldValue,
2262
+ isManualSave,
2263
+ isCreate,
2264
+ filterText,
2265
+ fieldRenderLimit,
2266
+ renderLabel,
2267
+ renderError,
2268
+ renderStatus,
2269
+ analytics
2270
+ } = props;
2271
+ const collapsedClass = !isExpanded && (expandEnabled || expandEnabled === void 0) ? "collapsed" : "";
2272
+ const fieldsToRender = GetFieldsToRender(fieldRenderLimit ?? 0, fieldOrder ?? [], formState?.fieldStates);
2273
+ const loadingKey = `${programName}-${entityType}-${entityId}-form-loaded`;
2274
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `dynamic-form-container ${collapsedClass}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2275
+ "form",
2276
+ {
2277
+ className: `dynamic-form ${collapsedClass} ${inPanel ? "in-panel" : ""}`,
2278
+ style: collapsedClass && collapsedMaxHeight ? { maxHeight: `${collapsedMaxHeight}px` } : void 0,
2279
+ "data-testid": `${programName}-${entityType}-${entityId}-form`,
2280
+ children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "hidden", id: loadingKey, name: loadingKey, "data-testid": loadingKey }),
2282
+ fieldsToRender?.map((fieldToRender) => {
2283
+ const { fieldName, softHidden } = fieldToRender;
2284
+ const fieldState = formState?.fieldStates[fieldName];
2285
+ if (!fieldState) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react10.default.Fragment, {}, fieldName);
2286
+ const fieldConfig = fields[fieldName];
2287
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FormErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2288
+ RenderField_default,
2289
+ {
2290
+ fieldName,
2291
+ entityId,
2292
+ entityType,
2293
+ programName,
2294
+ type: fieldState.type ?? "",
2295
+ hidden: fieldState.hidden,
2296
+ required: fieldState.required,
2297
+ readOnly: fieldState.readOnly,
2298
+ options: fieldState.options,
2299
+ validate: fieldState.validate,
2300
+ parentEntityId,
2301
+ parentEntityType,
2302
+ setFieldValue,
2303
+ isManualSave,
2304
+ isCreate,
2305
+ filterText,
2306
+ softHidden,
2307
+ label: fieldState?.label ?? fieldConfig?.label,
2308
+ skipLayoutReadOnly: fieldConfig?.skipLayoutReadOnly,
2309
+ hideOnCreate: fieldConfig?.hideOnCreate,
2310
+ config: fieldConfig?.config,
2311
+ description: fieldConfig?.description,
2312
+ placeholder: fieldConfig?.placeholder,
2313
+ helpText: fieldConfig?.helpText,
2314
+ renderLabel,
2315
+ renderError,
2316
+ renderStatus,
2317
+ analytics
2318
+ }
2319
+ ) }, `${fieldName}-${entityId}-form`);
2320
+ })
2321
+ ]
2322
+ }
2323
+ ) });
2324
+ };
2325
+
2326
+ // src/components/InlineForm.tsx
2327
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2328
+ var FormEngine = (props) => {
2329
+ const {
2330
+ configName,
2331
+ entityId,
2332
+ entityType,
2333
+ programName,
2334
+ parentEntityId,
2335
+ parentEntityType,
2336
+ entityPath,
2337
+ expandCutoffCount,
2338
+ formConfig,
2339
+ defaultValues,
2340
+ areAllFieldsReadonly,
2341
+ collapsedMaxHeight,
2342
+ isCreate,
2343
+ parentEntity,
2344
+ isChildEntity,
2345
+ enableFilter,
2346
+ currentUserId,
2347
+ onSaveError,
2348
+ isManualSave = false,
2349
+ saveTimeoutMs = 3e4,
2350
+ maxSaveRetries = 3,
2351
+ renderExpandButton,
2352
+ renderFilterInput,
2353
+ renderDialog,
2354
+ renderSaveButton,
2355
+ formErrors,
2356
+ renderLabel,
2357
+ renderError,
2358
+ renderStatus
2359
+ } = props;
2360
+ const fields = formConfig?.fields ?? props.fieldConfigs ?? {};
2361
+ const formSettings = formConfig?.settings;
2362
+ const effectiveManualSave = formSettings?.manualSave ?? isManualSave;
2363
+ const effectiveSaveTimeout = formSettings?.saveTimeoutMs ?? saveTimeoutMs;
2364
+ const effectiveMaxRetries = formSettings?.maxSaveRetries ?? maxSaveRetries;
2365
+ const effectiveExpandCutoff = formSettings?.expandCutoffCount ?? expandCutoffCount;
2366
+ const analytics = useFormAnalytics(formSettings?.analytics);
2367
+ const saveData = props.saveData ? props.saveData : () => Promise.resolve({});
2368
+ const { initFormState, processFieldChange, rulesState } = UseRulesEngineContext();
2369
+ const saveTimeoutDelay = import_react11.default.useRef(void 0);
2370
+ const saveTimeout = import_react11.default.useRef(void 0);
2371
+ const confirmInputModalProps = import_react11.default.useRef(void 0);
2372
+ const saveAbortControllerRef = import_react11.default.useRef(void 0);
2373
+ const [isExpanded, setIsExpanded] = import_react11.default.useState(false);
2374
+ const [expandEnabled, setExpandEnabled] = import_react11.default.useState();
2375
+ const [inputFieldsConfirmed, setInputFieldsConfirmed] = import_react11.default.useState(true);
2376
+ const [filterText, setFilterText] = import_react11.default.useState();
2377
+ const [statusMessage, setStatusMessage] = import_react11.default.useState("");
2378
+ const formMethods = (0, import_react_hook_form4.useForm)({ mode: "onChange", defaultValues });
2379
+ const { reset, resetField, handleSubmit, trigger, setValue, getValues, setError, clearErrors, formState } = formMethods;
2380
+ const rulesStateRef = import_react11.default.useRef(rulesState);
2381
+ const formStateRef = import_react11.default.useRef({ ...formState });
2382
+ const filterTimeoutRef = import_react11.default.useRef(void 0);
2383
+ const validateAndSaveRef = import_react11.default.useRef(void 0);
2384
+ const { isDirty, isValid, dirtyFields, errors, isSubmitting, isSubmitSuccessful } = formState;
2385
+ import_react11.default.useEffect(() => {
2386
+ rulesStateRef.current = rulesState;
2387
+ }, [rulesState]);
2388
+ import_react11.default.useEffect(() => {
2389
+ formStateRef.current = formState;
2390
+ }, [formState]);
2391
+ import_react11.default.useEffect(() => {
2392
+ initForm(defaultValues);
2393
+ }, [areAllFieldsReadonly]);
2394
+ const initForm = (entityData) => {
2395
+ const { formState: loadedState, initEntityData } = isCreate ? InitOnCreateFormState(configName, fields, entityData, parentEntity ?? {}, currentUserId ?? "", setValue, initFormState) : InitOnEditFormState(configName, fields, entityData, areAllFieldsReadonly ?? false, initFormState);
2396
+ setExpandEnabled(IsExpandVisible(loadedState.fieldStates, effectiveExpandCutoff));
2397
+ CheckValidDropdownOptions(loadedState.fieldStates, initEntityData, setValue);
2398
+ };
2399
+ import_react11.default.useEffect(() => {
2400
+ if (rulesState.configs[configName]) {
2401
+ const cfg = rulesState.configs[configName];
2402
+ CheckValidDropdownOptions(cfg.fieldStates, getValues(), setValue);
2403
+ CheckDefaultValues(cfg.fieldStates, getValues(), setValue);
2404
+ handleComputedValues();
2405
+ }
2406
+ }, [rulesState]);
2407
+ const attemptSave = import_react11.default.useCallback(() => {
2408
+ if (saveTimeout.current) {
2409
+ clearTimeout(saveTimeout.current);
2410
+ saveTimeout.current = void 0;
2411
+ }
2412
+ saveTimeout.current = setTimeout(() => {
2413
+ validateAndSaveRef.current?.();
2414
+ clearTimeout(saveTimeout.current);
2415
+ saveTimeout.current = void 0;
2416
+ }, saveTimeoutDelay?.current || 100);
2417
+ }, []);
2418
+ const setFieldValue = (fieldName, fieldValue, skipSave, timeout) => {
2419
+ saveTimeoutDelay.current = timeout;
2420
+ setValue(`${fieldName}`, fieldValue, { shouldDirty: !skipSave });
2421
+ trigger(fieldName);
2422
+ processFieldChange(getValues(), configName, fieldName, fields);
2423
+ if (!skipSave && !effectiveManualSave) {
2424
+ attemptSave();
2425
+ }
2426
+ };
2427
+ const manualSave = import_react11.default.useCallback(() => {
2428
+ validateAndSaveRef.current?.();
2429
+ }, []);
2430
+ const saveConfirmInputFields = () => {
2431
+ trigger().then((valid) => {
2432
+ if (valid) {
2433
+ setInputFieldsConfirmed(true);
2434
+ attemptSave();
2435
+ }
2436
+ });
2437
+ };
2438
+ const handleComputedValues = () => {
2439
+ const { dirtyFields: dirtyFields2 } = formStateRef.current;
2440
+ const currentRulesState = rulesStateRef.current;
2441
+ const cfg = currentRulesState.configs[configName];
2442
+ if (!cfg) return;
2443
+ const computedValues = GetComputedValuesOnDirtyFields(Object.keys(dirtyFields2), cfg.fieldStates);
2444
+ if (computedValues.length > 0) {
2445
+ computedValues.forEach((cv) => {
2446
+ const result = ExecuteComputedValue(cv.expression, getValues(), cv.fieldName);
2447
+ setValue(`${cv.fieldName}`, result, { shouldDirty: true });
2448
+ });
2449
+ }
2450
+ };
2451
+ const focusFirstError = () => {
2452
+ if (typeof document === "undefined") return;
2453
+ const currentErrors = formStateRef.current.errors;
2454
+ const errorFieldNames = Object.keys(currentErrors);
2455
+ if (errorFieldNames.length > 0) {
2456
+ const element = document.getElementById(errorFieldNames[0]) || document.querySelector(`[name="${errorFieldNames[0]}"]`);
2457
+ if (element && typeof element.focus === "function") element.focus();
2458
+ }
2459
+ };
2460
+ const validateAndSave = () => {
2461
+ const { dirtyFields: dirtyFields2 } = formStateRef.current;
2462
+ const currentRulesState = rulesStateRef.current;
2463
+ const cfg = currentRulesState.configs[configName];
2464
+ if (cfg?.fieldStates) {
2465
+ Object.keys(cfg.fieldStates).forEach((fieldName) => {
2466
+ if (cfg.fieldStates[fieldName]?.hidden) clearErrors(fieldName);
2467
+ });
2468
+ }
2469
+ setStatusMessage(FormStrings.validating);
2470
+ trigger().then((valid) => {
2471
+ if (!valid) {
2472
+ setIsExpanded(true);
2473
+ setStatusMessage("");
2474
+ (typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : setTimeout)(() => focusFirstError());
2475
+ } else {
2476
+ const newConfirmInputModalProps = confirmInputModalProps.current === void 0 ? GetConfirmInputModalProps(Object.keys(dirtyFields2), cfg?.fieldStates ?? {}) : void 0;
2477
+ if (newConfirmInputModalProps && !isEmpty(newConfirmInputModalProps.confirmInputsTriggeredBy) && (newConfirmInputModalProps.dependentFieldNames?.length ?? 0) > 0) {
2478
+ confirmInputModalProps.current = newConfirmInputModalProps;
2479
+ setInputFieldsConfirmed(false);
2480
+ setStatusMessage("");
2481
+ } else if (dirtyFields2 && Object.keys(dirtyFields2).length > 0) {
2482
+ setStatusMessage(FormStrings.saving);
2483
+ handleSubmit(handleSave)();
2484
+ confirmInputModalProps.current = void 0;
2485
+ } else {
2486
+ setStatusMessage("");
2487
+ }
2488
+ }
2489
+ });
2490
+ };
2491
+ validateAndSaveRef.current = validateAndSave;
2492
+ const handleSave = (data) => {
2493
+ if (saveAbortControllerRef.current) saveAbortControllerRef.current.abort();
2494
+ const abortController = new AbortController();
2495
+ saveAbortControllerRef.current = abortController;
2496
+ const dirtyFieldNames = Object.keys(formStateRef.current.dirtyFields);
2497
+ const saveWithTimeoutAndRetry = async (attempt) => {
2498
+ if (abortController.signal.aborted) return;
2499
+ const timeoutPromise = new Promise((_, reject) => {
2500
+ setTimeout(() => reject(new Error(FormStrings.saveTimeout)), effectiveSaveTimeout);
2501
+ });
2502
+ try {
2503
+ const updatedEntity = await Promise.race([saveData(data, dirtyFieldNames), timeoutPromise]);
2504
+ if (abortController.signal.aborted) return;
2505
+ setStatusMessage(FormStrings.saved);
2506
+ analytics.trackFormSubmit(data);
2507
+ if (!isCreate) handleDirtyFields(updatedEntity, data);
2508
+ } catch (error) {
2509
+ if (abortController.signal.aborted) return;
2510
+ if (attempt < effectiveMaxRetries) {
2511
+ const delay = Math.pow(2, attempt) * 1e3;
2512
+ await new Promise((resolve) => setTimeout(resolve, delay));
2513
+ if (abortController.signal.aborted) return;
2514
+ return saveWithTimeoutAndRetry(attempt + 1);
2515
+ }
2516
+ setStatusMessage(FormStrings.saveFailed);
2517
+ dirtyFieldNames.forEach((field) => {
2518
+ setError(field, { type: "custom", message: FormStrings.saveError });
2519
+ });
2520
+ onSaveError?.(`${FormStrings.saveError}${error ? `: ${error}` : ""}`);
2521
+ }
2522
+ };
2523
+ saveWithTimeoutAndRetry(0);
2524
+ };
2525
+ const handleDirtyFields = (entity, data) => {
2526
+ const { dirtyFields: dirtyFields2 } = formStateRef.current;
2527
+ const stillDirtyFields = {};
2528
+ Object.keys(dirtyFields2).forEach((field) => {
2529
+ stillDirtyFields[field] = getValues(field);
2530
+ });
2531
+ const resetValue = isChildEntity ? GetChildEntity(entityId, entity, entityPath) ?? entity : entity;
2532
+ reset(resetValue);
2533
+ Object.keys(stillDirtyFields).forEach((field) => {
2534
+ if (JSON.stringify(stillDirtyFields[field]) !== JSON.stringify(data[field])) {
2535
+ setFieldValue(field, stillDirtyFields[field], false, saveTimeoutDelay?.current);
2536
+ }
2537
+ });
2538
+ };
2539
+ const onFilterChange = import_react11.default.useCallback((value) => {
2540
+ if (filterTimeoutRef.current) clearTimeout(filterTimeoutRef.current);
2541
+ filterTimeoutRef.current = setTimeout(() => setFilterText(value), 500);
2542
+ }, []);
2543
+ const cancelConfirmInputFields = () => {
2544
+ const current = confirmInputModalProps.current;
2545
+ if (current && current.otherDirtyFields && current.otherDirtyFields.length > 0) {
2546
+ if (current.confirmInputsTriggeredBy) resetField(current.confirmInputsTriggeredBy);
2547
+ if (current.dependentFieldNames) current.dependentFieldNames.forEach((n) => resetField(n));
2548
+ saveData(getValues(), current.otherDirtyFields).then((updatedEntity) => initForm(updatedEntity));
2549
+ } else {
2550
+ reset();
2551
+ initForm(getValues());
2552
+ }
2553
+ setInputFieldsConfirmed(true);
2554
+ confirmInputModalProps.current = void 0;
2555
+ };
2556
+ const cutoff = expandEnabled && !isExpanded ? effectiveExpandCutoff ?? FormConstants.defaultExpandCutoffCount : void 0;
2557
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_hook_form4.FormProvider, { ...formMethods, formState: { ...formMethods.formState, isDirty, isValid, dirtyFields, errors, isSubmitting, isSubmitSuccessful }, children: [
2558
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "status", "aria-live": "polite", className: "sr-only", style: { position: "absolute", width: "1px", height: "1px", padding: 0, margin: "-1px", overflow: "hidden", clip: "rect(0, 0, 0, 0)", whiteSpace: "nowrap", border: 0 }, "data-testid": "form-status-live-region", children: statusMessage }),
2559
+ enableFilter && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dynamic-form-filter", children: renderFilterInput ? renderFilterInput({ onChange: onFilterChange }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "text", placeholder: FormStrings.filterFields, "aria-label": FormStrings.filterFields, onChange: (e) => onFilterChange(e.target.value), className: "dynamic-form-filter-input" }) }),
2560
+ formErrors && formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "form-errors", role: "alert", style: { color: "var(--form-error-color, #d13438)", padding: "8px", marginBottom: "8px" }, children: formErrors.map((err, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "form-error-item", children: err }, i)) }),
2561
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dynamic-form-wrapper", children: [
2562
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2563
+ FormFields,
2564
+ {
2565
+ entityId,
2566
+ entityType,
2567
+ programName,
2568
+ parentEntityId,
2569
+ parentEntityType,
2570
+ isExpanded,
2571
+ expandEnabled,
2572
+ fieldOrder: rulesState?.configs[configName]?.fieldOrder,
2573
+ collapsedMaxHeight,
2574
+ formState: rulesState?.configs[configName],
2575
+ fields,
2576
+ setFieldValue,
2577
+ isManualSave: effectiveManualSave,
2578
+ isCreate,
2579
+ filterText,
2580
+ fieldRenderLimit: cutoff,
2581
+ renderLabel,
2582
+ renderError,
2583
+ renderStatus,
2584
+ analytics
2585
+ }
2586
+ ),
2587
+ expandEnabled && (renderExpandButton ? renderExpandButton({ isExpanded, onToggle: () => setIsExpanded(!isExpanded) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "expand-button", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, "data-testid": `${programName}-${entityType}-${entityId}-expand-form`, children: isExpanded ? FormStrings.seeLess : FormStrings.expand })),
2588
+ effectiveManualSave && (renderSaveButton ? renderSaveButton({ onSave: manualSave, isDirty, isValid, isSubmitting }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dynamic-form-save-actions", style: { marginTop: "16px", display: "flex", gap: "8px" }, children: [
2589
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "save-button", onClick: manualSave, disabled: !isDirty || isSubmitting, children: isCreate ? FormStrings.create : FormStrings.save }),
2590
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "cancel-button", onClick: () => {
2591
+ reset();
2592
+ initForm(defaultValues);
2593
+ }, disabled: !isDirty || isSubmitting, children: FormStrings.cancel })
2594
+ ] }))
2595
+ ] }),
2596
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2597
+ ConfirmInputsModal_default,
2598
+ {
2599
+ isOpen: confirmInputModalProps !== void 0 && !inputFieldsConfirmed,
2600
+ configName,
2601
+ entityId,
2602
+ entityType,
2603
+ programName,
2604
+ fields,
2605
+ confirmInputFields: confirmInputModalProps?.current?.dependentFieldNames ?? [],
2606
+ cancelConfirmInputFields,
2607
+ saveConfirmInputFields,
2608
+ renderDialog
2609
+ }
2610
+ )
2611
+ ] });
2612
+ };
2613
+
2614
+ // src/components/FormDevTools.tsx
2615
+ var import_react12 = __toESM(require("react"));
2616
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2617
+ var FormDevTools = (props) => {
2618
+ const { configName, formState, formValues, formErrors, dirtyFields, enabled = true } = props;
2619
+ const [isOpen, setIsOpen] = import_react12.default.useState(false);
2620
+ const [activeTab, setActiveTab] = import_react12.default.useState("rules");
2621
+ const [timelineFilter, setTimelineFilter] = import_react12.default.useState("");
2622
+ const [depGraphSort, setDepGraphSort] = import_react12.default.useState("name");
2623
+ const [, forceUpdate] = import_react12.default.useReducer((x) => x + 1, 0);
2624
+ if (!enabled) return null;
2625
+ const fieldStates = formState?.fieldStates ?? {};
2626
+ const fieldNames = Object.keys(fieldStates);
2627
+ const dependencyGraph = import_react12.default.useMemo(() => {
2628
+ const lines = [];
2629
+ for (const [name, state] of Object.entries(fieldStates)) {
2630
+ if (state.dependentFields?.length) {
2631
+ lines.push(`${name} -> ${state.dependentFields.join(", ")}`);
2632
+ }
2633
+ if (state.dependsOnFields?.length) {
2634
+ lines.push(`${name} (depends on) ${state.dependsOnFields.join(", ")}`);
2635
+ }
2636
+ }
2637
+ return lines;
2638
+ }, [fieldStates]);
2639
+ const containerStyle = {
2640
+ position: "fixed",
2641
+ bottom: 0,
2642
+ right: 0,
2643
+ width: isOpen ? "520px" : "auto",
2644
+ maxHeight: isOpen ? "50vh" : "auto",
2645
+ background: "#1e1e1e",
2646
+ color: "#d4d4d4",
2647
+ fontFamily: "monospace",
2648
+ fontSize: "12px",
2649
+ zIndex: 9999,
2650
+ borderTopLeftRadius: "8px",
2651
+ overflow: "hidden",
2652
+ boxShadow: "0 -2px 10px rgba(0,0,0,0.3)"
2653
+ };
2654
+ const tabStyle = (active) => ({
2655
+ padding: "4px 8px",
2656
+ cursor: "pointer",
2657
+ background: active ? "#333" : "transparent",
2658
+ color: active ? "#fff" : "#888",
2659
+ border: "none",
2660
+ borderBottom: active ? "2px solid #007acc" : "2px solid transparent",
2661
+ fontFamily: "monospace",
2662
+ fontSize: "11px"
2663
+ });
2664
+ const thStyle = {
2665
+ textAlign: "left",
2666
+ padding: "3px 6px",
2667
+ borderBottom: "1px solid #555",
2668
+ fontWeight: "bold",
2669
+ color: "#fff",
2670
+ fontSize: "11px"
2671
+ };
2672
+ const tdStyle = {
2673
+ padding: "3px 6px",
2674
+ borderBottom: "1px solid #333",
2675
+ fontSize: "11px"
2676
+ };
2677
+ const btnStyle = {
2678
+ padding: "2px 8px",
2679
+ margin: "0 4px",
2680
+ cursor: "pointer",
2681
+ background: "#333",
2682
+ color: "#d4d4d4",
2683
+ border: "1px solid #555",
2684
+ fontFamily: "monospace",
2685
+ fontSize: "10px",
2686
+ borderRadius: "3px"
2687
+ };
2688
+ const renderPerformanceTab = () => {
2689
+ const counts = getRenderCounts();
2690
+ const lastRendered = getLastRenderedFields();
2691
+ const totalRenders = getTotalFormRenders();
2692
+ const entries = Array.from(counts.entries()).sort((a, b) => a[0].localeCompare(b[0]));
2693
+ const avgCount = entries.length > 0 ? entries.reduce((sum, [, c]) => sum + c, 0) / entries.length : 0;
2694
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2695
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginBottom: "6px", display: "flex", alignItems: "center", gap: "8px" }, children: [
2696
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
2697
+ "Total form renders: ",
2698
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { style: { color: "#4ec9b0" }, children: totalRenders })
2699
+ ] }),
2700
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: btnStyle, onClick: () => {
2701
+ resetRenderTracker();
2702
+ forceUpdate();
2703
+ }, children: "Reset" }),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: btnStyle, onClick: () => forceUpdate(), children: "Refresh" })
2705
+ ] }),
2706
+ entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: "No render data yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse" }, children: [
2707
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
2708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Field" }),
2709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Renders" }),
2710
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Last Cycle" }),
2711
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Hot" })
2712
+ ] }) }),
2713
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: entries.map(([fieldName, count]) => {
2714
+ const isHot = count > avgCount * 1.5;
2715
+ const wasLastRendered = lastRendered.has(fieldName);
2716
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { style: isHot ? { background: "#3e2a00" } : void 0, children: [
2717
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: fieldName }),
2718
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...tdStyle, color: isHot ? "#ff9900" : "#d4d4d4" }, children: count }),
2719
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: wasLastRendered ? "\u2713" : "" }),
2720
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: isHot ? "\u26A0" : "" })
2721
+ ] }, fieldName);
2722
+ }) })
2723
+ ] })
2724
+ ] });
2725
+ };
2726
+ const renderDepGraphTab = () => {
2727
+ const rows = [];
2728
+ let hasCycles = false;
2729
+ for (const [name, state] of Object.entries(fieldStates)) {
2730
+ const dependsOn = state.dependsOnFields ?? [];
2731
+ const dependedBy = state.dependentFields ?? [];
2732
+ const effects = [];
2733
+ if (state.hidden) effects.push("hidden");
2734
+ if (state.required) effects.push("required");
2735
+ if (state.readOnly) effects.push("readOnly");
2736
+ if (state.options && state.options.length > 0 && dependsOn.length > 0) effects.push("options");
2737
+ if (state.computedValue) effects.push("computed");
2738
+ rows.push({ name, dependsOn, dependedBy, effects });
2739
+ }
2740
+ for (const row of rows) {
2741
+ for (const dep of row.dependsOn) {
2742
+ const depRow = rows.find((r) => r.name === dep);
2743
+ if (depRow?.dependsOn.includes(row.name)) {
2744
+ hasCycles = true;
2745
+ break;
2746
+ }
2747
+ }
2748
+ if (hasCycles) break;
2749
+ }
2750
+ const depRows = rows.filter((r) => r.dependsOn.length > 0 || r.dependedBy.length > 0);
2751
+ if (depGraphSort === "name") {
2752
+ depRows.sort((a, b) => a.name.localeCompare(b.name));
2753
+ } else {
2754
+ depRows.sort((a, b) => b.dependsOn.length + b.dependedBy.length - (a.dependsOn.length + a.dependedBy.length));
2755
+ }
2756
+ const effectColor = (effects) => {
2757
+ if (effects.includes("hidden")) return { background: "#3e3a20" };
2758
+ if (effects.includes("required")) return { background: "#1e2a3e" };
2759
+ if (effects.includes("readOnly")) return { background: "#2a2a2a" };
2760
+ if (effects.includes("options")) return { background: "#1e3a2a" };
2761
+ return {};
2762
+ };
2763
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2764
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginBottom: "6px", display: "flex", alignItems: "center", gap: "8px" }, children: [
2765
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Sort by:" }),
2766
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: { ...btnStyle, borderColor: depGraphSort === "name" ? "#007acc" : "#555" }, onClick: () => setDepGraphSort("name"), children: "Name" }),
2767
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: { ...btnStyle, borderColor: depGraphSort === "depCount" ? "#007acc" : "#555" }, onClick: () => setDepGraphSort("depCount"), children: "Dep Count" }),
2768
+ hasCycles && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { color: "#f44747", fontWeight: "bold" }, children: "Cycles detected!" })
2769
+ ] }),
2770
+ depRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: "No dependencies defined." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse" }, children: [
2771
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
2772
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Field" }),
2773
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Depends On" }),
2774
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Depended By" }),
2775
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Effects" })
2776
+ ] }) }),
2777
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: depRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { style: effectColor(row.effects), children: [
2778
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: row.name }),
2779
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: row.dependsOn.join(", ") || "\u2014" }),
2780
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: row.dependedBy.join(", ") || "\u2014" }),
2781
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: row.effects.join(", ") || "\u2014" })
2782
+ ] }, row.name)) })
2783
+ ] })
2784
+ ] });
2785
+ };
2786
+ const renderTimelineTab = () => {
2787
+ const timeline2 = getTimeline();
2788
+ const filterLower = timelineFilter.toLowerCase();
2789
+ const filtered = filterLower ? timeline2.filter((e) => e.fieldName.toLowerCase().includes(filterLower) || e.type.toLowerCase().includes(filterLower)) : timeline2;
2790
+ const reversed = [...filtered].reverse();
2791
+ const typeColor = (type) => {
2792
+ switch (type) {
2793
+ case "field_change":
2794
+ return "#4ec9b0";
2795
+ case "rule_evaluated":
2796
+ return "#ce9178";
2797
+ case "validation_run":
2798
+ return "#dcdcaa";
2799
+ case "form_submit":
2800
+ return "#569cd6";
2801
+ default:
2802
+ return "#d4d4d4";
2803
+ }
2804
+ };
2805
+ const formatTime = (ts) => {
2806
+ const d = new Date(ts);
2807
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
2808
+ };
2809
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2810
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginBottom: "6px", display: "flex", alignItems: "center", gap: "8px" }, children: [
2811
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2812
+ "input",
2813
+ {
2814
+ type: "text",
2815
+ placeholder: "Filter by field or type...",
2816
+ value: timelineFilter,
2817
+ onChange: (e) => setTimelineFilter(e.target.value),
2818
+ style: {
2819
+ padding: "2px 6px",
2820
+ background: "#2d2d2d",
2821
+ color: "#d4d4d4",
2822
+ border: "1px solid #555",
2823
+ fontFamily: "monospace",
2824
+ fontSize: "11px",
2825
+ borderRadius: "3px",
2826
+ flex: 1
2827
+ }
2828
+ }
2829
+ ),
2830
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: btnStyle, onClick: () => {
2831
+ clearTimeline();
2832
+ forceUpdate();
2833
+ }, children: "Clear" }),
2834
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: btnStyle, onClick: () => forceUpdate(), children: "Refresh" })
2835
+ ] }),
2836
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontSize: "10px", color: "#888", marginBottom: "4px" }, children: [
2837
+ filtered.length,
2838
+ " event",
2839
+ filtered.length !== 1 ? "s" : ""
2840
+ ] }),
2841
+ reversed.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: "No events recorded yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse" }, children: [
2842
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
2843
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Time" }),
2844
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Type" }),
2845
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Field" }),
2846
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: thStyle, children: "Details" })
2847
+ ] }) }),
2848
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: reversed.slice(0, 200).map((event, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
2849
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...tdStyle, whiteSpace: "nowrap", color: "#888" }, children: formatTime(event.timestamp) }),
2850
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...tdStyle, color: typeColor(event.type), whiteSpace: "nowrap" }, children: event.type }),
2851
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: tdStyle, children: event.fieldName }),
2852
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...tdStyle, maxWidth: "200px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: event.details })
2853
+ ] }, i)) })
2854
+ ] })
2855
+ ] });
2856
+ };
2857
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: containerStyle, "data-testid": "form-devtools", children: [
2858
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", "aria-expanded": isOpen, "aria-controls": "devtools-content", style: { width: "100%", padding: "4px 8px", cursor: "pointer", background: "#333", display: "flex", justifyContent: "space-between", alignItems: "center", border: "none", color: "inherit", font: "inherit" }, onClick: () => setIsOpen(!isOpen), children: [
2859
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: "#007acc", fontWeight: "bold" }, children: [
2860
+ "DevTools: ",
2861
+ configName
2862
+ ] }),
2863
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: isOpen ? "\u25BC" : "\u25B2" })
2864
+ ] }),
2865
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2866
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { role: "tablist", "aria-label": "DevTools panels", style: { display: "flex", borderBottom: "1px solid #333", flexWrap: "wrap" }, children: [
2867
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { role: "tab", "aria-selected": activeTab === "rules", "aria-controls": "devtools-panel-rules", style: tabStyle(activeTab === "rules"), onClick: () => setActiveTab("rules"), children: [
2868
+ "Rules (",
2869
+ fieldNames.length,
2870
+ ")"
2871
+ ] }),
2872
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "values", "aria-controls": "devtools-panel-values", style: tabStyle(activeTab === "values"), onClick: () => setActiveTab("values"), children: "Values" }),
2873
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "errors", "aria-controls": "devtools-panel-errors", style: tabStyle(activeTab === "errors"), onClick: () => setActiveTab("errors"), children: "Errors" }),
2874
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "graph", "aria-controls": "devtools-panel-graph", style: tabStyle(activeTab === "graph"), onClick: () => setActiveTab("graph"), children: "Graph" }),
2875
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "performance", "aria-controls": "devtools-panel-performance", style: tabStyle(activeTab === "performance"), onClick: () => {
2876
+ setActiveTab("performance");
2877
+ forceUpdate();
2878
+ }, children: "Perf" }),
2879
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "depgraph", "aria-controls": "devtools-panel-depgraph", style: tabStyle(activeTab === "depgraph"), onClick: () => setActiveTab("depgraph"), children: "Deps" }),
2880
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { role: "tab", "aria-selected": activeTab === "timeline", "aria-controls": "devtools-panel-timeline", style: tabStyle(activeTab === "timeline"), onClick: () => {
2881
+ setActiveTab("timeline");
2882
+ forceUpdate();
2883
+ }, children: "Timeline" })
2884
+ ] }),
2885
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { role: "tabpanel", id: `devtools-panel-${activeTab}`, "aria-label": activeTab, style: { overflow: "auto", maxHeight: "calc(50vh - 60px)", padding: "8px" }, children: [
2886
+ activeTab === "rules" && fieldNames.map((name) => {
2887
+ const state = fieldStates[name];
2888
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginBottom: "8px", borderBottom: "1px solid #333", paddingBottom: "4px" }, children: [
2889
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { color: "#4ec9b0" }, children: name }),
2890
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2891
+ "type: ",
2892
+ state.type ?? "\u2014",
2893
+ " | required: ",
2894
+ String(state.required ?? false),
2895
+ " | hidden: ",
2896
+ String(state.hidden ?? false),
2897
+ " | readOnly: ",
2898
+ String(state.readOnly ?? false)
2899
+ ] }),
2900
+ state.validate?.length ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2901
+ "validate: ",
2902
+ state.validate.map((v) => v.name).join(", ")
2903
+ ] }) : null,
2904
+ state.computedValue ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2905
+ "computedValue: ",
2906
+ state.computedValue
2907
+ ] }) : null,
2908
+ state.activeRuleIds?.length ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2909
+ "activeRules: ",
2910
+ state.activeRuleIds.join(", ")
2911
+ ] }) : null
2912
+ ] }, name);
2913
+ }),
2914
+ activeTab === "values" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("pre", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: JSON.stringify(formValues, null, 2) }),
2915
+ activeTab === "errors" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("pre", { style: { margin: 0, whiteSpace: "pre-wrap", color: formErrors && Object.keys(formErrors).length > 0 ? "#f44747" : "#4ec9b0" }, children: formErrors && Object.keys(formErrors).length > 0 ? JSON.stringify(formErrors, null, 2) : "No errors" }),
2916
+ activeTab === "graph" && (dependencyGraph.length > 0 ? dependencyGraph.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { color: "#ce9178" }, children: line }, i)) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: "No dependencies defined" })),
2917
+ activeTab === "performance" && renderPerformanceTab(),
2918
+ activeTab === "depgraph" && renderDepGraphTab(),
2919
+ activeTab === "timeline" && renderTimelineTab()
2920
+ ] })
2921
+ ] })
2922
+ ] });
2923
+ };
2924
+
2925
+ // src/utils/rjsf/refResolver.ts
2926
+ function resolveRefs(schema) {
2927
+ const defs = {
2928
+ ...schema.definitions ?? {},
2929
+ ...schema.$defs ?? {}
2930
+ };
2931
+ const resolved = resolveNode(schema, defs, /* @__PURE__ */ new Set());
2932
+ const { definitions: _d, $defs: _dd, ...clean } = resolved;
2933
+ return clean;
2934
+ }
2935
+ function resolveNode(node, defs, visited) {
2936
+ if (node.$ref) {
2937
+ const refPath = node.$ref;
2938
+ if (visited.has(refPath)) {
2939
+ return { type: "string" };
2940
+ }
2941
+ const resolved = lookupRef(refPath, defs);
2942
+ if (!resolved) {
2943
+ return { type: "string" };
2944
+ }
2945
+ visited.add(refPath);
2946
+ const { $ref: _ref, ...siblings } = node;
2947
+ const inlined = resolveNode({ ...resolved, ...siblings }, defs, visited);
2948
+ visited.delete(refPath);
2949
+ return inlined;
2950
+ }
2951
+ const result = {};
2952
+ for (const [key, value] of Object.entries(node)) {
2953
+ if (key === "definitions" || key === "$defs") {
2954
+ continue;
2955
+ }
2956
+ if (key === "properties" && value && typeof value === "object") {
2957
+ const props = {};
2958
+ for (const [propName, propValue] of Object.entries(
2959
+ value
2960
+ )) {
2961
+ props[propName] = resolveNode(propValue, defs, visited);
2962
+ }
2963
+ result.properties = props;
2964
+ } else if (key === "items") {
2965
+ if (Array.isArray(value)) {
2966
+ result.items = value.map(
2967
+ (item) => resolveNode(item, defs, visited)
2968
+ );
2969
+ } else if (value && typeof value === "object") {
2970
+ result.items = resolveNode(value, defs, visited);
2971
+ }
2972
+ } else if ((key === "allOf" || key === "oneOf" || key === "anyOf") && Array.isArray(value)) {
2973
+ result[key] = value.map(
2974
+ (item) => resolveNode(item, defs, visited)
2975
+ );
2976
+ } else if (key === "if" || key === "then" || key === "else") {
2977
+ if (value && typeof value === "object") {
2978
+ result[key] = resolveNode(
2979
+ value,
2980
+ defs,
2981
+ visited
2982
+ );
2983
+ }
2984
+ } else if (key === "dependencies" && value && typeof value === "object") {
2985
+ const deps = {};
2986
+ for (const [depName, depValue] of Object.entries(
2987
+ value
2988
+ )) {
2989
+ if (Array.isArray(depValue)) {
2990
+ deps[depName] = depValue;
2991
+ } else if (typeof depValue === "object" && depValue !== null) {
2992
+ deps[depName] = resolveNode(
2993
+ depValue,
2994
+ defs,
2995
+ visited
2996
+ );
2997
+ }
2998
+ }
2999
+ result.dependencies = deps;
3000
+ } else if (key === "additionalProperties" && value && typeof value === "object") {
3001
+ result.additionalProperties = resolveNode(
3002
+ value,
3003
+ defs,
3004
+ visited
3005
+ );
3006
+ } else {
3007
+ result[key] = value;
3008
+ }
3009
+ }
3010
+ return result;
3011
+ }
3012
+ function lookupRef(ref, defs) {
3013
+ const match = ref.match(/^#\/(?:definitions|\$defs)\/(.+)$/);
3014
+ if (!match) return void 0;
3015
+ const path = match[1];
3016
+ const parts = path.split("/");
3017
+ let current = defs[parts[0]];
3018
+ for (let i = 1; i < parts.length && current; i++) {
3019
+ current = current[parts[i]];
3020
+ }
3021
+ return current;
3022
+ }
3023
+
3024
+ // src/utils/rjsf/fieldMapper.ts
3025
+ var WIDGET_MAP = {
3026
+ text: "Textbox",
3027
+ textarea: "Textarea",
3028
+ password: "Textbox",
3029
+ color: "Textbox",
3030
+ hidden: "DynamicFragment",
3031
+ select: "Dropdown",
3032
+ radio: "Dropdown",
3033
+ checkboxes: "Multiselect",
3034
+ updown: "Number",
3035
+ range: "Slider",
3036
+ date: "DateControl",
3037
+ datetime: "DateControl",
3038
+ "date-time": "DateControl",
3039
+ file: "DocumentLinks",
3040
+ checkbox: "Toggle"
3041
+ };
3042
+ var WIDGET_CONFIG = {
3043
+ password: { type: "password" },
3044
+ color: { type: "color" },
3045
+ radio: { display: "radio" },
3046
+ checkboxes: { display: "checkboxes" }
3047
+ };
3048
+ function schemaNodeToFieldConfig(fieldName, node, isRequired) {
3049
+ const type = mapTypeToComponent(node);
3050
+ const validate = extractValidationRules(node);
3051
+ const options = extractOptions(node);
3052
+ const config = {
3053
+ type,
3054
+ label: node.title ?? fieldName,
3055
+ required: isRequired
3056
+ };
3057
+ if (validate.length > 0) config.validate = validate;
3058
+ if (options) config.options = options;
3059
+ if (node.default !== void 0) config.defaultValue = node.default;
3060
+ if (node.description) config.description = node.description;
3061
+ if (node.const !== void 0) {
3062
+ config.readOnly = true;
3063
+ config.defaultValue = node.const;
3064
+ }
3065
+ return config;
3066
+ }
3067
+ function extractValidationRules(node) {
3068
+ const rules = [];
3069
+ if (node.minLength !== void 0) {
3070
+ rules.push({ name: "minLength", params: { min: node.minLength } });
3071
+ }
3072
+ if (node.maxLength !== void 0) {
3073
+ rules.push({ name: "maxLength", params: { max: node.maxLength } });
3074
+ }
3075
+ if (node.pattern) {
3076
+ rules.push({
3077
+ name: "pattern",
3078
+ params: { pattern: node.pattern, message: "Must match pattern" }
3079
+ });
3080
+ }
3081
+ const hasMin = node.minimum !== void 0;
3082
+ const hasMax = node.maximum !== void 0;
3083
+ const hasExclMin = node.exclusiveMinimum !== void 0;
3084
+ const hasExclMax = node.exclusiveMaximum !== void 0;
3085
+ if (hasExclMin || hasExclMax) {
3086
+ rules.push({
3087
+ name: "exclusiveNumericRange",
3088
+ params: {
3089
+ exclusiveMin: node.exclusiveMinimum,
3090
+ exclusiveMax: node.exclusiveMaximum,
3091
+ min: node.minimum,
3092
+ max: node.maximum
3093
+ }
3094
+ });
3095
+ } else if (hasMin || hasMax) {
3096
+ rules.push({
3097
+ name: "numericRange",
3098
+ params: {
3099
+ min: node.minimum ?? -Infinity,
3100
+ max: node.maximum ?? Infinity
3101
+ }
3102
+ });
3103
+ }
3104
+ if (node.multipleOf !== void 0) {
3105
+ rules.push({
3106
+ name: "multipleOf",
3107
+ params: { factor: node.multipleOf }
3108
+ });
3109
+ }
3110
+ if (node.format === "email") rules.push({ name: "email" });
3111
+ if (node.format === "uri" || node.format === "url") rules.push({ name: "url" });
3112
+ if (node.format === "phone") rules.push({ name: "phone" });
3113
+ if (node.uniqueItems) {
3114
+ rules.push({ name: "uniqueInArray" });
3115
+ }
3116
+ return rules;
3117
+ }
3118
+ function applyUiSchema(config, uiSchema) {
3119
+ const result = { ...config };
3120
+ const widget = uiSchema["ui:widget"];
3121
+ if (typeof widget === "string" && WIDGET_MAP[widget]) {
3122
+ result.type = WIDGET_MAP[widget];
3123
+ const extraConfig = WIDGET_CONFIG[widget];
3124
+ if (extraConfig) {
3125
+ result.config = { ...result.config ?? {}, ...extraConfig };
3126
+ }
3127
+ }
3128
+ if (uiSchema["ui:title"]) result.label = uiSchema["ui:title"];
3129
+ if (uiSchema["ui:description"])
3130
+ result.description = uiSchema["ui:description"];
3131
+ if (uiSchema["ui:help"]) result.helpText = uiSchema["ui:help"];
3132
+ if (uiSchema["ui:placeholder"])
3133
+ result.placeholder = uiSchema["ui:placeholder"];
3134
+ if (uiSchema["ui:hidden"] === true) result.hidden = true;
3135
+ if (uiSchema["ui:readonly"] === true) result.readOnly = true;
3136
+ if (uiSchema["ui:disabled"] === true) result.disabled = true;
3137
+ if (uiSchema["ui:autofocus"] === true) {
3138
+ result.config = { ...result.config ?? {}, autofocus: true };
3139
+ }
3140
+ if (uiSchema["ui:classNames"]) {
3141
+ result.config = {
3142
+ ...result.config ?? {},
3143
+ className: uiSchema["ui:classNames"]
3144
+ };
3145
+ }
3146
+ if (uiSchema["ui:options"] && typeof uiSchema["ui:options"] === "object") {
3147
+ result.config = { ...result.config ?? {}, ...uiSchema["ui:options"] };
3148
+ }
3149
+ if (uiSchema["ui:label"] === false) {
3150
+ result.config = { ...result.config ?? {}, hideLabel: true };
3151
+ }
3152
+ const enumDisabled = uiSchema["ui:enumDisabled"];
3153
+ if (Array.isArray(enumDisabled) && result.options) {
3154
+ result.options = result.options.map((opt) => ({
3155
+ ...opt,
3156
+ disabled: enumDisabled.includes(opt.value) ? true : opt.disabled
3157
+ }));
3158
+ }
3159
+ const enumNames = uiSchema["ui:enumNames"];
3160
+ if (Array.isArray(enumNames) && result.options) {
3161
+ result.options = result.options.map((opt, i) => ({
3162
+ ...opt,
3163
+ label: enumNames[i] != null ? String(enumNames[i]) : opt.label
3164
+ }));
3165
+ }
3166
+ return result;
3167
+ }
3168
+ function mapTypeToComponent(node) {
3169
+ if (node.enum) return "Dropdown";
3170
+ if (node.const !== void 0) return "Textbox";
3171
+ const type = resolveType(node);
3172
+ switch (type) {
3173
+ case "string":
3174
+ if (node.format === "date" || node.format === "date-time") return "DateControl";
3175
+ if (node.format === "data-url") return "DocumentLinks";
3176
+ if (node.maxLength && node.maxLength > 200) return "Textarea";
3177
+ return "Textbox";
3178
+ case "number":
3179
+ case "integer":
3180
+ if (node.minimum !== void 0 && node.maximum !== void 0) return "Slider";
3181
+ return "Number";
3182
+ case "boolean":
3183
+ return "Toggle";
3184
+ case "array":
3185
+ return mapArrayType(node);
3186
+ case "object":
3187
+ return "Textbox";
3188
+ // Objects handled at converter level
3189
+ default:
3190
+ return "Textbox";
3191
+ }
3192
+ }
3193
+ function resolveType(node) {
3194
+ if (!node.type) return "string";
3195
+ if (typeof node.type === "string") return node.type;
3196
+ const nonNull = node.type.filter((t) => t !== "null");
3197
+ return nonNull[0] ?? "string";
3198
+ }
3199
+ function mapArrayType(node) {
3200
+ const items = node.items;
3201
+ if (!items || Array.isArray(items)) return "Multiselect";
3202
+ if (items.enum) return "Multiselect";
3203
+ if (items.type === "object" && items.properties) return "FieldArray";
3204
+ return "Multiselect";
3205
+ }
3206
+ function extractOptions(node) {
3207
+ if (!node.enum) return void 0;
3208
+ const names = node.enumNames;
3209
+ return node.enum.map((val, i) => ({
3210
+ value: String(val),
3211
+ label: names && names[i] != null ? String(names[i]) : String(val)
3212
+ }));
3213
+ }
3214
+
3215
+ // src/utils/rjsf/ruleConverter.ts
3216
+ function convertDependencies(dependencies, fields, rootSchema, idPrefix) {
3217
+ for (const [sourceField, dep] of Object.entries(dependencies)) {
3218
+ if (Array.isArray(dep)) {
3219
+ for (const dependentField of dep) {
3220
+ if (!fields[dependentField]) continue;
3221
+ const rule = {
3222
+ id: `${idPrefix}_dep_${sourceField}_${dependentField}`,
3223
+ when: { field: sourceField, operator: "isNotEmpty" },
3224
+ then: { required: true },
3225
+ else: { required: false }
3226
+ };
3227
+ fields[dependentField].rules = [
3228
+ ...fields[dependentField].rules ?? [],
3229
+ rule
3230
+ ];
3231
+ }
3232
+ } else {
3233
+ convertSchemaDependency(sourceField, dep, fields, rootSchema, idPrefix);
3234
+ }
3235
+ }
3236
+ }
3237
+ function convertIfThenElse(schema, fields, rootSchema, idPrefix) {
3238
+ const condition = schemaToCondition(schema.if);
3239
+ if (!condition) return;
3240
+ const thenSchema = schema.then;
3241
+ const elseSchema = schema.else;
3242
+ const affectedFields = /* @__PURE__ */ new Set();
3243
+ if (thenSchema?.properties) {
3244
+ Object.keys(thenSchema.properties).forEach((f) => affectedFields.add(f));
3245
+ }
3246
+ if (thenSchema?.required) {
3247
+ thenSchema.required.forEach((f) => affectedFields.add(f));
3248
+ }
3249
+ if (elseSchema?.properties) {
3250
+ Object.keys(elseSchema.properties).forEach((f) => affectedFields.add(f));
3251
+ }
3252
+ if (elseSchema?.required) {
3253
+ elseSchema.required.forEach((f) => affectedFields.add(f));
3254
+ }
3255
+ for (const fieldName of affectedFields) {
3256
+ if (!fields[fieldName] && thenSchema?.properties?.[fieldName]) {
3257
+ fields[fieldName] = schemaNodeToFieldConfig(
3258
+ fieldName,
3259
+ thenSchema.properties[fieldName],
3260
+ false
3261
+ );
3262
+ fields[fieldName].hidden = true;
3263
+ }
3264
+ if (!fields[fieldName] && elseSchema?.properties?.[fieldName]) {
3265
+ fields[fieldName] = schemaNodeToFieldConfig(
3266
+ fieldName,
3267
+ elseSchema.properties[fieldName],
3268
+ false
3269
+ );
3270
+ fields[fieldName].hidden = true;
3271
+ }
3272
+ if (!fields[fieldName]) continue;
3273
+ const thenEffect = {};
3274
+ const elseEffect = {};
3275
+ if (thenSchema?.properties?.[fieldName]) {
3276
+ thenEffect.hidden = false;
3277
+ }
3278
+ if (elseSchema?.properties?.[fieldName]) {
3279
+ elseEffect.hidden = false;
3280
+ }
3281
+ if (thenSchema?.properties?.[fieldName] && !elseSchema?.properties?.[fieldName]) {
3282
+ elseEffect.hidden = true;
3283
+ }
3284
+ if (!thenSchema?.properties?.[fieldName] && elseSchema?.properties?.[fieldName]) {
3285
+ thenEffect.hidden = true;
3286
+ }
3287
+ if (thenSchema?.required?.includes(fieldName)) {
3288
+ thenEffect.required = true;
3289
+ }
3290
+ if (elseSchema?.required?.includes(fieldName)) {
3291
+ elseEffect.required = true;
3292
+ }
3293
+ const rule = {
3294
+ id: `${idPrefix}_ite_${fieldName}`,
3295
+ when: condition,
3296
+ then: thenEffect
3297
+ };
3298
+ if (Object.keys(elseEffect).length > 0) {
3299
+ rule.else = elseEffect;
3300
+ }
3301
+ fields[fieldName].rules = [...fields[fieldName].rules ?? [], rule];
3302
+ }
3303
+ }
3304
+ function convertComposition(schema, fields, rootSchema, idPrefix) {
3305
+ const variants = schema.oneOf ?? schema.anyOf;
3306
+ if (!variants || variants.length === 0) return;
3307
+ const compositionType = schema.oneOf ? "oneOf" : "anyOf";
3308
+ const discriminator = findDiscriminator(variants);
3309
+ if (discriminator) {
3310
+ convertWithDiscriminator(
3311
+ discriminator,
3312
+ variants,
3313
+ fields,
3314
+ rootSchema,
3315
+ idPrefix,
3316
+ compositionType
3317
+ );
3318
+ } else {
3319
+ convertWithSyntheticDiscriminator(
3320
+ variants,
3321
+ fields,
3322
+ rootSchema,
3323
+ idPrefix,
3324
+ compositionType
3325
+ );
3326
+ }
3327
+ }
3328
+ function schemaToCondition(schema) {
3329
+ if (!schema) return null;
3330
+ if (schema.not) {
3331
+ const inner = schemaToCondition(schema.not);
3332
+ if (!inner) return null;
3333
+ return { operator: "not", conditions: [inner] };
3334
+ }
3335
+ if (schema.allOf && schema.allOf.length > 0) {
3336
+ const conditions = schema.allOf.map((s) => schemaToCondition(s)).filter((c) => c !== null);
3337
+ if (conditions.length === 0) return null;
3338
+ if (conditions.length === 1) return conditions[0];
3339
+ return { operator: "and", conditions };
3340
+ }
3341
+ if (schema.anyOf && schema.anyOf.length > 0) {
3342
+ const conditions = schema.anyOf.map((s) => schemaToCondition(s)).filter((c) => c !== null);
3343
+ if (conditions.length === 0) return null;
3344
+ if (conditions.length === 1) return conditions[0];
3345
+ return { operator: "or", conditions };
3346
+ }
3347
+ if (schema.required && !schema.properties) {
3348
+ const conditions = schema.required.map((field) => ({
3349
+ field,
3350
+ operator: "isNotEmpty"
3351
+ }));
3352
+ if (conditions.length === 1) return conditions[0];
3353
+ return { operator: "and", conditions };
3354
+ }
3355
+ if (schema.properties) {
3356
+ const conditions = [];
3357
+ for (const [field, propSchema] of Object.entries(schema.properties)) {
3358
+ const condition = propertySchemaToCondition(field, propSchema);
3359
+ if (condition) conditions.push(condition);
3360
+ }
3361
+ if (schema.required) {
3362
+ for (const field of schema.required) {
3363
+ if (!schema.properties[field]) {
3364
+ conditions.push({ field, operator: "isNotEmpty" });
3365
+ }
3366
+ }
3367
+ }
3368
+ if (conditions.length === 0) return null;
3369
+ if (conditions.length === 1) return conditions[0];
3370
+ return { operator: "and", conditions };
3371
+ }
3372
+ return null;
3373
+ }
3374
+ function propertySchemaToCondition(field, schema) {
3375
+ if (schema.const !== void 0) {
3376
+ return { field, operator: "equals", value: schema.const };
3377
+ }
3378
+ if (schema.enum && schema.enum.length > 0) {
3379
+ return { field, operator: "in", value: schema.enum };
3380
+ }
3381
+ if (schema.minimum !== void 0) {
3382
+ return { field, operator: "greaterThanOrEqual", value: schema.minimum };
3383
+ }
3384
+ if (schema.maximum !== void 0) {
3385
+ return { field, operator: "lessThanOrEqual", value: schema.maximum };
3386
+ }
3387
+ if (schema.minLength !== void 0 && schema.minLength > 0) {
3388
+ return { field, operator: "isNotEmpty" };
3389
+ }
3390
+ if (schema.pattern) {
3391
+ return { field, operator: "matches", value: schema.pattern };
3392
+ }
3393
+ return null;
3394
+ }
3395
+ function convertSchemaDependency(sourceField, depSchema, fields, rootSchema, idPrefix) {
3396
+ const depRequired = new Set(depSchema.required ?? []);
3397
+ if (depSchema.properties) {
3398
+ for (const [depFieldName, depFieldSchema] of Object.entries(
3399
+ depSchema.properties
3400
+ )) {
3401
+ if (!fields[depFieldName]) {
3402
+ fields[depFieldName] = schemaNodeToFieldConfig(
3403
+ depFieldName,
3404
+ depFieldSchema,
3405
+ depRequired.has(depFieldName)
3406
+ );
3407
+ fields[depFieldName].hidden = true;
3408
+ }
3409
+ const rule = {
3410
+ id: `${idPrefix}_schemadep_${sourceField}_${depFieldName}`,
3411
+ when: { field: sourceField, operator: "isNotEmpty" },
3412
+ then: {
3413
+ hidden: false,
3414
+ ...depRequired.has(depFieldName) ? { required: true } : {}
3415
+ },
3416
+ else: {
3417
+ hidden: true
3418
+ }
3419
+ };
3420
+ fields[depFieldName].rules = [
3421
+ ...fields[depFieldName].rules ?? [],
3422
+ rule
3423
+ ];
3424
+ }
3425
+ }
3426
+ if (depSchema.oneOf) {
3427
+ convertComposition(
3428
+ depSchema,
3429
+ fields,
3430
+ rootSchema,
3431
+ `${idPrefix}_schemadep_${sourceField}`
3432
+ );
3433
+ }
3434
+ }
3435
+ function findDiscriminator(variants) {
3436
+ if (variants.length < 2) return null;
3437
+ const firstVariant = variants[0];
3438
+ if (!firstVariant.properties) return null;
3439
+ for (const propName of Object.keys(firstVariant.properties)) {
3440
+ const prop = firstVariant.properties[propName];
3441
+ if (!hasConstOrSingleEnum(prop)) continue;
3442
+ const allHave = variants.every(
3443
+ (v) => v.properties?.[propName] && hasConstOrSingleEnum(v.properties[propName])
3444
+ );
3445
+ if (allHave) {
3446
+ const values = variants.map(
3447
+ (v) => getConstValue(v.properties[propName])
3448
+ );
3449
+ const unique = new Set(values.map(String));
3450
+ if (unique.size === variants.length) return propName;
3451
+ }
3452
+ }
3453
+ return null;
3454
+ }
3455
+ function hasConstOrSingleEnum(node) {
3456
+ if (node.const !== void 0) return true;
3457
+ if (node.enum && node.enum.length === 1) return true;
3458
+ return false;
3459
+ }
3460
+ function getConstValue(node) {
3461
+ if (node.const !== void 0) return node.const;
3462
+ if (node.enum && node.enum.length === 1) return node.enum[0];
3463
+ return void 0;
3464
+ }
3465
+ function convertWithDiscriminator(discriminatorField, variants, fields, rootSchema, idPrefix, compositionType) {
3466
+ const allValues = variants.map(
3467
+ (v) => getConstValue(v.properties[discriminatorField])
3468
+ );
3469
+ if (!fields[discriminatorField]) {
3470
+ fields[discriminatorField] = {
3471
+ type: "Dropdown",
3472
+ label: discriminatorField,
3473
+ options: allValues.map((v) => ({
3474
+ value: String(v),
3475
+ label: String(v)
3476
+ }))
3477
+ };
3478
+ }
3479
+ for (const variant of variants) {
3480
+ if (!variant.properties) continue;
3481
+ const variantValue = getConstValue(variant.properties[discriminatorField]);
3482
+ const variantRequired = new Set(variant.required ?? []);
3483
+ for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {
3484
+ if (fieldName === discriminatorField) continue;
3485
+ if (!fields[fieldName]) {
3486
+ fields[fieldName] = schemaNodeToFieldConfig(
3487
+ fieldName,
3488
+ fieldSchema,
3489
+ variantRequired.has(fieldName)
3490
+ );
3491
+ fields[fieldName].hidden = true;
3492
+ }
3493
+ const rule = {
3494
+ id: `${idPrefix}_${compositionType}_${discriminatorField}_${fieldName}`,
3495
+ when: {
3496
+ field: discriminatorField,
3497
+ operator: "equals",
3498
+ value: variantValue
3499
+ },
3500
+ then: {
3501
+ hidden: false,
3502
+ ...variantRequired.has(fieldName) ? { required: true } : {}
3503
+ },
3504
+ else: { hidden: true }
3505
+ };
3506
+ fields[fieldName].rules = [
3507
+ ...fields[fieldName].rules ?? [],
3508
+ rule
3509
+ ];
3510
+ }
3511
+ }
3512
+ }
3513
+ function convertWithSyntheticDiscriminator(variants, fields, rootSchema, idPrefix, compositionType) {
3514
+ const options = variants.map((_, i) => ({
3515
+ value: String(i),
3516
+ label: `Option ${i + 1}`
3517
+ }));
3518
+ fields["_variant"] = {
3519
+ type: "Dropdown",
3520
+ label: "Variant",
3521
+ options
3522
+ };
3523
+ for (let i = 0; i < variants.length; i++) {
3524
+ const variant = variants[i];
3525
+ if (!variant.properties) continue;
3526
+ const variantRequired = new Set(variant.required ?? []);
3527
+ for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {
3528
+ if (!fields[fieldName]) {
3529
+ fields[fieldName] = schemaNodeToFieldConfig(
3530
+ fieldName,
3531
+ fieldSchema,
3532
+ variantRequired.has(fieldName)
3533
+ );
3534
+ fields[fieldName].hidden = true;
3535
+ }
3536
+ const rule = {
3537
+ id: `${idPrefix}_${compositionType}_variant${i}_${fieldName}`,
3538
+ when: {
3539
+ field: "_variant",
3540
+ operator: "equals",
3541
+ value: String(i)
3542
+ },
3543
+ then: {
3544
+ hidden: false,
3545
+ ...variantRequired.has(fieldName) ? { required: true } : {}
3546
+ },
3547
+ else: { hidden: true }
3548
+ };
3549
+ fields[fieldName].rules = [
3550
+ ...fields[fieldName].rules ?? [],
3551
+ rule
3552
+ ];
3553
+ }
3554
+ }
3555
+ }
3556
+
3557
+ // src/utils/rjsf/converter.ts
3558
+ function fromRjsfSchema(schema, uiSchema, formData, options) {
3559
+ const strategy = options?.nestedObjectStrategy ?? "flatten";
3560
+ const idPrefix = options?.ruleIdPrefix ?? "rjsf";
3561
+ const resolved = resolveRefs(schema);
3562
+ const merged = mergeAllOf(resolved);
3563
+ const fields = {};
3564
+ const requiredSet = new Set(merged.required ?? []);
3565
+ if (merged.properties) {
3566
+ mapProperties(
3567
+ merged.properties,
3568
+ requiredSet,
3569
+ fields,
3570
+ "",
3571
+ strategy,
3572
+ uiSchema,
3573
+ formData
3574
+ );
3575
+ }
3576
+ if (merged.dependencies) {
3577
+ convertDependencies(merged.dependencies, fields, merged, idPrefix);
3578
+ }
3579
+ if (merged.if) {
3580
+ convertIfThenElse(merged, fields, merged, idPrefix);
3581
+ }
3582
+ if (merged.oneOf || merged.anyOf) {
3583
+ convertComposition(merged, fields, merged, idPrefix);
3584
+ }
3585
+ const fieldOrder = resolveFieldOrder(fields, uiSchema);
3586
+ return {
3587
+ version: 2,
3588
+ fields,
3589
+ fieldOrder
3590
+ };
3591
+ }
3592
+ function mapProperties(properties, requiredSet, fields, prefix, strategy, uiSchema, formData) {
3593
+ for (const [propName, propSchema] of Object.entries(properties)) {
3594
+ const fullName = prefix ? `${prefix}.${propName}` : propName;
3595
+ const isRequired = requiredSet.has(propName);
3596
+ if (isObjectType(propSchema) && propSchema.properties) {
3597
+ if (strategy === "flatten") {
3598
+ const nestedRequired = new Set(propSchema.required ?? []);
3599
+ const nestedUiSchema = uiSchema?.[propName];
3600
+ const nestedFormData = formData?.[propName];
3601
+ mapProperties(
3602
+ propSchema.properties,
3603
+ nestedRequired,
3604
+ fields,
3605
+ fullName,
3606
+ strategy,
3607
+ nestedUiSchema,
3608
+ nestedFormData
3609
+ );
3610
+ continue;
3611
+ } else {
3612
+ const items = {};
3613
+ const nestedRequired = new Set(propSchema.required ?? []);
3614
+ for (const [itemProp, itemSchema] of Object.entries(
3615
+ propSchema.properties
3616
+ )) {
3617
+ items[itemProp] = schemaNodeToFieldConfig(
3618
+ itemProp,
3619
+ itemSchema,
3620
+ nestedRequired.has(itemProp)
3621
+ );
3622
+ }
3623
+ fields[fullName] = {
3624
+ type: "FieldArray",
3625
+ label: propSchema.title ?? propName,
3626
+ items
3627
+ };
3628
+ continue;
3629
+ }
3630
+ }
3631
+ if (isArrayWithObjectItems(propSchema)) {
3632
+ const itemSchema = propSchema.items;
3633
+ const items = {};
3634
+ const itemRequired = new Set(itemSchema.required ?? []);
3635
+ if (itemSchema.properties) {
3636
+ for (const [itemProp, itemPropSchema] of Object.entries(
3637
+ itemSchema.properties
3638
+ )) {
3639
+ items[itemProp] = schemaNodeToFieldConfig(
3640
+ itemProp,
3641
+ itemPropSchema,
3642
+ itemRequired.has(itemProp)
3643
+ );
3644
+ }
3645
+ }
3646
+ const config2 = schemaNodeToFieldConfig(fullName, propSchema, isRequired);
3647
+ config2.type = "FieldArray";
3648
+ config2.items = items;
3649
+ if (propSchema.minItems !== void 0) config2.minItems = propSchema.minItems;
3650
+ if (propSchema.maxItems !== void 0) config2.maxItems = propSchema.maxItems;
3651
+ fields[fullName] = config2;
3652
+ const fieldUiSchema2 = getFieldUiSchema(uiSchema, propName, prefix);
3653
+ if (fieldUiSchema2) {
3654
+ fields[fullName] = applyUiSchema(fields[fullName], fieldUiSchema2);
3655
+ }
3656
+ const dataValue2 = getFormDataValue(formData, propName);
3657
+ if (dataValue2 !== void 0 && fields[fullName].defaultValue === void 0) {
3658
+ fields[fullName].defaultValue = dataValue2;
3659
+ }
3660
+ continue;
3661
+ }
3662
+ const config = schemaNodeToFieldConfig(fullName, propSchema, isRequired);
3663
+ fields[fullName] = config;
3664
+ const fieldUiSchema = getFieldUiSchema(uiSchema, propName, prefix);
3665
+ if (fieldUiSchema) {
3666
+ fields[fullName] = applyUiSchema(fields[fullName], fieldUiSchema);
3667
+ }
3668
+ const dataValue = getFormDataValue(formData, propName);
3669
+ if (dataValue !== void 0 && fields[fullName].defaultValue === void 0) {
3670
+ fields[fullName].defaultValue = dataValue;
3671
+ }
3672
+ }
3673
+ }
3674
+ function mergeAllOf(schema) {
3675
+ if (!schema.allOf || schema.allOf.length === 0) return schema;
3676
+ const { allOf, ...base } = schema;
3677
+ let result = { ...base };
3678
+ for (const subSchema of allOf) {
3679
+ result = mergeSchemas(result, subSchema);
3680
+ }
3681
+ return result;
3682
+ }
3683
+ function mergeSchemas(a, b) {
3684
+ const result = { ...a };
3685
+ if (b.properties) {
3686
+ result.properties = { ...result.properties ?? {}, ...b.properties };
3687
+ }
3688
+ if (b.required) {
3689
+ const existing = new Set(result.required ?? []);
3690
+ for (const r of b.required) existing.add(r);
3691
+ result.required = [...existing];
3692
+ }
3693
+ if (b.if) result.if = b.if;
3694
+ if (b.then) result.then = b.then;
3695
+ if (b.else) result.else = b.else;
3696
+ if (b.dependencies) {
3697
+ result.dependencies = {
3698
+ ...result.dependencies ?? {},
3699
+ ...b.dependencies
3700
+ };
3701
+ }
3702
+ return result;
3703
+ }
3704
+ function isObjectType(node) {
3705
+ if (node.type === "object") return true;
3706
+ if (Array.isArray(node.type) && node.type.includes("object")) return true;
3707
+ return false;
3708
+ }
3709
+ function isArrayWithObjectItems(node) {
3710
+ const type = Array.isArray(node.type) ? node.type[0] : node.type;
3711
+ if (type !== "array") return false;
3712
+ const items = node.items;
3713
+ if (!items || Array.isArray(items)) return false;
3714
+ return items.type === "object" && !!items.properties;
3715
+ }
3716
+ function getFieldUiSchema(uiSchema, fieldName, prefix) {
3717
+ if (!uiSchema) return void 0;
3718
+ if (prefix) {
3719
+ const parts = prefix.split(".");
3720
+ let current = uiSchema;
3721
+ for (const part of parts) {
3722
+ current = current?.[part];
3723
+ }
3724
+ return current?.[fieldName];
3725
+ }
3726
+ return uiSchema[fieldName];
3727
+ }
3728
+ function getFormDataValue(formData, fieldName) {
3729
+ if (!formData) return void 0;
3730
+ return formData[fieldName];
3731
+ }
3732
+ function resolveFieldOrder(fields, uiSchema) {
3733
+ const uiOrder = uiSchema?.["ui:order"];
3734
+ if (!Array.isArray(uiOrder)) return Object.keys(fields);
3735
+ const allFields = new Set(Object.keys(fields));
3736
+ const order = [];
3737
+ const wildcardIdx = uiOrder.indexOf("*");
3738
+ for (const item of uiOrder) {
3739
+ if (item === "*") continue;
3740
+ if (allFields.has(item)) {
3741
+ order.push(item);
3742
+ allFields.delete(item);
3743
+ }
3744
+ }
3745
+ if (wildcardIdx !== -1) {
3746
+ const remaining = [...allFields];
3747
+ order.splice(wildcardIdx, 0, ...remaining);
3748
+ } else {
3749
+ order.push(...allFields);
3750
+ }
3751
+ return order;
3752
+ }
3753
+
3754
+ // src/utils/rjsf/reverseConverter.ts
3755
+ function toRjsfSchema(config) {
3756
+ const properties = {};
3757
+ const required2 = [];
3758
+ const uiSchema = {};
3759
+ for (const [fieldName, fieldConfig] of Object.entries(config.fields)) {
3760
+ if (fieldName.includes(".")) {
3761
+ setNestedProperty(properties, required2, uiSchema, fieldName, fieldConfig);
3762
+ continue;
3763
+ }
3764
+ properties[fieldName] = fieldConfigToSchemaNode(fieldConfig);
3765
+ if (fieldConfig.required) required2.push(fieldName);
3766
+ const fieldUi = fieldConfigToUiSchema(fieldConfig);
3767
+ if (Object.keys(fieldUi).length > 0) {
3768
+ uiSchema[fieldName] = fieldUi;
3769
+ }
3770
+ }
3771
+ if (config.fieldOrder && config.fieldOrder.length > 0) {
3772
+ uiSchema["ui:order"] = config.fieldOrder;
3773
+ }
3774
+ const schema = {
3775
+ type: "object",
3776
+ properties
3777
+ };
3778
+ if (required2.length > 0) schema.required = required2;
3779
+ return { schema, uiSchema };
3780
+ }
3781
+ var REVERSE_TYPE_MAP = {
3782
+ Textbox: "string",
3783
+ Textarea: "string",
3784
+ Number: "number",
3785
+ Slider: "number",
3786
+ Toggle: "boolean",
3787
+ DateControl: "string",
3788
+ Dropdown: "string",
3789
+ Multiselect: "array",
3790
+ DocumentLinks: "string",
3791
+ DynamicFragment: "string"
3792
+ };
3793
+ var REVERSE_WIDGET_MAP = {
3794
+ Textarea: "textarea",
3795
+ Slider: "range",
3796
+ Toggle: "checkbox",
3797
+ DocumentLinks: "file"
3798
+ };
3799
+ function fieldConfigToSchemaNode(config) {
3800
+ const node = {};
3801
+ const jsonType = REVERSE_TYPE_MAP[config.type] ?? "string";
3802
+ node.type = jsonType;
3803
+ if (config.label) node.title = config.label;
3804
+ if (config.description) node.description = config.description;
3805
+ if (config.defaultValue !== void 0) node.default = config.defaultValue;
3806
+ if (config.options && config.options.length > 0) {
3807
+ node.enum = config.options.map((o) => o.value);
3808
+ const labels = config.options.map((o) => o.label);
3809
+ const valuesAsStrings = config.options.map((o) => String(o.value));
3810
+ if (labels.some((l, i) => l !== valuesAsStrings[i])) {
3811
+ node.enumNames = labels;
3812
+ }
3813
+ }
3814
+ if (config.validate) {
3815
+ for (const rule of config.validate) {
3816
+ applyValidationToSchema(node, rule.name, rule.params);
3817
+ }
3818
+ }
3819
+ if (config.type === "FieldArray" && config.items) {
3820
+ node.type = "array";
3821
+ const itemProperties = {};
3822
+ const itemRequired = [];
3823
+ for (const [itemName, itemConfig] of Object.entries(config.items)) {
3824
+ itemProperties[itemName] = fieldConfigToSchemaNode(itemConfig);
3825
+ if (itemConfig.required) itemRequired.push(itemName);
3826
+ }
3827
+ node.items = {
3828
+ type: "object",
3829
+ properties: itemProperties,
3830
+ ...itemRequired.length > 0 ? { required: itemRequired } : {}
3831
+ };
3832
+ if (config.minItems !== void 0) node.minItems = config.minItems;
3833
+ if (config.maxItems !== void 0) node.maxItems = config.maxItems;
3834
+ }
3835
+ if (config.type === "Multiselect" && config.options) {
3836
+ node.type = "array";
3837
+ node.items = {
3838
+ type: "string",
3839
+ enum: config.options.map((o) => o.value)
3840
+ };
3841
+ delete node.enum;
3842
+ delete node.enumNames;
3843
+ }
3844
+ if (config.type === "DateControl") {
3845
+ node.format = "date";
3846
+ }
3847
+ if (config.type === "DocumentLinks") {
3848
+ node.format = "data-url";
3849
+ }
3850
+ if (config.config?.type === "password" || config.config?.type === "color") {
3851
+ }
3852
+ return node;
3853
+ }
3854
+ function fieldConfigToUiSchema(config) {
3855
+ const ui = {};
3856
+ const widget = REVERSE_WIDGET_MAP[config.type];
3857
+ if (widget) ui["ui:widget"] = widget;
3858
+ if (config.config?.type === "password") ui["ui:widget"] = "password";
3859
+ if (config.config?.type === "color") ui["ui:widget"] = "color";
3860
+ if (config.config?.display === "radio") ui["ui:widget"] = "radio";
3861
+ if (config.config?.display === "checkboxes") ui["ui:widget"] = "checkboxes";
3862
+ if (config.placeholder) ui["ui:placeholder"] = config.placeholder;
3863
+ if (config.helpText) ui["ui:help"] = config.helpText;
3864
+ if (config.hidden) ui["ui:hidden"] = true;
3865
+ if (config.readOnly) ui["ui:readonly"] = true;
3866
+ if (config.disabled) ui["ui:disabled"] = true;
3867
+ if (config.config?.autofocus) ui["ui:autofocus"] = true;
3868
+ if (config.config?.className) ui["ui:classNames"] = config.config.className;
3869
+ if (config.config?.hideLabel) ui["ui:label"] = false;
3870
+ if (config.options) {
3871
+ const disabled = config.options.filter((o) => o.disabled).map((o) => o.value);
3872
+ if (disabled.length > 0) ui["ui:enumDisabled"] = disabled;
3873
+ }
3874
+ return ui;
3875
+ }
3876
+ function applyValidationToSchema(node, name, params) {
3877
+ switch (name) {
3878
+ case "minLength":
3879
+ node.minLength = Number(params?.min ?? 0);
3880
+ break;
3881
+ case "maxLength":
3882
+ node.maxLength = Number(params?.max ?? 0);
3883
+ break;
3884
+ case "pattern":
3885
+ node.pattern = String(params?.pattern ?? "");
3886
+ break;
3887
+ case "numericRange":
3888
+ if (params?.min !== void 0 && params.min !== -Infinity)
3889
+ node.minimum = Number(params.min);
3890
+ if (params?.max !== void 0 && params.max !== Infinity)
3891
+ node.maximum = Number(params.max);
3892
+ break;
3893
+ case "exclusiveNumericRange":
3894
+ if (params?.exclusiveMin !== void 0)
3895
+ node.exclusiveMinimum = Number(params.exclusiveMin);
3896
+ if (params?.exclusiveMax !== void 0)
3897
+ node.exclusiveMaximum = Number(params.exclusiveMax);
3898
+ break;
3899
+ case "multipleOf":
3900
+ node.multipleOf = Number(params?.factor ?? 1);
3901
+ break;
3902
+ case "email":
3903
+ node.format = "email";
3904
+ break;
3905
+ case "url":
3906
+ node.format = "uri";
3907
+ break;
3908
+ case "uniqueInArray":
3909
+ node.uniqueItems = true;
3910
+ break;
3911
+ }
3912
+ }
3913
+ function setNestedProperty(properties, required2, uiSchema, dotPath, config) {
3914
+ const parts = dotPath.split(".");
3915
+ let currentProps = properties;
3916
+ let currentUi = uiSchema;
3917
+ for (let i = 0; i < parts.length - 1; i++) {
3918
+ const part = parts[i];
3919
+ if (!currentProps[part]) {
3920
+ currentProps[part] = {
3921
+ type: "object",
3922
+ properties: {}
3923
+ };
3924
+ }
3925
+ if (!currentProps[part].properties) {
3926
+ currentProps[part].properties = {};
3927
+ }
3928
+ currentProps = currentProps[part].properties;
3929
+ if (!currentUi[part]) {
3930
+ currentUi[part] = {};
3931
+ }
3932
+ currentUi = currentUi[part];
3933
+ }
3934
+ const leafName = parts[parts.length - 1];
3935
+ currentProps[leafName] = fieldConfigToSchemaNode(config);
3936
+ if (config.required) {
3937
+ const parentPath = parts.slice(0, -1);
3938
+ let parentNode;
3939
+ let props = properties;
3940
+ for (const p of parentPath) {
3941
+ parentNode = props[p];
3942
+ props = parentNode?.properties ?? {};
3943
+ }
3944
+ if (parentNode) {
3945
+ parentNode.required = [...parentNode.required ?? [], leafName];
3946
+ }
3947
+ }
3948
+ const fieldUi = fieldConfigToUiSchema(config);
3949
+ if (Object.keys(fieldUi).length > 0) {
3950
+ currentUi[leafName] = fieldUi;
3951
+ }
3952
+ }
3953
+
3954
+ // src/utils/zodSchemaImport.ts
3955
+ function zodSchemaToFieldConfig(zodSchema) {
3956
+ const configs = {};
3957
+ const shape = getZodShape(zodSchema);
3958
+ if (!shape) return configs;
3959
+ for (const [fieldName, fieldSchema] of Object.entries(shape)) {
3960
+ configs[fieldName] = zodFieldToConfig(fieldName, fieldSchema);
3961
+ }
3962
+ return configs;
3963
+ }
3964
+ function getZodShape(schema) {
3965
+ const s = schema;
3966
+ if (s?._def && typeof s._def === "object") {
3967
+ const def = s._def;
3968
+ if (typeof def.shape === "function") return def.shape();
3969
+ if (typeof def.shape === "object" && def.shape !== null) return def.shape;
3970
+ }
3971
+ return null;
3972
+ }
3973
+ function zodFieldToConfig(fieldName, field) {
3974
+ const { typeName, isOptional } = unwrapZodType(field);
3975
+ const checks = getZodChecks(field);
3976
+ const config = {
3977
+ type: "Textbox",
3978
+ label: formatLabel(fieldName),
3979
+ required: !isOptional
3980
+ };
3981
+ switch (typeName) {
3982
+ case "ZodString":
3983
+ config.type = "Textbox";
3984
+ if (checks.some((c) => c.kind === "email")) {
3985
+ config.validate = [...config.validate ?? [], { name: "email" }];
3986
+ }
3987
+ if (checks.some((c) => c.kind === "url")) {
3988
+ config.validate = [...config.validate ?? [], { name: "url" }];
3989
+ }
3990
+ break;
3991
+ case "ZodNumber":
3992
+ config.type = "Number";
3993
+ break;
3994
+ case "ZodBoolean":
3995
+ config.type = "Toggle";
3996
+ break;
3997
+ case "ZodEnum":
3998
+ case "ZodNativeEnum": {
3999
+ config.type = "Dropdown";
4000
+ const values = getZodEnumValues(field);
4001
+ if (values) {
4002
+ config.options = values.map((v) => ({ value: String(v), label: String(v) }));
4003
+ }
4004
+ break;
4005
+ }
4006
+ case "ZodDate":
4007
+ config.type = "DateControl";
4008
+ break;
4009
+ case "ZodArray":
4010
+ config.type = "Multiselect";
4011
+ break;
4012
+ default:
4013
+ config.type = "Textbox";
4014
+ }
4015
+ return config;
4016
+ }
4017
+ function unwrapZodType(field) {
4018
+ let current = field;
4019
+ let isOptional = false;
4020
+ while (current?._def) {
4021
+ const tn = current._def.typeName;
4022
+ if (tn === "ZodOptional" || tn === "ZodNullable") {
4023
+ isOptional = true;
4024
+ current = current._def.innerType;
4025
+ } else if (tn === "ZodDefault") {
4026
+ current = current._def.innerType;
4027
+ } else {
4028
+ break;
4029
+ }
4030
+ }
4031
+ return { typeName: current?._def?.typeName ?? "ZodString", isOptional };
4032
+ }
4033
+ function getZodChecks(field) {
4034
+ let current = field;
4035
+ while (current?._def) {
4036
+ if (current._def.checks) return current._def.checks;
4037
+ if (current._def.innerType) {
4038
+ current = current._def.innerType;
4039
+ } else {
4040
+ break;
4041
+ }
4042
+ }
4043
+ return [];
4044
+ }
4045
+ function getZodEnumValues(field) {
4046
+ let current = field;
4047
+ while (current?._def) {
4048
+ if (current._def.values) return current._def.values;
4049
+ if (current._def.innerType) {
4050
+ current = current._def.innerType;
4051
+ } else {
4052
+ break;
4053
+ }
4054
+ }
4055
+ return null;
4056
+ }
4057
+ function formatLabel(fieldName) {
4058
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
4059
+ }
4060
+
4061
+ // src/utils/lazyFieldRegistry.ts
4062
+ var import_react13 = __toESM(require("react"));
4063
+ function createLazyFieldRegistry(imports) {
4064
+ const registry = {};
4065
+ for (const [key, importFn] of Object.entries(imports)) {
4066
+ const LazyComponent = import_react13.default.lazy(importFn);
4067
+ registry[key] = import_react13.default.createElement(
4068
+ import_react13.default.Suspense,
4069
+ { fallback: import_react13.default.createElement("span", { className: "field-loading" }, "Loading...") },
4070
+ import_react13.default.createElement(LazyComponent)
4071
+ );
4072
+ }
4073
+ return registry;
4074
+ }
4075
+
4076
+ // src/hooks/useDraftPersistence.ts
4077
+ var import_react14 = require("react");
4078
+
4079
+ // src/utils/formStateSerialization.ts
4080
+ function markDates(value, visited = /* @__PURE__ */ new WeakSet()) {
4081
+ if (value instanceof Date) {
4082
+ return { __type: "Date", value: value.toISOString() };
4083
+ }
4084
+ if (Array.isArray(value)) {
4085
+ if (visited.has(value)) return value;
4086
+ visited.add(value);
4087
+ return value.map((item) => markDates(item, visited));
4088
+ }
4089
+ if (value !== null && typeof value === "object") {
4090
+ if (visited.has(value)) return value;
4091
+ visited.add(value);
4092
+ const result = {};
4093
+ for (const key of Object.keys(value)) {
4094
+ result[key] = markDates(value[key], visited);
4095
+ }
4096
+ return result;
4097
+ }
4098
+ return value;
4099
+ }
4100
+ function serializeFormState(data) {
4101
+ return JSON.stringify(markDates(data));
4102
+ }
4103
+ function deserializeFormState(json) {
4104
+ return JSON.parse(json, (_key, value) => {
4105
+ if (value && typeof value === "object" && value.__type === "Date") {
4106
+ return new Date(value.value);
4107
+ }
4108
+ return value;
4109
+ });
4110
+ }
4111
+
4112
+ // src/hooks/useDraftPersistence.ts
4113
+ function getStorageKey(formId, prefix) {
4114
+ return `${prefix}${formId}`;
4115
+ }
4116
+ function getStorage() {
4117
+ try {
4118
+ return typeof localStorage !== "undefined" ? localStorage : void 0;
4119
+ } catch {
4120
+ return void 0;
4121
+ }
4122
+ }
4123
+ function useDraftPersistence(options) {
4124
+ const {
4125
+ formId,
4126
+ data,
4127
+ saveIntervalMs = 3e4,
4128
+ enabled = true,
4129
+ storageKeyPrefix = "draft_"
4130
+ } = options;
4131
+ const [hasDraft, setHasDraft] = (0, import_react14.useState)(false);
4132
+ const dataRef = (0, import_react14.useRef)(data);
4133
+ const intervalRef = (0, import_react14.useRef)(void 0);
4134
+ (0, import_react14.useEffect)(() => {
4135
+ dataRef.current = data;
4136
+ }, [data]);
4137
+ const storageKey = getStorageKey(formId, storageKeyPrefix);
4138
+ const saveDraft = (0, import_react14.useCallback)(() => {
4139
+ try {
4140
+ const storage = getStorage();
4141
+ if (!storage) return;
4142
+ const draftState = {
4143
+ data: dataRef.current,
4144
+ timestamp: Date.now()
4145
+ };
4146
+ storage.setItem(storageKey, serializeFormState(draftState));
4147
+ setHasDraft(true);
4148
+ } catch {
4149
+ }
4150
+ }, [storageKey]);
4151
+ const recoverDraft = (0, import_react14.useCallback)(() => {
4152
+ try {
4153
+ const storage = getStorage();
4154
+ if (!storage) return null;
4155
+ const stored = storage.getItem(storageKey);
4156
+ if (!stored) return null;
4157
+ const parsed = deserializeFormState(stored);
4158
+ return parsed;
4159
+ } catch {
4160
+ return null;
4161
+ }
4162
+ }, [storageKey]);
4163
+ const clearDraft = (0, import_react14.useCallback)(() => {
4164
+ try {
4165
+ const storage = getStorage();
4166
+ if (!storage) return;
4167
+ storage.removeItem(storageKey);
4168
+ setHasDraft(false);
4169
+ } catch {
4170
+ }
4171
+ }, [storageKey]);
4172
+ (0, import_react14.useEffect)(() => {
4173
+ if (!enabled) return;
4174
+ try {
4175
+ const storage = getStorage();
4176
+ if (!storage) {
4177
+ setHasDraft(false);
4178
+ return;
4179
+ }
4180
+ const stored = storage.getItem(storageKey);
4181
+ setHasDraft(stored !== null);
4182
+ } catch {
4183
+ setHasDraft(false);
4184
+ }
4185
+ }, [enabled, storageKey]);
4186
+ (0, import_react14.useEffect)(() => {
4187
+ if (!enabled) return;
4188
+ intervalRef.current = setInterval(() => {
4189
+ saveDraft();
4190
+ }, saveIntervalMs);
4191
+ return () => {
4192
+ if (intervalRef.current !== void 0) {
4193
+ clearInterval(intervalRef.current);
4194
+ intervalRef.current = void 0;
4195
+ }
4196
+ };
4197
+ }, [enabled, saveIntervalMs, saveDraft]);
4198
+ return {
4199
+ recoverDraft,
4200
+ clearDraft,
4201
+ hasDraft,
4202
+ saveDraft
4203
+ };
4204
+ }
4205
+
4206
+ // src/hooks/useBeforeUnload.ts
4207
+ var import_react15 = require("react");
4208
+ function useBeforeUnload(shouldWarn, message, onAbandonment) {
4209
+ const onAbandonmentRef = (0, import_react15.useRef)(onAbandonment);
4210
+ onAbandonmentRef.current = onAbandonment;
4211
+ (0, import_react15.useEffect)(() => {
4212
+ if (!shouldWarn || typeof window === "undefined") return;
4213
+ const handler = (e) => {
4214
+ e.preventDefault();
4215
+ onAbandonmentRef.current?.();
4216
+ return e.returnValue = message ?? "You have unsaved changes.";
4217
+ };
4218
+ window.addEventListener("beforeunload", handler);
4219
+ return () => window.removeEventListener("beforeunload", handler);
4220
+ }, [shouldWarn, message]);
4221
+ }
4222
+
4223
+ // src/helpers/RuleTracer.ts
4224
+ var traceEnabled = false;
4225
+ var traceLog = [];
4226
+ var traceCallback = null;
4227
+ function enableRuleTracing(callback) {
4228
+ traceEnabled = true;
4229
+ traceLog = [];
4230
+ traceCallback = callback ?? null;
4231
+ }
4232
+ function disableRuleTracing() {
4233
+ traceEnabled = false;
4234
+ traceCallback = null;
4235
+ }
4236
+ function traceRuleEvent(event) {
4237
+ if (!traceEnabled) return;
4238
+ const fullEvent = { ...event, timestamp: Date.now() };
4239
+ traceLog.push(fullEvent);
4240
+ traceCallback?.(fullEvent);
4241
+ }
4242
+ function getRuleTraceLog() {
4243
+ return [...traceLog];
4244
+ }
4245
+ function clearRuleTraceLog() {
4246
+ traceLog = [];
4247
+ }
4248
+ function isRuleTracingEnabled() {
4249
+ return traceEnabled;
4250
+ }
4251
+ // Annotate the CommonJS export names for ESM import in node:
4252
+ 0 && (module.exports = {
4253
+ CheckAsyncFieldValidationRules,
4254
+ CheckDefaultValues,
4255
+ CheckFieldValidationRules,
4256
+ CheckValidDropdownOptions,
4257
+ ComponentTypes,
4258
+ ConfirmInputsModal,
4259
+ ExecuteComputedValue,
4260
+ FIELD_PARENT_PREFIX,
4261
+ FieldArray,
4262
+ FieldWrapper,
4263
+ FormConstants,
4264
+ FormDevTools,
4265
+ FormEngine,
4266
+ FormErrorBoundary,
4267
+ FormFields,
4268
+ FormStrings,
4269
+ GetChildEntity,
4270
+ GetComputedValuesOnCreate,
4271
+ GetComputedValuesOnDirtyFields,
4272
+ GetConfirmInputModalProps,
4273
+ GetFieldsToRender,
4274
+ InitOnCreateFormState,
4275
+ InitOnEditFormState,
4276
+ InjectedFieldProvider,
4277
+ IsExpandVisible,
4278
+ RenderField,
4279
+ RulesEngineActionType,
4280
+ RulesEngineProvider,
4281
+ ShowField,
4282
+ SortDropdownOptions,
4283
+ SortOptions,
4284
+ UseInjectedFieldContext,
4285
+ UseRulesEngineContext,
4286
+ WizardForm,
4287
+ buildDefaultFieldStates,
4288
+ buildDependencyGraph,
4289
+ clearRuleTraceLog,
4290
+ clearTimeline,
4291
+ convertBooleanToYesOrNoText,
4292
+ createLazyFieldRegistry,
4293
+ createMaxLengthRule,
4294
+ createMinLengthRule,
4295
+ createNumericRangeRule,
4296
+ createOption,
4297
+ createPatternRule,
4298
+ createRequiredIfRule,
4299
+ deepCopy,
4300
+ defineFormConfig,
4301
+ deserializeFormState,
4302
+ detectDependencyCycles,
4303
+ detectSelfDependencies,
4304
+ disableRuleTracing,
4305
+ enableRuleTracing,
4306
+ evaluateAffectedFields,
4307
+ evaluateAllRules,
4308
+ evaluateCondition,
4309
+ evaluateExpression,
4310
+ executeValueFunction,
4311
+ extractConditionDependencies,
4312
+ extractExpressionDependencies,
4313
+ extractFunctionDependencies,
4314
+ flushRenderCycle,
4315
+ fromRjsfSchema,
4316
+ getCurrentLocale,
4317
+ getLastRenderedFields,
4318
+ getLocaleString,
4319
+ getRenderCounts,
4320
+ getRuleTraceLog,
4321
+ getStepFieldOrder,
4322
+ getStepFields,
4323
+ getStepIndex,
4324
+ getTimeline,
4325
+ getTotalFormRenders,
4326
+ getValidator,
4327
+ getValidatorRegistry,
4328
+ getValueFunction,
4329
+ getVisibleSteps,
4330
+ isEmpty,
4331
+ isFieldCondition,
4332
+ isLogicalCondition,
4333
+ isNull,
4334
+ isRuleTracingEnabled,
4335
+ isStepValid,
4336
+ isStringEmpty,
4337
+ logEvent,
4338
+ registerLocale,
4339
+ registerValidators,
4340
+ registerValueFunctions,
4341
+ resetLocale,
4342
+ resetRenderTracker,
4343
+ resetValidatorRegistry,
4344
+ resetValueFunctionRegistry,
4345
+ runSyncValidations,
4346
+ runValidations,
4347
+ serializeFormState,
4348
+ sortDropdownOptions,
4349
+ toRjsfSchema,
4350
+ topologicalSort,
4351
+ traceRuleEvent,
4352
+ trackRender,
4353
+ useBeforeUnload,
4354
+ useDraftPersistence,
4355
+ useFormAnalytics,
4356
+ validateDependencyGraph,
4357
+ validateFieldConfigs,
4358
+ validateStepFields,
4359
+ zodSchemaToFieldConfig
4360
+ });
4361
+ //# sourceMappingURL=index.js.map