import { useRef, useMemo } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { IconArrowUp, IconArrowDown, IconEdit, IconTrash, IconCopy } from '@tabler/icons-react';
import TableSkeleton from './TableSkeleton.jsx';
import EmptyState from './EmptyState.jsx';
import Tooltip from './Tooltip.jsx';
/**
* Виртуализированная таблица для больших списков данных (1000+ элементов)
* Рендерит только видимые строки для оптимальной производительности
*
* @param {Object} props
* @param {Array} props.columns - Массив описаний колонок
* @param {Array} props.items - Массив данных для отображения
* @param {string} props.itemKey - Ключ уникального идентификатора
* @param {boolean} props.loading - Состояние загрузки
* @param {string} props.sortField - Текущее поле сортировки
* @param {string} props.sortOrder - Направление сортировки
* @param {function} props.onSort - Обработчик сортировки
* @param {Set} props.selectedItems - Выбранные элементы
* @param {function} props.onSelectItem - Обработчик выбора
* @param {function} props.onSelectAll - Обработчик выбора всех
* @param {function} props.onEdit - Обработчик редактирования
* @param {function} props.onDelete - Обработчик удаления
* @param {function} props.onCopy - Обработчик копирования
* @param {number} props.rowHeight - Высота строки в пикселях (default: 48)
* @param {number} props.containerHeight - Высота контейнера (default: 600)
* @param {number} props.overscan - Количество дополнительных строк (default: 5)
* @param {Object} props.emptyState - Настройки пустого состояния
* @param {boolean} props.selectable - Включить чекбоксы (default: true)
*/
function VirtualizedTable({
columns = [],
items = [],
itemKey = 'id',
loading = false,
sortField,
sortOrder = 'asc',
onSort,
selectedItems = new Set(),
onSelectItem,
onSelectAll,
onDeselectAll,
onEdit,
onDelete,
onCopy,
rowHeight = 48,
containerHeight = 600,
overscan = 5,
emptyState,
selectable = true,
actions = [],
}) {
const parentRef = useRef(null);
const hasActions = onEdit || onDelete || onCopy || actions.length > 0;
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => rowHeight,
overscan,
});
const virtualItems = virtualizer.getVirtualItems();
const totalSize = virtualizer.getTotalSize();
// Рендер заголовка
const renderHeader = () => (
{selectable && (
);
// Рендер действий
const renderActions = (item) => (
<>
{onEdit && (
0 && items.every(i => selectedItems.has(i[itemKey]))}
onChange={(e) => e.target.checked ? onSelectAll?.() : onDeselectAll?.()}
title="Выбрать все"
/>
)}
{columns.map((col) => {
const isSortable = col.sortable !== false && onSort;
const isActive = sortField === col.key;
return (
onSort(col.key) : undefined}
style={col.width ? { width: col.width } : undefined}
>
);
})}
{hasActions && Действия }
| onSelectItem?.(id)} /> | )} {columns.map((col) => ({col.render ? col.render(item[col.key], item) : item[col.key]} | ))} {hasActions && ({renderActions(item)} | )}