@form-engine-ts/react 2.9.3 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -101,7 +101,7 @@ function createLocalStorageSubmissionAttemptStore(options = {}) {
101
101
  import {
102
102
  populateSchemaTranslations
103
103
  } from "@form-engine-ts/core";
104
- import { createContext, useContext, useState } from "react";
104
+ import { Children, createContext, isValidElement, useContext, useState } from "react";
105
105
 
106
106
  // src/hooks/useFormBuilder.ts
107
107
  import {
@@ -1169,6 +1169,7 @@ var BUILDER_DEFAULTS = {
1169
1169
  "builder.basicSettings": "Basic settings",
1170
1170
  "builder.formTitle": "Form title",
1171
1171
  "builder.formDescription": "Form description",
1172
+ "builder.description": "Description",
1172
1173
  "builder.moveUp": "Move {{title}} up",
1173
1174
  "builder.moveDown": "Move {{title}} down",
1174
1175
  "builder.delete": "Delete {{title}}",
@@ -1203,12 +1204,31 @@ var BUILDER_DEFAULTS = {
1203
1204
  "builder.pageQuestion": "Question to move to the new page",
1204
1205
  "builder.questionPage": "Page",
1205
1206
  "builder.pageCondition": "Page display condition",
1207
+ "builder.unassigned": "Unassigned",
1206
1208
  "builder.localization": "Localization",
1207
1209
  "builder.defaultLocale": "Default locale",
1208
1210
  "builder.supportedLocales": "Supported locales",
1209
1211
  "builder.addLocale": "Add locale",
1210
1212
  "builder.editLocale": "Edit locale",
1211
1213
  "builder.autoTranslate": "Translate all text",
1214
+ "builder.translating": "Translating\u2026",
1215
+ "builder.translationLocale": "Translation locale",
1216
+ "builder.selectLocale": "Select a locale to edit translations.",
1217
+ "builder.translation": "{{locale}} translation",
1218
+ "builder.translatedFormTitle": "Translated form title",
1219
+ "builder.translatedFormDescription": "Translated form description",
1220
+ "builder.translatedCompletionMessage": "Translated completion message",
1221
+ "builder.translatedQuestionTitle": "Translated question title",
1222
+ "builder.translatedDescription": "Translated description",
1223
+ "builder.actions.moveUp": "Move up",
1224
+ "builder.actions.moveDown": "Move down",
1225
+ "builder.actions.delete": "Delete",
1226
+ "builder.actions.add": "Add",
1227
+ "builder.actions.edit": "Edit",
1228
+ "builder.actions.settings": "Settings",
1229
+ "builder.actions.translate": "Translate",
1230
+ "builder.actions.close": "Close",
1231
+ "builder.actions.dragHandle": "Reorder",
1212
1232
  "builder.translationUnavailable": "Provide an async translation adapter to enable automatic translation.",
1213
1233
  "builder.fieldType.text": "Text",
1214
1234
  "builder.fieldType.textarea": "Textarea",
@@ -1229,6 +1249,22 @@ function interpolate(template, params) {
1229
1249
  (token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
1230
1250
  );
1231
1251
  }
1252
+ function BuilderSectionGroup({ children }) {
1253
+ return children;
1254
+ }
1255
+ function sectionGroupName(node) {
1256
+ if (!isValidElement(node) || node.type !== BuilderSectionGroup) return void 0;
1257
+ return node.props.name;
1258
+ }
1259
+ function OrderedBuilderSections({
1260
+ order,
1261
+ children
1262
+ }) {
1263
+ if (order === void 0) return children;
1264
+ const ranks = new Map(order.map((name, index) => [name, index]));
1265
+ const groups = Children.toArray(children);
1266
+ return groups.map((group, index) => ({ group, index, rank: ranks.get(sectionGroupName(group) ?? "questions") ?? order.length })).sort((left, right) => left.rank - right.rank || left.index - right.index).map(({ group }) => group);
1267
+ }
1232
1268
  function fieldTypeKey(type) {
1233
1269
  return `builder.fieldType.${type}`;
1234
1270
  }
@@ -1331,6 +1367,7 @@ function FormBuilder({
1331
1367
  features,
1332
1368
  components: componentOverrides,
1333
1369
  slots,
1370
+ sectionOrder,
1334
1371
  disableDefaultStyles = false,
1335
1372
  unstyled = false
1336
1373
  }) {
@@ -1348,6 +1385,7 @@ function FormBuilder({
1348
1385
  const PagesSlot = slots?.pages;
1349
1386
  const LocalizationSlot = slots?.localization;
1350
1387
  const TranslationActionsSlot = slots?.translationActions;
1388
+ const resolvedSectionOrder = sectionOrder ?? slots?.sectionOrder;
1351
1389
  const headless = useFormBuilder({
1352
1390
  schema,
1353
1391
  onChange,
@@ -1362,7 +1400,11 @@ function FormBuilder({
1362
1400
  const [translationError, setTranslationError] = useState(null);
1363
1401
  const [translationReport, setTranslationReport] = useState();
1364
1402
  const translate = (key, params = {}) => {
1365
- const translated = translator?.translate(key, locale, params);
1403
+ const translatorParams = {};
1404
+ for (const [name, value] of Object.entries(params)) {
1405
+ if (typeof value === "string" || typeof value === "number") translatorParams[name] = value;
1406
+ }
1407
+ const translated = translator?.translate(key, locale, translatorParams);
1366
1408
  return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
1367
1409
  };
1368
1410
  const pagesEnabled = features?.pages ?? true;
@@ -1647,8 +1689,8 @@ function FormBuilder({
1647
1689
  addOption(fieldId);
1648
1690
  }
1649
1691
  },
1650
- children: /* @__PURE__ */ jsxs(Fieldset, { className: builderClass("form-engine-builder__controls"), disabled: readOnly, children: [
1651
- /* @__PURE__ */ jsx(
1692
+ children: /* @__PURE__ */ jsx(Fieldset, { className: builderClass("form-engine-builder__controls"), disabled: readOnly, children: /* @__PURE__ */ jsxs(OrderedBuilderSections, { ...resolvedSectionOrder === void 0 ? {} : { order: resolvedSectionOrder }, children: [
1693
+ /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "basicSettings", children: /* @__PURE__ */ jsx(
1652
1694
  Section,
1653
1695
  {
1654
1696
  className: builderClass("form-engine-builder__basic-settings"),
@@ -1682,8 +1724,17 @@ function FormBuilder({
1682
1724
  ) })
1683
1725
  ] })
1684
1726
  }
1685
- ),
1686
- pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ jsx(
1727
+ ) }),
1728
+ resolvedSectionOrder === void 0 ? null : /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "completionMessage", children: /* @__PURE__ */ jsx(Section, { headingId: "builder-completion-message-heading", title: translate("builder.completionMessage"), children: /* @__PURE__ */ jsx(
1729
+ TextInput,
1730
+ {
1731
+ id: "builder-completion-message",
1732
+ label: translate("builder.completionMessage"),
1733
+ value: schema.completionMessage ?? "",
1734
+ onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1735
+ }
1736
+ ) }) }),
1737
+ /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "questions", children: pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ jsx(
1687
1738
  Section,
1688
1739
  {
1689
1740
  className: builderClass("form-engine-builder__pages"),
@@ -1733,6 +1784,7 @@ function FormBuilder({
1733
1784
  ToolbarSlot,
1734
1785
  {
1735
1786
  schema,
1787
+ translate,
1736
1788
  kind: "page",
1737
1789
  targetId: page.id,
1738
1790
  index: pageIndex,
@@ -1879,7 +1931,10 @@ function FormBuilder({
1879
1931
  {
1880
1932
  source,
1881
1933
  condition: page.displayCondition,
1882
- onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1934
+ onChange: (condition) => updatePage(page.id, (current) => ({
1935
+ ...current,
1936
+ displayCondition: condition
1937
+ })),
1883
1938
  translate,
1884
1939
  components
1885
1940
  }
@@ -1914,20 +1969,22 @@ function FormBuilder({
1914
1969
  PagesSlot,
1915
1970
  {
1916
1971
  schema,
1972
+ translate,
1917
1973
  currentLocale: editingLocale,
1974
+ ...features === void 0 ? {} : { features },
1918
1975
  readOnly,
1919
1976
  actions,
1920
1977
  components
1921
1978
  }
1922
- ) : null,
1923
- localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ jsxs(
1979
+ ) : null }),
1980
+ /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "localization", children: localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ jsxs(
1924
1981
  Section,
1925
1982
  {
1926
1983
  className: builderClass("form-engine-builder__localization"),
1927
1984
  headingId: "builder-localization-heading",
1928
1985
  title: translate("builder.localization"),
1929
1986
  children: [
1930
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1987
+ resolvedSectionOrder === void 0 ? /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1931
1988
  TextInput,
1932
1989
  {
1933
1990
  id: "builder-completion-message",
@@ -1935,7 +1992,7 @@ function FormBuilder({
1935
1992
  value: schema.completionMessage ?? "",
1936
1993
  onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1937
1994
  }
1938
- ) }),
1995
+ ) }) : null,
1939
1996
  /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
1940
1997
  /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
1941
1998
  TextInput,
@@ -2000,12 +2057,14 @@ function FormBuilder({
2000
2057
  TranslationActionsSlot,
2001
2058
  {
2002
2059
  schema,
2060
+ translate,
2003
2061
  currentLocale: editingLocale,
2004
2062
  onAutoTranslate: () => void translateAll(),
2005
2063
  isTranslating,
2006
2064
  ...translationError === null ? {} : { translationError },
2007
2065
  ...translationReport === void 0 ? {} : { translationReport },
2008
2066
  onClearTranslationError: () => setTranslationError(null),
2067
+ translationAdapterAvailable: translationAdapter !== void 0,
2009
2068
  readOnly,
2010
2069
  actions,
2011
2070
  components
@@ -2049,17 +2108,20 @@ function FormBuilder({
2049
2108
  LocalizationSlot,
2050
2109
  {
2051
2110
  schema,
2111
+ translate,
2052
2112
  currentLocale: editingLocale,
2053
2113
  onCurrentLocaleChange: setEditingLocale,
2054
2114
  onAutoTranslate: () => void translateAll(),
2055
2115
  isTranslating,
2056
2116
  ...translationError === null ? {} : { translationError },
2117
+ ...policy === void 0 ? {} : { policy },
2118
+ translationAdapterAvailable: translationAdapter !== void 0,
2057
2119
  readOnly,
2058
2120
  actions,
2059
2121
  components
2060
2122
  }
2061
- ) : null,
2062
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
2123
+ ) : null }),
2124
+ /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "questions", children: /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
2063
2125
  const condition = field.displayCondition;
2064
2126
  const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
2065
2127
  const availableSources = schema.fields.slice(0, index);
@@ -2071,7 +2133,9 @@ function FormBuilder({
2071
2133
  field,
2072
2134
  index,
2073
2135
  currentLocale: editingLocale,
2136
+ translate,
2074
2137
  ...policy === void 0 ? {} : { policy },
2138
+ ...features === void 0 ? {} : { features },
2075
2139
  readOnly,
2076
2140
  actions,
2077
2141
  components
@@ -2079,348 +2143,362 @@ function FormBuilder({
2079
2143
  field.id
2080
2144
  );
2081
2145
  }
2082
- return /* @__PURE__ */ jsxs(Fieldset, { className: builderClass("form-engine-builder__question"), legend: field.title, children: [
2083
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__toolbar"), children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2084
- /* @__PURE__ */ jsx(
2085
- IconButton,
2086
- {
2087
- actionType: "moveUp",
2088
- title: translate("builder.moveUp", { title: field.title }),
2089
- disabled: index === 0,
2090
- onClick: () => moveField(index, -1)
2091
- }
2092
- ),
2093
- /* @__PURE__ */ jsx(
2094
- IconButton,
2095
- {
2096
- actionType: "moveDown",
2097
- title: translate("builder.moveDown", { title: field.title }),
2098
- disabled: index === schema.fields.length - 1,
2099
- onClick: () => moveField(index, 1)
2100
- }
2101
- ),
2102
- /* @__PURE__ */ jsx(
2103
- IconButton,
2104
- {
2105
- actionType: "delete",
2106
- disabled: schema.fields.length === 1,
2107
- onClick: () => removeField(field.id),
2108
- "aria-label": translate("builder.delete", { title: field.title }),
2109
- title: translate("builder.delete", { title: field.title })
2110
- }
2111
- )
2112
- ] }) : /* @__PURE__ */ jsx(
2113
- ToolbarSlot,
2114
- {
2115
- schema,
2116
- kind: "field",
2117
- targetId: field.id,
2118
- index,
2119
- total: schema.fields.length,
2120
- title: field.title,
2121
- onMoveUp: () => moveField(index, -1),
2122
- onMoveDown: () => moveField(index, 1),
2123
- onRemove: () => removeField(field.id),
2124
- readOnly,
2125
- actions,
2126
- components
2127
- }
2128
- ) }),
2129
- /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2130
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2131
- TextInput,
2132
- {
2133
- id: `builder-field-${field.id}-title`,
2134
- name: `fields.${field.id}.title`,
2135
- label: translate("builder.questionTitle"),
2136
- required: true,
2137
- error: field.title.trim().length === 0,
2138
- helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2139
- "aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
2140
- value: field.title,
2141
- placeholder: translate("builder.questionTitlePlaceholder"),
2142
- onChange: (value) => updateField(field.id, (current) => ({
2143
- ...current,
2144
- title: value.trim().length === 0 ? current.title : value
2145
- }))
2146
- }
2147
- ) }),
2148
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2149
- Select,
2150
- {
2151
- id: `builder-field-${field.id}-type`,
2152
- label: translate("builder.type"),
2153
- value: field.type,
2154
- onChange: (value) => changeType(field.id, value),
2155
- options: FIELD_TYPES.filter(
2156
- (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2157
- ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
2158
- }
2159
- ) }),
2160
- /* @__PURE__ */ jsx(
2161
- Checkbox,
2162
- {
2163
- className: builderClass("form-engine-builder__check"),
2164
- checked: field.required === true,
2165
- onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2166
- label: translate("builder.required")
2167
- }
2168
- )
2169
- ] }),
2170
- !pagesEnabled || schema.pages === void 0 ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2171
- Select,
2172
- {
2173
- id: `builder-field-${field.id}-page`,
2174
- label: translate("builder.questionPage"),
2175
- value: pageForField(field.id)?.id ?? "",
2176
- onChange: (value) => assignFieldToPage(field.id, value),
2177
- options: schema.pages.map((page, pageIndex) => ({
2178
- value: page.id,
2179
- label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2180
- }))
2181
- }
2182
- ) }),
2183
- !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
2184
- /* @__PURE__ */ jsx("strong", { children: editingLocale }),
2185
- /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2186
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2187
- TextInput,
2146
+ return /* @__PURE__ */ jsxs(
2147
+ Fieldset,
2148
+ {
2149
+ className: builderClass("form-engine-builder__question"),
2150
+ legend: field.title,
2151
+ children: [
2152
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__toolbar"), children: ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2153
+ /* @__PURE__ */ jsx(
2154
+ IconButton,
2155
+ {
2156
+ actionType: "moveUp",
2157
+ title: translate("builder.moveUp", { title: field.title }),
2158
+ disabled: index === 0,
2159
+ onClick: () => moveField(index, -1)
2160
+ }
2161
+ ),
2162
+ /* @__PURE__ */ jsx(
2163
+ IconButton,
2164
+ {
2165
+ actionType: "moveDown",
2166
+ title: translate("builder.moveDown", { title: field.title }),
2167
+ disabled: index === schema.fields.length - 1,
2168
+ onClick: () => moveField(index, 1)
2169
+ }
2170
+ ),
2171
+ /* @__PURE__ */ jsx(
2172
+ IconButton,
2173
+ {
2174
+ actionType: "delete",
2175
+ disabled: schema.fields.length === 1,
2176
+ onClick: () => removeField(field.id),
2177
+ "aria-label": translate("builder.delete", { title: field.title }),
2178
+ title: translate("builder.delete", { title: field.title })
2179
+ }
2180
+ )
2181
+ ] }) : /* @__PURE__ */ jsx(
2182
+ ToolbarSlot,
2188
2183
  {
2189
- id: `builder-field-${field.id}-${editingLocale}-title`,
2190
- label: translate("builder.questionTitle"),
2191
- value: field.translations?.[editingLocale]?.title ?? "",
2192
- onChange: (value) => updateManualTranslation({
2193
- locale: editingLocale,
2194
- kind: "field",
2195
- nodeId: field.id,
2196
- property: "title",
2197
- sourceText: field.title,
2198
- translatedText: value,
2199
- ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2200
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2201
- }
2202
- })
2184
+ schema,
2185
+ translate,
2186
+ kind: "field",
2187
+ targetId: field.id,
2188
+ index,
2189
+ total: schema.fields.length,
2190
+ title: field.title,
2191
+ onMoveUp: () => moveField(index, -1),
2192
+ onMoveDown: () => moveField(index, 1),
2193
+ onRemove: () => removeField(field.id),
2194
+ readOnly,
2195
+ actions,
2196
+ components
2203
2197
  }
2204
2198
  ) }),
2205
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2206
- TextInput,
2199
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2200
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2201
+ TextInput,
2202
+ {
2203
+ id: `builder-field-${field.id}-title`,
2204
+ name: `fields.${field.id}.title`,
2205
+ label: translate("builder.questionTitle"),
2206
+ required: true,
2207
+ error: field.title.trim().length === 0,
2208
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2209
+ "aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
2210
+ value: field.title,
2211
+ placeholder: translate("builder.questionTitlePlaceholder"),
2212
+ onChange: (value) => updateField(field.id, (current) => ({
2213
+ ...current,
2214
+ title: value.trim().length === 0 ? current.title : value
2215
+ }))
2216
+ }
2217
+ ) }),
2218
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2219
+ Select,
2220
+ {
2221
+ id: `builder-field-${field.id}-type`,
2222
+ label: translate("builder.type"),
2223
+ value: field.type,
2224
+ onChange: (value) => changeType(field.id, value),
2225
+ options: FIELD_TYPES.filter(
2226
+ (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2227
+ ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
2228
+ }
2229
+ ) }),
2230
+ /* @__PURE__ */ jsx(
2231
+ Checkbox,
2232
+ {
2233
+ className: builderClass("form-engine-builder__check"),
2234
+ checked: field.required === true,
2235
+ onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2236
+ label: translate("builder.required")
2237
+ }
2238
+ )
2239
+ ] }),
2240
+ !pagesEnabled || schema.pages === void 0 ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2241
+ Select,
2207
2242
  {
2208
- id: `builder-field-${field.id}-${editingLocale}-description`,
2209
- label: translate("builder.pageDescription"),
2210
- value: field.translations?.[editingLocale]?.description ?? "",
2211
- onChange: (value) => updateManualTranslation({
2212
- locale: editingLocale,
2213
- kind: "field",
2214
- nodeId: field.id,
2215
- property: "description",
2216
- sourceText: field.description ?? "",
2217
- translatedText: value,
2218
- ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2219
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2220
- }
2221
- })
2243
+ id: `builder-field-${field.id}-page`,
2244
+ label: translate("builder.questionPage"),
2245
+ value: pageForField(field.id)?.id ?? "",
2246
+ onChange: (value) => assignFieldToPage(field.id, value),
2247
+ options: schema.pages.map((page, pageIndex) => ({
2248
+ value: page.id,
2249
+ label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2250
+ }))
2222
2251
  }
