@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.js CHANGED
@@ -1,21 +1,69 @@
1
1
  // src/adapters/Button.tsx
2
2
  import { Button } from "@mui/material";
3
3
 
4
+ // src/context.ts
5
+ import { createContext, useContext } from "react";
6
+
4
7
  // src/types.ts
8
+ var DEFAULT_MUI_SECTION_ORDER = [
9
+ "basicSettings",
10
+ "questions",
11
+ "addQuestion",
12
+ "localization"
13
+ ];
5
14
  function resolveMuiAdapterOptions(options = {}) {
15
+ const buttonVariant = options.buttonVariant ?? "contained";
6
16
  return {
7
17
  size: options.size ?? "medium",
8
18
  variant: options.variant ?? "outlined",
9
- buttonVariant: options.buttonVariant ?? "contained",
19
+ buttonVariant,
20
+ buttonVariants: {
21
+ primary: options.buttonVariants?.primary ?? buttonVariant,
22
+ secondary: options.buttonVariants?.secondary ?? buttonVariant,
23
+ danger: options.buttonVariants?.danger ?? buttonVariant
24
+ },
10
25
  fullWidth: options.fullWidth ?? true,
11
- dense: options.dense ?? false
26
+ inputFullWidth: options.inputFullWidth ?? options.fullWidth ?? true,
27
+ buttonFullWidth: options.buttonFullWidth ?? options.fullWidth ?? false,
28
+ dense: options.dense ?? false,
29
+ getLocaleLabel: options.getLocaleLabel ?? ((locale) => locale),
30
+ ...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
31
+ layoutOptions: options.layoutOptions ?? {},
32
+ fieldEditorOptions: {
33
+ description: options.fieldEditorOptions?.description ?? "editable"
34
+ },
35
+ localizationOptions: {
36
+ collapsible: options.localizationOptions?.collapsible ?? false,
37
+ defaultExpanded: options.localizationOptions?.defaultExpanded ?? false,
38
+ defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable"
39
+ },
40
+ muiSlotProps: options.muiSlotProps ?? {}
41
+ };
42
+ }
43
+
44
+ // src/context.ts
45
+ var MuiFormBuilderContext = createContext({ options: {} });
46
+ function mergeMuiAdapterOptions(base = {}, overrides = {}) {
47
+ return {
48
+ ...base,
49
+ ...overrides,
50
+ ...base.buttonVariants === void 0 && overrides.buttonVariants === void 0 ? {} : { buttonVariants: { ...base.buttonVariants, ...overrides.buttonVariants } },
51
+ ...base.layoutOptions === void 0 && overrides.layoutOptions === void 0 ? {} : { layoutOptions: { ...base.layoutOptions, ...overrides.layoutOptions } },
52
+ ...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : { fieldEditorOptions: { ...base.fieldEditorOptions, ...overrides.fieldEditorOptions } },
53
+ ...base.localizationOptions === void 0 && overrides.localizationOptions === void 0 ? {} : { localizationOptions: { ...base.localizationOptions, ...overrides.localizationOptions } },
54
+ ...base.muiSlotProps === void 0 && overrides.muiSlotProps === void 0 ? {} : { muiSlotProps: { ...base.muiSlotProps, ...overrides.muiSlotProps } }
12
55
  };
13
56
  }
57
+ function useResolvedMuiAdapterOptions(overrides) {
58
+ const context = useContext(MuiFormBuilderContext);
59
+ return resolveMuiAdapterOptions(
60
+ overrides === void 0 ? context.options : mergeMuiAdapterOptions(context.options, overrides)
61
+ );
62
+ }
14
63
 
15
64
  // src/adapters/Button.tsx
16
65
  import { jsx } from "react/jsx-runtime";
