@form-engine-ts/mui 2.9.4 → 2.9.6

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.cjs CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  MuiFieldEditorSlot: () => MuiFieldEditorSlot,
28
28
  MuiFieldsetAdapter: () => MuiFieldsetAdapter,
29
29
  MuiFormBuilder: () => MuiFormBuilder,
30
+ MuiFormBuilderContext: () => MuiFormBuilderContext,
30
31
  MuiIconButtonAdapter: () => MuiIconButtonAdapter,
31
32
  MuiLocalizationSlot: () => MuiLocalizationSlot,
32
33
  MuiOptionEditorSlot: () => MuiOptionEditorSlot,
@@ -51,16 +52,21 @@ __export(index_exports, {
51
52
  createMuiTextAreaAdapter: () => createMuiTextAreaAdapter,
52
53
  createMuiTextInputAdapter: () => createMuiTextInputAdapter,
53
54
  createMuiToolbarSlot: () => createMuiToolbarSlot,
55
+ mergeMuiAdapterOptions: () => mergeMuiAdapterOptions,
54
56
  muiBuilderComponents: () => muiBuilderComponents,
55
57
  muiBuilderSlots: () => muiBuilderSlots,
56
58
  muiDefaultIconResolver: () => muiDefaultIconResolver,
57
- resolveMuiAdapterOptions: () => resolveMuiAdapterOptions
59
+ resolveMuiAdapterOptions: () => resolveMuiAdapterOptions,
60
+ useResolvedMuiAdapterOptions: () => useResolvedMuiAdapterOptions
58
61
  });
59
62
  module.exports = __toCommonJS(index_exports);
60
63
 
61
64
  // src/adapters/Button.tsx
62
65
  var import_material = require("@mui/material");
63
66
 
67
+ // src/context.ts
68
+ var import_react = require("react");
69
+
64
70
  // src/types.ts
65
71
  var DEFAULT_MUI_SECTION_ORDER = [
66
72
  "basicSettings",
@@ -80,22 +86,49 @@ function resolveMuiAdapterOptions(options = {}) {
80
86
  danger: options.buttonVariants?.danger ?? buttonVariant
81
87
  },
82
88
  fullWidth: options.fullWidth ?? true,
89
+ inputFullWidth: options.inputFullWidth ?? options.fullWidth ?? true,
90
+ buttonFullWidth: options.buttonFullWidth ?? options.fullWidth ?? false,
83
91
  dense: options.dense ?? false,
84
92
  getLocaleLabel: options.getLocaleLabel ?? ((locale) => locale),
85
93
  ...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
86
94
  layoutOptions: options.layoutOptions ?? {},
95
+ fieldEditorOptions: {
96
+ description: options.fieldEditorOptions?.description ?? "editable"
97
+ },
87
98
  localizationOptions: {
88
99
  collapsible: options.localizationOptions?.collapsible ?? false,
89
- defaultExpanded: options.localizationOptions?.defaultExpanded ?? false
100
+ defaultExpanded: options.localizationOptions?.defaultExpanded ?? false,
101
+ showSummary: options.localizationOptions?.showSummary ?? false,
102
+ ...options.localizationOptions?.emptyStateMessage === void 0 ? {} : { emptyStateMessage: options.localizationOptions.emptyStateMessage },
103
+ defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable"
90
104
  },
91
105
  muiSlotProps: options.muiSlotProps ?? {}
92
106
  };
93
107
  }
94
108
 
109
+ // src/context.ts
110
+ var MuiFormBuilderContext = (0, import_react.createContext)({ options: {} });
111
+ function mergeMuiAdapterOptions(base = {}, overrides = {}) {
112
+ return {
113
+ ...base,
114
+ ...overrides,
115
+ ...base.buttonVariants === void 0 && overrides.buttonVariants === void 0 ? {} : { buttonVariants: { ...base.buttonVariants, ...overrides.buttonVariants } },
116
+ ...base.layoutOptions === void 0 && overrides.layoutOptions === void 0 ? {} : { layoutOptions: { ...base.layoutOptions, ...overrides.layoutOptions } },
117
+ ...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : { fieldEditorOptions: { ...base.fieldEditorOptions, ...overrides.fieldEditorOptions } },
118
+ ...base.localizationOptions === void 0 && overrides.localizationOptions === void 0 ? {} : { localizationOptions: { ...base.localizationOptions, ...overrides.localizationOptions } },
119
+ ...base.muiSlotProps === void 0 && overrides.muiSlotProps === void 0 ? {} : { muiSlotProps: { ...base.muiSlotProps, ...overrides.muiSlotProps } }
120
+ };
121
+ }
122
+ function useResolvedMuiAdapterOptions(overrides) {
123
+ const context = (0, import_react.useContext)(MuiFormBuilderContext);
124
+ return resolveMuiAdapterOptions(
125
+ overrides === void 0 ? context.options : mergeMuiAdapterOptions(context.options, overrides)
126
+ );
127
+ }
128
+
95
129
  // src/adapters/Button.tsx
