|
|
|
|
@@ -3,6 +3,7 @@ import { type PointerEvent, type RefObject, useCallback, useRef } from "react";
|
|
|
|
|
import { isInReferenceMode } from "../Editor/util";
|
|
|
|
|
import type { Cell } from "../types";
|
|
|
|
|
import { rangeToStr } from "../util";
|
|
|
|
|
import { LAST_COLUMN, LAST_ROW } from "../WorksheetCanvas/constants";
|
|
|
|
|
import type WorksheetCanvas from "../WorksheetCanvas/worksheetCanvas";
|
|
|
|
|
import {
|
|
|
|
|
headerColumnWidth,
|
|
|
|
|
@@ -34,6 +35,10 @@ interface PointerEvents {
|
|
|
|
|
const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
const isSelecting = useRef(false);
|
|
|
|
|
const isInsertingRef = useRef(false);
|
|
|
|
|
const isSelectingRows = useRef(false);
|
|
|
|
|
const initialRowRef = useRef<number | null>(null);
|
|
|
|
|
const isSelectingColumns = useRef(false);
|
|
|
|
|
const initialColumnRef = useRef<number | null>(null);
|
|
|
|
|
|
|
|
|
|
const onPointerMove = useCallback(
|
|
|
|
|
(event: PointerEvent): void => {
|
|
|
|
|
@@ -43,10 +48,17 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(isSelecting.current || isInsertingRef.current)) {
|
|
|
|
|
if (
|
|
|
|
|
!(
|
|
|
|
|
isSelecting.current ||
|
|
|
|
|
isInsertingRef.current ||
|
|
|
|
|
isSelectingRows.current ||
|
|
|
|
|
isSelectingColumns.current
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const { canvasElement, model, worksheetCanvas } = options;
|
|
|
|
|
const { canvasElement, model, worksheetCanvas, refresh } = options;
|
|
|
|
|
const canvas = canvasElement.current;
|
|
|
|
|
const worksheet = worksheetCanvas.current;
|
|
|
|
|
// Silence the linter
|
|
|
|
|
@@ -57,6 +69,66 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
const x = event.clientX - canvasRect.x;
|
|
|
|
|
const y = event.clientY - canvasRect.y;
|
|
|
|
|
|
|
|
|
|
if (isSelectingRows.current) {
|
|
|
|
|
// Prevent text selection during row dragging
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
// Handle row selection dragging
|
|
|
|
|
if (initialRowRef.current === null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let targetRow: number | null = null;
|
|
|
|
|
if (x >= 0 && x < headerColumnWidth && y >= headerRowHeight) {
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(headerColumnWidth, y);
|
|
|
|
|
if (cell) targetRow = cell.row;
|
|
|
|
|
} else if (x >= headerColumnWidth && y >= headerRowHeight) {
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(x, y);
|
|
|
|
|
if (cell) targetRow = cell.row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (targetRow !== null) {
|
|
|
|
|
const initialRow = initialRowRef.current;
|
|
|
|
|
model.setSelectedCell(Math.min(initialRow, targetRow), 1);
|
|
|
|
|
model.setSelectedRange(
|
|
|
|
|
Math.min(initialRow, targetRow),
|
|
|
|
|
1,
|
|
|
|
|
Math.max(initialRow, targetRow),
|
|
|
|
|
LAST_COLUMN,
|
|
|
|
|
);
|
|
|
|
|
refresh();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isSelectingColumns.current) {
|
|
|
|
|
// Prevent text selection during column dragging
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
// Handle column selection dragging
|
|
|
|
|
if (initialColumnRef.current === null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let targetColumn: number | null = null;
|
|
|
|
|
if (x >= headerColumnWidth && y >= 0 && y < headerRowHeight) {
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(x, headerRowHeight);
|
|
|
|
|
if (cell) targetColumn = cell.column;
|
|
|
|
|
} else if (x >= headerColumnWidth && y >= headerRowHeight) {
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(x, y);
|
|
|
|
|
if (cell) targetColumn = cell.column;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (targetColumn !== null) {
|
|
|
|
|
const initialColumn = initialColumnRef.current;
|
|
|
|
|
model.setSelectedCell(1, Math.min(initialColumn, targetColumn));
|
|
|
|
|
model.setSelectedRange(
|
|
|
|
|
1,
|
|
|
|
|
Math.min(initialColumn, targetColumn),
|
|
|
|
|
LAST_ROW,
|
|
|
|
|
Math.max(initialColumn, targetColumn),
|
|
|
|
|
);
|
|
|
|
|
refresh();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(x, y);
|
|
|
|
|
if (!cell) {
|
|
|
|
|
return;
|
|
|
|
|
@@ -65,7 +137,7 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
if (isSelecting.current) {
|
|
|
|
|
options.onAreaSelecting(cell);
|
|
|
|
|
} else if (isInsertingRef.current) {
|
|
|
|
|
const { refresh, workbookState } = options;
|
|
|
|
|
const { workbookState } = options;
|
|
|
|
|
const editingCell = workbookState.getEditingCell();
|
|
|
|
|
if (!editingCell || !editingCell.referencedRange) {
|
|
|
|
|
return;
|
|
|
|
|
@@ -99,6 +171,16 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
const { worksheetElement } = options;
|
|
|
|
|
isInsertingRef.current = false;
|
|
|
|
|
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
|
|
|
|
} else if (isSelectingRows.current) {
|
|
|
|
|
const { worksheetElement } = options;
|
|
|
|
|
isSelectingRows.current = false;
|
|
|
|
|
initialRowRef.current = null;
|
|
|
|
|
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
|
|
|
|
} else if (isSelectingColumns.current) {
|
|
|
|
|
const { worksheetElement } = options;
|
|
|
|
|
isSelectingColumns.current = false;
|
|
|
|
|
initialColumnRef.current = null;
|
|
|
|
|
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[options],
|
|
|
|
|
@@ -157,7 +239,17 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
// Click on a row number
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(headerColumnWidth, y);
|
|
|
|
|
if (cell) {
|
|
|
|
|
onRowSelected(cell.row, event.shiftKey);
|
|
|
|
|
if (event.shiftKey) {
|
|
|
|
|
// Shift+click: extend selection
|
|
|
|
|
onRowSelected(cell.row, true);
|
|
|
|
|
} else {
|
|
|
|
|
// Regular click: start drag selection
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
initialRowRef.current = cell.row;
|
|
|
|
|
isSelectingRows.current = true;
|
|
|
|
|
worksheetWrapper.setPointerCapture(event.pointerId);
|
|
|
|
|
onRowSelected(cell.row, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (
|
|
|
|
|
x > headerColumnWidth &&
|
|
|
|
|
@@ -168,7 +260,17 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|
|
|
|
// Click on a column letter
|
|
|
|
|
const cell = worksheet.getCellByCoordinates(x, headerRowHeight);
|
|
|
|
|
if (cell) {
|
|
|
|
|
onColumnSelected(cell.column, event.shiftKey);
|
|
|
|
|
if (event.shiftKey) {
|
|
|
|
|
// Shift+click: extend selection
|
|
|
|
|
onColumnSelected(cell.column, true);
|
|
|
|
|
} else {
|
|
|
|
|
// Regular click: start drag selection
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
initialColumnRef.current = cell.column;
|
|
|
|
|
isSelectingColumns.current = true;
|
|
|
|
|
worksheetWrapper.setPointerCapture(event.pointerId);
|
|
|
|
|
onColumnSelected(cell.column, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|