@form-engine-ts/mui 2.9.6 → 3.0.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 +11 -3
- package/dist/index.cjs +110 -25
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +122 -27
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -25,6 +25,11 @@ import { MuiFormBuilder } from "@form-engine-ts/mui";
|
|
|
25
25
|
sectionOrder: ["basicSettings", "completionMessage", "questions", "addQuestion", "localization"]
|
|
26
26
|
}}
|
|
27
27
|
localizationOptions={{
|
|
28
|
+
availableLocales: [
|
|
29
|
+
{ value: "ja", label: "日本語" },
|
|
30
|
+
{ value: "en", label: "English" }
|
|
31
|
+
],
|
|
32
|
+
placement: "afterQuestions",
|
|
28
33
|
collapsible: true,
|
|
29
34
|
defaultExpanded: "when-configured",
|
|
30
35
|
showSummary: true,
|
|
@@ -56,9 +61,12 @@ slots as it does for the standard builder.
|
|
|
56
61
|
width options. `fieldEditorOptions.description` and `localizationOptions.defaultLocaleControl` independently make those
|
|
57
62
|
controls editable, read-only, or hidden. Set `dense` to reduce section, editor, option, and toolbar spacing.
|
|
58
63
|
`buttonVariants` can override the MUI variant for `primary`, `secondary`, and `danger` actions independently.
|
|
59
|
-
`localizationOptions.
|
|
60
|
-
|
|
61
|
-
`
|
|
64
|
+
`localizationOptions.availableLocales` supplies display-ready locale candidates independently from the policy; when
|
|
65
|
+
both are present, only candidates allowed by `allowedLocales` are shown. `placement` supports `top`,
|
|
66
|
+
`beforeQuestions`, `afterQuestions`, and `bottom` section presets. `showSummary` renders a status alert, while
|
|
67
|
+
`renderSummary` can provide a custom summary. `emptyStateMessage` customizes the guidance shown before a translation
|
|
68
|
+
locale is added. `defaultExpanded` also accepts `"always"`; `autoFocusNewTab` focuses a newly added locale tab by
|
|
69
|
+
default.
|
|
62
70
|
`layoutOptions`, `localizationOptions`, and `muiSlotProps` are also accepted in `muiOptions` for low-level factories such
|
|
63
71
|
as `createMuiBuilderSlots`; the dedicated `MuiFormBuilder` props take precedence.
|
|
64
72
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DEFAULT_MUI_SECTION_ORDER: () => DEFAULT_MUI_SECTION_ORDER,
|
|
24
|
+
MUI_LOCALIZATION_SECTION_ORDERS: () => MUI_LOCALIZATION_SECTION_ORDERS,
|
|
24
25
|
MuiButtonAdapter: () => MuiButtonAdapter,
|
|
25
26
|
MuiCheckboxAdapter: () => MuiCheckboxAdapter,
|
|
26
27
|
MuiErrorMessageAdapter: () => MuiErrorMessageAdapter,
|
|
@@ -72,8 +73,15 @@ var DEFAULT_MUI_SECTION_ORDER = [
|
|
|
72
73
|
"basicSettings",
|
|
73
74
|
"questions",
|
|
74
75
|
"addQuestion",
|
|
75
|
-
"localization"
|
|
76
|
+
"localization",
|
|
77
|
+
"completionMessage"
|
|
76
78
|
];
|
|
79
|
+
var MUI_LOCALIZATION_SECTION_ORDERS = {
|
|
80
|
+
top: ["localization", "basicSettings", "completionMessage", "questions", "addQuestion"],
|
|
81
|
+
beforeQuestions: ["basicSettings", "localization", "completionMessage", "questions", "addQuestion"],
|
|
82
|
+
afterQuestions: ["basicSettings", "questions", "addQuestion", "localization", "completionMessage"],
|
|
83
|
+
bottom: ["basicSettings", "completionMessage", "questions", "addQuestion", "localization"]
|
|
84
|
+
};
|
|
77
85
|
function resolveMuiAdapterOptions(options = {}) {
|
|
78
86
|
const buttonVariant = options.buttonVariant ?? "contained";
|
|
79
87
|
return {
|
|
@@ -99,8 +107,13 @@ function resolveMuiAdapterOptions(options = {}) {
|
|
|
99
107
|
collapsible: options.localizationOptions?.collapsible ?? false,
|
|
100
108
|
defaultExpanded: options.localizationOptions?.defaultExpanded ?? false,
|
|
101
109
|
showSummary: options.localizationOptions?.showSummary ?? false,
|
|
110
|
+
...options.localizationOptions?.availableLocales === void 0 ? {} : { availableLocales: options.localizationOptions.availableLocales },
|
|
111
|
+
...options.localizationOptions?.placement === void 0 ? {} : { placement: options.localizationOptions.placement },
|
|
112
|
+
...options.localizationOptions?.renderSummary === void 0 ? {} : { renderSummary: options.localizationOptions.renderSummary },
|
|
102
113
|
...options.localizationOptions?.emptyStateMessage === void 0 ? {} : { emptyStateMessage: options.localizationOptions.emptyStateMessage },
|
|
103
|
-
defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable"
|
|
114
|
+
defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable",
|
|
115
|
+
noWrapActions: options.localizationOptions?.noWrapActions ?? true,
|
|
116
|
+
autoFocusNewTab: options.localizationOptions?.autoFocusNewTab ?? true
|
|
104
117
|
},
|
|
105
118
|
muiSlotProps: options.muiSlotProps ?? {}
|
|
106
119
|
};
|
|
@@ -138,6 +151,7 @@ function createMuiButtonAdapter(options) {
|
|
|
138
151
|
"aria-describedby": ariaDescribedBy,
|
|
139
152
|
"aria-labelledby": ariaLabelledBy,
|
|
140
153
|
onClick,
|
|
154
|
+
noWrap,
|
|
141
155
|
children,
|
|
142
156
|
title,
|
|
143
157
|
variant,
|
|
@@ -163,7 +177,7 @@ function createMuiButtonAdapter(options) {
|
|
|
163
177
|
color: variant === "danger" ? "error" : "primary",
|
|
164
178
|
variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
|
|
165
179
|
fullWidth: resolved.buttonFullWidth ?? false,
|
|
166
|
-
sx: { whiteSpace: "nowrap" },
|
|
180
|
+
sx: { whiteSpace: noWrap === false ? "normal" : "nowrap" },
|
|
167
181
|
children
|
|
168
182
|
}
|
|
169
183
|
);
|
|
@@ -407,6 +421,7 @@ function createMuiSelectAdapter(options) {
|
|
|
407
421
|
helperText,
|
|
408
422
|
value,
|
|
409
423
|
onChange,
|
|
424
|
+
onKeyDown,
|
|
410
425
|
options: selectOptions
|
|
411
426
|
}) {
|
|
412
427
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
@@ -434,7 +449,9 @@ function createMuiSelectAdapter(options) {
|
|
|
434
449
|
name,
|
|
435
450
|
label,
|
|
436
451
|
value,
|
|
452
|
+
disabled,
|
|
437
453
|
onChange: handleChange,
|
|
454
|
+
onKeyDown,
|
|
438
455
|
required,
|
|
439
456
|
readOnly,
|
|
440
457
|
inputProps: {
|
|
@@ -532,6 +549,7 @@ function createMuiTextInputAdapter(options) {
|
|
|
532
549
|
helperText,
|
|
533
550
|
value,
|
|
534
551
|
onChange,
|
|
552
|
+
onKeyDown,
|
|
535
553
|
placeholder,
|
|
536
554
|
maxLength,
|
|
537
555
|
inputMode,
|
|
@@ -573,7 +591,8 @@ function createMuiTextInputAdapter(options) {
|
|
|
573
591
|
fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
|
|
574
592
|
size: resolved.size,
|
|
575
593
|
variant: resolved.variant,
|
|
576
|
-
onChange: (event) => onChange(event.currentTarget.value)
|
|
594
|
+
onChange: (event) => onChange(event.currentTarget.value),
|
|
595
|
+
onKeyDown
|
|
577
596
|
}
|
|
578
597
|
);
|
|
579
598
|
};
|
|
@@ -1090,6 +1109,17 @@ var import_material13 = require("@mui/material");
|
|
|
1090
1109
|
var import_react2 = require("react");
|
|
1091
1110
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1092
1111
|
var DEFAULT_EMPTY_STATE_MESSAGE = "No translation locales have been added yet. Select a language from the dropdown above to add one.";
|
|
1112
|
+
function normalizeLocaleOptions(options, getLocaleLabel) {
|
|
1113
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1114
|
+
const normalized = [];
|
|
1115
|
+
for (const item of options) {
|
|
1116
|
+
const value = typeof item === "string" ? item : item.value;
|
|
1117
|
+
if (value.length === 0 || seen.has(value)) continue;
|
|
1118
|
+
seen.add(value);
|
|
1119
|
+
normalized.push({ value, label: typeof item === "string" ? getLocaleLabel?.(value) ?? value : item.label });
|
|
1120
|
+
}
|
|
1121
|
+
return normalized;
|
|
1122
|
+
}
|
|
1093
1123
|
function createMuiLocalizationSlot(options) {
|
|
1094
1124
|
return function MuiLocalization({
|
|
1095
1125
|
schema,
|
|
@@ -1108,6 +1138,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1108
1138
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
1109
1139
|
const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
|
|
1110
1140
|
const [newLocale, setNewLocale] = (0, import_react2.useState)("");
|
|
1141
|
+
const [pendingFocusLocale, setPendingFocusLocale] = (0, import_react2.useState)(null);
|
|
1111
1142
|
const locales = Array.from(
|
|
1112
1143
|
new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
|
|
1113
1144
|
);
|
|
@@ -1116,21 +1147,44 @@ function createMuiLocalizationSlot(options) {
|
|
|
1116
1147
|
...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
|
|
1117
1148
|
...schema.supportedLocales ?? []
|
|
1118
1149
|
]);
|
|
1119
|
-
const
|
|
1150
|
+
const localizationOptions = resolved.localizationOptions ?? {};
|
|
1151
|
+
const availableLocaleSource = localizationOptions.availableLocales;
|
|
1152
|
+
const availableLocaleOptions = availableLocaleSource === void 0 ? policy?.allowedLocales?.map((value) => ({
|
|
1153
|
+
value,
|
|
1154
|
+
label: resolved.getLocaleLabel?.(value) ?? value
|
|
1155
|
+
})) : normalizeLocaleOptions(availableLocaleSource, resolved.getLocaleLabel);
|
|
1156
|
+
const filteredAvailableLocales = availableLocaleOptions?.filter(
|
|
1157
|
+
(locale) => !registeredLocales.has(locale.value) && (policy?.allowedLocales === void 0 || policy.allowedLocales.includes(locale.value))
|
|
1158
|
+
);
|
|
1159
|
+
const hasLocaleSelector = filteredAvailableLocales !== void 0;
|
|
1120
1160
|
const localeLimitReached = policy?.maxLocales !== void 0 && registeredLocales.size >= policy.maxLocales;
|
|
1121
1161
|
const normalizedLocale = newLocale.trim();
|
|
1162
|
+
const selectedLocaleAvailable = !hasLocaleSelector || filteredAvailableLocales.some((locale) => locale.value === normalizedLocale);
|
|
1122
1163
|
const localeAllowed = policy?.allowedLocales === void 0 || policy.allowedLocales.includes(normalizedLocale);
|
|
1123
|
-
const canAddLocale = !readOnly && normalizedLocale.length > 0 && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
|
|
1164
|
+
const canAddLocale = !readOnly && normalizedLocale.length > 0 && selectedLocaleAvailable && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
|
|
1124
1165
|
const handleTabChange = (_event, value) => onCurrentLocaleChange(value);
|
|
1125
1166
|
const addLocale = () => {
|
|
1126
1167
|
if (!canAddLocale) return;
|
|
1127
1168
|
const result = actions.addLocale(normalizedLocale);
|
|
1128
1169
|
if (!result.success) return;
|
|
1129
1170
|
onCurrentLocaleChange(normalizedLocale);
|
|
1171
|
+
if (localizationOptions.autoFocusNewTab ?? true) setPendingFocusLocale(normalizedLocale);
|
|
1130
1172
|
setNewLocale("");
|
|
1131
1173
|
};
|
|
1174
|
+
const handleAddKeyDown = (event) => {
|
|
1175
|
+
if (event.key !== "Enter" || !canAddLocale) return;
|
|
1176
|
+
event.preventDefault();
|
|
1177
|
+
event.stopPropagation();
|
|
1178
|
+
addLocale();
|
|
1179
|
+
};
|
|
1180
|
+
(0, import_react2.useEffect)(() => {
|
|
1181
|
+
if (pendingFocusLocale === null || currentLocale !== pendingFocusLocale) return;
|
|
1182
|
+
const tab = document.getElementById(`mui-builder-locale-tab-${pendingFocusLocale}`);
|
|
1183
|
+
if (tab === null) return;
|
|
1184
|
+
tab.focus();
|
|
1185
|
+
setPendingFocusLocale(null);
|
|
1186
|
+
}, [currentLocale, pendingFocusLocale]);
|
|
1132
1187
|
const stackProps = resolved.muiSlotProps?.stack;
|
|
1133
|
-
const localizationOptions = resolved.localizationOptions ?? {};
|
|
1134
1188
|
const collapsible = localizationOptions.collapsible ?? false;
|
|
1135
1189
|
const defaultLocaleControl = localizationOptions.defaultLocaleControl ?? "editable";
|
|
1136
1190
|
const configuredTranslationLocales = locales.filter((locale) => locale !== schema.defaultLocale);
|
|
@@ -1138,24 +1192,35 @@ function createMuiLocalizationSlot(options) {
|
|
|
1138
1192
|
...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
|
|
1139
1193
|
...configuredTranslationLocales
|
|
1140
1194
|
];
|
|
1141
|
-
const
|
|
1195
|
+
const legacySummaryLabel = configuredTranslationLocales.length === 0 ? "Translations not configured" : `${configuredLocales.length} ${configuredLocales.length === 1 ? "language" : "languages"} configured: ${configuredLocales.map(
|
|
1142
1196
|
(locale) => locale === schema.defaultLocale ? `${resolved.getLocaleLabel?.(locale) ?? locale} (default)` : resolved.getLocaleLabel?.(locale) ?? locale
|
|
1143
1197
|
).join(", ")}`;
|
|
1144
1198
|
const emptyStateMessage = localizationOptions.emptyStateMessage === void 0 ? DEFAULT_EMPTY_STATE_MESSAGE : translate(localizationOptions.emptyStateMessage);
|
|
1199
|
+
const summaryContext = {
|
|
1200
|
+
defaultLocale: schema.defaultLocale ?? "",
|
|
1201
|
+
supportedLocales: schema.supportedLocales ?? [],
|
|
1202
|
+
totalLocales: registeredLocales.size
|
|
1203
|
+
};
|
|
1204
|
+
const summary = localizationOptions.renderSummary === void 0 ? localizationOptions.showSummary ? configuredTranslationLocales.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Alert, { severity: "success", sx: { mb: 2 }, children: translate("builder.localization.localesConfiguredSummary", {
|
|
1205
|
+
count: schema.supportedLocales?.length ?? 0
|
|
1206
|
+
}) }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Alert, { severity: "info", sx: { mb: 2 }, children: translate("builder.localization.noLocalesConfigured") }) : null : localizationOptions.renderSummary(summaryContext);
|
|
1145
1207
|
const title = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { alignItems: "center", direction: "row", spacing: 1, children: [
|
|
1146
1208
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }),
|
|
1147
|
-
localizationOptions.showSummary ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1209
|
+
localizationOptions.renderSummary === void 0 && localizationOptions.showSummary && configuredTranslationLocales.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1148
1210
|
import_material13.Chip,
|
|
1149
1211
|
{
|
|
1150
|
-
label:
|
|
1212
|
+
label: legacySummaryLabel,
|
|
1151
1213
|
size: "small",
|
|
1152
1214
|
color: configuredTranslationLocales.length > 0 ? "primary" : "default",
|
|
1153
1215
|
variant: "outlined"
|
|
1154
1216
|
}
|
|
1155
1217
|
) : null
|
|
1156
1218
|
] });
|
|
1219
|
+
const noCandidateLocales = hasLocaleSelector && filteredAvailableLocales.length === 0;
|
|
1220
|
+
const candidateHelperText = localeLimitReached ? void 0 : noCandidateLocales ? translate("builder.localization.allLocalesAdded") : void 0;
|
|
1157
1221
|
const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material13.Stack, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
|
|
1158
1222
|
!collapsible ? title : null,
|
|
1223
|
+
summary,
|
|
1159
1224
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1160
1225
|
import_material13.Stack,
|
|
1161
1226
|
{
|
|
@@ -1187,36 +1252,52 @@ function createMuiLocalizationSlot(options) {
|
|
|
1187
1252
|
}
|
|
1188
1253
|
}
|
|
1189
1254
|
) }),
|
|
1190
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } },
|
|
1191
|
-
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Box, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } }, onKeyDownCapture: handleAddKeyDown, children: hasLocaleSelector ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1256
|
+
Select2,
|
|
1192
1257
|
{
|
|
1193
1258
|
id: "mui-builder-new-locale",
|
|
1194
|
-
label: translate("builder.
|
|
1259
|
+
label: translate("builder.localization.selectLocaleToAdd"),
|
|
1195
1260
|
value: newLocale,
|
|
1196
|
-
|
|
1261
|
+
options: filteredAvailableLocales.map((locale) => ({ value: locale.value, label: locale.label })),
|
|
1262
|
+
...candidateHelperText === void 0 ? {} : { helperText: candidateHelperText },
|
|
1263
|
+
disabled: readOnly || localeLimitReached || noCandidateLocales,
|
|
1197
1264
|
onChange: setNewLocale
|
|
1198
1265
|
}
|
|
1199
1266
|
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1200
|
-
|
|
1267
|
+
TextInput,
|
|
1201
1268
|
{
|
|
1202
1269
|
id: "mui-builder-new-locale",
|
|
1203
1270
|
label: translate("builder.addLocale"),
|
|
1204
1271
|
value: newLocale,
|
|
1205
|
-
|
|
1206
|
-
{ value: "", label: "\u2014" },
|
|
1207
|
-
...availableAllowedLocales.map((locale) => ({
|
|
1208
|
-
value: locale,
|
|
1209
|
-
label: resolved.getLocaleLabel?.(locale) ?? locale
|
|
1210
|
-
}))
|
|
1211
|
-
],
|
|
1212
|
-
disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
|
|
1272
|
+
disabled: readOnly || localeLimitReached,
|
|
1213
1273
|
onChange: setNewLocale
|
|
1214
1274
|
}
|
|
1215
1275
|
) }),
|
|
1216
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1276
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1277
|
+
import_material13.Box,
|
|
1278
|
+
{
|
|
1279
|
+
sx: {
|
|
1280
|
+
flexShrink: 0,
|
|
1281
|
+
minWidth: "max-content",
|
|
1282
|
+
...localizationOptions.noWrapActions ?? true ? { whiteSpace: "nowrap" } : {}
|
|
1283
|
+
},
|
|
1284
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1285
|
+
Button2,
|
|
1286
|
+
{
|
|
1287
|
+
variant: "primary",
|
|
1288
|
+
action: "addLocale",
|
|
1289
|
+
noWrap: localizationOptions.noWrapActions ?? true,
|
|
1290
|
+
disabled: !canAddLocale,
|
|
1291
|
+
onClick: addLocale,
|
|
1292
|
+
children: translate("builder.addLocale")
|
|
1293
|
+
}
|
|
1294
|
+
)
|
|
1295
|
+
}
|
|
1296
|
+
)
|
|
1217
1297
|
]
|
|
1218
1298
|
}
|
|
1219
1299
|
),
|
|
1300
|
+
localeLimitReached ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material13.Typography, { variant: "body2", color: "text.secondary", children: translate("builder.localization.maxLocalesReached", { max: policy?.maxLocales ?? 0 }) }) : null,
|
|
1220
1301
|
locales.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1221
1302
|
import_material13.Tabs,
|
|
1222
1303
|
{
|
|
@@ -1228,6 +1309,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1228
1309
|
children: locales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1229
1310
|
import_material13.Tab,
|
|
1230
1311
|
{
|
|
1312
|
+
id: `mui-builder-locale-tab-${locale}`,
|
|
1231
1313
|
value: locale,
|
|
1232
1314
|
label: resolved.getLocaleLabel?.(locale) ?? locale,
|
|
1233
1315
|
disabled: readOnly && locale !== currentLocale,
|
|
@@ -1241,6 +1323,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1241
1323
|
Button2,
|
|
1242
1324
|
{
|
|
1243
1325
|
variant: "secondary",
|
|
1326
|
+
noWrap: localizationOptions.noWrapActions ?? true,
|
|
1244
1327
|
disabled: readOnly || !editingLocaleConfigured || isTranslating,
|
|
1245
1328
|
onClick: onAutoTranslate,
|
|
1246
1329
|
children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
|
|
@@ -1359,7 +1442,8 @@ function MuiFormBuilder({
|
|
|
1359
1442
|
const contextValue = (0, import_react4.useMemo)(() => ({ options: contextOptions }), [contextOptions]);
|
|
1360
1443
|
const components = (0, import_react4.useMemo)(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
|
|
1361
1444
|
const slots = (0, import_react4.useMemo)(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
|
|
1362
|
-
const
|
|
1445
|
+
const placement = contextOptions.localizationOptions?.placement;
|
|
1446
|
+
const resolvedSectionOrder = sectionOrder ?? (placement === void 0 ? contextOptions.layoutOptions?.sectionOrder : MUI_LOCALIZATION_SECTION_ORDERS[placement]);
|
|
1363
1447
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1364
1448
|
import_react3.FormBuilder,
|
|
1365
1449
|
{
|
|
@@ -1374,6 +1458,7 @@ function MuiFormBuilder({
|
|
|
1374
1458
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1375
1459
|
0 && (module.exports = {
|
|
1376
1460
|
DEFAULT_MUI_SECTION_ORDER,
|
|
1461
|
+
MUI_LOCALIZATION_SECTION_ORDERS,
|
|
1377
1462
|
MuiButtonAdapter,
|
|
1378
1463
|
MuiCheckboxAdapter,
|
|
1379
1464
|
MuiErrorMessageAdapter,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
import { BuilderActionIconType, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps, BuilderFieldEditorSlotProps, BuilderLocalizationSlotProps, BuilderOptionEditorSlotProps, BuilderToolbarSlotProps } from '@form-engine-ts/react';
|
|
1
|
+
import { BuilderActionIconType, 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
|
-
import {
|
|
3
|
+
import { ReactNode, ComponentType } from 'react';
|
|
4
4
|
import { CardProps, PaperProps, StackProps, AccordionProps } from '@mui/material';
|
|
5
5
|
|
|
6
6
|
type BuilderSectionName = "basicSettings" | "completionMessage" | "questions" | "addQuestion" | "localization";
|
|
7
7
|
type MuiButtonVariant = "contained" | "outlined" | "text";
|
|
8
|
+
interface LocaleOptionItem {
|
|
9
|
+
readonly value: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}
|
|
12
|
+
type LocalizationSectionPlacement = "top" | "beforeQuestions" | "afterQuestions" | "bottom";
|
|
8
13
|
interface MuiLayoutOptions {
|
|
9
14
|
readonly sectionOrder?: readonly BuilderSectionName[];
|
|
10
15
|
}
|
|
11
16
|
interface MuiLocalizationOptions {
|
|
17
|
+
readonly availableLocales?: readonly (LocaleOptionItem | string)[];
|
|
18
|
+
readonly placement?: LocalizationSectionPlacement;
|
|
12
19
|
readonly collapsible?: boolean;
|
|
13
20
|
readonly defaultExpanded?: boolean | "when-configured" | "always";
|
|
14
21
|
readonly showSummary?: boolean;
|
|
22
|
+
readonly renderSummary?: (context: LocalizationSummaryContext) => ReactNode;
|
|
15
23
|
readonly emptyStateMessage?: string;
|
|
16
24
|
readonly defaultLocaleControl?: "editable" | "readOnly" | "hidden";
|
|
25
|
+
readonly noWrapActions?: boolean;
|
|
26
|
+
readonly autoFocusNewTab?: boolean;
|
|
17
27
|
}
|
|
18
28
|
interface MuiFieldEditorOptions {
|
|
19
29
|
readonly description?: "editable" | "readOnly" | "hidden";
|
|
@@ -65,6 +75,7 @@ interface ResolvedMuiAdapterOptions {
|
|
|
65
75
|
readonly muiSlotProps?: MuiBuilderSlotProps;
|
|
66
76
|
}
|
|
67
77
|
declare const DEFAULT_MUI_SECTION_ORDER: readonly BuilderSectionName[];
|
|
78
|
+
declare const MUI_LOCALIZATION_SECTION_ORDERS: Readonly<Record<LocalizationSectionPlacement, readonly BuilderSectionName[]>>;
|
|
68
79
|
declare function resolveMuiAdapterOptions(options?: MuiAdapterOptions): ResolvedMuiAdapterOptions;
|
|
69
80
|
|
|
70
81
|
declare function createMuiButtonAdapter(options?: MuiAdapterOptions): ComponentType<BuilderButtonProps>;
|
|
@@ -138,4 +149,4 @@ declare const MuiToolbarSlot: NonNullable<FormBuilderSlots["toolbar"]>;
|
|
|
138
149
|
declare const muiBuilderSlots: FormBuilderSlots;
|
|
139
150
|
declare function createMuiBuilderSlots(options?: MuiAdapterOptions, customOverrides?: Partial<FormBuilderSlots>): FormBuilderSlots;
|
|
140
151
|
|
|
141
|
-
export { type BuilderSectionName, DEFAULT_MUI_SECTION_ORDER, type MuiAdapterOptions, type MuiBuilderOverrides, type MuiBuilderSlotProps, MuiButtonAdapter, type MuiButtonVariant, MuiCheckboxAdapter, MuiErrorMessageAdapter, type MuiFieldEditorOptions, MuiFieldEditorSlot, MuiFieldsetAdapter, MuiFormBuilder, MuiFormBuilderContext, type MuiFormBuilderContextValue, type MuiFormBuilderProps, MuiIconButtonAdapter, type MuiLayoutOptions, type MuiLocalizationOptions, MuiLocalizationSlot, MuiOptionEditorSlot, MuiSectionAdapter, MuiSelectAdapter, MuiTextAreaAdapter, MuiTextInputAdapter, MuiToolbarSlot, type ResolvedMuiAdapterOptions, createMuiBuilderComponents, createMuiBuilderProps, createMuiBuilderSlots, createMuiButtonAdapter, createMuiCheckboxAdapter, createMuiErrorMessageAdapter, createMuiFieldEditorSlot, createMuiFieldsetAdapter, createMuiIconButtonAdapter, createMuiLocalizationSlot, createMuiOptionEditorSlot, createMuiSectionAdapter, createMuiSelectAdapter, createMuiTextAreaAdapter, createMuiTextInputAdapter, createMuiToolbarSlot, mergeMuiAdapterOptions, muiBuilderComponents, muiBuilderSlots, muiDefaultIconResolver, resolveMuiAdapterOptions, useResolvedMuiAdapterOptions };
|
|
152
|
+
export { type BuilderSectionName, DEFAULT_MUI_SECTION_ORDER, type LocaleOptionItem, type LocalizationSectionPlacement, MUI_LOCALIZATION_SECTION_ORDERS, type MuiAdapterOptions, type MuiBuilderOverrides, type MuiBuilderSlotProps, MuiButtonAdapter, type MuiButtonVariant, MuiCheckboxAdapter, MuiErrorMessageAdapter, type MuiFieldEditorOptions, MuiFieldEditorSlot, MuiFieldsetAdapter, MuiFormBuilder, MuiFormBuilderContext, type MuiFormBuilderContextValue, type MuiFormBuilderProps, MuiIconButtonAdapter, type MuiLayoutOptions, type MuiLocalizationOptions, MuiLocalizationSlot, MuiOptionEditorSlot, MuiSectionAdapter, MuiSelectAdapter, MuiTextAreaAdapter, MuiTextInputAdapter, MuiToolbarSlot, type ResolvedMuiAdapterOptions, createMuiBuilderComponents, createMuiBuilderProps, createMuiBuilderSlots, createMuiButtonAdapter, createMuiCheckboxAdapter, createMuiErrorMessageAdapter, createMuiFieldEditorSlot, createMuiFieldsetAdapter, createMuiIconButtonAdapter, createMuiLocalizationSlot, createMuiOptionEditorSlot, createMuiSectionAdapter, createMuiSelectAdapter, createMuiTextAreaAdapter, createMuiTextInputAdapter, createMuiToolbarSlot, mergeMuiAdapterOptions, muiBuilderComponents, muiBuilderSlots, muiDefaultIconResolver, resolveMuiAdapterOptions, useResolvedMuiAdapterOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
import { BuilderActionIconType, BuilderButtonProps, BuilderCheckboxProps, BuilderErrorMessageProps, BuilderFieldsetProps, BuilderIconButtonProps, BuilderSectionProps, BuilderSelectProps, BuilderTextAreaProps, BuilderTextInputProps, FormBuilderComponents, FormBuilderSlots, FormBuilderProps, BuilderFieldEditorSlotProps, BuilderLocalizationSlotProps, BuilderOptionEditorSlotProps, BuilderToolbarSlotProps } from '@form-engine-ts/react';
|
|
1
|
+
import { BuilderActionIconType, 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
|
-
import {
|
|
3
|
+
import { ReactNode, ComponentType } from 'react';
|
|
4
4
|
import { CardProps, PaperProps, StackProps, AccordionProps } from '@mui/material';
|
|
5
5
|
|
|
6
6
|
type BuilderSectionName = "basicSettings" | "completionMessage" | "questions" | "addQuestion" | "localization";
|
|
7
7
|
type MuiButtonVariant = "contained" | "outlined" | "text";
|
|
8
|
+
interface LocaleOptionItem {
|
|
9
|
+
readonly value: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}
|
|
12
|
+
type LocalizationSectionPlacement = "top" | "beforeQuestions" | "afterQuestions" | "bottom";
|
|
8
13
|
interface MuiLayoutOptions {
|
|
9
14
|
readonly sectionOrder?: readonly BuilderSectionName[];
|
|
10
15
|
}
|
|
11
16
|
interface MuiLocalizationOptions {
|
|
17
|
+
readonly availableLocales?: readonly (LocaleOptionItem | string)[];
|
|
18
|
+
readonly placement?: LocalizationSectionPlacement;
|
|
12
19
|
readonly collapsible?: boolean;
|
|
13
20
|
readonly defaultExpanded?: boolean | "when-configured" | "always";
|
|
14
21
|
readonly showSummary?: boolean;
|
|
22
|
+
readonly renderSummary?: (context: LocalizationSummaryContext) => ReactNode;
|
|
15
23
|
readonly emptyStateMessage?: string;
|
|
16
24
|
readonly defaultLocaleControl?: "editable" | "readOnly" | "hidden";
|
|
25
|
+
readonly noWrapActions?: boolean;
|
|
26
|
+
readonly autoFocusNewTab?: boolean;
|
|
17
27
|
}
|
|
18
28
|
interface MuiFieldEditorOptions {
|
|
19
29
|
readonly description?: "editable" | "readOnly" | "hidden";
|
|
@@ -65,6 +75,7 @@ interface ResolvedMuiAdapterOptions {
|
|
|
65
75
|
readonly muiSlotProps?: MuiBuilderSlotProps;
|
|
66
76
|
}
|
|
67
77
|
declare const DEFAULT_MUI_SECTION_ORDER: readonly BuilderSectionName[];
|
|
78
|
+
declare const MUI_LOCALIZATION_SECTION_ORDERS: Readonly<Record<LocalizationSectionPlacement, readonly BuilderSectionName[]>>;
|
|
68
79
|
declare function resolveMuiAdapterOptions(options?: MuiAdapterOptions): ResolvedMuiAdapterOptions;
|
|
69
80
|
|
|
70
81
|
declare function createMuiButtonAdapter(options?: MuiAdapterOptions): ComponentType<BuilderButtonProps>;
|
|
@@ -138,4 +149,4 @@ declare const MuiToolbarSlot: NonNullable<FormBuilderSlots["toolbar"]>;
|
|
|
138
149
|
declare const muiBuilderSlots: FormBuilderSlots;
|
|
139
150
|
declare function createMuiBuilderSlots(options?: MuiAdapterOptions, customOverrides?: Partial<FormBuilderSlots>): FormBuilderSlots;
|
|
140
151
|
|
|
141
|
-
export { type BuilderSectionName, DEFAULT_MUI_SECTION_ORDER, type MuiAdapterOptions, type MuiBuilderOverrides, type MuiBuilderSlotProps, MuiButtonAdapter, type MuiButtonVariant, MuiCheckboxAdapter, MuiErrorMessageAdapter, type MuiFieldEditorOptions, MuiFieldEditorSlot, MuiFieldsetAdapter, MuiFormBuilder, MuiFormBuilderContext, type MuiFormBuilderContextValue, type MuiFormBuilderProps, MuiIconButtonAdapter, type MuiLayoutOptions, type MuiLocalizationOptions, MuiLocalizationSlot, MuiOptionEditorSlot, MuiSectionAdapter, MuiSelectAdapter, MuiTextAreaAdapter, MuiTextInputAdapter, MuiToolbarSlot, type ResolvedMuiAdapterOptions, createMuiBuilderComponents, createMuiBuilderProps, createMuiBuilderSlots, createMuiButtonAdapter, createMuiCheckboxAdapter, createMuiErrorMessageAdapter, createMuiFieldEditorSlot, createMuiFieldsetAdapter, createMuiIconButtonAdapter, createMuiLocalizationSlot, createMuiOptionEditorSlot, createMuiSectionAdapter, createMuiSelectAdapter, createMuiTextAreaAdapter, createMuiTextInputAdapter, createMuiToolbarSlot, mergeMuiAdapterOptions, muiBuilderComponents, muiBuilderSlots, muiDefaultIconResolver, resolveMuiAdapterOptions, useResolvedMuiAdapterOptions };
|
|
152
|
+
export { type BuilderSectionName, DEFAULT_MUI_SECTION_ORDER, type LocaleOptionItem, type LocalizationSectionPlacement, MUI_LOCALIZATION_SECTION_ORDERS, type MuiAdapterOptions, type MuiBuilderOverrides, type MuiBuilderSlotProps, MuiButtonAdapter, type MuiButtonVariant, MuiCheckboxAdapter, MuiErrorMessageAdapter, type MuiFieldEditorOptions, MuiFieldEditorSlot, MuiFieldsetAdapter, MuiFormBuilder, MuiFormBuilderContext, type MuiFormBuilderContextValue, type MuiFormBuilderProps, MuiIconButtonAdapter, type MuiLayoutOptions, type MuiLocalizationOptions, MuiLocalizationSlot, MuiOptionEditorSlot, MuiSectionAdapter, MuiSelectAdapter, MuiTextAreaAdapter, MuiTextInputAdapter, MuiToolbarSlot, type ResolvedMuiAdapterOptions, createMuiBuilderComponents, createMuiBuilderProps, createMuiBuilderSlots, createMuiButtonAdapter, createMuiCheckboxAdapter, createMuiErrorMessageAdapter, createMuiFieldEditorSlot, createMuiFieldsetAdapter, createMuiIconButtonAdapter, createMuiLocalizationSlot, createMuiOptionEditorSlot, createMuiSectionAdapter, createMuiSelectAdapter, createMuiTextAreaAdapter, createMuiTextInputAdapter, createMuiToolbarSlot, mergeMuiAdapterOptions, muiBuilderComponents, muiBuilderSlots, muiDefaultIconResolver, resolveMuiAdapterOptions, useResolvedMuiAdapterOptions };
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,15 @@ var DEFAULT_MUI_SECTION_ORDER = [
|
|
|
9
9
|
"basicSettings",
|
|
10
10
|
"questions",
|
|
11
11
|
"addQuestion",
|
|
12
|
-
"localization"
|
|
12
|
+
"localization",
|
|
13
|
+
"completionMessage"
|
|
13
14
|
];
|
|
15
|
+
var MUI_LOCALIZATION_SECTION_ORDERS = {
|
|
16
|
+
top: ["localization", "basicSettings", "completionMessage", "questions", "addQuestion"],
|
|
17
|
+
beforeQuestions: ["basicSettings", "localization", "completionMessage", "questions", "addQuestion"],
|
|
18
|
+
afterQuestions: ["basicSettings", "questions", "addQuestion", "localization", "completionMessage"],
|
|
19
|
+
bottom: ["basicSettings", "completionMessage", "questions", "addQuestion", "localization"]
|
|
20
|
+
};
|
|
14
21
|
function resolveMuiAdapterOptions(options = {}) {
|
|
15
22
|
const buttonVariant = options.buttonVariant ?? "contained";
|
|
16
23
|
return {
|
|
@@ -36,8 +43,13 @@ function resolveMuiAdapterOptions(options = {}) {
|
|
|
36
43
|
collapsible: options.localizationOptions?.collapsible ?? false,
|
|
37
44
|
defaultExpanded: options.localizationOptions?.defaultExpanded ?? false,
|
|
38
45
|
showSummary: options.localizationOptions?.showSummary ?? false,
|
|
46
|
+
...options.localizationOptions?.availableLocales === void 0 ? {} : { availableLocales: options.localizationOptions.availableLocales },
|
|
47
|
+
...options.localizationOptions?.placement === void 0 ? {} : { placement: options.localizationOptions.placement },
|
|
48
|
+
...options.localizationOptions?.renderSummary === void 0 ? {} : { renderSummary: options.localizationOptions.renderSummary },
|
|
39
49
|
...options.localizationOptions?.emptyStateMessage === void 0 ? {} : { emptyStateMessage: options.localizationOptions.emptyStateMessage },
|
|
40
|
-
defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable"
|
|
50
|
+
defaultLocaleControl: options.localizationOptions?.defaultLocaleControl ?? "editable",
|
|
51
|
+
noWrapActions: options.localizationOptions?.noWrapActions ?? true,
|
|
52
|
+
autoFocusNewTab: options.localizationOptions?.autoFocusNewTab ?? true
|
|
41
53
|
},
|
|
42
54
|
muiSlotProps: options.muiSlotProps ?? {}
|
|
43
55
|
};
|
|
@@ -75,6 +87,7 @@ function createMuiButtonAdapter(options) {
|
|
|
75
87
|
"aria-describedby": ariaDescribedBy,
|
|
76
88
|
"aria-labelledby": ariaLabelledBy,
|
|
77
89
|
onClick,
|
|
90
|
+
noWrap,
|
|
78
91
|
children,
|
|
79
92
|
title,
|
|
80
93
|
variant,
|
|
@@ -100,7 +113,7 @@ function createMuiButtonAdapter(options) {
|
|
|
100
113
|
color: variant === "danger" ? "error" : "primary",
|
|
101
114
|
variant: resolved.buttonVariants?.[variant ?? "primary"] ?? resolved.buttonVariant,
|
|
102
115
|
fullWidth: resolved.buttonFullWidth ?? false,
|
|
103
|
-
sx: { whiteSpace: "nowrap" },
|
|
116
|
+
sx: { whiteSpace: noWrap === false ? "normal" : "nowrap" },
|
|
104
117
|
children
|
|
105
118
|
}
|
|
106
119
|
);
|
|
@@ -344,6 +357,7 @@ function createMuiSelectAdapter(options) {
|
|
|
344
357
|
helperText,
|
|
345
358
|
value,
|
|
346
359
|
onChange,
|
|
360
|
+
onKeyDown,
|
|
347
361
|
options: selectOptions
|
|
348
362
|
}) {
|
|
349
363
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
@@ -371,7 +385,9 @@ function createMuiSelectAdapter(options) {
|
|
|
371
385
|
name,
|
|
372
386
|
label,
|
|
373
387
|
value,
|
|
388
|
+
disabled,
|
|
374
389
|
onChange: handleChange,
|
|
390
|
+
onKeyDown,
|
|
375
391
|
required,
|
|
376
392
|
readOnly,
|
|
377
393
|
inputProps: {
|
|
@@ -469,6 +485,7 @@ function createMuiTextInputAdapter(options) {
|
|
|
469
485
|
helperText,
|
|
470
486
|
value,
|
|
471
487
|
onChange,
|
|
488
|
+
onKeyDown,
|
|
472
489
|
placeholder,
|
|
473
490
|
maxLength,
|
|
474
491
|
inputMode,
|
|
@@ -510,7 +527,8 @@ function createMuiTextInputAdapter(options) {
|
|
|
510
527
|
fullWidth: resolved.inputFullWidth ?? resolved.fullWidth,
|
|
511
528
|
size: resolved.size,
|
|
512
529
|
variant: resolved.variant,
|
|
513
|
-
onChange: (event) => onChange(event.currentTarget.value)
|
|
530
|
+
onChange: (event) => onChange(event.currentTarget.value),
|
|
531
|
+
onKeyDown
|
|
514
532
|
}
|
|
515
533
|
);
|
|
516
534
|
};
|
|
@@ -1033,10 +1051,32 @@ var MuiFieldEditorSlot = createMuiFieldEditorSlot();
|
|
|
1033
1051
|
|
|
1034
1052
|
// src/slots/Localization.tsx
|
|
1035
1053
|
import { ExpandMore } from "@mui/icons-material";
|
|
1036
|
-
import {
|
|
1037
|
-
|
|
1054
|
+
import {
|
|
1055
|
+
Accordion,
|
|
1056
|
+
AccordionDetails,
|
|
1057
|
+
AccordionSummary,
|
|
1058
|
+
Alert as Alert2,
|
|
1059
|
+
Box as Box2,
|
|
1060
|
+
Chip,
|
|
1061
|
+
Stack as Stack4,
|
|
1062
|
+
Tab,
|
|
1063
|
+
Tabs,
|
|
1064
|
+
Typography as Typography4
|
|
1065
|
+
} from "@mui/material";
|
|
1066
|
+
import { useEffect, useState } from "react";
|
|
1038
1067
|
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1039
1068
|
var DEFAULT_EMPTY_STATE_MESSAGE = "No translation locales have been added yet. Select a language from the dropdown above to add one.";
|
|
1069
|
+
function normalizeLocaleOptions(options, getLocaleLabel) {
|
|
1070
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1071
|
+
const normalized = [];
|
|
1072
|
+
for (const item of options) {
|
|
1073
|
+
const value = typeof item === "string" ? item : item.value;
|
|
1074
|
+
if (value.length === 0 || seen.has(value)) continue;
|
|
1075
|
+
seen.add(value);
|
|
1076
|
+
normalized.push({ value, label: typeof item === "string" ? getLocaleLabel?.(value) ?? value : item.label });
|
|
1077
|
+
}
|
|
1078
|
+
return normalized;
|
|
1079
|
+
}
|
|
1040
1080
|
function createMuiLocalizationSlot(options) {
|
|
1041
1081
|
return function MuiLocalization({
|
|
1042
1082
|
schema,
|
|
@@ -1055,6 +1095,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1055
1095
|
const resolved = useResolvedMuiAdapterOptions(options);
|
|
1056
1096
|
const { Button: Button2, ErrorMessage, Select: Select2, TextArea, TextInput } = components;
|
|
1057
1097
|
const [newLocale, setNewLocale] = useState("");
|
|
1098
|
+
const [pendingFocusLocale, setPendingFocusLocale] = useState(null);
|
|
1058
1099
|
const locales = Array.from(
|
|
1059
1100
|
new Set((schema.supportedLocales ?? []).filter((locale) => locale !== schema.defaultLocale))
|
|
1060
1101
|
);
|
|
@@ -1063,21 +1104,44 @@ function createMuiLocalizationSlot(options) {
|
|
|
1063
1104
|
...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
|
|
1064
1105
|
...schema.supportedLocales ?? []
|
|
1065
1106
|
]);
|
|
1066
|
-
const
|
|
1107
|
+
const localizationOptions = resolved.localizationOptions ?? {};
|
|
1108
|
+
const availableLocaleSource = localizationOptions.availableLocales;
|
|
1109
|
+
const availableLocaleOptions = availableLocaleSource === void 0 ? policy?.allowedLocales?.map((value) => ({
|
|
1110
|
+
value,
|
|
1111
|
+
label: resolved.getLocaleLabel?.(value) ?? value
|
|
1112
|
+
})) : normalizeLocaleOptions(availableLocaleSource, resolved.getLocaleLabel);
|
|
1113
|
+
const filteredAvailableLocales = availableLocaleOptions?.filter(
|
|
1114
|
+
(locale) => !registeredLocales.has(locale.value) && (policy?.allowedLocales === void 0 || policy.allowedLocales.includes(locale.value))
|
|
1115
|
+
);
|
|
1116
|
+
const hasLocaleSelector = filteredAvailableLocales !== void 0;
|
|
1067
1117
|
const localeLimitReached = policy?.maxLocales !== void 0 && registeredLocales.size >= policy.maxLocales;
|
|
1068
1118
|
const normalizedLocale = newLocale.trim();
|
|
1119
|
+
const selectedLocaleAvailable = !hasLocaleSelector || filteredAvailableLocales.some((locale) => locale.value === normalizedLocale);
|
|
1069
1120
|
const localeAllowed = policy?.allowedLocales === void 0 || policy.allowedLocales.includes(normalizedLocale);
|
|
1070
|
-
const canAddLocale = !readOnly && normalizedLocale.length > 0 && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
|
|
1121
|
+
const canAddLocale = !readOnly && normalizedLocale.length > 0 && selectedLocaleAvailable && localeAllowed && !registeredLocales.has(normalizedLocale) && !localeLimitReached;
|
|
1071
1122
|
const handleTabChange = (_event, value) => onCurrentLocaleChange(value);
|
|
1072
1123
|
const addLocale = () => {
|
|
1073
1124
|
if (!canAddLocale) return;
|
|
1074
1125
|
const result = actions.addLocale(normalizedLocale);
|
|
1075
1126
|
if (!result.success) return;
|
|
1076
1127
|
onCurrentLocaleChange(normalizedLocale);
|
|
1128
|
+
if (localizationOptions.autoFocusNewTab ?? true) setPendingFocusLocale(normalizedLocale);
|
|
1077
1129
|
setNewLocale("");
|
|
1078
1130
|
};
|
|
1131
|
+
const handleAddKeyDown = (event) => {
|
|
1132
|
+
if (event.key !== "Enter" || !canAddLocale) return;
|
|
1133
|
+
event.preventDefault();
|
|
1134
|
+
event.stopPropagation();
|
|
1135
|
+
addLocale();
|
|
1136
|
+
};
|
|
1137
|
+
useEffect(() => {
|
|
1138
|
+
if (pendingFocusLocale === null || currentLocale !== pendingFocusLocale) return;
|
|
1139
|
+
const tab = document.getElementById(`mui-builder-locale-tab-${pendingFocusLocale}`);
|
|
1140
|
+
if (tab === null) return;
|
|
1141
|
+
tab.focus();
|
|
1142
|
+
setPendingFocusLocale(null);
|
|
1143
|
+
}, [currentLocale, pendingFocusLocale]);
|
|
1079
1144
|
const stackProps = resolved.muiSlotProps?.stack;
|
|
1080
|
-
const localizationOptions = resolved.localizationOptions ?? {};
|
|
1081
1145
|
const collapsible = localizationOptions.collapsible ?? false;
|
|
1082
1146
|
const defaultLocaleControl = localizationOptions.defaultLocaleControl ?? "editable";
|
|
1083
1147
|
const configuredTranslationLocales = locales.filter((locale) => locale !== schema.defaultLocale);
|
|
@@ -1085,24 +1149,35 @@ function createMuiLocalizationSlot(options) {
|
|
|
1085
1149
|
...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
|
|
1086
1150
|
...configuredTranslationLocales
|
|
1087
1151
|
];
|
|
1088
|
-
const
|
|
1152
|
+
const legacySummaryLabel = configuredTranslationLocales.length === 0 ? "Translations not configured" : `${configuredLocales.length} ${configuredLocales.length === 1 ? "language" : "languages"} configured: ${configuredLocales.map(
|
|
1089
1153
|
(locale) => locale === schema.defaultLocale ? `${resolved.getLocaleLabel?.(locale) ?? locale} (default)` : resolved.getLocaleLabel?.(locale) ?? locale
|
|
1090
1154
|
).join(", ")}`;
|
|
1091
1155
|
const emptyStateMessage = localizationOptions.emptyStateMessage === void 0 ? DEFAULT_EMPTY_STATE_MESSAGE : translate(localizationOptions.emptyStateMessage);
|
|
1156
|
+
const summaryContext = {
|
|
1157
|
+
defaultLocale: schema.defaultLocale ?? "",
|
|
1158
|
+
supportedLocales: schema.supportedLocales ?? [],
|
|
1159
|
+
totalLocales: registeredLocales.size
|
|
1160
|
+
};
|
|
1161
|
+
const summary = localizationOptions.renderSummary === void 0 ? localizationOptions.showSummary ? configuredTranslationLocales.length > 0 ? /* @__PURE__ */ jsx14(Alert2, { severity: "success", sx: { mb: 2 }, children: translate("builder.localization.localesConfiguredSummary", {
|
|
1162
|
+
count: schema.supportedLocales?.length ?? 0
|
|
1163
|
+
}) }) : /* @__PURE__ */ jsx14(Alert2, { severity: "info", sx: { mb: 2 }, children: translate("builder.localization.noLocalesConfigured") }) : null : localizationOptions.renderSummary(summaryContext);
|
|
1092
1164
|
const title = /* @__PURE__ */ jsxs8(Stack4, { alignItems: "center", direction: "row", spacing: 1, children: [
|
|
1093
1165
|
/* @__PURE__ */ jsx14(Typography4, { variant: "subtitle1", fontWeight: "bold", children: translate("builder.localization") }),
|
|
1094
|
-
localizationOptions.showSummary ? /* @__PURE__ */ jsx14(
|
|
1166
|
+
localizationOptions.renderSummary === void 0 && localizationOptions.showSummary && configuredTranslationLocales.length > 0 ? /* @__PURE__ */ jsx14(
|
|
1095
1167
|
Chip,
|
|
1096
1168
|
{
|
|
1097
|
-
label:
|
|
1169
|
+
label: legacySummaryLabel,
|
|
1098
1170
|
size: "small",
|
|
1099
1171
|
color: configuredTranslationLocales.length > 0 ? "primary" : "default",
|
|
1100
1172
|
variant: "outlined"
|
|
1101
1173
|
}
|
|
1102
1174
|
) : null
|
|
1103
1175
|
] });
|
|
1176
|
+
const noCandidateLocales = hasLocaleSelector && filteredAvailableLocales.length === 0;
|
|
1177
|
+
const candidateHelperText = localeLimitReached ? void 0 : noCandidateLocales ? translate("builder.localization.allLocalesAdded") : void 0;
|
|
1104
1178
|
const content = /* @__PURE__ */ jsxs8(Stack4, { ...stackProps, spacing: resolved.dense ? 1 : 2, children: [
|
|
1105
1179
|
!collapsible ? title : null,
|
|
1180
|
+
summary,
|
|
1106
1181
|
/* @__PURE__ */ jsxs8(
|
|
1107
1182
|
Stack4,
|
|
1108
1183
|
{
|
|
@@ -1134,36 +1209,52 @@ function createMuiLocalizationSlot(options) {
|
|
|
1134
1209
|
}
|
|
1135
1210
|
}
|
|
1136
1211
|
) }),
|
|
1137
|
-
/* @__PURE__ */ jsx14(Box2, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } },
|
|
1138
|
-
|
|
1212
|
+
/* @__PURE__ */ jsx14(Box2, { sx: { flexGrow: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } }, onKeyDownCapture: handleAddKeyDown, children: hasLocaleSelector ? /* @__PURE__ */ jsx14(
|
|
1213
|
+
Select2,
|
|
1139
1214
|
{
|
|
1140
1215
|
id: "mui-builder-new-locale",
|
|
1141
|
-
label: translate("builder.
|
|
1216
|
+
label: translate("builder.localization.selectLocaleToAdd"),
|
|
1142
1217
|
value: newLocale,
|
|
1143
|
-
|
|
1218
|
+
options: filteredAvailableLocales.map((locale) => ({ value: locale.value, label: locale.label })),
|
|
1219
|
+
...candidateHelperText === void 0 ? {} : { helperText: candidateHelperText },
|
|
1220
|
+
disabled: readOnly || localeLimitReached || noCandidateLocales,
|
|
1144
1221
|
onChange: setNewLocale
|
|
1145
1222
|
}
|
|
1146
1223
|
) : /* @__PURE__ */ jsx14(
|
|
1147
|
-
|
|
1224
|
+
TextInput,
|
|
1148
1225
|
{
|
|
1149
1226
|
id: "mui-builder-new-locale",
|
|
1150
1227
|
label: translate("builder.addLocale"),
|
|
1151
1228
|
value: newLocale,
|
|
1152
|
-
|
|
1153
|
-
{ value: "", label: "\u2014" },
|
|
1154
|
-
...availableAllowedLocales.map((locale) => ({
|
|
1155
|
-
value: locale,
|
|
1156
|
-
label: resolved.getLocaleLabel?.(locale) ?? locale
|
|
1157
|
-
}))
|
|
1158
|
-
],
|
|
1159
|
-
disabled: readOnly || localeLimitReached || availableAllowedLocales.length === 0,
|
|
1229
|
+
disabled: readOnly || localeLimitReached,
|
|
1160
1230
|
onChange: setNewLocale
|
|
1161
1231
|
}
|
|
1162
1232
|
) }),
|
|
1163
|
-
/* @__PURE__ */ jsx14(
|
|
1233
|
+
/* @__PURE__ */ jsx14(
|
|
1234
|
+
Box2,
|
|
1235
|
+
{
|
|
1236
|
+
sx: {
|
|
1237
|
+
flexShrink: 0,
|
|
1238
|
+
minWidth: "max-content",
|
|
1239
|
+
...localizationOptions.noWrapActions ?? true ? { whiteSpace: "nowrap" } : {}
|
|
1240
|
+
},
|
|
1241
|
+
children: /* @__PURE__ */ jsx14(
|
|
1242
|
+
Button2,
|
|
1243
|
+
{
|
|
1244
|
+
variant: "primary",
|
|
1245
|
+
action: "addLocale",
|
|
1246
|
+
noWrap: localizationOptions.noWrapActions ?? true,
|
|
1247
|
+
disabled: !canAddLocale,
|
|
1248
|
+
onClick: addLocale,
|
|
1249
|
+
children: translate("builder.addLocale")
|
|
1250
|
+
}
|
|
1251
|
+
)
|
|
1252
|
+
}
|
|
1253
|
+
)
|
|
1164
1254
|
]
|
|
1165
1255
|
}
|
|
1166
1256
|
),
|
|
1257
|
+
localeLimitReached ? /* @__PURE__ */ jsx14(Typography4, { variant: "body2", color: "text.secondary", children: translate("builder.localization.maxLocalesReached", { max: policy?.maxLocales ?? 0 }) }) : null,
|
|
1167
1258
|
locales.length === 0 ? null : /* @__PURE__ */ jsx14(
|
|
1168
1259
|
Tabs,
|
|
1169
1260
|
{
|
|
@@ -1175,6 +1266,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1175
1266
|
children: locales.map((locale) => /* @__PURE__ */ jsx14(
|
|
1176
1267
|
Tab,
|
|
1177
1268
|
{
|
|
1269
|
+
id: `mui-builder-locale-tab-${locale}`,
|
|
1178
1270
|
value: locale,
|
|
1179
1271
|
label: resolved.getLocaleLabel?.(locale) ?? locale,
|
|
1180
1272
|
disabled: readOnly && locale !== currentLocale,
|
|
@@ -1188,6 +1280,7 @@ function createMuiLocalizationSlot(options) {
|
|
|
1188
1280
|
Button2,
|
|
1189
1281
|
{
|
|
1190
1282
|
variant: "secondary",
|
|
1283
|
+
noWrap: localizationOptions.noWrapActions ?? true,
|
|
1191
1284
|
disabled: readOnly || !editingLocaleConfigured || isTranslating,
|
|
1192
1285
|
onClick: onAutoTranslate,
|
|
1193
1286
|
children: isTranslating ? translate("builder.translating") : translate("builder.autoTranslate")
|
|
@@ -1308,7 +1401,8 @@ function MuiFormBuilder({
|
|
|
1308
1401
|
const contextValue = useMemo(() => ({ options: contextOptions }), [contextOptions]);
|
|
1309
1402
|
const components = useMemo(() => ({ ...muiBuilderComponents, ...customComponents }), [customComponents]);
|
|
1310
1403
|
const slots = useMemo(() => ({ ...muiBuilderSlots, ...customSlots }), [customSlots]);
|
|
1311
|
-
const
|
|
1404
|
+
const placement = contextOptions.localizationOptions?.placement;
|
|
1405
|
+
const resolvedSectionOrder = sectionOrder ?? (placement === void 0 ? contextOptions.layoutOptions?.sectionOrder : MUI_LOCALIZATION_SECTION_ORDERS[placement]);
|
|
1312
1406
|
return /* @__PURE__ */ jsx15(MuiFormBuilderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx15(
|
|
1313
1407
|
FormBuilder,
|
|
1314
1408
|
{
|
|
@@ -1322,6 +1416,7 @@ function MuiFormBuilder({
|
|
|
1322
1416
|
}
|
|
1323
1417
|
export {
|
|
1324
1418
|
DEFAULT_MUI_SECTION_ORDER,
|
|
1419
|
+
MUI_LOCALIZATION_SECTION_ORDERS,
|
|
1325
1420
|
MuiButtonAdapter,
|
|
1326
1421
|
MuiCheckboxAdapter,
|
|
1327
1422
|
MuiErrorMessageAdapter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/mui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.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": "
|
|
50
|
-
"@form-engine-ts/react": "
|
|
49
|
+
"@form-engine-ts/core": "3.0.0",
|
|
50
|
+
"@form-engine-ts/react": "3.0.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/core": "
|
|
62
|
-
"@form-engine-ts/react": "
|
|
61
|
+
"@form-engine-ts/core": "3.0.0",
|
|
62
|
+
"@form-engine-ts/react": "3.0.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",
|