hs-uix 1.0.4 → 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.mjs
CHANGED
|
@@ -155,12 +155,16 @@ var DataTable = ({
|
|
|
155
155
|
// enable fuzzy matching via Fuse.js
|
|
156
156
|
fuzzyOptions,
|
|
157
157
|
// custom Fuse.js options (threshold, distance, etc.)
|
|
158
|
+
showSearch = true,
|
|
159
|
+
// show the SearchInput in the toolbar
|
|
158
160
|
// Filters
|
|
159
161
|
filters = [],
|
|
160
162
|
showFilterBadges = true,
|
|
161
163
|
// show active filter chips/badges
|
|
162
164
|
showClearFiltersButton = true,
|
|
163
165
|
// show "Clear all" filters reset button
|
|
166
|
+
filterInlineLimit = 2,
|
|
167
|
+
// number of filters shown inline before overflow
|
|
164
168
|
// Pagination
|
|
165
169
|
pageSize = 10,
|
|
166
170
|
maxVisiblePageButtons,
|
|
@@ -242,6 +246,8 @@ var DataTable = ({
|
|
|
242
246
|
// optional key to force clear uncontrolled selection memory
|
|
243
247
|
resetSelectionOnQueryChange = true,
|
|
244
248
|
// clear uncontrolled selection on search/filter/sort changes
|
|
249
|
+
showSelectionBar = true,
|
|
250
|
+
// show the selection action bar when rows are selected
|
|
245
251
|
recordLabel,
|
|
246
252
|
// { singular: "Contact", plural: "Contacts" } — defaults to Record/Records
|
|
247
253
|
// -----------------------------------------------------------------------
|
|
@@ -262,11 +268,31 @@ var DataTable = ({
|
|
|
262
268
|
// (row, field, newValue) => void
|
|
263
269
|
onRowEditInput,
|
|
264
270
|
// optional live-input callback: (row, field, inputValue) => void
|
|
271
|
+
onEditStart,
|
|
272
|
+
// (row, field, currentValue) => void — fires when editing begins
|
|
273
|
+
onEditCancel,
|
|
274
|
+
// (row, field) => void — fires when editing is cancelled without commit
|
|
265
275
|
// -----------------------------------------------------------------------
|
|
266
276
|
// Auto-width
|
|
267
277
|
// -----------------------------------------------------------------------
|
|
268
|
-
autoWidth = true
|
|
278
|
+
autoWidth = true,
|
|
269
279
|
// auto-compute column widths from content analysis
|
|
280
|
+
// -----------------------------------------------------------------------
|
|
281
|
+
// Labels / i18n
|
|
282
|
+
// -----------------------------------------------------------------------
|
|
283
|
+
labels,
|
|
284
|
+
// override hardcoded UI strings for i18n
|
|
285
|
+
// -----------------------------------------------------------------------
|
|
286
|
+
// Render overrides (Phase 3 — full replacement escape hatches)
|
|
287
|
+
// -----------------------------------------------------------------------
|
|
288
|
+
renderSelectionBar,
|
|
289
|
+
// ({ selectedIds, selectedCount, displayCount, countLabel, onSelectAll, onDeselectAll, selectionActions }) => ReactNode
|
|
290
|
+
renderEmptyState,
|
|
291
|
+
// ({ title, message }) => ReactNode
|
|
292
|
+
renderLoadingState,
|
|
293
|
+
// ({ label }) => ReactNode
|
|
294
|
+
renderErrorState
|
|
295
|
+
// ({ error, title, message }) => ReactNode
|
|
270
296
|
}) => {
|
|
271
297
|
const initialSortState = useMemo(() => {
|
|
272
298
|
return normalizeSortState(columns, defaultSort);
|
|
@@ -500,11 +526,11 @@ var DataTable = ({
|
|
|
500
526
|
const type = filter.type || "select";
|
|
501
527
|
const prefix = filter.chipLabel || filter.placeholder || filter.name;
|
|
502
528
|
if (type === "multiselect") {
|
|
503
|
-
const
|
|
529
|
+
const labels2 = value.map((v) => {
|
|
504
530
|
var _a;
|
|
505
531
|
return ((_a = filter.options.find((o) => o.value === v)) == null ? void 0 : _a.label) || v;
|
|
506
532
|
}).join(", ");
|
|
507
|
-
chips.push({ key: filter.name, label: `${prefix}: ${
|
|
533
|
+
chips.push({ key: filter.name, label: `${prefix}: ${labels2}` });
|
|
508
534
|
} else if (type === "dateRange") {
|
|
509
535
|
const parts = [];
|
|
510
536
|
if (value.from) parts.push(`from ${formatDateChip(value.from)}`);
|
|
@@ -545,7 +571,17 @@ var DataTable = ({
|
|
|
545
571
|
const countLabel = (n) => n === 1 ? singularLabel : pluralLabel;
|
|
546
572
|
const resolvedEmptyTitle = emptyTitle || "No results found";
|
|
547
573
|
const resolvedEmptyMessage = emptyMessage || `No ${pluralLabel} match your search or filter criteria.`;
|
|
548
|
-
const
|
|
574
|
+
const resolvedSelectedLabel = (labels == null ? void 0 : labels.selected) || ((count, label) => `${count}\xA0${label}\xA0selected`);
|
|
575
|
+
const resolvedSelectAllLabel = (labels == null ? void 0 : labels.selectAll) || ((count, label) => `Select all ${count} ${label}`);
|
|
576
|
+
const resolvedDeselectAllLabel = (labels == null ? void 0 : labels.deselectAll) || "Deselect all";
|
|
577
|
+
const resolvedFiltersButtonLabel = (labels == null ? void 0 : labels.filtersButton) || "Filters";
|
|
578
|
+
const resolvedClearAllLabel = (labels == null ? void 0 : labels.clearAll) || "Clear all";
|
|
579
|
+
const resolvedDateFromLabel = (labels == null ? void 0 : labels.dateFrom) || "From";
|
|
580
|
+
const resolvedDateToLabel = (labels == null ? void 0 : labels.dateTo) || "To";
|
|
581
|
+
const resolvedLoadingLabel = (labels == null ? void 0 : labels.loading) || `Loading ${pluralLabel}...`;
|
|
582
|
+
const resolvedErrorTitle = (labels == null ? void 0 : labels.errorTitle) || "Something went wrong.";
|
|
583
|
+
const resolvedErrorMessage = (labels == null ? void 0 : labels.errorMessage) || "An error occurred while loading data.";
|
|
584
|
+
const resolvedRetryMessage = (labels == null ? void 0 : labels.retryMessage) || "Please try again.";
|
|
549
585
|
const recordCountLabel = rowCountText ? rowCountText(shownOnPageCount, displayCount) : displayCount === totalDataCount ? `${totalDataCount} ${countLabel(totalDataCount)}` : `${displayCount} of ${totalDataCount} ${countLabel(totalDataCount)}`;
|
|
550
586
|
const [internalSelectedIds, setInternalSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
551
587
|
const selectionResetRef = useRef("");
|
|
@@ -634,7 +670,11 @@ var DataTable = ({
|
|
|
634
670
|
setEditingCell({ rowId, field });
|
|
635
671
|
setEditValue(currentValue);
|
|
636
672
|
setEditError(null);
|
|
637
|
-
|
|
673
|
+
if (onEditStart) {
|
|
674
|
+
const row = data.find((r) => r[rowIdField] === rowId);
|
|
675
|
+
if (row) onEditStart(row, field, currentValue);
|
|
676
|
+
}
|
|
677
|
+
}, [onEditStart, data, rowIdField]);
|
|
638
678
|
const commitEdit = useCallback((row, field, value) => {
|
|
639
679
|
const col = columns.find((c) => c.field === field);
|
|
640
680
|
if (col == null ? void 0 : col.editValidate) {
|
|
@@ -656,6 +696,7 @@ var DataTable = ({
|
|
|
656
696
|
const commit = (val) => commitEdit(row, col.field, val);
|
|
657
697
|
const exitEdit = () => {
|
|
658
698
|
if (editError) return;
|
|
699
|
+
if (onEditCancel) onEditCancel(row, col.field);
|
|
659
700
|
setEditingCell(null);
|
|
660
701
|
setEditValue(null);
|
|
661
702
|
};
|
|
@@ -875,7 +916,7 @@ var DataTable = ({
|
|
|
875
916
|
{
|
|
876
917
|
name: `filter-${filter.name}-from`,
|
|
877
918
|
label: "",
|
|
878
|
-
placeholder:
|
|
919
|
+
placeholder: resolvedDateFromLabel,
|
|
879
920
|
format: "medium",
|
|
880
921
|
value: rangeVal.from,
|
|
881
922
|
onChange: (val) => handleFilterChange(filter.name, { ...rangeVal, from: val })
|
|
@@ -886,7 +927,7 @@ var DataTable = ({
|
|
|
886
927
|
size: "sm",
|
|
887
928
|
name: `filter-${filter.name}-to`,
|
|
888
929
|
label: "",
|
|
889
|
-
placeholder:
|
|
930
|
+
placeholder: resolvedDateToLabel,
|
|
890
931
|
format: "medium",
|
|
891
932
|
value: rangeVal.to,
|
|
892
933
|
onChange: (val) => handleFilterChange(filter.name, { ...rangeVal, to: val })
|
|
@@ -909,7 +950,7 @@ var DataTable = ({
|
|
|
909
950
|
}
|
|
910
951
|
);
|
|
911
952
|
};
|
|
912
|
-
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, searchFields.length > 0 && /* @__PURE__ */ React.createElement(
|
|
953
|
+
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ React.createElement(
|
|
913
954
|
SearchInput,
|
|
914
955
|
{
|
|
915
956
|
name: "datatable-search",
|
|
@@ -917,7 +958,7 @@ var DataTable = ({
|
|
|
917
958
|
value: searchTerm,
|
|
918
959
|
onChange: handleSearchChange
|
|
919
960
|
}
|
|
920
|
-
), filters.slice(0,
|
|
961
|
+
), filters.slice(0, filterInlineLimit).map(renderFilterControl), filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(
|
|
921
962
|
Button,
|
|
922
963
|
{
|
|
923
964
|
variant: "transparent",
|
|
@@ -925,16 +966,25 @@ var DataTable = ({
|
|
|
925
966
|
onClick: () => setShowMoreFilters((prev) => !prev)
|
|
926
967
|
},
|
|
927
968
|
/* @__PURE__ */ React.createElement(Icon, { name: "filter", size: "sm" }),
|
|
928
|
-
"
|
|
929
|
-
|
|
969
|
+
" ",
|
|
970
|
+
resolvedFiltersButtonLabel
|
|
971
|
+
)), showMoreFilters && filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "end", gap: "sm", wrap: "wrap" }, filters.slice(filterInlineLimit).map(renderFilterControl)), activeChips.length > 0 && (showFilterBadges || showClearFiltersButton) && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showFilterBadges && activeChips.map((chip) => /* @__PURE__ */ React.createElement(Tag, { key: chip.key, variant: "default", onDelete: () => handleFilterRemove(chip.key) }, chip.label)), showClearFiltersButton && /* @__PURE__ */ React.createElement(
|
|
930
972
|
Button,
|
|
931
973
|
{
|
|
932
974
|
variant: "transparent",
|
|
933
975
|
size: "extra-small",
|
|
934
976
|
onClick: () => handleFilterRemove("all")
|
|
935
977
|
},
|
|
936
|
-
|
|
937
|
-
)))), showRowCount && displayCount > 0 && !(selectable && selectedIds.size > 0) && /* @__PURE__ */ React.createElement(Box, { flex: 1, alignSelf: "end" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ React.createElement(Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), selectable && selectedIds.size > 0 &&
|
|
978
|
+
resolvedClearAllLabel
|
|
979
|
+
)))), showRowCount && displayCount > 0 && !(showSelectionBar && selectable && selectedIds.size > 0) && /* @__PURE__ */ React.createElement(Box, { flex: 1, alignSelf: "end" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ React.createElement(Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), showSelectionBar && selectable && selectedIds.size > 0 && (renderSelectionBar ? renderSelectionBar({
|
|
980
|
+
selectedIds,
|
|
981
|
+
selectedCount: selectedIds.size,
|
|
982
|
+
displayCount,
|
|
983
|
+
countLabel,
|
|
984
|
+
onSelectAll: handleSelectAllRows,
|
|
985
|
+
onDeselectAll: handleDeselectAll,
|
|
986
|
+
selectionActions
|
|
987
|
+
}) : /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "nowrap" }, /* @__PURE__ */ React.createElement(Text, { inline: true, format: { fontWeight: "demibold" } }, typeof resolvedSelectedLabel === "function" ? resolvedSelectedLabel(selectedIds.size, countLabel(selectedIds.size)) : resolvedSelectedLabel), /* @__PURE__ */ React.createElement(Button, { variant: "transparent", size: "extra-small", onClick: handleSelectAllRows }, typeof resolvedSelectAllLabel === "function" ? resolvedSelectAllLabel(displayCount, countLabel(displayCount)) : resolvedSelectAllLabel), /* @__PURE__ */ React.createElement(Button, { variant: "transparent", size: "extra-small", onClick: handleDeselectAll }, resolvedDeselectAllLabel), selectionActions.map((action, i) => /* @__PURE__ */ React.createElement(
|
|
938
988
|
Button,
|
|
939
989
|
{
|
|
940
990
|
key: i,
|
|
@@ -945,7 +995,11 @@ var DataTable = ({
|
|
|
945
995
|
action.icon && /* @__PURE__ */ React.createElement(Icon, { name: action.icon, size: "sm" }),
|
|
946
996
|
" ",
|
|
947
997
|
action.label
|
|
948
|
-
)))), showRowCount && displayCount > 0 && /* @__PURE__ */ React.createElement(Box, { flex: 1, alignSelf: "center" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ React.createElement(Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)))), loading ?
|
|
998
|
+
)))), showRowCount && displayCount > 0 && /* @__PURE__ */ React.createElement(Box, { flex: 1, alignSelf: "center" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", justify: "end" }, /* @__PURE__ */ React.createElement(Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel))))), loading ? renderLoadingState ? renderLoadingState({ label: resolvedLoadingLabel }) : /* @__PURE__ */ React.createElement(LoadingSpinner, { label: resolvedLoadingLabel, layout: "centered" }) : error ? renderErrorState ? renderErrorState({
|
|
999
|
+
error,
|
|
1000
|
+
title: typeof error === "string" ? error : resolvedErrorTitle,
|
|
1001
|
+
message: typeof error === "string" ? resolvedRetryMessage : resolvedErrorMessage
|
|
1002
|
+
}) : /* @__PURE__ */ React.createElement(ErrorState, { title: typeof error === "string" ? error : resolvedErrorTitle }, /* @__PURE__ */ React.createElement(Text, null, typeof error === "string" ? resolvedRetryMessage : resolvedErrorMessage)) : displayRows.length === 0 ? renderEmptyState ? renderEmptyState({ title: resolvedEmptyTitle, message: resolvedEmptyMessage }) : /* @__PURE__ */ React.createElement(Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ React.createElement(EmptyState, { title: resolvedEmptyTitle, layout: "vertical" }, /* @__PURE__ */ React.createElement(Text, null, resolvedEmptyMessage))) : /* @__PURE__ */ React.createElement(
|
|
949
1003
|
Table,
|
|
950
1004
|
{
|
|
951
1005
|
bordered,
|
|
@@ -1234,12 +1288,14 @@ var collectAsyncValidatorPromises = (value, field, allValues, context) => {
|
|
|
1234
1288
|
};
|
|
1235
1289
|
var runValidators = (value, field, allValues, fieldTypes, options = {}) => {
|
|
1236
1290
|
const includeCustomValidators = options.includeCustomValidators !== false;
|
|
1291
|
+
const msg = options.messages || {};
|
|
1237
1292
|
if (field.type === "display" || field.type === "crmPropertyList" || field.type === "crmAssociationPropertyList") return null;
|
|
1238
1293
|
const isRequired = resolveRequired(field, allValues);
|
|
1239
1294
|
const plugin = fieldTypes && fieldTypes[field.type];
|
|
1240
1295
|
const empty = plugin && plugin.isEmpty ? plugin.isEmpty(value) : isValueEmpty(value, field);
|
|
1241
1296
|
if (isRequired && empty) {
|
|
1242
|
-
|
|
1297
|
+
const fn = msg.required || ((label) => `${label} is required`);
|
|
1298
|
+
return typeof fn === "function" ? fn(field.label) : fn;
|
|
1243
1299
|
}
|
|
1244
1300
|
if (empty) return null;
|
|
1245
1301
|
if (field.useDefaultValidators !== false) {
|
|
@@ -1248,23 +1304,27 @@ var runValidators = (value, field, allValues, fieldTypes, options = {}) => {
|
|
|
1248
1304
|
}
|
|
1249
1305
|
if (field.pattern && typeof value === "string") {
|
|
1250
1306
|
if (!field.pattern.test(value)) {
|
|
1251
|
-
return field.patternMessage || "Invalid format";
|
|
1307
|
+
return field.patternMessage || msg.invalidFormat || "Invalid format";
|
|
1252
1308
|
}
|
|
1253
1309
|
}
|
|
1254
1310
|
if (typeof value === "string") {
|
|
1255
1311
|
if (field.minLength != null && value.length < field.minLength) {
|
|
1256
|
-
|
|
1312
|
+
const fn = msg.minLength || ((min) => `Must be at least ${min} characters`);
|
|
1313
|
+
return typeof fn === "function" ? fn(field.minLength) : fn;
|
|
1257
1314
|
}
|
|
1258
1315
|
if (field.maxLength != null && value.length > field.maxLength) {
|
|
1259
|
-
|
|
1316
|
+
const fn = msg.maxLength || ((max) => `Must be no more than ${max} characters`);
|
|
1317
|
+
return typeof fn === "function" ? fn(field.maxLength) : fn;
|
|
1260
1318
|
}
|
|
1261
1319
|
}
|
|
1262
1320
|
if (typeof value === "number") {
|
|
1263
1321
|
if (field.min != null && value < field.min) {
|
|
1264
|
-
|
|
1322
|
+
const fn = msg.minValue || ((min) => `Must be at least ${min}`);
|
|
1323
|
+
return typeof fn === "function" ? fn(field.min) : fn;
|
|
1265
1324
|
}
|
|
1266
1325
|
if (field.max != null && value > field.max) {
|
|
1267
|
-
|
|
1326
|
+
const fn = msg.maxValue || ((max) => `Must be no more than ${max}`);
|
|
1327
|
+
return typeof fn === "function" ? fn(field.max) : fn;
|
|
1268
1328
|
}
|
|
1269
1329
|
}
|
|
1270
1330
|
if (field.type === "date" && isDateValueObject(value)) {
|
|
@@ -1470,8 +1530,18 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1470
1530
|
// string — warning alert when readOnly
|
|
1471
1531
|
alerts,
|
|
1472
1532
|
// { addAlert, readOnlyTitle, errorTitle, successTitle }
|
|
1473
|
-
errors: controlledErrors
|
|
1533
|
+
errors: controlledErrors,
|
|
1474
1534
|
// controlled validation errors
|
|
1535
|
+
showReadOnlyAlert = true,
|
|
1536
|
+
// show warning Alert when readOnly is true
|
|
1537
|
+
showInlineAlerts = true,
|
|
1538
|
+
// show inline form-level error/success Alerts
|
|
1539
|
+
renderReadOnlyAlert,
|
|
1540
|
+
// (context: { title, message }) => ReactNode — custom readOnly alert renderer
|
|
1541
|
+
renderFieldError,
|
|
1542
|
+
// (error: string, field: object) => ReactNode — custom field error renderer
|
|
1543
|
+
defaultCurrency = "USD"
|
|
1544
|
+
// form-level default ISO 4217 currency code for currency fields
|
|
1475
1545
|
} = props;
|
|
1476
1546
|
const {
|
|
1477
1547
|
onDirtyChange,
|
|
@@ -1483,6 +1553,23 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1483
1553
|
const cancelButtonLabel = (labels == null ? void 0 : labels.cancel) || "Cancel";
|
|
1484
1554
|
const backButtonLabel = (labels == null ? void 0 : labels.back) || "Back";
|
|
1485
1555
|
const nextButtonLabel = (labels == null ? void 0 : labels.next) || "Next";
|
|
1556
|
+
const requiredMessage = (labels == null ? void 0 : labels.required) || ((label) => `${label} is required`);
|
|
1557
|
+
const invalidFormatMessage = (labels == null ? void 0 : labels.invalidFormat) || "Invalid format";
|
|
1558
|
+
const minLengthMessage = (labels == null ? void 0 : labels.minLength) || ((min) => `Must be at least ${min} characters`);
|
|
1559
|
+
const maxLengthMessage = (labels == null ? void 0 : labels.maxLength) || ((max) => `Must be no more than ${max} characters`);
|
|
1560
|
+
const minValueMessage = (labels == null ? void 0 : labels.minValue) || ((min) => `Must be at least ${min}`);
|
|
1561
|
+
const maxValueMessage = (labels == null ? void 0 : labels.maxValue) || ((max) => `Must be no more than ${max}`);
|
|
1562
|
+
const dependentPropertiesLabel = (labels == null ? void 0 : labels.dependentProperties) || "Dependent properties";
|
|
1563
|
+
const repeaterAddLabel = (labels == null ? void 0 : labels.repeaterAdd) || "Add";
|
|
1564
|
+
const repeaterRemoveLabel = (labels == null ? void 0 : labels.repeaterRemove) || "Remove";
|
|
1565
|
+
const validationMessages = labels ? {
|
|
1566
|
+
required: requiredMessage,
|
|
1567
|
+
invalidFormat: invalidFormatMessage,
|
|
1568
|
+
minLength: minLengthMessage,
|
|
1569
|
+
maxLength: maxLengthMessage,
|
|
1570
|
+
minValue: minValueMessage,
|
|
1571
|
+
maxValue: maxValueMessage
|
|
1572
|
+
} : void 0;
|
|
1486
1573
|
const addAlert = alerts == null ? void 0 : alerts.addAlert;
|
|
1487
1574
|
const readOnlyTitle = (alerts == null ? void 0 : alerts.readOnlyTitle) || "Read Only";
|
|
1488
1575
|
const errorTitle = (alerts == null ? void 0 : alerts.errorTitle) || "Error";
|
|
@@ -1721,7 +1808,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1721
1808
|
const rowValues = { ...allValues, [field.name]: rows };
|
|
1722
1809
|
subFields.forEach((subField) => {
|
|
1723
1810
|
if (subField.visible && !subField.visible(rowValues)) return;
|
|
1724
|
-
const err = runValidators(row == null ? void 0 : row[subField.name], subField, rowValues, fieldTypes);
|
|
1811
|
+
const err = runValidators(row == null ? void 0 : row[subField.name], subField, rowValues, fieldTypes, { messages: validationMessages });
|
|
1725
1812
|
if (!err) return;
|
|
1726
1813
|
const key = getRepeaterErrorKey(field.name, rowIdx, subField.name);
|
|
1727
1814
|
errors[key] = err;
|
|
@@ -1748,9 +1835,9 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1748
1835
|
);
|
|
1749
1836
|
return repeaterResult.errors[name] || null;
|
|
1750
1837
|
}
|
|
1751
|
-
return runValidators(value != null ? value : formValues[name], field, formValues, fieldTypes);
|
|
1838
|
+
return runValidators(value != null ? value : formValues[name], field, formValues, fieldTypes, { messages: validationMessages });
|
|
1752
1839
|
},
|
|
1753
|
-
[fieldByName, formValues, validateRepeaterField, fieldTypes]
|
|
1840
|
+
[fieldByName, formValues, validateRepeaterField, fieldTypes, validationMessages]
|
|
1754
1841
|
);
|
|
1755
1842
|
const validateVisibleFields = useCallback2(
|
|
1756
1843
|
(fieldSubset) => {
|
|
@@ -1766,7 +1853,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1766
1853
|
}
|
|
1767
1854
|
continue;
|
|
1768
1855
|
}
|
|
1769
|
-
const err = runValidators(formValues[field.name], field, formValues, fieldTypes);
|
|
1856
|
+
const err = runValidators(formValues[field.name], field, formValues, fieldTypes, { messages: validationMessages });
|
|
1770
1857
|
if (err) {
|
|
1771
1858
|
errors[field.name] = err;
|
|
1772
1859
|
hasErrors = true;
|
|
@@ -1774,14 +1861,14 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1774
1861
|
}
|
|
1775
1862
|
return { errors, hasErrors };
|
|
1776
1863
|
},
|
|
1777
|
-
[visibleFields, formValues, validateRepeaterField, fieldTypes]
|
|
1864
|
+
[visibleFields, formValues, validateRepeaterField, fieldTypes, validationMessages]
|
|
1778
1865
|
);
|
|
1779
1866
|
const runAsyncValidation = useCallback2(
|
|
1780
1867
|
(name, value) => {
|
|
1781
1868
|
const field = fieldByName.get(name);
|
|
1782
1869
|
if (!field || field.type === "repeater") return null;
|
|
1783
1870
|
const val = value != null ? value : formValues[name];
|
|
1784
|
-
const syncError = runValidators(val, field, formValues, fieldTypes, { includeCustomValidators: false });
|
|
1871
|
+
const syncError = runValidators(val, field, formValues, fieldTypes, { includeCustomValidators: false, messages: validationMessages });
|
|
1785
1872
|
const prevController = asyncAbortRef.current.get(name);
|
|
1786
1873
|
if (prevController) prevController.abort();
|
|
1787
1874
|
asyncAbortRef.current.delete(name);
|
|
@@ -2150,6 +2237,12 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2150
2237
|
[replaceErrors]
|
|
2151
2238
|
);
|
|
2152
2239
|
const renderField = (field) => {
|
|
2240
|
+
const fieldError = formErrors[field.name] || null;
|
|
2241
|
+
const rendered = renderFieldInner(field);
|
|
2242
|
+
if (!renderFieldError || !fieldError) return rendered;
|
|
2243
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, rendered, renderFieldError(fieldError, field));
|
|
2244
|
+
};
|
|
2245
|
+
const renderFieldInner = (field) => {
|
|
2153
2246
|
const fieldValue = formValues[field.name];
|
|
2154
2247
|
const fieldError = formErrors[field.name] || null;
|
|
2155
2248
|
const hasError = !!fieldError;
|
|
@@ -2216,7 +2309,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2216
2309
|
readOnly: isReadOnly,
|
|
2217
2310
|
disabled: isDisabled,
|
|
2218
2311
|
error: hasError,
|
|
2219
|
-
validationMessage: fieldError || void 0,
|
|
2312
|
+
validationMessage: renderFieldError ? void 0 : fieldError || void 0,
|
|
2220
2313
|
...field.loading || validatingFields[field.name] ? { loading: true } : {},
|
|
2221
2314
|
...field.fieldProps || {}
|
|
2222
2315
|
};
|
|
@@ -2286,7 +2379,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2286
2379
|
CurrencyInput2,
|
|
2287
2380
|
{
|
|
2288
2381
|
...commonProps,
|
|
2289
|
-
currency: field.currency ||
|
|
2382
|
+
currency: field.currency || defaultCurrency,
|
|
2290
2383
|
value: fieldValue,
|
|
2291
2384
|
min: field.min,
|
|
2292
2385
|
max: field.max,
|
|
@@ -2464,8 +2557,8 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2464
2557
|
const renderRemoveControl = repeaterProps.renderRemove;
|
|
2465
2558
|
const renderMoveUpControl = repeaterProps.renderMoveUp;
|
|
2466
2559
|
const renderMoveDownControl = repeaterProps.renderMoveDown;
|
|
2467
|
-
const addLabel = repeaterProps.addLabel ||
|
|
2468
|
-
const removeLabel = repeaterProps.removeLabel ||
|
|
2560
|
+
const addLabel = repeaterProps.addLabel || repeaterAddLabel;
|
|
2561
|
+
const removeLabel = repeaterProps.removeLabel || repeaterRemoveLabel;
|
|
2469
2562
|
const moveUpLabel = repeaterProps.moveUpLabel || "Up";
|
|
2470
2563
|
const moveDownLabel = repeaterProps.moveDownLabel || "Down";
|
|
2471
2564
|
const canEditRows = !isReadOnly && !isDisabled;
|
|
@@ -2499,7 +2592,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2499
2592
|
};
|
|
2500
2593
|
const validateSubField = (rowIdx, subField, subValue, nextRows) => {
|
|
2501
2594
|
const rowValues = { ...formValues, [field.name]: nextRows };
|
|
2502
|
-
const err = runValidators(subValue, subField, rowValues, fieldTypes);
|
|
2595
|
+
const err = runValidators(subValue, subField, rowValues, fieldTypes, { messages: validationMessages });
|
|
2503
2596
|
setRepeaterSubFieldError(field.name, rowIdx, subField.name, err);
|
|
2504
2597
|
};
|
|
2505
2598
|
const handleSubFieldChange = (rowIdx, subField, subValue) => {
|
|
@@ -2617,7 +2710,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2617
2710
|
const renderDependentGroup = (parentField, dependents) => {
|
|
2618
2711
|
const firstWithLabel = dependents.find((f) => getDependsOnLabel(f)) || dependents[0];
|
|
2619
2712
|
const firstWithMessage = dependents.find((f) => getDependsOnMessage(f)) || dependents[0];
|
|
2620
|
-
const groupLabel = getDependsOnLabel(firstWithLabel) ||
|
|
2713
|
+
const groupLabel = getDependsOnLabel(firstWithLabel) || dependentPropertiesLabel;
|
|
2621
2714
|
const rawMessage = getDependsOnMessage(firstWithMessage);
|
|
2622
2715
|
const tooltipMessage = typeof rawMessage === "function" ? rawMessage(parentField.label) : rawMessage || "";
|
|
2623
2716
|
return /* @__PURE__ */ React2.createElement(Tile, { key: `dep-${parentField.name}`, compact: true }, /* @__PURE__ */ React2.createElement(Flex2, { direction: "column", gap }, /* @__PURE__ */ React2.createElement(Flex2, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ React2.createElement(Text2, { format: { fontWeight: "demibold" } }, groupLabel, " ", tooltipMessage && /* @__PURE__ */ React2.createElement(Link2, { inline: true, variant: "dark", overlay: /* @__PURE__ */ React2.createElement(Tooltip, null, tooltipMessage) }, /* @__PURE__ */ React2.createElement(Icon2, { name: "info" })))), renderFieldSubset(dependents)));
|
|
@@ -2917,7 +3010,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2917
3010
|
currentStep,
|
|
2918
3011
|
stepNames: steps.map((s) => s.title)
|
|
2919
3012
|
}
|
|
2920
|
-
), formReadOnly && readOnlyMessage && /* @__PURE__ */ React2.createElement(Alert, { title: readOnlyTitle, variant: "warning" }, readOnlyMessage), !addAlert && formError && /* @__PURE__ */ React2.createElement(Alert, { title: errorTitle, variant: "danger" }, typeof formError === "string" ? formError : void 0), !addAlert && formSuccess && /* @__PURE__ */ React2.createElement(Alert, { title: successTitle, variant: "success" }, formSuccess), isMultiStep && steps[currentStep] && steps[currentStep].render ? steps[currentStep].render({
|
|
3013
|
+
), showReadOnlyAlert && formReadOnly && readOnlyMessage && (renderReadOnlyAlert ? renderReadOnlyAlert({ title: readOnlyTitle, message: readOnlyMessage }) : /* @__PURE__ */ React2.createElement(Alert, { title: readOnlyTitle, variant: "warning" }, readOnlyMessage)), showInlineAlerts && !addAlert && formError && /* @__PURE__ */ React2.createElement(Alert, { title: errorTitle, variant: "danger" }, typeof formError === "string" ? formError : void 0), showInlineAlerts && !addAlert && formSuccess && /* @__PURE__ */ React2.createElement(Alert, { title: successTitle, variant: "success" }, formSuccess), isMultiStep && steps[currentStep] && steps[currentStep].render ? steps[currentStep].render({
|
|
2921
3014
|
values: formValues,
|
|
2922
3015
|
goNext: handleNext,
|
|
2923
3016
|
goBack: handleBack,
|