@form-engine-ts/react 2.9.1 → 2.9.3

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
@@ -750,6 +750,8 @@ function DefaultButton({
750
750
  className,
751
751
  disabled,
752
752
  "aria-label": ariaLabel,
753
+ "aria-describedby": ariaDescribedBy,
754
+ "aria-labelledby": ariaLabelledBy,
753
755
  onClick,
754
756
  children,
755
757
  title,
@@ -764,6 +766,8 @@ function DefaultButton({
764
766
  type: "button",
765
767
  disabled,
766
768
  "aria-label": ariaLabel,
769
+ "aria-describedby": ariaDescribedBy,
770
+ "aria-labelledby": ariaLabelledBy,
767
771
  title,
768
772
  "data-builder-action": action,
769
773
  "data-target-id": targetId,
@@ -780,17 +784,43 @@ function DefaultIconButton(props) {
780
784
  ...props.className === void 0 ? {} : { className: props.className },
781
785
  ...props.disabled === void 0 ? {} : { disabled: props.disabled },
782
786
  "aria-label": props["aria-label"] ?? props.title,
787
+ "aria-describedby": props["aria-describedby"],
788
+ "aria-labelledby": props["aria-labelledby"],
789
+ ...props.title === void 0 ? {} : { title: props.title },
783
790
  ...props.onClick === void 0 ? {} : { onClick: props.onClick },
784
791
  children: props.icon
785
792
  }
786
793
  );
787
794
  }
795
+ function defaultIconFor(actionType) {
796
+ switch (actionType) {
797
+ case "moveUp":
798
+ return "\u2191";
799
+ case "moveDown":
800
+ return "\u2193";
801
+ case "delete":
802
+ case "close":
803
+ return "\xD7";
804
+ case "add":
805
+ return "+";
806
+ case "dragHandle":
807
+ return "\u283F";
808
+ case "edit":
809
+ return "\u270E";
810
+ case "settings":
811
+ return "\u2699";
812
+ case "translate":
813
+ return "\u6587";
814
+ }
815
+ }
788
816
  function DefaultTextInput({
789
817
  id,
790
818
  className,
791
819
  disabled,
792
820
  readOnly,
793
821
  "aria-label": ariaLabel,
822
+ "aria-describedby": ariaDescribedBy,
823
+ "aria-labelledby": ariaLabelledBy,
794
824
  name,
795
825
  label,
796
826
  required,
@@ -806,7 +836,9 @@ function DefaultTextInput({
806
836
  max,
807
837
  step
808
838
  }) {
839
+ const labelElement = label === void 0 ? null : id === void 0 ? /* @__PURE__ */ jsx("span", { children: label }) : /* @__PURE__ */ jsx("label", { htmlFor: id, children: label });
809
840
  return /* @__PURE__ */ jsxs(Fragment, { children: [
841
+ labelElement,
810
842
  /* @__PURE__ */ jsx(
811
843
  "input",
812
844
  {
@@ -816,7 +848,9 @@ function DefaultTextInput({
816
848
  disabled,
817
849
  readOnly,
818
850
  required,
819
- "aria-label": ariaLabel ?? label,
851
+ "aria-label": ariaLabel,
852
+ "aria-describedby": ariaDescribedBy,
853
+ "aria-labelledby": ariaLabelledBy,
820
854
  "aria-invalid": error === true ? true : void 0,
821
855
  type: type === "text" ? void 0 : type,
822
856
  inputMode,
@@ -829,7 +863,7 @@ function DefaultTextInput({
829
863
  onChange: (event) => onChange(event.currentTarget.value)
830
864
  }
831
865
  ),
832
- helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
866
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { id: ariaDescribedBy, children: helperText })
833
867
  ] });
834
868
  }
835
869
  function DefaultTextArea({
@@ -838,6 +872,8 @@ function DefaultTextArea({
838
872
  disabled,
839
873
  readOnly,
840
874
  "aria-label": ariaLabel,
875
+ "aria-describedby": ariaDescribedBy,
876
+ "aria-labelledby": ariaLabelledBy,
841
877
  name,
842
878
  label,
843
879
  required,
@@ -849,7 +885,9 @@ function DefaultTextArea({
849
885
  placeholder,
850
886
  maxLength
851
887
  }) {
888
+ const labelElement = label === void 0 ? null : id === void 0 ? /* @__PURE__ */ jsx("span", { children: label }) : /* @__PURE__ */ jsx("label", { htmlFor: id, children: label });
852
889
  return /* @__PURE__ */ jsxs(Fragment, { children: [
890
+ labelElement,
853
891
  /* @__PURE__ */ jsx(
854
892
  "textarea",
855
893
  {
@@ -859,7 +897,9 @@ function DefaultTextArea({
859
897
  disabled,
860
898
  readOnly,
861
899
  required,
862
- "aria-label": ariaLabel ?? label,
900
+ "aria-label": ariaLabel,
901
+ "aria-describedby": ariaDescribedBy,
902
+ "aria-labelledby": ariaLabelledBy,
863
903
  "aria-invalid": error === true ? true : void 0,
864
904
  value,
865
905
  rows,
@@ -868,7 +908,7 @@ function DefaultTextArea({
868
908
  onChange: (event) => onChange(event.currentTarget.value)
869
909
  }
870
910
  ),
871
- helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
911
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { id: ariaDescribedBy, children: helperText })
872
912
  ] });
873
913
  }
874
914
  function DefaultSelect({
@@ -876,6 +916,8 @@ function DefaultSelect({
876
916
  className,
877
917
  disabled,
878
918
  "aria-label": ariaLabel,
919
+ "aria-describedby": ariaDescribedBy,
920
+ "aria-labelledby": ariaLabelledBy,
879
921
  name,
880
922
  label,
881
923
  required,
@@ -885,7 +927,9 @@ function DefaultSelect({
885
927
  onChange,
886
928
  options
887
929
  }) {
930
+ const labelElement = label === void 0 ? null : id === void 0 ? /* @__PURE__ */ jsx("span", { children: label }) : /* @__PURE__ */ jsx("label", { htmlFor: id, children: label });
888
931
  return /* @__PURE__ */ jsxs(Fragment, { children: [
932
+ labelElement,
889
933
  /* @__PURE__ */ jsx(
890
934
  "select",
891
935
  {
@@ -894,38 +938,55 @@ function DefaultSelect({
894
938
  className,
895
939
  disabled,
896
940
  required,
897
- "aria-label": ariaLabel ?? label,
941
+ "aria-label": ariaLabel,
942
+ "aria-describedby": ariaDescribedBy,
943
+ "aria-labelledby": ariaLabelledBy,
898
944
  "aria-invalid": error === true ? true : void 0,
899
945
  value,
900
946
  onChange: (event) => onChange(event.currentTarget.value),
901
947
  children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
902
948
  }
903
949
  ),
904
- helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { children: helperText })
950
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { id: ariaDescribedBy, children: helperText })
905
951
  ] });
906
952
  }
907
953
  function DefaultCheckbox({
908
954
  id,
909
955
  className,
910
956
  disabled,
957
+ readOnly,
911
958
  "aria-label": ariaLabel,
959
+ "aria-describedby": ariaDescribedBy,
960
+ "aria-labelledby": ariaLabelledBy,
961
+ name,
962
+ required,
963
+ error,
964
+ helperText,
912
965
  checked,
913
966
  onChange,
914
967
  label
915
968
  }) {
916
- return /* @__PURE__ */ jsxs("label", { className, children: [
917
- /* @__PURE__ */ jsx(
918
- "input",
919
- {
920
- id,
921
- type: "checkbox",
922
- disabled,
923
- "aria-label": ariaLabel,
924
- checked,
925
- onChange: (event) => onChange(event.currentTarget.checked)
926
- }
927
- ),
928
- label
969
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
970
+ /* @__PURE__ */ jsxs("label", { className, children: [
971
+ /* @__PURE__ */ jsx(
972
+ "input",
973
+ {
974
+ id,
975
+ name,
976
+ type: "checkbox",
977
+ disabled: disabled || readOnly,
978
+ required,
979
+ "aria-label": ariaLabel,
980
+ "aria-describedby": ariaDescribedBy,
981
+ "aria-labelledby": ariaLabelledBy,
982
+ "aria-invalid": error === true ? true : void 0,
983
+ checked,
984
+ onChange: (event) => onChange(event.currentTarget.checked)
985
+ }
986
+ ),
987
+ label
988
+ ] }),
989
+ helperText === void 0 || helperText.length === 0 ? null : /* @__PURE__ */ jsx("small", { id: ariaDescribedBy, children: helperText })
929
990
  ] });
930
991
  }
931
992
  function DefaultSection({
@@ -960,8 +1021,8 @@ function DefaultFieldset({ className, legend, disabled, children }) {
960
1021
  children
961
1022
  ] });
962
1023
  }
963
- function DefaultErrorMessage({ message }) {
964
- return /* @__PURE__ */ jsx("p", { className: "form-engine-builder__error", children: message });
1024
+ function DefaultErrorMessage({ className, message }) {
1025
+ return /* @__PURE__ */ jsx("p", { className, children: message });
965
1026
  }
966
1027
  var DEFAULT_COMPONENTS = {
967
1028
  Button: DefaultButton,
@@ -972,41 +1033,101 @@ var DEFAULT_COMPONENTS = {
972
1033
  Checkbox: DefaultCheckbox,
973
1034
  Section: DefaultSection,
974
1035
  Fieldset: DefaultFieldset,
975
- ErrorMessage: DefaultErrorMessage
1036
+ ErrorMessage: DefaultErrorMessage,
1037
+ renderIcon: defaultIconFor
976
1038
  };
977
1039
  var BuilderPrimitiveContext = createContext({
978
1040
  components: DEFAULT_COMPONENTS,
979
- readOnly: false
1041
+ readOnly: false,
1042
+ unstyled: false
980
1043
  });
1044
+ function withoutDefaultStyleClasses(className) {
1045
+ const filtered = className?.split(/\s+/u).filter((name) => name.length > 0 && !name.startsWith("form-engine-builder") && !name.startsWith("feb-")).join(" ");
1046
+ return filtered === void 0 || filtered.length === 0 ? void 0 : filtered;
1047
+ }
1048
+ function primitiveClassName(className, defaultClassName, unstyled) {
1049
+ const userClassName = unstyled ? withoutDefaultStyleClasses(className) : className;
1050
+ return [unstyled ? void 0 : defaultClassName, userClassName].filter((value) => value !== void 0).join(" ") || void 0;
1051
+ }
981
1052
  function BuilderButton(props) {
982
1053
  const context = useContext(BuilderPrimitiveContext);
983
1054
  const Component = context.components.Button;
984
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1055
+ return /* @__PURE__ */ jsx(
1056
+ Component,
1057
+ {
1058
+ ...props,
1059
+ className: primitiveClassName(props.className, "feb-button", context.unstyled),
1060
+ disabled: context.readOnly || props.disabled === true,
1061
+ readOnly: context.readOnly
1062
+ }
1063
+ );
985
1064
  }
986
1065
  function BuilderIconButton(props) {
987
1066
  const context = useContext(BuilderPrimitiveContext);
988
1067
  const Component = context.components.IconButton;
989
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1068
+ const icon = props.actionType === void 0 ? props.icon ?? void 0 : context.components.renderIcon(props.actionType) ?? props.icon ?? defaultIconFor(props.actionType);
1069
+ return /* @__PURE__ */ jsx(
1070
+ Component,
1071
+ {
1072
+ ...props,
1073
+ icon,
1074
+ className: primitiveClassName(props.className, "feb-icon-button", context.unstyled),
1075
+ disabled: context.readOnly || props.disabled === true,
1076
+ readOnly: context.readOnly
1077
+ }
1078
+ );
990
1079
  }
991
1080
  function BuilderTextInput(props) {
992
1081
  const context = useContext(BuilderPrimitiveContext);
993
1082
  const Component = context.components.TextInput;
994
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1083
+ return /* @__PURE__ */ jsx(
1084
+ Component,
1085
+ {
1086
+ ...props,
1087
+ className: primitiveClassName(props.className, "feb-input", context.unstyled),
1088
+ disabled: context.readOnly || props.disabled === true,
1089
+ readOnly: context.readOnly
1090
+ }
1091
+ );
995
1092
  }
996
1093
  function BuilderTextArea(props) {
997
1094
  const context = useContext(BuilderPrimitiveContext);
998
1095
  const Component = context.components.TextArea;
999
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1096
+ return /* @__PURE__ */ jsx(
1097
+ Component,
1098
+ {
1099
+ ...props,
1100
+ className: primitiveClassName(props.className, "feb-textarea", context.unstyled),
1101
+ disabled: context.readOnly || props.disabled === true,
1102
+ readOnly: context.readOnly
1103
+ }
1104
+ );
1000
1105
  }
1001
1106
  function BuilderSelect(props) {
1002
1107
  const context = useContext(BuilderPrimitiveContext);
1003
1108
  const Component = context.components.Select;
1004
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1109
+ return /* @__PURE__ */ jsx(
1110
+ Component,
1111
+ {
1112
+ ...props,
1113
+ className: primitiveClassName(props.className, "feb-select", context.unstyled),
1114
+ disabled: context.readOnly || props.disabled === true,
1115
+ readOnly: context.readOnly
1116
+ }
1117
+ );
1005
1118
  }
1006
1119
  function BuilderCheckbox(props) {
1007
1120
  const context = useContext(BuilderPrimitiveContext);
1008
1121
  const Component = context.components.Checkbox;
1009
- return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true, readOnly: context.readOnly });
1122
+ return /* @__PURE__ */ jsx(
1123
+ Component,
1124
+ {
1125
+ ...props,
1126
+ className: primitiveClassName(props.className, "feb-checkbox", context.unstyled),
1127
+ disabled: context.readOnly || props.disabled === true,
1128
+ readOnly: context.readOnly
1129
+ }
1130
+ );
1010
1131
  }
1011
1132
  function BuilderSection(props) {
1012
1133
  const Component = useContext(BuilderPrimitiveContext).components.Section;
@@ -1018,8 +1139,9 @@ function BuilderFieldset(props) {
1018
1139
  return /* @__PURE__ */ jsx(Component, { ...props, disabled: context.readOnly || props.disabled === true });
1019
1140
  }
1020
1141
  function BuilderErrorMessage(props) {
1021
- const Component = useContext(BuilderPrimitiveContext).components.ErrorMessage;
1022
- return /* @__PURE__ */ jsx(Component, { ...props });
1142
+ const context = useContext(BuilderPrimitiveContext);
1143
+ const Component = context.components.ErrorMessage;
1144
+ return /* @__PURE__ */ jsx("div", { className: primitiveClassName(props.className, "form-engine-builder__error", context.unstyled), children: /* @__PURE__ */ jsx(Component, { message: props.message }) });
1023
1145
  }
1024
1146
  var GUARDED_COMPONENTS = {
1025
1147
  Button: BuilderButton,
@@ -1208,10 +1330,17 @@ function FormBuilder({
1208
1330
  readOnly = false,
1209
1331
  features,
1210
1332
  components: componentOverrides,
1211
- slots
1333
+ slots,
1334
+ disableDefaultStyles = false,
1335
+ unstyled = false
1212
1336
  }) {
1213
1337
  const resolvedComponents = { ...DEFAULT_COMPONENTS, ...componentOverrides };
1214
- const components = GUARDED_COMPONENTS;
1338
+ const components = {
1339
+ ...GUARDED_COMPONENTS,
1340
+ renderIcon: resolvedComponents.renderIcon
1341
+ };
1342
+ const defaultStylesDisabled = disableDefaultStyles || unstyled;
1343
+ const builderClass = (value) => defaultStylesDisabled ? void 0 : value;
1215
1344
  const { Button, Checkbox, ErrorMessage, Fieldset, IconButton, Section, Select, TextArea, TextInput } = components;
1216
1345
  const ToolbarSlot = slots?.toolbar;
1217
1346
  const FieldEditorSlot = slots?.fieldEditor;
@@ -1494,817 +1623,818 @@ function FormBuilder({
1494
1623
  params: { locale: targetLocale }
1495
1624
  })
1496
1625
  };
1497
- return /* @__PURE__ */ jsx(BuilderPrimitiveContext.Provider, { value: { components: resolvedComponents, readOnly }, children: /* @__PURE__ */ jsx(
1498
- Section,
1626
+ return /* @__PURE__ */ jsx(
1627
+ BuilderPrimitiveContext.Provider,
1499
1628
  {
1500
- className: `form-engine-builder ${className}`.trim(),
1501
- "aria-label": translate("builder.formBuilder"),
1502
- onClickCapture: (event) => {
1503
- if (readOnly) return;
1504
- if (!(event.target instanceof HTMLElement)) return;
1505
- const actionTarget = event.target.closest("[data-builder-action]");
1506
- if (actionTarget?.dataset.builderAction === "addField" && maxFieldsReached && initialFieldType !== null)
1507
- addField();
1508
- if (actionTarget?.dataset.builderAction === "addLocale" && localeLimitReached && newLocale.trim().length > 0)
1509
- addLocale();
1510
- if (actionTarget?.dataset.builderAction !== "addOption") return;
1511
- const fieldId = actionTarget.dataset.targetId;
1512
- const field = schema.fields.find((candidate) => candidate.id === fieldId);
1513
- if (fieldId !== void 0 && field !== void 0 && "options" in field && policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField) {
1514
- addOption(fieldId);
1515
- }
1516
- },
1517
- children: /* @__PURE__ */ jsxs(Fieldset, { className: "form-engine-builder__controls", disabled: readOnly, children: [
1518
- /* @__PURE__ */ jsx(
1519
- Section,
1520
- {
1521
- className: "form-engine-builder__basic-settings",
1522
- headingId: "builder-basic-settings-heading",
1523
- title: translate("builder.basicSettings"),
1524
- children: /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1525
- /* @__PURE__ */ jsxs("label", { children: [
1526
- translate("builder.formTitle"),
1527
- /* @__PURE__ */ jsx(
1528
- TextInput,
1529
- {
1530
- name: "title",
1531
- required: true,
1532
- error: schema.title.trim().length === 0,
1533
- helperText: schema.title.trim().length === 0 ? translate("builder.required") : "",
1534
- value: schema.title,
1535
- onChange: (value) => setSourceText({ kind: "form" }, "title", value)
1536
- }
1537
- )
1538
- ] }),
1539
- /* @__PURE__ */ jsxs("label", { children: [
1540
- translate("builder.formDescription"),
1541
- /* @__PURE__ */ jsx(
1542
- TextArea,
1543
- {
1544
- name: "description",
1545
- rows: 3,
1546
- value: schema.description ?? "",
1547
- onChange: (value) => setSourceText({ kind: "form" }, "description", value)
1548
- }
1549
- )
1550
- ] })
1551
- ] })
1552
- }
1553
- ),
1554
- pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ jsx(
1555
- Section,
1556
- {
1557
- className: "form-engine-builder__pages",
1558
- headingId: "builder-pages-heading",
1559
- title: translate("builder.pages"),
1560
- children: schema.pages === void 0 ? /* @__PURE__ */ jsx(Button, { onClick: enablePages, children: translate("builder.enablePages") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1561
- schema.pages.map((page, pageIndex) => {
1562
- const priorQuestionIds = new Set(
1563
- schema.pages?.slice(0, pageIndex).flatMap((item) => item.questionIds)
1564
- );
1565
- const availableSources = schema.fields.filter((field) => priorQuestionIds.has(field.id));
1566
- const source = schema.fields.find((field) => field.id === page.displayCondition?.questionId);
1567
- return /* @__PURE__ */ jsxs(
1568
- Fieldset,
1569
- {
1570
- className: "form-engine-builder__page",
1571
- legend: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`,
1572
- children: [
1573
- /* @__PURE__ */ jsx("div", { className: "form-engine-builder__toolbar", children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1574
- /* @__PURE__ */ jsx(
1575
- IconButton,
1576
- {
1577
- icon: "\u2191",
1578
- title: translate("builder.moveUp", { title: page.title ?? page.id }),
1579
- disabled: pageIndex === 0,
1580
- onClick: () => movePage(pageIndex, -1)
1581
- }
1582
- ),
1583
- /* @__PURE__ */ jsx(
1584
- IconButton,
1585
- {
1586
- icon: "\u2193",
1587
- title: translate("builder.moveDown", { title: page.title ?? page.id }),
1588
- disabled: pageIndex === (schema.pages?.length ?? 0) - 1,
1589
- onClick: () => movePage(pageIndex, 1)
1590
- }
1591
- ),
1592
- /* @__PURE__ */ jsx(Button, { onClick: () => removePage(pageIndex), variant: "danger", children: translate("builder.deleteAction") })
1593
- ] }) : /* @__PURE__ */ jsx(
1594
- ToolbarSlot,
1595
- {
1596
- schema,
1597
- kind: "page",
1598
- targetId: page.id,
1599
- index: pageIndex,
1600
- total: schema.pages?.length ?? 0,
1601
- title: page.title ?? page.id,
1602
- onMoveUp: () => movePage(pageIndex, -1),
1603
- onMoveDown: () => movePage(pageIndex, 1),
1604
- onRemove: () => removePage(pageIndex),
1605
- readOnly,
1606
- actions,
1607
- components
1608
- }
1609
- ) }),
1610
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1611
- /* @__PURE__ */ jsxs("label", { children: [
1612
- translate("builder.pageTitle"),
1613
- /* @__PURE__ */ jsx(
1614
- TextInput,
1615
- {
1616
- value: page.title ?? "",
1617
- onChange: (value) => {
1618
- updatePage(page.id, (current) => {
1619
- if (value.length > 0) return { ...current, title: value };
1620
- const { title: _title, ...withoutTitle } = current;
1621
- return withoutTitle;
1622
- });
1623
- }
1624
- }
1625
- )
1626
- ] }),
1627
- /* @__PURE__ */ jsxs("label", { children: [
1628
- translate("builder.pageDescription"),
1629
- /* @__PURE__ */ jsx(
1630
- TextInput,
1631
- {
1632
- value: page.description ?? "",
1633
- onChange: (value) => {
1634
- updatePage(page.id, (current) => {
1635
- if (value.length > 0) return { ...current, description: value };
1636
- const { description: _description, ...withoutDescription } = current;
1637
- return withoutDescription;
1638
- });
1629
+ value: { components: resolvedComponents, readOnly, unstyled: defaultStylesDisabled },
1630
+ children: /* @__PURE__ */ jsx(
1631
+ Section,
1632
+ {
1633
+ className: defaultStylesDisabled ? className || void 0 : `form-engine-builder ${className}`.trim(),
1634
+ "aria-label": translate("builder.formBuilder"),
1635
+ onClickCapture: (event) => {
1636
+ if (readOnly) return;
1637
+ if (!(event.target instanceof HTMLElement)) return;
1638
+ const actionTarget = event.target.closest("[data-builder-action]");
1639
+ if (actionTarget?.dataset.builderAction === "addField" && maxFieldsReached && initialFieldType !== null)
1640
+ addField();
1641
+ if (actionTarget?.dataset.builderAction === "addLocale" && localeLimitReached && newLocale.trim().length > 0)
1642
+ addLocale();
1643
+ if (actionTarget?.dataset.builderAction !== "addOption") return;
1644
+ const fieldId = actionTarget.dataset.targetId;
1645
+ const field = schema.fields.find((candidate) => candidate.id === fieldId);
1646
+ if (fieldId !== void 0 && field !== void 0 && "options" in field && policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField) {
1647
+ addOption(fieldId);
1648
+ }
1649
+ },
1650
+ children: /* @__PURE__ */ jsxs(Fieldset, { className: builderClass("form-engine-builder__controls"), disabled: readOnly, children: [
1651
+ /* @__PURE__ */ jsx(
1652
+ Section,
1653
+ {
1654
+ className: builderClass("form-engine-builder__basic-settings"),
1655
+ headingId: "builder-basic-settings-heading",
1656
+ title: translate("builder.basicSettings"),
1657
+ children: /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
1658
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1659
+ TextInput,
1660
+ {
1661
+ id: "builder-form-title",
1662
+ name: "title",
1663
+ label: translate("builder.formTitle"),
1664
+ required: true,
1665
+ error: schema.title.trim().length === 0,
1666
+ helperText: schema.title.trim().length === 0 ? translate("builder.required") : "",
1667
+ "aria-describedby": schema.title.trim().length === 0 ? "builder-form-title-error" : void 0,
1668
+ value: schema.title,
1669
+ onChange: (value) => setSourceText({ kind: "form" }, "title", value)
1670
+ }
1671
+ ) }),
1672
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1673
+ TextArea,
1674
+ {
1675
+ id: "builder-form-description",
1676
+ name: "description",
1677
+ label: translate("builder.formDescription"),
1678
+ rows: 3,
1679
+ value: schema.description ?? "",
1680
+ onChange: (value) => setSourceText({ kind: "form" }, "description", value)
1681
+ }
1682
+ ) })
1683
+ ] })
1684
+ }
1685
+ ),
1686
+ pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ jsx(
1687
+ Section,
1688
+ {
1689
+ className: builderClass("form-engine-builder__pages"),
1690
+ headingId: "builder-pages-heading",
1691
+ title: translate("builder.pages"),
1692
+ children: schema.pages === void 0 ? /* @__PURE__ */ jsx(Button, { onClick: enablePages, children: translate("builder.enablePages") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1693
+ schema.pages.map((page, pageIndex) => {
1694
+ const priorQuestionIds = new Set(
1695
+ schema.pages?.slice(0, pageIndex).flatMap((item) => item.questionIds)
1696
+ );
1697
+ const availableSources = schema.fields.filter((field) => priorQuestionIds.has(field.id));
1698
+ const source = schema.fields.find((field) => field.id === page.displayCondition?.questionId);
1699
+ return /* @__PURE__ */ jsxs(
1700
+ Fieldset,
1701
+ {
1702
+ className: builderClass("form-engine-builder__page"),
1703
+ legend: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`,
1704
+ children: [
1705
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__toolbar"), children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1706
+ /* @__PURE__ */ jsx(
1707
+ IconButton,
1708
+ {
1709
+ actionType: "moveUp",
1710
+ title: translate("builder.moveUp", { title: page.title ?? page.id }),
1711
+ disabled: pageIndex === 0,
1712
+ onClick: () => movePage(pageIndex, -1)
1639
1713
  }
1640
- }
1641
- )
1642
- ] })
1643
- ] }),
1644
- !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__translation-editor", children: [
1645
- /* @__PURE__ */ jsx("strong", { children: editingLocale }),
1646
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1647
- /* @__PURE__ */ jsxs("label", { children: [
1648
- translate("builder.pageTitle"),
1714
+ ),
1649
1715
  /* @__PURE__ */ jsx(
1650
- TextInput,
1716
+ IconButton,
1651
1717
  {
1652
- value: page.translations?.[editingLocale]?.title ?? "",
1653
- onChange: (value) => updateManualTranslation({
1654
- locale: editingLocale,
1655
- kind: "page",
1656
- nodeId: page.id,
1657
- property: "title",
1658
- sourceText: page.title ?? "",
1659
- translatedText: value,
1660
- ...page.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
1661
- existingTranslationMetadata: page.translationMetadata[editingLocale]?.title
1662
- }
1663
- })
1718
+ actionType: "moveDown",
1719
+ title: translate("builder.moveDown", { title: page.title ?? page.id }),
1720
+ disabled: pageIndex === (schema.pages?.length ?? 0) - 1,
1721
+ onClick: () => movePage(pageIndex, 1)
1664
1722
  }
1665
- )
1666
- ] }),
1667
- /* @__PURE__ */ jsxs("label", { children: [
1668
- translate("builder.pageDescription"),
1723
+ ),
1669
1724
  /* @__PURE__ */ jsx(
1670
- TextInput,
1725
+ IconButton,
1671
1726
  {
1672
- value: page.translations?.[editingLocale]?.description ?? "",
1673
- onChange: (value) => updateManualTranslation({
1674
- locale: editingLocale,
1675
- kind: "page",
1676
- nodeId: page.id,
1677
- property: "description",
1678
- sourceText: page.description ?? "",
1679
- translatedText: value,
1680
- ...page.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
1681
- existingTranslationMetadata: page.translationMetadata[editingLocale]?.description
1682
- }
1683
- })
1727
+ actionType: "delete",
1728
+ title: translate("builder.delete", { title: page.title ?? page.id }),
1729
+ onClick: () => removePage(pageIndex)
1684
1730
  }
1685
1731
  )
1686
- ] })
1687
- ] })
1688
- ] }),
1689
- conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__condition", children: [
1690
- /* @__PURE__ */ jsxs("label", { children: [
1691
- translate("builder.pageCondition"),
1692
- /* @__PURE__ */ jsx(
1693
- Select,
1732
+ ] }) : /* @__PURE__ */ jsx(
1733
+ ToolbarSlot,
1694
1734
  {
1695
- value: page.displayCondition?.questionId ?? "",
1696
- onChange: (value) => {
1697
- const selected = schema.fields.find((field) => field.id === value);
1698
- updatePage(page.id, (current) => {
1699
- if (selected === void 0) {
1700
- const { displayCondition: _condition, ...withoutCondition } = current;
1701
- return withoutCondition;
1702
- }
1703
- return {
1704
- ...current,
1705
- displayCondition: conditionWithValue(
1706
- selected.id,
1707
- conditionOperators(selected)[0] ?? "not_empty",
1708
- defaultConditionValue(selected)
1709
- )
1710
- };
1711
- });
1712
- },
1713
- options: [
1714
- { value: "", label: translate("builder.alwaysVisible") },
1715
- ...availableSources.map((field) => ({ value: field.id, label: field.title }))
1716
- ]
1717
- }
1718
- )
1719
- ] }),
1720
- page.displayCondition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1721
- /* @__PURE__ */ jsx(
1722
- Select,
1723
- {
1724
- "aria-label": translate("builder.conditionOperator"),
1725
- value: page.displayCondition.operator,
1726
- onChange: (value) => {
1727
- const operator = value;
1728
- updatePage(page.id, (current) => ({
1729
- ...current,
1730
- displayCondition: conditionWithValue(
1731
- source.id,
1732
- operator,
1733
- defaultConditionValue(source)
1734
- )
1735
- }));
1736
- },
1737
- options: conditionOperators(source).map((operator) => ({
1738
- value: operator,
1739
- label: translate(operatorKey(operator))
1740
- }))
1741
- }
1742
- ),
1743
- /* @__PURE__ */ jsx(
1744
- ConditionValueEditor,
1745
- {
1746
- source,
1747
- condition: page.displayCondition,
1748
- onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1749
- translate,
1735
+ schema,
1736
+ kind: "page",
1737
+ targetId: page.id,
1738
+ index: pageIndex,
1739
+ total: schema.pages?.length ?? 0,
1740
+ title: page.title ?? page.id,
1741
+ onMoveUp: () => movePage(pageIndex, -1),
1742
+ onMoveDown: () => movePage(pageIndex, 1),
1743
+ onRemove: () => removePage(pageIndex),
1744
+ readOnly,
1745
+ actions,
1750
1746
  components
1751
1747
  }
1752
- )
1753
- ] }) : null
1754
- ] }) : null
1755
- ]
1748
+ ) }),
1749
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
1750
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1751
+ TextInput,
1752
+ {
1753
+ id: `builder-page-${page.id}-title`,
1754
+ label: translate("builder.pageTitle"),
1755
+ value: page.title ?? "",
1756
+ onChange: (value) => {
1757
+ updatePage(page.id, (current) => {
1758
+ if (value.length > 0) return { ...current, title: value };
1759
+ const { title: _title, ...withoutTitle } = current;
1760
+ return withoutTitle;
1761
+ });
1762
+ }
1763
+ }
1764
+ ) }),
1765
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1766
+ TextInput,
1767
+ {
1768
+ id: `builder-page-${page.id}-description`,
1769
+ label: translate("builder.pageDescription"),
1770
+ value: page.description ?? "",
1771
+ onChange: (value) => {
1772
+ updatePage(page.id, (current) => {
1773
+ if (value.length > 0) return { ...current, description: value };
1774
+ const { description: _description, ...withoutDescription } = current;
1775
+ return withoutDescription;
1776
+ });
1777
+ }
1778
+ }
1779
+ ) })
1780
+ ] }),
1781
+ !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
1782
+ /* @__PURE__ */ jsx("strong", { children: editingLocale }),
1783
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
1784
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1785
+ TextInput,
1786
+ {
1787
+ id: `builder-page-${page.id}-${editingLocale}-title`,
1788
+ label: translate("builder.pageTitle"),
1789
+ value: page.translations?.[editingLocale]?.title ?? "",
1790
+ onChange: (value) => updateManualTranslation({
1791
+ locale: editingLocale,
1792
+ kind: "page",
1793
+ nodeId: page.id,
1794
+ property: "title",
1795
+ sourceText: page.title ?? "",
1796
+ translatedText: value,
1797
+ ...page.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
1798
+ existingTranslationMetadata: page.translationMetadata[editingLocale]?.title
1799
+ }
1800
+ })
1801
+ }
1802
+ ) }),
1803
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1804
+ TextInput,
1805
+ {
1806
+ id: `builder-page-${page.id}-${editingLocale}-description`,
1807
+ label: translate("builder.pageDescription"),
1808
+ value: page.translations?.[editingLocale]?.description ?? "",
1809
+ onChange: (value) => updateManualTranslation({
1810
+ locale: editingLocale,
1811
+ kind: "page",
1812
+ nodeId: page.id,
1813
+ property: "description",
1814
+ sourceText: page.description ?? "",
1815
+ translatedText: value,
1816
+ ...page.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
1817
+ existingTranslationMetadata: page.translationMetadata[editingLocale]?.description
1818
+ }
1819
+ })
1820
+ }
1821
+ ) })
1822
+ ] })
1823
+ ] }),
1824
+ conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
1825
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1826
+ Select,
1827
+ {
1828
+ id: `builder-page-${page.id}-condition`,
1829
+ label: translate("builder.pageCondition"),
1830
+ value: page.displayCondition?.questionId ?? "",
1831
+ onChange: (value) => {
1832
+ const selected = schema.fields.find((field) => field.id === value);
1833
+ updatePage(page.id, (current) => {
1834
+ if (selected === void 0) {
1835
+ const { displayCondition: _condition, ...withoutCondition } = current;
1836
+ return withoutCondition;
1837
+ }
1838
+ return {
1839
+ ...current,
1840
+ displayCondition: conditionWithValue(
1841
+ selected.id,
1842
+ conditionOperators(selected)[0] ?? "not_empty",
1843
+ defaultConditionValue(selected)
1844
+ )
1845
+ };
1846
+ });
1847
+ },
1848
+ options: [
1849
+ { value: "", label: translate("builder.alwaysVisible") },
1850
+ ...availableSources.map((field) => ({ value: field.id, label: field.title }))
1851
+ ]
1852
+ }
1853
+ ) }),
1854
+ page.displayCondition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1855
+ /* @__PURE__ */ jsx(
1856
+ Select,
1857
+ {
1858
+ "aria-label": translate("builder.conditionOperator"),
1859
+ value: page.displayCondition.operator,
1860
+ onChange: (value) => {
1861
+ const operator = value;
1862
+ updatePage(page.id, (current) => ({
1863
+ ...current,
1864
+ displayCondition: conditionWithValue(
1865
+ source.id,
1866
+ operator,
1867
+ defaultConditionValue(source)
1868
+ )
1869
+ }));
1870
+ },
1871
+ options: conditionOperators(source).map((operator) => ({
1872
+ value: operator,
1873
+ label: translate(operatorKey(operator))
1874
+ }))
1875
+ }
1876
+ ),
1877
+ /* @__PURE__ */ jsx(
1878
+ ConditionValueEditor,
1879
+ {
1880
+ source,
1881
+ condition: page.displayCondition,
1882
+ onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1883
+ translate,
1884
+ components
1885
+ }
1886
+ )
1887
+ ] }) : null
1888
+ ] }) : null
1889
+ ]
1890
+ },
1891
+ page.id
1892
+ );
1893
+ }),
1894
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__page-add"), children: [
1895
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1896
+ Select,
1897
+ {
1898
+ id: "builder-page-question",
1899
+ label: translate("builder.pageQuestion"),
1900
+ value: newPageQuestionId,
1901
+ disabled: movablePageQuestions.length === 0,
1902
+ onChange: setNewPageQuestionId,
1903
+ options: [
1904
+ { value: "", label: "\u2014" },
1905
+ ...schema.fields.filter((field) => movablePageQuestions.includes(field.id)).map((field) => ({ value: field.id, label: field.title }))
1906
+ ]
1907
+ }
1908
+ ) }),
1909
+ /* @__PURE__ */ jsx(Button, { disabled: movablePageQuestions.length === 0, onClick: addPage, children: translate("builder.addPage") })
1910
+ ] })
1911
+ ] })
1912
+ }
1913
+ ) : /* @__PURE__ */ jsx(
1914
+ PagesSlot,
1915
+ {
1916
+ schema,
1917
+ currentLocale: editingLocale,
1918
+ readOnly,
1919
+ actions,
1920
+ components
1921
+ }
1922
+ ) : null,
1923
+ localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ jsxs(
1924
+ Section,
1925
+ {
1926
+ className: builderClass("form-engine-builder__localization"),
1927
+ headingId: "builder-localization-heading",
1928
+ title: translate("builder.localization"),
1929
+ children: [
1930
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1931
+ TextInput,
1932
+ {
1933
+ id: "builder-completion-message",
1934
+ label: translate("builder.completionMessage"),
1935
+ value: schema.completionMessage ?? "",
1936
+ onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1937
+ }
1938
+ ) }),
1939
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
1940
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1941
+ TextInput,
1942
+ {
1943
+ id: "builder-default-locale",
1944
+ label: translate("builder.defaultLocale"),
1945
+ value: schema.defaultLocale ?? "",
1946
+ onChange: setDefaultLocale
1947
+ }
1948
+ ) }),
1949
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: availableAllowedLocales === void 0 ? /* @__PURE__ */ jsx(
1950
+ TextInput,
1951
+ {
1952
+ id: "builder-new-locale",
1953
+ label: translate("builder.addLocale"),
1954
+ value: newLocale,
1955
+ onChange: setNewLocale
1956
+ }
1957
+ ) : /* @__PURE__ */ jsx(
1958
+ Select,
1959
+ {
1960
+ id: "builder-new-locale",
1961
+ label: translate("builder.addLocale"),
1962
+ value: newLocale,
1963
+ onChange: setNewLocale,
1964
+ options: [
1965
+ { value: "", label: "\u2014" },
1966
+ ...availableAllowedLocales.map((candidate) => ({ value: candidate, label: candidate }))
1967
+ ]
1968
+ }
1969
+ ) }),
1970
+ /* @__PURE__ */ jsx(
1971
+ Button,
1972
+ {
1973
+ action: "addLocale",
1974
+ disabled: newLocale.trim().length === 0 || localeLimitReached,
1975
+ onClick: addLocale,
1976
+ children: translate("builder.addLocale")
1977
+ }
1978
+ ),
1979
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1980
+ Select,
1981
+ {
1982
+ id: "builder-edit-locale",
1983
+ label: translate("builder.editLocale"),
1984
+ value: editingLocale,
1985
+ onChange: setEditingLocale,
1986
+ options: [
1987
+ { value: "", label: "\u2014" },
1988
+ ...(schema.supportedLocales ?? []).filter((item) => item !== schema.defaultLocale).map((item) => ({ value: item, label: item }))
1989
+ ]
1990
+ }
1991
+ ) }),
1992
+ TranslationActionsSlot === void 0 ? /* @__PURE__ */ jsx(
1993
+ Button,
1994
+ {
1995
+ disabled: translationAdapter === void 0 || editingLocale.length === 0 || isTranslating,
1996
+ onClick: () => void translateAll(),
1997
+ children: translate("builder.autoTranslate")
1998
+ }
1999
+ ) : /* @__PURE__ */ jsx(
2000
+ TranslationActionsSlot,
2001
+ {
2002
+ schema,
2003
+ currentLocale: editingLocale,
2004
+ onAutoTranslate: () => void translateAll(),
2005
+ isTranslating,
2006
+ ...translationError === null ? {} : { translationError },
2007
+ ...translationReport === void 0 ? {} : { translationReport },
2008
+ onClearTranslationError: () => setTranslationError(null),
2009
+ readOnly,
2010
+ actions,
2011
+ components
2012
+ }
2013
+ )
2014
+ ] }),
2015
+ translationAdapter === void 0 ? /* @__PURE__ */ jsx("p", { children: translate("builder.translationUnavailable") }) : null,
2016
+ translationError === null ? null : /* @__PURE__ */ jsx(ErrorMessage, { message: translationError }),
2017
+ editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2018
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2019
+ TextInput,
2020
+ {
2021
+ id: `builder-${editingLocale}-form-title`,
2022
+ label: translate("builder.questionTitle"),
2023
+ value: schema.translations?.[editingLocale]?.title ?? "",
2024
+ onChange: (value) => updateFormTranslation("title", value)
2025
+ }
2026
+ ) }),
2027
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2028
+ TextInput,
2029
+ {
2030
+ id: `builder-${editingLocale}-form-description`,
2031
+ label: translate("builder.pageDescription"),
2032
+ value: schema.translations?.[editingLocale]?.description ?? "",
2033
+ onChange: (value) => updateFormTranslation("description", value)
2034
+ }
2035
+ ) }),
2036
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2037
+ TextInput,
2038
+ {
2039
+ id: `builder-${editingLocale}-completion-message`,
2040
+ label: translate("builder.completionMessage"),
2041
+ value: schema.translations?.[editingLocale]?.completionMessage ?? "",
2042
+ onChange: (value) => updateFormTranslation("completionMessage", value)
2043
+ }
2044
+ ) })
2045
+ ] })
2046
+ ]
2047
+ }
2048
+ ) : /* @__PURE__ */ jsx(
2049
+ LocalizationSlot,
2050
+ {
2051
+ schema,
2052
+ currentLocale: editingLocale,
2053
+ onCurrentLocaleChange: setEditingLocale,
2054
+ onAutoTranslate: () => void translateAll(),
2055
+ isTranslating,
2056
+ ...translationError === null ? {} : { translationError },
2057
+ readOnly,
2058
+ actions,
2059
+ components
2060
+ }
2061
+ ) : null,
2062
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
2063
+ const condition = field.displayCondition;
2064
+ const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
2065
+ const availableSources = schema.fields.slice(0, index);
2066
+ if (FieldEditorSlot !== void 0) {
2067
+ return /* @__PURE__ */ jsx(
2068
+ FieldEditorSlot,
2069
+ {
2070
+ schema,
2071
+ field,
2072
+ index,
2073
+ currentLocale: editingLocale,
2074
+ ...policy === void 0 ? {} : { policy },
2075
+ readOnly,
2076
+ actions,
2077
+ components
1756
2078
  },
1757
- page.id
2079
+ field.id
1758
2080
  );
1759
- }),
1760
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__page-add", children: [
1761
- /* @__PURE__ */ jsxs("label", { children: [
1762
- translate("builder.pageQuestion"),
2081
+ }
2082
+ return /* @__PURE__ */ jsxs(Fieldset, { className: builderClass("form-engine-builder__question"), legend: field.title, children: [
2083
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__toolbar"), children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1763
2084
  /* @__PURE__ */ jsx(
1764
- Select,
2085
+ IconButton,
1765
2086
  {
1766
- value: newPageQuestionId,
1767
- disabled: movablePageQuestions.length === 0,
1768
- onChange: setNewPageQuestionId,
1769
- options: [
1770
- { value: "", label: "\u2014" },
1771
- ...schema.fields.filter((field) => movablePageQuestions.includes(field.id)).map((field) => ({ value: field.id, label: field.title }))
1772
- ]
2087
+ actionType: "moveUp",
2088
+ title: translate("builder.moveUp", { title: field.title }),
2089
+ disabled: index === 0,
2090
+ onClick: () => moveField(index, -1)
1773
2091
  }
1774
- )
1775
- ] }),
1776
- /* @__PURE__ */ jsx(Button, { disabled: movablePageQuestions.length === 0, onClick: addPage, children: translate("builder.addPage") })
1777
- ] })
1778
- ] })
1779
- }
1780
- ) : /* @__PURE__ */ jsx(
1781
- PagesSlot,
1782
- {
1783
- schema,
1784
- currentLocale: editingLocale,
1785
- readOnly,
1786
- actions,
1787
- components
1788
- }
1789
- ) : null,
1790
- localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ jsxs(
1791
- Section,
1792
- {
1793
- className: "form-engine-builder__localization",
1794
- headingId: "builder-localization-heading",
1795
- title: translate("builder.localization"),
1796
- children: [
1797
- /* @__PURE__ */ jsxs("label", { children: [
1798
- translate("builder.completionMessage"),
1799
- /* @__PURE__ */ jsx(
1800
- TextInput,
1801
- {
1802
- value: schema.completionMessage ?? "",
1803
- onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1804
- }
1805
- )
1806
- ] }),
1807
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1808
- /* @__PURE__ */ jsxs("label", { children: [
1809
- translate("builder.defaultLocale"),
1810
- /* @__PURE__ */ jsx(TextInput, { value: schema.defaultLocale ?? "", onChange: setDefaultLocale })
1811
- ] }),
1812
- /* @__PURE__ */ jsxs("label", { htmlFor: "builder-new-locale", children: [
1813
- translate("builder.addLocale"),
1814
- availableAllowedLocales === void 0 ? /* @__PURE__ */ jsx(TextInput, { id: "builder-new-locale", value: newLocale, onChange: setNewLocale }) : /* @__PURE__ */ jsx(
1815
- Select,
2092
+ ),
2093
+ /* @__PURE__ */ jsx(
2094
+ IconButton,
1816
2095
  {
1817
- id: "builder-new-locale",
1818
- value: newLocale,
1819
- onChange: setNewLocale,
1820
- options: [
1821
- { value: "", label: "\u2014" },
1822
- ...availableAllowedLocales.map((candidate) => ({ value: candidate, label: candidate }))
1823
- ]
2096
+ actionType: "moveDown",
2097
+ title: translate("builder.moveDown", { title: field.title }),
2098
+ disabled: index === schema.fields.length - 1,
2099
+ onClick: () => moveField(index, 1)
1824
2100
  }
1825
- )
1826
- ] }),
1827
- /* @__PURE__ */ jsx(
1828
- Button,
1829
- {
1830
- action: "addLocale",
1831
- disabled: newLocale.trim().length === 0 || localeLimitReached,
1832
- onClick: addLocale,
1833
- children: translate("builder.addLocale")
1834
- }
1835
- ),
1836
- /* @__PURE__ */ jsxs("label", { children: [
1837
- translate("builder.editLocale"),
2101
+ ),
1838
2102
  /* @__PURE__ */ jsx(
1839
- Select,
2103
+ IconButton,
1840
2104
  {
1841
- value: editingLocale,
1842
- onChange: setEditingLocale,
1843
- options: [
1844
- { value: "", label: "\u2014" },
1845
- ...(schema.supportedLocales ?? []).filter((item) => item !== schema.defaultLocale).map((item) => ({ value: item, label: item }))
1846
- ]
2105
+ actionType: "delete",
2106
+ disabled: schema.fields.length === 1,
2107
+ onClick: () => removeField(field.id),
2108
+ "aria-label": translate("builder.delete", { title: field.title }),
2109
+ title: translate("builder.delete", { title: field.title })
1847
2110
  }
1848
2111
  )
1849
- ] }),
1850
- TranslationActionsSlot === void 0 ? /* @__PURE__ */ jsx(
1851
- Button,
1852
- {
1853
- disabled: translationAdapter === void 0 || editingLocale.length === 0 || isTranslating,
1854
- onClick: () => void translateAll(),
1855
- children: translate("builder.autoTranslate")
1856
- }
1857
- ) : /* @__PURE__ */ jsx(
1858
- TranslationActionsSlot,
2112
+ ] }) : /* @__PURE__ */ jsx(
2113
+ ToolbarSlot,
1859
2114
  {
1860
2115
  schema,
1861
- currentLocale: editingLocale,
1862
- onAutoTranslate: () => void translateAll(),
1863
- isTranslating,
1864
- ...translationError === null ? {} : { translationError },
1865
- ...translationReport === void 0 ? {} : { translationReport },
1866
- onClearTranslationError: () => setTranslationError(null),
2116
+ kind: "field",
2117
+ targetId: field.id,
2118
+ index,
2119
+ total: schema.fields.length,
2120
+ title: field.title,
2121
+ onMoveUp: () => moveField(index, -1),
2122
+ onMoveDown: () => moveField(index, 1),
2123
+ onRemove: () => removeField(field.id),
1867
2124
  readOnly,
1868
2125
  actions,
1869
2126
  components
1870
2127
  }
1871
- )
1872
- ] }),
1873
- translationAdapter === void 0 ? /* @__PURE__ */ jsx("p", { children: translate("builder.translationUnavailable") }) : null,
1874
- translationError === null ? null : /* @__PURE__ */ jsx(ErrorMessage, { message: translationError }),
1875
- editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1876
- /* @__PURE__ */ jsxs("label", { children: [
1877
- translate("builder.questionTitle"),
1878
- /* @__PURE__ */ jsx(
2128
+ ) }),
2129
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2130
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1879
2131
  TextInput,
1880
2132
  {
1881
- value: schema.translations?.[editingLocale]?.title ?? "",
1882
- onChange: (value) => updateFormTranslation("title", value)
2133
+ id: `builder-field-${field.id}-title`,
2134
+ name: `fields.${field.id}.title`,
2135
+ label: translate("builder.questionTitle"),
2136
+ required: true,
2137
+ error: field.title.trim().length === 0,
2138
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2139
+ "aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
2140
+ value: field.title,
2141
+ placeholder: translate("builder.questionTitlePlaceholder"),
2142
+ onChange: (value) => updateField(field.id, (current) => ({
2143
+ ...current,
2144
+ title: value.trim().length === 0 ? current.title : value
2145
+ }))
1883
2146
  }
1884
- )
1885
- ] }),
1886
- /* @__PURE__ */ jsxs("label", { children: [
1887
- translate("builder.pageDescription"),
1888
- /* @__PURE__ */ jsx(
1889
- TextInput,
2147
+ ) }),
2148
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2149
+ Select,
1890
2150
  {
1891
- value: schema.translations?.[editingLocale]?.description ?? "",
1892
- onChange: (value) => updateFormTranslation("description", value)
2151
+ id: `builder-field-${field.id}-type`,
2152
+ label: translate("builder.type"),
2153
+ value: field.type,
2154
+ onChange: (value) => changeType(field.id, value),
2155
+ options: FIELD_TYPES.filter(
2156
+ (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2157
+ ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
1893
2158
  }
1894
- )
1895
- ] }),
1896
- /* @__PURE__ */ jsxs("label", { children: [
1897
- translate("builder.completionMessage"),
2159
+ ) }),
1898
2160
  /* @__PURE__ */ jsx(
1899
- TextInput,
2161
+ Checkbox,
1900
2162
  {
1901
- value: schema.translations?.[editingLocale]?.completionMessage ?? "",
1902
- onChange: (value) => updateFormTranslation("completionMessage", value)
2163
+ className: builderClass("form-engine-builder__check"),
2164
+ checked: field.required === true,
2165
+ onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2166
+ label: translate("builder.required")
1903
2167
  }
1904
2168
  )
