From 90cf5f74f74006b5985244dae2f63c289d5e7670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher?= Date: Fri, 27 Sep 2024 19:25:26 +0200 Subject: [PATCH] FIX: Do not loose focus when clicking on the formula we are editing --- webapp/src/components/editor/editor.tsx | 9 ++++-- webapp/src/components/formulabar.tsx | 8 +---- webapp/src/components/usePointer.ts | 32 ++++++++++++++++++- webapp/src/components/workbook.tsx | 42 +++++++++++++++---------- webapp/src/components/worksheet.tsx | 18 +++-------- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/webapp/src/components/editor/editor.tsx b/webapp/src/components/editor/editor.tsx index 56f4703..a305347 100644 --- a/webapp/src/components/editor/editor.tsx +++ b/webapp/src/components/editor/editor.tsx @@ -193,7 +193,7 @@ const Editor = (options: EditorOptions) => { const isCellEditing = workbookState.getEditingCell() !== null; const showEditor = - isCellEditing && (display || type === "formula-bar") ? "block" : "none"; + (isCellEditing && display) || type === "formula-bar" ? "block" : "none"; return (
{ resize: "none", border: "none", height, - display: display ? "block" : "none", overflow: "hidden", }} defaultValue={text} spellCheck="false" onKeyDown={onKeyDown} onBlur={onChange} + onClick={(event) => { + // Prevents this from bubbling up and focusing on the spreadsheet + if (isCellEditing && type === "cell") { + event.stopPropagation(); + } + }} />
); diff --git a/webapp/src/components/formulabar.tsx b/webapp/src/components/formulabar.tsx index dfbc4f4..f1bac38 100644 --- a/webapp/src/components/formulabar.tsx +++ b/webapp/src/components/formulabar.tsx @@ -1,7 +1,6 @@ import type { Model } from "@ironcalc/wasm"; import { Button, styled } from "@mui/material"; import { ChevronDown } from "lucide-react"; -import { useState } from "react"; import { Fx } from "../icons"; import Editor from "./editor/editor"; import type { WorkbookState } from "./workbookState"; @@ -27,9 +26,6 @@ function FormulaBar(properties: FormulaBarProps) { onTextUpdated, workbookState, } = properties; - - const [display, setDisplay] = useState(false); - return ( @@ -55,7 +51,6 @@ function FormulaBar(properties: FormulaBarProps) { focus: "formula-bar", activeRanges: [], }); - setDisplay(true); event.stopPropagation(); event.preventDefault(); }} @@ -63,13 +58,12 @@ function FormulaBar(properties: FormulaBarProps) { { - setDisplay(false); onChange(); }} onTextUpdated={onTextUpdated} diff --git a/webapp/src/components/usePointer.ts b/webapp/src/components/usePointer.ts index 78a12d3..7328392 100644 --- a/webapp/src/components/usePointer.ts +++ b/webapp/src/components/usePointer.ts @@ -1,3 +1,4 @@ +import type { Model } from "@ironcalc/wasm"; import { type PointerEvent, type RefObject, useCallback, useRef } from "react"; import type WorksheetCanvas from "./WorksheetCanvas/worksheetCanvas"; import { @@ -5,6 +6,7 @@ import { headerRowHeight, } from "./WorksheetCanvas/worksheetCanvas"; import type { Cell } from "./types"; +import type { WorkbookState } from "./workbookState"; interface PointerSettings { canvasElement: RefObject; @@ -15,6 +17,8 @@ interface PointerSettings { onAreaSelected: () => void; onExtendToCell: (cell: Cell) => void; onExtendToEnd: () => void; + model: Model; + workbookState: WorkbookState; } interface PointerEvents { @@ -99,7 +103,13 @@ const usePointer = (options: PointerSettings): PointerEvents => { (event: PointerEvent) => { let x = event.clientX; let y = event.clientY; - const { canvasElement, worksheetElement, worksheetCanvas } = options; + const { + canvasElement, + model, + worksheetElement, + worksheetCanvas, + workbookState, + } = options; const worksheet = worksheetCanvas.current; const canvas = canvasElement.current; const worksheetWrapper = worksheetElement.current; @@ -132,8 +142,28 @@ const usePointer = (options: PointerSettings): PointerEvents => { } return; } + // if we are editing a cell finish that + 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; + } + workbookState.clearEditingCell(); + model.setUserInput( + editingCell.sheet, + editingCell.row, + editingCell.column, + editingCell.text, + ); + } options.onCellSelected(cell, event); isSelecting.current = true; worksheetWrapper.setPointerCapture(event.pointerId); diff --git a/webapp/src/components/workbook.tsx b/webapp/src/components/workbook.tsx index 015b38c..e5ef842 100644 --- a/webapp/src/components/workbook.tsx +++ b/webapp/src/components/workbook.tsx @@ -1,6 +1,6 @@ import type { BorderOptions, Model, WorksheetProperties } from "@ironcalc/wasm"; import { styled } from "@mui/material/styles"; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { LAST_COLUMN } from "./WorksheetCanvas/constants"; import FormulaBar from "./formulabar"; import Navigation from "./navigation/navigation"; @@ -262,26 +262,33 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => { } }); - const { - sheet, - row, - column, - range: [rowStart, columnStart, rowEnd, columnEnd], - } = model.getSelectedView(); + const cellAddress = useCallback(() => { + const { + row, + column, + range: [rowStart, columnStart, rowEnd, columnEnd], + } = model.getSelectedView(); + return getCellAddress( + { rowStart, rowEnd, columnStart, columnEnd }, + { row, column }, + ); + }, [model]); - const cellAddress = getCellAddress( - { rowStart, rowEnd, columnStart, columnEnd }, - { row, column }, - ); - const formulaValue = (() => { + const formulaValue = () => { const cell = workbookState.getEditingCell(); if (cell) { return cell.text; } + const { sheet, row, column } = model.getSelectedView(); return model.getCellContent(sheet, row, column); - })(); + }; - const style = model.getCellStyle(sheet, row, column); + const getCellStyle = useCallback(() => { + const { sheet, row, column } = model.getSelectedView(); + return model.getCellStyle(sheet, row, column); + }, [model]); + + const style = getCellStyle(); return ( { verticalAlign={style.alignment ? style.alignment.vertical : "center"} canEdit={true} numFmt={style.num_fmt} - showGridLines={model.getShowGridLines(sheet)} + showGridLines={model.getShowGridLines(model.getSelectedSheet())} onToggleShowGridLines={(show) => { + const sheet = model.getSelectedSheet(); model.setShowGridLines(sheet, show); setRedrawId((id) => id + 1); }} /> { setRedrawId((id) => id + 1); rootRef.current?.focus(); diff --git a/webapp/src/components/worksheet.tsx b/webapp/src/components/worksheet.tsx index bacade0..0b3663f 100644 --- a/webapp/src/components/worksheet.tsx +++ b/webapp/src/components/worksheet.tsx @@ -47,7 +47,6 @@ function Worksheet(props: { const ignoreScrollEventRef = useRef(false); - const [display, setDisplay] = useState(false); const [originalText, setOriginalText] = useState(""); const { model, workbookState, refresh } = props; @@ -143,6 +142,8 @@ function Worksheet(props: { onPointerUp, // onContextMenu, } = usePointer({ + model, + workbookState, onCellSelected: (cell: Cell, event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); @@ -315,18 +316,11 @@ function Worksheet(props: { { - // if we are editing a cell finish that - const cell = workbookState.getEditingCell(); - if (cell) { - workbookState.clearEditingCell(); - model.setUserInput(cell.sheet, cell.row, cell.column, cell.text); - } - onPointerDown(event); - }} + onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp} onDoubleClick={(event) => { + // Starts editing cell const { sheet, row, column } = model.getSelectedView(); const text = model.getCellContent(sheet, row, column) || ""; workbookState.setEditingCell({ @@ -334,11 +328,10 @@ function Worksheet(props: { row, column, text, - cursor: 0, + cursor: text.length, focus: "cell", activeRanges: [], }); - setDisplay(true); setOriginalText(text); event.stopPropagation(); event.preventDefault(); @@ -354,7 +347,6 @@ function Worksheet(props: { expand={true} originalText={workbookState.getEditingCell()?.text || originalText} onEditEnd={(): void => { - setDisplay(false); props.refresh(); }} onTextUpdated={(): void => {