@form-engine-ts/mui 4.0.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 +10 -3
- package/dist/index.cjs +137 -42
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +126 -31
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -17,7 +17,10 @@ import { MuiFormBuilder } from "@form-engine-ts/mui";
|
|
|
17
17
|
dense: true,
|
|
18
18
|
inputFullWidth: true,
|
|
19
19
|
buttonFullWidth: false,
|
|
20
|
-
fieldEditorOptions: {
|
|
20
|
+
fieldEditorOptions: {
|
|
21
|
+
description: "hidden",
|
|
22
|
+
byType: { rating: { ratingBounds: "readOnly" } }
|
|
23
|
+
},
|
|
21
24
|
getLocaleLabel: (locale) => localeNames[locale] ?? locale,
|
|
22
25
|
buttonVariants: { primary: "contained", secondary: "outlined", danger: "outlined" }
|
|
23
26
|
}}
|
|
@@ -64,8 +67,10 @@ slots as it does for the standard builder.
|
|
|
64
67
|
|
|
65
68
|
`MuiAdapterOptions` defaults to `size: "medium"`, `variant: "outlined"`, `buttonVariant: "contained"`,
|
|
66
69
|
`inputFullWidth: true`, and `buttonFullWidth: false`. The legacy `fullWidth` option remains the fallback for both new
|
|
67
|
-
width options. `fieldEditorOptions
|
|
68
|
-
|
|
70
|
+
width options. `fieldEditorOptions` controls title, description, required, type selection, options, display conditions,
|
|
71
|
+
text limits, rating bounds, and number limits. Each control can be `editable`, `readOnly`, or `hidden`, and `byType`
|
|
72
|
+
can override controls for individual question types. `localizationOptions.defaultLocaleControl` independently controls
|
|
73
|
+
the default locale input. Set `dense` to reduce section, editor, option, and toolbar spacing.
|
|
69
74
|
`buttonVariants` can override the MUI variant for `primary`, `secondary`, and `danger` actions independently.
|
|
70
75
|
`localizationOptions.availableLocales` supplies display-ready locale candidates independently from the policy; when
|
|
71
76
|
both are present, only candidates allowed by `allowedLocales` are shown. `placement` supports `top`,
|
|
@@ -82,6 +87,8 @@ in the selected value. The standard
|
|
|
82
87
|
MUI field editor supplies icons for every field type and accepts `slots.fieldTypeSelect` and `slots.fieldEditorHeader`
|
|
83
88
|
for focused customization. `muiSlotProps` also supports `textField`, `select`, `selectMenu`, `checkbox`, `button`, and
|
|
84
89
|
`iconButton` MUI props in addition to the layout props.
|
|
90
|
+
`fieldEditorOptions.fieldTypeOptions` can explicitly order, sort, or transform the generated type choices without
|
|
91
|
+
mutating the defaults.
|
|
85
92
|
|
|
86
93
|
`MuiFormBuilder` supplies options through `MuiFormBuilderContext` to module-stable adapter and slot component types.
|
|
87
94
|
Controlled schema updates therefore preserve input focus and uncontrolled MUI state such as an open localization
|
package/dist/index.cjs
CHANGED
|
@@ -102,7 +102,17 @@ function resolveMuiAdapterOptions(options = {}) {
|
|
|
102
102
|
...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
|
|
103
103
|
layoutOptions: options.layoutOptions ?? {},
|
|
104
104
|
fieldEditorOptions: {
|
|
105
|
-
|
|
105
|
+
title: options.fieldEditorOptions?.title ?? "editable",
|
|
106
|
+
description: options.fieldEditorOptions?.description ?? "editable",
|
|
107
|
+
required: options.fieldEditorOptions?.required ?? "editable",
|
|
108
|
+
typeSelect: options.fieldEditorOptions?.typeSelect ?? "editable",
|
|
109
|
+
options: options.fieldEditorOptions?.options ?? "editable",
|
|
110
|
+
displayConditions: options.fieldEditorOptions?.displayConditions ?? "editable",
|
|
111
|
+
textLimits: options.fieldEditorOptions?.textLimits ?? "editable",
|
|
112
|
+
ratingBounds: options.fieldEditorOptions?.ratingBounds ?? "editable",
|
|
113
|
+
numberLimits: options.fieldEditorOptions?.numberLimits ?? "editable",
|
|
114
|
+
...options.fieldEditorOptions?.byType === void 0 ? {} : { byType: options.fieldEditorOptions.byType },
|
|
115
|
+
...options.fieldEditorOptions?.fieldTypeOptions === void 0 ? {} : { fieldTypeOptions: options.fieldEditorOptions.fieldTypeOptions }
|
|
106
116
|
},
|
|
107
117
|
localizationOptions: {
|
|
108
118
|
collapsible: options.localizationOptions?.collapsible ?? false,
|
|
@@ -128,7 +138,13 @@ function mergeMuiAdapterOptions(base = {}, overrides = {}) {
|
|
|
128
138
|
...overrides,
|
|
129
139
|
...base.buttonVariants === void 0 && overrides.buttonVariants === void 0 ? {} : { buttonVariants: { ...base.buttonVariants, ...overrides.buttonVariants } },
|
|
130
140
|
...base.layoutOptions === void 0 && overrides.layoutOptions === void 0 ? {} : { layoutOptions: { ...base.layoutOptions, ...overrides.layoutOptions } },
|
|
131
|
-
...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : {
|
|
141
|
+
...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : {
|
|
142
|
+
fieldEditorOptions: {
|
|
143
|
+
...base.fieldEditorOptions,
|
|
144
|
+
...overrides.fieldEditorOptions,
|
|
145
|
+
...base.fieldEditorOptions?.byType === void 0 && overrides.fieldEditorOptions?.byType === void 0 ? {} : { byType: { ...base.fieldEditorOptions?.byType, ...overrides.fieldEditorOptions?.byType } }
|
|
146
|
+
}
|
|
147
|
+
},
|
|
132
148
|
...base.localizationOptions === void 0 && overrides.localizationOptions === void 0 ? {} : { localizationOptions: { ...base.localizationOptions, ...overrides.localizationOptions } },
|
|
133
149
|
...base.muiSlotProps === void 0 && overrides.muiSlotProps === void 0 ? {} : { muiSlotProps: { ...base.muiSlotProps, ...overrides.muiSlotProps } }
|
|
134
150
|
};
|
|
@@ -774,6 +790,7 @@ function createMuiBuilderComponents(optionsOrOverrides = {}, customOverrides) {
|
|
|
774
790
|
|
|
775
791
|
// src/slots/FieldEditor.tsx
|
|
776
792
|
var import_core = require("@form-engine-ts/core");
|
|
793
|
+
var import_react2 = require("@form-engine-ts/react");
|
|
777
794
|
var import_material12 = require("@mui/material");
|
|
778
795
|
|
|
779
796
|
// src/slots/OptionEditor.tsx
|
|
@@ -946,6 +963,13 @@ function updateBound(field, property, value) {
|
|
|
946
963
|
const { [property]: _removed, ...remaining } = field;
|
|
947
964
|
return remaining;
|
|
948
965
|
}
|
|
966
|
+
function updateNumberProperty(field, property, value) {
|
|
967
|
+
if (field.type !== "number") return field;
|
|
968
|
+
const nextValue = numericValue(value);
|
|
969
|
+
if (nextValue !== void 0) return { ...field, [property]: nextValue };
|
|
970
|
+
const { [property]: _removed, ...remaining } = field;
|
|
971
|
+
return remaining;
|
|
972
|
+
}
|
|
949
973
|
function createMuiFieldEditorSlot(options) {
|
|
950
974
|
const Toolbar = createMuiToolbarSlot(options);
|
|
951
975
|
const OptionEditor = createMuiOptionEditorSlot(options);
|
|
@@ -960,7 +984,9 @@ function createMuiFieldEditorSlot(options) {
|
|
|
960
984
|
actions,
|
|
961
985
|
components,
|
|
962
986
|
translate,
|
|
963
|
-
slots
|
|
987
|
+
slots,
|
|
988
|
+
fieldEditorControls,
|
|
989
|
+
fieldTypeOptions: fieldTypeOptionsConfig
|
|
964
990
|
}) {
|
|
965
991
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
966
992
|
const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
|
|
@@ -969,13 +995,18 @@ function createMuiFieldEditorSlot(options) {
|
|
|
969
995
|
const condition = field.displayCondition;
|
|
970
996
|
const conditionSources = schema.fields.slice(0, index);
|
|
971
997
|
const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
|
|
972
|
-
const
|
|
998
|
+
const fieldEditorOptions = resolved.fieldEditorOptions ?? {};
|
|
999
|
+
const controls = (0, import_react2.resolveFieldEditorControls)({
|
|
1000
|
+
...fieldEditorControls ?? {},
|
|
1001
|
+
...fieldEditorOptions,
|
|
1002
|
+
...fieldEditorOptions.byType?.[field.type] ?? {}
|
|
1003
|
+
});
|
|
973
1004
|
const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
|
|
974
1005
|
const FieldTypeSelect = slots?.fieldTypeSelect;
|
|
975
1006
|
const FieldEditorHeader = slots?.fieldEditorHeader;
|
|
976
1007
|
const fieldTypeSelectId = `mui-field-${field.id}-type`;
|
|
977
1008
|
const fieldTypeSelectLabel = translate("builder.type");
|
|
978
|
-
const
|
|
1009
|
+
const generatedFieldTypeOptions = FIELD_TYPES.filter(
|
|
979
1010
|
(type) => allowedTypes.includes(type)
|
|
980
1011
|
).map((type) => {
|
|
981
1012
|
const definition = import_core.DEFAULT_FIELD_TYPE_DEFINITIONS.find((candidate) => candidate.type === type);
|
|
@@ -991,6 +1022,14 @@ function createMuiFieldEditorSlot(options) {
|
|
|
991
1022
|
}
|
|
992
1023
|
};
|
|
993
1024
|
});
|
|
1025
|
+
const fieldTypeOptions = (0, import_react2.resolveFieldTypeSelectOptions)(
|
|
1026
|
+
generatedFieldTypeOptions,
|
|
1027
|
+
fieldTypeOptionsConfig ?? fieldEditorOptions.fieldTypeOptions,
|
|
1028
|
+
{
|
|
1029
|
+
currentType: field.type,
|
|
1030
|
+
allowedTypes
|
|
1031
|
+
}
|
|
1032
|
+
);
|
|
994
1033
|
const changeFieldType = (nextType) => {
|
|
995
1034
|
if (allowedTypes.includes(nextType)) actions.changeFieldType(field.id, nextType);
|
|
996
1035
|
};
|
|
@@ -1025,7 +1064,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1025
1064
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(FieldEditorHeader, { field, index, totalFields: schema.fields.length, actions }),
|
|
1026
1065
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { ...resolved.muiSlotProps?.stack, spacing: resolved.dense ? 1 : 2, children: [
|
|
1027
1066
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1028
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1067
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1029
1068
|
TextInput,
|
|
1030
1069
|
{
|
|
1031
1070
|
id: `mui-field-${field.id}-title`,
|
|
@@ -1036,11 +1075,11 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1036
1075
|
error: field.title.trim().length === 0,
|
|
1037
1076
|
helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
|
|
1038
1077
|
"aria-describedby": titleErrorId,
|
|
1039
|
-
disabled: readOnly,
|
|
1078
|
+
disabled: readOnly || controls.title === "readOnly",
|
|
1040
1079
|
onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "title", value)
|
|
1041
1080
|
}
|
|
1042
1081
|
),
|
|
1043
|
-
FieldTypeSelect === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1082
|
+
controls.typeSelect === "hidden" ? null : FieldTypeSelect === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1044
1083
|
Select2,
|
|
1045
1084
|
{
|
|
1046
1085
|
id: fieldTypeSelectId,
|
|
@@ -1048,7 +1087,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1048
1087
|
label: fieldTypeSelectLabel,
|
|
1049
1088
|
value: allowedTypes.includes(field.type) ? field.type : "",
|
|
1050
1089
|
options: fieldTypeOptions,
|
|
1051
|
-
disabled: readOnly,
|
|
1090
|
+
disabled: readOnly || controls.typeSelect === "readOnly",
|
|
1052
1091
|
onChange: (value) => {
|
|
1053
1092
|
if (isFieldType(value)) changeFieldType(value);
|
|
1054
1093
|
}
|
|
@@ -1063,14 +1102,14 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1063
1102
|
allowedTypes,
|
|
1064
1103
|
options: fieldTypeOptions,
|
|
1065
1104
|
onChangeType: changeFieldType,
|
|
1066
|
-
disabled: readOnly,
|
|
1067
|
-
readOnly,
|
|
1105
|
+
disabled: readOnly || controls.typeSelect === "readOnly",
|
|
1106
|
+
readOnly: readOnly || controls.typeSelect === "readOnly",
|
|
1068
1107
|
"aria-labelledby": `${fieldTypeSelectId}-label`,
|
|
1069
1108
|
renderIcon: components.renderFieldTypeIcon
|
|
1070
1109
|
}
|
|
1071
1110
|
)
|
|
1072
1111
|
] }),
|
|
1073
|
-
|
|
1112
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1074
1113
|
TextArea,
|
|
1075
1114
|
{
|
|
1076
1115
|
id: `mui-field-${field.id}-description`,
|
|
@@ -1078,19 +1117,19 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1078
1117
|
label: translate("builder.description"),
|
|
1079
1118
|
value: field.description ?? "",
|
|
1080
1119
|
rows: resolved.dense ? 2 : 3,
|
|
1081
|
-
disabled: readOnly,
|
|
1082
|
-
readOnly:
|
|
1120
|
+
disabled: readOnly || controls.description === "readOnly",
|
|
1121
|
+
readOnly: readOnly || controls.description === "readOnly",
|
|
1083
1122
|
onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "description", value)
|
|
1084
1123
|
}
|
|
1085
1124
|
),
|
|
1086
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1125
|
+
controls.required === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1087
1126
|
Checkbox2,
|
|
1088
1127
|
{
|
|
1089
1128
|
id: `mui-field-${field.id}-required`,
|
|
1090
1129
|
name: `fields.${field.id}.required`,
|
|
1091
1130
|
label: translate("builder.required"),
|
|
1092
1131
|
checked: field.required,
|
|
1093
|
-
disabled: readOnly,
|
|
1132
|
+
disabled: readOnly || controls.required === "readOnly",
|
|
1094
1133
|
onChange: (checked) => actions.updateField(field.id, (current) => ({ ...current, required: checked }))
|
|
1095
1134
|
}
|
|
1096
1135
|
),
|
|
@@ -1108,7 +1147,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1108
1147
|
onChange: (value) => actions.assignFieldToPage(field.id, value.length === 0 ? null : value)
|
|
1109
1148
|
}
|
|
1110
1149
|
),
|
|
1111
|
-
field.type === "number" || field.type === "rating" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1150
|
+
field.type === "number" || field.type === "rating" ? (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1112
1151
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1113
1152
|
TextInput,
|
|
1114
1153
|
{
|
|
@@ -1116,7 +1155,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1116
1155
|
label: translate("builder.minimum"),
|
|
1117
1156
|
type: "number",
|
|
1118
1157
|
value: field.min === void 0 ? "" : String(field.min),
|
|
1119
|
-
disabled: readOnly,
|
|
1158
|
+
disabled: readOnly || (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "readOnly",
|
|
1120
1159
|
onChange: (value) => actions.updateField(field.id, (current) => updateBound(current, "min", value))
|
|
1121
1160
|
}
|
|
1122
1161
|
),
|
|
@@ -1127,12 +1166,68 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1127
1166
|
label: translate("builder.maximum"),
|
|
1128
1167
|
type: "number",
|
|
1129
1168
|
value: field.max === void 0 ? "" : String(field.max),
|
|
1130
|
-
disabled: readOnly,
|
|
1169
|
+
disabled: readOnly || (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "readOnly",
|
|
1131
1170
|
onChange: (value) => actions.updateField(field.id, (current) => updateBound(current, "max", value))
|
|
1132
1171
|
}
|
|
1133
1172
|
)
|
|
1134
1173
|
] }) : null,
|
|
1135
|
-
|
|
1174
|
+
field.type === "number" && controls.numberLimits !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1175
|
+
TextInput,
|
|
1176
|
+
{
|
|
1177
|
+
id: `mui-field-${field.id}-step`,
|
|
1178
|
+
label: translate("builder.step"),
|
|
1179
|
+
type: "number",
|
|
1180
|
+
value: field.step === void 0 ? "" : String(field.step),
|
|
1181
|
+
disabled: readOnly || controls.numberLimits === "readOnly",
|
|
1182
|
+
onChange: (value) => actions.updateField(field.id, (current) => updateNumberProperty(current, "step", value))
|
|
1183
|
+
}
|
|
1184
|
+
) : null,
|
|
1185
|
+
(field.type === "text" || field.type === "textarea") && controls.textLimits !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1187
|
+
TextInput,
|
|
1188
|
+
{
|
|
1189
|
+
id: `mui-field-${field.id}-min-length`,
|
|
1190
|
+
label: translate("builder.minimumLength"),
|
|
1191
|
+
type: "number",
|
|
1192
|
+
value: field.minLength === void 0 ? "" : String(field.minLength),
|
|
1193
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1194
|
+
onChange: (value) => actions.updateField(field.id, (current) => {
|
|
1195
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
1196
|
+
const parsed = numericValue(value);
|
|
1197
|
+
return parsed === void 0 ? current : { ...current, minLength: Math.max(0, Math.floor(parsed)) };
|
|
1198
|
+
})
|
|
1199
|
+
}
|
|
1200
|
+
),
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1202
|
+
TextInput,
|
|
1203
|
+
{
|
|
1204
|
+
id: `mui-field-${field.id}-max-length`,
|
|
1205
|
+
label: translate("builder.maximumLength"),
|
|
1206
|
+
type: "number",
|
|
1207
|
+
value: field.maxLength === void 0 ? "" : String(field.maxLength),
|
|
1208
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1209
|
+
onChange: (value) => actions.updateField(field.id, (current) => {
|
|
1210
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
1211
|
+
const parsed = numericValue(value);
|
|
1212
|
+
return parsed === void 0 ? current : { ...current, maxLength: Math.max(0, Math.floor(parsed)) };
|
|
1213
|
+
})
|
|
1214
|
+
}
|
|
1215
|
+
),
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1217
|
+
TextInput,
|
|
1218
|
+
{
|
|
1219
|
+
id: `mui-field-${field.id}-pattern`,
|
|
1220
|
+
label: translate("builder.pattern"),
|
|
1221
|
+
value: field.pattern ?? "",
|
|
1222
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1223
|
+
onChange: (value) => actions.updateField(
|
|
1224
|
+
field.id,
|
|
1225
|
+
(current) => current.type === "text" || current.type === "textarea" ? value.length === 0 ? current : { ...current, pattern: value } : current
|
|
1226
|
+
)
|
|
1227
|
+
}
|
|
1228
|
+
)
|
|
1229
|
+
] }) : null,
|
|
1230
|
+
features?.conditions === false || conditionSources.length === 0 || controls.displayConditions === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1136
1231
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1137
1232
|
Select2,
|
|
1138
1233
|
{
|
|
@@ -1143,7 +1238,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1143
1238
|
{ value: "", label: translate("builder.alwaysVisible") },
|
|
1144
1239
|
...conditionSources.map((source) => ({ value: source.id, label: source.title }))
|
|
1145
1240
|
],
|
|
1146
|
-
disabled: readOnly,
|
|
1241
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1147
1242
|
onChange: (value) => actions.setDisplayCondition(
|
|
1148
1243
|
field.id,
|
|
1149
1244
|
value.length === 0 ? void 0 : { questionId: value, operator: "equals", value: "" }
|
|
@@ -1160,7 +1255,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1160
1255
|
options: (conditionSource === void 0 ? [] : conditionOperators(conditionSource)).map(
|
|
1161
1256
|
(operator) => ({ value: operator, label: translate(`builder.operator.${operator}`) })
|
|
1162
1257
|
),
|
|
1163
|
-
disabled: readOnly,
|
|
1258
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1164
1259
|
onChange: (value) => {
|
|
1165
1260
|
if (!isConditionOperator(value)) return;
|
|
1166
1261
|
actions.setDisplayCondition(
|
|
@@ -1176,7 +1271,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1176
1271
|
id: `mui-field-${field.id}-condition-value`,
|
|
1177
1272
|
label: translate("builder.conditionValue"),
|
|
1178
1273
|
value: condition.value === void 0 ? "" : String(condition.value),
|
|
1179
|
-
disabled: readOnly,
|
|
1274
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1180
1275
|
onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
|
|
1181
1276
|
}
|
|
1182
1277
|
)
|
|
@@ -1186,29 +1281,29 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1186
1281
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle2", children: translate("builder.translation", {
|
|
1187
1282
|
locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
|
|
1188
1283
|
}) }),
|
|
1189
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1284
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1190
1285
|
TextInput,
|
|
1191
1286
|
{
|
|
1192
1287
|
id: `mui-field-${field.id}-${currentLocale}-title`,
|
|
1193
1288
|
label: translate("builder.translatedQuestionTitle"),
|
|
1194
1289
|
value: field.translations?.[currentLocale]?.title ?? "",
|
|
1195
|
-
disabled: readOnly,
|
|
1290
|
+
disabled: readOnly || controls.title === "readOnly",
|
|
1196
1291
|
onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
|
|
1197
1292
|
}
|
|
1198
1293
|
),
|
|
1199
|
-
|
|
1294
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1200
1295
|
TextArea,
|
|
1201
1296
|
{
|
|
1202
1297
|
id: `mui-field-${field.id}-${currentLocale}-description`,
|
|
1203
1298
|
label: translate("builder.translatedDescription"),
|
|
1204
1299
|
value: field.translations?.[currentLocale]?.description ?? "",
|
|
1205
|
-
disabled: readOnly,
|
|
1206
|
-
readOnly:
|
|
1300
|
+
disabled: readOnly || controls.description === "readOnly",
|
|
1301
|
+
readOnly: readOnly || controls.description === "readOnly",
|
|
1207
1302
|
onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
|
|
1208
1303
|
}
|
|
1209
1304
|
)
|
|
1210
1305
|
] }),
|
|
1211
|
-
"options" in field ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
|
|
1306
|
+
"options" in field && controls.options !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material12.Stack, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
|
|
1212
1307
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material12.Typography, { variant: "subtitle2", children: translate("builder.options") }),
|
|
1213
1308
|
field.options.map((option, optionIndex) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1214
1309
|
OptionEditor,
|
|
@@ -1219,7 +1314,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1219
1314
|
index: optionIndex,
|
|
1220
1315
|
currentLocale,
|
|
1221
1316
|
translate,
|
|
1222
|
-
readOnly,
|
|
1317
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
1223
1318
|
actions,
|
|
1224
1319
|
components
|
|
1225
1320
|
},
|
|
@@ -1230,7 +1325,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1230
1325
|
{
|
|
1231
1326
|
action: "addOption",
|
|
1232
1327
|
targetId: field.id,
|
|
1233
|
-
disabled: readOnly || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
1328
|
+
disabled: readOnly || controls.options === "readOnly" || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
1234
1329
|
onClick: () => actions.addOption(field.id),
|
|
1235
1330
|
children: translate("builder.addOption")
|
|
1236
1331
|
}
|
|
@@ -1247,7 +1342,7 @@ var MuiFieldEditorSlot = createMuiFieldEditorSlot();
|
|
|
1247
1342
|
// src/slots/Localization.tsx
|
|
1248
1343
|
var import_icons_material2 = require("@mui/icons-material");
|
|
1249
1344
|
var import_material13 = require("@mui/material");
|
|
1250
|
-
var
|
|
1345
|
+
var import_react3 = require("react");
|
|
1251
1346
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1252
1347
|
var DEFAULT_EMPTY_STATE_MESSAGE = "No translation locales have been added yet. Select a language from the dropdown above to add one.";
|
|
1253
1348
|
function normalizeLocaleOptions(options, getLocaleLabel) {
|
|
@@ -1278,8 +1373,8 @@ function createMuiLocalizationSlot(options) {
|
|
|
1278
1373
|
}) {
|
|
1279
1374
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
1280
1375
|
const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
|
|
1281
|
-
const [newLocale, setNewLocale] = (0,
|
|
1282
|
-
const [pendingFocusLocale, setPendingFocusLocale] = (0,
|
|
1376
|
+
const [newLocale, setNewLocale] = (0, import_react3.useState)("");
|
|
1377
|
+
const [pendingFocusLocale, setPendingFocusLocale] = (0, import_react3.useState)(null);
|
|
1283
1378
|
const locales = Array.from(
|
|
1284
1379
|
new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
|
|
1285
1380
|
);
|
|
@@ -1318,7 +1413,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1318
1413
|
event.stopPropagation();
|
|
1319
1414
|
addLocale();
|
|
1320
1415
|
};
|
|
1321
|
-
(0,
|
|
1416
|
+
(0, import_react3.useEffect)(() => {
|
|
1322
1417
|
if (pendingFocusLocale === null || currentLocale !== pendingFocusLocale) return;
|
|
1323
1418
|
const tab = document.getElementById(`mui-builder-locale-tab-${pendingFocusLocale}`);
|
|
1324
1419
|
if (tab === null) return;
|
|
@@ -1559,8 +1654,8 @@ function createMuiBuilderProps(options, overrides = {}) {
|
|
|
1559
1654
|
}
|
|
1560
1655
|
|
|
1561
1656
|
// src/MuiFormBuilder.tsx
|
|
1562
|
-
var
|
|
1563
|
-
var
|
|
1657
|
+
var import_react4 = require("@form-engine-ts/react");
|
|
1658
|
+
var import_react5 = require("react");
|
|
1564
1659
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1565
1660
|
function MuiFormBuilder({
|
|
1566
1661
|
muiOptions,
|
|
@@ -1572,7 +1667,7 @@ function MuiFormBuilder({
|
|
|
1572
1667
|
sectionOrder,
|
|
1573
1668
|
...props
|
|
1574
1669
|
}) {
|
|
1575
|
-
const contextOptions = (0,
|
|
1670
|
+
const contextOptions = (0, import_react5.useMemo)(
|
|
1576
1671
|
() => mergeMuiAdapterOptions(muiOptions, {
|
|
1577
1672
|
...layoutOptions === void 0 ? {} : { layoutOptions },
|
|
1578
1673
|
...localizationOptions === void 0 ? {} : { localizationOptions },
|
|
@@ -1580,13 +1675,13 @@ function MuiFormBuilder({
|
|
|
1580
1675
|
}),
|
|
1581
1676
|
[layoutOptions, localizationOptions, muiOptions, muiSlotProps]
|
|
1582
1677
|
);
|
|
1583
|
-
const contextValue = (0,
|
|
1584
|
-
const components = (0,
|
|
1585
|
-
const slots = (0,
|
|
1678
|
+
const contextValue = (0, import_react5.useMemo)(() => ({ options: contextOptions }), [contextOptions]);
|
|
1679
|
+
const components = (0, import_react5.useMemo)(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
|
|
1680
|
+
const slots = (0, import_react5.useMemo)(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
|
|
1586
1681
|
const placement = contextOptions.localizationOptions?.placement;
|
|
1587
1682
|
const resolvedSectionOrder = sectionOrder ?? (placement === void 0 ? contextOptions.layoutOptions?.sectionOrder : MUI_LOCALIZATION_SECTION_ORDERS[placement]);
|
|
1588
1683
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1589
|
-
|
|
1684
|
+
import_react4.FormBuilder,
|
|
1590
1685
|
{
|
|
1591
1686
|
...props,
|
|
1592
1687
|
components,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BuilderActionIconType, LocalizationSummaryContext, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps,
|
|
1
|
+
import { BuilderActionIconType, FieldPropertyControlMode, QuestionType, FieldEditorControlsConfig, FieldTypeSelectOptionsConfig, LocalizationSummaryContext, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps, BuilderFieldEditorSlotProps, BuilderLocalizationSlotProps, BuilderOptionEditorSlotProps, BuilderToolbarSlotProps } from '@form-engine-ts/react';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, ComponentType, ReactElement } from 'react';
|
|
4
4
|
import { CardProps, PaperProps, AccordionProps, StackProps, TextFieldProps, SelectProps, MenuProps, CheckboxProps, ButtonProps, IconButtonProps } from '@mui/material';
|
|
@@ -28,8 +28,23 @@ interface MuiLocalizationOptions {
|
|
|
28
28
|
readonly noWrapActions?: boolean;
|
|
29
29
|
readonly autoFocusNewTab?: boolean;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* MUI's field editor controls mirror `FieldEditorControlsConfig` while keeping
|
|
33
|
+
* the original interface members directly declared for semver/reporting compatibility.
|
|
34
|
+
*/
|
|
31
35
|
interface MuiFieldEditorOptions {
|
|
36
|
+
readonly title?: FieldPropertyControlMode;
|
|
32
37
|
readonly description?: "editable" | "readOnly" | "hidden";
|
|
38
|
+
readonly required?: FieldPropertyControlMode;
|
|
39
|
+
readonly typeSelect?: FieldPropertyControlMode;
|
|
40
|
+
readonly options?: FieldPropertyControlMode;
|
|
41
|
+
readonly displayConditions?: FieldPropertyControlMode;
|
|
42
|
+
readonly textLimits?: FieldPropertyControlMode;
|
|
43
|
+
readonly ratingBounds?: FieldPropertyControlMode;
|
|
44
|
+
readonly numberLimits?: FieldPropertyControlMode;
|
|
45
|
+
/** Per-question-type overrides take precedence over the base controls. */
|
|
46
|
+
readonly byType?: Partial<Record<QuestionType, Partial<FieldEditorControlsConfig>>>;
|
|
47
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
33
48
|
}
|
|
34
49
|
interface MuiSlotProps {
|
|
35
50
|
readonly card?: Partial<CardProps>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BuilderActionIconType, LocalizationSummaryContext, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps,
|
|
1
|
+
import { BuilderActionIconType, FieldPropertyControlMode, QuestionType, FieldEditorControlsConfig, FieldTypeSelectOptionsConfig, LocalizationSummaryContext, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps, BuilderFieldEditorSlotProps, BuilderLocalizationSlotProps, BuilderOptionEditorSlotProps, BuilderToolbarSlotProps } from '@form-engine-ts/react';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, ComponentType, ReactElement } from 'react';
|
|
4
4
|
import { CardProps, PaperProps, AccordionProps, StackProps, TextFieldProps, SelectProps, MenuProps, CheckboxProps, ButtonProps, IconButtonProps } from '@mui/material';
|
|
@@ -28,8 +28,23 @@ interface MuiLocalizationOptions {
|
|
|
28
28
|
readonly noWrapActions?: boolean;
|
|
29
29
|
readonly autoFocusNewTab?: boolean;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* MUI's field editor controls mirror `FieldEditorControlsConfig` while keeping
|
|
33
|
+
* the original interface members directly declared for semver/reporting compatibility.
|
|
34
|
+
*/
|
|
31
35
|
interface MuiFieldEditorOptions {
|
|
36
|
+
readonly title?: FieldPropertyControlMode;
|
|
32
37
|
readonly description?: "editable" | "readOnly" | "hidden";
|
|
38
|
+
readonly required?: FieldPropertyControlMode;
|
|
39
|
+
readonly typeSelect?: FieldPropertyControlMode;
|
|
40
|
+
readonly options?: FieldPropertyControlMode;
|
|
41
|
+
readonly displayConditions?: FieldPropertyControlMode;
|
|
42
|
+
readonly textLimits?: FieldPropertyControlMode;
|
|
43
|
+
readonly ratingBounds?: FieldPropertyControlMode;
|
|
44
|
+
readonly numberLimits?: FieldPropertyControlMode;
|
|
45
|
+
/** Per-question-type overrides take precedence over the base controls. */
|
|
46
|
+
readonly byType?: Partial<Record<QuestionType, Partial<FieldEditorControlsConfig>>>;
|
|
47
|
+
readonly fieldTypeOptions?: FieldTypeSelectOptionsConfig;
|
|
33
48
|
}
|
|
34
49
|
interface MuiSlotProps {
|
|
35
50
|
readonly card?: Partial<CardProps>;
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,17 @@ function resolveMuiAdapterOptions(options = {}) {
|
|
|
37
37
|
...options.getActionLabel === void 0 ? {} : { getActionLabel: options.getActionLabel },
|
|
38
38
|
layoutOptions: options.layoutOptions ?? {},
|
|
39
39
|
fieldEditorOptions: {
|
|
40
|
-
|
|
40
|
+
title: options.fieldEditorOptions?.title ?? "editable",
|
|
41
|
+
description: options.fieldEditorOptions?.description ?? "editable",
|
|
42
|
+
required: options.fieldEditorOptions?.required ?? "editable",
|
|
43
|
+
typeSelect: options.fieldEditorOptions?.typeSelect ?? "editable",
|
|
44
|
+
options: options.fieldEditorOptions?.options ?? "editable",
|
|
45
|
+
displayConditions: options.fieldEditorOptions?.displayConditions ?? "editable",
|
|
46
|
+
textLimits: options.fieldEditorOptions?.textLimits ?? "editable",
|
|
47
|
+
ratingBounds: options.fieldEditorOptions?.ratingBounds ?? "editable",
|
|
48
|
+
numberLimits: options.fieldEditorOptions?.numberLimits ?? "editable",
|
|
49
|
+
...options.fieldEditorOptions?.byType === void 0 ? {} : { byType: options.fieldEditorOptions.byType },
|
|
50
|
+
...options.fieldEditorOptions?.fieldTypeOptions === void 0 ? {} : { fieldTypeOptions: options.fieldEditorOptions.fieldTypeOptions }
|
|
41
51
|
},
|
|
42
52
|
localizationOptions: {
|
|
43
53
|
collapsible: options.localizationOptions?.collapsible ?? false,
|
|
@@ -63,7 +73,13 @@ function mergeMuiAdapterOptions(base = {}, overrides = {}) {
|
|
|
63
73
|
...overrides,
|
|
64
74
|
...base.buttonVariants === void 0 && overrides.buttonVariants === void 0 ? {} : { buttonVariants: { ...base.buttonVariants, ...overrides.buttonVariants } },
|
|
65
75
|
...base.layoutOptions === void 0 && overrides.layoutOptions === void 0 ? {} : { layoutOptions: { ...base.layoutOptions, ...overrides.layoutOptions } },
|
|
66
|
-
...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : {
|
|
76
|
+
...base.fieldEditorOptions === void 0 && overrides.fieldEditorOptions === void 0 ? {} : {
|
|
77
|
+
fieldEditorOptions: {
|
|
78
|
+
...base.fieldEditorOptions,
|
|
79
|
+
...overrides.fieldEditorOptions,
|
|
80
|
+
...base.fieldEditorOptions?.byType === void 0 && overrides.fieldEditorOptions?.byType === void 0 ? {} : { byType: { ...base.fieldEditorOptions?.byType, ...overrides.fieldEditorOptions?.byType } }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
67
83
|
...base.localizationOptions === void 0 && overrides.localizationOptions === void 0 ? {} : { localizationOptions: { ...base.localizationOptions, ...overrides.localizationOptions } },
|
|
68
84
|
...base.muiSlotProps === void 0 && overrides.muiSlotProps === void 0 ? {} : { muiSlotProps: { ...base.muiSlotProps, ...overrides.muiSlotProps } }
|
|
69
85
|
};
|
|
@@ -736,6 +752,7 @@ function createMuiBuilderComponents(optionsOrOverrides = {}, customOverrides) {
|
|
|
736
752
|
|
|
737
753
|
// src/slots/FieldEditor.tsx
|
|
738
754
|
import { DEFAULT_FIELD_TYPE_DEFINITIONS } from "@form-engine-ts/core";
|
|
755
|
+
import { resolveFieldEditorControls, resolveFieldTypeSelectOptions } from "@form-engine-ts/react";
|
|
739
756
|
import { Card, Stack as Stack3, Typography as Typography3 } from "@mui/material";
|
|
740
757
|
|
|
741
758
|
// src/slots/OptionEditor.tsx
|
|
@@ -908,6 +925,13 @@ function updateBound(field, property, value) {
|
|
|
908
925
|
const { [property]: _removed, ...remaining } = field;
|
|
909
926
|
return remaining;
|
|
910
927
|
}
|
|
928
|
+
function updateNumberProperty(field, property, value) {
|
|
929
|
+
if (field.type !== "number") return field;
|
|
930
|
+
const nextValue = numericValue(value);
|
|
931
|
+
if (nextValue !== void 0) return { ...field, [property]: nextValue };
|
|
932
|
+
const { [property]: _removed, ...remaining } = field;
|
|
933
|
+
return remaining;
|
|
934
|
+
}
|
|
911
935
|
function createMuiFieldEditorSlot(options) {
|
|
912
936
|
const Toolbar = createMuiToolbarSlot(options);
|
|
913
937
|
const OptionEditor = createMuiOptionEditorSlot(options);
|
|
@@ -922,7 +946,9 @@ function createMuiFieldEditorSlot(options) {
|
|
|
922
946
|
actions,
|
|
923
947
|
components,
|
|
924
948
|
translate,
|
|
925
|
-
slots
|
|
949
|
+
slots,
|
|
950
|
+
fieldEditorControls,
|
|
951
|
+
fieldTypeOptions: fieldTypeOptionsConfig
|
|
926
952
|
}) {
|
|
927
953
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
928
954
|
const { Button: Button2, Checkbox: Checkbox2, Select: Select2, TextArea, TextInput } = components;
|
|
@@ -931,13 +957,18 @@ function createMuiFieldEditorSlot(options) {
|
|
|
931
957
|
const condition = field.displayCondition;
|
|
932
958
|
const conditionSources = schema.fields.slice(0, index);
|
|
933
959
|
const conditionSource = conditionSources.find((source) => source.id === condition?.questionId);
|
|
934
|
-
const
|
|
960
|
+
const fieldEditorOptions = resolved.fieldEditorOptions ?? {};
|
|
961
|
+
const controls = resolveFieldEditorControls({
|
|
962
|
+
...fieldEditorControls ?? {},
|
|
963
|
+
...fieldEditorOptions,
|
|
964
|
+
...fieldEditorOptions.byType?.[field.type] ?? {}
|
|
965
|
+
});
|
|
935
966
|
const titleErrorId = field.title.trim().length === 0 ? `mui-field-${field.id}-title-error` : void 0;
|
|
936
967
|
const FieldTypeSelect = slots?.fieldTypeSelect;
|
|
937
968
|
const FieldEditorHeader = slots?.fieldEditorHeader;
|
|
938
969
|
const fieldTypeSelectId = `mui-field-${field.id}-type`;
|
|
939
970
|
const fieldTypeSelectLabel = translate("builder.type");
|
|
940
|
-
const
|
|
971
|
+
const generatedFieldTypeOptions = FIELD_TYPES.filter(
|
|
941
972
|
(type) => allowedTypes.includes(type)
|
|
942
973
|
).map((type) => {
|
|
943
974
|
const definition = DEFAULT_FIELD_TYPE_DEFINITIONS.find((candidate) => candidate.type === type);
|
|
@@ -953,6 +984,14 @@ function createMuiFieldEditorSlot(options) {
|
|
|
953
984
|
}
|
|
954
985
|
};
|
|
955
986
|
});
|
|
987
|
+
const fieldTypeOptions = resolveFieldTypeSelectOptions(
|
|
988
|
+
generatedFieldTypeOptions,
|
|
989
|
+
fieldTypeOptionsConfig ?? fieldEditorOptions.fieldTypeOptions,
|
|
990
|
+
{
|
|
991
|
+
currentType: field.type,
|
|
992
|
+
allowedTypes
|
|
993
|
+
}
|
|
994
|
+
);
|
|
956
995
|
const changeFieldType = (nextType) => {
|
|
957
996
|
if (allowedTypes.includes(nextType)) actions.changeFieldType(field.id, nextType);
|
|
958
997
|
};
|
|
@@ -987,7 +1026,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
987
1026
|
] }) : /* @__PURE__ */ jsx13(FieldEditorHeader, { field, index, totalFields: schema.fields.length, actions }),
|
|
988
1027
|
/* @__PURE__ */ jsxs7(Stack3, { ...resolved.muiSlotProps?.stack, spacing: resolved.dense ? 1 : 2, children: [
|
|
989
1028
|
/* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
990
|
-
/* @__PURE__ */ jsx13(
|
|
1029
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ jsx13(
|
|
991
1030
|
TextInput,
|
|
992
1031
|
{
|
|
993
1032
|
id: `mui-field-${field.id}-title`,
|
|
@@ -998,11 +1037,11 @@ function createMuiFieldEditorSlot(options) {
|
|
|
998
1037
|
error: field.title.trim().length === 0,
|
|
999
1038
|
helperText: field.title.trim().length === 0 ? translate("builder.required") : "",
|
|
1000
1039
|
"aria-describedby": titleErrorId,
|
|
1001
|
-
disabled: readOnly,
|
|
1040
|
+
disabled: readOnly || controls.title === "readOnly",
|
|
1002
1041
|
onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "title", value)
|
|
1003
1042
|
}
|
|
1004
1043
|
),
|
|
1005
|
-
FieldTypeSelect === void 0 ? /* @__PURE__ */ jsx13(
|
|
1044
|
+
controls.typeSelect === "hidden" ? null : FieldTypeSelect === void 0 ? /* @__PURE__ */ jsx13(
|
|
1006
1045
|
Select2,
|
|
1007
1046
|
{
|
|
1008
1047
|
id: fieldTypeSelectId,
|
|
@@ -1010,7 +1049,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1010
1049
|
label: fieldTypeSelectLabel,
|
|
1011
1050
|
value: allowedTypes.includes(field.type) ? field.type : "",
|
|
1012
1051
|
options: fieldTypeOptions,
|
|
1013
|
-
disabled: readOnly,
|
|
1052
|
+
disabled: readOnly || controls.typeSelect === "readOnly",
|
|
1014
1053
|
onChange: (value) => {
|
|
1015
1054
|
if (isFieldType(value)) changeFieldType(value);
|
|
1016
1055
|
}
|
|
@@ -1025,14 +1064,14 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1025
1064
|
allowedTypes,
|
|
1026
1065
|
options: fieldTypeOptions,
|
|
1027
1066
|
onChangeType: changeFieldType,
|
|
1028
|
-
disabled: readOnly,
|
|
1029
|
-
readOnly,
|
|
1067
|
+
disabled: readOnly || controls.typeSelect === "readOnly",
|
|
1068
|
+
readOnly: readOnly || controls.typeSelect === "readOnly",
|
|
1030
1069
|
"aria-labelledby": `${fieldTypeSelectId}-label`,
|
|
1031
1070
|
renderIcon: components.renderFieldTypeIcon
|
|
1032
1071
|
}
|
|
1033
1072
|
)
|
|
1034
1073
|
] }),
|
|
1035
|
-
|
|
1074
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ jsx13(
|
|
1036
1075
|
TextArea,
|
|
1037
1076
|
{
|
|
1038
1077
|
id: `mui-field-${field.id}-description`,
|
|
@@ -1040,19 +1079,19 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1040
1079
|
label: translate("builder.description"),
|
|
1041
1080
|
value: field.description ?? "",
|
|
1042
1081
|
rows: resolved.dense ? 2 : 3,
|
|
1043
|
-
disabled: readOnly,
|
|
1044
|
-
readOnly:
|
|
1082
|
+
disabled: readOnly || controls.description === "readOnly",
|
|
1083
|
+
readOnly: readOnly || controls.description === "readOnly",
|
|
1045
1084
|
onChange: (value) => actions.setSourceText({ kind: "field", id: field.id }, "description", value)
|
|
1046
1085
|
}
|
|
1047
1086
|
),
|
|
1048
|
-
/* @__PURE__ */ jsx13(
|
|
1087
|
+
controls.required === "hidden" ? null : /* @__PURE__ */ jsx13(
|
|
1049
1088
|
Checkbox2,
|
|
1050
1089
|
{
|
|
1051
1090
|
id: `mui-field-${field.id}-required`,
|
|
1052
1091
|
name: `fields.${field.id}.required`,
|
|
1053
1092
|
label: translate("builder.required"),
|
|
1054
1093
|
checked: field.required,
|
|
1055
|
-
disabled: readOnly,
|
|
1094
|
+
disabled: readOnly || controls.required === "readOnly",
|
|
1056
1095
|
onChange: (checked) => actions.updateField(field.id, (current) => ({ ...current, required: checked }))
|
|
1057
1096
|
}
|
|
1058
1097
|
),
|
|
@@ -1070,7 +1109,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1070
1109
|
onChange: (value) => actions.assignFieldToPage(field.id, value.length === 0 ? null : value)
|
|
1071
1110
|
}
|
|
1072
1111
|
),
|
|
1073
|
-
field.type === "number" || field.type === "rating" ? /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1112
|
+
field.type === "number" || field.type === "rating" ? (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "hidden" ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1074
1113
|
/* @__PURE__ */ jsx13(
|
|
1075
1114
|
TextInput,
|
|
1076
1115
|
{
|
|
@@ -1078,7 +1117,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1078
1117
|
label: translate("builder.minimum"),
|
|
1079
1118
|
type: "number",
|
|
1080
1119
|
value: field.min === void 0 ? "" : String(field.min),
|
|
1081
|
-
disabled: readOnly,
|
|
1120
|
+
disabled: readOnly || (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "readOnly",
|
|
1082
1121
|
onChange: (value) => actions.updateField(field.id, (current) => updateBound(current, "min", value))
|
|
1083
1122
|
}
|
|
1084
1123
|
),
|
|
@@ -1089,12 +1128,68 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1089
1128
|
label: translate("builder.maximum"),
|
|
1090
1129
|
type: "number",
|
|
1091
1130
|
value: field.max === void 0 ? "" : String(field.max),
|
|
1092
|
-
disabled: readOnly,
|
|
1131
|
+
disabled: readOnly || (field.type === "number" ? controls.numberLimits : controls.ratingBounds) === "readOnly",
|
|
1093
1132
|
onChange: (value) => actions.updateField(field.id, (current) => updateBound(current, "max", value))
|
|
1094
1133
|
}
|
|
1095
1134
|
)
|
|
1096
1135
|
] }) : null,
|
|
1097
|
-
|
|
1136
|
+
field.type === "number" && controls.numberLimits !== "hidden" ? /* @__PURE__ */ jsx13(
|
|
1137
|
+
TextInput,
|
|
1138
|
+
{
|
|
1139
|
+
id: `mui-field-${field.id}-step`,
|
|
1140
|
+
label: translate("builder.step"),
|
|
1141
|
+
type: "number",
|
|
1142
|
+
value: field.step === void 0 ? "" : String(field.step),
|
|
1143
|
+
disabled: readOnly || controls.numberLimits === "readOnly",
|
|
1144
|
+
onChange: (value) => actions.updateField(field.id, (current) => updateNumberProperty(current, "step", value))
|
|
1145
|
+
}
|
|
1146
|
+
) : null,
|
|
1147
|
+
(field.type === "text" || field.type === "textarea") && controls.textLimits !== "hidden" ? /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", sm: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1148
|
+
/* @__PURE__ */ jsx13(
|
|
1149
|
+
TextInput,
|
|
1150
|
+
{
|
|
1151
|
+
id: `mui-field-${field.id}-min-length`,
|
|
1152
|
+
label: translate("builder.minimumLength"),
|
|
1153
|
+
type: "number",
|
|
1154
|
+
value: field.minLength === void 0 ? "" : String(field.minLength),
|
|
1155
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1156
|
+
onChange: (value) => actions.updateField(field.id, (current) => {
|
|
1157
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
1158
|
+
const parsed = numericValue(value);
|
|
1159
|
+
return parsed === void 0 ? current : { ...current, minLength: Math.max(0, Math.floor(parsed)) };
|
|
1160
|
+
})
|
|
1161
|
+
}
|
|
1162
|
+
),
|
|
1163
|
+
/* @__PURE__ */ jsx13(
|
|
1164
|
+
TextInput,
|
|
1165
|
+
{
|
|
1166
|
+
id: `mui-field-${field.id}-max-length`,
|
|
1167
|
+
label: translate("builder.maximumLength"),
|
|
1168
|
+
type: "number",
|
|
1169
|
+
value: field.maxLength === void 0 ? "" : String(field.maxLength),
|
|
1170
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1171
|
+
onChange: (value) => actions.updateField(field.id, (current) => {
|
|
1172
|
+
if (current.type !== "text" && current.type !== "textarea") return current;
|
|
1173
|
+
const parsed = numericValue(value);
|
|
1174
|
+
return parsed === void 0 ? current : { ...current, maxLength: Math.max(0, Math.floor(parsed)) };
|
|
1175
|
+
})
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
/* @__PURE__ */ jsx13(
|
|
1179
|
+
TextInput,
|
|
1180
|
+
{
|
|
1181
|
+
id: `mui-field-${field.id}-pattern`,
|
|
1182
|
+
label: translate("builder.pattern"),
|
|
1183
|
+
value: field.pattern ?? "",
|
|
1184
|
+
disabled: readOnly || controls.textLimits === "readOnly",
|
|
1185
|
+
onChange: (value) => actions.updateField(
|
|
1186
|
+
field.id,
|
|
1187
|
+
(current) => current.type === "text" || current.type === "textarea" ? value.length === 0 ? current : { ...current, pattern: value } : current
|
|
1188
|
+
)
|
|
1189
|
+
}
|
|
1190
|
+
)
|
|
1191
|
+
] }) : null,
|
|
1192
|
+
features?.conditions === false || conditionSources.length === 0 || controls.displayConditions === "hidden" ? null : /* @__PURE__ */ jsxs7(Stack3, { direction: { xs: "column", md: "row" }, spacing: resolved.dense ? 1 : 2, children: [
|
|
1098
1193
|
/* @__PURE__ */ jsx13(
|
|
1099
1194
|
Select2,
|
|
1100
1195
|
{
|
|
@@ -1105,7 +1200,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1105
1200
|
{ value: "", label: translate("builder.alwaysVisible") },
|
|
1106
1201
|
...conditionSources.map((source) => ({ value: source.id, label: source.title }))
|
|
1107
1202
|
],
|
|
1108
|
-
disabled: readOnly,
|
|
1203
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1109
1204
|
onChange: (value) => actions.setDisplayCondition(
|
|
1110
1205
|
field.id,
|
|
1111
1206
|
value.length === 0 ? void 0 : { questionId: value, operator: "equals", value: "" }
|
|
@@ -1122,7 +1217,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1122
1217
|
options: (conditionSource === void 0 ? [] : conditionOperators(conditionSource)).map(
|
|
1123
1218
|
(operator) => ({ value: operator, label: translate(`builder.operator.${operator}`) })
|
|
1124
1219
|
),
|
|
1125
|
-
disabled: readOnly,
|
|
1220
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1126
1221
|
onChange: (value) => {
|
|
1127
1222
|
if (!isConditionOperator(value)) return;
|
|
1128
1223
|
actions.setDisplayCondition(
|
|
@@ -1138,7 +1233,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1138
1233
|
id: `mui-field-${field.id}-condition-value`,
|
|
1139
1234
|
label: translate("builder.conditionValue"),
|
|
1140
1235
|
value: condition.value === void 0 ? "" : String(condition.value),
|
|
1141
|
-
disabled: readOnly,
|
|
1236
|
+
disabled: readOnly || controls.displayConditions === "readOnly",
|
|
1142
1237
|
onChange: (value) => actions.setDisplayCondition(field.id, { ...condition, value })
|
|
1143
1238
|
}
|
|
1144
1239
|
)
|
|
@@ -1148,29 +1243,29 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1148
1243
|
/* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.translation", {
|
|
1149
1244
|
locale: resolved.getLocaleLabel?.(currentLocale) ?? currentLocale
|
|
1150
1245
|
}) }),
|
|
1151
|
-
/* @__PURE__ */ jsx13(
|
|
1246
|
+
controls.title === "hidden" ? null : /* @__PURE__ */ jsx13(
|
|
1152
1247
|
TextInput,
|
|
1153
1248
|
{
|
|
1154
1249
|
id: `mui-field-${field.id}-${currentLocale}-title`,
|
|
1155
1250
|
label: translate("builder.translatedQuestionTitle"),
|
|
1156
1251
|
value: field.translations?.[currentLocale]?.title ?? "",
|
|
1157
|
-
disabled: readOnly,
|
|
1252
|
+
disabled: readOnly || controls.title === "readOnly",
|
|
1158
1253
|
onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "title", value)
|
|
1159
1254
|
}
|
|
1160
1255
|
),
|
|
1161
|
-
|
|
1256
|
+
controls.description === "hidden" ? null : /* @__PURE__ */ jsx13(
|
|
1162
1257
|
TextArea,
|
|
1163
1258
|
{
|
|
1164
1259
|
id: `mui-field-${field.id}-${currentLocale}-description`,
|
|
1165
1260
|
label: translate("builder.translatedDescription"),
|
|
1166
1261
|
value: field.translations?.[currentLocale]?.description ?? "",
|
|
1167
|
-
disabled: readOnly,
|
|
1168
|
-
readOnly:
|
|
1262
|
+
disabled: readOnly || controls.description === "readOnly",
|
|
1263
|
+
readOnly: readOnly || controls.description === "readOnly",
|
|
1169
1264
|
onChange: (value) => actions.setManualTranslation(currentLocale, { kind: "field", id: field.id }, "description", value)
|
|
1170
1265
|
}
|
|
1171
1266
|
)
|
|
1172
1267
|
] }),
|
|
1173
|
-
"options" in field ? /* @__PURE__ */ jsxs7(Stack3, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
|
|
1268
|
+
"options" in field && controls.options !== "hidden" ? /* @__PURE__ */ jsxs7(Stack3, { "data-mui-slot": "options", spacing: resolved.dense ? 1 : 2, children: [
|
|
1174
1269
|
/* @__PURE__ */ jsx13(Typography3, { variant: "subtitle2", children: translate("builder.options") }),
|
|
1175
1270
|
field.options.map((option, optionIndex) => /* @__PURE__ */ jsx13(
|
|
1176
1271
|
OptionEditor,
|
|
@@ -1181,7 +1276,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1181
1276
|
index: optionIndex,
|
|
1182
1277
|
currentLocale,
|
|
1183
1278
|
translate,
|
|
1184
|
-
readOnly,
|
|
1279
|
+
readOnly: readOnly || controls.options === "readOnly",
|
|
1185
1280
|
actions,
|
|
1186
1281
|
components
|
|
1187
1282
|
},
|
|
@@ -1192,7 +1287,7 @@ function createMuiFieldEditorSlot(options) {
|
|
|
1192
1287
|
{
|
|
1193
1288
|
action: "addOption",
|
|
1194
1289
|
targetId: field.id,
|
|
1195
|
-
disabled: readOnly || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
1290
|
+
disabled: readOnly || controls.options === "readOnly" || policy?.maxOptionsPerField !== void 0 && field.options.length >= policy.maxOptionsPerField,
|
|
1196
1291
|
onClick: () => actions.addOption(field.id),
|
|
1197
1292
|
children: translate("builder.addOption")
|
|
1198
1293
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/mui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"@mui/material": "^6.0.0 || ^7.0.0",
|
|
47
47
|
"react": "^18.0.0 || ^19.0.0",
|
|
48
48
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
49
|
-
"@form-engine-ts/core": "4.
|
|
50
|
-
"@form-engine-ts/react": "4.
|
|
49
|
+
"@form-engine-ts/core": "4.1.0",
|
|
50
|
+
"@form-engine-ts/react": "4.1.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@emotion/react": "^11.14.0",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"@types/react-dom": "^19.2.4",
|
|
59
59
|
"react": "^19.2.8",
|
|
60
60
|
"react-dom": "^19.2.8",
|
|
61
|
-
"@form-engine-ts/
|
|
62
|
-
"@form-engine-ts/
|
|
61
|
+
"@form-engine-ts/core": "4.1.0",
|
|
62
|
+
"@form-engine-ts/react": "4.1.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean --external @emotion/react --external @emotion/styled --external @form-engine-ts/core --external @form-engine-ts/react --external @mui/icons-material --external @mui/material --external react --external react-dom",
|