@seedgrid/fe-components 2026.3.31-6 → 2026.3.31-7
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/inputs/SgDatatable.d.ts +6 -0
- package/dist/inputs/SgDatatable.d.ts.map +1 -1
- package/dist/inputs/SgDatatable.js +195 -56
- package/dist/sandbox.cjs +38 -38
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@ export type SgDatatableCellMeta<T extends SgDatatableRow> = {
|
|
|
27
27
|
rowData: T;
|
|
28
28
|
};
|
|
29
29
|
export type SgDatatableColumn<T extends SgDatatableRow = SgDatatableRow> = {
|
|
30
|
+
columnId?: string;
|
|
30
31
|
field?: string;
|
|
31
32
|
header: React.ReactNode;
|
|
32
33
|
body?: (rowData: T, meta: SgDatatableCellMeta<T>) => React.ReactNode;
|
|
@@ -43,6 +44,8 @@ export type SgDatatableColumn<T extends SgDatatableRow = SgDatatableRow> = {
|
|
|
43
44
|
width?: number | string;
|
|
44
45
|
minWidth?: number | string;
|
|
45
46
|
hidden?: boolean;
|
|
47
|
+
hideable?: boolean;
|
|
48
|
+
reorderable?: boolean;
|
|
46
49
|
className?: string;
|
|
47
50
|
headerClassName?: string;
|
|
48
51
|
bodyClassName?: string | ((rowData: T, rowIndex: number) => string | undefined);
|
|
@@ -97,6 +100,9 @@ export type SgDatatableProps<T extends SgDatatableRow = SgDatatableRow> = {
|
|
|
97
100
|
groupBoxProps?: Omit<Partial<SgGroupBoxProps>, "children" | "title"> & {
|
|
98
101
|
title?: string;
|
|
99
102
|
};
|
|
103
|
+
showColumnManager?: boolean;
|
|
104
|
+
columnManagerLabel?: string;
|
|
105
|
+
columnManagerMaxHeight?: number | string;
|
|
100
106
|
};
|
|
101
107
|
export declare const SgDatatable: <T extends SgDatatableRow>(props: SgDatatableProps<T> & {
|
|
102
108
|
ref?: React.Ref<SgDatatableRef<T>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgDatatable.d.ts","sourceRoot":"","sources":["../../src/inputs/SgDatatable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SgDatatable.d.ts","sourceRoot":"","sources":["../../src/inputs/SgDatatable.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
|
+
import { Check, GripVertical, SlidersHorizontal } from "lucide-react";
|
|
4
5
|
import { SgButton } from "../buttons/SgButton";
|
|
5
6
|
import { SgGroupBox } from "../layout/SgGroupBox";
|
|
6
7
|
import { t, useComponentsI18n } from "../i18n";
|
|
@@ -112,6 +113,28 @@ function rowsAreEqual(rowA, rowB, dataKey) {
|
|
|
112
113
|
return rowA === rowB;
|
|
113
114
|
return getRowIdentity(rowA, dataKey) === getRowIdentity(rowB, dataKey);
|
|
114
115
|
}
|
|
116
|
+
function getColumnKey(column, index) {
|
|
117
|
+
if (column.columnId?.trim())
|
|
118
|
+
return `columnId:${column.columnId.trim()}`;
|
|
119
|
+
if (column.field?.trim())
|
|
120
|
+
return `field:${column.field.trim()}`;
|
|
121
|
+
return `index:${index}`;
|
|
122
|
+
}
|
|
123
|
+
function moveItem(list, fromIndex, toIndex) {
|
|
124
|
+
if (fromIndex === toIndex)
|
|
125
|
+
return list;
|
|
126
|
+
if (fromIndex < 0 || fromIndex >= list.length)
|
|
127
|
+
return list;
|
|
128
|
+
if (toIndex < 0 || toIndex >= list.length)
|
|
129
|
+
return list;
|
|
130
|
+
const next = [...list];
|
|
131
|
+
const item = next[fromIndex];
|
|
132
|
+
if (item === undefined)
|
|
133
|
+
return list;
|
|
134
|
+
next.splice(fromIndex, 1);
|
|
135
|
+
next.splice(toIndex, 0, item);
|
|
136
|
+
return next;
|
|
137
|
+
}
|
|
115
138
|
function resolveAlignmentClass(align) {
|
|
116
139
|
if (align === "center")
|
|
117
140
|
return "text-center";
|
|
@@ -121,7 +144,7 @@ function resolveAlignmentClass(align) {
|
|
|
121
144
|
}
|
|
122
145
|
function SgDatatableBase(props, imperativeRef) {
|
|
123
146
|
const i18n = useComponentsI18n();
|
|
124
|
-
const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, sortField, sortOrder, onSort, removableSort = true, selectionMode, selection, onSelectionChange, showGlobalFilter = false, globalFilter, globalFilterPlaceholder, onGlobalFilterChange, showColumnFilters = false, filters, onFilter, showClearFiltersButton = false, stripedRows = false, showGridlines = false, hoverableRows = true, loading = false, emptyMessage, className = "", style, tableClassName = "", rowClassName, groupBoxProps = {} } = props;
|
|
147
|
+
const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, sortField, sortOrder, onSort, removableSort = true, selectionMode, selection, onSelectionChange, showGlobalFilter = false, globalFilter, globalFilterPlaceholder, onGlobalFilterChange, showColumnFilters = false, filters, onFilter, showClearFiltersButton = false, stripedRows = false, showGridlines = false, hoverableRows = true, loading = false, emptyMessage, className = "", style, tableClassName = "", rowClassName, groupBoxProps = {}, showColumnManager = true, columnManagerLabel, columnManagerMaxHeight = 320 } = props;
|
|
125
148
|
const isFirstControlled = first !== undefined;
|
|
126
149
|
const isSortFieldControlled = sortField !== undefined;
|
|
127
150
|
const isSortOrderControlled = sortOrder !== undefined;
|
|
@@ -135,6 +158,19 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
135
158
|
const [internalSelection, setInternalSelection] = React.useState(null);
|
|
136
159
|
const [internalGlobalFilter, setInternalGlobalFilter] = React.useState(globalFilter ?? "");
|
|
137
160
|
const [internalFilters, setInternalFilters] = React.useState(() => normalizeFilters(filters));
|
|
161
|
+
const columnManagerRef = React.useRef(null);
|
|
162
|
+
const [isColumnManagerOpen, setIsColumnManagerOpen] = React.useState(false);
|
|
163
|
+
const [draggingColumnKey, setDraggingColumnKey] = React.useState(null);
|
|
164
|
+
const columnDescriptors = React.useMemo(() => columns.map((column, index) => ({
|
|
165
|
+
key: getColumnKey(column, index),
|
|
166
|
+
column,
|
|
167
|
+
originalIndex: index
|
|
168
|
+
})), [columns]);
|
|
169
|
+
const [columnOrder, setColumnOrder] = React.useState(() => columnDescriptors.map((item) => item.key));
|
|
170
|
+
const [hiddenColumnsMap, setHiddenColumnsMap] = React.useState(() => columnDescriptors.reduce((acc, item) => {
|
|
171
|
+
acc[item.key] = Boolean(item.column.hidden);
|
|
172
|
+
return acc;
|
|
173
|
+
}, {}));
|
|
138
174
|
React.useEffect(() => {
|
|
139
175
|
if (!isFirstControlled)
|
|
140
176
|
return;
|
|
@@ -168,7 +204,42 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
168
204
|
return;
|
|
169
205
|
setInternalFilters(normalizeFilters(filters));
|
|
170
206
|
}, [isFiltersControlled, filters]);
|
|
171
|
-
|
|
207
|
+
React.useEffect(() => {
|
|
208
|
+
const availableKeys = columnDescriptors.map((item) => item.key);
|
|
209
|
+
setColumnOrder((prev) => {
|
|
210
|
+
const kept = prev.filter((key) => availableKeys.includes(key));
|
|
211
|
+
const missing = availableKeys.filter((key) => !kept.includes(key));
|
|
212
|
+
return [...kept, ...missing];
|
|
213
|
+
});
|
|
214
|
+
setHiddenColumnsMap((prev) => {
|
|
215
|
+
const next = {};
|
|
216
|
+
for (const item of columnDescriptors) {
|
|
217
|
+
next[item.key] = prev[item.key] ?? Boolean(item.column.hidden);
|
|
218
|
+
}
|
|
219
|
+
return next;
|
|
220
|
+
});
|
|
221
|
+
}, [columnDescriptors]);
|
|
222
|
+
React.useEffect(() => {
|
|
223
|
+
if (!isColumnManagerOpen)
|
|
224
|
+
return;
|
|
225
|
+
const handlePointerDown = (event) => {
|
|
226
|
+
if (!columnManagerRef.current)
|
|
227
|
+
return;
|
|
228
|
+
if (columnManagerRef.current.contains(event.target))
|
|
229
|
+
return;
|
|
230
|
+
setIsColumnManagerOpen(false);
|
|
231
|
+
};
|
|
232
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
233
|
+
return () => document.removeEventListener("mousedown", handlePointerDown);
|
|
234
|
+
}, [isColumnManagerOpen]);
|
|
235
|
+
const orderedColumns = React.useMemo(() => {
|
|
236
|
+
const map = new Map(columnDescriptors.map((item) => [item.key, item]));
|
|
237
|
+
return columnOrder
|
|
238
|
+
.map((key) => map.get(key))
|
|
239
|
+
.filter((item) => Boolean(item));
|
|
240
|
+
}, [columnDescriptors, columnOrder]);
|
|
241
|
+
const visibleColumns = React.useMemo(() => orderedColumns.filter((item) => !hiddenColumnsMap[item.key]).map((item) => item.column), [orderedColumns, hiddenColumnsMap]);
|
|
242
|
+
const visibleColumnCount = React.useMemo(() => orderedColumns.filter((item) => !hiddenColumnsMap[item.key]).length, [orderedColumns, hiddenColumnsMap]);
|
|
172
243
|
const currentFirst = isFirstControlled ? Math.max(0, first ?? 0) : internalFirst;
|
|
173
244
|
const currentRows = Math.max(1, internalRows);
|
|
174
245
|
const currentSortField = isSortFieldControlled ? sortField ?? null : internalSortField;
|
|
@@ -379,61 +450,129 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
379
450
|
: [...previous, rowData];
|
|
380
451
|
commitSelection(next);
|
|
381
452
|
}, [selectionMode, currentSelection, dataKey, commitSelection]);
|
|
453
|
+
const resolvedColumnManagerLabel = columnManagerLabel ??
|
|
454
|
+
resolveMessage(t(i18n, "components.datatable.columns"), "components.datatable.columns", "Colunas");
|
|
455
|
+
const restoreColumnsLabel = resolveMessage(t(i18n, "components.datatable.restoreColumns"), "components.datatable.restoreColumns", "Restaurar padrão");
|
|
456
|
+
const showAllColumnsLabel = resolveMessage(t(i18n, "components.datatable.showAllColumns"), "components.datatable.showAllColumns", "Mostrar todas");
|
|
457
|
+
const dragHandleLabel = resolveMessage(t(i18n, "components.datatable.dragToReorder"), "components.datatable.dragToReorder", "Arrastar para reordenar");
|
|
458
|
+
const toggleColumnVisibility = React.useCallback((columnKey, forceVisible) => {
|
|
459
|
+
setHiddenColumnsMap((prev) => {
|
|
460
|
+
const isCurrentlyHidden = Boolean(prev[columnKey]);
|
|
461
|
+
const willHide = forceVisible === undefined ? !isCurrentlyHidden : !forceVisible;
|
|
462
|
+
if (willHide && visibleColumnCount <= 1) {
|
|
463
|
+
return prev;
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
...prev,
|
|
467
|
+
[columnKey]: willHide
|
|
468
|
+
};
|
|
469
|
+
});
|
|
470
|
+
}, [visibleColumnCount]);
|
|
471
|
+
const handleReorderColumn = React.useCallback((fromKey, toKey) => {
|
|
472
|
+
setColumnOrder((prev) => {
|
|
473
|
+
const fromIndex = prev.indexOf(fromKey);
|
|
474
|
+
const toIndex = prev.indexOf(toKey);
|
|
475
|
+
if (fromIndex < 0 || toIndex < 0)
|
|
476
|
+
return prev;
|
|
477
|
+
return moveItem(prev, fromIndex, toIndex);
|
|
478
|
+
});
|
|
479
|
+
}, []);
|
|
480
|
+
const restoreDefaultColumns = React.useCallback(() => {
|
|
481
|
+
setColumnOrder(columnDescriptors.map((item) => item.key));
|
|
482
|
+
setHiddenColumnsMap(columnDescriptors.reduce((acc, item) => {
|
|
483
|
+
acc[item.key] = Boolean(item.column.hidden);
|
|
484
|
+
return acc;
|
|
485
|
+
}, {}));
|
|
486
|
+
}, [columnDescriptors]);
|
|
487
|
+
const showAllColumns = React.useCallback(() => {
|
|
488
|
+
setHiddenColumnsMap((prev) => {
|
|
489
|
+
const next = { ...prev };
|
|
490
|
+
for (const item of columnDescriptors) {
|
|
491
|
+
next[item.key] = false;
|
|
492
|
+
}
|
|
493
|
+
return next;
|
|
494
|
+
});
|
|
495
|
+
}, [columnDescriptors]);
|
|
382
496
|
const resolvedTitle = (groupBoxProps.title ?? title ?? "").trim() || " ";
|
|
383
|
-
return (_jsx("div", { className: className, style: style, children: _jsx(SgGroupBox, { ...groupBoxProps, title: resolvedTitle, children: _jsxs("div", { className: "space-y-3", children: [shouldShowToolbar ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showGlobalFilter ? (_jsx("input", { value: currentGlobalFilter, onChange: (event) => commitFilters(currentFilters, event.target.value), placeholder: globalFilterLabel, className: "min-w-[220px] flex-1 rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-3 py-2 text-sm text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null, showClearFiltersButton ? (_jsx(SgButton, { size: "sm", appearance: "outline", onClick: clearFilters, children: clearFiltersLabel })) : null] })) : null,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
? column.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
497
|
+
return (_jsx("div", { className: className, style: style, children: _jsx(SgGroupBox, { ...groupBoxProps, title: resolvedTitle, children: _jsxs("div", { className: "space-y-3", children: [shouldShowToolbar ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showGlobalFilter ? (_jsx("input", { value: currentGlobalFilter, onChange: (event) => commitFilters(currentFilters, event.target.value), placeholder: globalFilterLabel, className: "min-w-[220px] flex-1 rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-3 py-2 text-sm text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null, showClearFiltersButton ? (_jsx(SgButton, { size: "sm", appearance: "outline", onClick: clearFilters, children: clearFiltersLabel })) : null] })) : null, _jsxs("div", { className: "relative", ref: columnManagerRef, children: [showColumnManager ? (_jsx("div", { className: "mb-2 flex items-center justify-start", children: _jsx("button", { type: "button", "aria-label": resolvedColumnManagerLabel, title: resolvedColumnManagerLabel, onClick: () => setIsColumnManagerOpen((prev) => !prev), className: "inline-flex h-9 w-9 items-center justify-center rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] text-[rgb(var(--sg-primary-600))] shadow-sm transition hover:bg-[rgb(var(--sg-primary-50))] hover:text-[rgb(var(--sg-primary-700))]", children: _jsx(SlidersHorizontal, { size: 18 }) }) })) : null, showColumnManager && isColumnManagerOpen ? (_jsxs("div", { className: "absolute left-0 top-11 z-30 w-[300px] rounded-xl border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] shadow-xl", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-[rgb(var(--sg-border))] px-4 py-3", children: [_jsx(SlidersHorizontal, { size: 18, className: "text-[rgb(var(--sg-primary-600))]" }), _jsx("span", { className: "text-sm font-semibold text-[rgb(var(--sg-text))]", children: resolvedColumnManagerLabel })] }), _jsx("div", { className: "overflow-y-auto px-2 py-2", style: { maxHeight: toCssSize(columnManagerMaxHeight) }, children: _jsx("div", { className: "space-y-1", children: orderedColumns.map((item) => {
|
|
498
|
+
const isHidden = Boolean(hiddenColumnsMap[item.key]);
|
|
499
|
+
const isHideable = item.column.hideable !== false;
|
|
500
|
+
const isReorderable = item.column.reorderable !== false;
|
|
501
|
+
const canHideThisColumn = isHideable && (!isHidden ? visibleColumnCount > 1 : true);
|
|
502
|
+
const columnLabel = typeof item.column.header === "string" || typeof item.column.header === "number"
|
|
503
|
+
? String(item.column.header)
|
|
504
|
+
: item.column.field ?? item.key;
|
|
505
|
+
return (_jsxs("div", { draggable: isReorderable, onDragStart: () => setDraggingColumnKey(item.key), onDragOver: (event) => {
|
|
506
|
+
if (!isReorderable)
|
|
507
|
+
return;
|
|
508
|
+
event.preventDefault();
|
|
509
|
+
}, onDrop: (event) => {
|
|
510
|
+
event.preventDefault();
|
|
511
|
+
if (!isReorderable)
|
|
512
|
+
return;
|
|
513
|
+
if (!draggingColumnKey || draggingColumnKey === item.key)
|
|
514
|
+
return;
|
|
515
|
+
handleReorderColumn(draggingColumnKey, item.key);
|
|
516
|
+
setDraggingColumnKey(null);
|
|
517
|
+
}, onDragEnd: () => setDraggingColumnKey(null), className: cn("flex items-center gap-3 rounded-md px-2 py-2", draggingColumnKey === item.key ? "opacity-60" : "", "hover:bg-[rgb(var(--sg-primary-50))]"), children: [_jsx("button", { type: "button", disabled: !canHideThisColumn, onClick: () => toggleColumnVisibility(item.key), className: cn("inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md border transition", !isHidden
|
|
518
|
+
? "border-[rgb(var(--sg-primary-600))] bg-[rgb(var(--sg-primary-600))] text-white"
|
|
519
|
+
: "border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] text-transparent", !canHideThisColumn ? "cursor-not-allowed opacity-50" : "hover:scale-[1.02]"), children: _jsx(Check, { size: 14 }) }), _jsx("button", { type: "button", disabled: !canHideThisColumn, onClick: () => toggleColumnVisibility(item.key), className: cn("flex-1 truncate text-left text-sm", isHidden
|
|
520
|
+
? "text-[rgb(var(--sg-muted))]"
|
|
521
|
+
: "text-[rgb(var(--sg-text))]", !canHideThisColumn ? "cursor-not-allowed" : ""), children: columnLabel }), _jsx("div", { className: cn("inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-[rgb(var(--sg-muted))]", isReorderable ? "cursor-grab active:cursor-grabbing" : "opacity-40"), title: dragHandleLabel, children: _jsx(GripVertical, { size: 16 }) })] }, `manager-${item.key}`));
|
|
522
|
+
}) }) }), _jsxs("div", { className: "flex items-center gap-2 border-t border-[rgb(var(--sg-border))] px-3 py-3", children: [_jsx(SgButton, { size: "sm", appearance: "outline", onClick: restoreDefaultColumns, children: restoreColumnsLabel }), _jsx(SgButton, { size: "sm", appearance: "outline", onClick: showAllColumns, children: showAllColumnsLabel })] })] })) : null, _jsx("div", { className: "overflow-x-auto rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))]", children: _jsxs("table", { id: id, className: cn("min-w-full border-collapse text-sm", tableClassName), children: [_jsxs("thead", { children: [_jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
|
|
523
|
+
const sortCandidate = column.sortField ?? column.field;
|
|
524
|
+
const isSorted = Boolean(sortCandidate) && sortCandidate === currentSortField;
|
|
525
|
+
const sortIcon = !column.sortable
|
|
526
|
+
? null
|
|
527
|
+
: isSorted
|
|
528
|
+
? currentSortOrder === 1
|
|
529
|
+
? " ^"
|
|
530
|
+
: currentSortOrder === -1
|
|
531
|
+
? " v"
|
|
532
|
+
: " <>"
|
|
533
|
+
: " <>";
|
|
534
|
+
return (_jsx("th", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.headerClassName, column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: column.sortable ? (_jsxs("button", { type: "button", onClick: () => handleHeaderSort(column), className: cn("inline-flex items-center gap-1 font-semibold", resolveAlignmentClass(column.align), "text-[rgb(var(--sg-text))] hover:text-[rgb(var(--sg-primary-600))]"), children: [_jsx("span", { children: column.header }), _jsx("span", { "aria-hidden": "true", children: sortIcon })] })) : (_jsx("span", { children: column.header })) }, `head-${column.columnId ?? column.field ?? columnIndex}`));
|
|
535
|
+
}) }), shouldShowFiltersRow ? (_jsx("tr", { children: visibleColumns.map((column, columnIndex) => {
|
|
536
|
+
const filterField = column.filterField ?? column.field;
|
|
537
|
+
const filterValue = filterField ? currentFilters[filterField] ?? "" : "";
|
|
538
|
+
return (_jsx("th", { className: cn("px-3 py-2 align-top", showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]"), children: column.filter && filterField ? (_jsx("input", { value: filterValue, onChange: (event) => {
|
|
539
|
+
const nextFilters = {
|
|
540
|
+
...currentFilters,
|
|
541
|
+
[filterField]: event.target.value
|
|
542
|
+
};
|
|
543
|
+
const normalized = normalizeFilters(nextFilters);
|
|
544
|
+
commitFilters(normalized, currentGlobalFilter);
|
|
545
|
+
}, placeholder: column.filterPlaceholder ?? t(i18n, "components.datatable.columnFilterPlaceholder", { column: String(column.header ?? "") }), className: "w-full rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-1 text-xs text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null }, `filter-${column.columnId ?? column.field ?? columnIndex}`));
|
|
546
|
+
}) })) : null] }), _jsx("tbody", { children: loading ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: loadingLabel }) })) : pagedRows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: emptyLabel }) })) : (pagedRows.map((rowData, rowIndex) => {
|
|
547
|
+
const absoluteRowIndex = safeFirst + rowIndex;
|
|
548
|
+
const selected = isRowSelected(rowData);
|
|
549
|
+
const customRowClass = typeof rowClassName === "function" ? rowClassName(rowData, absoluteRowIndex) : rowClassName;
|
|
550
|
+
return (_jsx("tr", { "aria-selected": selected || undefined, onClick: (event) => {
|
|
551
|
+
const target = event.target;
|
|
552
|
+
if (target.closest("button,a,input,select,textarea,label,[data-sg-stop-row-select='true']")) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
handleRowSelection(rowData);
|
|
556
|
+
}, className: cn(selectionMode ? "cursor-pointer" : "", stripedRows && absoluteRowIndex % 2 === 1 ? "bg-[rgb(var(--sg-primary-50))]" : "", hoverableRows ? "hover:bg-[rgb(var(--sg-primary-100))]" : "", selected ? "bg-[rgb(var(--sg-primary-100))]" : "", customRowClass), children: visibleColumns.map((column, columnIndex) => {
|
|
557
|
+
const cellField = column.field;
|
|
558
|
+
const cellValue = getFieldValue(rowData, cellField);
|
|
559
|
+
const customCellClass = typeof column.bodyClassName === "function"
|
|
560
|
+
? column.bodyClassName(rowData, absoluteRowIndex)
|
|
561
|
+
: column.bodyClassName;
|
|
562
|
+
const renderedValue = column.body
|
|
563
|
+
? column.body(rowData, {
|
|
564
|
+
rowData,
|
|
565
|
+
rowIndex: absoluteRowIndex,
|
|
566
|
+
field: cellField,
|
|
567
|
+
value: cellValue
|
|
568
|
+
})
|
|
569
|
+
: (_jsx("span", { children: cellValue === null || cellValue === undefined ? "-" : String(cellValue) }));
|
|
570
|
+
return (_jsx("td", { className: cn("px-3 py-2 text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.className, customCellClass), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: renderedValue }, `cell-${column.columnId ?? cellField ?? columnIndex}-${absoluteRowIndex}`));
|
|
571
|
+
}) }, String(getRowIdentity(rowData, dataKey) ?? absoluteRowIndex)));
|
|
572
|
+
})) }), hasFooter ? (_jsx("tfoot", { children: _jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
|
|
573
|
+
const footerValue = typeof column.footer === "function" ? column.footer(sortedRows) : column.footer;
|
|
574
|
+
return (_jsx("td", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-t border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-t border-[rgb(var(--sg-border))]", column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: footerValue ?? null }, `foot-${column.columnId ?? column.field ?? columnIndex}`));
|
|
575
|
+
}) }) })) : null] }) })] }), paginator ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage <= 1, onClick: () => goToPage(currentPage - 1), children: prevLabel }), pageWindow.map((pageNumber) => (_jsx(SgButton, { size: "sm", appearance: pageNumber === currentPage ? "solid" : "outline", onClick: () => goToPage(pageNumber), children: String(pageNumber) }, `page-${pageNumber}`))), _jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage >= pageCount, onClick: () => goToPage(currentPage + 1), children: nextLabel }), _jsx("span", { className: "min-w-[180px] text-xs text-[rgb(var(--sg-muted))] md:ml-auto", children: pageReport }), rowsPerPageOptions && rowsPerPageOptions.length > 0 ? (_jsxs("label", { className: "ml-auto inline-flex items-center gap-2 text-xs text-[rgb(var(--sg-muted))] md:ml-0", children: [_jsx("span", { children: rowsPerPageLabel }), _jsx("select", { value: currentRows, onChange: (event) => {
|
|
437
576
|
const nextRows = Number(event.target.value) || currentRows;
|
|
438
577
|
commitPage(0, nextRows);
|
|
439
578
|
}, className: "rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-1 text-xs text-[rgb(var(--sg-input-fg,var(--sg-text)))]", children: rowsPerPageOptions.map((option) => (_jsx("option", { value: option, children: option }, option))) })] })) : null] })) : null] }) }) }));
|