2223
- ) })
2224
- ] }),
2225
- "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2226
- TextInput,
2227
- {
2228
- id: `builder-option-${option.id}-${editingLocale}`,
2229
- label: `${translate("builder.optionLabel", { index: optionIndex + 1 })} (${editingLocale})`,
2230
- value: option.translations?.[editingLocale] ?? "",
2231
- onChange: (value) => updateManualTranslation({
2232
- locale: editingLocale,
2233
- kind: "option",
2234
- nodeId: option.id,
2235
- property: "label",
2236
- sourceText: option.label,
2237
- translatedText: value,
2238
- ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2239
- existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2252
+ ) }),
2253
+ !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
2254
+ /* @__PURE__ */ jsx("strong", { children: editingLocale }),
2255
+ /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2256
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2257
+ TextInput,
2258
+ {
2259
+ id: `builder-field-${field.id}-${editingLocale}-title`,
2260
+ label: translate("builder.questionTitle"),
2261
+ value: field.translations?.[editingLocale]?.title ?? "",
2262
+ onChange: (value) => updateManualTranslation({
2263
+ locale: editingLocale,
2264
+ kind: "field",
2265
+ nodeId: field.id,
2266
+ property: "title",
2267
+ sourceText: field.title,
2268
+ translatedText: value,
2269
+ ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2270
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2271
+ }
2272
+ })
2273
+ }
2274
+ ) }),
2275
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2276
+ TextInput,
2277
+ {
2278
+ id: `builder-field-${field.id}-${editingLocale}-description`,
2279
+ label: translate("builder.pageDescription"),
2280
+ value: field.translations?.[editingLocale]?.description ?? "",
2281
+ onChange: (value) => updateManualTranslation({
2282
+ locale: editingLocale,
2283
+ kind: "field",
2284
+ nodeId: field.id,
2285
+ property: "description",
2286
+ sourceText: field.description ?? "",
2287
+ translatedText: value,
2288
+ ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2289
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2290
+ }
2291
+ })
2292
+ }
2293
+ ) })
2294
+ ] }),
2295
+ "options" in field ? field.options.map((option, optionIndex) => /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2296
+ TextInput,
2297
+ {
2298
+ id: `builder-option-${option.id}-${editingLocale}`,
2299
+ label: `${translate("builder.optionLabel", { index: optionIndex + 1 })} (${editingLocale})`,
2300
+ value: option.translations?.[editingLocale] ?? "",
2301
+ onChange: (value) => updateManualTranslation({
2302
+ locale: editingLocale,
2303
+ kind: "option",
2304
+ nodeId: option.id,
2305
+ property: "label",
2306
+ sourceText: option.label,
2307
+ translatedText: value,
2308
+ ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2309
+ existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2310
+ }
2311
+ })
2240
2312
  }
