chordia-ui 4.0.7 → 4.0.8
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/dist/DataTable2.cjs.js +1 -1
- package/dist/DataTable2.cjs.js.map +1 -1
- package/dist/DataTable2.es.js +936 -814
- package/dist/DataTable2.es.js.map +1 -1
- package/dist/components/policies.cjs.js +1 -1
- package/dist/components/policies.cjs.js.map +1 -1
- package/dist/components/policies.es.js +48 -49
- package/dist/components/policies.es.js.map +1 -1
- package/package.json +1 -1
- package/src/components/data/DataTable2.jsx +168 -6
- package/src/components/policies/PoliciesPage.jsx +0 -1
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
horizontalListSortingStrategy,
|
|
19
19
|
} from "@dnd-kit/sortable";
|
|
20
20
|
import { CSS } from "@dnd-kit/utilities";
|
|
21
|
-
import { GripVertical, ChevronUp, ChevronDown, ListFilter, ArrowUp, ArrowDown, Settings2, Search, Check, X, ArrowUpDown } from "lucide-react";
|
|
21
|
+
import { GripVertical, ChevronUp, ChevronDown, ListFilter, ArrowUp, ArrowDown, Settings2, Search, Check, X, ArrowUpDown, Minus } from "lucide-react";
|
|
22
22
|
import { createPortal } from "react-dom";
|
|
23
23
|
import Pagination from "../common/Pagination.jsx";
|
|
24
24
|
// TODO: surface column limit errors via callback prop (onMaxColumnsError)
|
|
@@ -1189,6 +1189,16 @@ export default function DataTable2({
|
|
|
1189
1189
|
// surrounding toolbar wrapper is also skipped if no other toolbar content
|
|
1190
1190
|
// (e.g. `filtersConfig`) is configured.
|
|
1191
1191
|
hideColumnPicker = false,
|
|
1192
|
+
// Row selection (opt-in). When `selectable` is true a leading checkbox
|
|
1193
|
+
// column is rendered outside the reorderable/persisted column system, so it
|
|
1194
|
+
// is always visible and unaffected by the column picker or saved prefs.
|
|
1195
|
+
// Selection is controlled by the host: pass `selectedRowIds` (array of ids)
|
|
1196
|
+
// and handle `onSelectionChange(nextIdsArray)`. `getRowId` resolves a row's
|
|
1197
|
+
// id (defaults to `row.id`).
|
|
1198
|
+
selectable = false,
|
|
1199
|
+
selectedRowIds = null,
|
|
1200
|
+
onSelectionChange = null,
|
|
1201
|
+
getRowId = null,
|
|
1192
1202
|
}) {
|
|
1193
1203
|
// Get user email for user-specific storage
|
|
1194
1204
|
const { userData } = useUserContext();
|
|
@@ -1864,6 +1874,96 @@ export default function DataTable2({
|
|
|
1864
1874
|
}
|
|
1865
1875
|
}, [sortedData, page, pageSize, isServerSidePagination]);
|
|
1866
1876
|
|
|
1877
|
+
// ---- Row selection (opt-in) --------------------------------------------
|
|
1878
|
+
const resolveRowId = useCallback(
|
|
1879
|
+
(row, index) => {
|
|
1880
|
+
if (getRowId) return getRowId(row, index);
|
|
1881
|
+
return row?.id ?? index;
|
|
1882
|
+
},
|
|
1883
|
+
[getRowId]
|
|
1884
|
+
);
|
|
1885
|
+
|
|
1886
|
+
const selectedIdSet = useMemo(
|
|
1887
|
+
() => new Set(Array.isArray(selectedRowIds) ? selectedRowIds : []),
|
|
1888
|
+
[selectedRowIds]
|
|
1889
|
+
);
|
|
1890
|
+
|
|
1891
|
+
const pageRowIds = useMemo(
|
|
1892
|
+
() => paginatedData.map((row, index) => resolveRowId(row, index)),
|
|
1893
|
+
[paginatedData, resolveRowId]
|
|
1894
|
+
);
|
|
1895
|
+
|
|
1896
|
+
const selectedOnPageCount = useMemo(
|
|
1897
|
+
() => pageRowIds.reduce((count, id) => (selectedIdSet.has(id) ? count + 1 : count), 0),
|
|
1898
|
+
[pageRowIds, selectedIdSet]
|
|
1899
|
+
);
|
|
1900
|
+
|
|
1901
|
+
const allOnPageSelected = pageRowIds.length > 0 && selectedOnPageCount === pageRowIds.length;
|
|
1902
|
+
const someOnPageSelected = selectedOnPageCount > 0 && !allOnPageSelected;
|
|
1903
|
+
|
|
1904
|
+
const toggleRowSelection = useCallback(
|
|
1905
|
+
(rowId) => {
|
|
1906
|
+
if (!onSelectionChange) return;
|
|
1907
|
+
const next = new Set(selectedIdSet);
|
|
1908
|
+
if (next.has(rowId)) next.delete(rowId);
|
|
1909
|
+
else next.add(rowId);
|
|
1910
|
+
onSelectionChange(Array.from(next));
|
|
1911
|
+
},
|
|
1912
|
+
[onSelectionChange, selectedIdSet]
|
|
1913
|
+
);
|
|
1914
|
+
|
|
1915
|
+
const toggleSelectAllOnPage = useCallback(() => {
|
|
1916
|
+
if (!onSelectionChange) return;
|
|
1917
|
+
const next = new Set(selectedIdSet);
|
|
1918
|
+
if (allOnPageSelected) {
|
|
1919
|
+
pageRowIds.forEach((id) => next.delete(id));
|
|
1920
|
+
} else {
|
|
1921
|
+
pageRowIds.forEach((id) => next.add(id));
|
|
1922
|
+
}
|
|
1923
|
+
onSelectionChange(Array.from(next));
|
|
1924
|
+
}, [onSelectionChange, selectedIdSet, allOnPageSelected, pageRowIds]);
|
|
1925
|
+
|
|
1926
|
+
// Shared checkbox visual for row selection.
|
|
1927
|
+
const SelectionCheckbox = ({ checked, indeterminate = false, onToggle, ariaLabel }) => (
|
|
1928
|
+
<span
|
|
1929
|
+
role="checkbox"
|
|
1930
|
+
aria-checked={indeterminate ? "mixed" : checked}
|
|
1931
|
+
aria-label={ariaLabel}
|
|
1932
|
+
tabIndex={0}
|
|
1933
|
+
onClick={(e) => {
|
|
1934
|
+
e.stopPropagation();
|
|
1935
|
+
onToggle();
|
|
1936
|
+
}}
|
|
1937
|
+
onKeyDown={(e) => {
|
|
1938
|
+
if (e.key === " " || e.key === "Enter") {
|
|
1939
|
+
e.preventDefault();
|
|
1940
|
+
e.stopPropagation();
|
|
1941
|
+
onToggle();
|
|
1942
|
+
}
|
|
1943
|
+
}}
|
|
1944
|
+
style={{
|
|
1945
|
+
width: 16,
|
|
1946
|
+
height: 16,
|
|
1947
|
+
borderRadius: 5,
|
|
1948
|
+
display: "inline-flex",
|
|
1949
|
+
alignItems: "center",
|
|
1950
|
+
justifyContent: "center",
|
|
1951
|
+
background: checked || indeterminate ? "#0B0B0B" : "#FFFFFF",
|
|
1952
|
+
border: `1px solid ${checked || indeterminate ? "#0B0B0B" : "#676767"}`,
|
|
1953
|
+
cursor: "pointer",
|
|
1954
|
+
flexShrink: 0,
|
|
1955
|
+
}}
|
|
1956
|
+
>
|
|
1957
|
+
{indeterminate ? (
|
|
1958
|
+
<Minus size={11} color="#FFFFFF" strokeWidth={3} />
|
|
1959
|
+
) : checked ? (
|
|
1960
|
+
<Check size={11} color="#FFFFFF" strokeWidth={3} />
|
|
1961
|
+
) : null}
|
|
1962
|
+
</span>
|
|
1963
|
+
);
|
|
1964
|
+
|
|
1965
|
+
const SELECT_COLUMN_WIDTH = 44;
|
|
1966
|
+
|
|
1867
1967
|
// Handle header click for sorting
|
|
1868
1968
|
const handleSort = (field) => {
|
|
1869
1969
|
if (isServerSideSorting && onSort) {
|
|
@@ -2804,6 +2904,14 @@ export default function DataTable2({
|
|
|
2804
2904
|
</div>
|
|
2805
2905
|
)}
|
|
2806
2906
|
|
|
2907
|
+
{/* Custom actions (e.g. bulk-update buttons) — kept left of the
|
|
2908
|
+
Columns picker so Columns stays the right-most control. */}
|
|
2909
|
+
{filtersConfig?.rightActions && (
|
|
2910
|
+
<div style={{ display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
|
|
2911
|
+
{filtersConfig.rightActions}
|
|
2912
|
+
</div>
|
|
2913
|
+
)}
|
|
2914
|
+
|
|
2807
2915
|
{/* Columns button — compact */}
|
|
2808
2916
|
{!hideColumnPicker && (
|
|
2809
2917
|
<div style={{ position: "relative" }}>
|
|
@@ -3038,6 +3146,33 @@ export default function DataTable2({
|
|
|
3038
3146
|
<thead>
|
|
3039
3147
|
{/* Header row with column labels */}
|
|
3040
3148
|
<tr>
|
|
3149
|
+
{selectable && (
|
|
3150
|
+
<th
|
|
3151
|
+
style={{
|
|
3152
|
+
width: SELECT_COLUMN_WIDTH,
|
|
3153
|
+
minWidth: SELECT_COLUMN_WIDTH,
|
|
3154
|
+
padding: '10px 8px',
|
|
3155
|
+
textAlign: 'center',
|
|
3156
|
+
verticalAlign: 'middle',
|
|
3157
|
+
background: '#f2f2f0',
|
|
3158
|
+
borderRight: '1px solid #e6e6e6',
|
|
3159
|
+
borderBottom: '1px solid #e6e6e6',
|
|
3160
|
+
position: 'sticky',
|
|
3161
|
+
top: 0,
|
|
3162
|
+
zIndex: 10,
|
|
3163
|
+
boxSizing: 'border-box',
|
|
3164
|
+
}}
|
|
3165
|
+
>
|
|
3166
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 0 }}>
|
|
3167
|
+
<SelectionCheckbox
|
|
3168
|
+
checked={allOnPageSelected}
|
|
3169
|
+
indeterminate={someOnPageSelected}
|
|
3170
|
+
onToggle={toggleSelectAllOnPage}
|
|
3171
|
+
ariaLabel="Select all rows on this page"
|
|
3172
|
+
/>
|
|
3173
|
+
</div>
|
|
3174
|
+
</th>
|
|
3175
|
+
)}
|
|
3041
3176
|
<SortableContext
|
|
3042
3177
|
items={visibleColumns}
|
|
3043
3178
|
strategy={horizontalListSortingStrategy}
|
|
@@ -3052,7 +3187,7 @@ export default function DataTable2({
|
|
|
3052
3187
|
{!isLoading && paginatedData.length === 0 ? (
|
|
3053
3188
|
<tr>
|
|
3054
3189
|
<td
|
|
3055
|
-
colSpan={orderedColumns.length}
|
|
3190
|
+
colSpan={orderedColumns.length + (selectable ? 1 : 0)}
|
|
3056
3191
|
style={{
|
|
3057
3192
|
padding: '32px',
|
|
3058
3193
|
textAlign: 'center',
|
|
@@ -3065,14 +3200,18 @@ export default function DataTable2({
|
|
|
3065
3200
|
</td>
|
|
3066
3201
|
</tr>
|
|
3067
3202
|
) : !isLoading && paginatedData.length > 0 ? (
|
|
3068
|
-
paginatedData.map((row, rowIndex) =>
|
|
3203
|
+
paginatedData.map((row, rowIndex) => {
|
|
3204
|
+
const rowId = resolveRowId(row, rowIndex);
|
|
3205
|
+
const isRowSelected = selectable && selectedIdSet.has(rowId);
|
|
3206
|
+
return (
|
|
3069
3207
|
<tr
|
|
3070
3208
|
key={rowIndex}
|
|
3071
3209
|
data-row-id={row.id || rowIndex}
|
|
3072
3210
|
style={{
|
|
3073
3211
|
borderBottom: '1px solid #e6e6e6',
|
|
3074
3212
|
cursor: onRowClick ? 'pointer' : 'default',
|
|
3075
|
-
transition: 'background 0.15s ease'
|
|
3213
|
+
transition: 'background 0.15s ease',
|
|
3214
|
+
background: isRowSelected ? '#F2F4F7' : 'transparent',
|
|
3076
3215
|
}}
|
|
3077
3216
|
onClick={onRowClick ? (e) => {
|
|
3078
3217
|
e.stopPropagation();
|
|
@@ -3082,9 +3221,31 @@ export default function DataTable2({
|
|
|
3082
3221
|
e.currentTarget.style.background = '#E6E6E6';
|
|
3083
3222
|
}}
|
|
3084
3223
|
onMouseLeave={(e) => {
|
|
3085
|
-
e.currentTarget.style.background = 'transparent';
|
|
3224
|
+
e.currentTarget.style.background = isRowSelected ? '#F2F4F7' : 'transparent';
|
|
3086
3225
|
}}
|
|
3087
3226
|
>
|
|
3227
|
+
{selectable && (
|
|
3228
|
+
<td
|
|
3229
|
+
onClick={(e) => e.stopPropagation()}
|
|
3230
|
+
style={{
|
|
3231
|
+
width: SELECT_COLUMN_WIDTH,
|
|
3232
|
+
minWidth: SELECT_COLUMN_WIDTH,
|
|
3233
|
+
padding: '10px 8px',
|
|
3234
|
+
textAlign: 'center',
|
|
3235
|
+
verticalAlign: 'middle',
|
|
3236
|
+
borderRight: '1px solid #e6e6e6',
|
|
3237
|
+
boxSizing: 'border-box',
|
|
3238
|
+
}}
|
|
3239
|
+
>
|
|
3240
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 0 }}>
|
|
3241
|
+
<SelectionCheckbox
|
|
3242
|
+
checked={isRowSelected}
|
|
3243
|
+
onToggle={() => toggleRowSelection(rowId)}
|
|
3244
|
+
ariaLabel="Select row"
|
|
3245
|
+
/>
|
|
3246
|
+
</div>
|
|
3247
|
+
</td>
|
|
3248
|
+
)}
|
|
3088
3249
|
{orderedColumns.map((column) => {
|
|
3089
3250
|
const columnId = getColumnId(column);
|
|
3090
3251
|
const resolvedWidth = getResolvedColumnWidth(columnId, column.width);
|
|
@@ -3123,7 +3284,8 @@ export default function DataTable2({
|
|
|
3123
3284
|
);
|
|
3124
3285
|
})}
|
|
3125
3286
|
</tr>
|
|
3126
|
-
|
|
3287
|
+
);
|
|
3288
|
+
})
|
|
3127
3289
|
) : null}
|
|
3128
3290
|
</tbody>
|
|
3129
3291
|
</table>
|