@form-engine-ts/mui 2.9.3 → 2.9.5

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
@@ -20,12 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ DEFAULT_MUI_SECTION_ORDER: () => DEFAULT_MUI_SECTION_ORDER,
23
24
  MuiButtonAdapter: () => MuiButtonAdapter,
24
25
  MuiCheckboxAdapter: () => MuiCheckboxAdapter,
25
26
  MuiErrorMessageAdapter: () => MuiErrorMessageAdapter,
26
27
  MuiFieldEditorSlot: () => MuiFieldEditorSlot,
27
28
  MuiFieldsetAdapter: () => MuiFieldsetAdapter,
28
29
  MuiFormBuilder: () => MuiFormBuilder,
30
+ MuiFormBuilderContext: () => MuiFormBuilderContext,
29
31
  MuiIconButtonAdapter: () => MuiIconButtonAdapter,
30
32
  MuiLocalizationSlot: () => MuiLocalizationSlot,
31
33
  MuiOptionEditorSlot: () => MuiOptionEditorSlot,
@@ -50,31 +52,81 @@ __export(index_exports, {
50
52
  createMuiTextAreaAdapter: () => createMuiTextAreaAdapter,
51
53
  createMuiTextInputAdapter: () => createMuiTextInputAdapter,
52
54
  createMuiToolbarSlot: () => createMuiToolbarSlot,
55
+ mergeMuiAdapterOptions: () => mergeMuiAdapterOptions,
53
56
  muiBuilderComponents: () => muiBuilderComponents,
54
57
  muiBuilderSlots: () => muiBuilderSlots,
55
58
  muiDefaultIconResolver: () => muiDefaultIconResolver,
56
- resolveMuiAdapterOptions: () => resolveMuiAdapterOptions
59
+ resolveMuiAdapterOptions: () => resolveMuiAdapterOptions,
60
+ useResolvedMuiAdapterOptions: () => useResolvedMuiAdapterOptions
57
61
  });
58
62
  module.exports = __toCommonJS(index_exports);
59
63
 
60
64
  // src/adapters/Button.tsx
61
65
  var import_material = require("@mui/material");
62
66
 
67
+ // src/context.ts
68
+ var import_react = require("react");
69
+
63
70
  // src/types.ts
71
+ var DEFAULT_MUI_SECTION_ORDER = [
72
+ "basicSettings",
73
+ "questions",
74
+ "addQuestion",
75
+ "localization"
76
+ ];
64
77
  function resolveMuiAdapterOptions(options = {}) {
78
+ const buttonVariant = options.buttonVariant ?? "contained";
65
79
  return {
66
80
  size: options.size ?? "medium",
67
81
  variant: options.variant ?? "outlined",
68
- buttonVariant: options.buttonVariant ?? "contained",
82
+ buttonVariant,
83
+ buttonVariants: {
84
+ primary: options.buttonVariants?.primary ?? buttonVariant,
85
+ secondary: options.buttonVariants?.secondary ?? buttonVariant,
86
+ danger: options.buttonVariants?.danger ?? buttonVariant
87
+ },
69
88
  fullWidth: options.fullWidth ?? true,
70
- dense: options.dense ?? false
89
+ inputFullWidth: options.inputFullWidth ?? options.fullWidth ?? true,
90
+ buttonFullWidth: options.buttonFullWidth ?? options.fullWidth ?? false,
91
+ dense: options.dense ?? false,
92
+ getLocaleLabel: options.getLocaleLabel ?? ((locale) => locale),
93
+ ...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
94
+ layoutOptions: options.layoutOptions ?? {},
95
+ fieldEditorOptions: {
96
+ description: options.fieldEditorOptions?.description ?? "editable"
97
+ },
98
+ localizationOptions: {
99
+ collapsible: options.localizationOptions?.collapsible ?? false,
100
+ defaultExpanded: options.localizationOptions?.defaultExpanded ?? false,
101
+ defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable"
102
+ },
103
+ muiSlotProps: options.muiSlotProps ?? {}
104
+ };
105
+ }
106
+
107
+ // src/context.ts
108
+ var MuiFormBuilderContext = (0, import_react.createContext)({ options: {} });
109
+ function mergeMuiAdapterOptions(base = {}, overrides = {}) {
110
+ return {
111
+ ...base,
112
+ ...overrides,
113
+ ...base.buttonVariants === void 0 && overrides.buttonVariants === void 0 ? {} : { buttonVariants: { ...base.buttonVariants, ...overrides.buttonVariants } },
114
+ ...base.layoutOptions === void 0 && overrides.layoutOptions === void 0 ? {} : { layoutOptions: { ...base.layoutOptions, ...overrides.layoutOptions } },
115
+ ...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : { fieldEditorOptions: { ...base.fieldEditorOptions, ...overrides.fieldEditorOptions } },
116
+ ...base.localizationOptions === void 0 && overrides.localizationOptions === void 0 ? {} : { localizationOptions: { ...base.localizationOptions, ...overrides.localizationOptions } },
117
+ ...base.muiSlotProps === void 0 && overrides.muiSlotProps === void 0 ? {} : { muiSlotProps: { ...base.muiSlotProps, ...overrides.muiSlotProps } }
71
118
  };
72
119
  }
120
+ function useResolvedMuiAdapterOptions(overrides) {
121
+ const context = (0, import_react.useContext)(MuiFormBuilderContext);
122
+ return resolveMuiAdapterOptions(
123
+ overrides === void 0 ? context.options : mergeMuiAdapterOptions(context.options, overrides)
124
+ );
125
+ }
73
126
 
74
127
  // src/adapters/Button.tsx
75
128
  var import_jsx_runtime = require("react/jsx-runtime");
