@form-engine-ts/react 2.1.0 → 2.1.1

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
@@ -748,6 +748,14 @@ function ConditionValueEditor({
748
748
  }
749
749
  );
750
750
  }
751
+ function resolveInitialFieldType(defaultType, allowedTypes) {
752
+ if (defaultType !== void 0 && (allowedTypes === void 0 || allowedTypes.includes(defaultType))) {
753
+ return defaultType;
754
+ }
755
+ if (allowedTypes !== void 0 && allowedTypes.length > 0) return allowedTypes[0] ?? null;
756
+ if (allowedTypes === void 0 || allowedTypes.includes("text")) return "text";
757
+ return null;
758
+ }
751
759
  function FormBuilder({
752
760
  schema,
753
761
  onChange,
@@ -758,7 +766,11 @@ function FormBuilder({
758
766
  onTranslationReport,
759
767
  policy,
760
768
  idFactory,
761
- factories
769
+ factories,
770
+ className = "",
771
+ defaultFieldType,
772
+ onActionError,
773
+ createManualTranslationMetadata
762
774
  }) {
763
775
  const headless = useFormBuilder({
764
776
  schema,
@@ -776,17 +788,40 @@ function FormBuilder({
776
788
  const translated = translator?.translate(key, locale, params);
777
789
  return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
778
790
  };
779
- const updateField = headless.updateField;
780
- const changeType = headless.changeFieldType;
781
- const removeField = headless.removeField;
791
+ const executeAction = (result, context) => {
792
+ if (!result.success) onActionError?.(result.error, context);
793
+ return result;
794
+ };
795
+ const updateField = (fieldId, updater, params) => executeAction(headless.updateField(fieldId, updater), {
796
+ action: "updateField",
797
+ targetId: fieldId,
798
+ ...params === void 0 ? {} : { params }
799
+ });
800
+ const changeType = (fieldId, type) => executeAction(headless.changeFieldType(fieldId, type), {
801
+ action: "changeFieldType",
802
+ targetId: fieldId,
803
+ params: { type }
804
+ });
805
+ const removeField = (fieldId) => executeAction(headless.removeField(fieldId), { action: "removeField", targetId: fieldId });
806
+ const initialFieldType = resolveInitialFieldType(defaultFieldType, policy?.allowedFieldTypes);
807
+ const maxFieldsReached = policy?.maxFields !== void 0 && schema.fields.length >= policy.maxFields;
782
808
  const moveField = (index, offset) => {
783
809
  const target = index + offset;
784
810
  const field = schema.fields[index];
785
- if (field !== void 0) headless.moveField(field.id, target);
811
+ if (field !== void 0) {
812
+ executeAction(headless.moveField(field.id, target), {
813
+ action: "moveField",
814
+ targetId: field.id,
815
+ params: { targetIndex: target }
816
+ });
817
+ }
818
+ };
819
+ const addField = () => {
820
+ if (initialFieldType === null) return;
821
+ executeAction(headless.addField(initialFieldType), { action: "addField" });
786
822
  };
787
- const addField = () => headless.addField("text");
788
823
  const enablePages = () => {
789
- if (schema.pages === void 0) headless.addPage();
824
+ if (schema.pages === void 0) executeAction(headless.addPage(), { action: "addPage" });
790
825
  };
791
826
  const pageForField = (fieldId) => schema.pages?.find((page) => page.questionIds.includes(fieldId));
792
827
  const movablePageQuestions = schema.pages?.flatMap((page) => page.questionIds.length > 1 ? page.questionIds : []) ?? [];
@@ -797,23 +832,37 @@ function FormBuilder({
797
832
  }
798
833
  const questionId = movablePageQuestions.includes(newPageQuestionId) ? newPageQuestionId : movablePageQuestions[0];
799
834
  if (questionId === void 0) return;
800
- headless.addPage(questionId);
835
+ executeAction(headless.addPage(questionId), {
836
+ action: "addPage",
837
+ targetId: questionId,
838
+ params: { questionId }
839
+ });
801
840
  setNewPageQuestionId("");
802
841
  };
803
842
  const removePage = (pageIndex) => {
804
843
  const page = schema.pages?.[pageIndex];
805
- if (page !== void 0) headless.removePage(page.id);
844
+ if (page !== void 0) executeAction(headless.removePage(page.id), { action: "removePage", targetId: page.id });
806
845
  };
807
846
  const movePage = (pageIndex, offset) => {
808
847
  const target = pageIndex + offset;
809
848
  const page = schema.pages?.[pageIndex];
810
- if (page !== void 0) headless.movePage(page.id, target);
849
+ if (page !== void 0) {
850
+ executeAction(headless.movePage(page.id, target), {
851
+ action: "movePage",
852
+ targetId: page.id,
853
+ params: { targetIndex: target }
854
+ });
855
+ }
811
856
  };
812
857
  const updatePage = (pageId, update) => {
813
858
  headless.updatePage(pageId, update);
814
859
  };
815
860
  const assignFieldToPage = (fieldId, pageId) => {
816
- headless.assignFieldToPage(fieldId, pageId);
861
+ executeAction(headless.assignFieldToPage(fieldId, pageId), {
862
+ action: "assignFieldToPage",
863
+ targetId: fieldId,
864
+ params: { pageId }
865
+ });
817
866
  };
818
867
  const addLocale = () => {
819
868
  const normalized = newLocale.trim();
@@ -827,12 +876,10 @@ function FormBuilder({
827
876
  setIsTranslating(true);
828
877
  setTranslationError(null);
829
878
  try {
830
- const populated = await populateSchemaTranslations(
831
- schema,
832
- [editingLocale],
833
- translationAdapter,
834
- translationOptions ?? { overwrite: "all" }
835
- );
879
+ const populated = await populateSchemaTranslations(schema, [editingLocale], translationAdapter, {
880
+ overwrite: "missing-only",
881
+ ...translationOptions
882
+ });
836
883
  onChange(populated.schema);
837
884
  onTranslationReport?.(populated.report);
838
885
  } catch (cause) {
@@ -841,28 +888,366 @@ function FormBuilder({
841
888
  setIsTranslating(false);
842
889
  }
843
890
  };
844
- const updateFormTranslation = (key, value) => {
891
+ const updateManualTranslation = (context) => {
892
+ const metadata = createManualTranslationMetadata?.(context);
893
+ const target = context.kind === "form" ? { kind: "form" } : { kind: context.kind, id: context.nodeId };
894
+ executeAction(
895
+ headless.setLocaleTranslation(
896
+ context.locale,
897
+ target,
898
+ context.property,
899
+ context.translatedText,
900
+ metadata === void 0 ? void 0 : { metadata }
901
+ ),
902
+ {
903
+ action: "setLocaleTranslation",
904
+ targetId: context.nodeId,
905
+ params: { locale: context.locale, kind: context.kind, property: context.property }
906
+ }
907
+ );
908
+ };
909
+ const updateFormTranslation = (property, translatedText) => {
845
910
  if (editingLocale.length === 0) return;
846
- headless.setLocaleTranslation(editingLocale, { kind: "form" }, key, value);
911
+ updateManualTranslation({
912
+ locale: editingLocale,
913
+ kind: "form",
914
+ nodeId: schema.id,
915
+ property,
916
+ sourceText: schema[property] ?? "",
917
+ translatedText,
918
+ ...schema.translationMetadata?.[editingLocale]?.[property] === void 0 ? {} : { existingTranslationMetadata: schema.translationMetadata[editingLocale]?.[property] }
919
+ });
847
920
  };
848
- return /* @__PURE__ */ jsxs("section", { className: "form-engine-builder", "aria-label": translate("builder.formBuilder"), children: [
849
- /* @__PURE__ */ jsxs("section", { className: "form-engine-builder__pages", "aria-labelledby": "builder-pages-heading", children: [
850
- /* @__PURE__ */ jsx("h2", { id: "builder-pages-heading", children: translate("builder.pages") }),
851
- schema.pages === void 0 ? /* @__PURE__ */ jsx("button", { type: "button", onClick: enablePages, children: translate("builder.enablePages") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
852
- schema.pages.map((page, pageIndex) => {
853
- const priorQuestionIds = new Set(schema.pages?.slice(0, pageIndex).flatMap((item) => item.questionIds));
854
- const availableSources = schema.fields.filter((field) => priorQuestionIds.has(field.id));
855
- const source = schema.fields.find((field) => field.id === page.displayCondition?.questionId);
856
- return /* @__PURE__ */ jsxs("fieldset", { className: "form-engine-builder__page", children: [
857
- /* @__PURE__ */ jsx("legend", { children: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}` }),
921
+ const setSourceText = (target, property, text) => executeAction(headless.setSourceText(target, property, text), {
922
+ action: "setSourceText",
923
+ ...target.id === void 0 ? {} : { targetId: target.id },
924
+ params: { kind: target.kind, property }
925
+ });
926
+ const updateOption = (fieldId, optionId, label) => executeAction(
927
+ headless.updateOption(fieldId, optionId, (option) => ({ ...option, label })),
928
+ { action: "updateOption", targetId: optionId, params: { fieldId } }
929
+ );
930
+ const addOption = (fieldId) => executeAction(headless.addOption(fieldId), { action: "addOption", targetId: fieldId });
931
+ const removeOption = (fieldId, optionId) => executeAction(headless.removeOption(fieldId, optionId), {
932
+ action: "removeOption",
933
+ targetId: optionId,
934
+ params: { fieldId }
935
+ });
936
+ const moveOption = (fieldId, optionId, targetIndex) => executeAction(headless.moveOption(fieldId, optionId, targetIndex), {
937
+ action: "moveOption",
938
+ targetId: optionId,
939
+ params: { fieldId, targetIndex }
940
+ });
941
+ const setDisplayCondition = (fieldId, condition) => executeAction(headless.setDisplayCondition(fieldId, condition), {
942
+ action: "setDisplayCondition",
943
+ targetId: fieldId,
944
+ ...condition === void 0 ? {} : { params: { condition } }
945
+ });
946
+ return /* @__PURE__ */ jsxs(
947
+ "section",
948
+ {
949
+ className: `form-engine-builder ${className}`.trim(),
950
+ "aria-label": translate("builder.formBuilder"),
951
+ onClickCapture: (event) => {
952
+ if (!(event.target instanceof HTMLElement)) return;
953
+ const actionTarget = event.target.closest("[data-builder-action]");
954
+ if (actionTarget?.dataset.builderAction === "addField" && maxFieldsReached && initialFieldType !== null)
955
+ addField();
956
+ if (actionTarget?.dataset.builderAction !== "addOption") return;
957
+ const fieldId = actionTarget.dataset.targetId;
958
+ const field = schema.fields.find((candidate) => candidate.id === fieldId);
959
+ if (fieldId !== void 0 && field !== void 0 && "options" in field && policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField) {
960
+ addOption(fieldId);
961
+ }
962
+ },
963
+ children: [
964
+ /* @__PURE__ */ jsxs("section", { className: "form-engine-builder__pages", "aria-labelledby": "builder-pages-heading", children: [
965
+ /* @__PURE__ */ jsx("h2", { id: "builder-pages-heading", children: translate("builder.pages") }),
966
+ schema.pages === void 0 ? /* @__PURE__ */ jsx("button", { type: "button", onClick: enablePages, children: translate("builder.enablePages") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
967
+ schema.pages.map((page, pageIndex) => {
968
+ const priorQuestionIds = new Set(schema.pages?.slice(0, pageIndex).flatMap((item) => item.questionIds));
969
+ const availableSources = schema.fields.filter((field) => priorQuestionIds.has(field.id));
970
+ const source = schema.fields.find((field) => field.id === page.displayCondition?.questionId);
971
+ return /* @__PURE__ */ jsxs("fieldset", { className: "form-engine-builder__page", children: [
972
+ /* @__PURE__ */ jsx("legend", { children: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}` }),
973
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__toolbar", children: [
974
+ /* @__PURE__ */ jsx(
975
+ "button",
976
+ {
977
+ type: "button",
978
+ disabled: pageIndex === 0,
979
+ "aria-label": translate("builder.moveUp", { title: page.title ?? page.id }),
980
+ onClick: () => movePage(pageIndex, -1),
981
+ children: "\u2191"
982
+ }
983
+ ),
984
+ /* @__PURE__ */ jsx(
985
+ "button",
986
+ {
987
+ type: "button",
988
+ disabled: pageIndex === (schema.pages?.length ?? 0) - 1,
989
+ "aria-label": translate("builder.moveDown", { title: page.title ?? page.id }),
990
+ onClick: () => movePage(pageIndex, 1),
991
+ children: "\u2193"
992
+ }
993
+ ),
994
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => removePage(pageIndex), children: translate("builder.deleteAction") })
995
+ ] }),
996
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
997
+ /* @__PURE__ */ jsxs("label", { children: [
998
+ translate("builder.pageTitle"),
999
+ /* @__PURE__ */ jsx(
1000
+ "input",
1001
+ {
1002
+ value: page.title ?? "",
1003
+ onChange: (event) => {
1004
+ const value = event.currentTarget.value;
1005
+ updatePage(page.id, (current) => {
1006
+ if (value.length > 0) return { ...current, title: value };
1007
+ const { title: _title, ...withoutTitle } = current;
1008
+ return withoutTitle;
1009
+ });
1010
+ }
1011
+ }
1012
+ )
1013
+ ] }),
1014
+ /* @__PURE__ */ jsxs("label", { children: [
1015
+ translate("builder.pageDescription"),
1016
+ /* @__PURE__ */ jsx(
1017
+ "input",
1018
+ {
1019
+ value: page.description ?? "",
1020
+ onChange: (event) => {
1021
+ const value = event.currentTarget.value;
1022
+ updatePage(page.id, (current) => {
1023
+ if (value.length > 0) return { ...current, description: value };
1024
+ const { description: _description, ...withoutDescription } = current;
1025
+ return withoutDescription;
1026
+ });
1027
+ }
1028
+ }
1029
+ )
1030
+ ] })
1031
+ ] }),
1032
+ editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__translation-editor", children: [
1033
+ /* @__PURE__ */ jsx("strong", { children: editingLocale }),
1034
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1035
+ /* @__PURE__ */ jsxs("label", { children: [
1036
+ translate("builder.pageTitle"),
1037
+ /* @__PURE__ */ jsx(
1038
+ "input",
1039
+ {
1040
+ value: page.translations?.[editingLocale]?.title ?? "",
1041
+ onChange: (event) => updateManualTranslation({
1042
+ locale: editingLocale,
1043
+ kind: "page",
1044
+ nodeId: page.id,
1045
+ property: "title",
1046
+ sourceText: page.title ?? "",
1047
+ translatedText: event.currentTarget.value,
1048
+ ...page.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
1049
+ existingTranslationMetadata: page.translationMetadata[editingLocale]?.title
1050
+ }
1051
+ })
1052
+ }
1053
+ )
1054
+ ] }),
1055
+ /* @__PURE__ */ jsxs("label", { children: [
1056
+ translate("builder.pageDescription"),
1057
+ /* @__PURE__ */ jsx(
1058
+ "input",
1059
+ {
1060
+ value: page.translations?.[editingLocale]?.description ?? "",
1061
+ onChange: (event) => updateManualTranslation({
1062
+ locale: editingLocale,
1063
+ kind: "page",
1064
+ nodeId: page.id,
1065
+ property: "description",
1066
+ sourceText: page.description ?? "",
1067
+ translatedText: event.currentTarget.value,
1068
+ ...page.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
1069
+ existingTranslationMetadata: page.translationMetadata[editingLocale]?.description
1070
+ }
1071
+ })
1072
+ }
1073
+ )
1074
+ ] })
1075
+ ] })
1076
+ ] }),
1077
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__condition", children: [
1078
+ /* @__PURE__ */ jsxs("label", { children: [
1079
+ translate("builder.pageCondition"),
1080
+ /* @__PURE__ */ jsxs(
1081
+ "select",
1082
+ {
1083
+ value: page.displayCondition?.questionId ?? "",
1084
+ onChange: (event) => {
1085
+ const selected = schema.fields.find((field) => field.id === event.currentTarget.value);
1086
+ updatePage(page.id, (current) => {
1087
+ if (selected === void 0) {
1088
+ const { displayCondition: _condition, ...withoutCondition } = current;
1089
+ return withoutCondition;
1090
+ }
1091
+ return {
1092
+ ...current,
1093
+ displayCondition: conditionWithValue(
1094
+ selected.id,
1095
+ conditionOperators(selected)[0] ?? "not_empty",
1096
+ defaultConditionValue(selected)
1097
+ )
1098
+ };
1099
+ });
1100
+ },
1101
+ children: [
1102
+ /* @__PURE__ */ jsx("option", { value: "", children: translate("builder.alwaysVisible") }),
1103
+ availableSources.map((field) => /* @__PURE__ */ jsx("option", { value: field.id, children: field.title }, field.id))
1104
+ ]
1105
+ }
1106
+ )
1107
+ ] }),
1108
+ page.displayCondition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1109
+ /* @__PURE__ */ jsx(
1110
+ "select",
1111
+ {
1112
+ "aria-label": translate("builder.conditionOperator"),
1113
+ value: page.displayCondition.operator,
1114
+ onChange: (event) => {
1115
+ const operator = event.currentTarget.value;
1116
+ updatePage(page.id, (current) => ({
1117
+ ...current,
1118
+ displayCondition: conditionWithValue(source.id, operator, defaultConditionValue(source))
1119
+ }));
1120
+ },
1121
+ children: conditionOperators(source).map((operator) => /* @__PURE__ */ jsx("option", { value: operator, children: translate(operatorKey(operator)) }, operator))
1122
+ }
1123
+ ),
1124
+ /* @__PURE__ */ jsx(
1125
+ ConditionValueEditor,
1126
+ {
1127
+ source,
1128
+ condition: page.displayCondition,
1129
+ onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1130
+ translate
1131
+ }
1132
+ )
1133
+ ] }) : null
1134
+ ] })
1135
+ ] }, page.id);
1136
+ }),
1137
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__page-add", children: [
1138
+ /* @__PURE__ */ jsxs("label", { children: [
1139
+ translate("builder.pageQuestion"),
1140
+ /* @__PURE__ */ jsxs(
1141
+ "select",
1142
+ {
1143
+ value: newPageQuestionId,
1144
+ disabled: movablePageQuestions.length === 0,
1145
+ onChange: (event) => setNewPageQuestionId(event.currentTarget.value),
1146
+ children: [
1147
+ /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
1148
+ schema.fields.filter((field) => movablePageQuestions.includes(field.id)).map((field) => /* @__PURE__ */ jsx("option", { value: field.id, children: field.title }, field.id))
1149
+ ]
1150
+ }
1151
+ )
1152
+ ] }),
1153
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: movablePageQuestions.length === 0, onClick: addPage, children: translate("builder.addPage") })
1154
+ ] })
1155
+ ] })
1156
+ ] }),
1157
+ /* @__PURE__ */ jsxs("section", { className: "form-engine-builder__localization", "aria-labelledby": "builder-localization-heading", children: [
1158
+ /* @__PURE__ */ jsx("h2", { id: "builder-localization-heading", children: translate("builder.localization") }),
1159
+ /* @__PURE__ */ jsxs("label", { children: [
1160
+ translate("builder.completionMessage"),
1161
+ /* @__PURE__ */ jsx(
1162
+ "input",
1163
+ {
1164
+ value: schema.completionMessage ?? "",
1165
+ onChange: (event) => setSourceText({ kind: "form" }, "completionMessage", event.currentTarget.value)
1166
+ }
1167
+ )
1168
+ ] }),
1169
+ /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1170
+ /* @__PURE__ */ jsxs("label", { children: [
1171
+ translate("builder.defaultLocale"),
1172
+ /* @__PURE__ */ jsx(
1173
+ "input",
1174
+ {
1175
+ value: schema.defaultLocale ?? "",
1176
+ onChange: (event) => headless.setDefaultLocale(event.currentTarget.value)
1177
+ }
1178
+ )
1179
+ ] }),
1180
+ /* @__PURE__ */ jsxs("label", { children: [
1181
+ translate("builder.addLocale"),
1182
+ /* @__PURE__ */ jsx("input", { value: newLocale, onChange: (event) => setNewLocale(event.currentTarget.value) })
1183
+ ] }),
1184
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: addLocale, children: translate("builder.addLocale") }),
1185
+ /* @__PURE__ */ jsxs("label", { children: [
1186
+ translate("builder.editLocale"),
1187
+ /* @__PURE__ */ jsxs("select", { value: editingLocale, onChange: (event) => setEditingLocale(event.currentTarget.value), children: [
1188
+ /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
1189
+ (schema.supportedLocales ?? []).filter((item) => item !== schema.defaultLocale).map((item) => /* @__PURE__ */ jsx("option", { value: item, children: item }, item))
1190
+ ] })
1191
+ ] }),
1192
+ /* @__PURE__ */ jsx(
1193
+ "button",
1194
+ {
1195
+ type: "button",
1196
+ disabled: translationAdapter === void 0 || editingLocale.length === 0 || isTranslating,
1197
+ onClick: () => void translateAll(),
1198
+ children: translate("builder.autoTranslate")
1199
+ }
1200
+ )
1201
+ ] }),
1202
+ translationAdapter === void 0 ? /* @__PURE__ */ jsx("p", { children: translate("builder.translationUnavailable") }) : null,
1203
+ translationError === null ? null : /* @__PURE__ */ jsx("p", { className: "form-engine-builder__error", children: translationError }),
1204
+ editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1205
+ /* @__PURE__ */ jsxs("label", { children: [
1206
+ translate("builder.questionTitle"),
1207
+ /* @__PURE__ */ jsx(
1208
+ "input",
1209
+ {
1210
+ value: schema.translations?.[editingLocale]?.title ?? "",
1211
+ onChange: (event) => updateFormTranslation("title", event.currentTarget.value)
1212
+ }
1213
+ )
1214
+ ] }),
1215
+ /* @__PURE__ */ jsxs("label", { children: [
1216
+ translate("builder.pageDescription"),
1217
+ /* @__PURE__ */ jsx(
1218
+ "input",
1219
+ {
1220
+ value: schema.translations?.[editingLocale]?.description ?? "",
1221
+ onChange: (event) => updateFormTranslation("description", event.currentTarget.value)
1222
+ }
1223
+ )
1224
+ ] }),
1225
+ /* @__PURE__ */ jsxs("label", { children: [
1226
+ translate("builder.completionMessage"),
1227
+ /* @__PURE__ */ jsx(
1228
+ "input",
1229
+ {
1230
+ value: schema.translations?.[editingLocale]?.completionMessage ?? "",
1231
+ onChange: (event) => updateFormTranslation("completionMessage", event.currentTarget.value)
1232
+ }
1233
+ )
1234
+ ] })
1235
+ ] })
1236
+ ] }),
1237
+ /* @__PURE__ */ jsx("div", { className: "form-engine-builder__list", children: schema.fields.map((field, index) => {
1238
+ const condition = field.displayCondition;
1239
+ const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
1240
+ const availableSources = schema.fields.slice(0, index);
1241
+ return /* @__PURE__ */ jsxs("fieldset", { className: "form-engine-builder__question", children: [
1242
+ /* @__PURE__ */ jsx("legend", { children: field.title }),
858
1243
  /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__toolbar", children: [
859
1244
  /* @__PURE__ */ jsx(
860
1245
  "button",
861
1246
  {
862
1247
  type: "button",
863
- disabled: pageIndex === 0,
864
- "aria-label": translate("builder.moveUp", { title: page.title ?? page.id }),
865
- onClick: () => movePage(pageIndex, -1),
1248
+ disabled: index === 0,
1249
+ onClick: () => moveField(index, -1),
1250
+ "aria-label": translate("builder.moveUp", { title: field.title }),
866
1251
  children: "\u2191"
867
1252
  }
868
1253
  ),
@@ -870,65 +1255,94 @@ function FormBuilder({
870
1255
  "button",
871
1256
  {
872
1257
  type: "button",
873
- disabled: pageIndex === (schema.pages?.length ?? 0) - 1,
874
- "aria-label": translate("builder.moveDown", { title: page.title ?? page.id }),
875
- onClick: () => movePage(pageIndex, 1),
1258
+ disabled: index === schema.fields.length - 1,
1259
+ onClick: () => moveField(index, 1),
1260
+ "aria-label": translate("builder.moveDown", { title: field.title }),
876
1261
  children: "\u2193"
877
1262
  }
878
1263
  ),
879
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => removePage(pageIndex), children: translate("builder.deleteAction") })
1264
+ /* @__PURE__ */ jsx(
1265
+ "button",
1266
+ {
1267
+ type: "button",
1268
+ disabled: schema.fields.length === 1,
1269
+ onClick: () => removeField(field.id),
1270
+ "aria-label": translate("builder.delete", { title: field.title }),
1271
+ children: translate("builder.deleteAction")
1272
+ }
1273
+ )
880
1274
  ] }),
881
1275
  /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
882
1276
  /* @__PURE__ */ jsxs("label", { children: [
883
- translate("builder.pageTitle"),
1277
+ translate("builder.questionTitle"),
884
1278
  /* @__PURE__ */ jsx(
885
1279
  "input",
886
1280
  {
887
- value: page.title ?? "",
888
- onChange: (event) => {
889
- const value = event.currentTarget.value;
890
- updatePage(page.id, (current) => {
891
- if (value.length > 0) return { ...current, title: value };
892
- const { title: _title, ...withoutTitle } = current;
893
- return withoutTitle;
894
- });
895
- }
1281
+ value: field.title,
1282
+ placeholder: translate("builder.questionTitlePlaceholder"),
1283
+ onChange: (event) => updateField(field.id, (current) => ({
1284
+ ...current,
1285
+ title: event.currentTarget.value.trim().length === 0 ? current.title : event.currentTarget.value
1286
+ }))
896
1287
  }
897
1288
  )
898
1289
  ] }),
899
1290
  /* @__PURE__ */ jsxs("label", { children: [
900
- translate("builder.pageDescription"),
1291
+ translate("builder.type"),
901
1292
  /* @__PURE__ */ jsx(
902
- "input",
1293
+ "select",
903
1294
  {
904
- value: page.description ?? "",
905
- onChange: (event) => {
906
- const value = event.currentTarget.value;
907
- updatePage(page.id, (current) => {
908
- if (value.length > 0) return { ...current, description: value };
909
- const { description: _description, ...withoutDescription } = current;
910
- return withoutDescription;
911
- });
912
- }
1295
+ value: field.type,
1296
+ onChange: (event) => changeType(field.id, event.currentTarget.value),
1297
+ children: FIELD_TYPES.filter(
1298
+ (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
1299
+ ).map((type) => /* @__PURE__ */ jsx("option", { value: type, children: translate(fieldTypeKey(type)) }, type))
913
1300
  }
914
1301
  )
1302
+ ] }),
1303
+ /* @__PURE__ */ jsxs("label", { className: "form-engine-builder__check", children: [
1304
+ /* @__PURE__ */ jsx(
1305
+ "input",
1306
+ {
1307
+ type: "checkbox",
1308
+ checked: field.required === true,
1309
+ onChange: (event) => updateField(field.id, (current) => ({ ...current, required: event.currentTarget.checked }))
1310
+ }
1311
+ ),
1312
+ translate("builder.required")
915
1313
  ] })
916
1314
  ] }),
1315
+ schema.pages === void 0 ? null : /* @__PURE__ */ jsxs("label", { children: [
1316
+ translate("builder.questionPage"),
1317
+ /* @__PURE__ */ jsx(
1318
+ "select",
1319
+ {
1320
+ value: pageForField(field.id)?.id ?? "",
1321
+ onChange: (event) => assignFieldToPage(field.id, event.currentTarget.value),
1322
+ children: schema.pages.map((page, pageIndex) => /* @__PURE__ */ jsx("option", { value: page.id, children: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}` }, page.id))
1323
+ }
1324
+ )
1325
+ ] }),
917
1326
  editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__translation-editor", children: [
918
1327
  /* @__PURE__ */ jsx("strong", { children: editingLocale }),
919
1328
  /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
920
1329
  /* @__PURE__ */ jsxs("label", { children: [
921
- translate("builder.pageTitle"),
1330
+ translate("builder.questionTitle"),
922
1331
  /* @__PURE__ */ jsx(
923
1332
  "input",
924
1333
  {
925
- value: page.translations?.[editingLocale]?.title ?? "",
926
- onChange: (event) => headless.setLocaleTranslation(
927
- editingLocale,
928
- { kind: "page", id: page.id },
929
- "title",
930
- event.currentTarget.value
931
- )
1334
+ value: field.translations?.[editingLocale]?.title ?? "",
1335
+ onChange: (event) => updateManualTranslation({
1336
+ locale: editingLocale,
1337
+ kind: "field",
1338
+ nodeId: field.id,
1339
+ property: "title",
1340
+ sourceText: field.title,
1341
+ translatedText: event.currentTarget.value,
1342
+ ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
1343
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
1344
+ }
1345
+ })
932
1346
  }
933
1347
  )
934
1348
  ] }),
@@ -937,61 +1351,175 @@ function FormBuilder({
937
1351
  /* @__PURE__ */ jsx(
938
1352
  "input",
939
1353
  {
940
- value: page.translations?.[editingLocale]?.description ?? "",
941
- onChange: (event) => headless.setLocaleTranslation(
942
- editingLocale,
943
- { kind: "page", id: page.id },
944
- "description",
945
- event.currentTarget.value
946
- )
1354
+ value: field.translations?.[editingLocale]?.description ?? "",
1355
+ onChange: (event) => updateManualTranslation({
1356
+ locale: editingLocale,
1357
+ kind: "field",
1358
+ nodeId: field.id,
1359
+ property: "description",
1360
+ sourceText: field.description ?? "",
1361
+ translatedText: event.currentTarget.value,
1362
+ ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
1363
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
1364
+ }
1365
+ })
947
1366
  }
948
1367
  )
949
1368
  ] })
950
- ] })
1369
+ ] }),
1370
+ "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsxs("label", { children: [
1371
+ translate("builder.optionLabel", { index: optionIndex + 1 }),
1372
+ " (",
1373
+ editingLocale,
1374
+ ")",
1375
+ /* @__PURE__ */ jsx(
1376
+ "input",
1377
+ {
1378
+ value: option.translations?.[editingLocale] ?? "",
1379
+ onChange: (event) => updateManualTranslation({
1380
+ locale: editingLocale,
1381
+ kind: "option",
1382
+ nodeId: option.id,
1383
+ property: "label",
1384
+ sourceText: option.label,
1385
+ translatedText: event.currentTarget.value,
1386
+ ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
1387
+ existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
1388
+ }
1389
+ })
1390
+ }
1391
+ )
1392
+ ] }, option.id)) : null
951
1393
  ] }),
1394
+ field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1395
+ /* @__PURE__ */ jsxs("label", { children: [
1396
+ translate("builder.minimum"),
1397
+ /* @__PURE__ */ jsx(
1398
+ "input",
1399
+ {
1400
+ type: "number",
1401
+ value: field.min ?? 1,
1402
+ onChange: (event) => {
1403
+ const min = event.currentTarget.valueAsNumber;
1404
+ if (!Number.isInteger(min)) return;
1405
+ updateField(
1406
+ field.id,
1407
+ (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
1408
+ );
1409
+ }
1410
+ }
1411
+ )
1412
+ ] }),
1413
+ /* @__PURE__ */ jsxs("label", { children: [
1414
+ translate("builder.maximum"),
1415
+ /* @__PURE__ */ jsx(
1416
+ "input",
1417
+ {
1418
+ type: "number",
1419
+ value: field.max ?? 5,
1420
+ onChange: (event) => {
1421
+ const max = event.currentTarget.valueAsNumber;
1422
+ if (!Number.isInteger(max)) return;
1423
+ updateField(
1424
+ field.id,
1425
+ (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
1426
+ );
1427
+ }
1428
+ }
1429
+ )
1430
+ ] })
1431
+ ] }) : null,
1432
+ "options" in field ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__options", children: [
1433
+ /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
1434
+ field.options.map((option, optionIndex) => /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__option", children: [
1435
+ /* @__PURE__ */ jsx(
1436
+ "input",
1437
+ {
1438
+ "aria-label": translate("builder.optionLabel", { index: optionIndex + 1 }),
1439
+ value: option.label,
1440
+ placeholder: translate("builder.optionLabelPlaceholder"),
1441
+ onChange: (event) => event.currentTarget.value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, event.currentTarget.value)
1442
+ }
1443
+ ),
1444
+ /* @__PURE__ */ jsx(
1445
+ "button",
1446
+ {
1447
+ type: "button",
1448
+ disabled: optionIndex === 0,
1449
+ "aria-label": translate("builder.moveUp", { title: option.label }),
1450
+ onClick: () => moveOption(field.id, option.id, optionIndex - 1),
1451
+ children: "\u2191"
1452
+ }
1453
+ ),
1454
+ /* @__PURE__ */ jsx(
1455
+ "button",
1456
+ {
1457
+ type: "button",
1458
+ disabled: optionIndex === field.options.length - 1,
1459
+ "aria-label": translate("builder.moveDown", { title: option.label }),
1460
+ onClick: () => moveOption(field.id, option.id, optionIndex + 1),
1461
+ children: "\u2193"
1462
+ }
1463
+ ),
1464
+ /* @__PURE__ */ jsx(
1465
+ "button",
1466
+ {
1467
+ type: "button",
1468
+ disabled: field.options.length === 1,
1469
+ onClick: () => removeOption(field.id, option.id),
1470
+ children: translate("builder.remove")
1471
+ }
1472
+ )
1473
+ ] }, option.id)),
1474
+ /* @__PURE__ */ jsx(
1475
+ "button",
1476
+ {
1477
+ type: "button",
1478
+ "data-builder-action": "addOption",
1479
+ "data-target-id": field.id,
1480
+ disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
1481
+ onClick: () => addOption(field.id),
1482
+ children: translate("builder.addOption")
1483
+ }
1484
+ )
1485
+ ] }) : null,
952
1486
  /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__condition", children: [
953
1487
  /* @__PURE__ */ jsxs("label", { children: [
954
- translate("builder.pageCondition"),
1488
+ translate("builder.displayCondition"),
955
1489
  /* @__PURE__ */ jsxs(
956
1490
  "select",
957
1491
  {
958
- value: page.displayCondition?.questionId ?? "",
1492
+ value: condition?.questionId ?? "",
959
1493
  onChange: (event) => {
960
- const selected = schema.fields.find((field) => field.id === event.currentTarget.value);
961
- updatePage(page.id, (current) => {
962
- if (selected === void 0) {
963
- const { displayCondition: _condition, ...withoutCondition } = current;
964
- return withoutCondition;
965
- }
966
- return {
967
- ...current,
968
- displayCondition: conditionWithValue(
969
- selected.id,
970
- conditionOperators(selected)[0] ?? "not_empty",
971
- defaultConditionValue(selected)
972
- )
973
- };
974
- });
1494
+ const selected = schema.fields.find((item) => item.id === event.currentTarget.value);
1495
+ setDisplayCondition(
1496
+ field.id,
1497
+ selected === void 0 ? void 0 : conditionWithValue(
1498
+ selected.id,
1499
+ conditionOperators(selected)[0] ?? "not_empty",
1500
+ defaultConditionValue(selected)
1501
+ )
1502
+ );
975
1503
  },
976
1504
  children: [
977
1505
  /* @__PURE__ */ jsx("option", { value: "", children: translate("builder.alwaysVisible") }),
978
- availableSources.map((field) => /* @__PURE__ */ jsx("option", { value: field.id, children: field.title }, field.id))
1506
+ availableSources.map((candidate) => /* @__PURE__ */ jsx("option", { value: candidate.id, children: candidate.title }, candidate.id))
979
1507
  ]
980
1508
  }
981
1509
  )
982
1510
  ] }),
983
- page.displayCondition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1511
+ condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
984
1512
  /* @__PURE__ */ jsx(
985
1513
  "select",
986
1514
  {
987
1515
  "aria-label": translate("builder.conditionOperator"),
988
- value: page.displayCondition.operator,
1516
+ value: condition.operator,
989
1517
  onChange: (event) => {
990
1518
  const operator = event.currentTarget.value;
991
- updatePage(page.id, (current) => ({
992
- ...current,
993
- displayCondition: conditionWithValue(source.id, operator, defaultConditionValue(source))
994
- }));
1519
+ setDisplayCondition(
1520
+ field.id,
1521
+ conditionWithValue(source.id, operator, defaultConditionValue(source))
1522
+ );
995
1523
  },
996
1524
  children: conditionOperators(source).map((operator) => /* @__PURE__ */ jsx("option", { value: operator, children: translate(operatorKey(operator)) }, operator))
997
1525
  }
@@ -1000,395 +1528,29 @@ function FormBuilder({
1000
1528
  ConditionValueEditor,
1001
1529
  {
1002
1530
  source,
1003
- condition: page.displayCondition,
1004
- onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1531
+ condition,
1532
+ onChange: (next) => setDisplayCondition(field.id, next),
1005
1533
  translate
1006
1534
  }
1007
1535
  )
1008
1536
  ] }) : null
1009
1537
  ] })
1010
- ] }, page.id);
1011
- }),
1012
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__page-add", children: [
1013
- /* @__PURE__ */ jsxs("label", { children: [
1014
- translate("builder.pageQuestion"),
1015
- /* @__PURE__ */ jsxs(
1016
- "select",
1017
- {
1018
- value: newPageQuestionId,
1019
- disabled: movablePageQuestions.length === 0,
1020
- onChange: (event) => setNewPageQuestionId(event.currentTarget.value),
1021
- children: [
1022
- /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
1023
- schema.fields.filter((field) => movablePageQuestions.includes(field.id)).map((field) => /* @__PURE__ */ jsx("option", { value: field.id, children: field.title }, field.id))
1024
- ]
1025
- }
1026
- )
1027
- ] }),
1028
- /* @__PURE__ */ jsx("button", { type: "button", disabled: movablePageQuestions.length === 0, onClick: addPage, children: translate("builder.addPage") })
1029
- ] })
1030
- ] })
1031
- ] }),
1032
- /* @__PURE__ */ jsxs("section", { className: "form-engine-builder__localization", "aria-labelledby": "builder-localization-heading", children: [
1033
- /* @__PURE__ */ jsx("h2", { id: "builder-localization-heading", children: translate("builder.localization") }),
1034
- /* @__PURE__ */ jsxs("label", { children: [
1035
- translate("builder.completionMessage"),
1036
- /* @__PURE__ */ jsx(
1037
- "input",
1038
- {
1039
- value: schema.completionMessage ?? "",
1040
- onChange: (event) => headless.setSourceText({ kind: "form" }, "completionMessage", event.currentTarget.value)
1041
- }
1042
- )
1043
- ] }),
1044
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1045
- /* @__PURE__ */ jsxs("label", { children: [
1046
- translate("builder.defaultLocale"),
1047
- /* @__PURE__ */ jsx(
1048
- "input",
1049
- {
1050
- value: schema.defaultLocale ?? "",
1051
- onChange: (event) => headless.setDefaultLocale(event.currentTarget.value)
1052
- }
1053
- )
1054
- ] }),
1055
- /* @__PURE__ */ jsxs("label", { children: [
1056
- translate("builder.addLocale"),
1057
- /* @__PURE__ */ jsx("input", { value: newLocale, onChange: (event) => setNewLocale(event.currentTarget.value) })
1058
- ] }),
1059
- /* @__PURE__ */ jsx("button", { type: "button", onClick: addLocale, children: translate("builder.addLocale") }),
1060
- /* @__PURE__ */ jsxs("label", { children: [
1061
- translate("builder.editLocale"),
1062
- /* @__PURE__ */ jsxs("select", { value: editingLocale, onChange: (event) => setEditingLocale(event.currentTarget.value), children: [
1063
- /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
1064
- (schema.supportedLocales ?? []).filter((item) => item !== schema.defaultLocale).map((item) => /* @__PURE__ */ jsx("option", { value: item, children: item }, item))
1065
- ] })
1066
- ] }),
1538
+ ] }, field.id);
1539
+ }) }),
1067
1540
  /* @__PURE__ */ jsx(
1068
1541
  "button",
1069
1542
  {
1543
+ className: "form-engine-builder__add",
1070
1544
  type: "button",
1071
- disabled: translationAdapter === void 0 || editingLocale.length === 0 || isTranslating,
1072
- onClick: () => void translateAll(),
1073
- children: translate("builder.autoTranslate")
1545
+ "data-builder-action": "addField",
1546
+ disabled: initialFieldType === null || maxFieldsReached,
1547
+ onClick: addField,
1548
+ children: translate("builder.addQuestion")
1074
1549
  }
1075
1550
  )
1076
- ] }),
1077
- translationAdapter === void 0 ? /* @__PURE__ */ jsx("p", { children: translate("builder.translationUnavailable") }) : null,
1078
- translationError === null ? null : /* @__PURE__ */ jsx("p", { className: "form-engine-builder__error", children: translationError }),
1079
- editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1080
- /* @__PURE__ */ jsxs("label", { children: [
1081
- translate("builder.questionTitle"),
1082
- /* @__PURE__ */ jsx(
1083
- "input",
1084
- {
1085
- value: schema.translations?.[editingLocale]?.title ?? "",
1086
- onChange: (event) => updateFormTranslation("title", event.currentTarget.value)
1087
- }
1088
- )
1089
- ] }),
1090
- /* @__PURE__ */ jsxs("label", { children: [
1091
- translate("builder.pageDescription"),
1092
- /* @__PURE__ */ jsx(
1093
- "input",
1094
- {
1095
- value: schema.translations?.[editingLocale]?.description ?? "",
1096
- onChange: (event) => updateFormTranslation("description", event.currentTarget.value)
1097
- }
1098
- )
1099
- ] }),
1100
- /* @__PURE__ */ jsxs("label", { children: [
1101
- translate("builder.completionMessage"),
1102
- /* @__PURE__ */ jsx(
1103
- "input",
1104
- {
1105
- value: schema.translations?.[editingLocale]?.completionMessage ?? "",
1106
- onChange: (event) => updateFormTranslation("completionMessage", event.currentTarget.value)
1107
- }
1108
- )
1109
- ] })
1110
- ] })
1111
- ] }),
1112
- /* @__PURE__ */ jsx("div", { className: "form-engine-builder__list", children: schema.fields.map((field, index) => {
1113
- const condition = field.displayCondition;
1114
- const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
1115
- const availableSources = schema.fields.slice(0, index);
1116
- return /* @__PURE__ */ jsxs("fieldset", { className: "form-engine-builder__question", children: [
1117
- /* @__PURE__ */ jsx("legend", { children: field.title }),
1118
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__toolbar", children: [
1119
- /* @__PURE__ */ jsx(
1120
- "button",
1121
- {
1122
- type: "button",
1123
- disabled: index === 0,
1124
- onClick: () => moveField(index, -1),
1125
- "aria-label": translate("builder.moveUp", { title: field.title }),
1126
- children: "\u2191"
1127
- }
1128
- ),
1129
- /* @__PURE__ */ jsx(
1130
- "button",
1131
- {
1132
- type: "button",
1133
- disabled: index === schema.fields.length - 1,
1134
- onClick: () => moveField(index, 1),
1135
- "aria-label": translate("builder.moveDown", { title: field.title }),
1136
- children: "\u2193"
1137
- }
1138
- ),
1139
- /* @__PURE__ */ jsx(
1140
- "button",
1141
- {
1142
- type: "button",
1143
- disabled: schema.fields.length === 1,
1144
- onClick: () => removeField(field.id),
1145
- "aria-label": translate("builder.delete", { title: field.title }),
1146
- children: translate("builder.deleteAction")
1147
- }
1148
- )
1149
- ] }),
1150
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1151
- /* @__PURE__ */ jsxs("label", { children: [
1152
- translate("builder.questionTitle"),
1153
- /* @__PURE__ */ jsx(
1154
- "input",
1155
- {
1156
- value: field.title,
1157
- placeholder: translate("builder.questionTitlePlaceholder"),
1158
- onChange: (event) => updateField(field.id, (current) => ({
1159
- ...current,
1160
- title: event.currentTarget.value.trim().length === 0 ? current.title : event.currentTarget.value
1161
- }))
1162
- }
1163
- )
1164
- ] }),
1165
- /* @__PURE__ */ jsxs("label", { children: [
1166
- translate("builder.type"),
1167
- /* @__PURE__ */ jsx(
1168
- "select",
1169
- {
1170
- value: field.type,
1171
- onChange: (event) => changeType(field.id, event.currentTarget.value),
1172
- children: FIELD_TYPES.filter(
1173
- (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
1174
- ).map((type) => /* @__PURE__ */ jsx("option", { value: type, children: translate(fieldTypeKey(type)) }, type))
1175
- }
1176
- )
1177
- ] }),
1178
- /* @__PURE__ */ jsxs("label", { className: "form-engine-builder__check", children: [
1179
- /* @__PURE__ */ jsx(
1180
- "input",
1181
- {
1182
- type: "checkbox",
1183
- checked: field.required === true,
1184
- onChange: (event) => updateField(field.id, (current) => ({ ...current, required: event.currentTarget.checked }))
1185
- }
1186
- ),
1187
- translate("builder.required")
1188
- ] })
1189
- ] }),
1190
- schema.pages === void 0 ? null : /* @__PURE__ */ jsxs("label", { children: [
1191
- translate("builder.questionPage"),
1192
- /* @__PURE__ */ jsx(
1193
- "select",
1194
- {
1195
- value: pageForField(field.id)?.id ?? "",
1196
- onChange: (event) => assignFieldToPage(field.id, event.currentTarget.value),
1197
- children: schema.pages.map((page, pageIndex) => /* @__PURE__ */ jsx("option", { value: page.id, children: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}` }, page.id))
1198
- }
1199
- )
1200
- ] }),
1201
- editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__translation-editor", children: [
1202
- /* @__PURE__ */ jsx("strong", { children: editingLocale }),
1203
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1204
- /* @__PURE__ */ jsxs("label", { children: [
1205
- translate("builder.questionTitle"),
1206
- /* @__PURE__ */ jsx(
1207
- "input",
1208
- {
1209
- value: field.translations?.[editingLocale]?.title ?? "",
1210
- onChange: (event) => headless.setLocaleTranslation(
1211
- editingLocale,
1212
- { kind: "field", id: field.id },
1213
- "title",
1214
- event.currentTarget.value
1215
- )
1216
- }
1217
- )
1218
- ] }),
1219
- /* @__PURE__ */ jsxs("label", { children: [
1220
- translate("builder.pageDescription"),
1221
- /* @__PURE__ */ jsx(
1222
- "input",
1223
- {
1224
- value: field.translations?.[editingLocale]?.description ?? "",
1225
- onChange: (event) => headless.setLocaleTranslation(
1226
- editingLocale,
1227
- { kind: "field", id: field.id },
1228
- "description",
1229
- event.currentTarget.value
1230
- )
1231
- }
1232
- )
1233
- ] })
1234
- ] }),
1235
- "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsxs("label", { children: [
1236
- translate("builder.optionLabel", { index: optionIndex + 1 }),
1237
- " (",
1238
- editingLocale,
1239
- ")",
1240
- /* @__PURE__ */ jsx(
1241
- "input",
1242
- {
1243
- value: option.translations?.[editingLocale] ?? "",
1244
- onChange: (event) => headless.setLocaleTranslation(
1245
- editingLocale,
1246
- { kind: "option", id: option.id },
1247
- "label",
1248
- event.currentTarget.value
1249
- )
1250
- }
1251
- )
1252
- ] }, option.id)) : null
1253
- ] }),
1254
- field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__grid", children: [
1255
- /* @__PURE__ */ jsxs("label", { children: [
1256
- translate("builder.minimum"),
1257
- /* @__PURE__ */ jsx(
1258
- "input",
1259
- {
1260
- type: "number",
1261
- value: field.min ?? 1,
1262
- onChange: (event) => {
1263
- const min = event.currentTarget.valueAsNumber;
1264
- if (!Number.isInteger(min)) return;
1265
- updateField(
1266
- field.id,
1267
- (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
1268
- );
1269
- }
1270
- }
1271
- )
1272
- ] }),
1273
- /* @__PURE__ */ jsxs("label", { children: [
1274
- translate("builder.maximum"),
1275
- /* @__PURE__ */ jsx(
1276
- "input",
1277
- {
1278
- type: "number",
1279
- value: field.max ?? 5,
1280
- onChange: (event) => {
1281
- const max = event.currentTarget.valueAsNumber;
1282
- if (!Number.isInteger(max)) return;
1283
- updateField(
1284
- field.id,
1285
- (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
1286
- );
1287
- }
1288
- }
1289
- )
1290
- ] })
1291
- ] }) : null,
1292
- "options" in field ? /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__options", children: [
1293
- /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
1294
- field.options.map((option, optionIndex) => /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__option", children: [
1295
- /* @__PURE__ */ jsx(
1296
- "input",
1297
- {
1298
- "aria-label": translate("builder.optionLabel", { index: optionIndex + 1 }),
1299
- value: option.label,
1300
- placeholder: translate("builder.optionLabelPlaceholder"),
1301
- onChange: (event) => event.currentTarget.value.trim().length === 0 ? void 0 : headless.updateOption(field.id, option.id, (item) => ({
1302
- ...item,
1303
- label: event.currentTarget.value
1304
- }))
1305
- }
1306
- ),
1307
- /* @__PURE__ */ jsx(
1308
- "button",
1309
- {
1310
- type: "button",
1311
- disabled: field.options.length === 1,
1312
- onClick: () => headless.removeOption(field.id, option.id),
1313
- children: translate("builder.remove")
1314
- }
1315
- )
1316
- ] }, option.id)),
1317
- /* @__PURE__ */ jsx(
1318
- "button",
1319
- {
1320
- type: "button",
1321
- disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
1322
- onClick: () => headless.addOption(field.id),
1323
- children: translate("builder.addOption")
1324
- }
1325
- )
1326
- ] }) : null,
1327
- /* @__PURE__ */ jsxs("div", { className: "form-engine-builder__condition", children: [
1328
- /* @__PURE__ */ jsxs("label", { children: [
1329
- translate("builder.displayCondition"),
1330
- /* @__PURE__ */ jsxs(
1331
- "select",
1332
- {
1333
- value: condition?.questionId ?? "",
1334
- onChange: (event) => {
1335
- const selected = schema.fields.find((item) => item.id === event.currentTarget.value);
1336
- headless.setDisplayCondition(
1337
- field.id,
1338
- selected === void 0 ? void 0 : conditionWithValue(
1339
- selected.id,
1340
- conditionOperators(selected)[0] ?? "not_empty",
1341
- defaultConditionValue(selected)
1342
- )
1343
- );
1344
- },
1345
- children: [
1346
- /* @__PURE__ */ jsx("option", { value: "", children: translate("builder.alwaysVisible") }),
1347
- availableSources.map((candidate) => /* @__PURE__ */ jsx("option", { value: candidate.id, children: candidate.title }, candidate.id))
1348
- ]
1349
- }
1350
- )
1351
- ] }),
1352
- condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1353
- /* @__PURE__ */ jsx(
1354
- "select",
1355
- {
1356
- "aria-label": translate("builder.conditionOperator"),
1357
- value: condition.operator,
1358
- onChange: (event) => {
1359
- const operator = event.currentTarget.value;
1360
- headless.setDisplayCondition(
1361
- field.id,
1362
- conditionWithValue(source.id, operator, defaultConditionValue(source))
1363
- );
1364
- },
1365
- children: conditionOperators(source).map((operator) => /* @__PURE__ */ jsx("option", { value: operator, children: translate(operatorKey(operator)) }, operator))
1366
- }
1367
- ),
1368
- /* @__PURE__ */ jsx(
1369
- ConditionValueEditor,
1370
- {
1371
- source,
1372
- condition,
1373
- onChange: (next) => headless.setDisplayCondition(field.id, next),
1374
- translate
1375
- }
1376
- )
1377
- ] }) : null
1378
- ] })
1379
- ] }, field.id);
1380
- }) }),
1381
- /* @__PURE__ */ jsx(
1382
- "button",
1383
- {
1384
- className: "form-engine-builder__add",
1385
- type: "button",
1386
- disabled: policy?.maxFields !== void 0 && schema.fields.length >= policy.maxFields,
1387
- onClick: addField,
1388
- children: translate("builder.addQuestion")
1389
- }
1390
- )
1391
- ] });
1551
+ ]
1552
+ }
1553
+ );
1392
1554
  }
1393
1555
 
1394
1556
  // src/context.tsx
@@ -2045,6 +2207,7 @@ export {
2045
2207
  FormBuilder,
2046
2208
  FormProvider,
2047
2209
  FormRenderer,
2210
+ resolveInitialFieldType,
2048
2211
  useField,
2049
2212
  useForm,
2050
2213
  useFormBuilder