96
130
  var import_jsx_runtime = require("react/jsx-runtime");
97
131
  function createMuiButtonAdapter(options) {
98
- const resolved = resolveMuiAdapterOptions(options);
99
132
  return function MuiButton({
100
133
  id,
101
134
  className,
@@ -111,6 +144,7 @@ function createMuiButtonAdapter(options) {
111
144
  action,
112
145
  targetId
113
146
  }) {
147
+ const resolved = useResolvedMuiAdapterOptions(options);
114
148
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
149
  import_material.Button,
116
150
  {
@@ -128,7 +162,8 @@ function createMuiButtonAdapter(options) {
128
162
  onClick,
129
163
  color: variant === "danger" ? "error" : "primary",
130
164
  variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
131
- fullWidth: resolved.fullWidth,
165
+ fullWidth: resolved.buttonFullWidth ?? false,
166
+ sx: { whiteSpace: "nowrap" },
132
167
  children
133
168
  }
134
169
  );
@@ -140,7 +175,6 @@ var MuiButtonAdapter = createMuiButtonAdapter();
140
175
  var import_material2 = require("@mui/material");
141
176
  var import_jsx_runtime2 = require("react/jsx-runtime");
142
177
  function createMuiCheckboxAdapter(options) {
143
- const resolved = resolveMuiAdapterOptions(options);
144
178
  return function MuiCheckbox({
145
179
  id,
146
180
  className,
@@ -157,6 +191,9 @@ function createMuiCheckboxAdapter(options) {
157
191
  onChange,
158
192
  label
159
193
  }) {
194
+ const resolved = useResolvedMuiAdapterOptions(options);
195
+ const helperId = id === void 0 ? void 0 : ariaDescribedBy?.split(/\s+/u)[0] ?? `${id}-helper-text`;
196
+ const describedBy = ariaDescribedBy ?? (helperText === void 0 || helperText.length === 0 ? void 0 : helperId);
160
197
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_material2.FormControl, { className, error: Boolean(error), required, disabled: disabled || readOnly, children: [
161
198
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
162
199
  import_material2.FormControlLabel,
@@ -173,7 +210,7 @@ function createMuiCheckboxAdapter(options) {
173
210
  disabled: disabled || readOnly,
174
211
  inputProps: {
175
212
  "aria-label": ariaLabel,
176
- "aria-describedby": ariaDescribedBy,
213
+ "aria-describedby": describedBy,
177
214
  "aria-labelledby": ariaLabelledBy
178
215
  },
179
216
  onChange: (event) => onChange(event.target.checked)
@@ -181,7 +218,7 @@ function createMuiCheckboxAdapter(options) {
181
218
  )
182
219
  }
183
220
  ),
184
- helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_material2.FormHelperText, { id: ariaDescribedBy, children: helperText })
221
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_material2.FormHelperText, { id: helperId, children: helperText })
185
222
  ] });
186
223
  };
187
224
  }
@@ -220,8 +257,8 @@ var MuiErrorMessageAdapter = createMuiErrorMessageAdapter();
220
257
  var import_material4 = require("@mui/material");
221
258
  var import_jsx_runtime4 = require("react/jsx-runtime");
