@form-engine-ts/mui 2.9.3 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,13 +2,33 @@
2
2
  import { Button } from "@mui/material";
3
3
 
4
4
  // src/types.ts
5
+ var DEFAULT_MUI_SECTION_ORDER = [
6
+ "basicSettings",
7
+ "questions",
8
+ "addQuestion",
9
+ "localization"
10
+ ];
5
11
  function resolveMuiAdapterOptions(options = {}) {
12
+ const buttonVariant = options.buttonVariant ?? "contained";
6
13
  return {
7
14
  size: options.size ?? "medium",
8
15
  variant: options.variant ?? "outlined",
9
- buttonVariant: options.buttonVariant ?? "contained",
16
+ buttonVariant,
17
+ buttonVariants: {
18
+ primary: options.buttonVariants?.primary ?? buttonVariant,
19
+ secondary: options.buttonVariants?.secondary ?? buttonVariant,
20
+ danger: options.buttonVariants?.danger ?? buttonVariant
21
+ },
10
22
  fullWidth: options.fullWidth ?? true,
11
- dense: options.dense ?? false
23
+ dense: options.dense ?? false,
24
+ getLocaleLabel: options.getLocaleLabel ?? ((locale) => locale),
25
+ ...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
26
+ layoutOptions: options.layoutOptions ?? {},
27
+ localizationOptions: {
28
+ collapsible: options.localizationOptions?.collapsible ?? false,
29
+ defaultExpanded: options.localizationOptions?.defaultExpanded ?? false
30
+ },
31
+ muiSlotProps: options.muiSlotProps ?? {}
12
32
  };
13
33
  }
14
34
 
@@ -47,7 +67,7 @@ function createMuiButtonAdapter(options) {
47
67
  "data-target-id": targetId,
48
68
  onClick,
49
69
  color: variant === "danger" ? "error" : "primary",
50
- variant: resolved.buttonVariant,
70
+ variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
51
71
  fullWidth: resolved.fullWidth,
52
72
  children
53
73
  }
@@ -173,16 +193,16 @@ var MuiFieldsetAdapter = createMuiFieldsetAdapter();
173
193
  // src/adapters/IconButton.tsx
174
194
  import { IconButton, Tooltip } from "@mui/material";
175
195
  import { jsx as jsx5 } from "react/jsx-runtime";
