UPDATE: Adds cell and formula editing (#92)
* UPDATE: Adds cell and formula editing * FIX: Do not loose focus when clicking on the formula we are editing * FIX: Minimal implementation of browse mode * FIX: Initial browse mode within sheets * UPDATE: Webapp Minimal Web Application
This commit is contained in:
committed by
GitHub
parent
53d3d5144c
commit
48719b6416
@@ -1,10 +1,14 @@
|
||||
import type { Model } from "@ironcalc/wasm";
|
||||
import { type PointerEvent, type RefObject, useCallback, useRef } from "react";
|
||||
import type WorksheetCanvas from "./WorksheetCanvas/worksheetCanvas";
|
||||
import {
|
||||
headerColumnWidth,
|
||||
headerRowHeight,
|
||||
} from "./WorksheetCanvas/worksheetCanvas";
|
||||
import { isInReferenceMode } from "./editor/util";
|
||||
import type { Cell } from "./types";
|
||||
import { rangeToStr } from "./util";
|
||||
import type { WorkbookState } from "./workbookState";
|
||||
|
||||
interface PointerSettings {
|
||||
canvasElement: RefObject<HTMLCanvasElement>;
|
||||
@@ -15,6 +19,9 @@ interface PointerSettings {
|
||||
onAreaSelected: () => void;
|
||||
onExtendToCell: (cell: Cell) => void;
|
||||
onExtendToEnd: () => void;
|
||||
model: Model;
|
||||
workbookState: WorkbookState;
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
interface PointerEvents {
|
||||
@@ -27,6 +34,7 @@ interface PointerEvents {
|
||||
const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
const isSelecting = useRef(false);
|
||||
const isExtending = useRef(false);
|
||||
const isInsertingRef = useRef(false);
|
||||
|
||||
const onPointerMove = useCallback(
|
||||
(event: PointerEvent): void => {
|
||||
@@ -36,43 +44,50 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!(isSelecting.current || isExtending.current || isInsertingRef.current)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const { canvasElement, model, worksheetCanvas } = options;
|
||||
const canvas = canvasElement.current;
|
||||
const worksheet = worksheetCanvas.current;
|
||||
// Silence the linter
|
||||
if (!worksheet || !canvas) {
|
||||
return;
|
||||
}
|
||||
const canvasRect = canvas.getBoundingClientRect();
|
||||
const x = event.clientX - canvasRect.x;
|
||||
const y = event.clientY - canvasRect.y;
|
||||
|
||||
const cell = worksheet.getCellByCoordinates(x, y);
|
||||
if (!cell) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelecting.current) {
|
||||
const { canvasElement, worksheetCanvas } = options;
|
||||
const canvas = canvasElement.current;
|
||||
const worksheet = worksheetCanvas.current;
|
||||
// Silence the linter
|
||||
if (!worksheet || !canvas) {
|
||||
return;
|
||||
}
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
const canvasRect = canvas.getBoundingClientRect();
|
||||
x -= canvasRect.x;
|
||||
y -= canvasRect.y;
|
||||
const cell = worksheet.getCellByCoordinates(x, y);
|
||||
if (cell) {
|
||||
options.onAreaSelecting(cell);
|
||||
} else {
|
||||
console.log("Failed");
|
||||
}
|
||||
options.onAreaSelecting(cell);
|
||||
} else if (isExtending.current) {
|
||||
const { canvasElement, worksheetCanvas } = options;
|
||||
const canvas = canvasElement.current;
|
||||
const worksheet = worksheetCanvas.current;
|
||||
// Silence the linter
|
||||
if (!worksheet || !canvas) {
|
||||
return;
|
||||
}
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
const canvasRect = canvas.getBoundingClientRect();
|
||||
x -= canvasRect.x;
|
||||
y -= canvasRect.y;
|
||||
const cell = worksheet.getCellByCoordinates(x, y);
|
||||
if (!cell) {
|
||||
return;
|
||||
}
|
||||
options.onExtendToCell(cell);
|
||||
} else if (isInsertingRef.current) {
|
||||
const { refresh, workbookState } = options;
|
||||
const editingCell = workbookState.getEditingCell();
|
||||
if (!editingCell || !editingCell.referencedRange) {
|
||||
return;
|
||||
}
|
||||
const range = editingCell.referencedRange.range;
|
||||
range.rowEnd = cell.row;
|
||||
range.columnEnd = cell.column;
|
||||
|
||||
const sheetNames = model.getWorksheetsProperties().map((s) => s.name);
|
||||
|
||||
editingCell.referencedRange.str = rangeToStr(
|
||||
range,
|
||||
editingCell.sheet,
|
||||
sheetNames[range.sheet],
|
||||
);
|
||||
workbookState.setEditingCell(editingCell);
|
||||
refresh();
|
||||
}
|
||||
},
|
||||
[options],
|
||||
@@ -90,6 +105,10 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
isExtending.current = false;
|
||||
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
||||
options.onExtendToEnd();
|
||||
} else if (isInsertingRef.current) {
|
||||
const { worksheetElement } = options;
|
||||
isInsertingRef.current = false;
|
||||
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
},
|
||||
[options],
|
||||
@@ -99,7 +118,14 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
(event: PointerEvent) => {
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
const { canvasElement, worksheetElement, worksheetCanvas } = options;
|
||||
const {
|
||||
canvasElement,
|
||||
model,
|
||||
refresh,
|
||||
worksheetElement,
|
||||
worksheetCanvas,
|
||||
workbookState,
|
||||
} = options;
|
||||
const worksheet = worksheetCanvas.current;
|
||||
const canvas = canvasElement.current;
|
||||
const worksheetWrapper = worksheetElement.current;
|
||||
@@ -132,8 +158,60 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const editingCell = workbookState.getEditingCell();
|
||||
const cell = worksheet.getCellByCoordinates(x, y);
|
||||
if (cell) {
|
||||
if (editingCell) {
|
||||
if (
|
||||
cell.row === editingCell.row &&
|
||||
cell.column === editingCell.column
|
||||
) {
|
||||
// We are clicking on the cell we are editing
|
||||
// we do nothing
|
||||
return;
|
||||
}
|
||||
// now we are editing one cell and we click in another one
|
||||
// If we can insert a range we do that
|
||||
const text = editingCell.text;
|
||||
if (isInReferenceMode(text, editingCell.cursorEnd)) {
|
||||
const range = {
|
||||
sheet: model.getSelectedSheet(),
|
||||
rowStart: cell.row,
|
||||
rowEnd: cell.row,
|
||||
columnStart: cell.column,
|
||||
columnEnd: cell.column,
|
||||
};
|
||||
const sheetNames = model
|
||||
.getWorksheetsProperties()
|
||||
.map((s) => s.name);
|
||||
editingCell.referencedRange = {
|
||||
range,
|
||||
str: rangeToStr(
|
||||
range,
|
||||
editingCell.sheet,
|
||||
sheetNames[range.sheet],
|
||||
),
|
||||
};
|
||||
workbookState.setEditingCell(editingCell);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
isInsertingRef.current = true;
|
||||
worksheetWrapper.setPointerCapture(event.pointerId);
|
||||
refresh();
|
||||
return;
|
||||
}
|
||||
// We are clicking away but we are not in reference mode
|
||||
// We finish the editing
|
||||
workbookState.clearEditingCell();
|
||||
model.setUserInput(
|
||||
editingCell.sheet,
|
||||
editingCell.row,
|
||||
editingCell.column,
|
||||
editingCell.text,
|
||||
);
|
||||
// we continue to select the new cell
|
||||
}
|
||||
options.onCellSelected(cell, event);
|
||||
isSelecting.current = true;
|
||||
worksheetWrapper.setPointerCapture(event.pointerId);
|
||||
|
||||
Reference in New Issue
Block a user