import { useEffect, useRef, useState } from 'react' import { VariableSizeGrid } from 'react-window' import { COL_COUNT, ROW_COUNT, SHEET_NAMES, SpreadsheetProps } from '../types' import { getColumnLabel } from '../utils' import { CellRenderer } from './CellRenderer' // --- Spreadsheet Component --- export const Spreadsheet = ({ sheetType, columnWidths, spreadsheetWidths, getCachedCellData, selectedCell, activeSheet, isEditing, editingValue, handleCellClick, handleCellDoubleClick, handleCellChange, stopEditing, setActiveSheet, activeCellInputRef, containerRefs, handleKeyDown, headerRefs, rowHeaderRefs, gridRefs, onGridScroll, handleColumnResize, mergedCells, }: SpreadsheetProps) => { const widths = columnWidths const cachedData = getCachedCellData(sheetType) const itemData = { sheetType, widths, selectedCell, activeSheet, isEditing, editingValue, cachedData, mergedCells, handleCellClick, handleCellDoubleClick, handleCellChange, stopEditing, setActiveSheet, activeCellInputRef, } const parentRef = useRef(null) const [gridSize, setGridSize] = useState({ width: 0, height: 0 }) useEffect(() => { const parent = parentRef.current if (!parent) return const resizeObserver = new ResizeObserver(() => { const { width, height } = parent.getBoundingClientRect() const headerHeight = parent.querySelector('.column-headers')?.clientHeight || 0 setGridSize({ width, height: height - headerHeight }) }) resizeObserver.observe(parent) return () => resizeObserver.disconnect() }, []) return (
setActiveSheet(sheetType)} >
(containerRefs.current[sheetType] = el)} className="flex h-full flex-col overflow-hidden border bg-card shadow-sm" onKeyDown={handleKeyDown} tabIndex={0} > {/* Spreadsheet Body */}
{/* Row Headers */}
{/* Компактное обозначение листа */}
{SHEET_NAMES[sheetType]}
(rowHeaderRefs.current[sheetType] = el)} className="overflow-y-hidden" style={{ height: gridSize.height }} >
{Array.from({ length: ROW_COUNT }).map((_, rowIndex) => { const isActiveRow = selectedCell?.row === rowIndex && activeSheet === sheetType return (
{rowIndex + 1}
) })}
{/* Column Headers */}
(headerRefs.current[sheetType] = el)} className="column-headers overflow-x-hidden" >
{Array.from({ length: COL_COUNT }).map((_, i) => { const isActiveColumn = selectedCell?.col === i && activeSheet === sheetType const handleMouseDown = (e: React.MouseEvent) => { e.preventDefault() const startX = e.clientX const startWidth = widths[i] const handleMouseMove = (me: MouseEvent) => { const newWidth = startWidth + (me.clientX - startX) handleColumnResize(sheetType, i, newWidth) } const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove) document.removeEventListener('mouseup', handleMouseUp) } document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mouseup', handleMouseUp) } return (
{getColumnLabel(i)}
) })}
{/* Grid */}
(gridRefs.current[sheetType] = el) } columnCount={COL_COUNT} rowCount={ROW_COUNT} columnWidth={(index: number) => widths[index]} rowHeight={() => 28} height={gridSize.height} width={gridSize.width} itemData={itemData} overscanColumnCount={20} overscanRowCount={10} onScroll={e => onGridScroll(sheetType, e)} > {CellRenderer}
) }