1905
- ] })
1906
- ] })
1907
- ]
1908
- }
1909
- ) : /* @__PURE__ */ jsx(
1910
- LocalizationSlot,
1911
- {
1912
- schema,
1913
- currentLocale: editingLocale,
1914
- onCurrentLocaleChange: setEditingLocale,
1915
- onAutoTranslate: () => void translateAll(),
1916
- isTranslating,
1917
- ...translationError === null ? {} : { translationError },
1918
- readOnly,
1919
- actions,
1920
- components
1921
- }
1922
- ) : null,
1923
- /* @__PURE__ */ jsx("div", { className: "form-engine-builder__list", children: schema.fields.map((field, index) => {
1924
- const condition = field.displayCondition;
1925
- const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
1926
- const availableSources = schema.fields.slice(0, index);
1927
- if (FieldEditorSlot !== void 0) {
1928
- return /* @__PURE__ */ jsx(
1929
- FieldEditorSlot,
1930
- {
1931
- schema,
1932
- field,
1933
- index,
1934
- currentLocale: editingLocale,
1935
- ...policy === void 0 ? {} : { policy },
1936
- readOnly,
1937
- actions,
1938
- components
1939
- },
1940
- field.id
1941
- );
1942
- }
1943
- return /* @__PURE__ */ jsxs(Fieldset, { className: "form-engine-builder__question", legend: field.title, children: [
1944
- /* @__PURE__ */ jsx("div", { className: "form-engine-builder__toolbar", children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1945
- /* @__PURE__ */ jsx(
1946
- IconButton,
1947
- {
1948
- icon: "\u2191",
1949
- title: translate("builder.moveUp", { title: field.title }),
1950
- disabled: index === 0,
1951
- onClick: () => moveField(index, -1)
1952
- }
1953
- ),
1954
- /* @__PURE__ */ jsx(
1955
- IconButton,
1956
- {
1957
- icon: "\u2193",
1958
- title: translate("builder.moveDown", { title: field.title }),
1959
- disabled: index === schema.fields.length - 1,
1960
- onClick: () => moveField(index, 1)
1961
- }
1962
- ),
1963
- /* @__PURE__ */ jsx(
1964
- Button,
1965
- {
1966
- disabled: schema.fields.length === 1,
1967
- onClick: () => removeField(field.id),
1968
- "aria-label": translate("builder.delete", { title: field.title }),
1969
- variant: "danger",
1970
- children: translate("builder.deleteAction")
1971
- }
1972
- )
1973
- ] }) : /* @__PURE__ */ jsx(
1974
- ToolbarSlot,
1975
- {
1976
- schema,
1977
- kind: "field",
1978
- targetId: field.id,
1979
- index,
1980
- total: schema.fields.length,
1981
- title: field.title,
1982
- onMoveUp: () => moveField(index, -1),
1983
- onMoveDown: () => moveField(index, 1),
1984
- onRemove: () => removeField(field.id),
1985
- readOnly,
1986
- actions,
1987
- components
1988
- }
1989
- ) }),
1990
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1991
- /* @__PURE__ */ jsxs("label", { children: [
1992
- translate("builder.questionTitle"),
1993
- /* @__PURE__ */ jsx(
1994
- TextInput,
1995
- {
1996
- name: `fields.${field.id}.title`,
1997
- label: translate("builder.questionTitle"),
1998
- required: true,
1999
- error: field.title.trim().length === 0,
2000
- helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2001
- value: field.title,
2002
- placeholder: translate("builder.questionTitlePlaceholder"),
2003
- onChange: (value) => updateField(field.id, (current) => ({
2004
- ...current,
2005
- title: value.trim().length === 0 ? current.title : value
2006
- }))
2007
- }
2008
- )
2009
- ] }),
2010
- /* @__PURE__ */ jsxs("label", { children: [
2011
- translate("builder.type"),
2012
- /* @__PURE__ */ jsx(
2169
+ ] }),
2170
+ !pagesEnabled || schema.pages === void 0 ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2013
2171
  Select,
2014
2172
  {
2015
- value: field.type,
2016
- onChange: (value) => changeType(field.id, value),
2017
- options: FIELD_TYPES.filter(
2018
- (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2019
- ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
2173
+ id: `builder-field-${field.id}-page`,
2174
+ label: translate("builder.questionPage"),
2175
+ value: pageForField(field.id)?.id ?? "",
2176
+ onChange: (value) => assignFieldToPage(field.id, value),
2177
+ options: schema.pages.map((page, pageIndex) => ({
2178
+ value: page.id,
2179
+ label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2180
+ }))
2020
2181
  }
2021
- )
2022
- ] }),
2023
- /* @__PURE__ */ jsx(
2024
- Checkbox,
2025
- {
2026
- className: "form-engine-builder__check",
2027
- checked: field.required === true,
2028
- onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2029
- label: translate("builder.required")
2030
- }
2031
- )
2032
- ] }),
2033
- !pagesEnabled || schema.pages === void 0 ? null : /* @__PURE__ */ jsxs("label", { children: [
2034
- translate("builder.questionPage"),
2035
- /* @__PURE__ */ jsx(
2036
- Select,
2037
- {
2038
- value: pageForField(field.id)?.id ?? "",
2039
- onChange: (value) => assignFieldToPage(field.id, value),
2040
- options: schema.pages.map((page, pageIndex) => ({
2041
- value: page.id,
2042
- label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2043
- }))
2044
- }
2045
- )
2046
- ] }),
2047
- !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__translation-editor", children: [
2048
- /* @__PURE__ */ jsx("strong", { children: editingLocale }),
2049
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
2050
- /* @__PURE__ */ jsxs("label", { children: [
2051
- translate("builder.questionTitle"),
2052
- /* @__PURE__ */ jsx(
2182
+ ) }),
2183
+ !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
2184
+ /* @__PURE__ */ jsx("strong", { children: editingLocale }),
2185
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2186
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2187
+ TextInput,
2188
+ {
2189
+ id: `builder-field-${field.id}-${editingLocale}-title`,
2190
+ label: translate("builder.questionTitle"),
2191
+ value: field.translations?.[editingLocale]?.title ?? "",
2192
+ onChange: (value) => updateManualTranslation({
2193
+ locale: editingLocale,
2194
+ kind: "field",
2195
+ nodeId: field.id,
2196
+ property: "title",
2197
+ sourceText: field.title,
2198
+ translatedText: value,
2199
+ ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2200
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2201
+ }
2202
+ })
2203
+ }
2204
+ ) }),
2205
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2206
+ TextInput,
2207
+ {
2208
+ id: `builder-field-${field.id}-${editingLocale}-description`,
2209
+ label: translate("builder.pageDescription"),
2210
+ value: field.translations?.[editingLocale]?.description ?? "",
2211
+ onChange: (value) => updateManualTranslation({
2212
+ locale: editingLocale,
2213
+ kind: "field",
2214
+ nodeId: field.id,
2215
+ property: "description",
2216
+ sourceText: field.description ?? "",
2217
+ translatedText: value,
2218
+ ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2219
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2220
+ }
2221
+ })
2222
+ }
2223
+ ) })
2224
+ ] }),
2225
+ "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2053
2226
  TextInput,