176
- var ACTION_LABELS = {
177
- moveUp: "\u4E0A\u3078\u79FB\u52D5",
178
- moveDown: "\u4E0B\u3078\u79FB\u52D5",
179
- delete: "\u524A\u9664",
180
- add: "\u8FFD\u52A0",
181
- edit: "\u7DE8\u96C6",
182
- settings: "\u8A2D\u5B9A",
183
- translate: "\u7FFB\u8A33",
184
- close: "\u9589\u3058\u308B",
185
- dragHandle: "\u4E26\u3079\u66FF\u3048"
196
+ var FALLBACK_ACTION_LABELS = {
197
+ moveUp: "Move up",
198
+ moveDown: "Move down",
199
+ delete: "Delete",
200
+ add: "Add",
201
+ edit: "Edit",
202
+ settings: "Settings",
203
+ translate: "Translate",
204
+ close: "Close",
205
+ dragHandle: "Reorder"
186
206
  };
187
207
  function createMuiIconButtonAdapter(options) {
188
208
  const resolved = resolveMuiAdapterOptions(options);
@@ -199,7 +219,7 @@ function createMuiIconButtonAdapter(options) {
199
219
  actionType,
200
220
  title
201
221
  }) {
202
- const actionLabel = actionType === void 0 ? "\u64CD\u4F5C" : ACTION_LABELS[actionType];
222
+ const actionLabel = actionType === void 0 ? "Action" : resolved.getActionLabel?.(actionType) ?? FALLBACK_ACTION_LABELS[actionType];
203
223
  const tooltip = title ?? actionLabel;
204
224
  const color = actionType === "delete" ? "error" : actionType === "add" ? "primary" : "default";
205
225
  return /* @__PURE__ */ jsx5(Tooltip, { title: tooltip, children: /* @__PURE__ */ jsx5("span", { children: /* @__PURE__ */ jsx5(
@@ -240,13 +260,14 @@ function createMuiSectionAdapter(options) {
240
260
  return /* @__PURE__ */ jsxs3(
241
261
  Paper,
242
262
  {
263
+ ...resolved.muiSlotProps?.paper,
243
264
  id,
244
265
  className,
245
266
  elevation: 0,
246
267
  "aria-label": ariaLabel,
247
268
  "aria-labelledby": title === void 0 ? void 0 : headingId,
248
269
  onClickCapture,
249
- sx: {
270
+ sx: resolved.muiSlotProps?.paper?.sx ?? {
250
271
  p: resolved.dense ? 1.5 : 2,
251
272
  mb: resolved.dense ? 1 : 2,
252
273
  border: 1,
@@ -534,21 +555,22 @@ function createMuiOptionEditorSlot(options) {
534
555
  currentLocale,
535
556
  readOnly,
536
557
  actions,
537
- components
558
+ components,
559
+ translate
538
560
  }) {
539
561
  const { IconButton: IconButton2, TextInput } = components;
540
562
  const describedBy = option.label.trim().length === 0 ? `mui-option-${option.id}-error` : void 0;
541
- return /* @__PURE__ */ jsxs5(Stack, { "data-mui-slot": "option-editor", spacing: resolved.dense ? 0.75 : 1, children: [
563
+ return /* @__PURE__ */ jsxs5(Stack, { ...resolved.muiSlotProps?.stack, "data-mui-slot": "option-editor", spacing: resolved.dense ? 0.75 : 1, children: [
542
564
  /* @__PURE__ */ jsxs5(Stack, { direction: { xs: "column", sm: "row" }, spacing: 1, alignItems: { sm: "flex-start" }, children: [
543
565
  /* @__PURE__ */ jsx11(
544
566
  TextInput,
545
567
  {
546
568
  id: `mui-option-${option.id}`,
547
- label: `Option ${index + 1}`,
569
+ label: translate("builder.optionLabel", { index: index + 1 }),
548
570
  value: option.label,
549
571
  required: true,
550
572
  error: option.label.trim().length === 0,
551
- helperText: option.label.trim().length === 0 ? "Required" : "",
573
+ helperText: option.label.trim().length === 0 ? translate("builder.required") : "",
552
574
  "aria-describedby": describedBy,
553
575
  disabled: readOnly,
554
576
  onChange: (value) => actions.updateOption(field.id, option.id, (current) => ({ ...current, label: value }))
@@ -559,7 +581,7 @@ function createMuiOptionEditorSlot(options) {
559
581
  IconButton2,
560
582
  {
561
583
  actionType: "moveUp",
562
- title: `Move ${option.label} up`,
584
+ title: translate("builder.moveUp", { title: option.label }),
563
585
  disabled: readOnly || index === 0,
564
586
  onClick: () => actions.moveOption(field.id, option.id, index - 1)
565
587
  }
@@ -568,7 +590,7 @@ function createMuiOptionEditorSlot(options) {
568
590
  IconButton2,
569
591
  {
570
592
  actionType: "moveDown",
571
- title: `Move ${option.label} down`,
593
+ title: translate("builder.moveDown", { title: option.label }),
572
594
  disabled: readOnly || index === field.options.length - 1,
573
595
  onClick: () => actions.moveOption(field.id, option.id, index + 1)
574
596
  }
@@ -577,7 +599,7 @@ function createMuiOptionEditorSlot(options) {
577
599
  IconButton2,
578
600
  {
579
601
  actionType: "delete",
580
- title: `Delete ${option.label}`,
602
+ title: translate("builder.delete", { title: option.label }),
581
603
  disabled: readOnly || field.options.length <= 1,
582
604
  onClick: () => actions.removeOption(field.id, option.id)
583
605
  }
@@ -588,7 +610,9 @@ function createMuiOptionEditorSlot(options) {
588
610
  TextInput,
589
611
  {
590
612
  id: `mui-option-${option.id}-${currentLocale}`,
591
- label: `${currentLocale} translation`,
613
+ label: translate("builder.translation", {
614
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
615
+ }),
592
616
  value: option.translations?.[currentLocale] ?? "",
593
617
  disabled: readOnly,
594
618
  onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
@@ -613,23 +637,25 @@ function createMuiToolbarSlot(options) {
613
637
  onMoveDown,
614
638
  onRemove,
615
639
  readOnly,
616
- components
640
+ components,
641
+ translate
617
642
  }) {
618
643
  const { IconButton: IconButton2 } = components;
619
644
  return /* @__PURE__ */ jsxs6(
620
645
  Stack2,
621
646
  {
647
+ ...resolved.muiSlotProps?.stack,
622
648
  "data-mui-slot": "toolbar",
623
649
  direction: "row",
624
650
  spacing: resolved.dense ? 0.5 : 1,
625
651
  alignItems: "center",
626
- sx: { mb: resolved.dense ? 1 : 2 },
652
+ sx: resolved.muiSlotProps?.stack?.sx ?? { mb: resolved.dense ? 1 : 2 },
627
653
  children: [
628
654
  /* @__PURE__ */ jsx12(
629
655
  IconButton2,
630
656
  {
631
657
  actionType: "moveUp",
632
- title: `Move ${title} up`,
658
+ title: translate("builder.moveUp", { title }),
633
659
  disabled: readOnly || index === 0,
634
660
  onClick: onMoveUp
635
661
  }
@@ -638,7 +664,7 @@ function createMuiToolbarSlot(options) {
638
664
  IconButton2,
639
665
  {
640
666
  actionType: "moveDown",
641
- title: `Move ${title} down`,
667
+ title: translate("builder.moveDown", { title }),
642
668
  disabled: readOnly || index === total - 1,
643
669
  onClick: onMoveDown
644
670
  }
@@ -647,7 +673,7 @@ function createMuiToolbarSlot(options) {
647
673
  IconButton2,
648
674
  {
649
675
  actionType: "delete",
650
- title: `Delete ${title}`,
676
+ title: translate("builder.delete", { title }),
651
677
  disabled: readOnly || kind !== "page" && total <= 1,
652
678
  onClick: onRemove
653
679
  }
@@ -660,7 +686,7 @@ function createMuiToolbarSlot(options) {
660
686
  var MuiToolbarSlot = createMuiToolbarSlot();
661
687
 
662
688
  // src/slots/FieldEditor.tsx
663
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
689
+ import { Fragment, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
664
690
  var FIELD_TYPES = [
665
691
  "text",
666
692
  "textarea",
@@ -674,6 +700,16 @@ var FIELD_TYPES = [
674
700
  function isFieldType(value) {
675
701
  return FIELD_TYPES.some((type) => type === value);
676
702
  }
703
+ function conditionOperators(field) {
704
+ if (field.type === "multi-select") return ["contains", "not_empty"];
705
+ if (field.type === "text" || field.type === "textarea") {
706
+ return ["equals", "not_equals", "contains", "not_empty"];
707
+ }
708
+ return ["equals", "not_equals", "not_empty"];
709
+ }
710
+ function isConditionOperator(value) {
711
+ return ["equals", "not_equals", "contains", "not_empty"].some((operator) => operator === value);
712
+ }
677
713
  function numericValue(value) {
678
714
  if (value.trim().length === 0) return void 0;
679
715
  const parsed = Number(value);
@@ -696,27 +732,32 @@ function createMuiFieldEditorSlot(options) {
696
732
  index,
697
733
  currentLocale,
698
734
  policy,
735
+ features,
699
736
  readOnly,
700
737
  actions,
701
- components
738
+ components,
739
+ translate
702
740
  }) {
703
741
  const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
704
742
  const allowedTypes = policy?.allowedFieldTypes ?? FIELD_TYPES;
705
743
  const pageId = schema.pages?.find((page) => page.questionIds.includes(field.id))?.id ?? "";
706
744
  const condition = field.displayCondition;
707
745
  const conditionSources = schema.fields.slice(0, index);
746
+ const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
708
747
  const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
709
748
  return /* @__PURE__ */ jsxs7(
710
749
  Card,
711
750
  {
751
+ ...resolved.muiSlotProps?.card,
712
752
  "data-mui-slot": "field-editor",
713
753
  variant: "outlined",
714
- sx: { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
754
+ sx: resolved.muiSlotProps?.card?.sx ?? { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
715
755
  children: [
716
756
  /* @__PURE__ */ jsx13(
717
757
  Toolbar,
718
758
  {
719
759
  schema,
760
+ translate,
720
761
  kind: "field",
721
762
  targetId: field.id,
722
763
  index,
@@ -730,7 +771,7 @@ function createMuiFieldEditorSlot(options) {
730
771
  components
731
772
  }
732
773
  ),
733
- /* @__PURE__ */ jsxs7(Stack3, { spacing: resolved.dense ? 1 : 2, children: [
774
+ /* @__PURE__ */ jsxs7(Stack3, { ...resolved.muiSlotProps?.stack, spacing: resolved.dense ? 1 : 2, children: [
734
775
  /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle1", fontWeight: "bold", children: field.title }),
735
776
  /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
736
777
  /* @__PURE__ */ jsx13(
@@ -738,11 +779,11 @@ function createMuiFieldEditorSlot(options) {
738
779
  {
739
780
  id: `mui-field-${field.id}-title`,
740
781
  name: `fields.${field.id}.title`,
741
- label: "Question title",
782
+ label: translate("builder.questionTitle"),
742
783
  value: field.title,
743
784
  required: true,
744
785
  error: field.title.trim().length === 0,
745
- helperText: field.title.trim().length === 0 ? "Required" : "",
786
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
746
787
  "aria-describedby": titleErrorId,
747
788
  disabled: readOnly,
748
789
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "title", value)
@@ -753,12 +794,11 @@ function createMuiFieldEditorSlot(options) {
753
794
  {
754
795
  id: `mui-field-${field.id}-type`,
755
796
  name: `fields.${field.id}.type`,
756
- label: "Type",
757
- value: field.type,
758
- options: FIELD_TYPES.map((type) => ({
797
+ label: translate("builder.type"),
798
+ value: allowedTypes.includes(field.type) ? field.type : "",
799
+ options: FIELD_TYPES.filter((type) => allowedTypes.includes(type)).map((type) => ({
759
800
  value: type,
760
- label: type,
761
- disabled: !allowedTypes.includes(type)
801
+ label: translate(`builder.fieldType.${type}`)
762
802
  })),
763
803
  disabled: readOnly,
764
804
  onChange: (value) => {
@@ -772,7 +812,7 @@ function createMuiFieldEditorSlot(options) {
772
812
  {
773
813
  id: `mui-field-${field.id}-description`,
774
814
  name: `fields.${field.id}.description`,
775
- label: "Description",
815
+ label: translate("builder.description"),
776
816
  value: field.description ?? "",
777
817
  rows: resolved.dense ? 2 : 3,
778
818
  disabled: readOnly,
@@ -784,20 +824,20 @@ function createMuiFieldEditorSlot(options) {
784
824
  {
785
825
  id: `mui-field-${field.id}-required`,
786
826
  name: `fields.${field.id}.required`,
787
- label: "Required",
827
+ label: translate("builder.required"),
788
828
  checked: field.required,
789
829
  disabled: readOnly,
790
830
  onChange: (checked) => actions.updateField(field.id, (current) => ({ ...current, required: checked }))
791
831
  }
792
832
  ),
793
- schema.pages === void 0 ? null : /* @__PURE__ */ jsx13(
833
+ features?.pages === false || schema.pages === void 0 ? null : /* @__PURE__ */ jsx13(
794
834
  Select2,
795
835
  {
796
836
  id: `mui-field-${field.id}-page`,
797
- label: "Page",
837
+ label: translate("builder.questionPage"),
798
838
  value: pageId,
799
839
  options: [
800
- { value: "", label: "Unassigned" },
840
+ { value: "", label: translate("builder.unassigned") },
801
841
  ...schema.pages.map((page) => ({ value: page.id, label: page.title ?? page.id }))
802
842
  ],
803
843
  disabled: readOnly,
@@ -809,7 +849,7 @@ function createMuiFieldEditorSlot(options) {
809
849
  TextInput,
810
850
  {
811
851
  id: `mui-field-${field.id}-minimum`,
812
- label: "Minimum",
852
+ label: translate("builder.minimum"),
813
853
  type: "number",
814
854
  value: field.min === void 0 ? "" : String(field.min),
815
855
  disabled: readOnly,
@@ -820,7 +860,7 @@ function createMuiFieldEditorSlot(options) {
820
860
  TextInput,
821
861
  {
822
862
  id: `mui-field-${field.id}-maximum`,
823
- label: "Maximum",
863
+ label: translate("builder.maximum"),
824
864
  type: "number",
825
865
  value: field.max === void 0 ? "" : String(field.max),
826
866
  disabled: readOnly,
@@ -828,15 +868,15 @@ function createMuiFieldEditorSlot(options) {
828
868
  }
829
869
  )
830
870
  ] }) : null,
831
- conditionSources.length === 0 ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
871
+ features?.conditions === false || conditionSources.length === 0 ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
832
872
  /* @__PURE__ */ jsx13(
833
873
  Select2,
834
874
  {
835
875
  id: `mui-field-${field.id}-condition-source`,
836
- label: "Display condition",
876
+ label: translate("builder.displayCondition"),
837
877
  value: condition?.questionId ?? "",
838
878
  options: [
839
- { value: "", label: "Always visible" },
879
+ { value: "", label: translate("builder.alwaysVisible") },
840
880
  ...conditionSources.map((source) => ({ value: source.id, label: source.title }))
841
881
  ],
842
882
  disabled: readOnly,
@@ -846,27 +886,47 @@ function createMuiFieldEditorSlot(options) {
846
886
  )
847
887
  }
848
888
  ),
849
- condition === void 0 ? null : /* @__PURE__ */ jsx13(
850
- TextInput,
851
- {
852
- id: `mui-field-${field.id}-condition-value`,
853
- label: "Condition value",
854
- value: condition.value === void 0 ? "" : String(condition.value),
855
- disabled: readOnly,
856
- onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
857
- }
858
- )
889
+ condition === void 0 ? null : /* @__PURE__ */ jsxs7(Fragment, { children: [
890
+ /* @__PURE__ */ jsx13(
891
+ Select2,
892
+ {
893
+ id: `mui-field-${field.id}-condition-operator`,
894
+ label: translate("builder.conditionOperator"),
895
+ value: condition.operator,
896
+ options: (conditionSource === void 0 ? [] : conditionOperators(conditionSource)).map(
897
+ (operator) => ({ value: operator, label: translate(`builder.operator.${operator}`) })
898
+ ),
899
+ disabled: readOnly,
900
+ onChange: (value) => {
901
+ if (!isConditionOperator(value)) return;
902
+ actions.setDisplayCondition(
903
+ field.id,
904
+ value === "not_empty" ? { questionId: condition.questionId, operator: value } : { ...condition, operator: value, value: condition.value ?? "" }
905
+ );
906
+ }
907
+ }
908
+ ),
909
+ condition.operator === "not_empty" ? null : /* @__PURE__ */ jsx13(
910
+ TextInput,
911
+ {
912
+ id: `mui-field-${field.id}-condition-value`,
913
+ label: translate("builder.conditionValue"),
914
+ value: condition.value === void 0 ? "" : String(condition.value),
915
+ disabled: readOnly,
916
+ onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
917
+ }
918
+ )
919
+ ] })
859
920
  ] }),
860
921
  currentLocale.length === 0 ? null : /* @__PURE__ */ jsxs7(Stack3, { spacing: resolved.dense ? 1 : 2, children: [
861
- /* @__PURE__ */ jsxs7(Typography3, { variant: "subtitle2", children: [
862
- currentLocale,
863
- " translation"
864
- ] }),
922
+ /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.translation", {
923
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
924
+ }) }),
865
925
  /* @__PURE__ */ jsx13(
866
926
  TextInput,
867
927
  {
868
928
  id: `mui-field-${field.id}-${currentLocale}-title`,
869
- label: "Translated question title",
929
+ label: translate("builder.translatedQuestionTitle"),
870
930
  value: field.translations?.[currentLocale]?.title ?? "",
871
931
  disabled: readOnly,
872
932
  onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
@@ -876,7 +936,7 @@ function createMuiFieldEditorSlot(options) {
876
936
  TextArea,
877
937
  {
878
938
  id: `mui-field-${field.id}-${currentLocale}-description`,
879
- label: "Translated description",
939
+ label: translate("builder.translatedDescription"),
880
940
  value: field.translations?.[currentLocale]?.description ?? "",
881
941
  disabled: readOnly,
882
942
  onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
@@ -884,7 +944,7 @@ function createMuiFieldEditorSlot(options) {
884
944
  )
885
945
  ] }),
886
946
  "options" in field ? /* @__PURE__ */ jsxs7(Stack3, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
887
- /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: "Options" }),
947
+ /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.options") }),
888
948
  field.options.map((option, optionIndex) => /* @__PURE__ */ jsx13(
889
949
  OptionEditor,
890
950
  {
@@ -893,6 +953,7 @@ function createMuiFieldEditorSlot(options) {
893
953
  option,
894
954
  index: optionIndex,
895
955
  currentLocale,
956
+ translate,
896
957
  readOnly,
897
958
  actions,
898
959
  components
@@ -906,7 +967,7 @@ function createMuiFieldEditorSlot(options) {
906
967
  targetId: field.id,
907
968
  disabled: readOnly || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
908
969
  onClick: () => actions.addOption(field.id),
909
- children: "Add option"
970
+ children: translate("builder.addOption")
910
971
  }
911
972
  )
912
973
  ] }) : null
@@ -919,7 +980,8 @@ function createMuiFieldEditorSlot(options) {
919
980
  var MuiFieldEditorSlot = createMuiFieldEditorSlot();
920
981
 
921
982
  // src/slots/Localization.tsx
922
- import { Box as Box2, Stack as Stack4, Tab, Tabs, Typography as Typography4 } from "@mui/material";
983
+ import { ExpandMore } from "@mui/icons-material";
984
+ import { Accordion, AccordionDetails, AccordionSummary, Box as Box2, Stack as Stack4, Tab, Tabs, Typography as Typography4 } from "@mui/material";
923
985
  import { useState } from "react";
924
986
  import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
925
987
  function createMuiLocalizationSlot(options) {
@@ -931,27 +993,152 @@ function createMuiLocalizationSlot(options) {
931
993
  onAutoTranslate,
932
994
  isTranslating,
933
995
  translationError,
996
+ policy,
997
+ translationAdapterAvailable,
934
998
  readOnly,
935
999
  actions,
936
- components
1000
+ components,
1001
+ translate
937
1002
  }) {
938
- const { Button: Button2, ErrorMessage, TextArea, TextInput } = components;
1003
+ const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
939
1004
  const [newLocale, setNewLocale] = useState("");
940
1005
  const locales = Array.from(
941
- /* @__PURE__ */ new Set([
942
- ...schema.supportedLocales ?? [],
943
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale]
944
- ])
1006
+ new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
945
1007
  );
1008
+ const editingLocaleConfigured = locales.includes(currentLocale);
1009
+ const registeredLocales = /* @__PURE__ */ new Set([
1010
+ ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
1011
+ ...schema.supportedLocales ?? []
1012
+ ]);
1013
+ const availableAllowedLocales = policy?.allowedLocales?.filter((locale) => !registeredLocales.has(locale));
1014
+ const localeLimitReached = policy?.maxLocales !== void 0 && registeredLocales.size >= policy.maxLocales;
1015
+ const normalizedLocale = newLocale.trim();
1016
+ const localeAllowed = policy?.allowedLocales === void 0 || policy.allowedLocales.includes(normalizedLocale);
1017
+ const canAddLocale = !readOnly && normalizedLocale.length > 0 && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
946
1018
  const handleTabChange = (_event, value) => onCurrentLocaleChange(value);
947
1019
  const addLocale = () => {
948
- const normalized = newLocale.trim();
949
- if (normalized.length === 0) return;
950
- const result = actions.addLocale(normalized);
1020
+ if (!canAddLocale) return;
1021
+ const result = actions.addLocale(normalizedLocale);
951
1022
  if (!result.success) return;
952
- onCurrentLocaleChange(normalized);
1023
+ onCurrentLocaleChange(normalizedLocale);
953
1024
  setNewLocale("");
954
1025
  };
1026
+ const stackProps = resolved.muiSlotProps?.stack;
1027
+ const collapsible = resolved.localizationOptions?.collapsible ?? false;
1028
+ const content = /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1029
+ !collapsible ? /* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) : null,
1030
+ /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
1031
+ /* @__PURE__ */ jsx14(
1032
+ TextInput,
1033
+ {
1034
+ id: "mui-builder-default-locale",
1035
+ label: translate("builder.defaultLocale"),
1036
+ value: schema.defaultLocale ?? "",
1037
+ disabled: readOnly,
1038
+ onChange: (value) => {
1039
+ const result = actions.setDefaultLocale(value);
1040
+ if (result.success && value === currentLocale) onCurrentLocaleChange("");
1041
+ }
1042
+ }
1043
+ ),
1044
+ availableAllowedLocales === void 0 ? /* @__PURE__ */ jsx14(
1045
+ TextInput,
1046
+ {
1047
+ id: "mui-builder-new-locale",
1048
+ label: translate("builder.addLocale"),
1049
+ value: newLocale,
1050
+ disabled: readOnly || localeLimitReached,
1051
+ onChange: setNewLocale
1052
+ }
1053
+ ) : /* @__PURE__ */ jsx14(
1054
+ Select2,
1055
+ {
1056
+ id: "mui-builder-new-locale",
1057
+ label: translate("builder.addLocale"),
1058
+ value: newLocale,
1059
+ options: [
1060
+ { value: "", label: "\u2014" },
1061
+ ...availableAllowedLocales.map((locale) => ({
1062
+ value: locale,
1063
+ label: resolved.getLocaleLabel?.(locale) ?? locale
1064
+ }))
1065
+ ],
1066
+ disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
1067
+ onChange: setNewLocale
1068
+ }
1069
+ ),
1070
+ /* @__PURE__ */ jsx14(Button2, { variant: "primary", action: "addLocale", disabled: !canAddLocale, onClick: addLocale, children: translate("builder.addLocale") })
1071
+ ] }),
1072
+ locales.length === 0 ? null : /* @__PURE__ */ jsx14(
1073
+ Tabs,
1074
+ {
1075
+ value: editingLocaleConfigured ? currentLocale : false,
1076
+ onChange: handleTabChange,
1077
+ variant: "scrollable",
1078
+ scrollButtons: "auto",
1079
+ "aria-label": translate("builder.translationLocale"),
1080
+ children: locales.map((locale) => /* @__PURE__ */ jsx14(
1081
+ Tab,
1082
+ {
1083
+ value: locale,
1084
+ label: resolved.getLocaleLabel?.(locale) ?? locale,
1085
+ disabled: readOnly && locale !== currentLocale
1086
+ },
1087
+ locale
1088
+ ))
1089
+ }
1090
+ ),
1091
+ !translationAdapterAvailable ? null : /* @__PURE__ */ jsx14(
1092
+ Button2,
1093
+ {
1094
+ variant: "secondary",
1095
+ disabled: readOnly || !editingLocaleConfigured || isTranslating,
1096
+ onClick: onAutoTranslate,
1097
+ children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
1098
+ }
1099
+ ),
1100
+ translationError === void 0 ? null : /* @__PURE__ */ jsx14(ErrorMessage, { message: translationError }),
1101
+ !editingLocaleConfigured ? /* @__PURE__ */ jsx14(Typography4, { variant: "body2", color: "text.secondary", children: translate("builder.selectLocale") }) : /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1102
+ /* @__PURE__ */ jsx14(
1103
+ TextInput,
1104
+ {
1105
+ id: `mui-builder-${currentLocale}-form-title`,
1106
+ label: translate("builder.translatedFormTitle"),
1107
+ value: schema.translations?.[currentLocale]?.title ?? "",
1108
+ disabled: readOnly,
1109
+ onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "title", value)
1110
+ }
1111
+ ),
1112
+ /* @__PURE__ */ jsx14(
1113
+ TextArea,
1114
+ {
1115
+ id: `mui-builder-${currentLocale}-form-description`,
1116
+ label: translate("builder.translatedFormDescription"),
1117
+ value: schema.translations?.[currentLocale]?.description ?? "",
1118
+ disabled: readOnly,
1119
+ onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "description", value)
1120
+ }
1121
+ ),
1122
+ /* @__PURE__ */ jsx14(
1123
+ TextInput,
1124
+ {
1125
+ id: `mui-builder-${currentLocale}-completion-message`,
1126
+ label: translate("builder.translatedCompletionMessage"),
1127
+ value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1128
+ disabled: readOnly,
1129
+ onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1130
+ }
1131
+ )
1132
+ ] })
1133
+ ] });
1134
+ const configured = locales.length > 0;
1135
+ const defaultExpanded = resolved.localizationOptions?.defaultExpanded === "when-configured" ? configured : resolved.localizationOptions?.defaultExpanded ?? false;
1136
+ if (collapsible) {
1137
+ return /* @__PURE__ */ jsxs8(Accordion, { ...resolved.muiSlotProps?.accordion, "data-mui-slot": "localization", defaultExpanded, children: [
1138
+ /* @__PURE__ */ jsx14(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx14(ExpandMore, {}), children: /* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) }),
1139
+ /* @__PURE__ */ jsx14(AccordionDetails, { children: content })
1140
+ ] });
1141
+ }
955
1142
  return /* @__PURE__ */ jsx14(
956
1143
  Box2,
957
1144
  {
@@ -963,95 +1150,7 @@ function createMuiLocalizationSlot(options) {
963
1150
  borderColor: "divider",
964
1151
  borderRadius: 1
965
1152
  },
966
- children: /* @__PURE__ */ jsxs8(Stack4, { spacing: resolved.dense ? 1 : 2, children: [
967
- /* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: "Localization" }),
968
- /* @__PURE__ */ jsx14(
969
- TextInput,
970
- {
971
- id: "mui-builder-completion-message",
972
- label: "Completion message",
973
- value: schema.completionMessage ?? "",
974
- disabled: readOnly,
975
- onChange: (value) => actions.setSourceText({ kind: "form" }, "completionMessage", value)
976
- }
977
- ),
978
- /* @__PURE__ */ jsxs8(Stack4, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
979
- /* @__PURE__ */ jsx14(
980
- TextInput,
981
- {
982
- id: "mui-builder-default-locale",
983
- label: "Default locale",
984
- value: schema.defaultLocale ?? "",
985
- disabled: readOnly,
986
- onChange: (value) => actions.setDefaultLocale(value)
987
- }
988
- ),
989
- /* @__PURE__ */ jsx14(
990
- TextInput,
991
- {
992
- id: "mui-builder-new-locale",
993
- label: "Add locale",
994
- value: newLocale,
995
- disabled: readOnly,
996
- onChange: setNewLocale
997
- }
998
- ),
999
- /* @__PURE__ */ jsx14(Button2, { disabled: readOnly || newLocale.trim().length === 0, onClick: addLocale, children: "Add locale" })
1000
- ] }),
1001
- locales.length === 0 ? null : /* @__PURE__ */ jsx14(
1002
- Tabs,
1003
- {
1004
- value: locales.includes(currentLocale) ? currentLocale : false,
1005
- onChange: handleTabChange,
1006
- variant: "scrollable",
1007
- scrollButtons: "auto",
1008
- "aria-label": "Translation locale",
1009
- children: locales.map((locale) => /* @__PURE__ */ jsx14(Tab, { value: locale, label: locale, disabled: readOnly && locale !== currentLocale }, locale))
1010
- }
1011
- ),
1012
- /* @__PURE__ */ jsx14(
1013
- Button2,
1014
- {
1015
- variant: "secondary",
1016
- disabled: readOnly || currentLocale.length === 0 || isTranslating,
1017
- onClick: onAutoTranslate,
1018
- children: isTranslating ? "Translating\u2026" : "Translate all text"
1019
- }
1020
- ),
1021
- translationError === void 0 ? null : /* @__PURE__ */ jsx14(ErrorMessage, { message: translationError }),
1022
- currentLocale.length === 0 ? /* @__PURE__ */ jsx14(Typography4, { variant: "body2", color: "text.secondary", children: "Select a locale to edit translations." }) : /* @__PURE__ */ jsxs8(Stack4, { spacing: resolved.dense ? 1 : 2, children: [
1023
- /* @__PURE__ */ jsx14(
1024
- TextInput,
1025
- {
1026
- id: `mui-builder-${currentLocale}-form-title`,
1027
- label: "Translated form title",
1028
- value: schema.translations?.[currentLocale]?.title ?? "",
1029
- disabled: readOnly,
1030
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "title", value)
1031
- }
1032
- ),
1033
- /* @__PURE__ */ jsx14(
1034
- TextArea,
1035
- {
1036
- id: `mui-builder-${currentLocale}-form-description`,
1037
- label: "Translated form description",
1038
- value: schema.translations?.[currentLocale]?.description ?? "",
1039
- disabled: readOnly,
1040
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "description", value)
1041
- }
1042
- ),
1043
- /* @__PURE__ */ jsx14(
1044
- TextInput,
1045
- {
1046
- id: `mui-builder-${currentLocale}-completion-message`,
1047
- label: "Translated completion message",
1048
- value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1049
- disabled: readOnly,
1050
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1051
- }
1052
- )
1053
- ] })
1054
- ] })
1153
+ children: content
1055
1154
  }
1056
1155
  );
1057
1156
  };
@@ -1060,6 +1159,7 @@ var MuiLocalizationSlot = createMuiLocalizationSlot();
1060
1159
 
1061
1160
  // src/slots/index.ts
1062
1161
  var muiBuilderSlots = {
1162
+ sectionOrder: DEFAULT_MUI_SECTION_ORDER,
1063
1163
  toolbar: createMuiToolbarSlot(),
1064
1164
  fieldEditor: createMuiFieldEditorSlot(),
1065
1165
  optionEditor: createMuiOptionEditorSlot(),
@@ -1067,6 +1167,7 @@ var muiBuilderSlots = {
1067
1167
  };
1068
1168
  function createMuiBuilderSlots(options, customOverrides = {}) {
1069
1169
  return {
1170
+ sectionOrder: options?.layoutOptions?.sectionOrder ?? DEFAULT_MUI_SECTION_ORDER,
1070
1171
  toolbar: createMuiToolbarSlot(options),
1071
1172
  fieldEditor: createMuiFieldEditorSlot(options),
1072
1173
  optionEditor: createMuiOptionEditorSlot(options),
@@ -1092,18 +1193,34 @@ import { useMemo } from "react";
1092
1193
  import { jsx as jsx15 } from "react/jsx-runtime";
1093
1194
  function MuiFormBuilder({
1094
1195
  muiOptions,
1196
+ layoutOptions,
1197
+ localizationOptions,
1198
+ muiSlotProps,
1095
1199
  components: customComponents,
1096
1200
  slots: customSlots,
1097
1201
  ...props
1098
1202
  }) {
1203
+ const resolvedMuiOptions = useMemo(
1204
+ () => ({
1205
+ ...muiOptions,
1206
+ ...layoutOptions === void 0 ? {} : { layoutOptions },
1207
+ ...localizationOptions === void 0 ? {} : { localizationOptions },
1208
+ ...muiSlotProps === void 0 ? {} : { muiSlotProps }
1209
+ }),
1210
+ [layoutOptions, localizationOptions, muiOptions, muiSlotProps]
1211
+ );
1099
1212
  const components = useMemo(
1100
- () => createMuiBuilderComponents(muiOptions, customComponents),
1101
- [muiOptions, customComponents]
1213
+ () => createMuiBuilderComponents(resolvedMuiOptions, customComponents),
1214
+ [resolvedMuiOptions, customComponents]
1215
+ );
1216
+ const slots = useMemo(
1217
+ () => createMuiBuilderSlots(resolvedMuiOptions, customSlots),
1218
+ [resolvedMuiOptions, customSlots]
1102
1219
  );
1103
- const slots = useMemo(() => createMuiBuilderSlots(muiOptions, customSlots), [muiOptions, customSlots]);
1104
1220
  return /* @__PURE__ */ jsx15(FormBuilder, { ...props, components, disableDefaultStyles: true, slots });
1105
1221
  }
1106
1222
  export {
1223
+ DEFAULT_MUI_SECTION_ORDER,
1107
1224
  MuiButtonAdapter,
1108
1225
  MuiCheckboxAdapter,
1109
1226
  MuiErrorMessageAdapter,