hs-uix 1.6.4 → 1.7.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 +2 -0
- package/common-components.d.ts +152 -0
- package/dist/common-components.js +1385 -77
- package/dist/common-components.mjs +1438 -82
- package/dist/datatable.js +293 -242
- package/dist/datatable.mjs +209 -159
- package/dist/feed.js +939 -0
- package/dist/feed.mjs +927 -0
- package/dist/form.js +173 -102
- package/dist/form.mjs +173 -102
- package/dist/index.js +3588 -1071
- package/dist/index.mjs +3291 -783
- package/dist/kanban.js +286 -225
- package/dist/kanban.mjs +180 -119
- package/dist/utils.js +2906 -2
- package/dist/utils.mjs +2944 -1
- package/feed.d.ts +1 -0
- package/index.d.ts +51 -2
- package/package.json +17 -4
- package/packages/datatable/README.md +1046 -0
- package/packages/datatable/index.d.ts +246 -0
- package/packages/feed/README.md +224 -0
- package/packages/feed/index.d.ts +261 -0
- package/packages/form/README.md +1229 -0
- package/packages/form/index.d.ts +498 -0
- package/packages/kanban/README.md +707 -0
- package/packages/kanban/index.d.ts +367 -0
- package/utils.d.ts +122 -0
package/dist/datatable.mjs
CHANGED
|
@@ -1,6 +1,135 @@
|
|
|
1
1
|
// packages/datatable/src/DataTable.jsx
|
|
2
|
-
import React, { useState, useMemo, useEffect, useCallback, useRef } from "react";
|
|
2
|
+
import React, { useState, useMemo, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
3
|
+
|
|
4
|
+
// src/utils/query.js
|
|
3
5
|
import Fuse from "fuse.js";
|
|
6
|
+
var getEmptyFilterValue = (filter) => {
|
|
7
|
+
const type = filter.type || "select";
|
|
8
|
+
if (type === "multiselect") return [];
|
|
9
|
+
if (type === "dateRange") return { from: null, to: null };
|
|
10
|
+
return "";
|
|
11
|
+
};
|
|
12
|
+
var isFilterActive = (filter, value) => {
|
|
13
|
+
const type = filter.type || "select";
|
|
14
|
+
if (type === "multiselect") return Array.isArray(value) && value.length > 0;
|
|
15
|
+
if (type === "dateRange") return value && (value.from || value.to);
|
|
16
|
+
return !!value;
|
|
17
|
+
};
|
|
18
|
+
var formatDateChip = (dateObj) => {
|
|
19
|
+
if (!dateObj) return "";
|
|
20
|
+
const { year, month, date } = dateObj;
|
|
21
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
22
|
+
month: "short",
|
|
23
|
+
day: "numeric",
|
|
24
|
+
year: "numeric"
|
|
25
|
+
}).format(new Date(year, month, date));
|
|
26
|
+
};
|
|
27
|
+
var dateToTimestamp = (dateObj) => {
|
|
28
|
+
if (!dateObj) return null;
|
|
29
|
+
return new Date(dateObj.year, dateObj.month, dateObj.date).getTime();
|
|
30
|
+
};
|
|
31
|
+
var toStableKey = (value) => {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.stringify(value);
|
|
34
|
+
} catch (_error) {
|
|
35
|
+
return String(value);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var filterRows = (rows, filters, values) => {
|
|
39
|
+
let result = rows;
|
|
40
|
+
for (const filter of filters || []) {
|
|
41
|
+
const value = values[filter.name];
|
|
42
|
+
if (!isFilterActive(filter, value)) continue;
|
|
43
|
+
const type = filter.type || "select";
|
|
44
|
+
if (filter.filterFn) {
|
|
45
|
+
result = result.filter((row) => filter.filterFn(row, value));
|
|
46
|
+
} else if (type === "multiselect") {
|
|
47
|
+
result = result.filter((row) => value.includes(row[filter.name]));
|
|
48
|
+
} else if (type === "dateRange") {
|
|
49
|
+
const fromTs = dateToTimestamp(value.from);
|
|
50
|
+
const toTs = value.to ? dateToTimestamp(value.to) + 864e5 - 1 : null;
|
|
51
|
+
result = result.filter((row) => {
|
|
52
|
+
const rowTs = new Date(row[filter.name]).getTime();
|
|
53
|
+
if (Number.isNaN(rowTs)) return false;
|
|
54
|
+
if (fromTs && rowTs < fromTs) return false;
|
|
55
|
+
if (toTs && rowTs > toTs) return false;
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
result = result.filter((row) => row[filter.name] === value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
var searchRows = (rows, term, fields, opts = {}) => {
|
|
65
|
+
const { fuzzy = false, fuzzyOptions } = opts;
|
|
66
|
+
const t = String(term ?? "").toLowerCase();
|
|
67
|
+
if (!t || !fields || fields.length === 0) return rows;
|
|
68
|
+
if (fuzzy) {
|
|
69
|
+
const fuse = new Fuse(rows, {
|
|
70
|
+
keys: fields,
|
|
71
|
+
threshold: 0.4,
|
|
72
|
+
distance: 100,
|
|
73
|
+
ignoreLocation: true,
|
|
74
|
+
...fuzzyOptions
|
|
75
|
+
});
|
|
76
|
+
return fuse.search(t).map((r) => r.item);
|
|
77
|
+
}
|
|
78
|
+
return rows.filter(
|
|
79
|
+
(row) => fields.some((field) => {
|
|
80
|
+
const val = row[field];
|
|
81
|
+
return val && String(val).toLowerCase().includes(t);
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// src/utils/interactionHooks.js
|
|
87
|
+
import { useRef, useEffect, useCallback } from "react";
|
|
88
|
+
import { useDebounce } from "@hubspot/ui-extensions";
|
|
89
|
+
var useDebouncedDispatch = (value, debounceMs, dispatch) => {
|
|
90
|
+
const debounced = useDebounce(value, debounceMs > 0 ? debounceMs : 300);
|
|
91
|
+
const pendingRef = useRef(null);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (debounceMs <= 0) return;
|
|
94
|
+
if (pendingRef.current == null) return;
|
|
95
|
+
if (debounced !== pendingRef.current) return;
|
|
96
|
+
const next = pendingRef.current;
|
|
97
|
+
pendingRef.current = null;
|
|
98
|
+
dispatch(next);
|
|
99
|
+
}, [debounceMs, debounced, dispatch]);
|
|
100
|
+
return useCallback(
|
|
101
|
+
(next) => {
|
|
102
|
+
if (debounceMs > 0) {
|
|
103
|
+
pendingRef.current = next;
|
|
104
|
+
} else {
|
|
105
|
+
pendingRef.current = null;
|
|
106
|
+
dispatch(next);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
[debounceMs, dispatch]
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
var useSelectionReset = ({ resetKey, enabled, isControlled, clearSelection }) => {
|
|
113
|
+
const ref = useRef("");
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (!enabled || isControlled) {
|
|
116
|
+
ref.current = resetKey;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (ref.current && ref.current !== resetKey) {
|
|
120
|
+
clearSelection();
|
|
121
|
+
}
|
|
122
|
+
ref.current = resetKey;
|
|
123
|
+
}, [resetKey, enabled, isControlled, clearSelection]);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// packages/datatable/src/editValidation.js
|
|
127
|
+
var editValidationError = (result) => {
|
|
128
|
+
if (result === true || result === void 0 || result === null) return null;
|
|
129
|
+
return typeof result === "string" ? result : "Invalid value";
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// packages/datatable/src/DataTable.jsx
|
|
4
133
|
import {
|
|
5
134
|
Box,
|
|
6
135
|
Button,
|
|
@@ -10,11 +139,9 @@ import {
|
|
|
10
139
|
EmptyState,
|
|
11
140
|
ErrorState,
|
|
12
141
|
Flex,
|
|
13
|
-
Heading,
|
|
14
142
|
Icon,
|
|
15
143
|
Input,
|
|
16
144
|
Link,
|
|
17
|
-
LoadingSpinner,
|
|
18
145
|
MultiSelect,
|
|
19
146
|
NumberInput,
|
|
20
147
|
SearchInput,
|
|
@@ -28,25 +155,13 @@ import {
|
|
|
28
155
|
TableHeader,
|
|
29
156
|
TableRow,
|
|
30
157
|
Tag,
|
|
158
|
+
Tile,
|
|
31
159
|
Text,
|
|
32
160
|
TextArea,
|
|
33
161
|
TimeInput,
|
|
34
162
|
Toggle,
|
|
35
163
|
Tooltip
|
|
36
164
|
} from "@hubspot/ui-extensions";
|
|
37
|
-
var formatDateChip = (dateObj) => {
|
|
38
|
-
if (!dateObj) return "";
|
|
39
|
-
const { year, month, date } = dateObj;
|
|
40
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
41
|
-
month: "short",
|
|
42
|
-
day: "numeric",
|
|
43
|
-
year: "numeric"
|
|
44
|
-
}).format(new Date(year, month, date));
|
|
45
|
-
};
|
|
46
|
-
var dateToTimestamp = (dateObj) => {
|
|
47
|
-
if (!dateObj) return null;
|
|
48
|
-
return new Date(dateObj.year, dateObj.month, dateObj.date).getTime();
|
|
49
|
-
};
|
|
50
165
|
var NARROW_EDIT_TYPES = /* @__PURE__ */ new Set(["checkbox", "toggle"]);
|
|
51
166
|
var DATE_PATTERN = /^\d{4}[-/]\d{2}[-/]\d{2}/;
|
|
52
167
|
var BOOL_VALUES = /* @__PURE__ */ new Set(["true", "false", "yes", "no", "0", "1"]);
|
|
@@ -72,13 +187,6 @@ var serializeSortState = (sortState) => {
|
|
|
72
187
|
if (!activeField) return null;
|
|
73
188
|
return { field: activeField, direction: sortState[activeField] };
|
|
74
189
|
};
|
|
75
|
-
var toStableKey = (value) => {
|
|
76
|
-
try {
|
|
77
|
-
return JSON.stringify(value);
|
|
78
|
-
} catch (_error) {
|
|
79
|
-
return String(value);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
190
|
var computeAutoWidths = (columns, data) => {
|
|
83
191
|
if (!data || data.length === 0) return {};
|
|
84
192
|
const sample = data.slice(0, 50);
|
|
@@ -130,12 +238,6 @@ var computeAutoWidths = (columns, data) => {
|
|
|
130
238
|
});
|
|
131
239
|
return results;
|
|
132
240
|
};
|
|
133
|
-
var getEmptyFilterValue = (filter) => {
|
|
134
|
-
const type = filter.type || "select";
|
|
135
|
-
if (type === "multiselect") return [];
|
|
136
|
-
if (type === "dateRange") return { from: null, to: null };
|
|
137
|
-
return "";
|
|
138
|
-
};
|
|
139
241
|
var BOOLEAN_SELECT_OPTIONS = [
|
|
140
242
|
{ label: "Yes", value: true },
|
|
141
243
|
{ label: "No", value: false }
|
|
@@ -146,12 +248,6 @@ var resolveEditOptions = (col, data) => {
|
|
|
146
248
|
if (sample && typeof sample[col.field] === "boolean") return BOOLEAN_SELECT_OPTIONS;
|
|
147
249
|
return [];
|
|
148
250
|
};
|
|
149
|
-
var isFilterActive = (filter, value) => {
|
|
150
|
-
const type = filter.type || "select";
|
|
151
|
-
if (type === "multiselect") return Array.isArray(value) && value.length > 0;
|
|
152
|
-
if (type === "dateRange") return value && (value.from || value.to);
|
|
153
|
-
return !!value;
|
|
154
|
-
};
|
|
155
251
|
var DataTable = ({
|
|
156
252
|
// Data
|
|
157
253
|
data,
|
|
@@ -170,8 +266,8 @@ var DataTable = ({
|
|
|
170
266
|
filters = [],
|
|
171
267
|
showFilterBadges = true,
|
|
172
268
|
// show active filter chips/badges
|
|
173
|
-
showClearFiltersButton
|
|
174
|
-
// show "Clear all"
|
|
269
|
+
showClearFiltersButton,
|
|
270
|
+
// show "Clear all" reset button; defaults to showFilterBadges when omitted
|
|
175
271
|
filterInlineLimit = 2,
|
|
176
272
|
// number of filters shown inline before overflow
|
|
177
273
|
// Pagination
|
|
@@ -184,7 +280,7 @@ var DataTable = ({
|
|
|
184
280
|
// show First/Last page buttons (default: auto when pageCount > 5)
|
|
185
281
|
// Row count
|
|
186
282
|
title,
|
|
187
|
-
// optional title shown above the table toolbar
|
|
283
|
+
// optional title shown as demibold text above the table toolbar
|
|
188
284
|
showRowCount = true,
|
|
189
285
|
// show "X records" / "X of Y records" text
|
|
190
286
|
rowCountBold = false,
|
|
@@ -321,11 +417,11 @@ var DataTable = ({
|
|
|
321
417
|
const [internalSortState, setInternalSortState] = useState(initialSortState);
|
|
322
418
|
const [currentPage, setCurrentPage] = useState(1);
|
|
323
419
|
const [showMoreFilters, setShowMoreFilters] = useState(false);
|
|
324
|
-
const lastAppliedSearchRef =
|
|
420
|
+
const lastAppliedSearchRef = useRef2(
|
|
325
421
|
serverSide && searchValue != null ? searchValue : ""
|
|
326
422
|
);
|
|
327
423
|
const searchTerm = serverSide && searchValue != null ? searchValue : internalSearchTerm;
|
|
328
|
-
|
|
424
|
+
useEffect2(() => {
|
|
329
425
|
if (!serverSide || searchValue == null) return;
|
|
330
426
|
if (searchValue === lastAppliedSearchRef.current) return;
|
|
331
427
|
lastAppliedSearchRef.current = searchValue;
|
|
@@ -338,14 +434,13 @@ var DataTable = ({
|
|
|
338
434
|
);
|
|
339
435
|
const sortState = serverSide && externalSort != null ? externalSortState : internalSortState;
|
|
340
436
|
const activePage = serverSide && externalPage != null ? externalPage : currentPage;
|
|
341
|
-
|
|
437
|
+
useEffect2(() => {
|
|
342
438
|
if (!serverSide) setCurrentPage(1);
|
|
343
439
|
}, [internalSearchTerm, internalFilterValues, internalSortState, serverSide]);
|
|
344
|
-
const
|
|
345
|
-
const fireSearchCallback = useCallback((term) => {
|
|
440
|
+
const fireSearchCallback = useCallback2((term) => {
|
|
346
441
|
if (serverSide && onSearchChange) onSearchChange(term);
|
|
347
442
|
}, [serverSide, onSearchChange]);
|
|
348
|
-
const fireParamsChange =
|
|
443
|
+
const fireParamsChange = useCallback2((overrides) => {
|
|
349
444
|
if (!onParamsChange) return;
|
|
350
445
|
const nextSortState = overrides.sort != null ? normalizeSortState(columns, overrides.sort) : sortState;
|
|
351
446
|
onParamsChange({
|
|
@@ -355,38 +450,35 @@ var DataTable = ({
|
|
|
355
450
|
page: overrides.page != null ? overrides.page : activePage
|
|
356
451
|
});
|
|
357
452
|
}, [onParamsChange, columns, searchTerm, filterValues, sortState, activePage]);
|
|
358
|
-
const resetPage =
|
|
453
|
+
const resetPage = useCallback2(() => {
|
|
359
454
|
if (resetPageOnChange) {
|
|
360
455
|
setCurrentPage(1);
|
|
361
456
|
if (serverSide && onPageChange) onPageChange(1);
|
|
362
457
|
}
|
|
363
458
|
}, [resetPageOnChange, serverSide, onPageChange]);
|
|
364
|
-
const
|
|
459
|
+
const dispatchSearchChange = useCallback2((term) => {
|
|
460
|
+
lastAppliedSearchRef.current = term;
|
|
461
|
+
fireSearchCallback(term);
|
|
462
|
+
fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
|
|
463
|
+
}, [fireSearchCallback, fireParamsChange, resetPageOnChange]);
|
|
464
|
+
const dispatchSearchDebounced = useDebouncedDispatch(
|
|
465
|
+
internalSearchTerm,
|
|
466
|
+
searchDebounce,
|
|
467
|
+
dispatchSearchChange
|
|
468
|
+
);
|
|
469
|
+
const handleSearchChange = useCallback2((term) => {
|
|
365
470
|
setInternalSearchTerm(term);
|
|
366
471
|
resetPage();
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
|
|
371
|
-
};
|
|
372
|
-
if (searchDebounce > 0) {
|
|
373
|
-
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
374
|
-
debounceRef.current = setTimeout(dispatch, searchDebounce);
|
|
375
|
-
} else {
|
|
376
|
-
dispatch();
|
|
377
|
-
}
|
|
378
|
-
}, [searchDebounce, fireSearchCallback, fireParamsChange, resetPage, resetPageOnChange]);
|
|
379
|
-
useEffect(() => () => {
|
|
380
|
-
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
381
|
-
}, []);
|
|
382
|
-
const handleFilterChange = useCallback((name, value) => {
|
|
472
|
+
dispatchSearchDebounced(term);
|
|
473
|
+
}, [dispatchSearchDebounced, resetPage]);
|
|
474
|
+
const handleFilterChange = useCallback2((name, value) => {
|
|
383
475
|
const next = { ...filterValues, [name]: value };
|
|
384
476
|
setInternalFilterValues(next);
|
|
385
477
|
if (serverSide && onFilterChange) onFilterChange(next);
|
|
386
478
|
resetPage();
|
|
387
479
|
fireParamsChange({ filters: next, page: resetPageOnChange ? 1 : void 0 });
|
|
388
480
|
}, [filterValues, serverSide, onFilterChange, fireParamsChange, resetPage, resetPageOnChange]);
|
|
389
|
-
const handleSortChange =
|
|
481
|
+
const handleSortChange = useCallback2((field) => {
|
|
390
482
|
const current = sortState[field] || "none";
|
|
391
483
|
const nextDirection = current === "none" ? "ascending" : current === "ascending" ? "descending" : "none";
|
|
392
484
|
const reset = {};
|
|
@@ -399,55 +491,19 @@ var DataTable = ({
|
|
|
399
491
|
resetPage();
|
|
400
492
|
fireParamsChange({ sort: next, page: resetPageOnChange ? 1 : void 0 });
|
|
401
493
|
}, [sortState, columns, serverSide, onSortChange, fireParamsChange, resetPage, resetPageOnChange]);
|
|
402
|
-
const handlePageChange =
|
|
494
|
+
const handlePageChange = useCallback2((page) => {
|
|
403
495
|
setCurrentPage(page);
|
|
404
496
|
if (serverSide && onPageChange) onPageChange(page);
|
|
405
497
|
fireParamsChange({ page });
|
|
406
498
|
}, [serverSide, onPageChange, fireParamsChange]);
|
|
407
499
|
const filteredData = useMemo(() => {
|
|
408
500
|
if (serverSide) return data;
|
|
409
|
-
let result = data;
|
|
410
|
-
filters.forEach((filter) => {
|
|
411
|
-
const value = filterValues[filter.name];
|
|
412
|
-
if (!isFilterActive(filter, value)) return;
|
|
413
|
-
const type = filter.type || "select";
|
|
414
|
-
if (filter.filterFn) {
|
|
415
|
-
result = result.filter((row) => filter.filterFn(row, value));
|
|
416
|
-
} else if (type === "multiselect") {
|
|
417
|
-
result = result.filter((row) => value.includes(row[filter.name]));
|
|
418
|
-
} else if (type === "dateRange") {
|
|
419
|
-
const fromTs = dateToTimestamp(value.from);
|
|
420
|
-
const toTs = value.to ? dateToTimestamp(value.to) + 864e5 - 1 : null;
|
|
421
|
-
result = result.filter((row) => {
|
|
422
|
-
const rowTs = new Date(row[filter.name]).getTime();
|
|
423
|
-
if (Number.isNaN(rowTs)) return false;
|
|
424
|
-
if (fromTs && rowTs < fromTs) return false;
|
|
425
|
-
if (toTs && rowTs > toTs) return false;
|
|
426
|
-
return true;
|
|
427
|
-
});
|
|
428
|
-
} else {
|
|
429
|
-
result = result.filter((row) => row[filter.name] === value);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
501
|
+
let result = filterRows(data, filters, filterValues);
|
|
432
502
|
if (searchTerm && searchFields.length > 0) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
distance: 100,
|
|
438
|
-
ignoreLocation: true,
|
|
439
|
-
...fuzzyOptions
|
|
440
|
-
});
|
|
441
|
-
result = fuse.search(searchTerm).map((r) => r.item);
|
|
442
|
-
} else {
|
|
443
|
-
const term = searchTerm.toLowerCase();
|
|
444
|
-
result = result.filter(
|
|
445
|
-
(row) => searchFields.some((field) => {
|
|
446
|
-
const val = row[field];
|
|
447
|
-
return val && String(val).toLowerCase().includes(term);
|
|
448
|
-
})
|
|
449
|
-
);
|
|
450
|
-
}
|
|
503
|
+
result = searchRows(result, searchTerm, searchFields, {
|
|
504
|
+
fuzzy: fuzzySearch,
|
|
505
|
+
fuzzyOptions
|
|
506
|
+
});
|
|
451
507
|
}
|
|
452
508
|
return result;
|
|
453
509
|
}, [data, filterValues, searchTerm, filters, searchFields, serverSide, fuzzySearch, fuzzyOptions]);
|
|
@@ -512,7 +568,7 @@ var DataTable = ({
|
|
|
512
568
|
}
|
|
513
569
|
return /* @__PURE__ */ new Set();
|
|
514
570
|
});
|
|
515
|
-
|
|
571
|
+
useEffect2(() => {
|
|
516
572
|
if (!groupedData) return;
|
|
517
573
|
const defaultExpanded = (groupBy == null ? void 0 : groupBy.defaultExpanded) !== false;
|
|
518
574
|
if (defaultExpanded) {
|
|
@@ -523,7 +579,7 @@ var DataTable = ({
|
|
|
523
579
|
});
|
|
524
580
|
}
|
|
525
581
|
}, [groupedData, groupBy]);
|
|
526
|
-
const toggleGroup =
|
|
582
|
+
const toggleGroup = useCallback2((key) => {
|
|
527
583
|
setExpandedGroups((prev) => {
|
|
528
584
|
const next = new Set(prev);
|
|
529
585
|
if (next.has(key)) next.delete(key);
|
|
@@ -584,7 +640,7 @@ var DataTable = ({
|
|
|
584
640
|
});
|
|
585
641
|
return chips;
|
|
586
642
|
}, [filterValues, filters]);
|
|
587
|
-
const handleFilterRemove =
|
|
643
|
+
const handleFilterRemove = useCallback2((key) => {
|
|
588
644
|
if (key === "all") {
|
|
589
645
|
const cleared = {};
|
|
590
646
|
filters.forEach((f) => {
|
|
@@ -620,13 +676,14 @@ var DataTable = ({
|
|
|
620
676
|
const resolvedDateFromLabel = (labels == null ? void 0 : labels.dateFrom) || "From";
|
|
621
677
|
const resolvedDateToLabel = (labels == null ? void 0 : labels.dateTo) || "To";
|
|
622
678
|
const resolvedLoadingLabel = (labels == null ? void 0 : labels.loading) || `Loading ${pluralLabel}...`;
|
|
679
|
+
const resolvedLoadingMessage = (labels == null ? void 0 : labels.loadingMessage) || "This should only take a moment.";
|
|
623
680
|
const resolvedErrorTitle = (labels == null ? void 0 : labels.errorTitle) || "Something went wrong.";
|
|
624
681
|
const resolvedErrorMessage = (labels == null ? void 0 : labels.errorMessage) || "An error occurred while loading data.";
|
|
625
682
|
const resolvedRetryMessage = (labels == null ? void 0 : labels.retryMessage) || "Please try again.";
|
|
683
|
+
const resolvedShowClearFiltersButton = showClearFiltersButton ?? showFilterBadges;
|
|
626
684
|
const recordCountLabel = rowCountText ? rowCountText(shownOnPageCount, displayCount) : displayCount === totalDataCount ? `${totalDataCount} ${countLabel(totalDataCount)}` : `${displayCount} of ${totalDataCount} ${countLabel(totalDataCount)}`;
|
|
627
685
|
const [internalSelectedIds, setInternalSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
628
|
-
|
|
629
|
-
useEffect(() => {
|
|
686
|
+
useEffect2(() => {
|
|
630
687
|
if (externalSelectedIds != null) {
|
|
631
688
|
setInternalSelectedIds(new Set(externalSelectedIds));
|
|
632
689
|
}
|
|
@@ -643,22 +700,21 @@ var DataTable = ({
|
|
|
643
700
|
() => `${selectionQueryKey}::${selectionResetKey == null ? "" : toStableKey(selectionResetKey)}`,
|
|
644
701
|
[selectionQueryKey, selectionResetKey]
|
|
645
702
|
);
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}
|
|
654
|
-
selectionResetRef.current = combinedSelectionResetKey;
|
|
655
|
-
}, [combinedSelectionResetKey, selectable, externalSelectedIds]);
|
|
703
|
+
const clearSelection = useCallback2(() => setInternalSelectedIds(/* @__PURE__ */ new Set()), []);
|
|
704
|
+
useSelectionReset({
|
|
705
|
+
resetKey: combinedSelectionResetKey,
|
|
706
|
+
enabled: selectable,
|
|
707
|
+
isControlled: externalSelectedIds != null,
|
|
708
|
+
clearSelection
|
|
709
|
+
});
|
|
656
710
|
const selectedIds = externalSelectedIds != null ? new Set(externalSelectedIds) : internalSelectedIds;
|
|
657
|
-
const showToolbarCount = showRowCount &&
|
|
658
|
-
const
|
|
659
|
-
const
|
|
711
|
+
const showToolbarCount = showRowCount && displayCount > 0 && !(showSelectionBar && selectable && selectedIds.size > 0);
|
|
712
|
+
const hasToolbarLeft = showSearch && searchFields.length > 0 || filters.length > 0 || activeChips.length > 0 && (showFilterBadges || resolvedShowClearFiltersButton);
|
|
713
|
+
const countInTitleRow = !!title && showToolbarCount && !hasToolbarLeft;
|
|
714
|
+
const countInToolbar = showToolbarCount && !countInTitleRow;
|
|
715
|
+
const hasToolbarContent = hasToolbarLeft || countInToolbar;
|
|
660
716
|
const showRowActionsColumn = !!rowActions && !(hideRowActionsWhenSelectionActive && selectable && selectedIds.size > 0);
|
|
661
|
-
const applySelection =
|
|
717
|
+
const applySelection = useCallback2((nextSet) => {
|
|
662
718
|
if (externalSelectedIds == null) {
|
|
663
719
|
setInternalSelectedIds(nextSet);
|
|
664
720
|
}
|
|
@@ -674,13 +730,13 @@ var DataTable = ({
|
|
|
674
730
|
() => datasetRows.map((row) => row[rowIdField]).filter((id) => id != null),
|
|
675
731
|
[datasetRows, rowIdField]
|
|
676
732
|
);
|
|
677
|
-
const handleSelectRow =
|
|
733
|
+
const handleSelectRow = useCallback2((rowId, checked) => {
|
|
678
734
|
const next = new Set(selectedIds);
|
|
679
735
|
if (checked) next.add(rowId);
|
|
680
736
|
else next.delete(rowId);
|
|
681
737
|
applySelection(next);
|
|
682
738
|
}, [selectedIds, applySelection]);
|
|
683
|
-
const handleSelectAll =
|
|
739
|
+
const handleSelectAll = useCallback2((checked) => {
|
|
684
740
|
const next = new Set(selectedIds);
|
|
685
741
|
pageRowIds.forEach((id) => {
|
|
686
742
|
if (checked) next.add(id);
|
|
@@ -691,7 +747,7 @@ var DataTable = ({
|
|
|
691
747
|
const allVisibleSelected = useMemo(() => {
|
|
692
748
|
return pageRowIds.length > 0 && pageRowIds.every((id) => selectedIds.has(id));
|
|
693
749
|
}, [pageRowIds, selectedIds]);
|
|
694
|
-
const handleSelectAllRows =
|
|
750
|
+
const handleSelectAllRows = useCallback2(() => {
|
|
695
751
|
const idsToAdd = serverSide ? pageRowIds : allRowIds;
|
|
696
752
|
const next = new Set(selectedIds);
|
|
697
753
|
idsToAdd.forEach((id) => next.add(id));
|
|
@@ -704,13 +760,13 @@ var DataTable = ({
|
|
|
704
760
|
});
|
|
705
761
|
}
|
|
706
762
|
}, [serverSide, pageRowIds, allRowIds, selectedIds, applySelection, onSelectAllRequest, totalCount, data.length]);
|
|
707
|
-
const handleDeselectAll =
|
|
763
|
+
const handleDeselectAll = useCallback2(() => {
|
|
708
764
|
applySelection(/* @__PURE__ */ new Set());
|
|
709
765
|
}, [applySelection]);
|
|
710
766
|
const [editingCell, setEditingCell] = useState(null);
|
|
711
767
|
const [editValue, setEditValue] = useState(null);
|
|
712
768
|
const [editError, setEditError] = useState(null);
|
|
713
|
-
const startEditing =
|
|
769
|
+
const startEditing = useCallback2((rowId, field, currentValue) => {
|
|
714
770
|
setEditingCell({ rowId, field });
|
|
715
771
|
setEditValue(currentValue);
|
|
716
772
|
setEditError(null);
|
|
@@ -719,13 +775,13 @@ var DataTable = ({
|
|
|
719
775
|
if (row) onEditStart(row, field, currentValue);
|
|
720
776
|
}
|
|
721
777
|
}, [onEditStart, data, rowIdField]);
|
|
722
|
-
const commitEdit =
|
|
778
|
+
const commitEdit = useCallback2((row, field, value, options = {}) => {
|
|
723
779
|
const { keepEditing = false } = options;
|
|
724
780
|
const col = columns.find((c) => c.field === field);
|
|
725
781
|
if (col == null ? void 0 : col.editValidate) {
|
|
726
|
-
const
|
|
727
|
-
if (
|
|
728
|
-
setEditError(
|
|
782
|
+
const err = editValidationError(col.editValidate(value, row));
|
|
783
|
+
if (err) {
|
|
784
|
+
setEditError(err);
|
|
729
785
|
return false;
|
|
730
786
|
}
|
|
731
787
|
}
|
|
@@ -753,14 +809,7 @@ var DataTable = ({
|
|
|
753
809
|
const extra = col.editProps || {};
|
|
754
810
|
const validate = col.editValidate;
|
|
755
811
|
const validationProps = validate && editError ? { error: true, validationMessage: editError } : {};
|
|
756
|
-
const onInputValidate = validate ? (val) =>
|
|
757
|
-
const result = validate(val, row);
|
|
758
|
-
if (result !== true && result !== void 0 && result !== null) {
|
|
759
|
-
setEditError(typeof result === "string" ? result : "Invalid value");
|
|
760
|
-
} else {
|
|
761
|
-
setEditError(null);
|
|
762
|
-
}
|
|
763
|
-
} : void 0;
|
|
812
|
+
const onInputValidate = validate ? (val) => setEditError(editValidationError(validate(val, row))) : void 0;
|
|
764
813
|
const handleInput = (val) => {
|
|
765
814
|
setEditValue(val);
|
|
766
815
|
if (onInputValidate) onInputValidate(val);
|
|
@@ -836,9 +885,9 @@ var DataTable = ({
|
|
|
836
885
|
const validate = col.editValidate;
|
|
837
886
|
const fire = (val) => {
|
|
838
887
|
if (validate) {
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
841
|
-
setInlineErrors((prev) => ({ ...prev, [cellKey]:
|
|
888
|
+
const err = editValidationError(validate(val, row));
|
|
889
|
+
if (err) {
|
|
890
|
+
setInlineErrors((prev) => ({ ...prev, [cellKey]: err }));
|
|
842
891
|
return;
|
|
843
892
|
}
|
|
844
893
|
setInlineErrors((prev) => {
|
|
@@ -853,16 +902,13 @@ var DataTable = ({
|
|
|
853
902
|
const cellError = inlineErrors[cellKey];
|
|
854
903
|
const validationProps = cellError ? { error: true, validationMessage: cellError } : {};
|
|
855
904
|
const onInputValidate = validate ? (val) => {
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return next;
|
|
864
|
-
});
|
|
865
|
-
}
|
|
905
|
+
const err = editValidationError(validate(val, row));
|
|
906
|
+
setInlineErrors((prev) => {
|
|
907
|
+
if (err) return { ...prev, [cellKey]: err };
|
|
908
|
+
const next = { ...prev };
|
|
909
|
+
delete next[cellKey];
|
|
910
|
+
return next;
|
|
911
|
+
});
|
|
866
912
|
} : void 0;
|
|
867
913
|
const emitInput = (val) => {
|
|
868
914
|
if (onInputValidate) onInputValidate(val);
|
|
@@ -1006,7 +1052,7 @@ var DataTable = ({
|
|
|
1006
1052
|
}
|
|
1007
1053
|
);
|
|
1008
1054
|
};
|
|
1009
|
-
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, title && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", justify: "between", gap: "sm" }, /* @__PURE__ */ React.createElement(
|
|
1055
|
+
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, title && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", justify: "between", gap: "sm" }, /* @__PURE__ */ React.createElement(Text, { format: { fontWeight: "demibold" } }, title), countInTitleRow && /* @__PURE__ */ React.createElement(Text, { variant: "microcopy", format: rowCountBold ? { fontWeight: "bold" } : void 0 }, recordCountLabel)), hasToolbarContent && /* @__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(
|
|
1010
1056
|
SearchInput,
|
|
1011
1057
|
{
|
|
1012
1058
|
name: "datatable-search",
|
|
@@ -1024,7 +1070,7 @@ var DataTable = ({
|
|
|
1024
1070
|
/* @__PURE__ */ React.createElement(Icon, { name: "filter", size: "sm" }),
|
|
1025
1071
|
" ",
|
|
1026
1072
|
resolvedFiltersButtonLabel
|
|
1027
|
-
)), showMoreFilters && filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, filters.slice(filterInlineLimit).map(renderFilterControl)), activeChips.length > 0 && (showFilterBadges ||
|
|
1073
|
+
)), showMoreFilters && filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, filters.slice(filterInlineLimit).map(renderFilterControl)), activeChips.length > 0 && (showFilterBadges || resolvedShowClearFiltersButton) && /* @__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)), resolvedShowClearFiltersButton && /* @__PURE__ */ React.createElement(
|
|
1028
1074
|
Button,
|
|
1029
1075
|
{
|
|
1030
1076
|
variant: "transparent",
|
|
@@ -1032,7 +1078,7 @@ var DataTable = ({
|
|
|
1032
1078
|
onClick: () => handleFilterRemove("all")
|
|
1033
1079
|
},
|
|
1034
1080
|
resolvedClearAllLabel
|
|
1035
|
-
)))),
|
|
1081
|
+
)))), countInToolbar && /* @__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({
|
|
1036
1082
|
selectedIds,
|
|
1037
1083
|
selectedCount: selectedIds.size,
|
|
1038
1084
|
displayCount,
|
|
@@ -1052,11 +1098,15 @@ var DataTable = ({
|
|
|
1052
1098
|
action.icon && /* @__PURE__ */ React.createElement(Icon, { name: action.icon, size: "sm" }),
|
|
1053
1099
|
" ",
|
|
1054
1100
|
action.label
|
|
1055
|
-
)))), 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 }) :
|
|
1101
|
+
)))), 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 }) : (
|
|
1102
|
+
// Same EmptyState layout as the empty state, just the "building" image
|
|
1103
|
+
// + a loading message — so loading and empty match with no layout shift.
|
|
1104
|
+
/* @__PURE__ */ React.createElement(Tile, null, /* @__PURE__ */ React.createElement(Flex, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ React.createElement(EmptyState, { title: resolvedLoadingLabel, imageName: "building", layout: "vertical" }, /* @__PURE__ */ React.createElement(Text, null, resolvedLoadingMessage))))
|
|
1105
|
+
) : error ? renderErrorState ? renderErrorState({
|
|
1056
1106
|
error,
|
|
1057
1107
|
title: typeof error === "string" ? error : resolvedErrorTitle,
|
|
1058
1108
|
message: typeof error === "string" ? resolvedRetryMessage : resolvedErrorMessage
|
|
1059
|
-
}) : /* @__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(
|
|
1109
|
+
}) : /* @__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(Tile, null, /* @__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(
|
|
1060
1110
|
Table,
|
|
1061
1111
|
{
|
|
1062
1112
|
bordered,
|