Выдение ячеек по клику

This commit is contained in:
2025-07-22 05:55:43 +03:00
parent faad68cdc0
commit 1b17638565
6 changed files with 215 additions and 9 deletions

View File

@@ -19,6 +19,8 @@ import {
} from './types'
import {
convertReferencesToHighlights,
createCellAddress,
createQualifiedCellReference,
extractCellReferences,
getColumnLabel,
} from './utils'
@@ -67,6 +69,8 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
} | null>(null)
const [isEditing, setIsEditing] = useState(false)
const [editingValue, setEditingValue] = useState<string>('') // Локальное значение во время редактирования
// Источник ввода: 'cell' (редактирование внутри ячейки) или 'formula'
const [editingSource, setEditingSource] = useState<'cell' | 'formula'>('cell')
const [isInitialized, setIsInitialized] = useState(false)
const [baseFileData, setBaseFileData] = useState<
Record<string, Record<string, any>>
@@ -427,6 +431,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
}
setIsEditing(false)
setEditingValue('')
setEditingSource('cell')
containerRefs.current[activeSheet]?.focus({ preventScroll: true })
},
[activeSheet, selectedCell, editingValue, multiSheetEngine, updateRevision]
@@ -497,8 +502,14 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
ArrowDown: () => moveSelection(1, 0),
ArrowLeft: () => moveSelection(0, -1),
ArrowRight: () => moveSelection(0, 1),
Enter: () => startEditing(),
F2: () => startEditing(),
Enter: () => {
setEditingSource('cell')
startEditing()
},
F2: () => {
setEditingSource('cell')
startEditing()
},
Delete: handleClearCell,
Backspace: handleClearCell,
}
@@ -508,6 +519,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
keyHandlers[e.key]()
} else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
e.preventDefault()
setEditingSource('cell')
setEditingValue(e.key)
setIsEditing(true)
}
@@ -517,6 +529,13 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
const handleCellClick = useCallback(
(row: number, col: number) => {
console.log('🖱️ Обычный клик по ячейке:', {
row,
col,
isEditing,
activeSheet,
})
if (isEditing) {
stopEditing(true)
}
@@ -526,9 +545,71 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
[isEditing, stopEditing, activeSheet]
)
// Новый обработчик для кликов в режиме редактирования - вставляет ссылку
const handleCellReferenceClick = useCallback(
(targetSheetType: SheetType, row: number, col: number) => {
console.log('🔗 Клик для вставки ссылки:', {
targetSheetType,
row,
col,
isEditing,
selectedCell,
editingValue,
})
// Проверяем, что мы в режиме редактирования
if (!isEditing || !selectedCell) {
console.log(
'⚠️ Игнорируем клик ссылки: не в режиме редактирования или нет выбранной ячейки'
)
return
}
// Создаем ссылку на ячейку
let cellReference: string
// Если это другой лист, делаем квалифицированную ссылку
if (targetSheetType !== activeSheet) {
cellReference = createQualifiedCellReference(targetSheetType, row, col)
console.log('📋 Создана межлистовая ссылка:', cellReference)
} else {
// Если это тот же лист, делаем локальную ссылку
cellReference = createCellAddress(row, col)
console.log('📋 Создана локальная ссылка:', cellReference)
}
// Добавляем ссылку к текущему значению редактирования
const newValue = editingValue + cellReference
console.log('✏️ Новое значение формулы:', {
oldValue: editingValue,
newValue,
})
setEditingValue(newValue)
if (editingSource === 'formula') {
if (formulaBarRef.current) {
formulaBarRef.current.value = newValue
formulaBarRef.current.focus()
const length = newValue.length
formulaBarRef.current.setSelectionRange(length, length)
}
} else {
if (activeCellInputRef.current) {
activeCellInputRef.current.value = newValue
activeCellInputRef.current.focus({ preventScroll: true })
const length = newValue.length
activeCellInputRef.current.setSelectionRange(length, length)
}
}
},
[isEditing, selectedCell, editingValue, activeSheet, editingSource]
)
const handleCellDoubleClick = useCallback(
(row: number, col: number) => {
setSelectedCell({ row, col })
setEditingSource('cell')
startEditing()
},
[startEditing]
@@ -563,6 +644,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
const handleFormulaBarFocus = useCallback(() => {
if (selectedCell && !isEditing) {
setEditingSource('formula')
startEditing()
}
}, [selectedCell, isEditing, startEditing])
@@ -864,6 +946,8 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
handleCellClick={handleCellClick}
handleCellDoubleClick={handleCellDoubleClick}
handleCellChange={handleCellChange}
handleCellReferenceClick={handleCellReferenceClick}
isInEditMode={isEditing}
stopEditing={stopEditing}
setActiveSheet={setActiveSheet}
activeCellInputRef={activeCellInputRef}

View File

@@ -18,6 +18,8 @@ export const Cell = memo(
onCellClick,
onCellDoubleClick,
onCellValueChange,
onCellReferenceClick,
isInEditMode,
stopEditing,
setActiveSheet,
activeCellRef,
@@ -105,20 +107,89 @@ export const Cell = memo(
// Используем обычное значение displayValue для всех ячеек, включая объединенные
const cellDisplayValue = displayValue
const handleClick = useCallback(() => {
const handleClick = useCallback(
(e: React.MouseEvent) => {
console.log('🖱️ Cell клик:', {
rowIndex,
colIndex,
sheetType,
isInEditMode,
isSelected,
hasReferenceHandler: !!onCellReferenceClick,
})
// Если мы в режиме редактирования, вставка была обработана на mousedown.
// Останавливаем всплытие, чтобы родительский Spreadsheet не сменил активный лист.
if (isInEditMode) {
e.preventDefault()
e.stopPropagation()
return
}
// Обычная логика клика (выделение ячейки)
console.log('📍 Обычный клик - выбираем ячейку:', {
rowIndex,
colIndex,
sheetType,
})
// Подсказка для пользователя
if (!isInEditMode) {
console.log(
'💡 Чтобы вставить ссылку на ячейку: 1) Выберите ячейку 2) Нажмите F2 или Enter для редактирования 3) Кликните на нужную ячейку'
)
}
setActiveSheet(sheetType)
onCellClick(rowIndex, colIndex)
}, [setActiveSheet, sheetType, onCellClick, rowIndex, colIndex])
},
[
setActiveSheet,
sheetType,
onCellClick,
onCellReferenceClick,
rowIndex,
colIndex,
isInEditMode,
isSelected,
]
)
const handleDoubleClick = useCallback(
() => onCellDoubleClick(rowIndex, colIndex),
[onCellDoubleClick, rowIndex, colIndex]
)
const handleMouseDown = useCallback(
(e: React.MouseEvent) => {
// Используем mousedown, чтобы сработать раньше blur FormulaBar
if (isInEditMode && onCellReferenceClick && !isSelected) {
e.preventDefault()
e.stopPropagation()
console.log('🖱️ mousedown вставка ссылки до blur:', {
rowIndex,
colIndex,
sheetType,
})
onCellReferenceClick(sheetType, rowIndex, colIndex)
return
}
},
[
isInEditMode,
onCellReferenceClick,
isSelected,
sheetType,
rowIndex,
colIndex,
]
)
return (
<div
className={className}
style={cellStyle}
onMouseDown={handleMouseDown}
onClick={handleClick}
onDoubleClick={handleDoubleClick}
>

View File

@@ -22,6 +22,8 @@ export const CellRenderer = ({
handleCellClick,
handleCellDoubleClick,
handleCellChange,
handleCellReferenceClick,
isInEditMode,
stopEditing,
setActiveSheet,
activeCellInputRef,
@@ -99,6 +101,8 @@ export const CellRenderer = ({
onCellClick={handleCellClick}
onCellDoubleClick={handleCellDoubleClick}
onCellValueChange={handleCellChange}
onCellReferenceClick={handleCellReferenceClick}
isInEditMode={isEditing}
stopEditing={stopEditing}
setActiveSheet={setActiveSheet}
activeCellRef={activeCellInputRef}

View File

@@ -18,6 +18,8 @@ export const Spreadsheet = ({
handleCellClick,
handleCellDoubleClick,
handleCellChange,
handleCellReferenceClick,
isInEditMode,
stopEditing,
setActiveSheet,
activeCellInputRef,
@@ -46,11 +48,22 @@ export const Spreadsheet = ({
handleCellClick,
handleCellDoubleClick,
handleCellChange,
handleCellReferenceClick,
isInEditMode,
stopEditing,
setActiveSheet,
activeCellInputRef,
}
// Отладочное логирование для проверки состояния
console.log(`📊 Spreadsheet ${sheetType} состояние:`, {
isEditing,
isInEditMode,
selectedCell,
activeSheet,
isActiveSheet: activeSheet === sheetType,
})
const parentRef = useRef<HTMLDivElement>(null)
const [gridSize, setGridSize] = useState({ width: 0, height: 0 })

View File

@@ -56,9 +56,15 @@ export interface CellProps {
onCellClick: (row: number, col: number) => void
onCellDoubleClick: (row: number, col: number) => void
onCellValueChange: (newValue: string) => void // Изменение значения во время редактирования
onCellReferenceClick?: (
sheetType: SheetType,
row: number,
col: number
) => void // Клик для вставки ссылки
isInEditMode: boolean // Глобальный режим редактирования
stopEditing: (save: boolean) => void
setActiveSheet: (type: SheetType) => void
activeCellRef: React.RefObject<HTMLInputElement>
activeCellRef: React.RefObject<HTMLInputElement | null>
style: CSSProperties // Добавляем style для react-window
mergedCellInfo?: {
// Информация об объединенных ячейках
@@ -104,9 +110,15 @@ export interface CellRendererData {
handleCellClick: (row: number, col: number) => void
handleCellDoubleClick: (row: number, col: number) => void
handleCellChange: (newValue: string) => void
handleCellReferenceClick?: (
sheetType: SheetType,
row: number,
col: number
) => void // Клик для вставки ссылки
isInEditMode: boolean // Глобальный режим редактирования
stopEditing: (save: boolean) => void
setActiveSheet: (type: SheetType) => void
activeCellInputRef: React.RefObject<HTMLInputElement>
activeCellInputRef: React.RefObject<HTMLInputElement | null>
}
export interface CellRendererProps {
@@ -129,9 +141,15 @@ export interface SpreadsheetProps {
handleCellClick: (row: number, col: number) => void
handleCellDoubleClick: (row: number, col: number) => void
handleCellChange: (newValue: string) => void
handleCellReferenceClick?: (
sheetType: SheetType,
row: number,
col: number
) => void // Клик для вставки ссылки
isInEditMode: boolean // Глобальный режим редактирования
stopEditing: (save: boolean) => void
setActiveSheet: (type: SheetType) => void
activeCellInputRef: React.RefObject<HTMLInputElement>
activeCellInputRef: React.RefObject<HTMLInputElement | null>
containerRefs: React.MutableRefObject<
Record<SheetType, HTMLDivElement | null>
>

View File

@@ -11,6 +11,22 @@ export function getColumnLabel(index: number): string {
return label
}
// Создает адрес ячейки из координат (например, A1, B2)
export function createCellAddress(row: number, col: number): string {
return getColumnLabel(col) + (row + 1)
}
// Создает квалифицированную ссылку на ячейку с указанием листа
export function createQualifiedCellReference(
sheetType: 'report' | 'calculations',
row: number,
col: number
): string {
const sheetName = sheetType === 'report' ? 'L' : 'R'
const cellAddress = createCellAddress(row, col)
return `${sheetName}!${cellAddress}`
}
export function findMergedCellInfo(
row: number,
col: number,