17
66
  function createMuiButtonAdapter(options) {
18
- const resolved = resolveMuiAdapterOptions(options);
19
67
  return function MuiButton({
20
68
  id,
21
69
  className,
@@ -31,6 +79,7 @@ function createMuiButtonAdapter(options) {
31
79
  action,
32
80
  targetId
33
81
  }) {
82
+ const resolved = useResolvedMuiAdapterOptions(options);
34
83
  return /* @__PURE__ */ jsx(
35
84
  Button,
36
85
  {
@@ -47,8 +96,8 @@ function createMuiButtonAdapter(options) {
47
96
  "data-target-id": targetId,
48
97
  onClick,
49
98
  color: variant === "danger" ? "error" : "primary",
50
- variant: resolved.buttonVariant,
51
- fullWidth: resolved.fullWidth,
99
+ variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
100
+ fullWidth: resolved.buttonFullWidth ?? false,
52
101
  children
53
102
  }
54
103
  );
@@ -60,7 +109,6 @@ var MuiButtonAdapter = createMuiButtonAdapter();
60
109
  import { Checkbox, FormControl, FormControlLabel, FormHelperText } from "@mui/material";
61
110
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
62
111
  function createMuiCheckboxAdapter(options) {
63
- const resolved = resolveMuiAdapterOptions(options);
64
112
  return function MuiCheckbox({
65
113
  id,
66
114
  className,
@@ -77,6 +125,7 @@ function createMuiCheckboxAdapter(options) {
77
125
  onChange,
78
126
  label
79
127
  }) {
128
+ const resolved = useResolvedMuiAdapterOptions(options);
80
129
  return /* @__PURE__ */ jsxs(FormControl, { className, error: Boolean(error), required, disabled: disabled || readOnly, children: [
81
130
  /* @__PURE__ */ jsx2(
82
131
  FormControlLabel,
@@ -140,8 +189,8 @@ var MuiErrorMessageAdapter = createMuiErrorMessageAdapter();
140
189
  import { Box, Typography } from "@mui/material";
141
190
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
142
191
  function createMuiFieldsetAdapter(options) {
143
- const resolved = resolveMuiAdapterOptions(options);
144
192
  return function MuiFieldset({ className, legend, disabled, children }) {
193
+ const resolved = useResolvedMuiAdapterOptions(options);
145
194
  return /* @__PURE__ */ jsxs2(
146
195
  Box,
147
196
  {
@@ -173,19 +222,18 @@ var MuiFieldsetAdapter = createMuiFieldsetAdapter();
173
222
  // src/adapters/IconButton.tsx
174
223
  import { IconButton, Tooltip } from "@mui/material";
175
224
  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"
225
+ var FALLBACK_ACTION_LABELS = {
226
+ moveUp: "Move up",
227
+ moveDown: "Move down",
228
+ delete: "Delete",
229
+ add: "Add",
230
+ edit: "Edit",
231
+ settings: "Settings",
232
+ translate: "Translate",
233
+ close: "Close",
234
+ dragHandle: "Reorder"
186
235
  };
187
236
  function createMuiIconButtonAdapter(options) {
188
- const resolved = resolveMuiAdapterOptions(options);
189
237
  return function MuiIconButton({
190
238
  id,
191
239
  className,
@@ -199,7 +247,8 @@ function createMuiIconButtonAdapter(options) {
199
247
  actionType,
200
248
  title
201
249
  }) {
202
- const actionLabel = actionType === void 0 ? "\u64CD\u4F5C" : ACTION_LABELS[actionType];
250
+ const resolved = useResolvedMuiAdapterOptions(options);
251
+ const actionLabel = actionType === void 0 ? "Action" : resolved.getActionLabel?.(actionType) ?? FALLBACK_ACTION_LABELS[actionType];
203
252
  const tooltip = title ?? actionLabel;
204
253
  const color = actionType === "delete" ? "error" : actionType === "add" ? "primary" : "default";
205
254
  return /* @__PURE__ */ jsx5(Tooltip, { title: tooltip, children: /* @__PURE__ */ jsx5("span", { children: /* @__PURE__ */ jsx5(
@@ -226,7 +275,6 @@ var MuiIconButtonAdapter = createMuiIconButtonAdapter();
226
275
  import { Paper, Typography as Typography2 } from "@mui/material";
227
276
  import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
228
277
  function createMuiSectionAdapter(options) {
229
- const resolved = resolveMuiAdapterOptions(options);
230
278
  return function MuiSection({
231
279
  id,
232
280
  className,
@@ -237,16 +285,18 @@ function createMuiSectionAdapter(options) {
237
285
  onClickCapture,
238
286
  children
239
287
  }) {
288
+ const resolved = useResolvedMuiAdapterOptions(options);
240
289
  return /* @__PURE__ */ jsxs3(
241
290
  Paper,
242
291
  {
292
+ ...resolved.muiSlotProps?.paper,
243
293
  id,
244
294
  className,
245
295
  elevation: 0,
246
296
  "aria-label": ariaLabel,
247
297
  "aria-labelledby": title === void 0 ? void 0 : headingId,
248
298
  onClickCapture,
249
- sx: {
299
+ sx: resolved.muiSlotProps?.paper?.sx ?? {
250
300
  p: resolved.dense ? 1.5 : 2,
251
301
  mb: resolved.dense ? 1 : 2,
252
302
  border: 1,
@@ -274,7 +324,6 @@ var MuiSectionAdapter = createMuiSectionAdapter();
274
324
  import { FormControl as FormControl2, FormHelperText as FormHelperText2, InputLabel, MenuItem, Select } from "@mui/material";
275
325
  import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
276
326
  function createMuiSelectAdapter(options) {
277
- const resolved = resolveMuiAdapterOptions(options);
278
327
  return function MuiSelect({
279
328
  id,
280
329
  className,
@@ -292,13 +341,14 @@ function createMuiSelectAdapter(options) {
292
341
  onChange,
293
342
  options: selectOptions
294
343
  }) {
344
+ const resolved = useResolvedMuiAdapterOptions(options);
295
345
  const labelId = id === void 0 || label === void 0 ? void 0 : `${id}-label`;
296
346
  const handleChange = (event) => onChange(event.target.value);
297
347
  return /* @__PURE__ */ jsxs4(
298
348
  FormControl2,
299
349
  {
300
350
  className,
301
- fullWidth: resolved.fullWidth,
351
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
302
352
  size: resolved.size,
303
353
  variant: resolved.variant,
304
354
  error: Boolean(error),
@@ -337,7 +387,6 @@ var MuiSelectAdapter = createMuiSelectAdapter();
337
387
  import { TextField } from "@mui/material";
338
388
  import { jsx as jsx8 } from "react/jsx-runtime";
339
389
  function createMuiTextAreaAdapter(options) {
340
- const resolved = resolveMuiAdapterOptions(options);
341
390
  return function MuiTextArea({
342
391
  id,
343
392
  className,
@@ -357,6 +406,7 @@ function createMuiTextAreaAdapter(options) {
357
406
  maxLength,
358
407
  rows
359
408
  }) {
409
+ const resolved = useResolvedMuiAdapterOptions(options);
360
410
  return /* @__PURE__ */ jsx8(
361
411
  TextField,
362
412
  {
@@ -372,6 +422,7 @@ function createMuiTextAreaAdapter(options) {
372
422
  slotProps: {
373
423
  htmlInput: {
374
424
  maxLength,
425
+ readOnly,
375
426
  "aria-label": ariaLabel,
376
427
  "aria-describedby": ariaDescribedBy,
377
428
  "aria-labelledby": ariaLabelledBy
@@ -382,7 +433,7 @@ function createMuiTextAreaAdapter(options) {
382
433
  multiline: true,
383
434
  rows,
384
435
  placeholder,
385
- fullWidth: resolved.fullWidth,
436
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
386
437
  size: resolved.size,
387
438
  variant: resolved.variant,
388
439
  onChange: (event) => onChange(event.currentTarget.value)
@@ -396,7 +447,6 @@ var MuiTextAreaAdapter = createMuiTextAreaAdapter();
396
447
  import { TextField as TextField2 } from "@mui/material";
397
448
  import { jsx as jsx9 } from "react/jsx-runtime";
398
449
  function createMuiTextInputAdapter(options) {
399
- const resolved = resolveMuiAdapterOptions(options);
400
450
  return function MuiTextInput({
401
451
  id,
402
452
  className,
@@ -420,6 +470,7 @@ function createMuiTextInputAdapter(options) {
420
470
  max,
421
471
  step
422
472
  }) {
473
+ const resolved = useResolvedMuiAdapterOptions(options);
423
474
  return /* @__PURE__ */ jsx9(
424
475
  TextField2,
425
476
  {
@@ -439,6 +490,7 @@ function createMuiTextInputAdapter(options) {
439
490
  max,
440
491
  step,
441
492
  inputMode,
493
+ readOnly,
442
494
  "aria-label": ariaLabel,
443
495
  "aria-describedby": ariaDescribedBy,
444
496
  "aria-labelledby": ariaLabelledBy
@@ -448,7 +500,7 @@ function createMuiTextInputAdapter(options) {
448
500
  },
449
501
  type,
450
502
  placeholder,
451
- fullWidth: resolved.fullWidth,
503
+ fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
452
504
  size: resolved.size,
453
505
  variant: resolved.variant,
454
506
  onChange: (event) => onChange(event.currentTarget.value)
@@ -496,7 +548,7 @@ function muiDefaultIconResolver(actionType) {
496
548
 
497
549
  // src/components.ts
498
550
  function isAdapterOptions(value) {
499
- return "size" in value || "variant" in value || "buttonVariant" in value || "fullWidth" in value || "dense" in value;
551
+ 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;
500
552
  }
501
553
  function buildMuiBuilderComponents(options) {
502
554
  return {
@@ -512,11 +564,22 @@ function buildMuiBuilderComponents(options) {
512
564
  renderIcon: muiDefaultIconResolver
513
565
  };
514
566
  }
515
- var muiBuilderComponents = buildMuiBuilderComponents();
567
+ var muiBuilderComponents = {
568
+ Button: MuiButtonAdapter,
569
+ IconButton: MuiIconButtonAdapter,
570
+ TextInput: MuiTextInputAdapter,
571
+ TextArea: MuiTextAreaAdapter,
572
+ Select: MuiSelectAdapter,
573
+ Checkbox: MuiCheckboxAdapter,
574
+ Section: MuiSectionAdapter,
575
+ Fieldset: MuiFieldsetAdapter,
576
+ ErrorMessage: MuiErrorMessageAdapter,
577
+ renderIcon: muiDefaultIconResolver
578
+ };
516
579
  function createMuiBuilderComponents(optionsOrOverrides = {}, customOverrides) {
517
580
  const options = isAdapterOptions(optionsOrOverrides) ? optionsOrOverrides : void 0;
518
581
  const overrides = customOverrides ?? (options === void 0 ? optionsOrOverrides : {});
519
- return { ...buildMuiBuilderComponents(options), ...overrides };
582
+ return { ...options === void 0 ? muiBuilderComponents : buildMuiBuilderComponents(options), ...overrides };
520
583
  }
521
584
 
522
585
  // src/slots/FieldEditor.tsx
@@ -526,7 +589,6 @@ import { Card, Stack as Stack3, Typography as Typography3 } from "@mui/material"
526
589
  import { Stack } from "@mui/material";
527
590
  import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
528
591
  function createMuiOptionEditorSlot(options) {
529
- const resolved = resolveMuiAdapterOptions(options);
530
592
  return function MuiOptionEditor({
531
593
  field,
532
594
  option,
@@ -534,21 +596,23 @@ function createMuiOptionEditorSlot(options) {
534
596
  currentLocale,
535
597
  readOnly,
536
598
  actions,
537
- components
599
+ components,
600
+ translate
538
601
  }) {
602
+ const resolved = useResolvedMuiAdapterOptions(options);
539
603
  const { IconButton: IconButton2, TextInput } = components;
540
604
  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: [
605
+ return /* @__PURE__ */ jsxs5(Stack, { ...resolved.muiSlotProps?.stack, "data-mui-slot": "option-editor", spacing: resolved.dense ? 0.75 : 1, children: [
542
606
  /* @__PURE__ */ jsxs5(Stack, { direction: { xs: "column", sm: "row" }, spacing: 1, alignItems: { sm: "flex-start" }, children: [
543
607
  /* @__PURE__ */ jsx11(
544
608
  TextInput,
545
609
  {
546
610
  id: `mui-option-${option.id}`,
547
- label: `Option ${index + 1}`,
611
+ label: translate("builder.optionLabel", { index: index + 1 }),
548
612
  value: option.label,
549
613
  required: true,
550
614
  error: option.label.trim().length === 0,
551
- helperText: option.label.trim().length === 0 ? "Required" : "",
615
+ helperText: option.label.trim().length === 0 ? translate("builder.required") : "",
552
616
  "aria-describedby": describedBy,
553
617
  disabled: readOnly,
554
618
  onChange: (value) => actions.updateOption(field.id, option.id, (current) => ({ ...current, label: value }))
@@ -559,7 +623,7 @@ function createMuiOptionEditorSlot(options) {
559
623
  IconButton2,
560
624
  {
561
625
  actionType: "moveUp",
562
- title: `Move ${option.label} up`,
626
+ title: translate("builder.moveUp", { title: option.label }),
563
627
  disabled: readOnly || index === 0,
564
628
  onClick: () => actions.moveOption(field.id, option.id, index - 1)
565
629
  }
@@ -568,7 +632,7 @@ function createMuiOptionEditorSlot(options) {
568
632
  IconButton2,
569
633
  {
570
634
  actionType: "moveDown",
571
- title: `Move ${option.label} down`,
635
+ title: translate("builder.moveDown", { title: option.label }),
572
636
  disabled: readOnly || index === field.options.length - 1,
573
637
  onClick: () => actions.moveOption(field.id, option.id, index + 1)
574
638
  }
@@ -577,7 +641,7 @@ function createMuiOptionEditorSlot(options) {
577
641
  IconButton2,
578
642
  {
579
643
  actionType: "delete",
580
- title: `Delete ${option.label}`,
644
+ title: translate("builder.delete", { title: option.label }),
581
645
  disabled: readOnly || field.options.length <= 1,
582
646
  onClick: () => actions.removeOption(field.id, option.id)
583
647
  }
@@ -588,10 +652,12 @@ function createMuiOptionEditorSlot(options) {
588
652
  TextInput,
589
653
  {
590
654
  id: `mui-option-${option.id}-${currentLocale}`,
591
- label: `${currentLocale} translation`,
655
+ label: translate("builder.translation", {
656
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
657
+ }),
592
658
  value: option.translations?.[currentLocale] ?? "",
593
659
  disabled: readOnly,
594
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
660
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "option", id: option.id }, "label", value)
595
661
  }
596
662
  )
597
663
  ] });
@@ -603,7 +669,6 @@ var MuiOptionEditorSlot = createMuiOptionEditorSlot();
603
669
  import { Stack as Stack2 } from "@mui/material";
604
670
  import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
605
671
  function createMuiToolbarSlot(options) {
606
- const resolved = resolveMuiAdapterOptions(options);
607
672
  return function MuiToolbar({
608
673
  kind,
609
674
  index,
@@ -613,23 +678,26 @@ function createMuiToolbarSlot(options) {
613
678
  onMoveDown,
614
679
  onRemove,
615
680
  readOnly,
616
- components
681
+ components,
682
+ translate
617
683
  }) {
684
+ const resolved = useResolvedMuiAdapterOptions(options);
618
685
  const { IconButton: IconButton2 } = components;
619
686
  return /* @__PURE__ */ jsxs6(
620
687
  Stack2,
621
688
  {
689
+ ...resolved.muiSlotProps?.stack,
622
690
  "data-mui-slot": "toolbar",
623
691
  direction: "row",
624
692
  spacing: resolved.dense ? 0.5 : 1,
625
693
  alignItems: "center",
626
- sx: { mb: resolved.dense ? 1 : 2 },
694
+ sx: resolved.muiSlotProps?.stack?.sx ?? { mb: resolved.dense ? 1 : 2 },
627
695
  children: [
628
696
  /* @__PURE__ */ jsx12(
629
697
  IconButton2,
630
698
  {
631
699
  actionType: "moveUp",
632
- title: `Move ${title} up`,
700
+ title: translate("builder.moveUp", { title }),
633
701
  disabled: readOnly || index === 0,
634
702
  onClick: onMoveUp
635
703
  }
@@ -638,7 +706,7 @@ function createMuiToolbarSlot(options) {
638
706
  IconButton2,
639
707
  {
640
708
  actionType: "moveDown",
641
- title: `Move ${title} down`,
709
+ title: translate("builder.moveDown", { title }),
642
710
  disabled: readOnly || index === total - 1,
643
711
  onClick: onMoveDown
644
712
  }
@@ -647,7 +715,7 @@ function createMuiToolbarSlot(options) {
647
715
  IconButton2,
648
716
  {
649
717
  actionType: "delete",
650
- title: `Delete ${title}`,
718
+ title: translate("builder.delete", { title }),
651
719
  disabled: readOnly || kind !== "page" && total <= 1,
652
720
  onClick: onRemove
653
721
  }
@@ -660,7 +728,7 @@ function createMuiToolbarSlot(options) {
660
728
  var MuiToolbarSlot = createMuiToolbarSlot();
661
729
 
662
730
  // src/slots/FieldEditor.tsx
663
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
731
+ import { Fragment, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
664
732
  var FIELD_TYPES = [
665
733
  "text",
666
734
  "textarea",
@@ -674,6 +742,16 @@ var FIELD_TYPES = [
674
742
  function isFieldType(value) {
675
743
  return FIELD_TYPES.some((type) => type === value);
676
744
  }
745
+ function conditionOperators(field) {
746
+ if (field.type === "multi-select") return ["contains", "not_empty"];
747
+ if (field.type === "text" || field.type === "textarea") {
748
+ return ["equals", "not_equals", "contains", "not_empty"];
749
+ }
750
+ return ["equals", "not_equals", "not_empty"];
751
+ }
752
+ function isConditionOperator(value) {
753
+ return ["equals", "not_equals", "contains", "not_empty"].some((operator) => operator === value);
754
+ }
677
755
  function numericValue(value) {
678
756
  if (value.trim().length === 0) return void 0;
679
757
  const parsed = Number(value);
@@ -687,7 +765,6 @@ function updateBound(field, property, value) {
687
765
  return remaining;
688
766
  }
689
767
  function createMuiFieldEditorSlot(options) {
690
- const resolved = resolveMuiAdapterOptions(options);
691
768
  const Toolbar = createMuiToolbarSlot(options);
692
769
  const OptionEditor = createMuiOptionEditorSlot(options);
693
770
  return function MuiFieldEditor({
@@ -696,27 +773,34 @@ function createMuiFieldEditorSlot(options) {
696
773
  index,
697
774
  currentLocale,
698
775
  policy,
776
+ features,
699
777
  readOnly,
700
778
  actions,
701
- components
779
+ components,
780
+ translate
702
781
  }) {
782
+ const resolved = useResolvedMuiAdapterOptions(options);
703
783
  const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
704
784
  const allowedTypes = policy?.allowedFieldTypes ?? FIELD_TYPES;
705
785
  const pageId = schema.pages?.find((page) => page.questionIds.includes(field.id))?.id ?? "";
706
786
  const condition = field.displayCondition;
707
787
  const conditionSources = schema.fields.slice(0, index);
788
+ const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
789
+ const descriptionMode = resolved.fieldEditorOptions?.description ?? "editable";
708
790
  const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
709
791
  return /* @__PURE__ */ jsxs7(
710
792
  Card,
711
793
  {
794
+ ...resolved.muiSlotProps?.card,
712
795
  "data-mui-slot": "field-editor",
713
796
  variant: "outlined",
714
- sx: { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
797
+ sx: resolved.muiSlotProps?.card?.sx ?? { mb: resolved.dense ? 1 : 2, p: resolved.dense ? 1.5 : 2 },
715
798
  children: [
716
799
  /* @__PURE__ */ jsx13(
717
800
  Toolbar,
718
801
  {
719
802
  schema,
803
+ translate,
720
804
  kind: "field",
721
805
  targetId: field.id,
722
806
  index,
@@ -730,7 +814,7 @@ function createMuiFieldEditorSlot(options) {
730
814
  components
731
815
  }
732
816
  ),
733
- /* @__PURE__ */ jsxs7(Stack3, { spacing: resolved.dense ? 1 : 2, children: [
817
+ /* @__PURE__ */ jsxs7(Stack3, { ...resolved.muiSlotProps?.stack, spacing: resolved.dense ? 1 : 2, children: [
734
818
  /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle1", fontWeight: "bold", children: field.title }),
735
819
  /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
736
820
  /* @__PURE__ */ jsx13(
@@ -738,11 +822,11 @@ function createMuiFieldEditorSlot(options) {
738
822
  {
739
823
  id: `mui-field-${field.id}-title`,
740
824
  name: `fields.${field.id}.title`,
741
- label: "Question title",
825
+ label: translate("builder.questionTitle"),
742
826
  value: field.title,
743
827
  required: true,
744
828
  error: field.title.trim().length === 0,
745
- helperText: field.title.trim().length === 0 ? "Required" : "",
829
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
746
830
  "aria-describedby": titleErrorId,
747
831
  disabled: readOnly,
748
832
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "title", value)
@@ -753,12 +837,11 @@ function createMuiFieldEditorSlot(options) {
753
837
  {
754
838
  id: `mui-field-${field.id}-type`,
755
839
  name: `fields.${field.id}.type`,
756
- label: "Type",
757
- value: field.type,
758
- options: FIELD_TYPES.map((type) => ({
840
+ label: translate("builder.type"),
841
+ value: allowedTypes.includes(field.type) ? field.type : "",
842
+ options: FIELD_TYPES.filter((type) => allowedTypes.includes(type)).map((type) => ({
759
843
  value: type,
760
- label: type,
761
- disabled: !allowedTypes.includes(type)
844
+ label: translate(`builder.fieldType.${type}`)
762
845
  })),
763
846
  disabled: readOnly,
764
847
  onChange: (value) => {
@@ -767,15 +850,16 @@ function createMuiFieldEditorSlot(options) {
767
850
  }
768
851
  )
769
852
  ] }),
770
- /* @__PURE__ */ jsx13(
853
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ jsx13(
771
854
  TextArea,
772
855
  {
773
856
  id: `mui-field-${field.id}-description`,
774
857
  name: `fields.${field.id}.description`,
775
- label: "Description",
858
+ label: translate("builder.description"),
776
859
  value: field.description ?? "",
777
860
  rows: resolved.dense ? 2 : 3,
778
861
  disabled: readOnly,
862
+ readOnly: descriptionMode === "readOnly",
779
863
  onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "description", value)
780
864
  }
781
865
  ),
@@ -784,20 +868,20 @@ function createMuiFieldEditorSlot(options) {
784
868
  {
785
869
  id: `mui-field-${field.id}-required`,
786
870
  name: `fields.${field.id}.required`,
787
- label: "Required",
871
+ label: translate("builder.required"),
788
872
  checked: field.required,
789
873
  disabled: readOnly,
790
874
  onChange: (checked) => actions.updateField(field.id, (current) => ({ ...current, required: checked }))
791
875
  }
792
876
  ),
793
- schema.pages === void 0 ? null : /* @__PURE__ */ jsx13(
877
+ features?.pages === false || schema.pages === void 0 ? null : /* @__PURE__ */ jsx13(
794
878
  Select2,
795
879
  {
796
880
  id: `mui-field-${field.id}-page`,
797
- label: "Page",
881
+ label: translate("builder.questionPage"),
798
882
  value: pageId,
799
883
  options: [
800
- { value: "", label: "Unassigned" },
884
+ { value: "", label: translate("builder.unassigned") },
801
885
  ...schema.pages.map((page) => ({ value: page.id, label: page.title ?? page.id }))
802
886
  ],
803
887
  disabled: readOnly,
@@ -809,7 +893,7 @@ function createMuiFieldEditorSlot(options) {
809
893
  TextInput,
810
894
  {
811
895
  id: `mui-field-${field.id}-minimum`,
812
- label: "Minimum",
896
+ label: translate("builder.minimum"),
813
897
  type: "number",
814
898
  value: field.min === void 0 ? "" : String(field.min),
815
899
  disabled: readOnly,
@@ -820,7 +904,7 @@ function createMuiFieldEditorSlot(options) {
820
904
  TextInput,
821
905
  {
822
906
  id: `mui-field-${field.id}-maximum`,
823
- label: "Maximum",
907
+ label: translate("builder.maximum"),
824
908
  type: "number",
825
909
  value: field.max === void 0 ? "" : String(field.max),
826
910
  disabled: readOnly,
@@ -828,15 +912,15 @@ function createMuiFieldEditorSlot(options) {
828
912
  }
829
913
  )
830
914
  ] }) : null,
831
- conditionSources.length === 0 ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
915
+ features?.conditions === false || conditionSources.length === 0 ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
832
916
  /* @__PURE__ */ jsx13(
833
917
  Select2,
834
918
  {
835
919
  id: `mui-field-${field.id}-condition-source`,
836
- label: "Display condition",
920
+ label: translate("builder.displayCondition"),
837
921
  value: condition?.questionId ?? "",
838
922
  options: [
839
- { value: "", label: "Always visible" },
923
+ { value: "", label: translate("builder.alwaysVisible") },
840
924
  ...conditionSources.map((source) => ({ value: source.id, label: source.title }))
841
925
  ],
842
926
  disabled: readOnly,
@@ -846,45 +930,66 @@ function createMuiFieldEditorSlot(options) {
846
930
  )
847
931
  }
848
932
  ),
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
- )
933
+ condition === void 0 ? null : /* @__PURE__ */ jsxs7(Fragment, { children: [
934
+ /* @__PURE__ */ jsx13(
935
+ Select2,
936
+ {
937
+ id: `mui-field-${field.id}-condition-operator`,
938
+ label: translate("builder.conditionOperator"),
939
+ value: condition.operator,
940
+ options: (conditionSource === void 0 ? [] : conditionOperators(conditionSource)).map(
941
+ (operator) => ({ value: operator, label: translate(`builder.operator.${operator}`) })
942
+ ),
943
+ disabled: readOnly,
944
+ onChange: (value) => {
945
+ if (!isConditionOperator(value)) return;
946
+ actions.setDisplayCondition(
947
+ field.id,
948
+ value === "not_empty" ? { questionId: condition.questionId, operator: value } : { ...condition, operator: value, value: condition.value ?? "" }
949
+ );
950
+ }
951
+ }
952
+ ),
953
+ condition.operator === "not_empty" ? null : /* @__PURE__ */ jsx13(
954
+ TextInput,
955
+ {
956
+ id: `mui-field-${field.id}-condition-value`,
957
+ label: translate("builder.conditionValue"),
958
+ value: condition.value === void 0 ? "" : String(condition.value),
959
+ disabled: readOnly,
960
+ onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
961
+ }
962
+ )
963
+ ] })
859
964
  ] }),
860
965
  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
- ] }),
966
+ /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.translation", {
967
+ locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
968
+ }) }),
865
969
  /* @__PURE__ */ jsx13(
866
970
  TextInput,
867
971
  {
868
972
  id: `mui-field-${field.id}-${currentLocale}-title`,
869
- label: "Translated question title",
973
+ label: translate("builder.translatedQuestionTitle"),
870
974
  value: field.translations?.[currentLocale]?.title ?? "",
871
975
  disabled: readOnly,
872
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
976
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
873
977
  }
874
978
  ),
875
- /* @__PURE__ */ jsx13(
979
+ descriptionMode === "hidden" ? null : /* @__PURE__ */ jsx13(
876
980
  TextArea,
877
981
  {
878
982
  id: `mui-field-${field.id}-${currentLocale}-description`,
879
- label: "Translated description",
983
+ label: translate("builder.translatedDescription"),
880
984
  value: field.translations?.[currentLocale]?.description ?? "",
881
985
  disabled: readOnly,
882
- onChange: (value) => actions.setLocaleTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
986
+ readOnly: descriptionMode === "readOnly",
987
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
883
988
  }
884
989
  )
885
990
  ] }),
886
991
  "options" in field ? /* @__PURE__ */ jsxs7(Stack3, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
887
- /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: "Options" }),
992
+ /* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.options") }),
888
993
  field.options.map((option, optionIndex) => /* @__PURE__ */ jsx13(
889
994
  OptionEditor,
890
995
  {
@@ -893,6 +998,7 @@ function createMuiFieldEditorSlot(options) {
893
998
  option,
894
999
  index: optionIndex,
895
1000
  currentLocale,
1001
+ translate,
896
1002
  readOnly,
897
1003
  actions,
898
1004
  components
@@ -906,7 +1012,7 @@ function createMuiFieldEditorSlot(options) {
906
1012
  targetId: field.id,
907
1013
  disabled: readOnly || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
908
1014
  onClick: () => actions.addOption(field.id),
909
- children: "Add option"
1015
+ children: translate("builder.addOption")
910
1016
  }
911
1017
  )
912
1018
  ] }) : null
@@ -919,11 +1025,11 @@ function createMuiFieldEditorSlot(options) {
919
1025
  var MuiFieldEditorSlot = createMuiFieldEditorSlot();
920
1026
 
921
1027
  // src/slots/Localization.tsx
922
- import { Box as Box2, Stack as Stack4, Tab, Tabs, Typography as Typography4 } from "@mui/material";
1028
+ import { ExpandMore } from "@mui/icons-material";
1029
+ import { Accordion, AccordionDetails, AccordionSummary, Box as Box2, Chip, Stack as Stack4, Tab, Tabs, Typography as Typography4 } from "@mui/material";
923
1030
  import { useState } from "react";
924
1031
  import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
925
1032
  function createMuiLocalizationSlot(options) {
926
- const resolved = resolveMuiAdapterOptions(options);
927
1033
  return function MuiLocalization({
928
1034
  schema,
929
1035
  currentLocale,
@@ -931,27 +1037,163 @@ function createMuiLocalizationSlot(options) {
931
1037
  onAutoTranslate,
932
1038
  isTranslating,
933
1039
  translationError,
1040
+ policy,
1041
+ translationAdapterAvailable,
934
1042
  readOnly,
935
1043
  actions,
936
- components
1044
+ components,
1045
+ translate
937
1046
  }) {
938
- const { Button: Button2, ErrorMessage, TextArea, TextInput } = components;
1047
+ const resolved = useResolvedMuiAdapterOptions(options);
1048
+ const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
939
1049
  const [newLocale, setNewLocale] = useState("");
940
1050
  const locales = Array.from(
941
- /* @__PURE__ */ new Set([
942
- ...schema.supportedLocales ?? [],
943
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale]
944
- ])
1051
+ new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
945
1052
  );
1053
+ const editingLocaleConfigured = locales.includes(currentLocale);
1054
+ const registeredLocales = /* @__PURE__ */ new Set([
1055
+ ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
1056
+ ...schema.supportedLocales ?? []
1057
+ ]);
1058
+ const availableAllowedLocales = policy?.allowedLocales?.filter((locale) => !registeredLocales.has(locale));
1059
+ const localeLimitReached = policy?.maxLocales !== void 0 && registeredLocales.size >= policy.maxLocales;
1060
+ const normalizedLocale = newLocale.trim();
1061
+ const localeAllowed = policy?.allowedLocales === void 0 || policy.allowedLocales.includes(normalizedLocale);
1062
+ const canAddLocale = !readOnly && normalizedLocale.length > 0 && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
946
1063
  const handleTabChange = (_event, value) => onCurrentLocaleChange(value);
947
1064
  const addLocale = () => {
948
- const normalized = newLocale.trim();
949
- if (normalized.length === 0) return;
950
- const result = actions.addLocale(normalized);
1065
+ if (!canAddLocale) return;
1066
+ const result = actions.addLocale(normalizedLocale);
951
1067
  if (!result.success) return;
952
- onCurrentLocaleChange(normalized);
1068
+ onCurrentLocaleChange(normalizedLocale);
953
1069
  setNewLocale("");
954
1070
  };
1071
+ const stackProps = resolved.muiSlotProps?.stack;
1072
+ const collapsible = resolved.localizationOptions?.collapsible ?? false;
1073
+ const defaultLocaleControl = resolved.localizationOptions?.defaultLocaleControl ?? "editable";
1074
+ const content = /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1075
+ !collapsible ? /* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) : null,
1076
+ /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
1077
+ defaultLocaleControl === "hidden" ? null : defaultLocaleControl === "readOnly" ? /* @__PURE__ */ jsxs8(Stack4, { spacing: 0.5, children: [
1078
+ /* @__PURE__ */ jsx14(Typography4, { variant: "caption", color: "text.secondary", children: translate("builder.defaultLocale") }),
1079
+ /* @__PURE__ */ jsx14(
1080
+ Chip,
1081
+ {
1082
+ label: resolved.getLocaleLabel?.(schema.defaultLocale ?? "") ?? schema.defaultLocale ?? "",
1083
+ size: resolved.size
1084
+ }
1085
+ )
1086
+ ] }) : /* @__PURE__ */ jsx14(
1087
+ TextInput,
1088
+ {
1089
+ id: "mui-builder-default-locale",
1090
+ label: translate("builder.defaultLocale"),
1091
+ value: schema.defaultLocale ?? "",
1092
+ disabled: readOnly,
1093
+ onChange: (value) => {
1094
+ const result = actions.setDefaultLocale(value);
1095
+ if (result.success && value === currentLocale) onCurrentLocaleChange("");
1096
+ }
1097
+ }
1098
+ ),
1099
+ availableAllowedLocales === void 0 ? /* @__PURE__ */ jsx14(
1100
+ TextInput,
1101
+ {
1102
+ id: "mui-builder-new-locale",
1103
+ label: translate("builder.addLocale"),
1104
+ value: newLocale,
1105
+ disabled: readOnly || localeLimitReached,
1106
+ onChange: setNewLocale
1107
+ }
1108
+ ) : /* @__PURE__ */ jsx14(
1109
+ Select2,
1110
+ {
1111
+ id: "mui-builder-new-locale",
1112
+ label: translate("builder.addLocale"),
1113
+ value: newLocale,
1114
+ options: [
1115
+ { value: "", label: "\u2014" },
1116
+ ...availableAllowedLocales.map((locale) => ({
1117
+ value: locale,
1118
+ label: resolved.getLocaleLabel?.(locale) ?? locale
1119
+ }))
1120
+ ],
1121
+ disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
1122
+ onChange: setNewLocale
1123
+ }
1124
+ ),
1125
+ /* @__PURE__ */ jsx14(Button2, { variant: "primary", action: "addLocale", disabled: !canAddLocale, onClick: addLocale, children: translate("builder.addLocale") })
1126
+ ] }),
1127
+ locales.length === 0 ? null : /* @__PURE__ */ jsx14(
1128
+ Tabs,
1129
+ {
1130
+ value: editingLocaleConfigured ? currentLocale : false,
1131
+ onChange: handleTabChange,
1132
+ variant: "scrollable",
1133
+ scrollButtons: "auto",
1134
+ "aria-label": translate("builder.translationLocale"),
1135
+ children: locales.map((locale) => /* @__PURE__ */ jsx14(
1136
+ Tab,
1137
+ {
1138
+ value: locale,
1139
+ label: resolved.getLocaleLabel?.(locale) ?? locale,
1140
+ disabled: readOnly && locale !== currentLocale
1141
+ },
1142
+ locale
1143
+ ))
1144
+ }
1145
+ ),
1146
+ !translationAdapterAvailable ? null : /* @__PURE__ */ jsx14(
1147
+ Button2,
1148
+ {
1149
+ variant: "secondary",
1150
+ disabled: readOnly || !editingLocaleConfigured || isTranslating,
1151
+ onClick: onAutoTranslate,
1152
+ children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
1153
+ }
1154
+ ),
1155
+ translationError === void 0 ? null : /* @__PURE__ */ jsx14(ErrorMessage, { message: translationError }),
1156
+ !editingLocaleConfigured ? /* @__PURE__ */ jsx14(Typography4, { variant: "body2", color: "text.secondary", children: translate("builder.selectLocale") }) : /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
1157
+ /* @__PURE__ */ jsx14(
1158
+ TextInput,
1159
+ {
1160
+ id: `mui-builder-${currentLocale}-form-title`,
1161
+ label: translate("builder.translatedFormTitle"),
1162
+ value: schema.translations?.[currentLocale]?.title ?? "",
1163
+ disabled: readOnly,
1164
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "title", value)
1165
+ }
1166
+ ),
1167
+ /* @__PURE__ */ jsx14(
1168
+ TextArea,
1169
+ {
1170
+ id: `mui-builder-${currentLocale}-form-description`,
1171
+ label: translate("builder.translatedFormDescription"),
1172
+ value: schema.translations?.[currentLocale]?.description ?? "",
1173
+ disabled: readOnly,
1174
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "description", value)
1175
+ }
1176
+ ),
1177
+ /* @__PURE__ */ jsx14(
1178
+ TextInput,
1179
+ {
1180
+ id: `mui-builder-${currentLocale}-completion-message`,
1181
+ label: translate("builder.translatedCompletionMessage"),
1182
+ value: schema.translations?.[currentLocale]?.completionMessage ?? "",
1183
+ disabled: readOnly,
1184
+ onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "form" }, "completionMessage", value)
1185
+ }
1186
+ )
1187
+ ] })
1188
+ ] });
1189
+ const configured = locales.length > 0;
1190
+ const defaultExpanded = resolved.localizationOptions?.defaultExpanded === "when-configured" ? configured : resolved.localizationOptions?.defaultExpanded ?? false;
1191
+ if (collapsible) {
1192
+ return /* @__PURE__ */ jsxs8(Accordion, { ...resolved.muiSlotProps?.accordion, "data-mui-slot": "localization", defaultExpanded, children: [
1193
+ /* @__PURE__ */ jsx14(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx14(ExpandMore, {}), children: /* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }) }),
1194
+ /* @__PURE__ */ jsx14(AccordionDetails, { children: content })
1195
+ ] });
1196
+ }
955
1197
  return /* @__PURE__ */ jsx14(
956
1198
  Box2,
957
1199
  {
@@ -963,95 +1205,7 @@ function createMuiLocalizationSlot(options) {
963
1205
  borderColor: "divider",
964
1206
  borderRadius: 1
965
1207
  },
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
- ] })
1208
+ children: content
1055
1209
  }
1056
1210
  );
1057
1211
  };
@@ -1060,13 +1214,15 @@ var MuiLocalizationSlot = createMuiLocalizationSlot();
1060
1214
 
1061
1215
  // src/slots/index.ts
1062
1216
  var muiBuilderSlots = {
1063
- toolbar: createMuiToolbarSlot(),
1064
- fieldEditor: createMuiFieldEditorSlot(),
1065
- optionEditor: createMuiOptionEditorSlot(),
1066
- localization: createMuiLocalizationSlot()
1217
+ sectionOrder: DEFAULT_MUI_SECTION_ORDER,
1218
+ toolbar: MuiToolbarSlot,
1219
+ fieldEditor: MuiFieldEditorSlot,
1220
+ optionEditor: MuiOptionEditorSlot,
1221
+ localization: MuiLocalizationSlot
1067
1222
  };
1068
1223
  function createMuiBuilderSlots(options, customOverrides = {}) {
1069
1224
  return {
1225
+ sectionOrder: options?.layoutOptions?.sectionOrder ?? DEFAULT_MUI_SECTION_ORDER,
1070
1226
  toolbar: createMuiToolbarSlot(options),
1071
1227
  fieldEditor: createMuiFieldEditorSlot(options),
1072
1228
  optionEditor: createMuiOptionEditorSlot(options),
@@ -1092,24 +1248,46 @@ import { useMemo } from "react";
1092
1248
  import { jsx as jsx15 } from "react/jsx-runtime";
1093
1249
  function MuiFormBuilder({
1094
1250
  muiOptions,
1251
+ layoutOptions,
1252
+ localizationOptions,
1253
+ muiSlotProps,
1095
1254
  components: customComponents,
1096
1255
  slots: customSlots,
1256
+ sectionOrder,
1097
1257
  ...props
1098
1258
  }) {
1099
- const components = useMemo(
1100
- () => createMuiBuilderComponents(muiOptions, customComponents),
1101
- [muiOptions, customComponents]
1259
+ const contextOptions = useMemo(
1260
+ () => mergeMuiAdapterOptions(muiOptions, {
1261
+ ...layoutOptions === void 0 ? {} : { layoutOptions },
1262
+ ...localizationOptions === void 0 ? {} : { localizationOptions },
1263
+ ...muiSlotProps === void 0 ? {} : { muiSlotProps }
1264
+ }),
1265
+ [layoutOptions, localizationOptions, muiOptions, muiSlotProps]
1102
1266
  );
1103
- const slots = useMemo(() => createMuiBuilderSlots(muiOptions, customSlots), [muiOptions, customSlots]);
1104
- return /* @__PURE__ */ jsx15(FormBuilder, { ...props, components, disableDefaultStyles: true, slots });
1267
+ const contextValue = useMemo(() => ({ options: contextOptions }), [contextOptions]);
1268
+ const components = useMemo(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
1269
+ const slots = useMemo(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
1270
+ const resolvedSectionOrder = sectionOrder ?? contextOptions.layoutOptions?.sectionOrder;
1271
+ return /* @__PURE__ */ jsx15(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx15(
1272
+ FormBuilder,
1273
+ {
1274
+ ...props,
1275
+ components,
1276
+ disableDefaultStyles: true,
1277
+ slots,
1278
+ ...resolvedSectionOrder === void 0 ? {} : { sectionOrder: resolvedSectionOrder }
1279
+ }
1280
+ ) });
1105
1281
  }
1106
1282
  export {
1283
+ DEFAULT_MUI_SECTION_ORDER,
1107
1284
  MuiButtonAdapter,
1108
1285
  MuiCheckboxAdapter,
1109
1286
  MuiErrorMessageAdapter,
1110
1287
  MuiFieldEditorSlot,
1111
1288
  MuiFieldsetAdapter,
1112
1289
  MuiFormBuilder,
1290
+ MuiFormBuilderContext,
1113
1291
  MuiIconButtonAdapter,
1114
1292
  MuiLocalizationSlot,
1115
1293
  MuiOptionEditorSlot,
@@ -1134,8 +1312,10 @@ export {
1134
1312
  createMuiTextAreaAdapter,
1135
1313
  createMuiTextInputAdapter,
1136
1314
  createMuiToolbarSlot,
1315
+ mergeMuiAdapterOptions,
1137
1316
  muiBuilderComponents,
1138
1317
  muiBuilderSlots,
1139
1318
  muiDefaultIconResolver,
1140
- resolveMuiAdapterOptions
1319
+ resolveMuiAdapterOptions,
1320
+ useResolvedMuiAdapterOptions
1141
1321
  };