2241
- })
2242
- }
2243
- ) }, option.id)) : null
2244
- ] }),
2245
- field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2246
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2247
- TextInput,
2248
- {
2249
- id: `builder-field-${field.id}-minimum`,
2250
- label: translate("builder.minimum"),
2251
- type: "number",
2252
- value: String(field.min ?? 1),
2253
- onChange: (value) => {
2254
- const min = Number(value);
2255
- if (!Number.isInteger(min)) return;
2256
- updateField(
2257
- field.id,
2258
- (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2259
- );
2260
- }
2261
- }
2262
- ) }),
2263
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2264
- TextInput,
2265
- {
2266
- id: `builder-field-${field.id}-maximum`,
2267
- label: translate("builder.maximum"),
2268
- type: "number",
2269
- value: String(field.max ?? 5),
2270
- onChange: (value) => {
2271
- const max = Number(value);
2272
- if (!Number.isInteger(max)) return;
2273
- updateField(
2274
- field.id,
2275
- (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2276
- );
2277
- }
2278
- }
2279
- ) })
2280
- ] }) : null,
2281
- "options" in field ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__options"), children: [
2282
- /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
2283
- field.options.map(
2284
- (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__option"), children: [
2285
- /* @__PURE__ */ jsx(
2313
+ ) }, option.id)) : null
2314
+ ] }),
2315
+ field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
2316
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2286
2317
  TextInput,
