Files
tnsu-approval-route/frontend/src/webparts/approvalAdmin/components/ui/DataTable.tsx
T
2026-07-30 06:11:24 +00:00

61 lines
1.9 KiB
TypeScript

import * as React from 'react';
import styles from './DataTable.module.scss';
export interface IColumn<T> {
key: string;
header: string;
render: (row: T) => React.ReactNode;
align?: 'left' | 'right' | 'center';
width?: string;
// Держит колонку у правого края видимой области при горизонтальной
// прокрутке — чтобы кнопки действий не уезжали за край на узких экранах.
sticky?: boolean;
}
export interface IDataTableProps<T> {
columns: IColumn<T>[];
rows: T[];
keyOf: (row: T) => string | number;
emptyMessage: string;
}
export function DataTable<T>({ columns, rows, keyOf, emptyMessage }: IDataTableProps<T>): React.ReactElement {
return (
<div className={styles.wrap}>
<div className={styles.scroll}>
<table className={styles.table}>
<thead>
<tr>
{columns.map(col => (
<th
key={col.key}
className={col.sticky ? styles.stickyCell : undefined}
style={{ width: col.width, textAlign: col.align ?? 'left' }}
>
{col.header}
</th>
))}
</tr>
</thead>
<tbody>
{rows.map(row => (
<tr key={keyOf(row)}>
{columns.map(col => (
<td
key={col.key}
className={col.sticky ? styles.stickyCell : undefined}
style={{ textAlign: col.align ?? 'left' }}
>
{col.render(row)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
{rows.length === 0 && <div className={styles.empty}>{emptyMessage}</div>}
</div>
);
}