222
259
  function createMuiFieldsetAdapter(options) {
223
- const resolved = resolveMuiAdapterOptions(options);
224
260
  return function MuiFieldset({ className, legend, disabled, children }) {
261
+ const resolved = useResolvedMuiAdapterOptions(options);
225
262
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
226
263
  import_material4.Box,
227
264
  {
@@ -265,7 +302,6 @@ var FALLBACK_ACTION_LABELS = {
265
302
  dragHandle: "Reorder"
266
303
  };
267
304
  function createMuiIconButtonAdapter(options) {
268
- const resolved = resolveMuiAdapterOptions(options);
269
305
  return function MuiIconButton({
270
306
  id,
271
307
  className,
@@ -279,6 +315,7 @@ function createMuiIconButtonAdapter(options) {
279
315
  actionType,
280
316
  title
281
317
  }) {
318
+ const resolved = useResolvedMuiAdapterOptions(options);
282
319
  const actionLabel = actionType === void 0 ? "Action" : resolved.getActionLabel?.(actionType) ?? FALLBACK_ACTION_LABELS[actionType];
283
320
  const tooltip = title ?? actionLabel;
284
321
  const color = actionType === "delete" ? "error" : actionType === "add" ? "primary" : "default";
@@ -306,7 +343,6 @@ var MuiIconButtonAdapter = createMuiIconButtonAdapter();
306
343
  var import_material6 = require("@mui/material");
307
344
  var import_jsx_runtime6 = require("react/jsx-runtime");
308
345
  function createMuiSectionAdapter(options) {
309
- const resolved = resolveMuiAdapterOptions(options);
310
346
  return function MuiSection({
311
347
  id,
312
348
  className,
@@ -317,6 +353,7 @@ function createMuiSectionAdapter(options) {
317
353
  onClickCapture,
318
354
  children
319
355
  }) {
356
+ const resolved = useResolvedMuiAdapterOptions(options);
320
357
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
321
358
  import_material6.Paper,
322
359
  {
@@ -355,7 +392,6 @@ var MuiSectionAdapter = createMuiSectionAdapter();
355
392
  var import_material7 = require("@mui/material");
356
393
  var import_jsx_runtime7 = require("react/jsx-runtime");
357
394
  function createMuiSelectAdapter(options) {
358
- const resolved = resolveMuiAdapterOptions(options);
359
395
  return function MuiSelect({
360
396
  id,
361
397
  className,
@@ -373,13 +409,16 @@ function createMuiSelectAdapter(options) {
373
409
  onChange,
374
410
  options: selectOptions
375
411
  }) {
412
+ const resolved = useResolvedMuiAdapterOptions(options);
376
413
  const labelId = id === void 0 || label === void 0 ? void 0 : `${id}-label`;
414
+ const helperId = id === void 0 ? void 0 : ariaDescribedBy?.split(/\s+/u)[0] ?? `${id}-helper-text`;
415
+ const describedBy = ariaDescribedBy ?? (helperText === void 0 || helperText.length === 0 ? void 0 : helperId);
377
416
  const handleChange = (event) => onChange(event.target.value);
378
417
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
379
418
  import_material7.FormControl,
380
419
  {
381
420
  className,
382
- fullWidth: resolved.fullWidth,
421
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
383
422
  size: resolved.size,
384
423
  variant: resolved.variant,
385
424
  error: Boolean(error),
@@ -400,13 +439,13 @@ function createMuiSelectAdapter(options) {
400
439
  readOnly,
401
440
  inputProps: {
402
441
  "aria-label": ariaLabel,
403
- "aria-describedby": ariaDescribedBy,
442
+ "aria-describedby": describedBy,
404
443
  "aria-labelledby": ariaLabelledBy
405
444
  },
406
445
  children: selectOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material7.MenuItem, { value: option.value, disabled: option.disabled, children: option.label }, option.value))
407
446
  }
408
447
  ),
409
- helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material7.FormHelperText, { id: ariaDescribedBy, children: helperText })
448
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material7.FormHelperText, { id: helperId, children: helperText })
410
449
  ]
411
450
  }
412
451
  );
@@ -418,7 +457,6 @@ var MuiSelectAdapter = createMuiSelectAdapter();
418
457
  var import_material8 = require("@mui/material");
419
458
  var import_jsx_runtime8 = require("react/jsx-runtime");
420
459
  function createMuiTextAreaAdapter(options) {
421
- const resolved = resolveMuiAdapterOptions(options);
422
460
  return function MuiTextArea({
423
461
  id,
424
462
  className,
@@ -438,6 +476,7 @@ function createMuiTextAreaAdapter(options) {
438
476
  maxLength,
439
477
  rows
440
478
  }) {
479
+ const resolved = useResolvedMuiAdapterOptions(options);
441
480
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
442
481
  import_material8.TextField,
443
482
  {
@@ -453,6 +492,7 @@ function createMuiTextAreaAdapter(options) {
453
492
  slotProps: {
454
493
  htmlInput: {
455
494
  maxLength,
495
+ readOnly,
456
496
  "aria-label": ariaLabel,
457
497
  "aria-describedby": ariaDescribedBy,
458
498
  "aria-labelledby": ariaLabelledBy
@@ -463,7 +503,7 @@ function createMuiTextAreaAdapter(options) {
463
503
  multiline: true,
464
504
  rows,
465
505
  placeholder,
466
- fullWidth: resolved.fullWidth,
506
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
467
507
  size: resolved.size,
468
508
  variant: resolved.variant,
469
509
  onChange: (event) => onChange(event.currentTarget.value)
@@ -477,7 +517,6 @@ var MuiTextAreaAdapter = createMuiTextAreaAdapter();
477
517
  var import_material9 = require("@mui/material");
478
518
  var import_jsx_runtime9 = require("react/jsx-runtime");
479
519
  function createMuiTextInputAdapter(options) {
480
- const resolved = resolveMuiAdapterOptions(options);
481
520
  return function MuiTextInput({
482
521
  id,
483
522
  className,
@@ -501,6 +540,7 @@ function createMuiTextInputAdapter(options) {
501
540
  max,
502
541
  step
503
542
  }) {
543
+ const resolved = useResolvedMuiAdapterOptions(options);
504
544
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
505
545
  import_material9.TextField,
506
546
  {
@@ -520,6 +560,7 @@ function createMuiTextInputAdapter(options) {
520
560
  max,
521
561
  step,
522
562
  inputMode,
563
+ readOnly,
523
564
  "aria-label": ariaLabel,
524
565
  "aria-describedby": ariaDescribedBy,
525
566
  "aria-labelledby": ariaLabelledBy
@@ -529,7 +570,7 @@ function createMuiTextInputAdapter(options) {
529
570
  },
530
571
  type,
531
572
  placeholder,
532
- fullWidth: resolved.fullWidth,
573
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
533
574
  size: resolved.size,
534
575
  variant: resolved.variant,
535
576
  onChange: (event) => onChange(event.currentTarget.value)
@@ -567,7 +608,7 @@ function muiDefaultIconResolver(actionType) {
567
608
 
568
609
  // src/components.ts
569
610
  function isAdapterOptions(value) {
570
- return "size" in value || "variant" in value || "buttonVariant" in value || "fullWidth" in value || "dense" in value;
611
+ return "size" in value || "variant" in value || "buttonVariant" in value || "buttonVariants" in value || "fullWidth" in value || "inputFullWidth" in value || "buttonFullWidth" in value || "dense" in value || "fieldEditorOptions" in value || "localizationOptions" in value || "layoutOptions" in value || "muiSlotProps" in value || "getLocaleLabel" in value || "getActionLabel" in value;
571
612
  }
572
613
  function buildMuiBuilderComponents(options) {
573
614
  return {
@@ -583,11 +624,22 @@ function buildMuiBuilderComponents(options) {
583
624
  renderIcon: muiDefaultIconResolver
584
625
  };
585
626
  }
586
- var muiBuilderComponents = buildMuiBuilderComponents();
627
+ var muiBuilderComponents = {
628
+ Button: MuiButtonAdapter,
629
+ IconButton: MuiIconButtonAdapter,
630
+ TextInput: MuiTextInputAdapter,
631
+ TextArea: MuiTextAreaAdapter,
632
+ Select: MuiSelectAdapter,
633
+ Checkbox: MuiCheckboxAdapter,
634
+ Section: MuiSectionAdapter,
635
+ Fieldset: MuiFieldsetAdapter,
636
+ ErrorMessage: MuiErrorMessageAdapter,
637
+ renderIcon: muiDefaultIconResolver
638
+ };
587
639
  function createMuiBuilderComponents(optionsOrOverrides = {}, customOverrides) {
588
640
  const options = isAdapterOptions(optionsOrOverrides) ? optionsOrOverrides : void 0;
589
641
  const overrides = customOverrides ?? (options === void 0 ? optionsOrOverrides : {});
590
- return { ...buildMuiBuilderComponents(options), ...overrides };
642
+ return { ...options === void 0 ? muiBuilderComponents : buildMuiBuilderComponents(options), ...overrides };
591
643
  }
592
644
 
593
645
  // src/slots/FieldEditor.tsx
@@ -597,7 +649,6 @@ var import_material12 = require("@mui/material");
597
649
  var import_material10 = require("@mui/material");
598
650
  var import_jsx_runtime11 = require("react/jsx-runtime");
599
651
  function createMuiOptionEditorSlot(options) {
600
- const resolved = resolveMuiAdapterOptions(options);
601
652
  return function MuiOptionEditor({
602
653
  field,
603
654
  option,
@@ -608,6 +659,7 @@ function createMuiOptionEditorSlot(options) {
608
659
  components,
609
660
  translate
610
661
  }) {
662
+ const resolved = useResolvedMuiAdapterOptions(options);
611
663
  const { IconButton: IconButton2, TextInput } = components;
612
664
  const describedBy = option.label.trim().length === 0 ? `mui-option-${option.id}-error` : void 0;
613
665
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material10.Stack, { ...resolved.muiSlotProps?.stack, "data-mui-slot": "option-editor", spacing: resolved.dense ? 0.75 : 1, children: [
@@ -665,7 +717,7 @@ function createMuiOptionEditorSlot(options) {
665
717
  }),
666
718
  value: option.translations?.[currentLocale] ?? "",
667
719
  disabled: readOnly,
668
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
720
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
669
721
  }
670
722
  )
671
723
  ] });
@@ -677,7 +729,6 @@ var MuiOptionEditorSlot = createMuiOptionEditorSlot();
677
729
  var import_material11 = require("@mui/material");
678
730
  var import_jsx_runtime12 = require("react/jsx-runtime");
679
731
  function createMuiToolbarSlot(options) {
680
- const resolved = resolveMuiAdapterOptions(options);
681
732
  return function MuiToolbar({
682
733
  kind,
683
734
  index,
@@ -690,6 +741,7 @@ function createMuiToolbarSlot(options) {
690
741
  components,
691
742
  translate
692
743
  }) {
744
+ const resolved = useResolvedMuiAdapterOptions(options);
693
745
  const { IconButton: IconButton2 } = components;
694
746
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
695
747
  import_material11.Stack,
@@ -773,7 +825,6 @@ function updateBound(field, property, value) {
773
825
  return remaining;
774
826
  }
775
827
  function createMuiFieldEditorSlot(options) {
776
- const resolved = resolveMuiAdapterOptions(options);
777
828
  const Toolbar = createMuiToolbarSlot(options);
778
829
  const OptionEditor = createMuiOptionEditorSlot(options);
779
830
  return function MuiFieldEditor({
@@ -788,12 +839,14 @@ function createMuiFieldEditorSlot(options) {
788
839
  components,
789
840
  translate
790
841
  }) {
842
+ const resolved = useResolvedMuiAdapterOptions(options);
791
843
  const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
792
844
  const allowedTypes = policy?.allowedFieldTypes ?? FIELD_TYPES;
793
845
  const pageId = schema.pages?.find((page) => page.questionIds.includes(field.id))?.id ?? "";
794
846
  const condition = field.displayCondition;
795
847
  const conditionSources = schema.fields.slice(0, index);
796
848
  const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
849
+ const descriptionMode = resolved.fieldEditorOptions?.description ?? "editable";
797
850
  const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
798
851
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
799
852
  import_material12.Card,
@@ -857,7 +910,7 @@ function createMuiFieldEditorSlot(options) {
857
910
  }
858
911
  )
859
912
  ] }),
860
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
913
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
861
914
  TextArea,
862
915
  {
863
916
  id: `mui-field-${field.id}-description`,
@@ -866,6 +919,7 @@ function createMuiFieldEditorSlot(options) {
866
919
  value: field.description ?? "",
867
920
  rows: resolved.dense ? 2 : 3,
868
921
  disabled: readOnly,
922
+ readOnly: descriptionMode === "readOnly",
869
923
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "description", value)
870
924
  }
871
925
  ),
@@ -979,17 +1033,18 @@ function createMuiFieldEditorSlot(options) {
979
1033
  label: translate("builder.translatedQuestionTitle"),
980
1034
  value: field.translations?.[currentLocale]?.title ?? "",
981
1035
  disabled: readOnly,
982
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
1036
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
983
1037
  }
984
1038
  ),
985
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1039
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
986
1040
  TextArea,
987
1041
  {
988
1042
  id: `mui-field-${field.id}-${currentLocale}-description`,
989
1043
  label: translate("builder.translatedDescription"),
990
1044
  value: field.translations?.[currentLocale]?.description ?? "",
991
1045
  disabled: readOnly,
992
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
1046
+ readOnly: descriptionMode === "readOnly",
1047
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
993
1048
  }
994
1049
  )
995
1050
  ] }),
@@ -1032,10 +1087,10 @@ var MuiFieldEditorSlot = createMuiFieldEditorSlot();
1032
1087
  // src/slots/Localization.tsx
1033
1088
  var import_icons_material2 = require("@mui/icons-material");
1034
1089
  var import_material13 = require("@mui/material");
1035
- var import_react = require("react");
1090
+ var import_react2 = require("react");
1036
1091
  var import_jsx_runtime14 = require("react/jsx-runtime");
1092
+ var DEFAULT_EMPTY_STATE_MESSAGE = "No translation locales have been added yet. Select a language from the dropdown above to add one.";
1037
1093
  function createMuiLocalizationSlot(options) {
1038
- const resolved = resolveMuiAdapterOptions(options);
1039
1094
  return function MuiLocalization({
1040
1095
  schema,
1041
1096
  currentLocale,
@@ -1050,8 +1105,9 @@ function createMuiLocalizationSlot(options) {
1050
1105
  components,
1051
1106
  translate
1052
1107
  }) {
1108
+ const resolved = useResolvedMuiAdapterOptions(options);
1053
1109
  const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
1054
- const [newLocale, setNewLocale] = (0, import_react.useState)("");
1110
+ const [newLocale, setNewLocale] = (0, import_react2.useState)("");
1055
1111
  const locales = Array.from(
1056
1112
  new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
1057
1113
  );
@@ -1074,51 +1130,93 @@ function createMuiLocalizationSlot(options) {
1074
1130
  setNewLocale("");
1075
1131
  };
1076
1132
  const stackProps = resolved.muiSlotProps?.stack;
1077
- const collapsible = resolved.localizationOptions?.collapsible ?? false;
1133
+ const localizationOptions = resolved.localizationOptions ?? {};
1134
+ const collapsible = localizationOptions.collapsible ?? false;
1135
+ const defaultLocaleControl = localizationOptions.defaultLocaleControl ?? "editable";
1136
+ const configuredTranslationLocales = locales.filter((locale) => locale !== schema.defaultLocale);
1137
+ const configuredLocales = [
1138
+ ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
1139
+ ...configuredTranslationLocales
1140
+ ];
1141
+ const summaryLabel = configuredTranslationLocales.length === 0 ? "Translations not configured" : `${configuredLocales.length} ${configuredLocales.length === 1 ? "language" : "languages"} configured: ${configuredLocales.map(
1142
+ (locale) => locale === schema.defaultLocale ? `${resolved.getLocaleLabel?.(locale) ?? locale} (default)` : resolved.getLocaleLabel?.(locale) ?? locale
1143
+ ).join(", ")}`;
1144
+ const emptyStateMessage = localizationOptions.emptyStateMessage === void 0 ? DEFAULT_EMPTY_STATE_MESSAGE : translate(localizationOptions.emptyStateMessage);
1145
+ const title = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { alignItems: "center", direction: "row", spacing: 1, children: [
1146
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }),
1147
+ localizationOptions.showSummary ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1148
+ import_material13.Chip,
1149
+ {
1150
+ label: summaryLabel,
1151
+ size: "small",
1152
+ color: configuredTranslationLocales.length > 0 ? "primary" : "default",
1153
+ variant: "outlined"
1154
+ }
1155
+ ) : null
1156
+ ] });
1078
1157
  const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1079
- !collapsible ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) : null,
1080
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
1081
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1082
- TextInput,
1083
- {
1084
- id: "mui-builder-default-locale",
1085
- label: translate("builder.defaultLocale"),
1086
- value: schema.defaultLocale ?? "",
1087
- disabled: readOnly,
1088
- onChange: (value) => {
1089
- const result = actions.setDefaultLocale(value);
1090
- if (result.success && value === currentLocale) onCurrentLocaleChange("");
1091
- }
1092
- }
1093
- ),
1094
- availableAllowedLocales === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1095
- TextInput,
1096
- {
1097
- id: "mui-builder-new-locale",
1098
- label: translate("builder.addLocale"),
1099
- value: newLocale,
1100
- disabled: readOnly || localeLimitReached,
1101
- onChange: setNewLocale
1102
- }
1103
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1104
- Select2,
1105
- {
1106
- id: "mui-builder-new-locale",
1107
- label: translate("builder.addLocale"),
1108
- value: newLocale,
1109
- options: [
1110
- { value: "", label: "\u2014" },
1111
- ...availableAllowedLocales.map((locale) => ({
1112
- value: locale,
1113
- label: resolved.getLocaleLabel?.(locale) ?? locale
1114
- }))
1115
- ],
1116
- disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
1117
- onChange: setNewLocale
1118
- }
1119
- ),
1120
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button2, { variant: "primary", action: "addLocale", disabled: !canAddLocale, onClick: addLocale, children: translate("builder.addLocale") })
1121
- ] }),
1158
+ !collapsible ? title : null,
1159
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1160
+ import_material13.Stack,
1161
+ {
1162
+ ...stackProps,
1163
+ direction: { xs: "column", sm: "row" },
1164
+ alignItems: { xs: "stretch", sm: "center" },
1165
+ spacing: resolved.dense ? 1 : 2,
1166
+ sx: { mt: 1 },
1167
+ children: [
1168
+ defaultLocaleControl === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } }, children: defaultLocaleControl === "readOnly" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { spacing: 0.5, children: [
1169
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "caption", color: "text.secondary", children: translate("builder.defaultLocale") }),
1170
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1171
+ import_material13.Chip,
1172
+ {
1173
+ label: resolved.getLocaleLabel?.(schema.defaultLocale ?? "") ?? schema.defaultLocale ?? "",
1174
+ size: resolved.size
1175
+ }
1176
+ )
1177
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1178
+ TextInput,
1179
+ {
1180
+ id: "mui-builder-default-locale",
1181
+ label: translate("builder.defaultLocale"),
1182
+ value: schema.defaultLocale ?? "",
1183
+ disabled: readOnly,
1184
+ onChange: (value) => {
1185
+ const result = actions.setDefaultLocale(value);
1186
+ if (result.success && value === currentLocale) onCurrentLocaleChange("");
1187
+ }
1188
+ }
1189
+ ) }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } }, children: availableAllowedLocales === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1191
+ TextInput,
1192
+ {
1193
+ id: "mui-builder-new-locale",
1194
+ label: translate("builder.addLocale"),
1195
+ value: newLocale,
1196
+ disabled: readOnly || localeLimitReached,
1197
+ onChange: setNewLocale
1198
+ }
1199
+ ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1200
+ Select2,
1201
+ {
1202
+ id: "mui-builder-new-locale",
1203
+ label: translate("builder.addLocale"),
1204
+ value: newLocale,
1205
+ options: [
1206
+ { value: "", label: "\u2014" },
1207
+ ...availableAllowedLocales.map((locale) => ({
1208
+ value: locale,
1209
+ label: resolved.getLocaleLabel?.(locale) ?? locale
1210
+ }))
1211
+ ],
1212
+ disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
1213
+ onChange: setNewLocale
1214
+ }
1215
+ ) }),
1216
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { flexShrink: 0, minWidth: "max-content", whiteSpace: "nowrap" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button2, { variant: "primary", action: "addLocale", disabled: !canAddLocale, onClick: addLocale, children: translate("builder.addLocale") }) })
1217
+ ]
1218
+ }
1219
+ ),
1122
1220
  locales.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1123