2054
2227
  {
2055
- value: field.translations?.[editingLocale]?.title ?? "",
2228
+ id: `builder-option-${option.id}-${editingLocale}`,
2229
+ label: `${translate("builder.optionLabel", { index: optionIndex + 1 })} (${editingLocale})`,
2230
+ value: option.translations?.[editingLocale] ?? "",
2056
2231
  onChange: (value) => updateManualTranslation({
2057
2232
  locale: editingLocale,
2058
- kind: "field",
2059
- nodeId: field.id,
2060
- property: "title",
2061
- sourceText: field.title,
2233
+ kind: "option",
2234
+ nodeId: option.id,
2235
+ property: "label",
2236
+ sourceText: option.label,
2062
2237
  translatedText: value,
2063
- ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2064
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2238
+ ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2239
+ existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2065
2240
  }
2066
2241
  })
2067
2242
  }
2068
- )
2243
+ ) }, option.id)) : null
2069
2244
  ] }),
2070
- /* @__PURE__ */ jsxs("label", { children: [
2071
- translate("builder.pageDescription"),
2072
- /* @__PURE__ */ jsx(
2245
+ field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2246
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2073
2247
  TextInput,
2074
2248
  {
2075
- value: field.translations?.[editingLocale]?.description ?? "",
2076
- onChange: (value) => updateManualTranslation({
2077
- locale: editingLocale,
2078
- kind: "field",
2079
- nodeId: field.id,
2080
- property: "description",
2081
- sourceText: field.description ?? "",
2082
- translatedText: value,
2083
- ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2084
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2085
- }
2086
- })
2087
- }
2088
- )
2089
- ] })
2090
- ] }),
2091
- "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsxs("label", { children: [
2092
- translate("builder.optionLabel", { index: optionIndex + 1 }),
2093
- " (",
2094
- editingLocale,
2095
- ")",
2096
- /* @__PURE__ */ jsx(
2097
- TextInput,
2098
- {
2099
- value: option.translations?.[editingLocale] ?? "",
2100
- onChange: (value) => updateManualTranslation({
2101
- locale: editingLocale,
2102
- kind: "option",
2103
- nodeId: option.id,
2104
- property: "label",
2105
- sourceText: option.label,
2106
- translatedText: value,
2107
- ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2108
- existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2249
+ id: `builder-field-${field.id}-minimum`,
2250
+ label: translate("builder.minimum"),
2251
+ type: "number",
2252
+ value: String(field.min ?? 1),
2253
+ onChange: (value) => {
2254
+ const min = Number(value);
2255
+ if (!Number.isInteger(min)) return;
2256
+ updateField(
2257
+ field.id,
2258
+ (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2259
+ );
2109
2260
  }
2110
- })
2111
- }
2112
- )
2113
- ] }, option.id)) : null
2114
- ] }),
2115
- field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
2116
- /* @__PURE__ */ jsxs("label", { children: [
2117
- translate("builder.minimum"),
2118
- /* @__PURE__ */ jsx(
2119
- TextInput,
2120
- {
2121
- type: "number",
2122
- value: String(field.min ?? 1),
2123
- onChange: (value) => {
2124
- const min = Number(value);
2125
- if (!Number.isInteger(min)) return;
2126
- updateField(
2127
- field.id,
2128
- (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2129
- );
2130
2261
  }
2131
- }
2132
- )
2133
- ] }),
2134
- /* @__PURE__ */ jsxs("label", { children: [
2135
- translate("builder.maximum"),
2136
- /* @__PURE__ */ jsx(
2137
- TextInput,
2138
- {
2139
- type: "number",
2140
- value: String(field.max ?? 5),
2141
- onChange: (value) => {
2142
- const max = Number(value);
2143
- if (!Number.isInteger(max)) return;
2144
- updateField(
2145
- field.id,
2146
- (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2147
- );
2148
- }
2149
- }
2150
- )
2151
- ] })
2152
- ] }) : null,
2153
- "options" in field ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__options", children: [
2154
- /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
2155
- field.options.map(
2156
- (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__option", children: [
2157
- /* @__PURE__ */ jsx(
2262
+ ) }),
2263
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2158
2264
  TextInput,
