@form-engine-ts/react 3.2.0 → 4.1.0
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/README.md +9 -1
- package/dist/index.cjs +209 -37
- package/dist/index.d.cts +53 -10
- package/dist/index.d.ts +53 -10
- package/dist/index.js +205 -37
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -72,6 +72,11 @@ controls `pages`, `localization`, and `conditions` authoring surfaces; each defa
|
|
|
72
72
|
set, locale addition becomes a selector containing only unregistered allowed locales, and the action is disabled at
|
|
73
73
|
`maxLocales`.
|
|
74
74
|
|
|
75
|
+
`fieldEditorControls` makes the standard field editor's title, description, required flag, type selector, options,
|
|
76
|
+
display conditions, text limits, rating bounds, and number limits independently `editable`, `readOnly`, or `hidden`.
|
|
77
|
+
`fieldTypeOptions` can provide an explicit order, comparator, or transformation for generated type choices; the default
|
|
78
|
+
choices are copied before they are changed.
|
|
79
|
+
|
|
75
80
|
Visual Builder has two independent design-system extension layers. `components` replaces normalized primitives such as
|
|
76
81
|
`Button`, `TextInput`, `TextArea`, `Select`, `Checkbox`, `Section`, and `Fieldset`. `slots` replaces complete authoring
|
|
77
82
|
surfaces: `toolbar`, `fieldEditor`, `optionEditor`, `pages`, `localization`, or `translationActions`. Slot props expose
|
|
@@ -96,11 +101,14 @@ When either is enabled, the builder omits its `form-engine-builder` and `feb-*`
|
|
|
96
101
|
and `Select` components receive the field `label` and accessibility attributes and are responsible for rendering their
|
|
97
102
|
own labels. Builder action icons can be supplied with `renderIcon`, which resolves `actionType` values such as
|
|
98
103
|
`moveUp`, `moveDown`, `delete`, and `add`. `renderFieldTypeIcon` supplies icons for field-type selectors. Select
|
|
99
|
-
options may be strings or `BuilderSelectOption` objects with `icon`, `description`, `
|
|
104
|
+
options may be strings or `BuilderSelectOption` objects with `icon`, `description`, `group`, `groupLabel`, `kind`, and
|
|
105
|
+
`metadata`; custom
|
|
100
106
|
`renderOption` and `renderValue` functions can control their presentation. `BUILDER_TRANSLATION_KEYS` exposes the
|
|
101
107
|
canonical typed builder translation keys while legacy catalog aliases remain supported.
|
|
102
108
|
|
|
103
109
|
The `fieldEditor` slot can expose only the type selector or header through `fieldTypeSelect` and `fieldEditorHeader`:
|
|
110
|
+
The `fieldTypeSelect` slot receives the resolved `id`, `name`, `label`, `options`, and accessibility attributes in addition
|
|
111
|
+
to `currentType`, `allowedTypes`, and `onChangeType`.
|
|
104
112
|
|
|
105
113
|
```tsx
|
|
106
114
|
<FormBuilder
|
package/dist/index.cjs
CHANGED
|
@@ -28,7 +28,11 @@ __export(index_exports, {
|
|
|
28
28
|
FormSubmissionError: () => FormSubmissionError,
|
|
29
29
|
createLocalStorageSubmissionAttemptStore: () => createLocalStorageSubmissionAttemptStore,
|
|
30
30
|
createLocalStorageSubmissionReceiptStore: () => createLocalStorageSubmissionReceiptStore,
|
|
31
|
+
isTranslationUnresolved: () => isTranslationUnresolved,
|
|
32
|
+
resolveFieldEditorControls: () => resolveFieldEditorControls,
|
|
33
|
+
resolveFieldTypeSelectOptions: () => resolveFieldTypeSelectOptions,
|
|
31
34
|
resolveInitialFieldType: () => resolveInitialFieldType,
|
|
35
|
+
resolveTranslation: () => resolveTranslation,
|
|
32
36
|
submissionReceiptQueryKey: () => submissionReceiptQueryKey,
|
|
33
37
|
useField: () => useField,
|
|
34
38
|
useForm: () => useForm,
|
|
@@ -802,6 +806,41 @@ var BUILDER_TRANSLATION_ALIASES = {
|
|
|
802
806
|
"builder.fields.typeSelect": "builder.fieldType.select",
|
|
803
807
|
"builder.fields.typeMultiSelect": "builder.fieldType.multi-select"
|
|
804
808
|
};
|
|
809
|
+
function isTranslationUnresolved(result, key, aliases = []) {
|
|
810
|
+
if (result === void 0 || result === null || result === "") return true;
|
|
811
|
+
if (typeof result !== "string") return false;
|
|
812
|
+
if (result === key || aliases.includes(result)) return true;
|
|
813
|
+
return result.endsWith(key) || aliases.some((alias) => result.endsWith(alias));
|
|
814
|
+
}
|
|
815
|
+
function isResolvedAdapterResult(result, key, aliases) {
|
|
816
|
+
return typeof result === "string" && result.startsWith("translated:") ? true : !isTranslationUnresolved(result, key, aliases);
|
|
817
|
+
}
|
|
818
|
+
function formatTemplate(template, params) {
|
|
819
|
+
return template.replace(
|
|
820
|
+
/\{\{(\w+)\}\}/g,
|
|
821
|
+
(token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
function resolveTranslation(key, aliases, adapter, defaultCatalog, params = {}, locale = "") {
|
|
825
|
+
const adapterParams = {};
|
|
826
|
+
for (const [name, value] of Object.entries(params)) {
|
|
827
|
+
if (typeof value === "string" || typeof value === "number") adapterParams[name] = value;
|
|
828
|
+
}
|
|
829
|
+
const translate = (candidate) => adapter?.translate(candidate, locale, adapterParams);
|
|
830
|
+
const translated = translate(key);
|
|
831
|
+
if (isResolvedAdapterResult(translated, key, aliases)) return translated;
|
|
832
|
+
for (const alias of aliases) {
|
|
833
|
+
const aliased = translate(alias);
|
|
834
|
+
if (isResolvedAdapterResult(aliased, alias, aliases)) return aliased;
|
|
835
|
+
}
|
|
836
|
+
const catalogValue = defaultCatalog?.[key];
|
|
837
|
+
if (catalogValue !== void 0) return formatTemplate(catalogValue, params);
|
|
838
|
+
for (const alias of aliases) {
|
|
839
|
+
const aliasValue = defaultCatalog?.[alias];
|
|
840
|
+
if (aliasValue !== void 0) return formatTemplate(aliasValue, params);
|
|
841
|
+
}
|
|
842
|
+
return key;
|
|
843
|
+
}
|
|
805
844
|
|
|
806
845
|
// src/builder.tsx
|
|
807
846
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -1254,6 +1293,34 @@ var FIELD_TYPES = [
|
|
|
1254
1293
|
"checkbox",
|
|
1255
1294
|
"radio"
|
|
1256
1295
|
];
|
|
1296
|
+
var DEFAULT_FIELD_EDITOR_CONTROL_MODE = "editable";
|
|
1297
|
+
function resolveFieldEditorControls(config = {}) {
|
|
1298
|
+
return {
|
|
1299
|
+
title: config.title ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1300
|
+
description: config.description ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1301
|
+
required: config.required ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1302
|
+
typeSelect: config.typeSelect ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1303
|
+
options: config.options ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1304
|
+
displayConditions: config.displayConditions ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1305
|
+
textLimits: config.textLimits ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1306
|
+
ratingBounds: config.ratingBounds ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1307
|
+
numberLimits: config.numberLimits ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
function resolveFieldTypeSelectOptions(options, config, context) {
|
|
1311
|
+
let resolved = [...options];
|
|
1312
|
+
if (config?.transform !== void 0) resolved = [...config.transform(resolved, context)];
|
|
1313
|
+
if (config?.order !== void 0) {
|
|
1314
|
+
const ranks = new Map(config.order.map((type, index) => [type, index]));
|
|
1315
|
+
resolved.sort((left, right) => {
|
|
1316
|
+
const leftRank = ranks.get(left.value) ?? config.order?.length ?? 0;
|
|
1317
|
+
const rightRank = ranks.get(right.value) ?? config.order?.length ?? 0;
|
|
1318
|
+
return leftRank - rightRank;
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
if (config?.sort !== void 0) resolved.sort((left, right) => config.sort?.(left, right, context) ?? 0);
|
|
1322
|
+
return resolved;
|
|
1323
|
+
}
|
|
1257
1324
|
var BUILDER_DEFAULTS = {
|
|
1258
1325
|
"builder.formBuilder": "Form builder",
|
|
1259
1326
|
"builder.basicSettings": "Basic settings",
|
|
@@ -1272,6 +1339,10 @@ var BUILDER_DEFAULTS = {
|
|
|
1272
1339
|
"builder.required": "Required",
|
|
1273
1340
|
"builder.minimum": "Minimum",
|
|
1274
1341
|
"builder.maximum": "Maximum",
|
|
1342
|
+
"builder.minimumLength": "Minimum length",
|
|
1343
|
+
"builder.maximumLength": "Maximum length",
|
|
1344
|
+
"builder.pattern": "Pattern",
|
|
1345
|
+
"builder.step": "Step",
|
|
1275
1346
|
"builder.options": "Options",
|
|
1276
1347
|
"builder.optionLabel": "\u9078\u629E\u80A2 / Option Label {{index}}",
|
|
1277
1348
|
"builder.optionLabelPlaceholder": "Example: Very satisfied",
|
|
@@ -1334,6 +1405,18 @@ var BUILDER_DEFAULTS = {
|
|
|
1334
1405
|
"builder.fields.typeMultiSelect": "Multi-select",
|
|
1335
1406
|
"builder.fields.typeCheckbox": "Checkbox",
|
|
1336
1407
|
"builder.fields.typeRadio": "Radio",
|
|
1408
|
+
"builder.fieldCategory.text": "Text",
|
|
1409
|
+
"builder.fieldCategory.choice": "Choice",
|
|
1410
|
+
"builder.fieldCategory.number": "Number",
|
|
1411
|
+
"builder.fieldCategory.advanced": "Advanced",
|
|
1412
|
+
"builder.fieldTypeDescription.text": "A single-line text answer",
|
|
1413
|
+
"builder.fieldTypeDescription.textarea": "A long-form text answer",
|
|
1414
|
+
"builder.fieldTypeDescription.number": "A numeric answer",
|
|
1415
|
+
"builder.fieldTypeDescription.rating": "A rating scale answer",
|
|
1416
|
+
"builder.fieldTypeDescription.radio": "A single-choice answer",
|
|
1417
|
+
"builder.fieldTypeDescription.checkbox": "A yes/no answer",
|
|
1418
|
+
"builder.fieldTypeDescription.select": "A dropdown choice",
|
|
1419
|
+
"builder.fieldTypeDescription.multi-select": "Multiple choices",
|
|
1337
1420
|
"builder.actions.addField": "Add question",
|
|
1338
1421
|
"builder.fieldType.text": "Text",
|
|
1339
1422
|
"builder.fieldType.textarea": "Textarea",
|
|
@@ -1348,12 +1431,6 @@ var BUILDER_DEFAULTS = {
|
|
|
1348
1431
|
"builder.operator.contains": "contains",
|
|
1349
1432
|
"builder.operator.not_empty": "is not empty"
|
|
1350
1433
|
};
|
|
1351
|
-
function interpolate(template, params) {
|
|
1352
|
-
return template.replace(
|
|
1353
|
-
/\{\{(\w+)\}\}/g,
|
|
1354
|
-
(token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
|
|
1355
|
-
);
|
|
1356
|
-
}
|
|
1357
1434
|
function BuilderSectionGroup({ children }) {
|
|
1358
1435
|
return children;
|
|
1359
1436
|
}
|
|
@@ -1523,6 +1600,8 @@ function FormBuilder({
|
|
|
1523
1600
|
createManualTranslationMetadata,
|
|
1524
1601
|
readOnly = false,
|
|
1525
1602
|
features,
|
|
1603
|
+
fieldEditorControls,
|
|
1604
|
+
fieldTypeOptions,
|
|
1526
1605
|
components: componentOverrides,
|
|
1527
1606
|
slots,
|
|
1528
1607
|
sectionOrder,
|
|
@@ -1558,20 +1637,14 @@ function FormBuilder({
|
|
|
1558
1637
|
const [isTranslating, setIsTranslating] = (0, import_react2.useState)(false);
|
|
1559
1638
|
const [translationError, setTranslationError] = (0, import_react2.useState)(null);
|
|
1560
1639
|
const [translationReport, setTranslationReport] = (0, import_react2.useState)();
|
|
1561
|
-
const translate = (key, params = {}) =>
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
if (alias !== void 0) {
|
|
1570
|
-
const aliased = translator?.translate(alias, locale, translatorParams);
|
|
1571
|
-
if (aliased !== void 0 && aliased !== alias) return aliased;
|
|
1572
|
-
}
|
|
1573
|
-
return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
|
|
1574
|
-
};
|
|
1640
|
+
const translate = (key, params = {}) => resolveTranslation(
|
|
1641
|
+
key,
|
|
1642
|
+
BUILDER_TRANSLATION_ALIASES[key] === void 0 ? [] : [BUILDER_TRANSLATION_ALIASES[key]],
|
|
1643
|
+
translator,
|
|
1644
|
+
BUILDER_DEFAULTS,
|
|
1645
|
+
params,
|
|
1646
|
+
locale
|
|
1647
|
+
);
|
|
1575
1648
|
const pagesEnabled = features?.pages ?? true;
|
|
1576
1649
|
const localizationEnabled = features?.localization ?? true;
|
|
1577
1650
|
const conditionsEnabled = features?.conditions ?? true;
|
|
@@ -2293,6 +2366,7 @@ function FormBuilder({
|
|
|
2293
2366
|
}
|
|
2294
2367
|
) : null }),
|
|
2295
2368
|
/* @__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) => {
|
|
2369
|
+
const controls = resolveFieldEditorControls(fieldEditorControls);
|
|
2296
2370
|
const condition = field.displayCondition;
|
|
2297
2371
|
const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
|
|
2298
2372
|
const availableSources = schema.fields.slice(0, index);
|
|
@@ -2308,6 +2382,8 @@ function FormBuilder({
|
|
|
2308
2382
|
...slots === void 0 ? {} : { slots },
|
|
2309
2383
|
...policy === void 0 ? {} : { policy },
|
|
2310
2384
|
...features === void 0 ? {} : { features },
|
|
2385
|
+
...fieldEditorControls === void 0 ? {} : { fieldEditorControls },
|
|
2386
|
+
...fieldTypeOptions === void 0 ? {} : { fieldTypeOptions },
|
|
2311
2387
|
readOnly,
|
|
2312
2388
|
actions,
|
|
2313
2389
|
components
|
|
@@ -2369,7 +2445,7 @@ function FormBuilder({
|
|
|
2369
2445
|
}
|
|
2370
2446
|
) }),
|
|
2371
2447
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2372
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2448
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2373
2449
|
TextInput,
|
|
2374
2450
|
{
|
|
2375
2451
|
id: `builder-field-${field.id}-title`,
|
|
@@ -2381,34 +2457,56 @@ function FormBuilder({
|
|
|
2381
2457
|
"aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
|
|
2382
2458
|
value: field.title,
|
|
2383
2459
|
placeholder: translate("builder.questionTitlePlaceholder"),
|
|
2460
|
+
readOnly: controls.title === "readOnly",
|
|
2384
2461
|
onChange: (value) => updateField(field.id, (current) => ({
|
|
2385
2462
|
...current,
|
|
2386
2463
|
title: value.trim().length === 0 ? current.title : value
|
|
2387
2464
|
}))
|
|
2388
2465
|
}
|
|
2389
2466
|
) }),
|
|
2390
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2467
|
+
controls.typeSelect === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2391
2468
|
Select,
|
|
2392
2469
|
{
|
|
2393
2470
|
id: `builder-field-${field.id}-type`,
|
|
2394
2471
|
label: translate("builder.type"),
|
|
2395
2472
|
value: field.type,
|
|
2473
|
+
disabled: controls.typeSelect === "readOnly",
|
|
2396
2474
|
onChange: (value) => changeType(field.id, value),
|
|
2397
|
-
options:
|
|
2398
|
-
|
|
2399
|
-
|
|
2475
|
+
options: resolveFieldTypeSelectOptions(
|
|
2476
|
+
FIELD_TYPES.filter(
|
|
2477
|
+
(type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
|
|
2478
|
+
).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) })),
|
|
2479
|
+
fieldTypeOptions,
|
|
2480
|
+
{ currentType: field.type, allowedTypes: policy?.allowedFieldTypes ?? FIELD_TYPES }
|
|
2481
|
+
)
|
|
2400
2482
|
}
|
|
2401
2483
|
) }),
|
|
2402
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2484
|
+
controls.required === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2403
2485
|
Checkbox,
|
|
2404
2486
|
{
|
|
2405
2487
|
className: builderClass("form-engine-builder__check"),
|
|
2406
2488
|
checked: field.required === true,
|
|
2489
|
+
disabled: controls.required === "readOnly",
|
|
2407
2490
|
onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
|
|
2408
2491
|
label: translate("builder.required")
|
|
2409
2492
|
}
|
|
2410
2493
|
)
|
|
2411
2494
|
] }),
|
|
2495
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2496
|
+
TextArea,
|
|
2497
|
+
{
|
|
2498
|
+
id: `builder-field-${field.id}-description`,
|
|
2499
|
+
name: `fields.${field.id}.description`,
|
|
2500
|
+
label: translate("builder.description"),
|
|
2501
|
+
value: field.description ?? "",
|
|
2502
|
+
readOnly: controls.description === "readOnly",
|
|
2503
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2504
|
+
if (value.length > 0) return { ...current, description: value };
|
|
2505
|
+
const { description: _description, ...remaining } = current;
|
|
2506
|
+
return remaining;
|
|
2507
|
+
})
|
|
2508
|
+
}
|
|
2509
|
+
) }),
|
|
2412
2510
|
!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)(
|
|
2413
2511
|
Select,
|
|
2414
2512
|
{
|
|
@@ -2444,12 +2542,13 @@ function FormBuilder({
|
|
|
2444
2542
|
})
|
|
2445
2543
|
}
|
|
2446
2544
|
) }),
|
|
2447
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2545
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2448
2546
|
TextInput,
|
|
2449
2547
|
{
|
|
2450
2548
|
id: `builder-field-${field.id}-${editingLocale}-description`,
|
|
2451
2549
|
label: translate("builder.pageDescription"),
|
|
2452
2550
|
value: field.translations?.[editingLocale]?.description ?? "",
|
|
2551
|
+
readOnly: controls.description === "readOnly",
|
|
2453
2552
|
onChange: (value) => updateManualTranslation({
|
|
2454
2553
|
locale: editingLocale,
|
|
2455
2554
|
kind: "field",
|
|
@@ -2484,7 +2583,7 @@ function FormBuilder({
|
|
|
2484
2583
|
}
|
|
2485
2584
|
) }, option.id)) : null
|
|
2486
2585
|
] }),
|
|
2487
|
-
field.type === "rating" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2586
|
+
field.type === "rating" && controls.ratingBounds !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2488
2587
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2489
2588
|
TextInput,
|
|
2490
2589
|
{
|
|
@@ -2492,6 +2591,7 @@ function FormBuilder({
|
|
|
2492
2591
|
label: translate("builder.minimum"),
|
|
2493
2592
|
type: "number",
|
|
2494
2593
|
value: String(field.min ?? 1),
|
|
2594
|
+
readOnly: controls.ratingBounds === "readOnly",
|
|
2495
2595
|
onChange: (value) => {
|
|
2496
2596
|
const min = Number(value);
|
|
2497
2597
|
if (!Number.isInteger(min)) return;
|
|
@@ -2509,6 +2609,7 @@ function FormBuilder({
|
|
|
2509
2609
|
label: translate("builder.maximum"),
|
|
2510
2610
|
type: "number",
|
|
2511
2611
|
value: String(field.max ?? 5),
|
|
2612
|
+
readOnly: controls.ratingBounds === "readOnly",
|
|
2512
2613
|
onChange: (value) => {
|
|
2513
2614
|
const max = Number(value);
|
|
2514
2615
|
if (!Number.isInteger(max)) return;
|
|
@@ -2520,7 +2621,73 @@ function FormBuilder({
|
|
|
2520
2621
|
}
|
|
2521
2622
|
) })
|
|
2522
2623
|
] }) : null,
|
|
2523
|
-
"
|
|
2624
|
+
(field.type === "text" || field.type === "textarea") && controls.textLimits !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2625
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2626
|
+
TextInput,
|
|
2627
|
+
{
|
|
2628
|
+
id: `builder-field-${field.id}-min-length`,
|
|
2629
|
+
label: translate("builder.minimumLength"),
|
|
2630
|
+
type: "number",
|
|
2631
|
+
value: field.minLength === void 0 ? "" : String(field.minLength),
|
|
2632
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2633
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2634
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2635
|
+
const parsed = value.trim().length === 0 ? void 0 : Number(value);
|
|
2636
|
+
return parsed === void 0 || !Number.isInteger(parsed) || parsed < 0 ? current : { ...current, minLength: parsed };
|
|
2637
|
+
})
|
|
2638
|
+
}
|
|
2639
|
+
) }),
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2641
|
+
TextInput,
|
|
2642
|
+
{
|
|
2643
|
+
id: `builder-field-${field.id}-max-length`,
|
|
2644
|
+
label: translate("builder.maximumLength"),
|
|
2645
|
+
type: "number",
|
|
2646
|
+
value: field.maxLength === void 0 ? "" : String(field.maxLength),
|
|
2647
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2648
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2649
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2650
|
+
const parsed = value.trim().length === 0 ? void 0 : Number(value);
|
|
2651
|
+
return parsed === void 0 || !Number.isInteger(parsed) || parsed < 0 ? current : { ...current, maxLength: parsed };
|
|
2652
|
+
})
|
|
2653
|
+
}
|
|
2654
|
+
) }),
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2656
|
+
TextInput,
|
|
2657
|
+
{
|
|
2658
|
+
id: `builder-field-${field.id}-pattern`,
|
|
2659
|
+
label: translate("builder.pattern"),
|
|
2660
|
+
value: field.pattern ?? "",
|
|
2661
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2662
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2663
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2664
|
+
return value.length === 0 ? current : { ...current, pattern: value };
|
|
2665
|
+
})
|
|
2666
|
+
}
|
|
2667
|
+
) })
|
|
2668
|
+
] }) : null,
|
|
2669
|
+
field.type === "number" && controls.numberLimits !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__grid"), children: ["min", "max", "step"].map((property) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2670
|
+
TextInput,
|
|
2671
|
+
{
|
|
2672
|
+
id: `builder-field-${field.id}-${property}`,
|
|
2673
|
+
label: translate(
|
|
2674
|
+
property === "step" ? "builder.step" : property === "min" ? "builder.minimum" : "builder.maximum"
|
|
2675
|
+
),
|
|
2676
|
+
type: "number",
|
|
2677
|
+
value: field[property] === void 0 ? "" : String(field[property]),
|
|
2678
|
+
readOnly: controls.numberLimits === "readOnly",
|
|
2679
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2680
|
+
if (current.type !== "number") return current;
|
|
2681
|
+
if (value.trim().length === 0) {
|
|
2682
|
+
const { [property]: _removed, ...remaining } = current;
|
|
2683
|
+
return remaining;
|
|
2684
|
+
}
|
|
2685
|
+
const parsed = Number(value);
|
|
2686
|
+
return Number.isFinite(parsed) ? { ...current, [property]: parsed } : current;
|
|
2687
|
+
})
|
|
2688
|
+
}
|
|
2689
|
+
) }, property)) }) : null,
|
|
2690
|
+
"options" in field && controls.options !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__options"), children: [
|
|
2524
2691
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: translate("builder.options") }),
|
|
2525
2692
|
field.options.map(
|
|
2526
2693
|
(option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__option"), children: [
|
|
@@ -2531,6 +2698,7 @@ function FormBuilder({
|
|
|
2531
2698
|
label: translate("builder.optionLabel", { index: optionIndex + 1 }),
|
|
2532
2699
|
value: option.label,
|
|
2533
2700
|
placeholder: translate("builder.optionLabelPlaceholder"),
|
|
2701
|
+
readOnly: controls.options === "readOnly",
|
|
2534
2702
|
onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
|
|
2535
2703
|
}
|
|
2536
2704
|
),
|
|
@@ -2540,7 +2708,7 @@ function FormBuilder({
|
|
|
2540
2708
|
{
|
|
2541
2709
|
actionType: "moveUp",
|
|
2542
2710
|
title: translate("builder.moveUp", { title: option.label }),
|
|
2543
|
-
disabled: optionIndex === 0,
|
|
2711
|
+
disabled: controls.options === "readOnly" || optionIndex === 0,
|
|
2544
2712
|
onClick: () => moveOption(field.id, option.id, optionIndex - 1)
|
|
2545
2713
|
}
|
|
2546
2714
|
),
|
|
@@ -2549,7 +2717,7 @@ function FormBuilder({
|
|
|
2549
2717
|
{
|
|
2550
2718
|
actionType: "moveDown",
|
|
2551
2719
|
title: translate("builder.moveDown", { title: option.label }),
|
|
2552
|
-
disabled: optionIndex === field.options.length - 1,
|
|
2720
|
+
disabled: controls.options === "readOnly" || optionIndex === field.options.length - 1,
|
|
2553
2721
|
onClick: () => moveOption(field.id, option.id, optionIndex + 1)
|
|
2554
2722
|
}
|
|
2555
2723
|
),
|
|
@@ -2557,7 +2725,7 @@ function FormBuilder({
|
|
|
2557
2725
|
IconButton,
|
|
2558
2726
|
{
|
|
2559
2727
|
actionType: "delete",
|
|
2560
|
-
disabled: field.options.length === 1,
|
|
2728
|
+
disabled: controls.options === "readOnly" || field.options.length === 1,
|
|
2561
2729
|
onClick: () => removeOption(field.id, option.id),
|
|
2562
2730
|
title: translate("builder.remove")
|
|
2563
2731
|
}
|
|
@@ -2575,7 +2743,7 @@ function FormBuilder({
|
|
|
2575
2743
|
onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
|
|
2576
2744
|
onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
|
|
2577
2745
|
onRemove: () => removeOption(field.id, option.id),
|
|
2578
|
-
readOnly,
|
|
2746
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
2579
2747
|
actions,
|
|
2580
2748
|
components
|
|
2581
2749
|
}
|
|
@@ -2589,7 +2757,7 @@ function FormBuilder({
|
|
|
2589
2757
|
index: optionIndex,
|
|
2590
2758
|
currentLocale: editingLocale,
|
|
2591
2759
|
translate,
|
|
2592
|
-
readOnly,
|
|
2760
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
2593
2761
|
actions,
|
|
2594
2762
|
components
|
|
2595
2763
|
},
|
|
@@ -2601,13 +2769,13 @@ function FormBuilder({
|
|
|
2601
2769
|
{
|
|
2602
2770
|
action: "addOption",
|
|
2603
2771
|
targetId: field.id,
|
|
2604
|
-
disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
2772
|
+
disabled: controls.options === "readOnly" || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
2605
2773
|
onClick: () => addOption(field.id),
|
|
2606
2774
|
children: translate("builder.addOption")
|
|
2607
2775
|
}
|
|
2608
2776
|
)
|
|
2609
2777
|
] }) : null,
|
|
2610
|
-
conditionsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__condition"), children: [
|
|
2778
|
+
conditionsEnabled && controls.displayConditions !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: builderClass("form-engine-builder__condition"), children: [
|
|
2611
2779
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2612
2780
|
Select,
|
|
2613
2781
|
{
|
|
@@ -2852,7 +3020,7 @@ function FormProvider({
|
|
|
2852
3020
|
[initialValues, locale, onSubmit, resetOnSuccess, validSchema, values]
|
|
2853
3021
|
);
|
|
2854
3022
|
const translate = (0, import_react3.useCallback)(
|
|
2855
|
-
(key, params) => translator.translate(key, locale, params),
|
|
3023
|
+
(key, params) => translator.translate(key, locale, params) ?? key,
|
|
2856
3024
|
[locale, translator]
|
|
2857
3025
|
);
|
|
2858
3026
|
const contextValue = (0, import_react3.useMemo)(
|
|
@@ -3963,7 +4131,11 @@ function FormRenderer(props) {
|
|
|
3963
4131
|
FormSubmissionError,
|
|
3964
4132
|
createLocalStorageSubmissionAttemptStore,
|
|
3965
4133
|
createLocalStorageSubmissionReceiptStore,
|
|
4134
|
+
isTranslationUnresolved,
|
|
4135
|
+
resolveFieldEditorControls,
|
|
4136
|
+
resolveFieldTypeSelectOptions,
|
|
3966
4137
|
resolveInitialFieldType,
|
|
4138
|
+
resolveTranslation,
|
|
3967
4139
|
submissionReceiptQueryKey,
|
|
3968
4140
|
useField,
|
|
3969
4141
|
useForm,
|
package/dist/index.d.cts
CHANGED
|
@@ -187,19 +187,45 @@ interface BuilderSelectOption<T extends string = string> {
|
|
|
187
187
|
readonly icon?: ReactNode;
|
|
188
188
|
readonly description?: string;
|
|
189
189
|
readonly disabled?: boolean;
|
|
190
|
+
readonly group?: string;
|
|
191
|
+
readonly groupLabel?: string;
|
|
190
192
|
readonly kind?: string;
|
|
191
193
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
192
194
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
readonly
|
|
196
|
-
readonly
|
|
195
|
+
type FieldPropertyControlMode = "editable" | "readOnly" | "hidden";
|
|
196
|
+
interface FieldEditorControlsConfig {
|
|
197
|
+
readonly title?: FieldPropertyControlMode;
|
|
198
|
+
readonly description?: FieldPropertyControlMode;
|
|
199
|
+
readonly required?: FieldPropertyControlMode;
|
|
200
|
+
readonly typeSelect?: FieldPropertyControlMode;
|
|
201
|
+
readonly options?: FieldPropertyControlMode;
|
|
202
|
+
readonly displayConditions?: FieldPropertyControlMode;
|
|
203
|
+
readonly textLimits?: FieldPropertyControlMode;
|
|
204
|
+
readonly ratingBounds?: FieldPropertyControlMode;
|
|
205
|
+
readonly numberLimits?: FieldPropertyControlMode;
|
|
206
|
+
}
|
|
207
|
+
interface FieldTypeSelectOptionsContext {
|
|
208
|
+
readonly currentType: QuestionType;
|
|
209
|
+
readonly allowedTypes: readonly QuestionType[];
|
|
197
210
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
type FieldTypeSelectOptionsTransformer = (options: readonly BuilderSelectOption<QuestionType>[], context: FieldTypeSelectOptionsContext) => readonly BuilderSelectOption<QuestionType>[];
|
|
212
|
+
type FieldTypeSelectOptionsSorter = (left: BuilderSelectOption<QuestionType>, right: BuilderSelectOption<QuestionType>, context: FieldTypeSelectOptionsContext) => number;
|
|
213
|
+
interface FieldTypeSelectOptionsConfig {
|
|
214
|
+
/** Transform the generated choices. The returned array is used as-is. */
|
|
215
|
+
readonly transform?: FieldTypeSelectOptionsTransformer;
|
|
216
|
+
/** Sort generated choices after transform. The source array is never mutated. */
|
|
217
|
+
readonly sort?: FieldTypeSelectOptionsSorter;
|
|
218
|
+
/** Optional explicit order applied before `sort`. */
|
|
219
|
+
readonly order?: readonly QuestionType[];
|
|
220
|
+
}
|
|
221
|
+
interface SelectComponentProps<T extends string = string> extends Omit<InputComponentProps, "value" | "onChange"> {
|
|
222
|
+
readonly value: T;
|
|
223
|
+
readonly onChange: (value: T) => void;
|
|
224
|
+
readonly options: readonly (T | BuilderSelectOption<T>)[];
|
|
225
|
+
readonly renderOption?: (option: BuilderSelectOption<T>) => ReactNode;
|
|
226
|
+
readonly renderValue?: (option: BuilderSelectOption<T> | undefined) => ReactNode;
|
|
202
227
|
}
|
|
228
|
+
type BuilderSelectProps<T extends string = string> = SelectComponentProps<T>;
|
|
203
229
|
interface BuilderCheckboxProps extends ComponentBaseProps {
|
|
204
230
|
readonly name?: string;
|
|
205
231
|
readonly required?: boolean;
|
|
@@ -278,14 +304,25 @@ interface BuilderFieldEditorSlotProps extends BuilderSlotBaseProps {
|
|
|
278
304
|
readonly localization?: boolean;
|
|
279
305
|
readonly conditions?: boolean;
|
|
280
306
|
};
|
|
307
|
+
readonly fieldEditorControls?: FieldEditorControlsConfig;
|
|
308
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
281
309
|
readonly slots?: Pick<FormBuilderSlots, "fieldTypeSelect" | "fieldEditorHeader">;
|
|
282
310
|
}
|
|
283
311
|
interface FieldTypeSelectSlotProps {
|
|
312
|
+
readonly id?: string;
|
|
313
|
+
readonly name?: string;
|
|
314
|
+
readonly label?: string;
|
|
284
315
|
readonly currentType: QuestionType;
|
|
285
316
|
readonly allowedTypes: readonly QuestionType[];
|
|
317
|
+
readonly options: readonly BuilderSelectOption<QuestionType>[];
|
|
286
318
|
readonly onChangeType: (nextType: QuestionType) => void;
|
|
287
319
|
readonly disabled?: boolean;
|
|
288
320
|
readonly readOnly?: boolean;
|
|
321
|
+
readonly required?: boolean;
|
|
322
|
+
readonly error?: boolean;
|
|
323
|
+
readonly helperText?: string;
|
|
324
|
+
readonly "aria-describedby"?: string;
|
|
325
|
+
readonly "aria-labelledby"?: string;
|
|
289
326
|
readonly renderIcon?: (type: QuestionType) => ReactNode;
|
|
290
327
|
}
|
|
291
328
|
interface FieldEditorHeaderSlotProps {
|
|
@@ -515,6 +552,8 @@ interface SubmissionProtectionProps {
|
|
|
515
552
|
}
|
|
516
553
|
type BeforeSubmit = (values: Readonly<Record<string, unknown>>) => "continue" | "cancel" | Promise<"continue" | "cancel">;
|
|
517
554
|
|
|
555
|
+
declare function resolveFieldEditorControls(config?: FieldEditorControlsConfig): Required<FieldEditorControlsConfig>;
|
|
556
|
+
declare function resolveFieldTypeSelectOptions(options: readonly BuilderSelectOption<QuestionType>[], config: FieldTypeSelectOptionsConfig | undefined, context: FieldTypeSelectOptionsContext): readonly BuilderSelectOption<QuestionType>[];
|
|
518
557
|
declare function resolveInitialFieldType(defaultType?: QuestionType, allowedTypes?: readonly QuestionType[]): QuestionType | null;
|
|
519
558
|
interface FormBuilderFeatures {
|
|
520
559
|
readonly pages?: boolean;
|
|
@@ -538,13 +577,15 @@ interface FormBuilderProps {
|
|
|
538
577
|
readonly createManualTranslationMetadata?: (context: ManualTranslationContext) => Readonly<Record<string, JsonValue>> | undefined;
|
|
539
578
|
readonly readOnly?: boolean;
|
|
540
579
|
readonly features?: FormBuilderFeatures;
|
|
580
|
+
readonly fieldEditorControls?: FieldEditorControlsConfig;
|
|
581
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
541
582
|
readonly components?: FormBuilderComponents;
|
|
542
583
|
readonly slots?: FormBuilderSlots;
|
|
543
584
|
readonly sectionOrder?: readonly FormBuilderSectionName[];
|
|
544
585
|
readonly disableDefaultStyles?: boolean;
|
|
545
586
|
readonly unstyled?: boolean;
|
|
546
587
|
}
|
|
547
|
-
declare function FormBuilder({ schema, onChange, locale, translator, translationAdapter, translationOptions, onTranslationReport, policy, idFactory, factories, className, defaultFieldType, onActionError, createManualTranslationMetadata, readOnly, features, components: componentOverrides, slots, sectionOrder, disableDefaultStyles, unstyled }: FormBuilderProps): react.JSX.Element;
|
|
588
|
+
declare function FormBuilder({ schema, onChange, locale, translator, translationAdapter, translationOptions, onTranslationReport, policy, idFactory, factories, className, defaultFieldType, onActionError, createManualTranslationMetadata, readOnly, features, fieldEditorControls, fieldTypeOptions, components: componentOverrides, slots, sectionOrder, disableDefaultStyles, unstyled }: FormBuilderProps): react.JSX.Element;
|
|
548
589
|
|
|
549
590
|
type SubmitStatus = "idle" | "submitting" | "success" | "error";
|
|
550
591
|
interface FormContextValue {
|
|
@@ -601,6 +642,8 @@ declare const BUILDER_TRANSLATION_KEYS: {
|
|
|
601
642
|
type BuilderTranslationKey = (typeof BUILDER_TRANSLATION_KEYS)[keyof typeof BUILDER_TRANSLATION_KEYS];
|
|
602
643
|
/** Legacy keys are checked when an older catalog does not contain a canonical key. */
|
|
603
644
|
declare const BUILDER_TRANSLATION_ALIASES: Readonly<Record<string, string>>;
|
|
645
|
+
declare function isTranslationUnresolved(result: unknown, key: string, aliases?: readonly string[]): boolean;
|
|
646
|
+
declare function resolveTranslation(key: string, aliases: readonly string[], adapter?: TranslationAdapter, defaultCatalog?: Readonly<Record<string, string>>, params?: Readonly<Record<string, unknown>>, locale?: string): string;
|
|
604
647
|
|
|
605
648
|
interface FieldComponentProps {
|
|
606
649
|
readonly field: FormField;
|
|
@@ -648,4 +691,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
|
|
|
648
691
|
type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
|
|
649
692
|
declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
|
|
650
693
|
|
|
651
|
-
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldEditorHeaderSlotProps, type FieldState, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormCompletionSlotProps, type FormContextValue, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type UseSubmissionReceiptsResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, resolveInitialFieldType, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useSubmissionReceipts };
|
|
694
|
+
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormCompletionSlotProps, type FormContextValue, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type UseSubmissionReceiptsResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useSubmissionReceipts };
|
package/dist/index.d.ts
CHANGED
|
@@ -187,19 +187,45 @@ interface BuilderSelectOption<T extends string = string> {
|
|
|
187
187
|
readonly icon?: ReactNode;
|
|
188
188
|
readonly description?: string;
|
|
189
189
|
readonly disabled?: boolean;
|
|
190
|
+
readonly group?: string;
|
|
191
|
+
readonly groupLabel?: string;
|
|
190
192
|
readonly kind?: string;
|
|
191
193
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
192
194
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
readonly
|
|
196
|
-
readonly
|
|
195
|
+
type FieldPropertyControlMode = "editable" | "readOnly" | "hidden";
|
|
196
|
+
interface FieldEditorControlsConfig {
|
|
197
|
+
readonly title?: FieldPropertyControlMode;
|
|
198
|
+
readonly description?: FieldPropertyControlMode;
|
|
199
|
+
readonly required?: FieldPropertyControlMode;
|
|
200
|
+
readonly typeSelect?: FieldPropertyControlMode;
|
|
201
|
+
readonly options?: FieldPropertyControlMode;
|
|
202
|
+
readonly displayConditions?: FieldPropertyControlMode;
|
|
203
|
+
readonly textLimits?: FieldPropertyControlMode;
|
|
204
|
+
readonly ratingBounds?: FieldPropertyControlMode;
|
|
205
|
+
readonly numberLimits?: FieldPropertyControlMode;
|
|
206
|
+
}
|
|
207
|
+
interface FieldTypeSelectOptionsContext {
|
|
208
|
+
readonly currentType: QuestionType;
|
|
209
|
+
readonly allowedTypes: readonly QuestionType[];
|
|
197
210
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
type FieldTypeSelectOptionsTransformer = (options: readonly BuilderSelectOption<QuestionType>[], context: FieldTypeSelectOptionsContext) => readonly BuilderSelectOption<QuestionType>[];
|
|
212
|
+
type FieldTypeSelectOptionsSorter = (left: BuilderSelectOption<QuestionType>, right: BuilderSelectOption<QuestionType>, context: FieldTypeSelectOptionsContext) => number;
|
|
213
|
+
interface FieldTypeSelectOptionsConfig {
|
|
214
|
+
/** Transform the generated choices. The returned array is used as-is. */
|
|
215
|
+
readonly transform?: FieldTypeSelectOptionsTransformer;
|
|
216
|
+
/** Sort generated choices after transform. The source array is never mutated. */
|
|
217
|
+
readonly sort?: FieldTypeSelectOptionsSorter;
|
|
218
|
+
/** Optional explicit order applied before `sort`. */
|
|
219
|
+
readonly order?: readonly QuestionType[];
|
|
220
|
+
}
|
|
221
|
+
interface SelectComponentProps<T extends string = string> extends Omit<InputComponentProps, "value" | "onChange"> {
|
|
222
|
+
readonly value: T;
|
|
223
|
+
readonly onChange: (value: T) => void;
|
|
224
|
+
readonly options: readonly (T | BuilderSelectOption<T>)[];
|
|
225
|
+
readonly renderOption?: (option: BuilderSelectOption<T>) => ReactNode;
|
|
226
|
+
readonly renderValue?: (option: BuilderSelectOption<T> | undefined) => ReactNode;
|
|
202
227
|
}
|
|
228
|
+
type BuilderSelectProps<T extends string = string> = SelectComponentProps<T>;
|
|
203
229
|
interface BuilderCheckboxProps extends ComponentBaseProps {
|
|
204
230
|
readonly name?: string;
|
|
205
231
|
readonly required?: boolean;
|
|
@@ -278,14 +304,25 @@ interface BuilderFieldEditorSlotProps extends BuilderSlotBaseProps {
|
|
|
278
304
|
readonly localization?: boolean;
|
|
279
305
|
readonly conditions?: boolean;
|
|
280
306
|
};
|
|
307
|
+
readonly fieldEditorControls?: FieldEditorControlsConfig;
|
|
308
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
281
309
|
readonly slots?: Pick<FormBuilderSlots, "fieldTypeSelect" | "fieldEditorHeader">;
|
|
282
310
|
}
|
|
283
311
|
interface FieldTypeSelectSlotProps {
|
|
312
|
+
readonly id?: string;
|
|
313
|
+
readonly name?: string;
|
|
314
|
+
readonly label?: string;
|
|
284
315
|
readonly currentType: QuestionType;
|
|
285
316
|
readonly allowedTypes: readonly QuestionType[];
|
|
317
|
+
readonly options: readonly BuilderSelectOption<QuestionType>[];
|
|
286
318
|
readonly onChangeType: (nextType: QuestionType) => void;
|
|
287
319
|
readonly disabled?: boolean;
|
|
288
320
|
readonly readOnly?: boolean;
|
|
321
|
+
readonly required?: boolean;
|
|
322
|
+
readonly error?: boolean;
|
|
323
|
+
readonly helperText?: string;
|
|
324
|
+
readonly "aria-describedby"?: string;
|
|
325
|
+
readonly "aria-labelledby"?: string;
|
|
289
326
|
readonly renderIcon?: (type: QuestionType) => ReactNode;
|
|
290
327
|
}
|
|
291
328
|
interface FieldEditorHeaderSlotProps {
|
|
@@ -515,6 +552,8 @@ interface SubmissionProtectionProps {
|
|
|
515
552
|
}
|
|
516
553
|
type BeforeSubmit = (values: Readonly<Record<string, unknown>>) => "continue" | "cancel" | Promise<"continue" | "cancel">;
|
|
517
554
|
|
|
555
|
+
declare function resolveFieldEditorControls(config?: FieldEditorControlsConfig): Required<FieldEditorControlsConfig>;
|
|
556
|
+
declare function resolveFieldTypeSelectOptions(options: readonly BuilderSelectOption<QuestionType>[], config: FieldTypeSelectOptionsConfig | undefined, context: FieldTypeSelectOptionsContext): readonly BuilderSelectOption<QuestionType>[];
|
|
518
557
|
declare function resolveInitialFieldType(defaultType?: QuestionType, allowedTypes?: readonly QuestionType[]): QuestionType | null;
|
|
519
558
|
interface FormBuilderFeatures {
|
|
520
559
|
readonly pages?: boolean;
|
|
@@ -538,13 +577,15 @@ interface FormBuilderProps {
|
|
|
538
577
|
readonly createManualTranslationMetadata?: (context: ManualTranslationContext) => Readonly<Record<string, JsonValue>> | undefined;
|
|
539
578
|
readonly readOnly?: boolean;
|
|
540
579
|
readonly features?: FormBuilderFeatures;
|
|
580
|
+
readonly fieldEditorControls?: FieldEditorControlsConfig;
|
|
581
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
541
582
|
readonly components?: FormBuilderComponents;
|
|
542
583
|
readonly slots?: FormBuilderSlots;
|
|
543
584
|
readonly sectionOrder?: readonly FormBuilderSectionName[];
|
|
544
585
|
readonly disableDefaultStyles?: boolean;
|
|
545
586
|
readonly unstyled?: boolean;
|
|
546
587
|
}
|
|
547
|
-
declare function FormBuilder({ schema, onChange, locale, translator, translationAdapter, translationOptions, onTranslationReport, policy, idFactory, factories, className, defaultFieldType, onActionError, createManualTranslationMetadata, readOnly, features, components: componentOverrides, slots, sectionOrder, disableDefaultStyles, unstyled }: FormBuilderProps): react.JSX.Element;
|
|
588
|
+
declare function FormBuilder({ schema, onChange, locale, translator, translationAdapter, translationOptions, onTranslationReport, policy, idFactory, factories, className, defaultFieldType, onActionError, createManualTranslationMetadata, readOnly, features, fieldEditorControls, fieldTypeOptions, components: componentOverrides, slots, sectionOrder, disableDefaultStyles, unstyled }: FormBuilderProps): react.JSX.Element;
|
|
548
589
|
|
|
549
590
|
type SubmitStatus = "idle" | "submitting" | "success" | "error";
|
|
550
591
|
interface FormContextValue {
|
|
@@ -601,6 +642,8 @@ declare const BUILDER_TRANSLATION_KEYS: {
|
|
|
601
642
|
type BuilderTranslationKey = (typeof BUILDER_TRANSLATION_KEYS)[keyof typeof BUILDER_TRANSLATION_KEYS];
|
|
602
643
|
/** Legacy keys are checked when an older catalog does not contain a canonical key. */
|
|
603
644
|
declare const BUILDER_TRANSLATION_ALIASES: Readonly<Record<string, string>>;
|
|
645
|
+
declare function isTranslationUnresolved(result: unknown, key: string, aliases?: readonly string[]): boolean;
|
|
646
|
+
declare function resolveTranslation(key: string, aliases: readonly string[], adapter?: TranslationAdapter, defaultCatalog?: Readonly<Record<string, string>>, params?: Readonly<Record<string, unknown>>, locale?: string): string;
|
|
604
647
|
|
|
605
648
|
interface FieldComponentProps {
|
|
606
649
|
readonly field: FormField;
|
|
@@ -648,4 +691,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
|
|
|
648
691
|
type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
|
|
649
692
|
declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
|
|
650
693
|
|
|
651
|
-
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldEditorHeaderSlotProps, type FieldState, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormCompletionSlotProps, type FormContextValue, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type UseSubmissionReceiptsResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, resolveInitialFieldType, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useSubmissionReceipts };
|
|
694
|
+
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ComponentBaseProps, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormCompletionSlotProps, type FormContextValue, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type UseSubmissionReceiptsResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useSubmissionReceipts };
|
package/dist/index.js
CHANGED
|
@@ -770,6 +770,41 @@ var BUILDER_TRANSLATION_ALIASES = {
|
|
|
770
770
|
"builder.fields.typeSelect": "builder.fieldType.select",
|
|
771
771
|
"builder.fields.typeMultiSelect": "builder.fieldType.multi-select"
|
|
772
772
|
};
|
|
773
|
+
function isTranslationUnresolved(result, key, aliases = []) {
|
|
774
|
+
if (result === void 0 || result === null || result === "") return true;
|
|
775
|
+
if (typeof result !== "string") return false;
|
|
776
|
+
if (result === key || aliases.includes(result)) return true;
|
|
777
|
+
return result.endsWith(key) || aliases.some((alias) => result.endsWith(alias));
|
|
778
|
+
}
|
|
779
|
+
function isResolvedAdapterResult(result, key, aliases) {
|
|
780
|
+
return typeof result === "string" && result.startsWith("translated:") ? true : !isTranslationUnresolved(result, key, aliases);
|
|
781
|
+
}
|
|
782
|
+
function formatTemplate(template, params) {
|
|
783
|
+
return template.replace(
|
|
784
|
+
/\{\{(\w+)\}\}/g,
|
|
785
|
+
(token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
function resolveTranslation(key, aliases, adapter, defaultCatalog, params = {}, locale = "") {
|
|
789
|
+
const adapterParams = {};
|
|
790
|
+
for (const [name, value] of Object.entries(params)) {
|
|
791
|
+
if (typeof value === "string" || typeof value === "number") adapterParams[name] = value;
|
|
792
|
+
}
|
|
793
|
+
const translate = (candidate) => adapter?.translate(candidate, locale, adapterParams);
|
|
794
|
+
const translated = translate(key);
|
|
795
|
+
if (isResolvedAdapterResult(translated, key, aliases)) return translated;
|
|
796
|
+
for (const alias of aliases) {
|
|
797
|
+
const aliased = translate(alias);
|
|
798
|
+
if (isResolvedAdapterResult(aliased, alias, aliases)) return aliased;
|
|
799
|
+
}
|
|
800
|
+
const catalogValue = defaultCatalog?.[key];
|
|
801
|
+
if (catalogValue !== void 0) return formatTemplate(catalogValue, params);
|
|
802
|
+
for (const alias of aliases) {
|
|
803
|
+
const aliasValue = defaultCatalog?.[alias];
|
|
804
|
+
if (aliasValue !== void 0) return formatTemplate(aliasValue, params);
|
|
805
|
+
}
|
|
806
|
+
return key;
|
|
807
|
+
}
|
|
773
808
|
|
|
774
809
|
// src/builder.tsx
|
|
775
810
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1222,6 +1257,34 @@ var FIELD_TYPES = [
|
|
|
1222
1257
|
"checkbox",
|
|
1223
1258
|
"radio"
|
|
1224
1259
|
];
|
|
1260
|
+
var DEFAULT_FIELD_EDITOR_CONTROL_MODE = "editable";
|
|
1261
|
+
function resolveFieldEditorControls(config = {}) {
|
|
1262
|
+
return {
|
|
1263
|
+
title: config.title ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1264
|
+
description: config.description ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1265
|
+
required: config.required ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1266
|
+
typeSelect: config.typeSelect ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1267
|
+
options: config.options ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1268
|
+
displayConditions: config.displayConditions ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1269
|
+
textLimits: config.textLimits ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1270
|
+
ratingBounds: config.ratingBounds ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE,
|
|
1271
|
+
numberLimits: config.numberLimits ?? DEFAULT_FIELD_EDITOR_CONTROL_MODE
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
function resolveFieldTypeSelectOptions(options, config, context) {
|
|
1275
|
+
let resolved = [...options];
|
|
1276
|
+
if (config?.transform !== void 0) resolved = [...config.transform(resolved, context)];
|
|
1277
|
+
if (config?.order !== void 0) {
|
|
1278
|
+
const ranks = new Map(config.order.map((type, index) => [type, index]));
|
|
1279
|
+
resolved.sort((left, right) => {
|
|
1280
|
+
const leftRank = ranks.get(left.value) ?? config.order?.length ?? 0;
|
|
1281
|
+
const rightRank = ranks.get(right.value) ?? config.order?.length ?? 0;
|
|
1282
|
+
return leftRank - rightRank;
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
if (config?.sort !== void 0) resolved.sort((left, right) => config.sort?.(left, right, context) ?? 0);
|
|
1286
|
+
return resolved;
|
|
1287
|
+
}
|
|
1225
1288
|
var BUILDER_DEFAULTS = {
|
|
1226
1289
|
"builder.formBuilder": "Form builder",
|
|
1227
1290
|
"builder.basicSettings": "Basic settings",
|
|
@@ -1240,6 +1303,10 @@ var BUILDER_DEFAULTS = {
|
|
|
1240
1303
|
"builder.required": "Required",
|
|
1241
1304
|
"builder.minimum": "Minimum",
|
|
1242
1305
|
"builder.maximum": "Maximum",
|
|
1306
|
+
"builder.minimumLength": "Minimum length",
|
|
1307
|
+
"builder.maximumLength": "Maximum length",
|
|
1308
|
+
"builder.pattern": "Pattern",
|
|
1309
|
+
"builder.step": "Step",
|
|
1243
1310
|
"builder.options": "Options",
|
|
1244
1311
|
"builder.optionLabel": "\u9078\u629E\u80A2 / Option Label {{index}}",
|
|
1245
1312
|
"builder.optionLabelPlaceholder": "Example: Very satisfied",
|
|
@@ -1302,6 +1369,18 @@ var BUILDER_DEFAULTS = {
|
|
|
1302
1369
|
"builder.fields.typeMultiSelect": "Multi-select",
|
|
1303
1370
|
"builder.fields.typeCheckbox": "Checkbox",
|
|
1304
1371
|
"builder.fields.typeRadio": "Radio",
|
|
1372
|
+
"builder.fieldCategory.text": "Text",
|
|
1373
|
+
"builder.fieldCategory.choice": "Choice",
|
|
1374
|
+
"builder.fieldCategory.number": "Number",
|
|
1375
|
+
"builder.fieldCategory.advanced": "Advanced",
|
|
1376
|
+
"builder.fieldTypeDescription.text": "A single-line text answer",
|
|
1377
|
+
"builder.fieldTypeDescription.textarea": "A long-form text answer",
|
|
1378
|
+
"builder.fieldTypeDescription.number": "A numeric answer",
|
|
1379
|
+
"builder.fieldTypeDescription.rating": "A rating scale answer",
|
|
1380
|
+
"builder.fieldTypeDescription.radio": "A single-choice answer",
|
|
1381
|
+
"builder.fieldTypeDescription.checkbox": "A yes/no answer",
|
|
1382
|
+
"builder.fieldTypeDescription.select": "A dropdown choice",
|
|
1383
|
+
"builder.fieldTypeDescription.multi-select": "Multiple choices",
|
|
1305
1384
|
"builder.actions.addField": "Add question",
|
|
1306
1385
|
"builder.fieldType.text": "Text",
|
|
1307
1386
|
"builder.fieldType.textarea": "Textarea",
|
|
@@ -1316,12 +1395,6 @@ var BUILDER_DEFAULTS = {
|
|
|
1316
1395
|
"builder.operator.contains": "contains",
|
|
1317
1396
|
"builder.operator.not_empty": "is not empty"
|
|
1318
1397
|
};
|
|
1319
|
-
function interpolate(template, params) {
|
|
1320
|
-
return template.replace(
|
|
1321
|
-
/\{\{(\w+)\}\}/g,
|
|
1322
|
-
(token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
|
|
1323
|
-
);
|
|
1324
|
-
}
|
|
1325
1398
|
function BuilderSectionGroup({ children }) {
|
|
1326
1399
|
return children;
|
|
1327
1400
|
}
|
|
@@ -1491,6 +1564,8 @@ function FormBuilder({
|
|
|
1491
1564
|
createManualTranslationMetadata,
|
|
1492
1565
|
readOnly = false,
|
|
1493
1566
|
features,
|
|
1567
|
+
fieldEditorControls,
|
|
1568
|
+
fieldTypeOptions,
|
|
1494
1569
|
components: componentOverrides,
|
|
1495
1570
|
slots,
|
|
1496
1571
|
sectionOrder,
|
|
@@ -1526,20 +1601,14 @@ function FormBuilder({
|
|
|
1526
1601
|
const [isTranslating, setIsTranslating] = useState(false);
|
|
1527
1602
|
const [translationError, setTranslationError] = useState(null);
|
|
1528
1603
|
const [translationReport, setTranslationReport] = useState();
|
|
1529
|
-
const translate = (key, params = {}) =>
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
if (alias !== void 0) {
|
|
1538
|
-
const aliased = translator?.translate(alias, locale, translatorParams);
|
|
1539
|
-
if (aliased !== void 0 && aliased !== alias) return aliased;
|
|
1540
|
-
}
|
|
1541
|
-
return translated === void 0 ? interpolate(BUILDER_DEFAULTS[key] ?? key, params) : translated;
|
|
1542
|
-
};
|
|
1604
|
+
const translate = (key, params = {}) => resolveTranslation(
|
|
1605
|
+
key,
|
|
1606
|
+
BUILDER_TRANSLATION_ALIASES[key] === void 0 ? [] : [BUILDER_TRANSLATION_ALIASES[key]],
|
|
1607
|
+
translator,
|
|
1608
|
+
BUILDER_DEFAULTS,
|
|
1609
|
+
params,
|
|
1610
|
+
locale
|
|
1611
|
+
);
|
|
1543
1612
|
const pagesEnabled = features?.pages ?? true;
|
|
1544
1613
|
const localizationEnabled = features?.localization ?? true;
|
|
1545
1614
|
const conditionsEnabled = features?.conditions ?? true;
|
|
@@ -2261,6 +2330,7 @@ function FormBuilder({
|
|
|
2261
2330
|
}
|
|
2262
2331
|
) : null }),
|
|
2263
2332
|
/* @__PURE__ */ jsx(BuilderSectionGroup, { name: "questions", children: /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__list"), children: schema.fields.map((field, index) => {
|
|
2333
|
+
const controls = resolveFieldEditorControls(fieldEditorControls);
|
|
2264
2334
|
const condition = field.displayCondition;
|
|
2265
2335
|
const source = condition === void 0 ? void 0 : schema.fields.find((item) => item.id === condition.questionId);
|
|
2266
2336
|
const availableSources = schema.fields.slice(0, index);
|
|
@@ -2276,6 +2346,8 @@ function FormBuilder({
|
|
|
2276
2346
|
...slots === void 0 ? {} : { slots },
|
|
2277
2347
|
...policy === void 0 ? {} : { policy },
|
|
2278
2348
|
...features === void 0 ? {} : { features },
|
|
2349
|
+
...fieldEditorControls === void 0 ? {} : { fieldEditorControls },
|
|
2350
|
+
...fieldTypeOptions === void 0 ? {} : { fieldTypeOptions },
|
|
2279
2351
|
readOnly,
|
|
2280
2352
|
actions,
|
|
2281
2353
|
components
|
|
@@ -2337,7 +2409,7 @@ function FormBuilder({
|
|
|
2337
2409
|
}
|
|
2338
2410
|
) }),
|
|
2339
2411
|
/* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2340
|
-
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2412
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2341
2413
|
TextInput,
|
|
2342
2414
|
{
|
|
2343
2415
|
id: `builder-field-${field.id}-title`,
|
|
@@ -2349,34 +2421,56 @@ function FormBuilder({
|
|
|
2349
2421
|
"aria-describedby": field.title.trim().length === 0 ? `builder-field-${field.id}-title-error` : void 0,
|
|
2350
2422
|
value: field.title,
|
|
2351
2423
|
placeholder: translate("builder.questionTitlePlaceholder"),
|
|
2424
|
+
readOnly: controls.title === "readOnly",
|
|
2352
2425
|
onChange: (value) => updateField(field.id, (current) => ({
|
|
2353
2426
|
...current,
|
|
2354
2427
|
title: value.trim().length === 0 ? current.title : value
|
|
2355
2428
|
}))
|
|
2356
2429
|
}
|
|
2357
2430
|
) }),
|
|
2358
|
-
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2431
|
+
controls.typeSelect === "hidden" ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2359
2432
|
Select,
|
|
2360
2433
|
{
|
|
2361
2434
|
id: `builder-field-${field.id}-type`,
|
|
2362
2435
|
label: translate("builder.type"),
|
|
2363
2436
|
value: field.type,
|
|
2437
|
+
disabled: controls.typeSelect === "readOnly",
|
|
2364
2438
|
onChange: (value) => changeType(field.id, value),
|
|
2365
|
-
options:
|
|
2366
|
-
|
|
2367
|
-
|
|
2439
|
+
options: resolveFieldTypeSelectOptions(
|
|
2440
|
+
FIELD_TYPES.filter(
|
|
2441
|
+
(type) => policy?.allowedFieldTypes === void 0 || policy.allowedFieldTypes.includes(type)
|
|
2442
|
+
).map((type) => ({ value: type, label: translate(fieldTypeKey(type)) })),
|
|
2443
|
+
fieldTypeOptions,
|
|
2444
|
+
{ currentType: field.type, allowedTypes: policy?.allowedFieldTypes ?? FIELD_TYPES }
|
|
2445
|
+
)
|
|
2368
2446
|
}
|
|
2369
2447
|
) }),
|
|
2370
|
-
/* @__PURE__ */ jsx(
|
|
2448
|
+
controls.required === "hidden" ? null : /* @__PURE__ */ jsx(
|
|
2371
2449
|
Checkbox,
|
|
2372
2450
|
{
|
|
2373
2451
|
className: builderClass("form-engine-builder__check"),
|
|
2374
2452
|
checked: field.required === true,
|
|
2453
|
+
disabled: controls.required === "readOnly",
|
|
2375
2454
|
onChange: (checked) => updateField(field.id, (current) => ({ ...current, required: checked })),
|
|
2376
2455
|
label: translate("builder.required")
|
|
2377
2456
|
}
|
|
2378
2457
|
)
|
|
2379
2458
|
] }),
|
|
2459
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2460
|
+
TextArea,
|
|
2461
|
+
{
|
|
2462
|
+
id: `builder-field-${field.id}-description`,
|
|
2463
|
+
name: `fields.${field.id}.description`,
|
|
2464
|
+
label: translate("builder.description"),
|
|
2465
|
+
value: field.description ?? "",
|
|
2466
|
+
readOnly: controls.description === "readOnly",
|
|
2467
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2468
|
+
if (value.length > 0) return { ...current, description: value };
|
|
2469
|
+
const { description: _description, ...remaining } = current;
|
|
2470
|
+
return remaining;
|
|
2471
|
+
})
|
|
2472
|
+
}
|
|
2473
|
+
) }),
|
|
2380
2474
|
!pagesEnabled || schema.pages === void 0 ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2381
2475
|
Select,
|
|
2382
2476
|
{
|
|
@@ -2412,12 +2506,13 @@ function FormBuilder({
|
|
|
2412
2506
|
})
|
|
2413
2507
|
}
|
|
2414
2508
|
) }),
|
|
2415
|
-
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2509
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2416
2510
|
TextInput,
|
|
2417
2511
|
{
|
|
2418
2512
|
id: `builder-field-${field.id}-${editingLocale}-description`,
|
|
2419
2513
|
label: translate("builder.pageDescription"),
|
|
2420
2514
|
value: field.translations?.[editingLocale]?.description ?? "",
|
|
2515
|
+
readOnly: controls.description === "readOnly",
|
|
2421
2516
|
onChange: (value) => updateManualTranslation({
|
|
2422
2517
|
locale: editingLocale,
|
|
2423
2518
|
kind: "field",
|
|
@@ -2452,7 +2547,7 @@ function FormBuilder({
|
|
|
2452
2547
|
}
|
|
2453
2548
|
) }, option.id)) : null
|
|
2454
2549
|
] }),
|
|
2455
|
-
field.type === "rating" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2550
|
+
field.type === "rating" && controls.ratingBounds !== "hidden" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2456
2551
|
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2457
2552
|
TextInput,
|
|
2458
2553
|
{
|
|
@@ -2460,6 +2555,7 @@ function FormBuilder({
|
|
|
2460
2555
|
label: translate("builder.minimum"),
|
|
2461
2556
|
type: "number",
|
|
2462
2557
|
value: String(field.min ?? 1),
|
|
2558
|
+
readOnly: controls.ratingBounds === "readOnly",
|
|
2463
2559
|
onChange: (value) => {
|
|
2464
2560
|
const min = Number(value);
|
|
2465
2561
|
if (!Number.isInteger(min)) return;
|
|
@@ -2477,6 +2573,7 @@ function FormBuilder({
|
|
|
2477
2573
|
label: translate("builder.maximum"),
|
|
2478
2574
|
type: "number",
|
|
2479
2575
|
value: String(field.max ?? 5),
|
|
2576
|
+
readOnly: controls.ratingBounds === "readOnly",
|
|
2480
2577
|
onChange: (value) => {
|
|
2481
2578
|
const max = Number(value);
|
|
2482
2579
|
if (!Number.isInteger(max)) return;
|
|
@@ -2488,7 +2585,73 @@ function FormBuilder({
|
|
|
2488
2585
|
}
|
|
2489
2586
|
) })
|
|
2490
2587
|
] }) : null,
|
|
2491
|
-
"
|
|
2588
|
+
(field.type === "text" || field.type === "textarea") && controls.textLimits !== "hidden" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__grid"), children: [
|
|
2589
|
+
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2590
|
+
TextInput,
|
|
2591
|
+
{
|
|
2592
|
+
id: `builder-field-${field.id}-min-length`,
|
|
2593
|
+
label: translate("builder.minimumLength"),
|
|
2594
|
+
type: "number",
|
|
2595
|
+
value: field.minLength === void 0 ? "" : String(field.minLength),
|
|
2596
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2597
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2598
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2599
|
+
const parsed = value.trim().length === 0 ? void 0 : Number(value);
|
|
2600
|
+
return parsed === void 0 || !Number.isInteger(parsed) || parsed < 0 ? current : { ...current, minLength: parsed };
|
|
2601
|
+
})
|
|
2602
|
+
}
|
|
2603
|
+
) }),
|
|
2604
|
+
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2605
|
+
TextInput,
|
|
2606
|
+
{
|
|
2607
|
+
id: `builder-field-${field.id}-max-length`,
|
|
2608
|
+
label: translate("builder.maximumLength"),
|
|
2609
|
+
type: "number",
|
|
2610
|
+
value: field.maxLength === void 0 ? "" : String(field.maxLength),
|
|
2611
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2612
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2613
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2614
|
+
const parsed = value.trim().length === 0 ? void 0 : Number(value);
|
|
2615
|
+
return parsed === void 0 || !Number.isInteger(parsed) || parsed < 0 ? current : { ...current, maxLength: parsed };
|
|
2616
|
+
})
|
|
2617
|
+
}
|
|
2618
|
+
) }),
|
|
2619
|
+
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2620
|
+
TextInput,
|
|
2621
|
+
{
|
|
2622
|
+
id: `builder-field-${field.id}-pattern`,
|
|
2623
|
+
label: translate("builder.pattern"),
|
|
2624
|
+
value: field.pattern ?? "",
|
|
2625
|
+
readOnly: controls.textLimits === "readOnly",
|
|
2626
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2627
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
2628
|
+
return value.length === 0 ? current : { ...current, pattern: value };
|
|
2629
|
+
})
|
|
2630
|
+
}
|
|
2631
|
+
) })
|
|
2632
|
+
] }) : null,
|
|
2633
|
+
field.type === "number" && controls.numberLimits !== "hidden" ? /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__grid"), children: ["min", "max", "step"].map((property) => /* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2634
|
+
TextInput,
|
|
2635
|
+
{
|
|
2636
|
+
id: `builder-field-${field.id}-${property}`,
|
|
2637
|
+
label: translate(
|
|
2638
|
+
property === "step" ? "builder.step" : property === "min" ? "builder.minimum" : "builder.maximum"
|
|
2639
|
+
),
|
|
2640
|
+
type: "number",
|
|
2641
|
+
value: field[property] === void 0 ? "" : String(field[property]),
|
|
2642
|
+
readOnly: controls.numberLimits === "readOnly",
|
|
2643
|
+
onChange: (value) => updateField(field.id, (current) => {
|
|
2644
|
+
if (current.type !== "number") return current;
|
|
2645
|
+
if (value.trim().length === 0) {
|
|
2646
|
+
const { [property]: _removed, ...remaining } = current;
|
|
2647
|
+
return remaining;
|
|
2648
|
+
}
|
|
2649
|
+
const parsed = Number(value);
|
|
2650
|
+
return Number.isFinite(parsed) ? { ...current, [property]: parsed } : current;
|
|
2651
|
+
})
|
|
2652
|
+
}
|
|
2653
|
+
) }, property)) }) : null,
|
|
2654
|
+
"options" in field && controls.options !== "hidden" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__options"), children: [
|
|
2492
2655
|
/* @__PURE__ */ jsx("strong", { children: translate("builder.options") }),
|
|
2493
2656
|
field.options.map(
|
|
2494
2657
|
(option, optionIndex) => OptionEditorSlot === void 0 ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__option"), children: [
|
|
@@ -2499,6 +2662,7 @@ function FormBuilder({
|
|
|
2499
2662
|
label: translate("builder.optionLabel", { index: optionIndex + 1 }),
|
|
2500
2663
|
value: option.label,
|
|
2501
2664
|
placeholder: translate("builder.optionLabelPlaceholder"),
|
|
2665
|
+
readOnly: controls.options === "readOnly",
|
|
2502
2666
|
onChange: (value) => value.trim().length === 0 ? void 0 : updateOption(field.id, option.id, value)
|
|
2503
2667
|
}
|
|
2504
2668
|
),
|
|
@@ -2508,7 +2672,7 @@ function FormBuilder({
|
|
|
2508
2672
|
{
|
|
2509
2673
|
actionType: "moveUp",
|
|
2510
2674
|
title: translate("builder.moveUp", { title: option.label }),
|
|
2511
|
-
disabled: optionIndex === 0,
|
|
2675
|
+
disabled: controls.options === "readOnly" || optionIndex === 0,
|
|
2512
2676
|
onClick: () => moveOption(field.id, option.id, optionIndex - 1)
|
|
2513
2677
|
}
|
|
2514
2678
|
),
|
|
@@ -2517,7 +2681,7 @@ function FormBuilder({
|
|
|
2517
2681
|
{
|
|
2518
2682
|
actionType: "moveDown",
|
|
2519
2683
|
title: translate("builder.moveDown", { title: option.label }),
|
|
2520
|
-
disabled: optionIndex === field.options.length - 1,
|
|
2684
|
+
disabled: controls.options === "readOnly" || optionIndex === field.options.length - 1,
|
|
2521
2685
|
onClick: () => moveOption(field.id, option.id, optionIndex + 1)
|
|
2522
2686
|
}
|
|
2523
2687
|
),
|
|
@@ -2525,7 +2689,7 @@ function FormBuilder({
|
|
|
2525
2689
|
IconButton,
|
|
2526
2690
|
{
|
|
2527
2691
|
actionType: "delete",
|
|
2528
|
-
disabled: field.options.length === 1,
|
|
2692
|
+
disabled: controls.options === "readOnly" || field.options.length === 1,
|
|
2529
2693
|
onClick: () => removeOption(field.id, option.id),
|
|
2530
2694
|
title: translate("builder.remove")
|
|
2531
2695
|
}
|
|
@@ -2543,7 +2707,7 @@ function FormBuilder({
|
|
|
2543
2707
|
onMoveUp: () => moveOption(field.id, option.id, optionIndex - 1),
|
|
2544
2708
|
onMoveDown: () => moveOption(field.id, option.id, optionIndex + 1),
|
|
2545
2709
|
onRemove: () => removeOption(field.id, option.id),
|
|
2546
|
-
readOnly,
|
|
2710
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
2547
2711
|
actions,
|
|
2548
2712
|
components
|
|
2549
2713
|
}
|
|
@@ -2557,7 +2721,7 @@ function FormBuilder({
|
|
|
2557
2721
|
index: optionIndex,
|
|
2558
2722
|
currentLocale: editingLocale,
|
|
2559
2723
|
translate,
|
|
2560
|
-
readOnly,
|
|
2724
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
2561
2725
|
actions,
|
|
2562
2726
|
components
|
|
2563
2727
|
},
|
|
@@ -2569,13 +2733,13 @@ function FormBuilder({
|
|
|
2569
2733
|
{
|
|
2570
2734
|
action: "addOption",
|
|
2571
2735
|
targetId: field.id,
|
|
2572
|
-
disabled: policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
2736
|
+
disabled: controls.options === "readOnly" || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
2573
2737
|
onClick: () => addOption(field.id),
|
|
2574
2738
|
children: translate("builder.addOption")
|
|
2575
2739
|
}
|
|
2576
2740
|
)
|
|
2577
2741
|
] }) : null,
|
|
2578
|
-
conditionsEnabled ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
|
|
2742
|
+
conditionsEnabled && controls.displayConditions !== "hidden" ? /* @__PURE__ */ jsxs("div", { className: builderClass("form-engine-builder__condition"), children: [
|
|
2579
2743
|
/* @__PURE__ */ jsx("div", { className: builderClass("form-engine-builder__field"), children: /* @__PURE__ */ jsx(
|
|
2580
2744
|
Select,
|
|
2581
2745
|
{
|
|
@@ -2828,7 +2992,7 @@ function FormProvider({
|
|
|
2828
2992
|
[initialValues, locale, onSubmit, resetOnSuccess, validSchema, values]
|
|
2829
2993
|
);
|
|
2830
2994
|
const translate = useCallback2(
|
|
2831
|
-
(key, params) => translator.translate(key, locale, params),
|
|
2995
|
+
(key, params) => translator.translate(key, locale, params) ?? key,
|
|
2832
2996
|
[locale, translator]
|
|
2833
2997
|
);
|
|
2834
2998
|
const contextValue = useMemo2(
|
|
@@ -3949,7 +4113,11 @@ export {
|
|
|
3949
4113
|
FormSubmissionError,
|
|
3950
4114
|
createLocalStorageSubmissionAttemptStore,
|
|
3951
4115
|
createLocalStorageSubmissionReceiptStore,
|
|
4116
|
+
isTranslationUnresolved,
|
|
4117
|
+
resolveFieldEditorControls,
|
|
4118
|
+
resolveFieldTypeSelectOptions,
|
|
3952
4119
|
resolveInitialFieldType,
|
|
4120
|
+
resolveTranslation,
|
|
3953
4121
|
submissionReceiptQueryKey,
|
|
3954
4122
|
useField,
|
|
3955
4123
|
useForm,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"typescript"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@form-engine-ts/core": "
|
|
46
|
-
"@form-engine-ts/privacy": "
|
|
45
|
+
"@form-engine-ts/core": "4.1.0",
|
|
46
|
+
"@form-engine-ts/privacy": "4.1.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"react": ">=18.2 <20",
|