2287
2318
  {
2288
- id: `builder-option-${option.id}`,
2289
- label: translate("builder.optionLabel", { index: optionIndex + 1 }),
2290
- value: option.label,
2291
- placeholder: translate("builder.optionLabelPlaceholder"),
2292
- onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2319
+ id: `builder-field-${field.id}-minimum`,
2320
+ label: translate("builder.minimum"),
2321
+ type: "number",
2322
+ value: String(field.min ?? 1),
2323
+ onChange: (value) => {
2324
+ const min = Number(value);
2325
+ if (!Number.isInteger(min)) return;
2326
+ updateField(
2327
+ field.id,
2328
+ (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2329
+ );
2330
+ }
2293
2331
  }
2294
- ),
2295
- ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2296
- /* @__PURE__ */ jsx(
2297
- IconButton,
2298
- {
2299
- actionType: "moveUp",
2300
- title: translate("builder.moveUp", { title: option.label }),
2301
- disabled: optionIndex === 0,
2302
- onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2332
+ ) }),
2333
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2334
+ TextInput,
2335
+ {
2336
+ id: `builder-field-${field.id}-maximum`,
2337
+ label: translate("builder.maximum"),
2338
+ type: "number",
2339
+ value: String(field.max ?? 5),
2340
+ onChange: (value) => {
2341
+ const max = Number(value);
2342
+ if (!Number.isInteger(max)) return;
2343
+ updateField(
2344
+ field.id,
2345
+ (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2346
+ );
2303
2347
  }
2304
- ),
2348
+ }
2349
+ ) })
2350
+ ] }) : null,
2351
+ "options" in field ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__options"), children: [
2352
+ /* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
2353
+ field.options.map(
2354
+ (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__option"), children: [
2355
+ /* @__PURE__ */ jsx(
2356
+ TextInput,
2357
+ {
2358
+ id: `builder-option-${option.id}`,
2359
+ label: translate("builder.optionLabel", { index: optionIndex + 1 }),
2360
+ value: option.label,
2361
+ placeholder: translate("builder.optionLabelPlaceholder"),
2362
+ onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2363
+ }
2364
+ ),
2365
+ ToolbarSlot === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2366
+ /* @__PURE__ */ jsx(
2367
+ IconButton,
2368
+ {
2369
+ actionType: "moveUp",
2370
+ title: translate("builder.moveUp", { title: option.label }),
2371
+ disabled: optionIndex === 0,
2372
+ onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2373
+ }
2374
+ ),
2375
+ /* @__PURE__ */ jsx(
2376
+ IconButton,
2377
+ {
2378
+ actionType: "moveDown",
2379
+ title: translate("builder.moveDown", { title: option.label }),
2380
+ disabled: optionIndex === field.options.length - 1,
2381
+ onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2382
+ }
2383
+ ),
2384
+ /* @__PURE__ */ jsx(
2385
+ IconButton,
2386
+ {
2387
+ actionType: "delete",
2388
+ disabled: field.options.length === 1,
2389
+ onClick: () => removeOption(field.id, option.id),
2390
+ title: translate("builder.remove")
2391
+ }
2392
+ )
2393
+ ] }) : /* @__PURE__ */ jsx(
2394
+ ToolbarSlot,
2395
+ {
2396
+ schema,
2397
+ translate,
2398
+ kind: "option",
2399
+ targetId: option.id,
2400
+ index: optionIndex,
2401
+ total: field.options.length,
2402
+ title: option.label,
2403
+ onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2404
+ onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2405
+ onRemove: () => removeOption(field.id, option.id),
2406
+ readOnly,
2407
+ actions,
2408
+ components
2409
+ }
2410
+ )
2411
+ ] }, option.id) : /* @__PURE__ */ jsx(
2412
+ OptionEditorSlot,
2413
+ {
2414
+ schema,
2415
+ field,
2416
+ option,
2417
+ index: optionIndex,
2418
+ currentLocale: editingLocale,
2419
+ translate,
2420
+ readOnly,
2421
+ actions,
2422
+ components
2423
+ },
2424
+ option.id
2425
+ )
2426
+ ),
2427
+ /* @__PURE__ */ jsx(
2428
+ Button,
2429
+ {
2430
+ action: "addOption",
2431
+ targetId: field.id,
2432
+ disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2433
+ onClick: () => addOption(field.id),
2434
+ children: translate("builder.addOption")
2435
+ }
2436
+ )
2437
+ ] }) : null,
2438
+ conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
2439
+ /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2440
+ Select,
2441
+ {
2442
+ id: `builder-field-${field.id}-condition`,
2443
+ label: translate("builder.displayCondition"),
2444
+ value: condition?.questionId ?? "",
2445
+ onChange: (value) => {
2446
+ const selected = schema.fields.find((item) => item.id === value);
2447
+ setDisplayCondition(
2448
+ field.id,
2449
+ selected === void 0 ? void 0 : conditionWithValue(
2450
+ selected.id,
2451
+ conditionOperators(selected)[0] ?? "not_empty",
2452
+ defaultConditionValue(selected)
2453
+ )
2454
+ );
2455
+ },
2456
+ options: [
2457
+ { value: "", label: translate("builder.alwaysVisible") },
2458
+ ...availableSources.map((candidate) => ({
2459
+ value: candidate.id,
2460
+ label: candidate.title
2461
+ }))
2462
+ ]
2463
+ }
2464
+ ) }),
2465
+ condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2305
2466
  /* @__PURE__ */ jsx(
2306
- IconButton,
2467
+ Select,
2307
2468
  {
2308
- actionType: "moveDown",
2309
- title: translate("builder.moveDown", { title: option.label }),
2310
- disabled: optionIndex === field.options.length - 1,
2311
- onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2469
+ "aria-label": translate("builder.conditionOperator"),
2470
+ value: condition.operator,
2471
+ onChange: (value) => {
2472
+ const operator = value;
2473
+ setDisplayCondition(
2474
+ field.id,
2475
+ conditionWithValue(source.id, operator, defaultConditionValue(source))
2476
+ );
2477
+ },
2478
+ options: conditionOperators(source).map((operator) => ({
2479
+ value: operator,
2480
+ label: translate(operatorKey(operator))
2481
+ }))
2312
2482
  }
2313
2483
  ),