2159
2265
  {
2160
- "aria-label": translate("builder.optionLabel", { index: optionIndex + 1 }),
2161
- value: option.label,
2162
- placeholder: translate("builder.optionLabelPlaceholder"),
2163
- onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2266
+ id: `builder-field-${field.id}-maximum`,
2267
+ label: translate("builder.maximum"),
2268
+ type: "number",
2269
+ value: String(field.max ?? 5),
2270
+ onChange: (value) => {
2271
+ const max = Number(value);
2272
+ if (!Number.isInteger(max)) return;
2273
+ updateField(
2274
+ field.id,
2275
+ (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2276
+ );
2277
+ }
2164
2278
  }
2165
- ),
2166
- ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2167
- /* @__PURE__ */ jsx(
2168
- IconButton,
2279
+ ) })
2280
+ ] }) : null,
2281
+ "options" in field ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__options"), children: [
2282
+ /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
2283
+ field.options.map(
2284
+ (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__option"), children: [
2285
+ /* @__PURE__ */ jsx(
2286
+ TextInput,
2287
+ {
2288
+ id: `builder-option-${option.id}`,
2289
+ label: translate("builder.optionLabel", { index: optionIndex + 1 }),
2290
+ value: option.label,
2291
+ placeholder: translate("builder.optionLabelPlaceholder"),
2292
+ onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2293
+ }
2294
+ ),
2295
+ ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2296
+ /* @__PURE__ */ jsx(
2297
+ IconButton,
2298
+ {
2299
+ actionType: "moveUp",
2300
+ title: translate("builder.moveUp", { title: option.label }),
2301
+ disabled: optionIndex === 0,
2302
+ onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2303
+ }
2304
+ ),
2305
+ /* @__PURE__ */ jsx(
2306
+ IconButton,
2307
+ {
2308
+ actionType: "moveDown",
2309
+ title: translate("builder.moveDown", { title: option.label }),
2310
+ disabled: optionIndex === field.options.length - 1,
2311
+ onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2312
+ }
2313
+ ),
2314
+ /* @__PURE__ */ jsx(
2315
+ IconButton,
2316
+ {
2317
+ actionType: "delete",
2318
+ disabled: field.options.length === 1,
2319
+ onClick: () => removeOption(field.id, option.id),
2320
+ title: translate("builder.remove")
2321
+ }
2322
+ )
2323
+ ] }) : /* @__PURE__ */ jsx(
2324
+ ToolbarSlot,
2325
+ {
2326
+ schema,
2327
+ kind: "option",
2328
+ targetId: option.id,
2329
+ index: optionIndex,
2330
+ total: field.options.length,
2331
+ title: option.label,
2332
+ onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2333
+ onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2334
+ onRemove: () => removeOption(field.id, option.id),
2335
+ readOnly,
2336
+ actions,
2337
+ components
2338
+ }
2339
+ )
2340
+ ] }, option.id) : /* @__PURE__ */ jsx(
2341
+ OptionEditorSlot,
2169
2342
  {
2170
- icon: "\u2191",
2171
- title: translate("builder.moveUp", { title: option.label }),
2172
- disabled: optionIndex === 0,
2173
- onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2174
- }
2175
- ),
2343
+ schema,
2344
+ field,
2345
+ option,
2346
+ index: optionIndex,
2347
+ currentLocale: editingLocale,
2348
+ readOnly,
2349
+ actions,
2350
+ components
2351
+ },
2352
+ option.id
2353
+ )
2354
+ ),
2355
+ /* @__PURE__ */ jsx(
2356
+ Button,
2357
+ {
2358
+ action: "addOption",
2359
+ targetId: field.id,
2360
+ disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2361
+ onClick: () => addOption(field.id),
2362
+ children: translate("builder.addOption")
2363
+ }
2364
+ )
2365
+ ] }) : null,
2366
+ conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
2367
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2368
+ Select,
2369
+ {
2370
+ id: `builder-field-${field.id}-condition`,
2371
+ label: translate("builder.displayCondition"),
2372
+ value: condition?.questionId ?? "",
2373
+ onChange: (value) => {
2374
+ const selected = schema.fields.find((item) => item.id === value);
2375
+ setDisplayCondition(
2376
+ field.id,
2377
+ selected === void 0 ? void 0 : conditionWithValue(
2378
+ selected.id,
2379
+ conditionOperators(selected)[0] ?? "not_empty",
2380
+ defaultConditionValue(selected)
2381
+ )
2382
+ );
2383
+ },
2384
+ options: [
2385
+ { value: "", label: translate("builder.alwaysVisible") },
2386
+ ...availableSources.map((candidate) => ({ value: candidate.id, label: candidate.title }))
2387
+ ]
2388
+ }
2389
+ ) }),
2390
+ condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2176
2391
  /* @__PURE__ */ jsx(
2177
- IconButton,
2392
+ Select,
2178
2393
  {
2179
- icon: "\u2193",
2180
- title: translate("builder.moveDown", { title: option.label }),
2181
- disabled: optionIndex === field.options.length - 1,
2182
- onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2394
+ "aria-label": translate("builder.conditionOperator"),
2395
+ value: condition.operator,
2396
+ onChange: (value) => {
2397
+ const operator = value;
2398
+ setDisplayCondition(
2399
+ field.id,
2400
+ conditionWithValue(source.id, operator, defaultConditionValue(source))
2401
+ );
2402
+ },
2403
+ options: conditionOperators(source).map((operator) => ({
2404
+ value: operator,
2405
+ label: translate(operatorKey(operator))
2406
+ }))
2183
2407
  }
2184
2408
  ),