1221
  import_material13.Tabs,
1124
1222
  {
@@ -1132,13 +1230,14 @@ function createMuiLocalizationSlot(options) {
1132
1230
  {
1133
1231
  value: locale,
1134
1232
  label: resolved.getLocaleLabel?.(locale) ?? locale,
1135
- disabled: readOnly && locale !== currentLocale
1233
+ disabled: readOnly && locale !== currentLocale,
1234
+ sx: { whiteSpace: "nowrap" }
1136
1235
  },
1137
1236
  locale
1138
1237
  ))
1139
1238
  }
1140
1239
  ),
1141
- !translationAdapterAvailable ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1240
+ !translationAdapterAvailable ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { minWidth: "max-content", whiteSpace: "nowrap" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1142
1241
  Button2,
1143
1242
  {
1144
1243
  variant: "secondary",
@@ -1146,9 +1245,9 @@ function createMuiLocalizationSlot(options) {
1146
1245
  onClick: onAutoTranslate,
1147
1246
  children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
1148
1247
  }
1149
- ),
1248
+ ) }),
1150
1249
  translationError === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ErrorMessage, { message: translationError }),
1151
- !editingLocaleConfigured ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "body2", color: "text.secondary", children: translate("builder.selectLocale") }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1250
+ !editingLocaleConfigured ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "body2", color: "text.secondary", children: locales.length === 0 ? emptyStateMessage : translate("builder.selectLocale") }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1152
1251
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1153
1252
  TextInput,
