@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.cjs CHANGED
@@ -1199,6 +1199,7 @@ var BUILDER_DEFAULTS = {
1199
1199
  "builder.basicSettings": "Basic settings",
1200
1200
  "builder.formTitle": "Form title",
1201
1201
  "builder.formDescription": "Form description",
1202
+ "builder.description": "Description",
1202
1203
  "builder.moveUp": "Move {{title}} up",
1203
1204
  "builder.moveDown": "Move {{title}} down",
1204
1205
  "builder.delete": "Delete {{title}}",
@@ -1233,12 +1234,31 @@ var BUILDER_DEFAULTS = {
1233
1234
  "builder.pageQuestion": "Question to move to the new page",
1234
1235
  "builder.questionPage": "Page",
1235
1236
  "builder.pageCondition": "Page display condition",
1237
+ "builder.unassigned": "Unassigned",
1236
1238
  "builder.localization": "Localization",
1237
1239
  "builder.defaultLocale": "Default locale",
1238
1240
  "builder.supportedLocales": "Supported locales",
1239
1241
  "builder.addLocale": "Add locale",
1240
1242
  "builder.editLocale": "Edit locale",
1241
1243
  "builder.autoTranslate": "Translate all text",
1244
+ "builder.translating": "Translating\u2026",
1245
+ "builder.translationLocale": "Translation locale",
1246
+ "builder.selectLocale": "Select a locale to edit translations.",
1247
+ "builder.translation": "{{locale}} translation",
1248
+ "builder.translatedFormTitle": "Translated form title",
1249
+ "builder.translatedFormDescription": "Translated form description",
1250
+ "builder.translatedCompletionMessage": "Translated completion message",
1251
+ "builder.translatedQuestionTitle": "Translated question title",
1252
+ "builder.translatedDescription": "Translated description",
1253
+ "builder.actions.moveUp": "Move up",
1254
+ "builder.actions.moveDown": "Move down",
1255
+ "builder.actions.delete": "Delete",
1256
+ "builder.actions.add": "Add",
1257
+ "builder.actions.edit": "Edit",
1258
+ "builder.actions.settings": "Settings",
1259
+ "builder.actions.translate": "Translate",
1260
+ "builder.actions.close": "Close",
1261
+ "builder.actions.dragHandle": "Reorder",
1242
1262
  "builder.translationUnavailable": "Provide an async translation adapter to enable automatic translation.",
1243
1263
  "builder.fieldType.text": "Text",
1244
1264
  "builder.fieldType.textarea": "Textarea",
@@ -1259,6 +1279,22 @@ function interpolate(template, params) {
1259
1279
  (token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
1260
1280
  );
1261
1281
  }
1282
+ function BuilderSectionGroup({ children }) {
1283
+ return children;
1284
+ }
1285
+ function sectionGroupName(node) {
1286
+ if (!(0, import_react2.isValidElement)(node) || node.type !== BuilderSectionGroup) return void 0;
1287
+ return node.props.name;
1288
+ }
1289
+ function OrderedBuilderSections({
1290
+ order,
1291
+ children
1292
+ }) {
1293
+ if (order === void 0) return children;
1294
+ const ranks = new Map(order.map((name, index) => [name, index]));
1295
+ const groups = import_react2.Children.toArray(children);
1296
+ 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);
1297
+ }
1262
1298
  function fieldTypeKey(type) {
1263
1299
  return `builder.fieldType.${type}`;
1264
1300
  }
@@ -1361,6 +1397,7 @@ function FormBuilder({
1361
1397
  features,
1362
1398
  components: componentOverrides,
1363
1399
  slots,
1400
+ sectionOrder,
1364
1401
  disableDefaultStyles = false,
1365
1402
  unstyled = false
1366
1403
  }) {
@@ -1378,6 +1415,7 @@ function FormBuilder({
1378
1415
  const PagesSlot = slots?.pages;
1379
1416
  const LocalizationSlot = slots?.localization;
1380
1417
  const TranslationActionsSlot = slots?.translationActions;
1418
+ const resolvedSectionOrder = sectionOrder ?? slots?.sectionOrder;
1381
1419
  const headless = useFormBuilder({
1382
1420
  schema,
1383
1421
  onChange,
@@ -1392,7 +1430,11 @@ function FormBuilder({
1392
1430
  const [translationError, setTranslationError] = (0, import_react2.useState)(null);
1393
1431
  const [translationReport, setTranslationReport] = (0, import_react2.useState)();
1394
1432
  const translate = (key, params = {}) => {
1395
- const translated = translator?.translate(key, locale, params);
1433
+ const translatorParams = {};
1434
+ for (const [name, value] of Object.entries(params)) {
1435
+ if (typeof value === "string" || typeof value === "number") translatorParams[name] = value;
1436
+ }
1437
+ const translated = translator?.translate(key, locale, translatorParams);
1396
1438
  return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
1397
1439
  };
1398
1440
  const pagesEnabled = features?.pages ?? true;
@@ -1677,8 +1719,8 @@ function FormBuilder({
1677
1719
  addOption(fieldId);
1678
1720
  }
1679
1721
  },
1680
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Fieldset, { className: builderClass("form-engine-builder__controls"), disabled: readOnly, children: [
1681
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1722
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Fieldset, { className: builderClass("form-engine-builder__controls"), disabled: readOnly, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(OrderedBuilderSections, { ...resolvedSectionOrder === void 0 ? {} : { order: resolvedSectionOrder }, children: [
1723
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "basicSettings", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1682
1724
  Section,
1683
1725
  {
1684
1726
  className: builderClass("form-engine-builder__basic-settings"),
@@ -1712,8 +1754,17 @@ function FormBuilder({
1712
1754
  ) })
1713
1755
  ] })
1714
1756
  }
1715
- ),
1716
- pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1757
+ ) }),
1758
+ resolvedSectionOrder === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "completionMessage", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, { headingId: "builder-completion-message-heading", title: translate("builder.completionMessage"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1759
+ TextInput,
1760
+ {
1761
+ id: "builder-completion-message",
1762
+ label: translate("builder.completionMessage"),
1763
+ value: schema.completionMessage ?? "",
1764
+ onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1765
+ }
1766
+ ) }) }),
1767
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "questions", children: pagesEnabled ? PagesSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1717
1768
  Section,
1718
1769
  {
1719
1770
  className: builderClass("form-engine-builder__pages"),
@@ -1763,6 +1814,7 @@ function FormBuilder({
1763
1814
  ToolbarSlot,
1764
1815
  {
1765
1816
  schema,
1817
+ translate,
1766
1818
  kind: "page",
1767
1819
  targetId: page.id,
1768
1820
  index: pageIndex,
@@ -1909,7 +1961,10 @@ function FormBuilder({
1909
1961
  {
1910
1962
  source,
1911
1963
  condition: page.displayCondition,
1912
- onChange: (condition) => updatePage(page.id, (current) => ({ ...current, displayCondition: condition })),
1964
+ onChange: (condition) => updatePage(page.id, (current) => ({
1965
+ ...current,
1966
+ displayCondition: condition
1967
+ })),
1913
1968
  translate,
1914
1969
  components
1915
1970
  }
@@ -1944,20 +1999,22 @@ function FormBuilder({
1944
1999
  PagesSlot,
1945
2000
  {
1946
2001
  schema,
2002
+ translate,
1947
2003
  currentLocale: editingLocale,
2004
+ ...features === void 0 ? {} : { features },
1948
2005
  readOnly,
1949
2006
  actions,
1950
2007
  components
1951
2008
  }
1952
- ) : null,
1953
- localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2009
+ ) : null }),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "localization", children: localizationEnabled ? LocalizationSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1954
2011
  Section,
1955
2012
  {
1956
2013
  className: builderClass("form-engine-builder__localization"),
1957
2014
  headingId: "builder-localization-heading",
1958
2015
  title: translate("builder.localization"),
1959
2016
  children: [
1960
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2017
+ resolvedSectionOrder === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1961
2018
  TextInput,
1962
2019
  {
1963
2020
  id: "builder-completion-message",
@@ -1965,7 +2022,7 @@ function FormBuilder({
1965
2022
  value: schema.completionMessage ?? "",
1966
2023
  onChange: (value) => setSourceText({ kind: "form" }, "completionMessage", value)
1967
2024
  }
1968
- ) }),
2025
+ ) }) : null,
1969
2026
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
1970
2027
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1971
2028
  TextInput,
@@ -2030,12 +2087,14 @@ function FormBuilder({
2030
2087
  TranslationActionsSlot,
2031
2088
  {
2032
2089
  schema,
2090
+ translate,
2033
2091
  currentLocale: editingLocale,
2034
2092
  onAutoTranslate: () => void translateAll(),
2035
2093
  isTranslating,
2036
2094
  ...translationError === null ? {} : { translationError },
2037
2095
  ...translationReport === void 0 ? {} : { translationReport },
2038
2096
  onClearTranslationError: () => setTranslationError(null),
2097
+ translationAdapterAvailable: translationAdapter !== void 0,
2039
2098
  readOnly,
2040
2099
  actions,
2041
2100
  components
@@ -2079,17 +2138,20 @@ function FormBuilder({
2079
2138
  LocalizationSlot,
2080
2139
  {
2081
2140
  schema,
2141
+ translate,
2082
2142
  currentLocale: editingLocale,
2083
2143
  onCurrentLocaleChange: setEditingLocale,
2084
2144
  onAutoTranslate: () => void translateAll(),
2085
2145
  isTranslating,
2086
2146
  ...translationError === null ? {} : { translationError },
2147
+ ...policy === void 0 ? {} : { policy },
2148
+ translationAdapterAvailable: translationAdapter !== void 0,
2087
2149
  readOnly,
2088
2150
  actions,
2089
2151
  components
2090
2152
  }
2091
- ) : null,
2092
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
2153
+ ) : null }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "questions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
2093
2155
  const condition = field.displayCondition;
2094
2156
  const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
2095
2157
  const availableSources = schema.fields.slice(0, index);
@@ -2101,7 +2163,9 @@ function FormBuilder({
2101
2163
  field,
2102
2164
  index,
2103
2165
  currentLocale: editingLocale,
2166
+ translate,
2104
2167
  ...policy === void 0 ? {} : { policy },
2168
+ ...features === void 0 ? {} : { features },
2105
2169
  readOnly,
2106
2170
  actions,
2107
2171
  components
@@ -2109,348 +2173,362 @@ function FormBuilder({
2109
2173
  field.id
2110
2174
  );
2111
2175
  }
2112
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Fieldset, { className: builderClass("form-engine-builder__question"), legend: field.title, children: [
2113
- /* @__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: [
2114
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2115
- IconButton,
2116
- {
2117
- actionType: "moveUp",
2118
- title: translate("builder.moveUp", { title: field.title }),
2119
- disabled: index === 0,
2120
- onClick: () => moveField(index, -1)
2121
- }
2122
- ),
2123
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2124
- IconButton,
2125
- {
2126
- actionType: "moveDown",
2127
- title: translate("builder.moveDown", { title: field.title }),
2128
- disabled: index === schema.fields.length - 1,
2129
- onClick: () => moveField(index, 1)
2130
- }
2131
- ),
2132
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2133
- IconButton,
2134
- {
2135
- actionType: "delete",
2136
- disabled: schema.fields.length === 1,
2137
- onClick: () => removeField(field.id),
2138
- "aria-label": translate("builder.delete", { title: field.title }),
2139
- title: translate("builder.delete", { title: field.title })
2140
- }
2141
- )
2142
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2143
- ToolbarSlot,
2144
- {
2145
- schema,
2146
- kind: "field",
2147
- targetId: field.id,
2148
- index,
2149
- total: schema.fields.length,
2150
- title: field.title,
2151
- onMoveUp: () => moveField(index, -1),
2152
- onMoveDown: () => moveField(index, 1),
2153
- onRemove: () => removeField(field.id),
2154
- readOnly,
2155
- actions,
2156
- components
2157
- }
2158
- ) }),
2159
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2160
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2161
- TextInput,
2162
- {
2163
- id: `builder-field-${field.id}-title`,
2164
- name: `fields.${field.id}.title`,
2165
- label: translate("builder.questionTitle"),
2166
- required: true,
2167
- error: field.title.trim().length === 0,
2168
- helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2169
- "aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
2170
- value: field.title,
2171
- placeholder: translate("builder.questionTitlePlaceholder"),
2172
- onChange: (value) => updateField(field.id, (current) => ({
2173
- ...current,
2174
- title: value.trim().length === 0 ? current.title : value
2175
- }))
2176
- }
2177
- ) }),
2178
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2179
- Select,
2180
- {
2181
- id: `builder-field-${field.id}-type`,
2182
- label: translate("builder.type"),
2183
- value: field.type,
2184
- onChange: (value) => changeType(field.id, value),
2185
- options: FIELD_TYPES.filter(
2186
- (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2187
- ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
2188
- }
2189
- ) }),
2190
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2191
- Checkbox,
2192
- {
2193
- className: builderClass("form-engine-builder__check"),
2194
- checked: field.required === true,
2195
- onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2196
- label: translate("builder.required")
2197
- }
2198
- )
2199
- ] }),
2200
- !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)(
2201
- Select,
2202
- {
2203
- id: `builder-field-${field.id}-page`,
2204
- label: translate("builder.questionPage"),
2205
- value: pageForField(field.id)?.id ?? "",
2206
- onChange: (value) => assignFieldToPage(field.id, value),
2207
- options: schema.pages.map((page, pageIndex) => ({
2208
- value: page.id,
2209
- label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2210
- }))
2211
- }
2212
- ) }),
2213
- !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
2214
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: editingLocale }),
2215
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2216
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2217
- TextInput,
2176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2177
+ Fieldset,
2178
+ {
2179
+ className: builderClass("form-engine-builder__question"),
2180
+ legend: field.title,
2181
+ children: [
2182
+ /* @__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: [
2183
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2184
+ IconButton,
2185
+ {
2186
+ actionType: "moveUp",
2187
+ title: translate("builder.moveUp", { title: field.title }),
2188
+ disabled: index === 0,
2189
+ onClick: () => moveField(index, -1)
2190
+ }
2191
+ ),
2192
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2193
+ IconButton,
2194
+ {
2195
+ actionType: "moveDown",
2196
+ title: translate("builder.moveDown", { title: field.title }),
2197
+ disabled: index === schema.fields.length - 1,
2198
+ onClick: () => moveField(index, 1)
2199
+ }
2200
+ ),
2201
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2202
+ IconButton,
2203
+ {
2204
+ actionType: "delete",
2205
+ disabled: schema.fields.length === 1,
2206
+ onClick: () => removeField(field.id),
2207
+ "aria-label": translate("builder.delete", { title: field.title }),
2208
+ title: translate("builder.delete", { title: field.title })
2209
+ }
2210
+ )
2211
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2212
+ ToolbarSlot,
2218
2213
  {
2219
- id: `builder-field-${field.id}-${editingLocale}-title`,
2220
- label: translate("builder.questionTitle"),
2221
- value: field.translations?.[editingLocale]?.title ?? "",
2222
- onChange: (value) => updateManualTranslation({
2223
- locale: editingLocale,
2224
- kind: "field",
2225
- nodeId: field.id,
2226
- property: "title",
2227
- sourceText: field.title,
2228
- translatedText: value,
2229
- ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2230
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2231
- }
2232
- })
2214
+ schema,
2215
+ translate,
2216
+ kind: "field",
2217
+ targetId: field.id,
2218
+ index,
2219
+ total: schema.fields.length,
2220
+ title: field.title,
2221
+ onMoveUp: () => moveField(index, -1),
2222
+ onMoveDown: () => moveField(index, 1),
2223
+ onRemove: () => removeField(field.id),
2224
+ readOnly,
2225
+ actions,
2226
+ components
2233
2227
  }
2234
2228
  ) }),
2235
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2236
- TextInput,
2229
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2231
+ TextInput,
2232
+ {
2233
+ id: `builder-field-${field.id}-title`,
2234
+ name: `fields.${field.id}.title`,
2235
+ label: translate("builder.questionTitle"),
2236
+ required: true,
2237
+ error: field.title.trim().length === 0,
2238
+ helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
2239
+ "aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
2240
+ value: field.title,
2241
+ placeholder: translate("builder.questionTitlePlaceholder"),
2242
+ onChange: (value) => updateField(field.id, (current) => ({
2243
+ ...current,
2244
+ title: value.trim().length === 0 ? current.title : value
2245
+ }))
2246
+ }
2247
+ ) }),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2249
+ Select,
2250
+ {
2251
+ id: `builder-field-${field.id}-type`,
2252
+ label: translate("builder.type"),
2253
+ value: field.type,
2254
+ onChange: (value) => changeType(field.id, value),
2255
+ options: FIELD_TYPES.filter(
2256
+ (type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
2257
+ ).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) }))
2258
+ }
2259
+ ) }),
2260
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2261
+ Checkbox,
2262
+ {
2263
+ className: builderClass("form-engine-builder__check"),
2264
+ checked: field.required === true,
2265
+ onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
2266
+ label: translate("builder.required")
2267
+ }
2268
+ )
2269
+ ] }),
2270
+ !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)(
2271
+ Select,
2237
2272
  {
2238
- id: `builder-field-${field.id}-${editingLocale}-description`,
2239
- label: translate("builder.pageDescription"),
2240
- value: field.translations?.[editingLocale]?.description ?? "",
2241
- onChange: (value) => updateManualTranslation({
2242
- locale: editingLocale,
2243
- kind: "field",
2244
- nodeId: field.id,
2245
- property: "description",
2246
- sourceText: field.description ?? "",
2247
- translatedText: value,
2248
- ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2249
- existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2250
- }
2251
- })
2273
+ id: `builder-field-${field.id}-page`,
2274
+ label: translate("builder.questionPage"),
2275
+ value: pageForField(field.id)?.id ?? "",
2276
+ onChange: (value) => assignFieldToPage(field.id, value),
2277
+ options: schema.pages.map((page, pageIndex) => ({
2278
+ value: page.id,
2279
+ label: page.title ?? `${translate("builder.newPage")} ${pageIndex + 1}`
2280
+ }))
2252
2281
  }
2253
- ) })
2254
- ] }),
2255
- "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)(
2256
- TextInput,
2257
- {
2258
- id: `builder-option-${option.id}-${editingLocale}`,
2259
- label: `${translate("builder.optionLabel", { index: optionIndex + 1 })} (${editingLocale})`,
2260
- value: option.translations?.[editingLocale] ?? "",
2261
- onChange: (value) => updateManualTranslation({
2262
- locale: editingLocale,
2263
- kind: "option",
2264
- nodeId: option.id,
2265
- property: "label",
2266
- sourceText: option.label,
2267
- translatedText: value,
2268
- ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2269
- existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2282
+ ) }),
2283
+ !localizationEnabled || editingLocale.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__translation-editor"), children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: editingLocale }),
2285
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2286
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2287
+ TextInput,
2288
+ {
2289
+ id: `builder-field-${field.id}-${editingLocale}-title`,
2290
+ label: translate("builder.questionTitle"),
2291
+ value: field.translations?.[editingLocale]?.title ?? "",
2292
+ onChange: (value) => updateManualTranslation({
2293
+ locale: editingLocale,
2294
+ kind: "field",
2295
+ nodeId: field.id,
2296
+ property: "title",
2297
+ sourceText: field.title,
2298
+ translatedText: value,
2299
+ ...field.translationMetadata?.[editingLocale]?.title === void 0 ? {} : {
2300
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.title
2301
+ }
2302
+ })
2303
+ }
2304
+ ) }),
2305
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2306
+ TextInput,
2307
+ {
2308
+ id: `builder-field-${field.id}-${editingLocale}-description`,
2309
+ label: translate("builder.pageDescription"),
2310
+ value: field.translations?.[editingLocale]?.description ?? "",
2311
+ onChange: (value) => updateManualTranslation({
2312
+ locale: editingLocale,
2313
+ kind: "field",
2314
+ nodeId: field.id,
2315
+ property: "description",
2316
+ sourceText: field.description ?? "",
2317
+ translatedText: value,
2318
+ ...field.translationMetadata?.[editingLocale]?.description === void 0 ? {} : {
2319
+ existingTranslationMetadata: field.translationMetadata[editingLocale]?.description
2320
+ }
2321
+ })
2322
+ }
2323
+ ) })
2324
+ ] }),
2325
+ "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)(
2326
+ TextInput,
2327
+ {
2328
+ id: `builder-option-${option.id}-${editingLocale}`,
2329
+ label: `${translate("builder.optionLabel", { index: optionIndex + 1 })} (${editingLocale})`,
2330
+ value: option.translations?.[editingLocale] ?? "",
2331
+ onChange: (value) => updateManualTranslation({
2332
+ locale: editingLocale,
2333
+ kind: "option",
2334
+ nodeId: option.id,
2335
+ property: "label",
2336
+ sourceText: option.label,
2337
+ translatedText: value,
2338
+ ...option.translationMetadata?.[editingLocale]?.label === void 0 ? {} : {
2339
+ existingTranslationMetadata: option.translationMetadata[editingLocale]?.label
2340
+ }
2341
+ })
2270
2342
  }
2271
- })
2272
- }
2273
- ) }, option.id)) : null
2274
- ] }),
2275
- field.type === "rating" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2276
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2277
- TextInput,
2278
- {
2279
- id: `builder-field-${field.id}-minimum`,
2280
- label: translate("builder.minimum"),
2281
- type: "number",
2282
- value: String(field.min ?? 1),
2283
- onChange: (value) => {
2284
- const min = Number(value);
2285
- if (!Number.isInteger(min)) return;
2286
- updateField(
2287
- field.id,
2288
- (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2289
- );
2290
- }
2291
- }
2292
- ) }),
2293
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2294
- TextInput,
2295
- {
2296
- id: `builder-field-${field.id}-maximum`,
2297
- label: translate("builder.maximum"),
2298
- type: "number",
2299
- value: String(field.max ?? 5),
2300
- onChange: (value) => {
2301
- const max = Number(value);
2302
- if (!Number.isInteger(max)) return;
2303
- updateField(
2304
- field.id,
2305
- (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2306
- );
2307
- }
2308
- }
2309
- ) })
2310
- ] }) : null,
2311
- "options" in field ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__options"), children: [
2312
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: translate("builder.options") }),
2313
- field.options.map(
2314
- (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__option"), children: [
2315
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2343
+ ) }, option.id)) : null
2344
+ ] }),
2345
+ field.type === "rating" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
2346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2316
2347
  TextInput,
2317
2348
  {
2318
- id: `builder-option-${option.id}`,
2319
- label: translate("builder.optionLabel", { index: optionIndex + 1 }),
2320
- value: option.label,
2321
- placeholder: translate("builder.optionLabelPlaceholder"),
2322
- onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2349
+ id: `builder-field-${field.id}-minimum`,
2350
+ label: translate("builder.minimum"),
2351
+ type: "number",
2352
+ value: String(field.min ?? 1),
2353
+ onChange: (value) => {
2354
+ const min = Number(value);
2355
+ if (!Number.isInteger(min)) return;
2356
+ updateField(
2357
+ field.id,
2358
+ (current) => current.type === "rating" ? { ...current, min, max: Math.max(min, current.max ?? 5) } : current
2359
+ );
2360
+ }
2323
2361
  }
2324
- ),
2325
- ToolbarSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2326
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2327
- IconButton,
2328
- {
2329
- actionType: "moveUp",
2330
- title: translate("builder.moveUp", { title: option.label }),
2331
- disabled: optionIndex === 0,
2332
- onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2362
+ ) }),
2363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2364
+ TextInput,
2365
+ {
2366
+ id: `builder-field-${field.id}-maximum`,
2367
+ label: translate("builder.maximum"),
2368
+ type: "number",
2369
+ value: String(field.max ?? 5),
2370
+ onChange: (value) => {
2371
+ const max = Number(value);
2372
+ if (!Number.isInteger(max)) return;
2373
+ updateField(
2374
+ field.id,
2375
+ (current) => current.type === "rating" ? { ...current, min: Math.min(current.min ?? 1, max), max } : current
2376
+ );
2333
2377
  }
2334
- ),
2378
+ }
2379
+ ) })
2380
+ ] }) : null,
2381
+ "options" in field ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__options"), children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: translate("builder.options") }),
2383
+ field.options.map(
2384
+ (option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__option"), children: [
2385
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2386
+ TextInput,
2387
+ {
2388
+ id: `builder-option-${option.id}`,
2389
+ label: translate("builder.optionLabel", { index: optionIndex + 1 }),
2390
+ value: option.label,
2391
+ placeholder: translate("builder.optionLabelPlaceholder"),
2392
+ onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
2393
+ }
2394
+ ),
2395
+ ToolbarSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2396
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2397
+ IconButton,
2398
+ {
2399
+ actionType: "moveUp",
2400
+ title: translate("builder.moveUp", { title: option.label }),
2401
+ disabled: optionIndex === 0,
2402
+ onClick: () => moveOption(field.id, option.id, optionIndex - 1)
2403
+ }
2404
+ ),
2405
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2406
+ IconButton,
2407
+ {
2408
+ actionType: "moveDown",
2409
+ title: translate("builder.moveDown", { title: option.label }),
2410
+ disabled: optionIndex === field.options.length - 1,
2411
+ onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2412
+ }
2413
+ ),
2414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2415
+ IconButton,
2416
+ {
2417
+ actionType: "delete",
2418
+ disabled: field.options.length === 1,
2419
+ onClick: () => removeOption(field.id, option.id),
2420
+ title: translate("builder.remove")
2421
+ }
2422
+ )
2423
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2424
+ ToolbarSlot,
2425
+ {
2426
+ schema,
2427
+ translate,
2428
+ kind: "option",
2429
+ targetId: option.id,
2430
+ index: optionIndex,
2431
+ total: field.options.length,
2432
+ title: option.label,
2433
+ onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2434
+ onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2435
+ onRemove: () => removeOption(field.id, option.id),
2436
+ readOnly,
2437
+ actions,
2438
+ components
2439
+ }
2440
+ )
2441
+ ] }, option.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2442
+ OptionEditorSlot,
2443
+ {
2444
+ schema,
2445
+ field,
2446
+ option,
2447
+ index: optionIndex,
2448
+ currentLocale: editingLocale,
2449
+ translate,
2450
+ readOnly,
2451
+ actions,
2452
+ components
2453
+ },
2454
+ option.id
2455
+ )
2456
+ ),
2457
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2458
+ Button,
2459
+ {
2460
+ action: "addOption",
2461
+ targetId: field.id,
2462
+ disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2463
+ onClick: () => addOption(field.id),
2464
+ children: translate("builder.addOption")
2465
+ }
2466
+ )
2467
+ ] }) : null,
2468
+ conditionsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__condition"), children: [
2469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2470
+ Select,
2471
+ {
2472
+ id: `builder-field-${field.id}-condition`,
2473
+ label: translate("builder.displayCondition"),
2474
+ value: condition?.questionId ?? "",
2475
+ onChange: (value) => {
2476
+ const selected = schema.fields.find((item) => item.id === value);
2477
+ setDisplayCondition(
2478
+ field.id,
2479
+ selected === void 0 ? void 0 : conditionWithValue(
2480
+ selected.id,
2481
+ conditionOperators(selected)[0] ?? "not_empty",
2482
+ defaultConditionValue(selected)
2483
+ )
2484
+ );
2485
+ },
2486
+ options: [
2487
+ { value: "", label: translate("builder.alwaysVisible") },
2488
+ ...availableSources.map((candidate) => ({
2489
+ value: candidate.id,
2490
+ label: candidate.title
2491
+ }))
2492
+ ]
2493
+ }
2494
+ ) }),
2495
+ condition !== void 0 && source !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2335
2496
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2336
- IconButton,
2497
+ Select,
2337
2498
  {
2338
- actionType: "moveDown",
2339
- title: translate("builder.moveDown", { title: option.label }),
2340
- disabled: optionIndex === field.options.length - 1,
2341
- onClick: () => moveOption(field.id, option.id, optionIndex + 1)
2499
+ "aria-label": translate("builder.conditionOperator"),
2500
+ value: condition.operator,
2501
+ onChange: (value) => {
2502
+ const operator = value;
2503
+ setDisplayCondition(
2504
+ field.id,
2505
+ conditionWithValue(source.id, operator, defaultConditionValue(source))
2506
+ );
2507
+ },
2508
+ options: conditionOperators(source).map((operator) => ({
2509
+ value: operator,
2510
+ label: translate(operatorKey(operator))
2511
+ }))
2342
2512
  }
2343
2513
  ),
2344
2514
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2345
- IconButton,
2515
+ ConditionValueEditor,
2346
2516
  {
2347
- actionType: "delete",
2348
- disabled: field.options.length === 1,
2349
- onClick: () => removeOption(field.id, option.id),
2350
- title: translate("builder.remove")
2517
+ source,
2518
+ condition,
2519
+ onChange: (next) => setDisplayCondition(field.id, next),
2520
+ translate,
2521
+ components
2351
2522
  }
2352
2523
  )
2353
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2354
- ToolbarSlot,
2355
- {
2356
- schema,
2357
- kind: "option",
2358
- targetId: option.id,
2359
- index: optionIndex,
2360
- total: field.options.length,
2361
- title: option.label,
2362
- onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
2363
- onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
2364
- onRemove: () => removeOption(field.id, option.id),
2365
- readOnly,
2366
- actions,
2367
- components
2368
- }
2369
- )
2370
- ] }, option.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2371
- OptionEditorSlot,
2372
- {
2373
- schema,
2374
- field,
2375
- option,
2376
- index: optionIndex,
2377
- currentLocale: editingLocale,
2378
- readOnly,
2379
- actions,
2380
- components
2381
- },
2382
- option.id
2383
- )
2384
- ),
2385
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2386
- Button,
2387
- {
2388
- action: "addOption",
2389
- targetId: field.id,
2390
- disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
2391
- onClick: () => addOption(field.id),
2392
- children: translate("builder.addOption")
2393
- }
2394
- )
2395
- ] }) : null,
2396
- conditionsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__condition"), children: [
2397
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2398
- Select,
2399
- {
2400
- id: `builder-field-${field.id}-condition`,
2401
- label: translate("builder.displayCondition"),
2402
- value: condition?.questionId ?? "",
2403
- onChange: (value) => {
2404
- const selected = schema.fields.find((item) => item.id === value);
2405
- setDisplayCondition(
2406
- field.id,
2407
- selected === void 0 ? void 0 : conditionWithValue(
2408
- selected.id,
2409
- conditionOperators(selected)[0] ?? "not_empty",
2410
- defaultConditionValue(selected)
2411
- )
2412
- );
2413
- },
2414
- options: [
2415
- { value: "", label: translate("builder.alwaysVisible") },
2416
- ...availableSources.map((candidate) => ({ value: candidate.id, label: candidate.title }))
2417
- ]
2418
- }
2419
- ) }),
2420
- condition !== void 0 && source !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2421
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2422
- Select,
2423
- {
2424
- "aria-label": translate("builder.conditionOperator"),
2425
- value: condition.operator,
2426
- onChange: (value) => {
2427
- const operator = value;
2428
- setDisplayCondition(
2429
- field.id,
2430
- conditionWithValue(source.id, operator, defaultConditionValue(source))
2431
- );
2432
- },
2433
- options: conditionOperators(source).map((operator) => ({
2434
- value: operator,
2435
- label: translate(operatorKey(operator))
2436
- }))
2437
- }
2438
- ),
2439
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2440
- ConditionValueEditor,
2441
- {
2442
- source,
2443
- condition,
2444
- onChange: (next) => setDisplayCondition(field.id, next),
2445
- translate,
2446
- components
2447
- }
2448
- )
2449
- ] }) : null
2450
- ] }) : null
2451
- ] }, field.id);
2452
- }) }),
2453
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2524
+ ] }) : null
2525
+ ] }) : null
2526
+ ]
2527
+ },
2528
+ field.id
2529
+ );
2530
+ }) }) }),
2531
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderSectionGroup, { name: "addQuestion", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2454
2532
  Button,
2455
2533
  {
2456
2534
  className: builderClass("form-engine-builder__add"),
@@ -2459,8 +2537,8 @@ function FormBuilder({
2459
2537
  onClick: addField,
2460
2538
  children: translate("builder.addQuestion")
2461
2539
  }
2462
- )
2463
- ] })
2540
+ ) })
2541
+ ] }) })
2464
2542
  }
2465
2543
  )
2466
2544
  }