2185
2409
  /* @__PURE__ */ jsx(
2186
- Button,
2410
+ ConditionValueEditor,
2187
2411
  {
2188
- disabled: field.options.length === 1,
2189
- onClick: () => removeOption(field.id, option.id),
2190
- variant: "danger",
2191
- children: translate("builder.remove")
2412
+ source,
2413
+ condition,
2414
+ onChange: (next) => setDisplayCondition(field.id, next),
2415
+ translate,
2416
+ components
2192
2417
  }
2193
2418
  )
2194
- ] }) : /* @__PURE__ */ jsx(
2195
- ToolbarSlot,
2196
- {
2197
- schema,
2198
- kind: "option",
2199
- targetId: option.id,
2200
- index: optionIndex,
2201
- total: field.options.length,
2202
- title: option.label,
2203
- onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2204
- onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2205
- onRemove: () => removeOption(field.id, option.id),
2206
- readOnly,
2207
- actions,
2208
- components
2209
- }
2210
- )
2211
- ] }, option.id) : /* @__PURE__ */ jsx(
2212
- OptionEditorSlot,
2213
- {
2214
- schema,
2215
- field,
2216
- option,
2217
- index: optionIndex,
2218
- currentLocale: editingLocale,
2219
- readOnly,
2220
- actions,
2221
- components
2222
- },
2223
- option.id
2224
- )
2225
- ),
2226
- /* @__PURE__ */ jsx(
2227
- Button,
2228
- {
2229
- action: "addOption",
2230
- targetId: field.id,
2231
- disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2232
- onClick: () => addOption(field.id),
2233
- children: translate("builder.addOption")
2234
- }
2235
- )
2236
- ] }) : null,
2237
- conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__condition", children: [
2238
- /* @__PURE__ */ jsxs("label", { children: [
2239
- translate("builder.displayCondition"),
2240
- /* @__PURE__ */ jsx(
2241
- Select,
2242
- {
2243
- value: condition?.questionId ?? "",
2244
- onChange: (value) => {
2245
- const selected = schema.fields.find((item) => item.id === value);
2246
- setDisplayCondition(
2247
- field.id,
2248
- selected === void 0 ? void 0 : conditionWithValue(
2249
- selected.id,
2250
- conditionOperators(selected)[0] ?? "not_empty",
2251
- defaultConditionValue(selected)
2252
- )
2253
- );
2254
- },
2255
- options: [
2256
- { value: "", label: translate("builder.alwaysVisible") },
2257
- ...availableSources.map((candidate) => ({ value: candidate.id, label: candidate.title }))
2258
- ]
2259
- }
2260
- )
2261
- ] }),
2262
- condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2263
- /* @__PURE__ */ jsx(
2264
- Select,
2265
- {
2266
- "aria-label": translate("builder.conditionOperator"),
2267
- value: condition.operator,
2268
- onChange: (value) => {
2269
- const operator = value;
2270
- setDisplayCondition(
2271
- field.id,
2272
- conditionWithValue(source.id, operator, defaultConditionValue(source))
2273
- );
2274
- },
2275
- options: conditionOperators(source).map((operator) => ({
2276
- value: operator,
2277
- label: translate(operatorKey(operator))
2278
- }))
2279
- }
2280
- ),
2281
- /* @__PURE__ */ jsx(
2282
- ConditionValueEditor,
2283
- {
2284
- source,
2285
- condition,
2286
- onChange: (next) => setDisplayCondition(field.id, next),
2287
- translate,
2288
- components
2289
- }
2290
- )
2291
- ] }) : null
2292
- ] }) : null
2293
- ] }, field.id);
2294
- }) }),
2295
- /* @__PURE__ */ jsx(
2296
- Button,
2297
- {
2298
- className: "form-engine-builder__add",
2299
- action: "addField",
2300
- disabled: initialFieldType === null || maxFieldsReached,
2301
- onClick: addField,
2302
- children: translate("builder.addQuestion")
2303
- }
2304
- )
2305
- ] })
2419
+ ] }) : null
2420
+ ] }) : null
2421
+ ] }, field.id);
2422
+ }) }),
2423
+ /* @__PURE__ */ jsx(
2424
+ Button,
2425
+ {
2426
+ className: builderClass("form-engine-builder__add"),
2427
+ action: "addField",
2428
+ disabled: initialFieldType === null || maxFieldsReached,
2429
+ onClick: addField,
2430
+ children: translate("builder.addQuestion")
2431
+ }
2432
+ )
2433
+ ] })
2434
+ }
2435
+ )
2306
2436
  }
2307
- ) });
2437
+ );
2308
2438
  }
2309
2439
 
2310
2440
  // src/context.tsx