hs-uix 1.0.3 → 1.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 +7 -4
- package/dist/datatable.js +68 -14
- package/dist/datatable.mjs +68 -14
- package/dist/form.js +59 -20
- package/dist/form.mjs +59 -20
- package/dist/index.js +127 -34
- package/dist/index.mjs +127 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -162,12 +162,16 @@ var DataTable = ({
|
|
|
162
162
|
// enable fuzzy matching via Fuse.js
|
|
163
163
|
fuzzyOptions,
|
|
164
164
|
// custom Fuse.js options (threshold, distance, etc.)
|
|
165
|
+
showSearch = true,
|
|
166
|
+
// show the SearchInput in the toolbar
|
|
165
167
|
// Filters
|
|
166
168
|
filters = [],
|
|
167
169
|
showFilterBadges = true,
|
|
168
170
|
// show active filter chips/badges
|
|
169
171
|
showClearFiltersButton = true,
|
|
170
172
|
// show "Clear all" filters reset button
|
|
173
|
+
filterInlineLimit = 2,
|
|
174
|
+
// number of filters shown inline before overflow
|
|
171
175
|
// Pagination
|
|
172
176
|
pageSize = 10,
|
|
173
177
|
maxVisiblePageButtons,
|
|
@@ -249,6 +253,8 @@ var DataTable = ({
|
|
|
249
253
|
// optional key to force clear uncontrolled selection memory
|
|
250
254
|
resetSelectionOnQueryChange = true,
|
|
251
255
|
// clear uncontrolled selection on search/filter/sort changes
|
|
256
|
+
showSelectionBar = true,
|
|
257
|
+
// show the selection action bar when rows are selected
|
|
252
258
|
recordLabel,
|
|
253
259
|
// { singular: "Contact", plural: "Contacts" } — defaults to Record/Records
|
|
254
260
|
// -----------------------------------------------------------------------
|
|
@@ -269,11 +275,31 @@ var DataTable = ({
|
|
|
269
275
|
// (row, field, newValue) => void
|
|
270
276
|
onRowEditInput,
|
|
271
277
|
// optional live-input callback: (row, field, inputValue) => void
|
|
278
|
+
onEditStart,
|
|
279
|
+
// (row, field, currentValue) => void — fires when editing begins
|
|
280
|
+
onEditCancel,
|
|
281
|
+
// (row, field) => void — fires when editing is cancelled without commit
|
|
272
282
|
// -----------------------------------------------------------------------
|
|
273
283
|
// Auto-width
|
|
274
284
|
// -----------------------------------------------------------------------
|
|
275
|
-
autoWidth = true
|
|
285
|
+
autoWidth = true,
|
|
276
286
|
// auto-compute column widths from content analysis
|
|
287
|
+
// -----------------------------------------------------------------------
|
|
288
|
+
// Labels / i18n
|
|
289
|
+
// -----------------------------------------------------------------------
|
|
290
|
+
labels,
|
|
291
|
+
// override hardcoded UI strings for i18n
|
|
292
|
+
// -----------------------------------------------------------------------
|
|
293
|
+
// Render overrides (Phase 3 — full replacement escape hatches)
|
|
294
|
+
// -----------------------------------------------------------------------
|
|
295
|
+
renderSelectionBar,
|
|
296
|
+
// ({ selectedIds, selectedCount, displayCount, countLabel, onSelectAll, onDeselectAll, selectionActions }) => ReactNode
|
|
297
|
+
renderEmptyState,
|
|
298
|
+
// ({ title, message }) => ReactNode
|
|
299
|
+
renderLoadingState,
|
|
300
|
+
// ({ label }) => ReactNode
|
|
301
|
+
renderErrorState
|
|
302
|
+
// ({ error, title, message }) => ReactNode
|
|
277
303
|
}) => {
|
|
278
304
|
const initialSortState = (0, import_react.useMemo)(() => {
|
|
279
305
|
return normalizeSortState(columns, defaultSort);
|
|
@@ -507,11 +533,11 @@ var DataTable = ({
|
|
|
507
533
|
const type = filter.type || "select";
|
|
508
534
|
const prefix = filter.chipLabel || filter.placeholder || filter.name;
|
|
509
535
|
if (type === "multiselect") {
|
|
510
|
-
const
|
|
536
|
+
const labels2 = value.map((v) => {
|
|
511
537
|
var _a;
|
|
512
538
|
return ((_a = filter.options.find((o) => o.value === v)) == null ? void 0 : _a.label) || v;
|
|
513
539
|
}).join(", ");
|
|
514
|
-
chips.push({ key: filter.name, label: `${prefix}: ${
|
|
540
|
+
chips.push({ key: filter.name, label: `${prefix}: ${labels2}` });
|
|
515
541
|
} else if (type === "dateRange") {
|
|
516
542
|
const parts = [];
|
|
517
543
|
if (value.from) parts.push(`from ${formatDateChip(value.from)}`);
|
|
@@ -552,7 +578,17 @@ var DataTable = ({
|
|
|
552
578
|
const countLabel = (n) => n === 1 ? singularLabel : pluralLabel;
|
|
553
579
|
const resolvedEmptyTitle = emptyTitle || "No results found";
|
|
554
580
|
const resolvedEmptyMessage = emptyMessage || `No ${pluralLabel} match your search or filter criteria.`;
|
|
555
|
-
const
|
|
581
|
+
const resolvedSelectedLabel = (labels == null ? void 0 : labels.selected) || ((count, label) => `${count}\xA0${label}\xA0selected`);
|
|
582
|
+
const resolvedSelectAllLabel = (labels == null ? void 0 : labels.selectAll) || ((count, label) => `Select all ${count} ${label}`);
|
|
583
|
+
const resolvedDeselectAllLabel = (labels == null ? void 0 : labels.deselectAll) || "Deselect all";
|
|
584
|
+
const resolvedFiltersButtonLabel = (labels == null ? void 0 : labels.filtersButton) || "Filters";
|
|
585
|
+
const resolvedClearAllLabel = (labels == null ? void 0 : labels.clearAll) || "Clear all";
|
|
586
|
+
const resolvedDateFromLabel = (labels == null ? void 0 : labels.dateFrom) || "From";
|
|
587
|
+
const resolvedDateToLabel = (labels == null ? void 0 : labels.dateTo) || "To";
|
|
588
|
+
const resolvedLoadingLabel = (labels == null ? void 0 : labels.loading) || `Loading ${pluralLabel}...`;
|
|
589
|
+
const resolvedErrorTitle = (labels == null ? void 0 : labels.errorTitle) || "Something went wrong.";
|
|
590
|
+
const resolvedErrorMessage = (labels == null ? void 0 : labels.errorMessage) || "An error occurred while loading data.";
|
|
591
|
+
const resolvedRetryMessage = (labels == null ? void 0 : labels.retryMessage) || "Please try again.";
|
|
556
592
|
const recordCountLabel = rowCountText ? rowCountText(shownOnPageCount, displayCount) : displayCount === totalDataCount ? `${totalDataCount} ${countLabel(totalDataCount)}` : `${displayCount} of ${totalDataCount} ${countLabel(totalDataCount)}`;
|
|
557
593
|
const [internalSelectedIds, setInternalSelectedIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
558
594
|
const selectionResetRef = (0, import_react.useRef)("");
|
|
@@ -641,7 +677,11 @@ var DataTable = ({
|
|
|
641
677
|
setEditingCell({ rowId, field });
|
|
642
678
|
setEditValue(currentValue);
|
|
643
679
|
setEditError(null);
|
|
644
|
-
|
|
680
|
+
if (onEditStart) {
|
|
681
|
+
const row = data.find((r) => r[rowIdField] === rowId);
|
|
682
|
+
if (row) onEditStart(row, field, currentValue);
|
|
683
|
+
}
|
|
684
|
+
}, [onEditStart, data, rowIdField]);
|
|
645
685
|
const commitEdit = (0, import_react.useCallback)((row, field, value) => {
|
|
646
686
|
const col = columns.find((c) => c.field === field);
|
|
647
687
|
if (col == null ? void 0 : col.editValidate) {
|
|
@@ -663,6 +703,7 @@ var DataTable = ({
|
|
|
663
703
|
const commit = (val) => commitEdit(row, col.field, val);
|
|
664
704
|
const exitEdit = () => {
|
|
665
705
|
if (editError) return;
|
|
706
|
+
if (onEditCancel) onEditCancel(row, col.field);
|
|
666
707
|
setEditingCell(null);
|
|
667
708
|
setEditValue(null);
|
|
668
709
|
};
|
|
@@ -882,7 +923,7 @@ var DataTable = ({
|
|
|
882
923
|
{
|
|
883
924
|
name: `filter-${filter.name}-from`,
|
|
884
925
|
label: "",
|
|
885
|
-
placeholder:
|
|
926
|
+
placeholder: resolvedDateFromLabel,
|
|
886
927
|
format: "medium",
|
|
887
928
|
value: rangeVal.from,
|
|
888
929
|
onChange: (val) => handleFilterChange(filter.name, { ...rangeVal, from: val })
|
|
@@ -893,7 +934,7 @@ var DataTable = ({
|
|
|
893
934
|
size: "sm",
|
|
894
935
|
name: `filter-${filter.name}-to`,
|
|
895
936
|
label: "",
|
|
896
|
-
placeholder:
|
|
937
|
+
placeholder: resolvedDateToLabel,
|
|
897
938
|
format: "medium",
|
|
898
939
|
value: rangeVal.to,
|
|
899
940
|
onChange: (val) => handleFilterChange(filter.name, { ...rangeVal, to: val })
|
|
@@ -916,7 +957,7 @@ var DataTable = ({
|
|
|
916
957
|
}
|
|
917
958
|
);
|
|
918
959
|
};
|
|
919
|
-
return /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 3 }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, searchFields.length > 0 && /* @__PURE__ */ import_react.default.createElement(
|
|
960
|
+
return /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 3 }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ import_react.default.createElement(
|
|
920
961
|
import_ui_extensions.SearchInput,
|
|
921
962
|
{
|
|
922
963
|
name: "datatable-search",
|
|
@@ -924,7 +965,7 @@ var DataTable = ({
|
|
|
924
965
|
value: searchTerm,
|
|
925
966
|
onChange: handleSearchChange
|
|
926
967
|
}
|
|
927
|
-
), filters.slice(0,
|
|
968
|
+
), filters.slice(0, filterInlineLimit).map(renderFilterControl), filters.length > filterInlineLimit && /* @__PURE__ */ import_react.default.createElement(
|
|
928
969
|
import_ui_extensions.Button,
|
|
929
970
|
{
|
|
930
971
|
variant: "transparent",
|
|
@@ -932,16 +973,25 @@ var DataTable = ({
|
|
|
932
973
|
onClick: () => setShowMoreFilters((prev) => !prev)
|
|
933
974
|
},
|
|
934
975
|
/* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Icon, { name: "filter", size: "sm" }),
|
|
935
|
-
"
|
|
936
|
-
|
|
976
|
+
" ",
|
|
977
|
+
resolvedFiltersButtonLabel
|
|
978
|
+
)), showMoreFilters && filters.length > filterInlineLimit && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "end", gap: "sm", wrap: "wrap" }, filters.slice(filterInlineLimit).map(renderFilterControl)), activeChips.length > 0 && (showFilterBadges || showClearFiltersButton) && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showFilterBadges && activeChips.map((chip) => /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Tag, { key: chip.key, variant: "default", onDelete: () => handleFilterRemove(chip.key) }, chip.label)), showClearFiltersButton && /* @__PURE__ */ import_react.default.createElement(
|
|
937
979
|
import_ui_extensions.Button,
|
|
938
980
|
{
|
|
939
981
|
variant: "transparent",
|
|
940
982
|
size: "extra-small",
|
|
941
983
|
onClick: () => handleFilterRemove("all")
|
|
942
984
|
},
|
|
943
|
-
|
|
944
|
-
)))), showRowCount && displayCount > 0 && !(selectable && selectedIds.size > 0) && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 1, alignSelf: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), selectable && selectedIds.size > 0 &&
|
|
985
|
+
resolvedClearAllLabel
|
|
986
|
+
)))), showRowCount && displayCount > 0 && !(showSelectionBar && selectable && selectedIds.size > 0) && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 1, alignSelf: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), showSelectionBar && selectable && selectedIds.size > 0 && (renderSelectionBar ? renderSelectionBar({
|
|
987
|
+
selectedIds,
|
|
988
|
+
selectedCount: selectedIds.size,
|
|
989
|
+
displayCount,
|
|
990
|
+
countLabel,
|
|
991
|
+
onSelectAll: handleSelectAllRows,
|
|
992
|
+
onDeselectAll: handleDeselectAll,
|
|
993
|
+
selectionActions
|
|
994
|
+
}) : /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 3 }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "center", gap: "sm", wrap: "nowrap" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, { inline: true, format: { fontWeight: "demibold" } }, typeof resolvedSelectedLabel === "function" ? resolvedSelectedLabel(selectedIds.size, countLabel(selectedIds.size)) : resolvedSelectedLabel), /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Button, { variant: "transparent", size: "extra-small", onClick: handleSelectAllRows }, typeof resolvedSelectAllLabel === "function" ? resolvedSelectAllLabel(displayCount, countLabel(displayCount)) : resolvedSelectAllLabel), /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Button, { variant: "transparent", size: "extra-small", onClick: handleDeselectAll }, resolvedDeselectAllLabel), selectionActions.map((action, i) => /* @__PURE__ */ import_react.default.createElement(
|
|
945
995
|
import_ui_extensions.Button,
|
|
946
996
|
{
|
|
947
997
|
key: i,
|
|
@@ -952,7 +1002,11 @@ var DataTable = ({
|
|
|
952
1002
|
action.icon && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Icon, { name: action.icon, size: "sm" }),
|
|
953
1003
|
" ",
|
|
954
1004
|
action.label
|
|
955
|
-
)))), showRowCount && displayCount > 0 && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 1, alignSelf: "center" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), loading ?
|
|
1005
|
+
)))), showRowCount && displayCount > 0 && /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 1, alignSelf: "center" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel))))), loading ? renderLoadingState ? renderLoadingState({ label: resolvedLoadingLabel }) : /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.LoadingSpinner, { label: resolvedLoadingLabel, layout: "centered" }) : error ? renderErrorState ? renderErrorState({
|
|
1006
|
+
error,
|
|
1007
|
+
title: typeof error === "string" ? error : resolvedErrorTitle,
|
|
1008
|
+
message: typeof error === "string" ? resolvedRetryMessage : resolvedErrorMessage
|
|
1009
|
+
}) : /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.ErrorState, { title: typeof error === "string" ? error : resolvedErrorTitle }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, null, typeof error === "string" ? resolvedRetryMessage : resolvedErrorMessage)) : displayRows.length === 0 ? renderEmptyState ? renderEmptyState({ title: resolvedEmptyTitle, message: resolvedEmptyMessage }) : /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.EmptyState, { title: resolvedEmptyTitle, layout: "vertical" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Text, null, resolvedEmptyMessage))) : /* @__PURE__ */ import_react.default.createElement(
|
|
956
1010
|
import_ui_extensions.Table,
|
|
957
1011
|
{
|
|
958
1012
|
bordered,
|
|
@@ -1201,12 +1255,14 @@ var collectAsyncValidatorPromises = (value, field, allValues, context) => {
|
|
|
1201
1255
|
};
|
|
1202
1256
|
var runValidators = (value, field, allValues, fieldTypes, options = {}) => {
|
|
1203
1257
|
const includeCustomValidators = options.includeCustomValidators !== false;
|
|
1258
|
+
const msg = options.messages || {};
|
|
1204
1259
|
if (field.type === "display" || field.type === "crmPropertyList" || field.type === "crmAssociationPropertyList") return null;
|
|
1205
1260
|
const isRequired = resolveRequired(field, allValues);
|
|
1206
1261
|
const plugin = fieldTypes && fieldTypes[field.type];
|
|
1207
1262
|
const empty = plugin && plugin.isEmpty ? plugin.isEmpty(value) : isValueEmpty(value, field);
|
|
1208
1263
|
if (isRequired && empty) {
|
|
1209
|
-
|
|
1264
|
+
const fn = msg.required || ((label) => `${label} is required`);
|
|
1265
|
+
return typeof fn === "function" ? fn(field.label) : fn;
|
|
1210
1266
|
}
|
|
1211
1267
|
if (empty) return null;
|
|
1212
1268
|
if (field.useDefaultValidators !== false) {
|
|
@@ -1215,23 +1271,27 @@ var runValidators = (value, field, allValues, fieldTypes, options = {}) => {
|
|
|
1215
1271
|
}
|
|
1216
1272
|
if (field.pattern && typeof value === "string") {
|
|
1217
1273
|
if (!field.pattern.test(value)) {
|
|
1218
|
-
return field.patternMessage || "Invalid format";
|
|
1274
|
+
return field.patternMessage || msg.invalidFormat || "Invalid format";
|
|
1219
1275
|
}
|
|
1220
1276
|
}
|
|
1221
1277
|
if (typeof value === "string") {
|
|
1222
1278
|
if (field.minLength != null && value.length < field.minLength) {
|
|
1223
|
-
|
|
1279
|
+
const fn = msg.minLength || ((min) => `Must be at least ${min} characters`);
|
|
1280
|
+
return typeof fn === "function" ? fn(field.minLength) : fn;
|
|
1224
1281
|
}
|
|
1225
1282
|
if (field.maxLength != null && value.length > field.maxLength) {
|
|
1226
|
-
|
|
1283
|
+
const fn = msg.maxLength || ((max) => `Must be no more than ${max} characters`);
|
|
1284
|
+
return typeof fn === "function" ? fn(field.maxLength) : fn;
|
|
1227
1285
|
}
|
|
1228
1286
|
}
|
|
1229
1287
|
if (typeof value === "number") {
|
|
1230
1288
|
if (field.min != null && value < field.min) {
|
|
1231
|
-
|
|
1289
|
+
const fn = msg.minValue || ((min) => `Must be at least ${min}`);
|
|
1290
|
+
return typeof fn === "function" ? fn(field.min) : fn;
|
|
1232
1291
|
}
|
|
1233
1292
|
if (field.max != null && value > field.max) {
|
|
1234
|
-
|
|
1293
|
+
const fn = msg.maxValue || ((max) => `Must be no more than ${max}`);
|
|
1294
|
+
return typeof fn === "function" ? fn(field.max) : fn;
|
|
1235
1295
|
}
|
|
1236
1296
|
}
|
|
1237
1297
|
if (field.type === "date" && isDateValueObject(value)) {
|
|
@@ -1437,8 +1497,18 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1437
1497
|
// string — warning alert when readOnly
|
|
1438
1498
|
alerts,
|
|
1439
1499
|
// { addAlert, readOnlyTitle, errorTitle, successTitle }
|
|
1440
|
-
errors: controlledErrors
|
|
1500
|
+
errors: controlledErrors,
|
|
1441
1501
|
// controlled validation errors
|
|
1502
|
+
showReadOnlyAlert = true,
|
|
1503
|
+
// show warning Alert when readOnly is true
|
|
1504
|
+
showInlineAlerts = true,
|
|
1505
|
+
// show inline form-level error/success Alerts
|
|
1506
|
+
renderReadOnlyAlert,
|
|
1507
|
+
// (context: { title, message }) => ReactNode — custom readOnly alert renderer
|
|
1508
|
+
renderFieldError,
|
|
1509
|
+
// (error: string, field: object) => ReactNode — custom field error renderer
|
|
1510
|
+
defaultCurrency = "USD"
|
|
1511
|
+
// form-level default ISO 4217 currency code for currency fields
|
|
1442
1512
|
} = props;
|
|
1443
1513
|
const {
|
|
1444
1514
|
onDirtyChange,
|
|
@@ -1450,6 +1520,23 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1450
1520
|
const cancelButtonLabel = (labels == null ? void 0 : labels.cancel) || "Cancel";
|
|
1451
1521
|
const backButtonLabel = (labels == null ? void 0 : labels.back) || "Back";
|
|
1452
1522
|
const nextButtonLabel = (labels == null ? void 0 : labels.next) || "Next";
|
|
1523
|
+
const requiredMessage = (labels == null ? void 0 : labels.required) || ((label) => `${label} is required`);
|
|
1524
|
+
const invalidFormatMessage = (labels == null ? void 0 : labels.invalidFormat) || "Invalid format";
|
|
1525
|
+
const minLengthMessage = (labels == null ? void 0 : labels.minLength) || ((min) => `Must be at least ${min} characters`);
|
|
1526
|
+
const maxLengthMessage = (labels == null ? void 0 : labels.maxLength) || ((max) => `Must be no more than ${max} characters`);
|
|
1527
|
+
const minValueMessage = (labels == null ? void 0 : labels.minValue) || ((min) => `Must be at least ${min}`);
|
|
1528
|
+
const maxValueMessage = (labels == null ? void 0 : labels.maxValue) || ((max) => `Must be no more than ${max}`);
|
|
1529
|
+
const dependentPropertiesLabel = (labels == null ? void 0 : labels.dependentProperties) || "Dependent properties";
|
|
1530
|
+
const repeaterAddLabel = (labels == null ? void 0 : labels.repeaterAdd) || "Add";
|
|
1531
|
+
const repeaterRemoveLabel = (labels == null ? void 0 : labels.repeaterRemove) || "Remove";
|
|
1532
|
+
const validationMessages = labels ? {
|
|
1533
|
+
required: requiredMessage,
|
|
1534
|
+
invalidFormat: invalidFormatMessage,
|
|
1535
|
+
minLength: minLengthMessage,
|
|
1536
|
+
maxLength: maxLengthMessage,
|
|
1537
|
+
minValue: minValueMessage,
|
|
1538
|
+
maxValue: maxValueMessage
|
|
1539
|
+
} : void 0;
|
|
1453
1540
|
const addAlert = alerts == null ? void 0 : alerts.addAlert;
|
|
1454
1541
|
const readOnlyTitle = (alerts == null ? void 0 : alerts.readOnlyTitle) || "Read Only";
|
|
1455
1542
|
const errorTitle = (alerts == null ? void 0 : alerts.errorTitle) || "Error";
|
|
@@ -1688,7 +1775,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1688
1775
|
const rowValues = { ...allValues, [field.name]: rows };
|
|
1689
1776
|
subFields.forEach((subField) => {
|
|
1690
1777
|
if (subField.visible && !subField.visible(rowValues)) return;
|
|
1691
|
-
const err = runValidators(row == null ? void 0 : row[subField.name], subField, rowValues, fieldTypes);
|
|
1778
|
+
const err = runValidators(row == null ? void 0 : row[subField.name], subField, rowValues, fieldTypes, { messages: validationMessages });
|
|
1692
1779
|
if (!err) return;
|
|
1693
1780
|
const key = getRepeaterErrorKey(field.name, rowIdx, subField.name);
|
|
1694
1781
|
errors[key] = err;
|
|
@@ -1715,9 +1802,9 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1715
1802
|
);
|
|
1716
1803
|
return repeaterResult.errors[name] || null;
|
|
1717
1804
|
}
|
|
1718
|
-
return runValidators(value != null ? value : formValues[name], field, formValues, fieldTypes);
|
|
1805
|
+
return runValidators(value != null ? value : formValues[name], field, formValues, fieldTypes, { messages: validationMessages });
|
|
1719
1806
|
},
|
|
1720
|
-
[fieldByName, formValues, validateRepeaterField, fieldTypes]
|
|
1807
|
+
[fieldByName, formValues, validateRepeaterField, fieldTypes, validationMessages]
|
|
1721
1808
|
);
|
|
1722
1809
|
const validateVisibleFields = (0, import_react2.useCallback)(
|
|
1723
1810
|
(fieldSubset) => {
|
|
@@ -1733,7 +1820,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1733
1820
|
}
|
|
1734
1821
|
continue;
|
|
1735
1822
|
}
|
|
1736
|
-
const err = runValidators(formValues[field.name], field, formValues, fieldTypes);
|
|
1823
|
+
const err = runValidators(formValues[field.name], field, formValues, fieldTypes, { messages: validationMessages });
|
|
1737
1824
|
if (err) {
|
|
1738
1825
|
errors[field.name] = err;
|
|
1739
1826
|
hasErrors = true;
|
|
@@ -1741,14 +1828,14 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1741
1828
|
}
|
|
1742
1829
|
return { errors, hasErrors };
|
|
1743
1830
|
},
|
|
1744
|
-
[visibleFields, formValues, validateRepeaterField, fieldTypes]
|
|
1831
|
+
[visibleFields, formValues, validateRepeaterField, fieldTypes, validationMessages]
|
|
1745
1832
|
);
|
|
1746
1833
|
const runAsyncValidation = (0, import_react2.useCallback)(
|
|
1747
1834
|
(name, value) => {
|
|
1748
1835
|
const field = fieldByName.get(name);
|
|
1749
1836
|
if (!field || field.type === "repeater") return null;
|
|
1750
1837
|
const val = value != null ? value : formValues[name];
|
|
1751
|
-
const syncError = runValidators(val, field, formValues, fieldTypes, { includeCustomValidators: false });
|
|
1838
|
+
const syncError = runValidators(val, field, formValues, fieldTypes, { includeCustomValidators: false, messages: validationMessages });
|
|
1752
1839
|
const prevController = asyncAbortRef.current.get(name);
|
|
1753
1840
|
if (prevController) prevController.abort();
|
|
1754
1841
|
asyncAbortRef.current.delete(name);
|
|
@@ -2117,6 +2204,12 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2117
2204
|
[replaceErrors]
|
|
2118
2205
|
);
|
|
2119
2206
|
const renderField = (field) => {
|
|
2207
|
+
const fieldError = formErrors[field.name] || null;
|
|
2208
|
+
const rendered = renderFieldInner(field);
|
|
2209
|
+
if (!renderFieldError || !fieldError) return rendered;
|
|
2210
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, rendered, renderFieldError(fieldError, field));
|
|
2211
|
+
};
|
|
2212
|
+
const renderFieldInner = (field) => {
|
|
2120
2213
|
const fieldValue = formValues[field.name];
|
|
2121
2214
|
const fieldError = formErrors[field.name] || null;
|
|
2122
2215
|
const hasError = !!fieldError;
|
|
@@ -2183,7 +2276,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2183
2276
|
readOnly: isReadOnly,
|
|
2184
2277
|
disabled: isDisabled,
|
|
2185
2278
|
error: hasError,
|
|
2186
|
-
validationMessage: fieldError || void 0,
|
|
2279
|
+
validationMessage: renderFieldError ? void 0 : fieldError || void 0,
|
|
2187
2280
|
...field.loading || validatingFields[field.name] ? { loading: true } : {},
|
|
2188
2281
|
...field.fieldProps || {}
|
|
2189
2282
|
};
|
|
@@ -2253,7 +2346,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2253
2346
|
import_ui_extensions2.CurrencyInput,
|
|
2254
2347
|
{
|
|
2255
2348
|
...commonProps,
|
|
2256
|
-
currency: field.currency ||
|
|
2349
|
+
currency: field.currency || defaultCurrency,
|
|
2257
2350
|
value: fieldValue,
|
|
2258
2351
|
min: field.min,
|
|
2259
2352
|
max: field.max,
|
|
@@ -2431,8 +2524,8 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2431
2524
|
const renderRemoveControl = repeaterProps.renderRemove;
|
|
2432
2525
|
const renderMoveUpControl = repeaterProps.renderMoveUp;
|
|
2433
2526
|
const renderMoveDownControl = repeaterProps.renderMoveDown;
|
|
2434
|
-
const addLabel = repeaterProps.addLabel ||
|
|
2435
|
-
const removeLabel = repeaterProps.removeLabel ||
|
|
2527
|
+
const addLabel = repeaterProps.addLabel || repeaterAddLabel;
|
|
2528
|
+
const removeLabel = repeaterProps.removeLabel || repeaterRemoveLabel;
|
|
2436
2529
|
const moveUpLabel = repeaterProps.moveUpLabel || "Up";
|
|
2437
2530
|
const moveDownLabel = repeaterProps.moveDownLabel || "Down";
|
|
2438
2531
|
const canEditRows = !isReadOnly && !isDisabled;
|
|
@@ -2466,7 +2559,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2466
2559
|
};
|
|
2467
2560
|
const validateSubField = (rowIdx, subField, subValue, nextRows) => {
|
|
2468
2561
|
const rowValues = { ...formValues, [field.name]: nextRows };
|
|
2469
|
-
const err = runValidators(subValue, subField, rowValues, fieldTypes);
|
|
2562
|
+
const err = runValidators(subValue, subField, rowValues, fieldTypes, { messages: validationMessages });
|
|
2470
2563
|
setRepeaterSubFieldError(field.name, rowIdx, subField.name, err);
|
|
2471
2564
|
};
|
|
2472
2565
|
const handleSubFieldChange = (rowIdx, subField, subValue) => {
|
|
@@ -2584,7 +2677,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2584
2677
|
const renderDependentGroup = (parentField, dependents) => {
|
|
2585
2678
|
const firstWithLabel = dependents.find((f) => getDependsOnLabel(f)) || dependents[0];
|
|
2586
2679
|
const firstWithMessage = dependents.find((f) => getDependsOnMessage(f)) || dependents[0];
|
|
2587
|
-
const groupLabel = getDependsOnLabel(firstWithLabel) ||
|
|
2680
|
+
const groupLabel = getDependsOnLabel(firstWithLabel) || dependentPropertiesLabel;
|
|
2588
2681
|
const rawMessage = getDependsOnMessage(firstWithMessage);
|
|
2589
2682
|
const tooltipMessage = typeof rawMessage === "function" ? rawMessage(parentField.label) : rawMessage || "";
|
|
2590
2683
|
return /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Tile, { key: `dep-${parentField.name}`, compact: true }, /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Flex, { direction: "column", gap }, /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Flex, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Text, { format: { fontWeight: "demibold" } }, groupLabel, " ", tooltipMessage && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Link, { inline: true, variant: "dark", overlay: /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Tooltip, null, tooltipMessage) }, /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Icon, { name: "info" })))), renderFieldSubset(dependents)));
|
|
@@ -2884,7 +2977,7 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
2884
2977
|
currentStep,
|
|
2885
2978
|
stepNames: steps.map((s) => s.title)
|
|
2886
2979
|
}
|
|
2887
|
-
), formReadOnly && readOnlyMessage && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: readOnlyTitle, variant: "warning" }, readOnlyMessage), !addAlert && formError && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: errorTitle, variant: "danger" }, typeof formError === "string" ? formError : void 0), !addAlert && formSuccess && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: successTitle, variant: "success" }, formSuccess), isMultiStep && steps[currentStep] && steps[currentStep].render ? steps[currentStep].render({
|
|
2980
|
+
), showReadOnlyAlert && formReadOnly && readOnlyMessage && (renderReadOnlyAlert ? renderReadOnlyAlert({ title: readOnlyTitle, message: readOnlyMessage }) : /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: readOnlyTitle, variant: "warning" }, readOnlyMessage)), showInlineAlerts && !addAlert && formError && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: errorTitle, variant: "danger" }, typeof formError === "string" ? formError : void 0), showInlineAlerts && !addAlert && formSuccess && /* @__PURE__ */ import_react2.default.createElement(import_ui_extensions2.Alert, { title: successTitle, variant: "success" }, formSuccess), isMultiStep && steps[currentStep] && steps[currentStep].render ? steps[currentStep].render({
|
|
2888
2981
|
values: formValues,
|
|
2889
2982
|
goNext: handleNext,
|
|
2890
2983
|
goBack: handleBack,
|