@aatulwork/customform-renderer 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,1840 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactHookForm = require('react-hook-form');
5
+ var material = require('@mui/material');
6
+ var ExpandMoreIcon = require('@mui/icons-material/ExpandMore');
7
+ var DoubleArrowOutlinedIcon = require('@mui/icons-material/DoubleArrowOutlined');
8
+ var ArrowForwardIcon = require('@mui/icons-material/ArrowForward');
9
+ var ArrowBackIcon = require('@mui/icons-material/ArrowBack');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+ var ckeditor5React = require('@ckeditor/ckeditor5-react');
12
+ var dayjs2 = require('dayjs');
13
+ var CloseIcon = require('@mui/icons-material/Close');
14
+ var CloudUploadIcon = require('@mui/icons-material/CloudUpload');
15
+ var InsertDriveFileIcon = require('@mui/icons-material/InsertDriveFile');
16
+ var DatePicker = require('@mui/x-date-pickers/DatePicker');
17
+ var DateTimePicker = require('@mui/x-date-pickers/DateTimePicker');
18
+ var TimePicker = require('@mui/x-date-pickers/TimePicker');
19
+ var LocalizationProvider = require('@mui/x-date-pickers/LocalizationProvider');
20
+ var AdapterDayjs = require('@mui/x-date-pickers/AdapterDayjs');
21
+
22
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
23
+
24
+ var ExpandMoreIcon__default = /*#__PURE__*/_interopDefault(ExpandMoreIcon);
25
+ var DoubleArrowOutlinedIcon__default = /*#__PURE__*/_interopDefault(DoubleArrowOutlinedIcon);
26
+ var ArrowForwardIcon__default = /*#__PURE__*/_interopDefault(ArrowForwardIcon);
27
+ var ArrowBackIcon__default = /*#__PURE__*/_interopDefault(ArrowBackIcon);
28
+ var dayjs2__default = /*#__PURE__*/_interopDefault(dayjs2);
29
+ var CloseIcon__default = /*#__PURE__*/_interopDefault(CloseIcon);
30
+ var CloudUploadIcon__default = /*#__PURE__*/_interopDefault(CloudUploadIcon);
31
+ var InsertDriveFileIcon__default = /*#__PURE__*/_interopDefault(InsertDriveFileIcon);
32
+
33
+ // src/components/FormRenderer.tsx
34
+
35
+ // src/utils/formHelpers.ts
36
+ var getAllFields = (formSchema) => {
37
+ return formSchema.sections ? formSchema.sections.flatMap((section) => section.fields) : formSchema.fields || [];
38
+ };
39
+ var normalizeInitialValues = (values, formSchema) => {
40
+ if (!values) return values;
41
+ const normalized = { ...values };
42
+ const allFields = getAllFields(formSchema);
43
+ allFields.forEach((field) => {
44
+ const fieldValue = normalized[field.name];
45
+ if (field.type === "select" || field.type === "formReference" || field.type === "apiReference") {
46
+ if (field.allowMultiple) {
47
+ if (fieldValue !== null && fieldValue !== void 0 && fieldValue !== "") {
48
+ if (!Array.isArray(fieldValue)) {
49
+ normalized[field.name] = [fieldValue];
50
+ }
51
+ } else {
52
+ normalized[field.name] = [];
53
+ }
54
+ } else {
55
+ if (Array.isArray(fieldValue) && fieldValue.length > 0) {
56
+ normalized[field.name] = fieldValue[0];
57
+ } else if (Array.isArray(fieldValue) && fieldValue.length === 0) {
58
+ normalized[field.name] = "";
59
+ }
60
+ }
61
+ }
62
+ if (field.type === "file") {
63
+ if (field.allowMultiple) {
64
+ if (fieldValue !== null && fieldValue !== void 0) {
65
+ if (!Array.isArray(fieldValue)) {
66
+ normalized[field.name] = [fieldValue];
67
+ }
68
+ } else {
69
+ normalized[field.name] = [];
70
+ }
71
+ } else {
72
+ if (Array.isArray(fieldValue) && fieldValue.length > 0) {
73
+ normalized[field.name] = fieldValue[0];
74
+ } else if (Array.isArray(fieldValue) && fieldValue.length === 0) {
75
+ normalized[field.name] = null;
76
+ }
77
+ }
78
+ }
79
+ });
80
+ return normalized;
81
+ };
82
+ var getDefaultValue = (field) => {
83
+ switch (field.type) {
84
+ case "checkbox":
85
+ case "toggle":
86
+ return false;
87
+ case "datepicker":
88
+ return null;
89
+ case "file":
90
+ return field.allowMultiple ? [] : null;
91
+ case "select":
92
+ case "formReference":
93
+ case "apiReference":
94
+ return field.allowMultiple ? [] : "";
95
+ case "text":
96
+ case "email":
97
+ case "number":
98
+ case "radio":
99
+ case "ckeditor":
100
+ default:
101
+ return "";
102
+ }
103
+ };
104
+ var transformFormValues = (data, formSchema) => {
105
+ const allFields = getAllFields(formSchema);
106
+ const fieldTypeMap = /* @__PURE__ */ new Map();
107
+ allFields.forEach((field) => {
108
+ fieldTypeMap.set(field.name, field.type);
109
+ });
110
+ const transformedData = {};
111
+ Object.keys(data).forEach((key) => {
112
+ const fieldType = fieldTypeMap.get(key);
113
+ const value = data[key];
114
+ if (value === null || value === void 0) {
115
+ transformedData[key] = value;
116
+ return;
117
+ }
118
+ switch (fieldType) {
119
+ case "number":
120
+ if (value === "" || value === null || value === void 0) {
121
+ transformedData[key] = null;
122
+ } else {
123
+ const numValue = Number(value);
124
+ transformedData[key] = isNaN(numValue) ? value : numValue;
125
+ }
126
+ break;
127
+ case "checkbox":
128
+ case "toggle":
129
+ transformedData[key] = Boolean(value);
130
+ break;
131
+ case "datepicker":
132
+ case "file":
133
+ default:
134
+ transformedData[key] = value;
135
+ }
136
+ });
137
+ return transformedData;
138
+ };
139
+ var TextField = ({ field, control, defaultValue, rules, errors }) => {
140
+ return /* @__PURE__ */ jsxRuntime.jsx(
141
+ reactHookForm.Controller,
142
+ {
143
+ name: field.name,
144
+ control,
145
+ defaultValue,
146
+ rules,
147
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsxs(
148
+ material.FormControl,
149
+ {
150
+ fullWidth: true,
151
+ required: field.required,
152
+ error: !!errors[field.name],
153
+ children: [
154
+ /* @__PURE__ */ jsxRuntime.jsxs(material.FormLabel, { children: [
155
+ " ",
156
+ field.label
157
+ ] }),
158
+ /* @__PURE__ */ jsxRuntime.jsx(
159
+ material.TextField,
160
+ {
161
+ ...formField,
162
+ type: field.type === "number" ? "number" : field.type,
163
+ placeholder: field.placeholder || "Enter value",
164
+ fullWidth: true,
165
+ size: "small",
166
+ required: field.required,
167
+ error: !!errors[field.name],
168
+ helperText: errors[field.name]?.message,
169
+ inputProps: field.type === "number" ? {
170
+ min: field.validation?.min,
171
+ max: field.validation?.max
172
+ } : void 0
173
+ }
174
+ )
175
+ ]
176
+ }
177
+ )
178
+ },
179
+ field.name
180
+ );
181
+ };
182
+
183
+ // src/utils/fieldHelpers.ts
184
+ var formatFileSize = (bytes) => {
185
+ if (bytes === 0) return "0 Bytes";
186
+ const k = 1024;
187
+ const sizes = ["Bytes", "KB", "MB", "GB"];
188
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
189
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
190
+ };
191
+ var validateFile = (file, field) => {
192
+ if (field.validation?.allowedFileTypes && field.validation.allowedFileTypes.length > 0) {
193
+ const fileExtension = file.name.split(".").pop()?.toLowerCase();
194
+ const allowedTypes = field.validation.allowedFileTypes.map((t) => t.toLowerCase().replace(".", ""));
195
+ if (!fileExtension || !allowedTypes.includes(fileExtension)) {
196
+ return `File type not allowed. Allowed types: ${field.validation.allowedFileTypes.join(", ")}`;
197
+ }
198
+ }
199
+ if (field.validation?.maxFileSize) {
200
+ if (file.size > field.validation.maxFileSize) {
201
+ const maxSizeFormatted = formatFileSize(field.validation.maxFileSize);
202
+ return `File size exceeds maximum allowed size of ${maxSizeFormatted}`;
203
+ }
204
+ }
205
+ return true;
206
+ };
207
+ var buildFieldRules = (field) => {
208
+ const rules = {};
209
+ if (field.required) {
210
+ rules.required = `${field.label} is required`;
211
+ }
212
+ if (field.type === "file") {
213
+ rules.validate = (value) => {
214
+ if (field.required) {
215
+ if (field.allowMultiple) {
216
+ const files = Array.isArray(value) ? value : [];
217
+ if (files.length === 0) {
218
+ return `${field.label} is required`;
219
+ }
220
+ const hasValidFiles = files.some(
221
+ (file) => file && typeof file === "object" && ("fileName" in file || "fileUrl" in file)
222
+ );
223
+ if (!hasValidFiles) {
224
+ return `${field.label} is required`;
225
+ }
226
+ } else {
227
+ if (!value || typeof value === "object" && !("fileName" in value || "fileUrl" in value)) {
228
+ return `${field.label} is required`;
229
+ }
230
+ }
231
+ }
232
+ return true;
233
+ };
234
+ }
235
+ if ((field.type === "select" || field.type === "formReference" || field.type === "apiReference") && field.allowMultiple) {
236
+ rules.validate = (value) => {
237
+ const values = value;
238
+ if (!values || values.length === 0) {
239
+ if (field.required) {
240
+ return `${field.label} is required`;
241
+ }
242
+ return true;
243
+ }
244
+ return true;
245
+ };
246
+ }
247
+ return rules;
248
+ };
249
+ var normalizeOptions = (options) => {
250
+ if (!options) return [];
251
+ return options.map((opt) => {
252
+ if (typeof opt === "string") {
253
+ return { label: opt, value: opt };
254
+ }
255
+ return opt;
256
+ });
257
+ };
258
+ var SimpleSelect = ({
259
+ label,
260
+ value,
261
+ onChange,
262
+ options,
263
+ placeholder,
264
+ helperText,
265
+ fullWidth = true,
266
+ size = "small",
267
+ required = false,
268
+ error = false,
269
+ disabled = false,
270
+ multiple = false,
271
+ isLoading = false
272
+ }) => {
273
+ const handleChange = (event) => {
274
+ const val = event.target.value;
275
+ onChange(val);
276
+ };
277
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.FormControl, { fullWidth, size, required, error, disabled, children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(material.InputLabel, { children: label }),
279
+ /* @__PURE__ */ jsxRuntime.jsx(
280
+ material.Select,
281
+ {
282
+ value: value ?? (multiple ? [] : ""),
283
+ onChange: handleChange,
284
+ input: /* @__PURE__ */ jsxRuntime.jsx(material.OutlinedInput, { label }),
285
+ multiple,
286
+ disabled: disabled || isLoading,
287
+ endAdornment: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(material.CircularProgress, { size: 20 }) : void 0,
288
+ renderValue: (selected) => {
289
+ if (multiple) {
290
+ const selectedValues = selected;
291
+ if (selectedValues.length === 0) {
292
+ return /* @__PURE__ */ jsxRuntime.jsx("em", { children: placeholder || "Select..." });
293
+ }
294
+ return /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", flexWrap: "wrap", gap: 0.5 }, children: selectedValues.map((val) => {
295
+ const option2 = options.find((opt) => opt.value === val);
296
+ return /* @__PURE__ */ jsxRuntime.jsx(
297
+ material.Chip,
298
+ {
299
+ label: option2?.label || val,
300
+ size: "small"
301
+ },
302
+ val
303
+ );
304
+ }) });
305
+ }
306
+ const option = options.find((opt) => opt.value === selected);
307
+ return option?.label || selected || /* @__PURE__ */ jsxRuntime.jsx("em", { children: placeholder || "Select..." });
308
+ },
309
+ children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(material.MenuItem, { value: option.value, children: option.label }, option.value))
310
+ }
311
+ ),
312
+ helperText && /* @__PURE__ */ jsxRuntime.jsx(material.FormHelperText, { children: helperText })
313
+ ] });
314
+ };
315
+ var SelectField = ({ field, control, defaultValue, rules, errors, services }) => {
316
+ const isMultiple = field.allowMultiple || false;
317
+ const normalizedOptions = normalizeOptions(field.options);
318
+ const selectOptions = react.useMemo(() => {
319
+ return normalizedOptions.map((opt) => ({
320
+ value: String(opt.value),
321
+ label: opt.label
322
+ }));
323
+ }, [normalizedOptions]);
324
+ const SelectComponent = services?.SelectComponent || SimpleSelect;
325
+ return /* @__PURE__ */ jsxRuntime.jsx(
326
+ reactHookForm.Controller,
327
+ {
328
+ name: field.name,
329
+ control,
330
+ defaultValue,
331
+ rules,
332
+ render: ({ field: formField }) => {
333
+ return /* @__PURE__ */ jsxRuntime.jsx(
334
+ SelectComponent,
335
+ {
336
+ label: field.label,
337
+ value: formField.value,
338
+ onChange: (value) => {
339
+ formField.onChange(value);
340
+ },
341
+ options: selectOptions,
342
+ placeholder: field.placeholder || "Select...",
343
+ helperText: errors[field.name]?.message,
344
+ fullWidth: true,
345
+ size: "small",
346
+ required: field.required,
347
+ error: !!errors[field.name],
348
+ disabled: false,
349
+ multiple: isMultiple
350
+ }
351
+ );
352
+ }
353
+ },
354
+ field.name
355
+ );
356
+ };
357
+ var CheckboxField = ({ field, control, defaultValue, rules }) => {
358
+ return /* @__PURE__ */ jsxRuntime.jsx(
359
+ reactHookForm.Controller,
360
+ {
361
+ name: field.name,
362
+ control,
363
+ defaultValue,
364
+ rules,
365
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsx(
366
+ material.FormControlLabel,
367
+ {
368
+ control: /* @__PURE__ */ jsxRuntime.jsx(
369
+ material.Checkbox,
370
+ {
371
+ ...formField,
372
+ checked: formField.value || false,
373
+ size: "small"
374
+ }
375
+ ),
376
+ label: field.label
377
+ }
378
+ )
379
+ },
380
+ field.name
381
+ );
382
+ };
383
+ var RadioField = ({ field, control, defaultValue, rules, errors }) => {
384
+ const normalizedOptions = normalizeOptions(field.options);
385
+ return /* @__PURE__ */ jsxRuntime.jsx(
386
+ reactHookForm.Controller,
387
+ {
388
+ name: field.name,
389
+ control,
390
+ defaultValue,
391
+ rules,
392
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsxs(material.FormControl, { component: "fieldset", required: field.required, error: !!errors[field.name], children: [
393
+ /* @__PURE__ */ jsxRuntime.jsx(material.FormLabel, { required: field.required, error: !!errors[field.name], children: field.label }),
394
+ /* @__PURE__ */ jsxRuntime.jsx(material.RadioGroup, { ...formField, row: true, children: normalizedOptions.map((option, index) => /* @__PURE__ */ jsxRuntime.jsx(
395
+ material.FormControlLabel,
396
+ {
397
+ value: option.value,
398
+ control: /* @__PURE__ */ jsxRuntime.jsx(material.Radio, { size: "small" }),
399
+ label: option.label
400
+ },
401
+ index
402
+ )) })
403
+ ] })
404
+ },
405
+ field.name
406
+ );
407
+ };
408
+ var ToggleField = ({ field, control, defaultValue, rules, errors }) => {
409
+ return /* @__PURE__ */ jsxRuntime.jsx(
410
+ reactHookForm.Controller,
411
+ {
412
+ name: field.name,
413
+ control,
414
+ defaultValue,
415
+ rules,
416
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsx(
417
+ material.FormControlLabel,
418
+ {
419
+ control: /* @__PURE__ */ jsxRuntime.jsx(
420
+ material.Switch,
421
+ {
422
+ ...formField,
423
+ checked: formField.value || false,
424
+ size: "medium"
425
+ }
426
+ ),
427
+ label: /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { children: [
428
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Typography, { variant: "body2", children: [
429
+ field.label,
430
+ " ",
431
+ field.required && "*"
432
+ ] }),
433
+ errors[field.name] && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "error", sx: { display: "block", mt: 0.5 }, children: errors[field.name]?.message })
434
+ ] })
435
+ }
436
+ )
437
+ },
438
+ field.name
439
+ );
440
+ };
441
+ var ColorField = ({ field, control, defaultValue, rules, errors }) => {
442
+ return /* @__PURE__ */ jsxRuntime.jsx(
443
+ reactHookForm.Controller,
444
+ {
445
+ name: field.name,
446
+ control,
447
+ defaultValue,
448
+ rules,
449
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 2, width: "100%" }, children: [
450
+ /* @__PURE__ */ jsxRuntime.jsx(
451
+ material.FormLabel,
452
+ {
453
+ required: field.required,
454
+ error: !!errors[field.name],
455
+ children: field.label
456
+ }
457
+ ),
458
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", flexDirection: "column", flex: 1, maxWidth: 200 }, children: [
459
+ /* @__PURE__ */ jsxRuntime.jsx(
460
+ material.Input,
461
+ {
462
+ ...formField,
463
+ type: "color",
464
+ sx: {
465
+ width: "20%",
466
+ height: "40px",
467
+ cursor: "pointer",
468
+ border: errors[field.name] ? "1px solid red" : "1px solid rgba(0, 0, 0, 0.23)",
469
+ borderRadius: "4px",
470
+ padding: "1px"
471
+ },
472
+ inputProps: {
473
+ style: {
474
+ height: "100%",
475
+ cursor: "pointer"
476
+ }
477
+ }
478
+ }
479
+ ),
480
+ errors[field.name] && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "error", sx: { mt: 0.5 }, children: errors[field.name]?.message })
481
+ ] })
482
+ ] })
483
+ },
484
+ field.name
485
+ );
486
+ };
487
+ var defaultFileUploadService = {
488
+ uploadFiles: async () => {
489
+ throw new Error("File upload service not provided. Please provide a fileUpload service in FormServices.");
490
+ }
491
+ };
492
+ var defaultFormReferenceService = {
493
+ fetchOptions: async () => {
494
+ throw new Error("Form reference service not provided. Please provide a formReference service in FormServices.");
495
+ }
496
+ };
497
+ var defaultApiReferenceService = {
498
+ fetchOptions: async () => {
499
+ throw new Error("API reference service not provided. Please provide an apiReference service in FormServices.");
500
+ }
501
+ };
502
+ var defaultDateFormatterService = {
503
+ format: (value, options) => {
504
+ if (!value) return "\u2014";
505
+ const mode = options?.datePickerMode || "date";
506
+ const date = dayjs2__default.default(value);
507
+ if (!date.isValid()) return String(value);
508
+ switch (mode) {
509
+ case "date":
510
+ return date.format("DD/MM/YYYY");
511
+ case "time":
512
+ return date.format("hh:mm A");
513
+ case "datetime":
514
+ return date.format("DD/MM/YYYY hh:mm A");
515
+ default:
516
+ return date.format("DD/MM/YYYY");
517
+ }
518
+ }
519
+ };
520
+
521
+ // src/utils/ckeditorLoader.ts
522
+ var loadCKEditor = (scriptPath = "/lib/ckeditor/ckeditor.js") => {
523
+ return new Promise((resolve, reject) => {
524
+ if (window.ClassicEditor) {
525
+ resolve();
526
+ return;
527
+ }
528
+ const existingScript = document.querySelector(`script[src="${scriptPath}"]`);
529
+ if (existingScript) {
530
+ existingScript.addEventListener("load", () => {
531
+ if (window.ClassicEditor) {
532
+ resolve();
533
+ } else {
534
+ reject(new Error("CKEditor script loaded but ClassicEditor not found on window"));
535
+ }
536
+ });
537
+ existingScript.addEventListener("error", () => {
538
+ reject(new Error("Failed to load CKEditor script"));
539
+ });
540
+ return;
541
+ }
542
+ const script = document.createElement("script");
543
+ script.src = scriptPath;
544
+ script.async = true;
545
+ script.onload = () => {
546
+ const checkInterval = setInterval(() => {
547
+ if (window.ClassicEditor) {
548
+ clearInterval(checkInterval);
549
+ resolve();
550
+ }
551
+ }, 100);
552
+ setTimeout(() => {
553
+ clearInterval(checkInterval);
554
+ if (!window.ClassicEditor) {
555
+ reject(new Error("CKEditor script loaded but ClassicEditor not found on window after 10 seconds"));
556
+ }
557
+ }, 1e4);
558
+ };
559
+ script.onerror = () => {
560
+ reject(new Error(`Failed to load CKEditor from ${scriptPath}`));
561
+ };
562
+ document.head.appendChild(script);
563
+ });
564
+ };
565
+ var isCKEditorAvailable = () => {
566
+ return typeof window !== "undefined" && typeof window.ClassicEditor !== "undefined";
567
+ };
568
+ var waitForCKEditor = (timeout = 1e4) => {
569
+ return new Promise((resolve, reject) => {
570
+ if (isCKEditorAvailable()) {
571
+ resolve();
572
+ return;
573
+ }
574
+ const startTime = Date.now();
575
+ const checkInterval = setInterval(() => {
576
+ if (isCKEditorAvailable()) {
577
+ clearInterval(checkInterval);
578
+ resolve();
579
+ } else if (Date.now() - startTime > timeout) {
580
+ clearInterval(checkInterval);
581
+ reject(new Error("CKEditor not available after timeout"));
582
+ }
583
+ }, 100);
584
+ });
585
+ };
586
+
587
+ // src/hooks/useCKEditor.ts
588
+ var useCKEditor = (options = {}) => {
589
+ const {
590
+ scriptPath = "/lib/ckeditor/ckeditor.js",
591
+ autoLoad = true,
592
+ timeout = 1e4
593
+ } = options;
594
+ const [isReady, setIsReady] = react.useState(false);
595
+ const [isLoading, setIsLoading] = react.useState(false);
596
+ const [error, setError] = react.useState(null);
597
+ const load = async () => {
598
+ if (isCKEditorAvailable()) {
599
+ setIsReady(true);
600
+ setIsLoading(false);
601
+ return;
602
+ }
603
+ setIsLoading(true);
604
+ setError(null);
605
+ try {
606
+ await loadCKEditor(scriptPath);
607
+ setIsReady(true);
608
+ } catch (err) {
609
+ const error2 = err instanceof Error ? err : new Error("Failed to load CKEditor");
610
+ setError(error2);
611
+ setIsReady(false);
612
+ } finally {
613
+ setIsLoading(false);
614
+ }
615
+ };
616
+ react.useEffect(() => {
617
+ if (isCKEditorAvailable()) {
618
+ setIsReady(true);
619
+ return;
620
+ }
621
+ if (autoLoad) {
622
+ load();
623
+ } else {
624
+ waitForCKEditor(timeout).then(() => setIsReady(true)).catch((err) => setError(err instanceof Error ? err : new Error("CKEditor not available")));
625
+ }
626
+ }, [scriptPath, autoLoad, timeout]);
627
+ return {
628
+ isReady,
629
+ isLoading,
630
+ error,
631
+ load
632
+ };
633
+ };
634
+ var CKEditorField = ({ field, control, defaultValue, rules, errors, setValue, formSchema, services }) => {
635
+ const theme = material.useTheme();
636
+ const editorContainerRef = react.useRef(null);
637
+ const fileUploadService = services?.fileUpload || defaultFileUploadService;
638
+ const fileBaseUrl = services?.fileBaseUrl || "";
639
+ const licenseKey = services?.ckEditorLicenseKey || "";
640
+ const ckEditorScriptPath = services?.ckEditorScriptPath || "/lib/ckeditor/ckeditor.js";
641
+ const { isReady: isCKEditorReady, isLoading: isCKEditorLoading, error: ckEditorError } = useCKEditor({
642
+ scriptPath: ckEditorScriptPath,
643
+ autoLoad: true
644
+ });
645
+ const createCustomUploadAdapter = react.useCallback((loader) => {
646
+ return {
647
+ upload: async () => {
648
+ if (!formSchema?.name) {
649
+ throw new Error("Form schema name is required for image uploads");
650
+ }
651
+ try {
652
+ const file = await loader.file;
653
+ if (!file) {
654
+ throw new Error("No file provided");
655
+ }
656
+ if (!file.type.startsWith("image/")) {
657
+ throw new Error("Only image files are allowed");
658
+ }
659
+ const uploadedFiles = await fileUploadService.uploadFiles(
660
+ formSchema.name,
661
+ field.name,
662
+ [file]
663
+ );
664
+ if (uploadedFiles && uploadedFiles.length > 0 && uploadedFiles[0].fileUrl) {
665
+ const fileUrl = uploadedFiles[0].fileUrl;
666
+ const isFullUrl = fileUrl.startsWith("http://") || fileUrl.startsWith("https://");
667
+ const url = isFullUrl ? fileUrl : fileBaseUrl + fileUrl;
668
+ return {
669
+ default: url
670
+ };
671
+ }
672
+ throw new Error("Upload failed: No file URL returned");
673
+ } catch (error) {
674
+ console.error("Upload error:", error);
675
+ const errorMessage = error.response?.data?.message || error.message || "Upload failed";
676
+ throw new Error(errorMessage);
677
+ }
678
+ },
679
+ abort: () => {
680
+ console.log("Upload aborted");
681
+ }
682
+ };
683
+ }, [formSchema?.name, field.name, fileUploadService, fileBaseUrl]);
684
+ if (isCKEditorLoading) {
685
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { children: [
686
+ /* @__PURE__ */ jsxRuntime.jsx(material.FormLabel, { required: field.required, error: !!errors[field.name], children: field.label }),
687
+ /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { p: 2, textAlign: "center", color: "text.secondary" }, children: "Loading editor..." })
688
+ ] });
689
+ }
690
+ if (ckEditorError || !isCKEditorReady) {
691
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { children: [
692
+ /* @__PURE__ */ jsxRuntime.jsx(material.FormLabel, { required: field.required, error: !!errors[field.name], children: field.label }),
693
+ /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { p: 2, border: "1px solid", borderColor: "error.main", borderRadius: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(material.FormHelperText, { error: true, children: ckEditorError?.message || "CKEditor failed to load. Please ensure the CKEditor script is loaded." }) })
694
+ ] });
695
+ }
696
+ return /* @__PURE__ */ jsxRuntime.jsx(
697
+ reactHookForm.Controller,
698
+ {
699
+ name: field.name,
700
+ control,
701
+ defaultValue: defaultValue || "",
702
+ rules,
703
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { children: [
704
+ /* @__PURE__ */ jsxRuntime.jsx(
705
+ material.FormLabel,
706
+ {
707
+ required: field.required,
708
+ error: !!errors[field.name],
709
+ children: field.label
710
+ }
711
+ ),
712
+ /* @__PURE__ */ jsxRuntime.jsx(
713
+ material.Box,
714
+ {
715
+ ref: editorContainerRef,
716
+ sx: {
717
+ "& .ck-editor": {
718
+ borderRadius: "4px",
719
+ "& .ck-toolbar": {
720
+ width: "100%",
721
+ maxWidth: "100%",
722
+ overflow: "visible",
723
+ display: "flex",
724
+ flexWrap: "wrap",
725
+ "& .ck-toolbar__items": {
726
+ display: "flex",
727
+ flexWrap: "wrap !important",
728
+ width: "100%",
729
+ maxWidth: "100%",
730
+ "& > *": {
731
+ flexShrink: 0
732
+ }
733
+ }
734
+ },
735
+ "& .ck-editor__editable": {
736
+ minHeight: "100px"
737
+ },
738
+ "&:hover": {
739
+ borderColor: errors[field.name] ? theme.palette.error.main : theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.87)" : theme.palette.primary.main
740
+ },
741
+ "& .ck-focused": {
742
+ border: errors[field.name] ? `1px solid ${theme.palette.error.main} !important` : `1px solid ${theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.23)" : `${theme.palette.primary.main}`} !important`,
743
+ boxShadow: errors[field.name] ? `0 0 0 1px ${theme.palette.error.main}` : `0 0 0 1px ${material.alpha(theme.palette.primary.main, 0.5)} !important`
744
+ }
745
+ }
746
+ },
747
+ children: window.ClassicEditor && isCKEditorReady && /* @__PURE__ */ jsxRuntime.jsx(
748
+ ckeditor5React.CKEditor,
749
+ {
750
+ editor: window.ClassicEditor,
751
+ config: {
752
+ licenseKey,
753
+ initialData: formField.value || ""
754
+ },
755
+ data: formField.value || "",
756
+ onReady: (editor) => {
757
+ if (formSchema?.name) {
758
+ try {
759
+ const fileRepository = editor.plugins.get("FileRepository");
760
+ if (fileRepository) {
761
+ fileRepository.createUploadAdapter = (loader) => {
762
+ return createCustomUploadAdapter(loader);
763
+ };
764
+ } else {
765
+ console.warn("FileRepository plugin not found");
766
+ }
767
+ } catch (error) {
768
+ console.error("Error setting up upload adapter:", error);
769
+ }
770
+ } else {
771
+ console.warn("Form schema name not available, upload adapter not set");
772
+ }
773
+ if (defaultValue && !formField.value) {
774
+ editor.setData(defaultValue);
775
+ setValue?.(field.name, defaultValue);
776
+ }
777
+ },
778
+ onChange: (_event, editor) => {
779
+ const data = editor.getData();
780
+ formField.onChange(data);
781
+ },
782
+ onBlur: () => {
783
+ formField.onBlur();
784
+ }
785
+ }
786
+ )
787
+ }
788
+ ),
789
+ errors[field.name] && /* @__PURE__ */ jsxRuntime.jsx(material.FormHelperText, { error: true, sx: { mt: 0.5, mx: 0 }, children: errors[field.name]?.message })
790
+ ] })
791
+ },
792
+ field.name
793
+ );
794
+ };
795
+ var FileField = ({
796
+ field,
797
+ control,
798
+ defaultValue,
799
+ rules,
800
+ errors,
801
+ formSchema,
802
+ uploadingFiles = {},
803
+ setUploadingFiles,
804
+ setError,
805
+ clearErrors,
806
+ services
807
+ }) => {
808
+ const theme = material.useTheme();
809
+ const isMobile = material.useMediaQuery(theme.breakpoints.down("md"));
810
+ const acceptTypes = field.validation?.allowedFileTypes ? field.validation.allowedFileTypes.map((type) => `.${type.replace(".", "")}`).join(",") : void 0;
811
+ const isMultiple = field.allowMultiple || false;
812
+ const fileUploadService = services?.fileUpload || defaultFileUploadService;
813
+ return /* @__PURE__ */ jsxRuntime.jsx(
814
+ reactHookForm.Controller,
815
+ {
816
+ name: field.name,
817
+ control,
818
+ defaultValue,
819
+ rules,
820
+ render: ({ field: formField }) => {
821
+ const isUploading = uploadingFiles[field.name] || false;
822
+ let files = [];
823
+ if (isMultiple) {
824
+ files = Array.isArray(formField.value) ? formField.value : [];
825
+ } else {
826
+ files = formField.value ? [formField.value] : [];
827
+ }
828
+ const hasFiles = files.length > 0;
829
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { children: [
830
+ /* @__PURE__ */ jsxRuntime.jsx(
831
+ material.FormLabel,
832
+ {
833
+ required: field.required,
834
+ error: !!errors[field.name],
835
+ children: field.label
836
+ }
837
+ ),
838
+ /* @__PURE__ */ jsxRuntime.jsxs(
839
+ material.Box,
840
+ {
841
+ component: "label",
842
+ htmlFor: `file-input-${field.name}`,
843
+ sx: {
844
+ display: "flex",
845
+ flexDirection: "column",
846
+ alignItems: "center",
847
+ justifyContent: "center",
848
+ border: "1px dashed",
849
+ borderColor: errors[field.name] ? "error.main" : isUploading ? "primary.main" : hasFiles ? "primary.main" : "divider",
850
+ p: 1,
851
+ cursor: isUploading ? "wait" : "pointer",
852
+ transition: "all 0.2s ease-in-out",
853
+ backgroundColor: isUploading || hasFiles ? "action.hover" : "background.paper",
854
+ opacity: isUploading ? 0.7 : 1,
855
+ pointerEvents: isUploading ? "none" : "auto",
856
+ "&:hover": {
857
+ borderColor: isUploading ? "primary.main" : "primary.main",
858
+ backgroundColor: "action.hover"
859
+ }
860
+ },
861
+ children: [
862
+ /* @__PURE__ */ jsxRuntime.jsx(
863
+ "input",
864
+ {
865
+ id: `file-input-${field.name}`,
866
+ type: "file",
867
+ hidden: true,
868
+ multiple: isMultiple,
869
+ accept: acceptTypes,
870
+ onChange: async (e) => {
871
+ const fileList = e.target.files;
872
+ if (!fileList || fileList.length === 0) return;
873
+ const newFiles = Array.from(fileList);
874
+ const isUploading2 = uploadingFiles[field.name] || false;
875
+ if (isUploading2) {
876
+ e.target.value = "";
877
+ return;
878
+ }
879
+ for (const file of newFiles) {
880
+ const validationResult = validateFile(file, field);
881
+ if (validationResult !== true) {
882
+ setError?.(field.name, {
883
+ type: "manual",
884
+ message: validationResult
885
+ });
886
+ e.target.value = "";
887
+ return;
888
+ }
889
+ }
890
+ try {
891
+ setUploadingFiles?.((prev) => ({ ...prev, [field.name]: true }));
892
+ clearErrors?.(field.name);
893
+ if (!formSchema?.name) {
894
+ throw new Error("Form schema name is required for file uploads");
895
+ }
896
+ const uploadedFiles = await fileUploadService.uploadFiles(
897
+ formSchema.name,
898
+ field.name,
899
+ newFiles
900
+ );
901
+ if (isMultiple) {
902
+ const currentValue = formField.value;
903
+ const existingFiles = Array.isArray(currentValue) ? currentValue.filter((item) => item && typeof item === "object" && "fileName" in item) : [];
904
+ const allUploadedFiles = [...existingFiles, ...uploadedFiles];
905
+ formField.onChange(allUploadedFiles);
906
+ } else {
907
+ formField.onChange(uploadedFiles[0] || null);
908
+ }
909
+ } catch (error) {
910
+ console.error(`Failed to upload files for field ${field.name}:`, error);
911
+ const errorMessage = error.response?.data?.message || error.message || "Failed to upload files";
912
+ setError?.(field.name, {
913
+ type: "manual",
914
+ message: `Failed to upload files: ${errorMessage}`
915
+ });
916
+ } finally {
917
+ setUploadingFiles?.((prev) => ({ ...prev, [field.name]: false }));
918
+ e.target.value = "";
919
+ }
920
+ },
921
+ disabled: uploadingFiles[field.name] || false
922
+ }
923
+ ),
924
+ isUploading ? /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 1, py: 3, width: "100%" }, children: [
925
+ /* @__PURE__ */ jsxRuntime.jsx(material.CircularProgress, { size: 40 }),
926
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", color: "primary.main", sx: { fontWeight: 500 }, children: "Uploading files..." }),
927
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", children: "Please wait while files are being uploaded" })
928
+ ] }) : !hasFiles ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
929
+ /* @__PURE__ */ jsxRuntime.jsx(CloudUploadIcon__default.default, { sx: { fontSize: 40, color: "text.secondary", mb: 1 } }),
930
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Typography, { variant: "caption", color: "text.secondary", children: [
931
+ "Click to upload or drag and drop",
932
+ isMultiple && " (multiple files allowed)"
933
+ ] }),
934
+ field.validation?.allowedFileTypes && field.validation.allowedFileTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(material.Typography, { variant: "caption", color: "text.secondary", sx: { mt: 0.5 }, children: [
935
+ "Allowed: ",
936
+ field.validation.allowedFileTypes.join(", ")
937
+ ] }),
938
+ field.validation?.maxFileSize && /* @__PURE__ */ jsxRuntime.jsxs(material.Typography, { variant: "caption", color: "text.secondary", sx: { mt: 0.5 }, children: [
939
+ "Max size: ",
940
+ formatFileSize(field.validation.maxFileSize),
941
+ " per file"
942
+ ] })
943
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { width: "100%" }, children: [
944
+ isMultiple && /* @__PURE__ */ jsxRuntime.jsxs(material.Typography, { variant: "body2", sx: { fontWeight: 500, mb: 1.5 }, children: [
945
+ files.length,
946
+ " file",
947
+ files.length !== 1 ? "s" : "",
948
+ " uploaded"
949
+ ] }),
950
+ files.length === 1 && !isMultiple ? /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 2, width: "100%" }, children: [
951
+ /* @__PURE__ */ jsxRuntime.jsx(InsertDriveFileIcon__default.default, { sx: { fontSize: 40, color: "primary.main" } }),
952
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { flexGrow: 1, minWidth: 0 }, children: [
953
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", maxWidth: isMobile ? "200px" : "300px" }, children: files[0] instanceof File ? files[0].name : files[0].originalName || files[0].fileName }),
954
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", children: formatFileSize(files[0].size || 0) })
955
+ ] }),
956
+ /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: "Remove file", placement: "bottom", arrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
957
+ material.IconButton,
958
+ {
959
+ size: "small",
960
+ onClick: (e) => {
961
+ e.preventDefault();
962
+ e.stopPropagation();
963
+ formField.onChange(null);
964
+ const fileInput = document.getElementById(`file-input-${field.name}`);
965
+ if (fileInput) {
966
+ fileInput.value = "";
967
+ }
968
+ },
969
+ sx: { color: "error.main" },
970
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon__default.default, { fontSize: "small" })
971
+ }
972
+ ) })
973
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", flexDirection: "column", gap: 1, width: "100%" }, children: files.map((file, index) => {
974
+ const fileName = file instanceof File ? file.name : file.originalName || file.fileName;
975
+ return /* @__PURE__ */ jsxRuntime.jsxs(
976
+ material.Box,
977
+ {
978
+ sx: {
979
+ display: "flex",
980
+ alignItems: "center",
981
+ gap: 1.5,
982
+ p: 1,
983
+ borderRadius: 1,
984
+ backgroundColor: "background.default",
985
+ border: "1px solid",
986
+ borderColor: "divider"
987
+ },
988
+ children: [
989
+ /* @__PURE__ */ jsxRuntime.jsx(InsertDriveFileIcon__default.default, { sx: { fontSize: 32, color: "primary.main" } }),
990
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { flexGrow: 1, minWidth: 0 }, children: [
991
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis" }, children: fileName }),
992
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", children: formatFileSize(file.size || 0) })
993
+ ] }),
994
+ /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: "Remove file", placement: "bottom", arrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
995
+ material.IconButton,
996
+ {
997
+ size: "small",
998
+ onClick: (e) => {
999
+ e.preventDefault();
1000
+ e.stopPropagation();
1001
+ if (isMultiple) {
1002
+ const updatedFiles = files.filter((_, i) => i !== index);
1003
+ formField.onChange(updatedFiles.length > 0 ? updatedFiles : []);
1004
+ } else {
1005
+ formField.onChange(null);
1006
+ }
1007
+ },
1008
+ sx: { color: "error.main" },
1009
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon__default.default, { fontSize: "small" })
1010
+ }
1011
+ ) })
1012
+ ]
1013
+ },
1014
+ `${fileName}-${index}`
1015
+ );
1016
+ }) })
1017
+ ] })
1018
+ ]
1019
+ }
1020
+ ),
1021
+ errors[field.name] && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "error", sx: { mt: 1, display: "block" }, children: errors[field.name]?.message })
1022
+ ] });
1023
+ }
1024
+ },
1025
+ field.name
1026
+ );
1027
+ };
1028
+ var FormReferenceField = ({ field, control, defaultValue, rules, errors, services }) => {
1029
+ const isMultiple = field.allowMultiple || false;
1030
+ const [options, setOptions] = react.useState([]);
1031
+ const [isLoading, setIsLoading] = react.useState(false);
1032
+ const formReferenceService = services?.formReference || defaultFormReferenceService;
1033
+ react.useEffect(() => {
1034
+ if (!field.referenceFormName || !field.referenceFieldName) return;
1035
+ setIsLoading(true);
1036
+ formReferenceService.fetchOptions(field.referenceFormName, field.referenceFieldName).then((opts) => {
1037
+ setOptions(opts);
1038
+ }).catch((error) => {
1039
+ console.error("Failed to fetch form reference options:", error);
1040
+ setOptions([]);
1041
+ }).finally(() => {
1042
+ setIsLoading(false);
1043
+ });
1044
+ }, [field.referenceFormName, field.referenceFieldName, formReferenceService]);
1045
+ const selectOptions = react.useMemo(() => {
1046
+ return options.map((opt) => ({
1047
+ value: String(opt.value),
1048
+ label: opt.label
1049
+ }));
1050
+ }, [options]);
1051
+ const fieldDefaultValue = defaultValue ?? getDefaultValue(field);
1052
+ const fieldRules = rules ?? buildFieldRules(field);
1053
+ const isDisabled = !field.referenceFormName || !field.referenceFieldName;
1054
+ const SelectComponent = services?.SelectComponent || SimpleSelect;
1055
+ return /* @__PURE__ */ jsxRuntime.jsx(
1056
+ reactHookForm.Controller,
1057
+ {
1058
+ name: field.name,
1059
+ control,
1060
+ defaultValue: fieldDefaultValue,
1061
+ rules: fieldRules,
1062
+ render: ({ field: formField }) => {
1063
+ return /* @__PURE__ */ jsxRuntime.jsx(
1064
+ SelectComponent,
1065
+ {
1066
+ label: field.label,
1067
+ value: formField.value,
1068
+ onChange: (value) => {
1069
+ formField.onChange(value);
1070
+ },
1071
+ options: selectOptions,
1072
+ placeholder: field.placeholder || "Search and select...",
1073
+ helperText: errors[field.name]?.message,
1074
+ fullWidth: true,
1075
+ size: "small",
1076
+ required: field.required,
1077
+ error: !!errors[field.name],
1078
+ disabled: isDisabled || isLoading,
1079
+ multiple: isMultiple,
1080
+ isLoading
1081
+ }
1082
+ );
1083
+ }
1084
+ },
1085
+ field.name
1086
+ );
1087
+ };
1088
+ var ApiReferenceField = ({ field, control, defaultValue, rules, errors, services }) => {
1089
+ const isMultiple = field.allowMultiple || false;
1090
+ const [options, setOptions] = react.useState([]);
1091
+ const [isLoading, setIsLoading] = react.useState(false);
1092
+ const apiReferenceService = services?.apiReference || defaultApiReferenceService;
1093
+ react.useEffect(() => {
1094
+ if (!field.apiEndpoint || !field.apiLabelField) return;
1095
+ setIsLoading(true);
1096
+ apiReferenceService.fetchOptions(field.apiEndpoint, field.apiLabelField, field.apiValueField || "_id").then((opts) => {
1097
+ setOptions(opts);
1098
+ }).catch((error) => {
1099
+ console.error("Failed to fetch API reference options:", error);
1100
+ setOptions([]);
1101
+ }).finally(() => {
1102
+ setIsLoading(false);
1103
+ });
1104
+ }, [field.apiEndpoint, field.apiLabelField, field.apiValueField, apiReferenceService]);
1105
+ const selectOptions = react.useMemo(() => {
1106
+ return options.map((opt) => ({
1107
+ value: String(opt.value),
1108
+ label: opt.label
1109
+ }));
1110
+ }, [options]);
1111
+ const fieldDefaultValue = defaultValue ?? getDefaultValue(field);
1112
+ const fieldRules = rules ?? buildFieldRules(field);
1113
+ const isDisabled = !field.apiEndpoint || !field.apiLabelField;
1114
+ const SelectComponent = services?.SelectComponent || SimpleSelect;
1115
+ return /* @__PURE__ */ jsxRuntime.jsx(
1116
+ reactHookForm.Controller,
1117
+ {
1118
+ name: field.name,
1119
+ control,
1120
+ defaultValue: fieldDefaultValue,
1121
+ rules: fieldRules,
1122
+ render: ({ field: formField }) => {
1123
+ return /* @__PURE__ */ jsxRuntime.jsx(
1124
+ SelectComponent,
1125
+ {
1126
+ label: field.label,
1127
+ value: formField.value,
1128
+ onChange: (value) => {
1129
+ formField.onChange(value);
1130
+ },
1131
+ options: selectOptions,
1132
+ placeholder: field.placeholder || "Search and select...",
1133
+ helperText: errors[field.name]?.message,
1134
+ fullWidth: true,
1135
+ size: "small",
1136
+ required: field.required,
1137
+ error: !!errors[field.name],
1138
+ disabled: isDisabled || isLoading,
1139
+ multiple: isMultiple,
1140
+ isLoading
1141
+ }
1142
+ );
1143
+ }
1144
+ },
1145
+ field.name
1146
+ );
1147
+ };
1148
+ var textFieldSlotProps = (field, errors) => ({
1149
+ fullWidth: true,
1150
+ size: "small",
1151
+ required: field.required,
1152
+ error: !!errors[field.name],
1153
+ helperText: errors[field.name]?.message
1154
+ });
1155
+ function resolveDatePickerMode(field) {
1156
+ if (field.datePickerMode) return field.datePickerMode;
1157
+ return field?.displayTime ? "datetime" : "date";
1158
+ }
1159
+ var DateTimePickerField = ({ field, control, defaultValue, rules, errors }) => {
1160
+ const mode = resolveDatePickerMode(field);
1161
+ return /* @__PURE__ */ jsxRuntime.jsx(
1162
+ reactHookForm.Controller,
1163
+ {
1164
+ name: field.name,
1165
+ control,
1166
+ defaultValue,
1167
+ rules,
1168
+ render: ({ field: formField }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1169
+ /* @__PURE__ */ jsxRuntime.jsx(
1170
+ material.FormLabel,
1171
+ {
1172
+ required: field.required,
1173
+ error: !!errors[field.name],
1174
+ children: field.label
1175
+ }
1176
+ ),
1177
+ /* @__PURE__ */ jsxRuntime.jsxs(LocalizationProvider.LocalizationProvider, { dateAdapter: AdapterDayjs.AdapterDayjs, children: [
1178
+ mode === "date" && /* @__PURE__ */ jsxRuntime.jsx(
1179
+ DatePicker.DatePicker,
1180
+ {
1181
+ format: "DD-MM-YYYY",
1182
+ value: formField.value ? dayjs2__default.default(formField.value) : null,
1183
+ onChange: (date) => formField.onChange(date?.toISOString() ?? null),
1184
+ slotProps: { textField: textFieldSlotProps(field, errors) }
1185
+ }
1186
+ ),
1187
+ mode === "datetime" && /* @__PURE__ */ jsxRuntime.jsx(
1188
+ DateTimePicker.DateTimePicker,
1189
+ {
1190
+ format: "DD-MM-YYYY hh:mm A",
1191
+ value: formField.value ? dayjs2__default.default(formField.value) : null,
1192
+ onChange: (date) => formField.onChange(date?.toISOString() ?? null),
1193
+ slotProps: { textField: textFieldSlotProps(field, errors) }
1194
+ }
1195
+ ),
1196
+ mode === "time" && /* @__PURE__ */ jsxRuntime.jsx(
1197
+ TimePicker.TimePicker,
1198
+ {
1199
+ format: "hh:mm A",
1200
+ value: formField.value ? dayjs2__default.default(formField.value) : null,
1201
+ onChange: (date) => formField.onChange(date?.toISOString() ?? null),
1202
+ slotProps: { textField: textFieldSlotProps(field, errors) }
1203
+ }
1204
+ )
1205
+ ] })
1206
+ ] })
1207
+ },
1208
+ field.name
1209
+ );
1210
+ };
1211
+ var FieldRenderer = (props) => {
1212
+ const { field, formSchema, uploadingFiles, setUploadingFiles, setError, clearErrors, services } = props;
1213
+ const rules = buildFieldRules(field);
1214
+ const defaultValue = getDefaultValue(field);
1215
+ const commonProps = {
1216
+ field,
1217
+ control: props.control,
1218
+ defaultValue,
1219
+ rules,
1220
+ errors: props.errors,
1221
+ setValue: props.setValue,
1222
+ formSchema,
1223
+ services
1224
+ };
1225
+ switch (field.type) {
1226
+ case "text":
1227
+ case "email":
1228
+ case "number":
1229
+ return /* @__PURE__ */ jsxRuntime.jsx(TextField, { ...commonProps });
1230
+ case "select":
1231
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectField, { ...commonProps, services });
1232
+ case "checkbox":
1233
+ return /* @__PURE__ */ jsxRuntime.jsx(CheckboxField, { ...commonProps });
1234
+ case "radio":
1235
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioField, { ...commonProps });
1236
+ case "datepicker":
1237
+ return /* @__PURE__ */ jsxRuntime.jsx(DateTimePickerField, { ...commonProps });
1238
+ case "toggle":
1239
+ return /* @__PURE__ */ jsxRuntime.jsx(ToggleField, { ...commonProps });
1240
+ case "color":
1241
+ return /* @__PURE__ */ jsxRuntime.jsx(ColorField, { ...commonProps });
1242
+ case "ckeditor":
1243
+ return /* @__PURE__ */ jsxRuntime.jsx(CKEditorField, { ...commonProps, formSchema, setValue: props.setValue });
1244
+ case "file":
1245
+ return /* @__PURE__ */ jsxRuntime.jsx(
1246
+ FileField,
1247
+ {
1248
+ ...commonProps,
1249
+ uploadingFiles,
1250
+ setUploadingFiles,
1251
+ setError,
1252
+ clearErrors
1253
+ }
1254
+ );
1255
+ case "formReference":
1256
+ return /* @__PURE__ */ jsxRuntime.jsx(FormReferenceField, { ...commonProps, services });
1257
+ case "apiReference":
1258
+ return /* @__PURE__ */ jsxRuntime.jsx(ApiReferenceField, { ...commonProps, services });
1259
+ default:
1260
+ return null;
1261
+ }
1262
+ };
1263
+ var FieldView = ({ field, value, services }) => {
1264
+ const dateFormatter = services?.dateFormatter || defaultDateFormatterService;
1265
+ const FileDisplayComponent = services?.FileDisplayComponent;
1266
+ const CKEditorDisplayComponent = services?.CKEditorDisplayComponent;
1267
+ const formattedValue = formatFieldValue(field, value, dateFormatter);
1268
+ if (field.type === "file") {
1269
+ if (FileDisplayComponent) {
1270
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1271
+ material.Box,
1272
+ {
1273
+ sx: {
1274
+ display: "flex",
1275
+ flexDirection: "column",
1276
+ gap: 0.5,
1277
+ py: 1.5,
1278
+ px: 1,
1279
+ borderColor: "divider"
1280
+ },
1281
+ children: [
1282
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: field.label }),
1283
+ /* @__PURE__ */ jsxRuntime.jsx(FileDisplayComponent, { fieldValue: value })
1284
+ ]
1285
+ },
1286
+ field.name
1287
+ );
1288
+ }
1289
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1290
+ material.Box,
1291
+ {
1292
+ sx: {
1293
+ display: "flex",
1294
+ flexDirection: "column",
1295
+ gap: 0.5,
1296
+ py: 1.5,
1297
+ px: 1,
1298
+ borderColor: "divider"
1299
+ },
1300
+ children: [
1301
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: field.label }),
1302
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body1", sx: { color: "text.secondary" }, children: value ? Array.isArray(value) ? `${value.length} file(s)` : "1 file" : "\u2014" })
1303
+ ]
1304
+ },
1305
+ field.name
1306
+ );
1307
+ }
1308
+ if (field.type === "ckeditor") {
1309
+ if (CKEditorDisplayComponent) {
1310
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1311
+ material.Box,
1312
+ {
1313
+ sx: {
1314
+ display: "flex",
1315
+ flexDirection: "column",
1316
+ gap: 0.5,
1317
+ py: 1.5,
1318
+ px: 1,
1319
+ borderColor: "divider"
1320
+ },
1321
+ children: [
1322
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: field.label }),
1323
+ /* @__PURE__ */ jsxRuntime.jsx(
1324
+ CKEditorDisplayComponent,
1325
+ {
1326
+ content: value || "",
1327
+ maxLength: 150,
1328
+ showViewButton: true
1329
+ }
1330
+ )
1331
+ ]
1332
+ },
1333
+ field.name
1334
+ );
1335
+ }
1336
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1337
+ material.Box,
1338
+ {
1339
+ sx: {
1340
+ display: "flex",
1341
+ flexDirection: "column",
1342
+ gap: 0.5,
1343
+ py: 1.5,
1344
+ px: 1,
1345
+ borderColor: "divider"
1346
+ },
1347
+ children: [
1348
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: field.label }),
1349
+ /* @__PURE__ */ jsxRuntime.jsx(
1350
+ material.Typography,
1351
+ {
1352
+ variant: "body1",
1353
+ sx: {
1354
+ color: formattedValue === "\u2014" ? "text.disabled" : "text.primary",
1355
+ fontStyle: formattedValue === "\u2014" ? "italic" : "normal"
1356
+ },
1357
+ dangerouslySetInnerHTML: { __html: value || "" }
1358
+ }
1359
+ )
1360
+ ]
1361
+ },
1362
+ field.name
1363
+ );
1364
+ }
1365
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1366
+ material.Box,
1367
+ {
1368
+ sx: {
1369
+ display: "flex",
1370
+ flexDirection: "column",
1371
+ gap: 0.5,
1372
+ py: 1.5,
1373
+ px: 1,
1374
+ borderColor: "divider"
1375
+ },
1376
+ children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { fontWeight: 500 }, children: field.label }),
1378
+ /* @__PURE__ */ jsxRuntime.jsx(
1379
+ material.Typography,
1380
+ {
1381
+ variant: "body1",
1382
+ sx: {
1383
+ color: formattedValue === "\u2014" ? "text.disabled" : "text.primary",
1384
+ fontStyle: formattedValue === "\u2014" ? "italic" : "normal",
1385
+ fontWeight: 400,
1386
+ fontSize: "0.875rem",
1387
+ lineHeight: 1.5
1388
+ },
1389
+ children: formattedValue
1390
+ }
1391
+ )
1392
+ ]
1393
+ },
1394
+ field.name
1395
+ );
1396
+ };
1397
+ var formatFieldValue = (field, value, dateFormatter, services) => {
1398
+ if (value === null || value === void 0 || value === "") {
1399
+ return "\u2014";
1400
+ }
1401
+ switch (field.type) {
1402
+ case "checkbox":
1403
+ case "toggle":
1404
+ return value ? "Yes" : "No";
1405
+ case "datepicker":
1406
+ return dateFormatter?.format(value, { datePickerMode: field.datePickerMode }) || String(value);
1407
+ case "select":
1408
+ case "formReference":
1409
+ case "apiReference":
1410
+ let values;
1411
+ if (field.allowMultiple) {
1412
+ values = Array.isArray(value) ? value : value ? [value] : [];
1413
+ } else {
1414
+ if (Array.isArray(value)) {
1415
+ values = value.length > 0 ? [value[0]] : [];
1416
+ } else {
1417
+ values = value ? [value] : [];
1418
+ }
1419
+ }
1420
+ if (values.length === 0) {
1421
+ return "\u2014";
1422
+ }
1423
+ const getLabelForValue = (val) => {
1424
+ if (field.options) {
1425
+ const normalizedOptions = normalizeOptions(field.options);
1426
+ const option = normalizedOptions.find((opt) => {
1427
+ return opt.value === val || String(opt.value) === String(val);
1428
+ });
1429
+ if (option) {
1430
+ return option.label;
1431
+ }
1432
+ }
1433
+ return String(val);
1434
+ };
1435
+ if (values.length > 1 || field.allowMultiple) {
1436
+ const labels = values.map((val) => getLabelForValue(val));
1437
+ return labels.join(", ");
1438
+ }
1439
+ return getLabelForValue(values[0]);
1440
+ case "radio":
1441
+ if (field.options) {
1442
+ const normalizedOptions = normalizeOptions(field.options);
1443
+ const option = normalizedOptions.find((opt) => {
1444
+ return opt.value === value;
1445
+ });
1446
+ if (option) {
1447
+ return option.label;
1448
+ }
1449
+ }
1450
+ return String(value);
1451
+ default:
1452
+ return String(value);
1453
+ }
1454
+ };
1455
+ var FormViewMode = ({ formSchema, initialValues, hideTitle = false, services }) => {
1456
+ const fieldsToRender = getAllFields(formSchema);
1457
+ const theme = material.useTheme();
1458
+ const isMobile = material.useMediaQuery(theme.breakpoints.down("md"));
1459
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { maxWidth: 600, mx: "auto", width: "100%" }, children: [
1460
+ !hideTitle && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "h6", gutterBottom: true, sx: { mb: 2, fontWeight: 600 }, children: formSchema.title }),
1461
+ formSchema.sections && formSchema.sections.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", flexDirection: "column", gap: 1.5 }, children: formSchema.sections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(material.Accordion, { defaultExpanded: sectionIndex === 0, children: [
1462
+ /* @__PURE__ */ jsxRuntime.jsx(
1463
+ material.AccordionSummary,
1464
+ {
1465
+ expandIcon: /* @__PURE__ */ jsxRuntime.jsx(ExpandMoreIcon__default.default, {}),
1466
+ "aria-controls": `panel-${section.id}-content`,
1467
+ id: `panel-${section.id}-header`,
1468
+ children: /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1469
+ /* @__PURE__ */ jsxRuntime.jsx(DoubleArrowOutlinedIcon__default.default, { fontSize: "small", color: "primary" }),
1470
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "subtitle1", sx: { fontWeight: 600 }, color: "primary", children: section.title })
1471
+ ] })
1472
+ }
1473
+ ),
1474
+ /* @__PURE__ */ jsxRuntime.jsxs(material.AccordionDetails, { children: [
1475
+ section.description && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", sx: { mb: 1.5, display: "block" }, children: section.description }),
1476
+ /* @__PURE__ */ jsxRuntime.jsx(
1477
+ material.Box,
1478
+ {
1479
+ sx: {
1480
+ display: "grid",
1481
+ gridTemplateColumns: isMobile ? "repeat(1, 1fr)" : "repeat(2, 1fr)",
1482
+ gap: 1
1483
+ },
1484
+ children: section.fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(FieldView, { field, value: initialValues?.[field.name], services }, field.name))
1485
+ }
1486
+ )
1487
+ ] })
1488
+ ] }, section.id)) }) : /* @__PURE__ */ jsxRuntime.jsx(
1489
+ material.Box,
1490
+ {
1491
+ sx: {
1492
+ display: "grid",
1493
+ gridTemplateColumns: "repeat(2, 1fr)",
1494
+ gap: 1
1495
+ },
1496
+ children: fieldsToRender.map((field) => /* @__PURE__ */ jsxRuntime.jsx(FieldView, { field, value: initialValues?.[field.name], services }, field.name))
1497
+ }
1498
+ )
1499
+ ] });
1500
+ };
1501
+ var FormRenderer = ({
1502
+ formSchema,
1503
+ onSubmit,
1504
+ onCancel,
1505
+ isLoading = false,
1506
+ onSuccess,
1507
+ initialValues,
1508
+ hideTitle = false,
1509
+ allowResetOnValuesChange = false,
1510
+ mode = "edit",
1511
+ services
1512
+ }) => {
1513
+ const {
1514
+ control,
1515
+ handleSubmit,
1516
+ reset,
1517
+ clearErrors,
1518
+ setValue,
1519
+ setError,
1520
+ formState: { errors }
1521
+ } = reactHookForm.useForm({
1522
+ defaultValues: initialValues || {}
1523
+ });
1524
+ const [submitError, setSubmitError] = react.useState(null);
1525
+ const prevInitialValuesRef = react.useRef(initialValues);
1526
+ const isFormInitializedRef = react.useRef(false);
1527
+ const [uploadingFiles, setUploadingFiles] = react.useState({});
1528
+ const [activeStep, setActiveStep] = react.useState(0);
1529
+ react.useEffect(() => {
1530
+ setActiveStep(0);
1531
+ }, [formSchema]);
1532
+ react.useEffect(() => {
1533
+ const wasUndefined = prevInitialValuesRef.current === void 0;
1534
+ const isNowDefined = initialValues !== void 0;
1535
+ if (initialValues) {
1536
+ const normalizedValues = normalizeInitialValues(initialValues, formSchema);
1537
+ if (allowResetOnValuesChange) {
1538
+ const prevValues = prevInitialValuesRef.current;
1539
+ const valuesChanged = !prevValues || JSON.stringify(prevValues) !== JSON.stringify(normalizedValues);
1540
+ if (valuesChanged) {
1541
+ reset(normalizedValues);
1542
+ setSubmitError(null);
1543
+ isFormInitializedRef.current = true;
1544
+ }
1545
+ } else if (wasUndefined && isNowDefined) {
1546
+ reset(normalizedValues);
1547
+ setSubmitError(null);
1548
+ isFormInitializedRef.current = true;
1549
+ }
1550
+ } else if (initialValues === void 0 && prevInitialValuesRef.current !== void 0) {
1551
+ setSubmitError(null);
1552
+ isFormInitializedRef.current = false;
1553
+ }
1554
+ prevInitialValuesRef.current = initialValues;
1555
+ }, [initialValues, reset, allowResetOnValuesChange, formSchema]);
1556
+ const fieldsToRender = react.useMemo(() => getAllFields(formSchema), [formSchema]);
1557
+ react.useMemo(() => {
1558
+ return fieldsToRender.filter(
1559
+ (field) => field.type === "formReference" && field.referenceFormName && field.referenceFieldName
1560
+ );
1561
+ }, [fieldsToRender]);
1562
+ react.useMemo(() => {
1563
+ return fieldsToRender.filter(
1564
+ (field) => field.type === "apiReference" && field.apiEndpoint && field.apiLabelField
1565
+ );
1566
+ }, [fieldsToRender]);
1567
+ const handleFormSubmit = async (data) => {
1568
+ setSubmitError(null);
1569
+ const transformedData = transformFormValues(data, formSchema);
1570
+ if (onSubmit) {
1571
+ try {
1572
+ await onSubmit(transformedData);
1573
+ if (onSuccess) {
1574
+ reset(initialValues || {});
1575
+ onSuccess();
1576
+ }
1577
+ } catch (error) {
1578
+ console.error("Form submission error:", error);
1579
+ let errorMessage = "Form submission failed. Please try again.";
1580
+ if (error?.response?.data) {
1581
+ const errorData = error.response.data;
1582
+ errorMessage = errorData.message || errorData.error || errorData.errors?.message || (Array.isArray(errorData.errors) ? errorData.errors.join(", ") : null) || errorData.msg || errorMessage;
1583
+ } else if (error?.message) {
1584
+ errorMessage = error.message;
1585
+ }
1586
+ setSubmitError(errorMessage);
1587
+ }
1588
+ } else {
1589
+ console.log("Form Data:", transformedData);
1590
+ }
1591
+ };
1592
+ if (mode === "view") {
1593
+ return /* @__PURE__ */ jsxRuntime.jsx(FormViewMode, { formSchema, initialValues, hideTitle, services });
1594
+ }
1595
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { component: "form", onSubmit: handleSubmit(handleFormSubmit), sx: { mx: "auto", width: "100%" }, children: [
1596
+ !hideTitle && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "h6", gutterBottom: true, sx: { mb: 2, fontWeight: 600 }, children: formSchema.title }),
1597
+ submitError && /* @__PURE__ */ jsxRuntime.jsx(material.Alert, { severity: "error", sx: { mb: 2 }, onClose: () => setSubmitError(null), children: submitError }),
1598
+ formSchema.sections && formSchema.sections.length > 0 ? (() => {
1599
+ const sectionDisplayMode = formSchema.settings?.sectionDisplayMode || "panel";
1600
+ const fieldsPerRow = formSchema.settings?.fieldsPerRow || 1;
1601
+ const gridColumns = Math.min(Math.max(1, fieldsPerRow), 3);
1602
+ const fullWidthFieldTypes = ["ckeditor"];
1603
+ const renderFieldsGrid = (section) => /* @__PURE__ */ jsxRuntime.jsx(
1604
+ material.Box,
1605
+ {
1606
+ sx: {
1607
+ display: "grid",
1608
+ gridTemplateColumns: {
1609
+ xs: "1fr",
1610
+ sm: gridColumns === 1 ? "1fr" : gridColumns === 2 ? "repeat(2, 1fr)" : "repeat(3, 1fr)"
1611
+ },
1612
+ gap: "10px"
1613
+ },
1614
+ children: section.fields.map((field) => {
1615
+ const shouldTakeFullWidth = fullWidthFieldTypes.includes(field.type);
1616
+ return /* @__PURE__ */ jsxRuntime.jsx(
1617
+ material.Box,
1618
+ {
1619
+ sx: {
1620
+ gridColumn: shouldTakeFullWidth ? {
1621
+ xs: "1 / -1",
1622
+ sm: "1 / -1"
1623
+ } : "auto"
1624
+ },
1625
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1626
+ FieldRenderer,
1627
+ {
1628
+ field,
1629
+ control,
1630
+ errors,
1631
+ setValue,
1632
+ formSchema,
1633
+ uploadingFiles,
1634
+ setUploadingFiles,
1635
+ setError,
1636
+ clearErrors,
1637
+ services
1638
+ }
1639
+ )
1640
+ },
1641
+ field.name
1642
+ );
1643
+ })
1644
+ }
1645
+ );
1646
+ if (sectionDisplayMode === "stepper") {
1647
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { border: "1px solid", borderColor: "divider", p: 5, backgroundColor: "background.paper" }, children: [
1648
+ /* @__PURE__ */ jsxRuntime.jsx(material.Stepper, { activeStep, orientation: "horizontal", children: formSchema.sections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(material.Step, { children: /* @__PURE__ */ jsxRuntime.jsx(material.StepLabel, { children: /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "subtitle1", sx: { fontWeight: 600 }, children: section.title }) }) }, section.id)) }),
1649
+ /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { mt: 5 }, children: formSchema.sections.map((section, sectionIndex) => {
1650
+ const sectionsLength = formSchema.sections?.length || 0;
1651
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1652
+ material.Box,
1653
+ {
1654
+ sx: {
1655
+ display: activeStep === sectionIndex ? "block" : "none"
1656
+ },
1657
+ children: [
1658
+ section.description && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", sx: { mb: 1.5, display: "block" }, children: section.description }),
1659
+ renderFieldsGrid(section),
1660
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { mt: 2, display: "flex", gap: 1, borderTop: "1px solid", pt: 2, borderColor: "divider", justifyContent: "center" }, children: [
1661
+ sectionIndex > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1662
+ material.Button,
1663
+ {
1664
+ size: "small",
1665
+ variant: "outlined",
1666
+ color: "success",
1667
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(ArrowBackIcon__default.default, {}),
1668
+ onClick: () => setActiveStep(sectionIndex - 1),
1669
+ children: "Previous"
1670
+ }
1671
+ ),
1672
+ sectionIndex < sectionsLength - 1 && /* @__PURE__ */ jsxRuntime.jsx(
1673
+ material.Button,
1674
+ {
1675
+ variant: "outlined",
1676
+ size: "small",
1677
+ color: "warning",
1678
+ endIcon: /* @__PURE__ */ jsxRuntime.jsx(ArrowForwardIcon__default.default, {}),
1679
+ onClick: () => {
1680
+ if (sectionIndex < sectionsLength - 1) {
1681
+ setActiveStep(sectionIndex + 1);
1682
+ }
1683
+ },
1684
+ children: "Next"
1685
+ }
1686
+ )
1687
+ ] })
1688
+ ]
1689
+ },
1690
+ section.id
1691
+ );
1692
+ }) })
1693
+ ] });
1694
+ }
1695
+ return /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", flexDirection: "column", gap: 1.5 }, children: formSchema.sections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(material.Accordion, { defaultExpanded: sectionIndex === 0, children: [
1696
+ /* @__PURE__ */ jsxRuntime.jsx(
1697
+ material.AccordionSummary,
1698
+ {
1699
+ expandIcon: /* @__PURE__ */ jsxRuntime.jsx(ExpandMoreIcon__default.default, {}),
1700
+ "aria-controls": `panel-${section.id}-content`,
1701
+ id: `panel-${section.id}-header`,
1702
+ children: /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1703
+ /* @__PURE__ */ jsxRuntime.jsx(DoubleArrowOutlinedIcon__default.default, { fontSize: "small", color: "primary" }),
1704
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "subtitle1", color: "primary", sx: { fontWeight: 600 }, children: section.title })
1705
+ ] })
1706
+ }
1707
+ ),
1708
+ /* @__PURE__ */ jsxRuntime.jsxs(material.AccordionDetails, { children: [
1709
+ section.description && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "caption", color: "text.secondary", sx: { mb: 1.5, display: "block" }, children: section.description }),
1710
+ renderFieldsGrid(section)
1711
+ ] })
1712
+ ] }, section.id)) });
1713
+ })() : (() => {
1714
+ const fieldsPerRow = formSchema.settings?.fieldsPerRow || 1;
1715
+ const gridColumns = Math.min(Math.max(1, fieldsPerRow), 3);
1716
+ const fullWidthFieldTypes = ["ckeditor"];
1717
+ return /* @__PURE__ */ jsxRuntime.jsx(
1718
+ material.Box,
1719
+ {
1720
+ sx: {
1721
+ display: "grid",
1722
+ gridTemplateColumns: {
1723
+ xs: "1fr",
1724
+ sm: gridColumns === 1 ? "1fr" : gridColumns === 2 ? "repeat(2, 1fr)" : "repeat(3, 1fr)"
1725
+ },
1726
+ gap: 3
1727
+ },
1728
+ children: fieldsToRender.map((field) => {
1729
+ const shouldTakeFullWidth = fullWidthFieldTypes.includes(field.type);
1730
+ return /* @__PURE__ */ jsxRuntime.jsx(
1731
+ material.Box,
1732
+ {
1733
+ sx: {
1734
+ gridColumn: shouldTakeFullWidth ? {
1735
+ xs: "1 / -1",
1736
+ sm: "1 / -1"
1737
+ } : "auto"
1738
+ },
1739
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1740
+ FieldRenderer,
1741
+ {
1742
+ field,
1743
+ control,
1744
+ errors,
1745
+ setValue,
1746
+ formSchema,
1747
+ uploadingFiles,
1748
+ setUploadingFiles,
1749
+ setError,
1750
+ clearErrors,
1751
+ services
1752
+ }
1753
+ )
1754
+ },
1755
+ field.name
1756
+ );
1757
+ })
1758
+ }
1759
+ );
1760
+ })(),
1761
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Stack, { direction: "row", spacing: 2, sx: { mt: 3 }, justifyContent: "space-between", children: [
1762
+ /* @__PURE__ */ jsxRuntime.jsx(
1763
+ material.Button,
1764
+ {
1765
+ type: "submit",
1766
+ variant: "contained",
1767
+ size: "small",
1768
+ sx: { minWidth: 120 },
1769
+ disabled: isLoading,
1770
+ children: isLoading ? "Submitting..." : "Submit"
1771
+ }
1772
+ ),
1773
+ /* @__PURE__ */ jsxRuntime.jsxs(material.Stack, { direction: "row", spacing: 2, children: [
1774
+ /* @__PURE__ */ jsxRuntime.jsx(
1775
+ material.Button,
1776
+ {
1777
+ variant: "outlined",
1778
+ size: "small",
1779
+ onClick: () => {
1780
+ reset();
1781
+ clearErrors();
1782
+ setSubmitError(null);
1783
+ const sectionDisplayMode = formSchema.settings?.sectionDisplayMode || "panel";
1784
+ if (sectionDisplayMode === "stepper") {
1785
+ setActiveStep(0);
1786
+ }
1787
+ },
1788
+ disabled: isLoading,
1789
+ children: "Reset form"
1790
+ }
1791
+ ),
1792
+ onCancel && /* @__PURE__ */ jsxRuntime.jsx(
1793
+ material.Button,
1794
+ {
1795
+ variant: "outlined",
1796
+ size: "small",
1797
+ onClick: onCancel,
1798
+ disabled: isLoading,
1799
+ children: "Cancel"
1800
+ }
1801
+ )
1802
+ ] })
1803
+ ] })
1804
+ ] });
1805
+ };
1806
+
1807
+ exports.ApiReferenceField = ApiReferenceField;
1808
+ exports.CKEditorField = CKEditorField;
1809
+ exports.CheckboxField = CheckboxField;
1810
+ exports.ColorField = ColorField;
1811
+ exports.DateTimePickerField = DateTimePickerField;
1812
+ exports.FieldRenderer = FieldRenderer;
1813
+ exports.FieldView = FieldView;
1814
+ exports.FileField = FileField;
1815
+ exports.FormReferenceField = FormReferenceField;
1816
+ exports.FormRenderer = FormRenderer;
1817
+ exports.FormViewMode = FormViewMode;
1818
+ exports.RadioField = RadioField;
1819
+ exports.SelectField = SelectField;
1820
+ exports.SimpleSelect = SimpleSelect;
1821
+ exports.TextField = TextField;
1822
+ exports.ToggleField = ToggleField;
1823
+ exports.buildFieldRules = buildFieldRules;
1824
+ exports.defaultApiReferenceService = defaultApiReferenceService;
1825
+ exports.defaultDateFormatterService = defaultDateFormatterService;
1826
+ exports.defaultFileUploadService = defaultFileUploadService;
1827
+ exports.defaultFormReferenceService = defaultFormReferenceService;
1828
+ exports.formatFileSize = formatFileSize;
1829
+ exports.getAllFields = getAllFields;
1830
+ exports.getDefaultValue = getDefaultValue;
1831
+ exports.isCKEditorAvailable = isCKEditorAvailable;
1832
+ exports.loadCKEditor = loadCKEditor;
1833
+ exports.normalizeInitialValues = normalizeInitialValues;
1834
+ exports.normalizeOptions = normalizeOptions;
1835
+ exports.transformFormValues = transformFormValues;
1836
+ exports.useCKEditor = useCKEditor;
1837
+ exports.validateFile = validateFile;
1838
+ exports.waitForCKEditor = waitForCKEditor;
1839
+ //# sourceMappingURL=index.js.map
1840
+ //# sourceMappingURL=index.js.map