1154
1253
  {
@@ -1156,7 +1255,7 @@ function createMuiLocalizationSlot(options) {
1156
1255
  label: translate("builder.translatedFormTitle"),
1157
1256
  value: schema.translations?.[currentLocale]?.title ?? "",
1158
1257
  disabled: readOnly,
1159
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "title", value)
1258
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "title", value)
1160
1259
  }
1161
1260
  ),
1162
1261
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -1166,7 +1265,7 @@ function createMuiLocalizationSlot(options) {
1166
1265
  label: translate("builder.translatedFormDescription"),
1167
1266
  value: schema.translations?.[currentLocale]?.description ?? "",
1168
1267
  disabled: readOnly,
1169
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "description", value)
1268
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "description", value)
1170
1269
  }
1171
1270
  ),
1172
1271
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -1176,16 +1275,16 @@ function createMuiLocalizationSlot(options) {
1176
1275
  label: translate("builder.translatedCompletionMessage"),
1177
1276
  value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1178
1277
  disabled: readOnly,
1179
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1278
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1180
1279
  }
1181
1280
  )
1182
1281
  ] })
1183
1282
  ] });
1184
1283
  const configured = locales.length > 0;
1185
- const defaultExpanded = resolved.localizationOptions?.defaultExpanded === "when-configured" ? configured : resolved.localizationOptions?.defaultExpanded ?? false;
1284
+ const defaultExpanded = localizationOptions.defaultExpanded === "when-configured" ? configured : localizationOptions.defaultExpanded === "always" ? true : localizationOptions.defaultExpanded ?? false;
1186
1285
  if (collapsible) {
1187
1286
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Accordion, { ...resolved.muiSlotProps?.accordion, "data-mui-slot": "localization", defaultExpanded, children: [
1188
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.AccordionSummary, { expandIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.ExpandMore, {}), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.AccordionSummary, { expandIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.ExpandMore, {}), children: title }),
1189
1288
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.AccordionDetails, { children: content })
1190
1289
  ] });