76
129
  function createMuiButtonAdapter(options) {
77
- const resolved = resolveMuiAdapterOptions(options);
78
130
  return function MuiButton({
79
131
  id,
80
132
  className,
@@ -90,6 +142,7 @@ function createMuiButtonAdapter(options) {
90
142
  action,
91
143
  targetId
92
144
  }) {
145
+ const resolved = useResolvedMuiAdapterOptions(options);
93
146
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
94
147
  import_material.Button,
95
148
  {
@@ -106,8 +159,8 @@ function createMuiButtonAdapter(options) {
106
159
  "data-target-id": targetId,
107
160
  onClick,
108
161
  color: variant === "danger" ? "error" : "primary",
109
- variant: resolved.buttonVariant,
110
- fullWidth: resolved.fullWidth,
162
+ variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
163
+ fullWidth: resolved.buttonFullWidth ?? false,
111
164
  children
112
165
  }
113
166
  );
@@ -119,7 +172,6 @@ var MuiButtonAdapter = createMuiButtonAdapter();
119
172
  var import_material2 = require("@mui/material");
120
173
  var import_jsx_runtime2 = require("react/jsx-runtime");
121
174
  function createMuiCheckboxAdapter(options) {
122
- const resolved = resolveMuiAdapterOptions(options);
123
175
  return function MuiCheckbox({
124
176
  id,
125
177
  className,
@@ -136,6 +188,7 @@ function createMuiCheckboxAdapter(options) {
136
188
  onChange,
137
189
  label
138
190
  }) {
191
+ const resolved = useResolvedMuiAdapterOptions(options);
139
192
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_material2.FormControl, { className, error: Boolean(error), required, disabled: disabled || readOnly, children: [
140
193
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
141
194
  import_material2.FormControlLabel,
@@ -199,8 +252,8 @@ var MuiErrorMessageAdapter = createMuiErrorMessageAdapter();
199
252
  var import_material4 = require("@mui/material");
200
253
  var import_jsx_runtime4 = require("react/jsx-runtime");
201
254
  function createMuiFieldsetAdapter(options) {
202
- const resolved = resolveMuiAdapterOptions(options);
203
255
  return function MuiFieldset({ className, legend, disabled, children }) {
256
+ const resolved = useResolvedMuiAdapterOptions(options);
204
257
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
205
258
  import_material4.Box,
206
259
  {
@@ -232,19 +285,18 @@ var MuiFieldsetAdapter = createMuiFieldsetAdapter();
232
285
  // src/adapters/IconButton.tsx
233
286
  var import_material5 = require("@mui/material");
234
287
  var import_jsx_runtime5 = require("react/jsx-runtime");
235
- var ACTION_LABELS = {
236
- moveUp: "\u4E0A\u3078\u79FB\u52D5",
237
- moveDown: "\u4E0B\u3078\u79FB\u52D5",
238
- delete: "\u524A\u9664",
239
- add: "\u8FFD\u52A0",
240
- edit: "\u7DE8\u96C6",
241
- settings: "\u8A2D\u5B9A",
242
- translate: "\u7FFB\u8A33",
243
- close: "\u9589\u3058\u308B",
244
- dragHandle: "\u4E26\u3079\u66FF\u3048"
288
+ var FALLBACK_ACTION_LABELS = {
289
+ moveUp: "Move up",
290
+ moveDown: "Move down",
291
+ delete: "Delete",
292
+ add: "Add",
293
+ edit: "Edit",
294
+ settings: "Settings",
295
+ translate: "Translate",
296
+ close: "Close",
297
+ dragHandle: "Reorder"
245
298
  };
246
299
  function createMuiIconButtonAdapter(options) {
247
- const resolved = resolveMuiAdapterOptions(options);
248
300
  return function MuiIconButton({
249
301
  id,
250
302
  className,
@@ -258,7 +310,8 @@ function createMuiIconButtonAdapter(options) {
258
310
  actionType,
259
311
  title
260
312
  }) {
261
- const actionLabel = actionType === void 0 ? "\u64CD\u4F5C" : ACTION_LABELS[actionType];
313
+ const resolved = useResolvedMuiAdapterOptions(options);
314
+ const actionLabel = actionType === void 0 ? "Action" : resolved.getActionLabel?.(actionType) ?? FALLBACK_ACTION_LABELS[actionType];
262
315
  const tooltip = title ?? actionLabel;
263
316
  const color = actionType === "delete" ? "error" : actionType === "add" ? "primary" : "default";
264
317
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material5.Tooltip, { title: tooltip, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -285,7 +338,6 @@ var MuiIconButtonAdapter = createMuiIconButtonAdapter();
285
338
  var import_material6 = require("@mui/material");
286
339
  var import_jsx_runtime6 = require("react/jsx-runtime");
287
340
  function createMuiSectionAdapter(options) {
288
- const resolved = resolveMuiAdapterOptions(options);
289
341
  return function MuiSection({
290
342
  id,
291
343
  className,
@@ -296,16 +348,18 @@ function createMuiSectionAdapter(options) {
296
348
  onClickCapture,
297
349
  children
298
350
  }) {
351
+ const resolved = useResolvedMuiAdapterOptions(options);
299
352
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
300
353
  import_material6.Paper,
301
354
  {
355
+ ...resolved.muiSlotProps?.paper,
302
356
  id,
303
357
  className,
304
358
  elevation: 0,
305
359
  "aria-label": ariaLabel,
306
360
  "aria-labelledby": title === void 0 ? void 0 : headingId,
307
361
  onClickCapture,
308
- sx: {
362
+ sx: resolved.muiSlotProps?.paper?.sx ?? {
309
363
  p: resolved.dense ? 1.5 : 2,
310
364
  mb: resolved.dense ? 1 : 2,
311
365
  border: 1,
@@ -333,7 +387,6 @@ var MuiSectionAdapter = createMuiSectionAdapter();
333
387
  var import_material7 = require("@mui/material");
334
388
  var import_jsx_runtime7 = require("react/jsx-runtime");
335
389
  function createMuiSelectAdapter(options) {
336
- const resolved = resolveMuiAdapterOptions(options);
337
390
  return function MuiSelect({
338
391
  id,
339
392
  className,
@@ -351,13 +404,14 @@ function createMuiSelectAdapter(options) {
351
404
  onChange,
352
405
  options: selectOptions
353
406
  }) {
407
+ const resolved = useResolvedMuiAdapterOptions(options);
354
408
  const labelId = id === void 0 || label === void 0 ? void 0 : `${id}-label`;
355
409
  const handleChange = (event) => onChange(event.target.value);
356
410
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
357
411
  import_material7.FormControl,
358
412
  {
359
413
  className,
360
- fullWidth: resolved.fullWidth,
414
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
361
415
  size: resolved.size,
362
416
  variant: resolved.variant,
363
417
  error: Boolean(error),
@@ -396,7 +450,6 @@ var MuiSelectAdapter = createMuiSelectAdapter();
396
450
  var import_material8 = require("@mui/material");
397
451
  var import_jsx_runtime8 = require("react/jsx-runtime");
398
452
  function createMuiTextAreaAdapter(options) {
399
- const resolved = resolveMuiAdapterOptions(options);
400
453
  return function MuiTextArea({
401
454
  id,
402
455
  className,
@@ -416,6 +469,7 @@ function createMuiTextAreaAdapter(options) {
416
469
  maxLength,
417
470
  rows
418
471
  }) {
472
+ const resolved = useResolvedMuiAdapterOptions(options);
419
473
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
420
474
  import_material8.TextField,
421
475
  {
@@ -431,6 +485,7 @@ function createMuiTextAreaAdapter(options) {
431
485
  slotProps: {
432
486
  htmlInput: {
433
487
  maxLength,
488
+ readOnly,
434
489
  "aria-label": ariaLabel,
435
490
  "aria-describedby": ariaDescribedBy,
436
491
  "aria-labelledby": ariaLabelledBy
@@ -441,7 +496,7 @@ function createMuiTextAreaAdapter(options) {
441
496
  multiline: true,
442
497
  rows,
443
498
  placeholder,
444
- fullWidth: resolved.fullWidth,
499
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
445
500
  size: resolved.size,
446
501
  variant: resolved.variant,
447
502
  onChange: (event) => onChange(event.currentTarget.value)
@@ -455,7 +510,6 @@ var MuiTextAreaAdapter = createMuiTextAreaAdapter();
455
510
  var import_material9 = require("@mui/material");
456
511
  var import_jsx_runtime9 = require("react/jsx-runtime");
457
512
  function createMuiTextInputAdapter(options) {
458
- const resolved = resolveMuiAdapterOptions(options);
459
513
  return function MuiTextInput({
460
514
  id,
461
515
  className,
@@ -479,6 +533,7 @@ function createMuiTextInputAdapter(options) {
479
533
  max,
480
534
  step
481
535
  }) {
536
+ const resolved = useResolvedMuiAdapterOptions(options);
482
537
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
483
538
  import_material9.TextField,
484
539
  {
@@ -498,6 +553,7 @@ function createMuiTextInputAdapter(options) {
498
553
  max,
499
554
  step,
500
555
  inputMode,
556
+ readOnly,
501
557
  "aria-label": ariaLabel,
502
558
  "aria-describedby": ariaDescribedBy,
503
559
  "aria-labelledby": ariaLabelledBy
@@ -507,7 +563,7 @@ function createMuiTextInputAdapter(options) {
507
563
  },
508
564
  type,
509
565
  placeholder,
510
- fullWidth: resolved.fullWidth,
566
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
511
567
  size: resolved.size,
512
568
  variant: resolved.variant,
513
569
  onChange: (event) => onChange(event.currentTarget.value)
@@ -545,7 +601,7 @@ function muiDefaultIconResolver(actionType) {
545
601
 
546
602
  // src/components.ts
547
603
  function isAdapterOptions(value) {
548
- return "size" in value || "variant" in value || "buttonVariant" in value || "fullWidth" in value || "dense" in value;
604
+ 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;
549
605
  }
550
606
  function buildMuiBuilderComponents(options) {
551
607
  return {
@@ -561,11 +617,22 @@ function buildMuiBuilderComponents(options) {
561
617
  renderIcon: muiDefaultIconResolver
562
618
  };
563
619
  }
564
- var muiBuilderComponents = buildMuiBuilderComponents();
620
+ var muiBuilderComponents = {
621
+ Button: MuiButtonAdapter,
622
+ IconButton: MuiIconButtonAdapter,
623
+ TextInput: MuiTextInputAdapter,
624
+ TextArea: MuiTextAreaAdapter,
625
+ Select: MuiSelectAdapter,
626
+ Checkbox: MuiCheckboxAdapter,
627
+ Section: MuiSectionAdapter,
628
+ Fieldset: MuiFieldsetAdapter,
629
+ ErrorMessage: MuiErrorMessageAdapter,
630
+ renderIcon: muiDefaultIconResolver
631
+ };
565
632
  function createMuiBuilderComponents(optionsOrOverrides = {}, customOverrides) {
566
633
  const options = isAdapterOptions(optionsOrOverrides) ? optionsOrOverrides : void 0;
567
634
  const overrides = customOverrides ?? (options === void 0 ? optionsOrOverrides : {});
568
- return { ...buildMuiBuilderComponents(options), ...overrides };
635
+ return { ...options === void 0 ? muiBuilderComponents : buildMuiBuilderComponents(options), ...overrides };
569
636
  }
570
637
 
571
638
  // src/slots/FieldEditor.tsx
@@ -575,7 +642,6 @@ var import_material12 = require("@mui/material");
575
642
  var import_material10 = require("@mui/material");
576
643
  var import_jsx_runtime11 = require("react/jsx-runtime");
577
644
  function createMuiOptionEditorSlot(options) {
578
- const resolved = resolveMuiAdapterOptions(options);
579
645
  return function MuiOptionEditor({
580
646
  field,
581
647
  option,
@@ -583,21 +649,23 @@ function createMuiOptionEditorSlot(options) {
583
649
  currentLocale,
584
650
  readOnly,
585
651
  actions,
586
- components
652
+ components,
653
+ translate
587
654
  }) {
655
+ const resolved = useResolvedMuiAdapterOptions(options);
588
656
  const { IconButton: IconButton2, TextInput } = components;
589
657
  const describedBy = option.label.trim().length === 0 ? `mui-option-${option.id}-error` : void 0;
590
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material10.Stack, { "data-mui-slot": "option-editor", spacing: resolved.dense ? 0.75 : 1, children: [
658
+ 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: [
591
659
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material10.Stack, { direction: { xs: "column", sm: "row" }, spacing: 1, alignItems: { sm: "flex-start" }, children: [
592
660
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
593
661
  TextInput,
594
662
  {
595
663
  id: `mui-option-${option.id}`,
596
- label: `Option ${index + 1}`,
664
+ label: translate("builder.optionLabel", { index: index + 1 }),
597
665
  value: option.label,
598
666
  required: true,
599
667
  error: option.label.trim().length === 0,
600
- helperText: option.label.trim().length === 0 ? "Required" : "",
668
+ helperText: option.label.trim().length === 0 ? translate("builder.required") : "",
601
669
  "aria-describedby": describedBy,
602
670
  disabled: readOnly,
603
671
  onChange: (value) => actions.updateOption(field.id, option.id, (current) => ({ ...current, label: value }))
@@ -608,7 +676,7 @@ function createMuiOptionEditorSlot(options) {
608
676
  IconButton2,
609
677
  {
610
678
  actionType: "moveUp",
611
- title: `Move ${option.label} up`,
679
+ title: translate("builder.moveUp", { title: option.label }),
612
680
  disabled: readOnly || index === 0,
613
681
  onClick: () => actions.moveOption(field.id, option.id, index - 1)
614
682
  }
@@ -617,7 +685,7 @@ function createMuiOptionEditorSlot(options) {
617
685
  IconButton2,
618
686
  {
619
687
  actionType: "moveDown",
620
- title: `Move ${option.label} down`,
688
+ title: translate("builder.moveDown", { title: option.label }),
621
689
  disabled: readOnly || index === field.options.length - 1,
622
690
  onClick: () => actions.moveOption(field.id, option.id, index + 1)
623
691
  }
@@ -626,7 +694,7 @@ function createMuiOptionEditorSlot(options) {
626
694
  IconButton2,
627
695
  {
628
696
  actionType: "delete",
629
- title: `Delete ${option.label}`,
697
+ title: translate("builder.delete", { title: option.label }),
630
698
  disabled: readOnly || field.options.length <= 1,
631
699
  onClick: () => actions.removeOption(field.id, option.id)
632
700
  }
@@ -637,10 +705,12 @@ function createMuiOptionEditorSlot(options) {
637
705
  TextInput,
638
706
  {
639
707
  id: `mui-option-${option.id}-${currentLocale}`,
640
- label: `${currentLocale} translation`,
708
+ label: translate("builder.translation", {
709
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
710
+ }),
641
711
  value: option.translations?.[currentLocale] ?? "",
642
712
  disabled: readOnly,
643
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
713
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
644
714
  }
645
715
  )
646
716
  ] });
@@ -652,7 +722,6 @@ var MuiOptionEditorSlot = createMuiOptionEditorSlot();
652
722
  var import_material11 = require("@mui/material");
653
723
  var import_jsx_runtime12 = require("react/jsx-runtime");
654
724
  function createMuiToolbarSlot(options) {
655
- const resolved = resolveMuiAdapterOptions(options);
656
725
  return function MuiToolbar({
657
726
  kind,
658
727
  index,
@@ -662,23 +731,26 @@ function createMuiToolbarSlot(options) {
662
731
  onMoveDown,
663
732
  onRemove,
664
733
  readOnly,
665
- components
734
+ components,
735
+ translate
666
736
  }) {
737
+ const resolved = useResolvedMuiAdapterOptions(options);
667
738
  const { IconButton: IconButton2 } = components;
668
739
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
669
740
  import_material11.Stack,
670
741
  {
742
+ ...resolved.muiSlotProps?.stack,
671
743
  "data-mui-slot": "toolbar",
672
744
  direction: "row",
673
745
  spacing: resolved.dense ? 0.5 : 1,
674
746
  alignItems: "center",
675
- sx: { mb: resolved.dense ? 1 : 2 },
747
+ sx: resolved.muiSlotProps?.stack?.sx ?? { mb: resolved.dense ? 1 : 2 },
676
748
  children: [
677
749
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
678
750
  IconButton2,
679
751
  {
680
752
  actionType: "moveUp",
681
- title: `Move ${title} up`,
753
+ title: translate("builder.moveUp", { title }),
682
754
  disabled: readOnly || index === 0,
683
755
  onClick: onMoveUp
684
756
  }
@@ -687,7 +759,7 @@ function createMuiToolbarSlot(options) {
687
759
  IconButton2,
688
760
  {
689
761
  actionType: "moveDown",
690
- title: `Move ${title} down`,
762
+ title: translate("builder.moveDown", { title }),
691
763
  disabled: readOnly || index === total - 1,
692
764
  onClick: onMoveDown
693
765
  }
@@ -696,7 +768,7 @@ function createMuiToolbarSlot(options) {
696
768
  IconButton2,
697
769
  {
698
770
  actionType: "delete",
699
- title: `Delete ${title}`,
771
+ title: translate("builder.delete", { title }),
700
772
  disabled: readOnly || kind !== "page" && total <= 1,
701
773
  onClick: onRemove
702
774
  }
@@ -723,6 +795,16 @@ var FIELD_TYPES = [
723
795
  function isFieldType(value) {
724
796
  return FIELD_TYPES.some((type) => type === value);
725
797
  }
798
+ function conditionOperators(field) {
799
+ if (field.type === "multi-select") return ["contains", "not_empty"];
800
+ if (field.type === "text" || field.type === "textarea") {
801
+ return ["equals", "not_equals", "contains", "not_empty"];
802
+ }
803
+ return ["equals", "not_equals", "not_empty"];
804
+ }
805
+ function isConditionOperator(value) {
806
+ return ["equals", "not_equals", "contains", "not_empty"].some((operator) => operator === value);
807
+ }
726
808
  function numericValue(value) {
727
809
  if (value.trim().length === 0) return void 0;
728
810
  const parsed = Number(value);
@@ -736,7 +818,6 @@ function updateBound(field, property, value) {
736
818
  return remaining;
737
819
  }
738
820
  function createMuiFieldEditorSlot(options) {
739
- const resolved = resolveMuiAdapterOptions(options);
740
821
  const Toolbar = createMuiToolbarSlot(options);
741
822
  const OptionEditor = createMuiOptionEditorSlot(options);
742
823
  return function MuiFieldEditor({
@@ -745,27 +826,34 @@ function createMuiFieldEditorSlot(options) {
745
826
  index,
746
827
  currentLocale,
747
828
  policy,
829
+ features,
748
830
  readOnly,
749
831
  actions,
750
- components
832
+ components,
833
+ translate
751
834
  }) {
835
+ const resolved = useResolvedMuiAdapterOptions(options);
752
836
  const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
753
837
  const allowedTypes = policy?.allowedFieldTypes ?? FIELD_TYPES;
754
838
  const pageId = schema.pages?.find((page) => page.questionIds.includes(field.id))?.id ?? "";
755
839
  const condition = field.displayCondition;
756
840
  const conditionSources = schema.fields.slice(0, index);
841
+ const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
842
+ const descriptionMode = resolved.fieldEditorOptions?.description ?? "editable";
757
843
  const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
758
844
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
759
845
  import_material12.Card,
760
846
  {
847
+ ...resolved.muiSlotProps?.card,
761
848
  "data-mui-slot": "field-editor",
762
849
  variant: "outlined",
763
- sx: { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
850
+ sx: resolved.muiSlotProps?.card?.sx ?? { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
764
851
  children: [
765
852
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
766
853
  Toolbar,
767
854
  {
768
855
  schema,
856
+ translate,
769
857
  kind: "field",
770
858
  targetId: field.id,
771
859
  index,
@@ -779,7 +867,7 @@ function createMuiFieldEditorSlot(options) {
779
867
  components
780
868
  }
781
869
  ),
782
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { spacing: resolved.dense ? 1 : 2, children: [
870
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { ...resolved.muiSlotProps?.stack, spacing: resolved.dense ? 1 : 2, children: [
783
871
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle1", fontWeight: "bold", children: field.title }),
784
872
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
785
873
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
@@ -787,11 +875,11 @@ function createMuiFieldEditorSlot(options) {
787
875
  {
788
876
  id: `mui-field-${field.id}-title`,
789
877
  name: `fields.${field.id}.title`,
790
- label: "Question title",
878
+ label: translate("builder.questionTitle"),
791
879
  value: field.title,
792
880
  required: true,
793
881
  error: field.title.trim().length === 0,
794
- helperText: field.title.trim().length === 0 ? "Required" : "",
882
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
795
883
  "aria-describedby": titleErrorId,
796
884
  disabled: readOnly,
797
885
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "title", value)
@@ -802,12 +890,11 @@ function createMuiFieldEditorSlot(options) {
802
890
  {
803
891
  id: `mui-field-${field.id}-type`,
804
892
  name: `fields.${field.id}.type`,
805
- label: "Type",
806
- value: field.type,
807
- options: FIELD_TYPES.map((type) => ({
893
+ label: translate("builder.type"),
894
+ value: allowedTypes.includes(field.type) ? field.type : "",
895
+ options: FIELD_TYPES.filter((type) => allowedTypes.includes(type)).map((type) => ({
808
896
  value: type,
809
- label: type,
810
- disabled: !allowedTypes.includes(type)
897
+ label: translate(`builder.fieldType.${type}`)
811
898
  })),
812
899
  disabled: readOnly,
813
900
  onChange: (value) => {
@@ -816,15 +903,16 @@ function createMuiFieldEditorSlot(options) {
816
903
  }
817
904
  )
818
905
  ] }),
819
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
906
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
820
907
  TextArea,
821
908
  {
822
909
  id: `mui-field-${field.id}-description`,
823
910
  name: `fields.${field.id}.description`,
824
- label: "Description",
911
+ label: translate("builder.description"),
825
912
  value: field.description ?? "",
826
913
  rows: resolved.dense ? 2 : 3,
827
914
  disabled: readOnly,
915
+ readOnly: descriptionMode === "readOnly",
828
916
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "description", value)
829
917
  }
830
918
  ),
@@ -833,20 +921,20 @@ function createMuiFieldEditorSlot(options) {
833
921
  {
834
922
  id: `mui-field-${field.id}-required`,
835
923
  name: `fields.${field.id}.required`,
836
- label: "Required",
924
+ label: translate("builder.required"),
837
925
  checked: field.required,
838
926
  disabled: readOnly,
839
927
  onChange: (checked) => actions.updateField(field.id, (current) => ({ ...current, required: checked }))
840
928
  }
841
929
  ),
842
- schema.pages === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
930
+ features?.pages === false || schema.pages === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
843
931
  Select2,
844
932
  {
845
933
  id: `mui-field-${field.id}-page`,
846
- label: "Page",
934
+ label: translate("builder.questionPage"),
847
935
  value: pageId,
848
936
  options: [
849
- { value: "", label: "Unassigned" },
937
+ { value: "", label: translate("builder.unassigned") },
850
938
  ...schema.pages.map((page) => ({ value: page.id, label: page.title ?? page.id }))
851
939
  ],
852
940
  disabled: readOnly,
@@ -858,7 +946,7 @@ function createMuiFieldEditorSlot(options) {
858
946
  TextInput,
859
947
  {
860
948
  id: `mui-field-${field.id}-minimum`,
861
- label: "Minimum",
949
+ label: translate("builder.minimum"),
862
950
  type: "number",
863
951
  value: field.min === void 0 ? "" : String(field.min),
864
952
  disabled: readOnly,
@@ -869,7 +957,7 @@ function createMuiFieldEditorSlot(options) {
869
957
  TextInput,
870
958
  {
871
959
  id: `mui-field-${field.id}-maximum`,
872
- label: "Maximum",
960
+ label: translate("builder.maximum"),
873
961
  type: "number",
874
962
  value: field.max === void 0 ? "" : String(field.max),
875
963
  disabled: readOnly,
@@ -877,15 +965,15 @@ function createMuiFieldEditorSlot(options) {
877
965
  }
878
966
  )
879
967
  ] }) : null,
880
- conditionSources.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
968
+ features?.conditions === false || conditionSources.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
881
969
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
882
970
  Select2,
883
971
  {
884
972
  id: `mui-field-${field.id}-condition-source`,
885
- label: "Display condition",
973
+ label: translate("builder.displayCondition"),
886
974
  value: condition?.questionId ?? "",
887
975
  options: [
888
- { value: "", label: "Always visible" },
976
+ { value: "", label: translate("builder.alwaysVisible") },
889
977
  ...conditionSources.map((source) => ({ value: source.id, label: source.title }))
890
978
  ],
891
979
  disabled: readOnly,
@@ -895,45 +983,66 @@ function createMuiFieldEditorSlot(options) {
895
983
  )
896
984
  }
897
985
  ),
898
- condition === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
899
- TextInput,
900
- {
901
- id: `mui-field-${field.id}-condition-value`,
902
- label: "Condition value",
903
- value: condition.value === void 0 ? "" : String(condition.value),
904
- disabled: readOnly,
905
- onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
906
- }
907
- )
986
+ condition === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
988
+ Select2,
989
+ {
990
+ id: `mui-field-${field.id}-condition-operator`,
991
+ label: translate("builder.conditionOperator"),
992
+ value: condition.operator,
993
+ options: (conditionSource === void 0 ? [] : conditionOperators(conditionSource)).map(
994
+ (operator) => ({ value: operator, label: translate(`builder.operator.${operator}`) })
995
+ ),
996
+ disabled: readOnly,
997
+ onChange: (value) => {
998
+ if (!isConditionOperator(value)) return;
999
+ actions.setDisplayCondition(
1000
+ field.id,
1001
+ value === "not_empty" ? { questionId: condition.questionId, operator: value } : { ...condition, operator: value, value: condition.value ?? "" }
1002
+ );
1003
+ }
1004
+ }
1005
+ ),
1006
+ condition.operator === "not_empty" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1007
+ TextInput,
1008
+ {
1009
+ id: `mui-field-${field.id}-condition-value`,
1010
+ label: translate("builder.conditionValue"),
1011
+ value: condition.value === void 0 ? "" : String(condition.value),
1012
+ disabled: readOnly,
1013
+ onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
1014
+ }
1015
+ )
1016
+ ] })
908
1017
  ] }),
909
1018
  currentLocale.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { spacing: resolved.dense ? 1 : 2, children: [
910
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Typography, { variant: "subtitle2", children: [
911
- currentLocale,
912
- " translation"
913
- ] }),
1019
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle2", children: translate("builder.translation", {
1020
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
1021
+ }) }),
914
1022
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
915
1023
  TextInput,
916
1024
  {
917
1025
  id: `mui-field-${field.id}-${currentLocale}-title`,
918
- label: "Translated question title",
1026
+ label: translate("builder.translatedQuestionTitle"),
919
1027
  value: field.translations?.[currentLocale]?.title ?? "",
920
1028
  disabled: readOnly,
921
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
1029
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
922
1030
  }
923
1031
  ),
924
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1032
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
925
1033
  TextArea,
926
1034
  {
927
1035
  id: `mui-field-${field.id}-${currentLocale}-description`,
928
- label: "Translated description",
1036
+ label: translate("builder.translatedDescription"),
929
1037
  value: field.translations?.[currentLocale]?.description ?? "",
930
1038
  disabled: readOnly,
931
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
1039
+ readOnly: descriptionMode === "readOnly",
1040
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
932
1041
  }
933
1042
  )
934
1043
  ] }),
935
1044
  "options" in field ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
936
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle2", children: "Options" }),
1045
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle2", children: translate("builder.options") }),
937
1046
  field.options.map((option, optionIndex) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
938
1047
  OptionEditor,
939
1048
  {
@@ -942,6 +1051,7 @@ function createMuiFieldEditorSlot(options) {
942
1051
  option,
943
1052
  index: optionIndex,
944
1053
  currentLocale,
1054
+ translate,
945
1055
  readOnly,
946
1056
  actions,
947
1057
  components
@@ -955,7 +1065,7 @@ function createMuiFieldEditorSlot(options) {
955
1065
  targetId: field.id,
956
1066
  disabled: readOnly || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
957
1067
  onClick: () => actions.addOption(field.id),
958
- children: "Add option"
1068
+ children: translate("builder.addOption")
959
1069
  }
960
1070
  )
961
1071
  ] }) : null
@@ -968,11 +1078,11 @@ function createMuiFieldEditorSlot(options) {
968
1078
  var MuiFieldEditorSlot = createMuiFieldEditorSlot();
969
1079
 
970
1080
  // src/slots/Localization.tsx
1081
+ var import_icons_material2 = require("@mui/icons-material");
971
1082
  var import_material13 = require("@mui/material");
972
- var import_react = require("react");
1083
+ var import_react2 = require("react");
973
1084
  var import_jsx_runtime14 = require("react/jsx-runtime");
974
1085
  function createMuiLocalizationSlot(options) {
975
- const resolved = resolveMuiAdapterOptions(options);
976
1086
  return function MuiLocalization({
977
1087
  schema,
978
1088
  currentLocale,
@@ -980,27 +1090,163 @@ function createMuiLocalizationSlot(options) {
980
1090
  onAutoTranslate,
981
1091
  isTranslating,
982
1092
  translationError,
1093
+ policy,
1094
+ translationAdapterAvailable,
983
1095
  readOnly,
984
1096
  actions,
985
- components
1097
+ components,
1098
+ translate
986
1099
  }) {
987
- const { Button: Button2, ErrorMessage, TextArea, TextInput } = components;
988
- const [newLocale, setNewLocale] = (0, import_react.useState)("");
1100
+ const resolved = useResolvedMuiAdapterOptions(options);
1101
+ const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
1102
+ const [newLocale, setNewLocale] = (0, import_react2.useState)("");
989
1103
  const locales = Array.from(
990
- /* @__PURE__ */ new Set([
991
- ...schema.supportedLocales ?? [],
992
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale]
993
- ])
1104
+ new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
994
1105
  );
1106
+ const editingLocaleConfigured = locales.includes(currentLocale);
1107
+ const registeredLocales = /* @__PURE__ */ new Set([
1108
+ ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
1109
+ ...schema.supportedLocales ?? []
1110
+ ]);
1111
+ const availableAllowedLocales = policy?.allowedLocales?.filter((locale) => !registeredLocales.has(locale));
1112
+ const localeLimitReached = policy?.maxLocales !== void 0 && registeredLocales.size >= policy.maxLocales;
1113
+ const normalizedLocale = newLocale.trim();
1114
+ const localeAllowed = policy?.allowedLocales === void 0 || policy.allowedLocales.includes(normalizedLocale);
1115
+ const canAddLocale = !readOnly && normalizedLocale.length > 0 && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
995
1116
  const handleTabChange = (_event, value) => onCurrentLocaleChange(value);
996
1117
  const addLocale = () => {
997
- const normalized = newLocale.trim();
998
- if (normalized.length === 0) return;
999
- const result = actions.addLocale(normalized);
1118
+ if (!canAddLocale) return;
1119
+ const result = actions.addLocale(normalizedLocale);
1000
1120
  if (!result.success) return;
1001
- onCurrentLocaleChange(normalized);
1121
+ onCurrentLocaleChange(normalizedLocale);
1002
1122
  setNewLocale("");
1003
1123
  };
1124
+ const stackProps = resolved.muiSlotProps?.stack;
1125
+ const collapsible = resolved.localizationOptions?.collapsible ?? false;
1126
+ const defaultLocaleControl = resolved.localizationOptions?.defaultLocaleControl ?? "editable";
1127
+ const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1128
+ !collapsible ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) : null,
1129
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
1130
+ defaultLocaleControl === "hidden" ? null : defaultLocaleControl === "readOnly" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { spacing: 0.5, children: [
1131
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "caption", color: "text.secondary", children: translate("builder.defaultLocale") }),
1132
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1133
+ import_material13.Chip,
1134
+ {
1135
+ label: resolved.getLocaleLabel?.(schema.defaultLocale ?? "") ?? schema.defaultLocale ?? "",
1136
+ size: resolved.size
1137
+ }
1138
+ )
1139
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1140
+ TextInput,
1141
+ {
1142
+ id: "mui-builder-default-locale",
1143
+ label: translate("builder.defaultLocale"),
1144
+ value: schema.defaultLocale ?? "",
1145
+ disabled: readOnly,
1146
+ onChange: (value) => {
1147
+ const result = actions.setDefaultLocale(value);
1148
+ if (result.success && value === currentLocale) onCurrentLocaleChange("");
1149
+ }
1150
+ }
1151
+ ),
1152
+ availableAllowedLocales === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1153
+ TextInput,
1154
+ {
1155
+ id: "mui-builder-new-locale",
1156
+ label: translate("builder.addLocale"),
1157
+ value: newLocale,
1158
+ disabled: readOnly || localeLimitReached,
1159
+ onChange: setNewLocale
1160
+ }
1161
+ ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1162
+ Select2,
1163
+ {
1164
+ id: "mui-builder-new-locale",
1165
+ label: translate("builder.addLocale"),
1166
+ value: newLocale,
1167
+ options: [
1168
+ { value: "", label: "\u2014" },
1169
+ ...availableAllowedLocales.map((locale) => ({
1170
+ value: locale,
1171
+ label: resolved.getLocaleLabel?.(locale) ?? locale
1172
+ }))
1173
+ ],
1174
+ disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
1175
+ onChange: setNewLocale
1176
+ }
1177
+ ),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button2, { variant: "primary", action: "addLocale", disabled: !canAddLocale, onClick: addLocale, children: translate("builder.addLocale") })
1179
+ ] }),
1180
+ locales.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1181
+ import_material13.Tabs,
1182
+ {
1183
+ value: editingLocaleConfigured ? currentLocale : false,
1184
+ onChange: handleTabChange,
1185
+ variant: "scrollable",
1186
+ scrollButtons: "auto",
1187
+ "aria-label": translate("builder.translationLocale"),
1188
+ children: locales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1189
+ import_material13.Tab,
1190
+ {
1191
+ value: locale,
1192
+ label: resolved.getLocaleLabel?.(locale) ?? locale,
1193
+ disabled: readOnly && locale !== currentLocale
1194
+ },
1195
+ locale
1196
+ ))
1197
+ }
1198
+ ),
1199
+ !translationAdapterAvailable ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1200
+ Button2,
1201
+ {
1202
+ variant: "secondary",
1203
+ disabled: readOnly || !editingLocaleConfigured || isTranslating,
1204
+ onClick: onAutoTranslate,
1205
+ children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
1206
+ }
1207
+ ),
1208
+ translationError === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ErrorMessage, { message: translationError }),
1209
+ !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: [
1210
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1211
+ TextInput,
1212
+ {
1213
+ id: `mui-builder-${currentLocale}-form-title`,
1214
+ label: translate("builder.translatedFormTitle"),
1215
+ value: schema.translations?.[currentLocale]?.title ?? "",
1216
+ disabled: readOnly,
1217
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "title", value)
1218
+ }
1219
+ ),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1221
+ TextArea,
1222
+ {
1223
+ id: `mui-builder-${currentLocale}-form-description`,
1224
+ label: translate("builder.translatedFormDescription"),
1225
+ value: schema.translations?.[currentLocale]?.description ?? "",
1226
+ disabled: readOnly,
1227
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "description", value)
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1231
+ TextInput,
1232
+ {
1233
+ id: `mui-builder-${currentLocale}-completion-message`,
1234
+ label: translate("builder.translatedCompletionMessage"),
1235
+ value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1236
+ disabled: readOnly,
1237
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1238
+ }
1239
+ )
1240
+ ] })
1241
+ ] });
1242
+ const configured = locales.length > 0;
1243
+ const defaultExpanded = resolved.localizationOptions?.defaultExpanded === "when-configured" ? configured : resolved.localizationOptions?.defaultExpanded ?? false;
1244
+ if (collapsible) {
1245
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Accordion, { ...resolved.muiSlotProps?.accordion, "data-mui-slot": "localization", defaultExpanded, children: [
1246
+ /* @__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") }) }),
1247
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.AccordionDetails, { children: content })
1248
+ ] });
1249
+ }
1004
1250
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1005
1251
  import_material13.Box,
1006
1252
  {
@@ -1012,95 +1258,7 @@ function createMuiLocalizationSlot(options) {
1012
1258
  borderColor: "divider",
1013
1259
  borderRadius: 1
1014
1260
  },
1015
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { spacing: resolved.dense ? 1 : 2, children: [
1016
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: "Localization" }),
1017
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1018
- TextInput,
1019
- {
1020
- id: "mui-builder-completion-message",
1021
- label: "Completion message",
1022
- value: schema.completionMessage ?? "",
1023
- disabled: readOnly,
1024
- onChange: (value) => actions.setSourceText({ kind: "form" }, "completionMessage", value)
1025
- }
1026
- ),
1027
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
1028
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1029
- TextInput,
1030
- {
1031
- id: "mui-builder-default-locale",
1032
- label: "Default locale",
1033
- value: schema.defaultLocale ?? "",
1034
- disabled: readOnly,
1035
- onChange: (value) => actions.setDefaultLocale(value)
1036
- }
1037
- ),
1038
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1039
- TextInput,
1040
- {
1041
- id: "mui-builder-new-locale",
1042
- label: "Add locale",
1043
- value: newLocale,
1044
- disabled: readOnly,
1045
- onChange: setNewLocale
1046
- }
1047
- ),
1048
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button2, { disabled: readOnly || newLocale.trim().length === 0, onClick: addLocale, children: "Add locale" })
1049
- ] }),
1050
- locales.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1051
- import_material13.Tabs,
1052
- {
1053
- value: locales.includes(currentLocale) ? currentLocale : false,
1054
- onChange: handleTabChange,
1055
- variant: "scrollable",
1056
- scrollButtons: "auto",
1057
- "aria-label": "Translation locale",
1058
- children: locales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Tab, { value: locale, label: locale, disabled: readOnly && locale !== currentLocale }, locale))
1059
- }
1060
- ),
1061
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1062
- Button2,
1063
- {
1064
- variant: "secondary",
1065
- disabled: readOnly || currentLocale.length === 0 || isTranslating,
1066
- onClick: onAutoTranslate,
1067
- children: isTranslating ? "Translating\u2026" : "Translate all text"
1068
- }
1069
- ),
1070
- translationError === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ErrorMessage, { message: translationError }),
1071
- currentLocale.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "body2", color: "text.secondary", children: "Select a locale to edit translations." }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { spacing: resolved.dense ? 1 : 2, children: [
1072
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1073
- TextInput,
1074
- {
1075
- id: `mui-builder-${currentLocale}-form-title`,
1076
- label: "Translated form title",
1077
- value: schema.translations?.[currentLocale]?.title ?? "",
1078
- disabled: readOnly,
1079
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "title", value)
1080
- }
1081
- ),
1082
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1083
- TextArea,
1084
- {
1085
- id: `mui-builder-${currentLocale}-form-description`,
1086
- label: "Translated form description",
1087
- value: schema.translations?.[currentLocale]?.description ?? "",
1088
- disabled: readOnly,
1089
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "description", value)
1090
- }
1091
- ),
1092
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1093
- TextInput,
1094
- {
1095
- id: `mui-builder-${currentLocale}-completion-message`,
1096
- label: "Translated completion message",
1097
- value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1098
- disabled: readOnly,
1099
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1100
- }
1101
- )
1102
- ] })
1103
- ] })
1261
+ children: content
1104
1262
  }
1105
1263
  );
1106
1264
  };
@@ -1109,13 +1267,15 @@ var MuiLocalizationSlot = createMuiLocalizationSlot();
1109
1267
 
1110
1268
  // src/slots/index.ts
1111
1269
  var muiBuilderSlots = {
1112
- toolbar: createMuiToolbarSlot(),
1113
- fieldEditor: createMuiFieldEditorSlot(),
1114
- optionEditor: createMuiOptionEditorSlot(),
1115
- localization: createMuiLocalizationSlot()
1270
+ sectionOrder: DEFAULT_MUI_SECTION_ORDER,
1271
+ toolbar: MuiToolbarSlot,
1272
+ fieldEditor: MuiFieldEditorSlot,
1273
+ optionEditor: MuiOptionEditorSlot,
1274
+ localization: MuiLocalizationSlot
1116
1275
  };
1117
1276
  function createMuiBuilderSlots(options, customOverrides = {}) {
1118
1277
  return {
1278
+ sectionOrder: options?.layoutOptions?.sectionOrder ?? DEFAULT_MUI_SECTION_ORDER,
1119
1279
  toolbar: createMuiToolbarSlot(options),
1120
1280
  fieldEditor: createMuiFieldEditorSlot(options),
1121
1281
  optionEditor: createMuiOptionEditorSlot(options),
@@ -1134,30 +1294,52 @@ function createMuiBuilderProps(options, overrides = {}) {
1134
1294
  }
1135
1295
 
1136
1296
  // src/MuiFormBuilder.tsx
1137
- var import_react2 = require("@form-engine-ts/react");
1138
- var import_react3 = require("react");
1297
+ var import_react3 = require("@form-engine-ts/react");
1298
+ var import_react4 = require("react");
1139
1299
  var import_jsx_runtime15 = require("react/jsx-runtime");
1140
1300
  function MuiFormBuilder({
1141
1301
  muiOptions,
1302
+ layoutOptions,
1303
+ localizationOptions,
1304
+ muiSlotProps,
1142
1305
  components: customComponents,
1143
1306
  slots: customSlots,
1307
+ sectionOrder,
1144
1308
  ...props
1145
1309
  }) {
1146
- const components = (0, import_react3.useMemo)(
1147
- () => createMuiBuilderComponents(muiOptions, customComponents),
1148
- [muiOptions, customComponents]
1310
+ const contextOptions = (0, import_react4.useMemo)(
1311
+ () => mergeMuiAdapterOptions(muiOptions, {
1312
+ ...layoutOptions === void 0 ? {} : { layoutOptions },
1313
+ ...localizationOptions === void 0 ? {} : { localizationOptions },
1314
+ ...muiSlotProps === void 0 ? {} : { muiSlotProps }
1315
+ }),
1316
+ [layoutOptions, localizationOptions, muiOptions, muiSlotProps]
1149
1317
  );
1150
- const slots = (0, import_react3.useMemo)(() => createMuiBuilderSlots(muiOptions, customSlots), [muiOptions, customSlots]);
1151
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react2.FormBuilder, { ...props, components, disableDefaultStyles: true, slots });
1318
+ const contextValue = (0, import_react4.useMemo)(() => ({ options: contextOptions }), [contextOptions]);
1319
+ const components = (0, import_react4.useMemo)(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
1320
+ const slots = (0, import_react4.useMemo)(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
1321
+ const resolvedSectionOrder = sectionOrder ?? contextOptions.layoutOptions?.sectionOrder;
1322
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1323
+ import_react3.FormBuilder,
1324
+ {
1325
+ ...props,
1326
+ components,
1327
+ disableDefaultStyles: true,
1328
+ slots,
1329
+ ...resolvedSectionOrder === void 0 ? {} : { sectionOrder: resolvedSectionOrder }
1330
+ }
1331
+ ) });
1152
1332
  }
1153
1333
  // Annotate the CommonJS export names for ESM import in node:
1154
1334
  0 && (module.exports = {
1335
+ DEFAULT_MUI_SECTION_ORDER,
1155
1336
  MuiButtonAdapter,
1156
1337
  MuiCheckboxAdapter,
1157
1338
  MuiErrorMessageAdapter,
1158
1339
  MuiFieldEditorSlot,
1159
1340
  MuiFieldsetAdapter,
1160
1341
  MuiFormBuilder,
1342
+ MuiFormBuilderContext,
1161
1343
  MuiIconButtonAdapter,
1162
1344
  MuiLocalizationSlot,
1163
1345
  MuiOptionEditorSlot,
@@ -1182,8 +1364,10 @@ function MuiFormBuilder({
1182
1364
  createMuiTextAreaAdapter,
1183
1365
  createMuiTextInputAdapter,
1184
1366
  createMuiToolbarSlot,
1367
+ mergeMuiAdapterOptions,
1185
1368
  muiBuilderComponents,
1186
1369
  muiBuilderSlots,
1187
1370
  muiDefaultIconResolver,
1188
- resolveMuiAdapterOptions
1371
+ resolveMuiAdapterOptions,
1372
+ useResolvedMuiAdapterOptions
1189
1373
  });