2314
2484
  /* @__PURE__ */ jsx(
2315
- IconButton,
2485
+ ConditionValueEditor,
2316
2486
  {
2317
- actionType: "delete",
2318
- disabled: field.options.length === 1,
2319
- onClick: () => removeOption(field.id, option.id),
2320
- title: translate("builder.remove")
2487
+ source,
2488
+ condition,
2489
+ onChange: (next) => setDisplayCondition(field.id, next),
2490
+ translate,
2491
+ components
2321
2492
  }
2322
2493
  )
2323
- ] }) : /* @__PURE__ */ jsx(
2324
- ToolbarSlot,
2325
- {
2326
- schema,
2327
- kind: "option",
2328
- targetId: option.id,
2329
- index: optionIndex,
2330
- total: field.options.length,
2331
- title: option.label,
2332
- onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2333
- onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2334
- onRemove: () => removeOption(field.id, option.id),
2335
- readOnly,
2336
- actions,
2337
- components
2338
- }
2339
- )
2340
- ] }, option.id) : /* @__PURE__ */ jsx(
2341
- OptionEditorSlot,
2342
- {
2343
- schema,
2344
- field,
2345
- option,
2346
- index: optionIndex,
2347
- currentLocale: editingLocale,
2348
- readOnly,
2349
- actions,
2350
- components
2351
- },
2352
- option.id
2353
- )
2354
- ),
2355
- /* @__PURE__ */ jsx(
2356
- Button,
2357
- {
2358
- action: "addOption",
2359
- targetId: field.id,
2360
- disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2361
- onClick: () => addOption(field.id),
2362
- children: translate("builder.addOption")
2363
- }
2364
- )
2365
- ] }) : null,
2366
- conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
2367
- /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
2368
- Select,
2369
- {
2370
- id: `builder-field-${field.id}-condition`,
2371
- label: translate("builder.displayCondition"),
2372
- value: condition?.questionId ?? "",
2373
- onChange: (value) => {
2374
- const selected = schema.fields.find((item) => item.id === value);
2375
- setDisplayCondition(
2376
- field.id,
2377
- selected === void 0 ? void 0 : conditionWithValue(
2378
- selected.id,
2379
- conditionOperators(selected)[0] ?? "not_empty",
2380
- defaultConditionValue(selected)
2381
- )
2382
- );
2383
- },
2384
- options: [
2385
- { value: "", label: translate("builder.alwaysVisible") },
2386
- ...availableSources.map((candidate) => ({ value: candidate.id, label: candidate.title }))
2387
- ]
2388
- }
2389
- ) }),
2390
- condition !== void 0 && source !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2391
- /* @__PURE__ */ jsx(
2392
- Select,
2393
- {
2394
- "aria-label": translate("builder.conditionOperator"),
2395
- value: condition.operator,
2396
- onChange: (value) => {
2397
- const operator = value;
2398
- setDisplayCondition(
2399
- field.id,
2400
- conditionWithValue(source.id, operator, defaultConditionValue(source))
2401
- );
2402
- },
2403
- options: conditionOperators(source).map((operator) => ({
2404
- value: operator,
2405
- label: translate(operatorKey(operator))
2406
- }))
2407
- }
2408
- ),
2409
- /* @__PURE__ */ jsx(
2410
- ConditionValueEditor,
2411
- {
2412
- source,
2413
- condition,
2414
- onChange: (next) => setDisplayCondition(field.id, next),
2415
- translate,
2416
- components
2417
- }
2418
- )
2419
- ] }) : null
2420
- ] }) : null
2421
- ] }, field.id);
2422
- }) }),
2423
- /* @__PURE__ */ jsx(
2494
+ ] }) : null
2495
+ ] }) : null
2496
+ ]
2497
+ },
2498
+ field.id
2499
+ );
2500
+ }) }) }),
2501
+ /* @__PURE__ */ jsx(BuilderSectionGroup, { name: "addQuestion", children: /* @__PURE__ */ jsx(
2424
2502
  Button,
2425
2503
  {
2426
2504
  className: builderClass("form-engine-builder__add"),
@@ -2429,8 +2507,8 @@ function FormBuilder({
2429
2507
  onClick: addField,
2430
2508
  children: translate("builder.addQuestion")
2431
2509
  }
2432
- )
2433
- ] })
2510
+ ) })
2511
+ ] }) })
2434
2512
  }
2435
2513
  )
2436
2514
  }