1191
1290
  }
@@ -1210,10 +1309,10 @@ var MuiLocalizationSlot = createMuiLocalizationSlot();
1210
1309
  // src/slots/index.ts
1211
1310
  var muiBuilderSlots = {
1212
1311
  sectionOrder: DEFAULT_MUI_SECTION_ORDER,
1213
- toolbar: createMuiToolbarSlot(),
1214
- fieldEditor: createMuiFieldEditorSlot(),
1215
- optionEditor: createMuiOptionEditorSlot(),
1216
- localization: createMuiLocalizationSlot()
1312
+ toolbar: MuiToolbarSlot,
1313
+ fieldEditor: MuiFieldEditorSlot,
1314
+ optionEditor: MuiOptionEditorSlot,
1315
+ localization: MuiLocalizationSlot
1217
1316
  };
1218
1317
  function createMuiBuilderSlots(options, customOverrides = {}) {
1219
1318
  return {
@@ -1236,8 +1335,8 @@ function createMuiBuilderProps(options, overrides = {}) {
1236
1335
  }
1237
1336
 
1238
1337
  // src/MuiFormBuilder.tsx
1239
- var import_react2 = require("@form-engine-ts/react");
1240
- var import_react3 = require("react");
1338
+ var import_react3 = require("@form-engine-ts/react");
1339
+ var import_react4 = require("react");
1241
1340
  var import_jsx_runtime15 = require("react/jsx-runtime");
1242
1341
  function MuiFormBuilder({
1243
1342
  muiOptions,
@@ -1246,26 +1345,31 @@ function MuiFormBuilder({
1246
1345
  muiSlotProps,
1247
1346
  components: customComponents,
1248
1347
  slots: customSlots,
1348
+ sectionOrder,
1249
1349
  ...props
1250
1350
  }) {
1251
- const resolvedMuiOptions = (0, import_react3.useMemo)(
1252
- () => ({
1253
- ...muiOptions,
1351
+ const contextOptions = (0, import_react4.useMemo)(
1352
+ () => mergeMuiAdapterOptions(muiOptions, {
1254
1353
  ...layoutOptions === void 0 ? {} : { layoutOptions },
1255
1354
  ...localizationOptions === void 0 ? {} : { localizationOptions },
1256
1355
  ...muiSlotProps === void 0 ? {} : { muiSlotProps }
1257
1356
  }),
1258
1357
  [layoutOptions, localizationOptions, muiOptions, muiSlotProps]
1259
1358
  );
1260
- const components = (0, import_react3.useMemo)(
1261
- () => createMuiBuilderComponents(resolvedMuiOptions, customComponents),
1262
- [resolvedMuiOptions, customComponents]
1263
- );
1264
- const slots = (0, import_react3.useMemo)(
1265
- () => createMuiBuilderSlots(resolvedMuiOptions, customSlots),
1266
- [resolvedMuiOptions, customSlots]
1267
- );
1268
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react2.FormBuilder, { ...props, components, disableDefaultStyles: true, slots });
1359
+ const contextValue = (0, import_react4.useMemo)(() => ({ options: contextOptions }), [contextOptions]);
1360
+ const components = (0, import_react4.useMemo)(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
1361
+ const slots = (0, import_react4.useMemo)(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
1362
+ const resolvedSectionOrder = sectionOrder ?? contextOptions.layoutOptions?.sectionOrder;
1363
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1364
+ import_react3.FormBuilder,
1365
+ {
1366
+ ...props,
1367
+ components,
1368
+ disableDefaultStyles: true,
1369
+ slots,
1370
+ ...resolvedSectionOrder === void 0 ? {} : { sectionOrder: resolvedSectionOrder }
1371
+ }
1372
+ ) });
1269
1373
  }
1270
1374
  // Annotate the CommonJS export names for ESM import in node:
1271
1375
  0 && (module.exports = {
@@ -1276,6 +1380,7 @@ function MuiFormBuilder({
1276
1380
  MuiFieldEditorSlot,
1277
1381
  MuiFieldsetAdapter,
1278
1382
  MuiFormBuilder,
1383
+ MuiFormBuilderContext,
1279
1384
  MuiIconButtonAdapter,
1280
1385
  MuiLocalizationSlot,
1281
1386
  MuiOptionEditorSlot,
@@ -1300,8 +1405,10 @@ function MuiFormBuilder({
1300
1405
  createMuiTextAreaAdapter,
1301
1406
  createMuiTextInputAdapter,
1302
1407
  createMuiToolbarSlot,
1408
+ mergeMuiAdapterOptions,
1303
1409
  muiBuilderComponents,
1304
1410
  muiBuilderSlots,
1305
1411
  muiDefaultIconResolver,
1306
- resolveMuiAdapterOptions
1412
+ resolveMuiAdapterOptions,
1413
+ useResolvedMuiAdapterOptions
1307
1414
  });