2023-12-17 20:19:28 +03:00
|
|
|
import { Cell, flexRender, Row, Table } from '@tanstack/react-table';
|
2024-05-02 21:19:23 +03:00
|
|
|
import clsx from 'clsx';
|
2023-12-17 20:19:28 +03:00
|
|
|
|
2024-04-07 19:45:07 +03:00
|
|
|
import { CProps } from '@/components/props';
|
|
|
|
|
2023-12-17 20:19:28 +03:00
|
|
|
import { IConditionalStyle } from '.';
|
|
|
|
import SelectRow from './SelectRow';
|
|
|
|
|
|
|
|
interface TableBodyProps<TData> {
|
2023-12-28 14:04:44 +03:00
|
|
|
table: Table<TData>;
|
|
|
|
dense?: boolean;
|
2024-05-02 21:19:23 +03:00
|
|
|
noHeader?: boolean;
|
2023-12-28 14:04:44 +03:00
|
|
|
enableRowSelection?: boolean;
|
|
|
|
conditionalRowStyles?: IConditionalStyle<TData>[];
|
2024-03-25 23:10:29 +03:00
|
|
|
|
|
|
|
lastSelected: string | undefined;
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeLastSelected: (newValue: string | undefined) => void;
|
2024-03-25 23:10:29 +03:00
|
|
|
|
2024-04-07 19:45:07 +03:00
|
|
|
onRowClicked?: (rowData: TData, event: CProps.EventMouse) => void;
|
|
|
|
onRowDoubleClicked?: (rowData: TData, event: CProps.EventMouse) => void;
|
2023-12-17 20:19:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function TableBody<TData>({
|
2023-12-28 14:04:44 +03:00
|
|
|
table,
|
|
|
|
dense,
|
2024-05-02 21:19:23 +03:00
|
|
|
noHeader,
|
2023-12-17 20:19:28 +03:00
|
|
|
enableRowSelection,
|
|
|
|
conditionalRowStyles,
|
2024-03-25 23:10:29 +03:00
|
|
|
lastSelected,
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeLastSelected,
|
2023-12-28 14:04:44 +03:00
|
|
|
onRowClicked,
|
|
|
|
onRowDoubleClicked
|
2023-12-17 20:19:28 +03:00
|
|
|
}: TableBodyProps<TData>) {
|
2024-04-07 19:45:07 +03:00
|
|
|
function handleRowClicked(target: Row<TData>, event: CProps.EventMouse) {
|
2024-12-04 22:53:01 +03:00
|
|
|
onRowClicked?.(target.original, event);
|
2024-03-25 23:10:29 +03:00
|
|
|
if (enableRowSelection && target.getCanSelect()) {
|
|
|
|
if (event.shiftKey && !!lastSelected && lastSelected !== target.id) {
|
|
|
|
const { rows, rowsById } = table.getRowModel();
|
|
|
|
const lastIndex = rowsById[lastSelected].index;
|
|
|
|
const currentIndex = target.index;
|
|
|
|
const toggleRows = rows.slice(
|
|
|
|
lastIndex > currentIndex ? currentIndex : lastIndex + 1,
|
|
|
|
lastIndex > currentIndex ? lastIndex : currentIndex + 1
|
|
|
|
);
|
2024-08-06 14:39:00 +03:00
|
|
|
const newSelection: Record<string, boolean> = {};
|
2024-03-25 23:10:29 +03:00
|
|
|
toggleRows.forEach(row => {
|
|
|
|
newSelection[row.id] = !target.getIsSelected();
|
|
|
|
});
|
|
|
|
table.setRowSelection(prev => ({ ...prev, ...newSelection }));
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeLastSelected(undefined);
|
2024-03-25 23:10:29 +03:00
|
|
|
} else {
|
2024-11-21 00:26:16 +03:00
|
|
|
onChangeLastSelected(target.id);
|
2024-03-25 23:10:29 +03:00
|
|
|
target.toggleSelected(!target.getIsSelected());
|
|
|
|
}
|
2023-12-17 20:19:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getRowStyles(row: Row<TData>) {
|
2023-12-28 14:04:44 +03:00
|
|
|
return {
|
|
|
|
...conditionalRowStyles!
|
|
|
|
.filter(item => item.when(row.original))
|
|
|
|
.reduce((prev, item) => ({ ...prev, ...item.style }), {})
|
|
|
|
};
|
2023-12-17 20:19:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<tbody>
|
2023-12-28 14:04:44 +03:00
|
|
|
{table.getRowModel().rows.map((row: Row<TData>, index) => (
|
|
|
|
<tr
|
|
|
|
key={row.id}
|
2024-05-02 21:19:23 +03:00
|
|
|
className={clsx(
|
2024-05-14 19:16:04 +03:00
|
|
|
'cc-scroll-row',
|
2024-05-02 21:19:23 +03:00
|
|
|
!noHeader && 'scroll-mt-[calc(2px+2rem)]',
|
2023-12-28 14:04:44 +03:00
|
|
|
row.getIsSelected()
|
|
|
|
? 'clr-selected clr-hover'
|
|
|
|
: index % 2 === 0
|
|
|
|
? 'clr-controls clr-hover'
|
|
|
|
: 'clr-app clr-hover'
|
2024-05-02 21:19:23 +03:00
|
|
|
)}
|
|
|
|
style={{ ...(conditionalRowStyles ? getRowStyles(row) : []) }}
|
2023-12-28 14:04:44 +03:00
|
|
|
>
|
|
|
|
{enableRowSelection ? (
|
2024-03-18 16:21:39 +03:00
|
|
|
<td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'>
|
2024-11-21 00:26:16 +03:00
|
|
|
<SelectRow row={row} onChangeLastSelected={onChangeLastSelected} />
|
2023-12-28 14:04:44 +03:00
|
|
|
</td>
|
|
|
|
) : null}
|
|
|
|
{row.getVisibleCells().map((cell: Cell<TData, unknown>) => (
|
|
|
|
<td
|
|
|
|
key={cell.id}
|
2024-03-18 16:21:39 +03:00
|
|
|
className='px-2 align-middle border-y'
|
2023-12-28 14:04:44 +03:00
|
|
|
style={{
|
|
|
|
cursor: onRowClicked || onRowDoubleClicked ? 'pointer' : 'auto',
|
|
|
|
paddingBottom: dense ? '0.25rem' : '0.5rem',
|
2024-09-27 15:29:03 +03:00
|
|
|
paddingTop: dense ? '0.25rem' : '0.5rem',
|
|
|
|
width: noHeader && index === 0 ? `calc(var(--col-${cell.column.id}-size) * 1px)` : 'auto'
|
2023-12-28 14:04:44 +03:00
|
|
|
}}
|
|
|
|
onClick={event => handleRowClicked(row, event)}
|
|
|
|
onDoubleClick={event => (onRowDoubleClicked ? onRowDoubleClicked(row.original, event) : undefined)}
|
|
|
|
>
|
|
|
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
|
|
</td>
|
|
|
|
))}
|
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
);
|
2023-12-17 20:19:28 +03:00
|
|
|
}
|
|
|
|
|
2023-12-28 14:04:44 +03:00
|
|
|
export default TableBody;
|