@form-engine-ts/react 2.9.0 → 2.9.2

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