FIX: Do not loose focus when clicking on the formula we are editing

This commit is contained in:
Nicolás Hatcher
2024-09-27 19:25:26 +02:00
parent f53b39b220
commit 90cf5f74f7
5 changed files with 69 additions and 40 deletions

View File

@@ -193,7 +193,7 @@ const Editor = (options: EditorOptions) => {
const isCellEditing = workbookState.getEditingCell() !== null; const isCellEditing = workbookState.getEditingCell() !== null;
const showEditor = const showEditor =
isCellEditing && (display || type === "formula-bar") ? "block" : "none"; (isCellEditing && display) || type === "formula-bar" ? "block" : "none";
return ( return (
<div <div
@@ -229,13 +229,18 @@ const Editor = (options: EditorOptions) => {
resize: "none", resize: "none",
border: "none", border: "none",
height, height,
display: display ? "block" : "none",
overflow: "hidden", overflow: "hidden",
}} }}
defaultValue={text} defaultValue={text}
spellCheck="false" spellCheck="false"
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onBlur={onChange} onBlur={onChange}
onClick={(event) => {
// Prevents this from bubbling up and focusing on the spreadsheet
if (isCellEditing && type === "cell") {
event.stopPropagation();
}
}}
/> />
</div> </div>
); );

View File

@@ -1,7 +1,6 @@
import type { Model } from "@ironcalc/wasm"; import type { Model } from "@ironcalc/wasm";
import { Button, styled } from "@mui/material"; import { Button, styled } from "@mui/material";
import { ChevronDown } from "lucide-react"; import { ChevronDown } from "lucide-react";
import { useState } from "react";
import { Fx } from "../icons"; import { Fx } from "../icons";
import Editor from "./editor/editor"; import Editor from "./editor/editor";
import type { WorkbookState } from "./workbookState"; import type { WorkbookState } from "./workbookState";
@@ -27,9 +26,6 @@ function FormulaBar(properties: FormulaBarProps) {
onTextUpdated, onTextUpdated,
workbookState, workbookState,
} = properties; } = properties;
const [display, setDisplay] = useState(false);
return ( return (
<Container> <Container>
<AddressContainer> <AddressContainer>
@@ -55,7 +51,6 @@ function FormulaBar(properties: FormulaBarProps) {
focus: "formula-bar", focus: "formula-bar",
activeRanges: [], activeRanges: [],
}); });
setDisplay(true);
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
}} }}
@@ -63,13 +58,12 @@ function FormulaBar(properties: FormulaBarProps) {
<Editor <Editor
minimalWidth={"100%"} minimalWidth={"100%"}
minimalHeight={"100%"} minimalHeight={"100%"}
display={display} display={true}
expand={false} expand={false}
originalText={formulaValue} originalText={formulaValue}
model={model} model={model}
workbookState={workbookState} workbookState={workbookState}
onEditEnd={() => { onEditEnd={() => {
setDisplay(false);
onChange(); onChange();
}} }}
onTextUpdated={onTextUpdated} onTextUpdated={onTextUpdated}

View File

@@ -1,3 +1,4 @@
import type { Model } from "@ironcalc/wasm";
import { type PointerEvent, type RefObject, useCallback, useRef } from "react"; import { type PointerEvent, type RefObject, useCallback, useRef } from "react";
import type WorksheetCanvas from "./WorksheetCanvas/worksheetCanvas"; import type WorksheetCanvas from "./WorksheetCanvas/worksheetCanvas";
import { import {
@@ -5,6 +6,7 @@ import {
headerRowHeight, headerRowHeight,
} from "./WorksheetCanvas/worksheetCanvas"; } from "./WorksheetCanvas/worksheetCanvas";
import type { Cell } from "./types"; import type { Cell } from "./types";
import type { WorkbookState } from "./workbookState";
interface PointerSettings { interface PointerSettings {
canvasElement: RefObject<HTMLCanvasElement>; canvasElement: RefObject<HTMLCanvasElement>;
@@ -15,6 +17,8 @@ interface PointerSettings {
onAreaSelected: () => void; onAreaSelected: () => void;
onExtendToCell: (cell: Cell) => void; onExtendToCell: (cell: Cell) => void;
onExtendToEnd: () => void; onExtendToEnd: () => void;
model: Model;
workbookState: WorkbookState;
} }
interface PointerEvents { interface PointerEvents {
@@ -99,7 +103,13 @@ const usePointer = (options: PointerSettings): PointerEvents => {
(event: PointerEvent) => { (event: PointerEvent) => {
let x = event.clientX; let x = event.clientX;
let y = event.clientY; let y = event.clientY;
const { canvasElement, worksheetElement, worksheetCanvas } = options; const {
canvasElement,
model,
worksheetElement,
worksheetCanvas,
workbookState,
} = options;
const worksheet = worksheetCanvas.current; const worksheet = worksheetCanvas.current;
const canvas = canvasElement.current; const canvas = canvasElement.current;
const worksheetWrapper = worksheetElement.current; const worksheetWrapper = worksheetElement.current;
@@ -132,8 +142,28 @@ const usePointer = (options: PointerSettings): PointerEvents => {
} }
return; return;
} }
// if we are editing a cell finish that
const editingCell = workbookState.getEditingCell();
const cell = worksheet.getCellByCoordinates(x, y); const cell = worksheet.getCellByCoordinates(x, y);
if (cell) { 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); options.onCellSelected(cell, event);
isSelecting.current = true; isSelecting.current = true;
worksheetWrapper.setPointerCapture(event.pointerId); worksheetWrapper.setPointerCapture(event.pointerId);

View File

@@ -1,6 +1,6 @@
import type { BorderOptions, Model, WorksheetProperties } from "@ironcalc/wasm"; import type { BorderOptions, Model, WorksheetProperties } from "@ironcalc/wasm";
import { styled } from "@mui/material/styles"; 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 { LAST_COLUMN } from "./WorksheetCanvas/constants";
import FormulaBar from "./formulabar"; import FormulaBar from "./formulabar";
import Navigation from "./navigation/navigation"; import Navigation from "./navigation/navigation";
@@ -262,26 +262,33 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
} }
}); });
const { const cellAddress = useCallback(() => {
sheet, const {
row, row,
column, column,
range: [rowStart, columnStart, rowEnd, columnEnd], range: [rowStart, columnStart, rowEnd, columnEnd],
} = model.getSelectedView(); } = model.getSelectedView();
return getCellAddress(
{ rowStart, rowEnd, columnStart, columnEnd },
{ row, column },
);
}, [model]);
const cellAddress = getCellAddress( const formulaValue = () => {
{ rowStart, rowEnd, columnStart, columnEnd },
{ row, column },
);
const formulaValue = (() => {
const cell = workbookState.getEditingCell(); const cell = workbookState.getEditingCell();
if (cell) { if (cell) {
return cell.text; return cell.text;
} }
const { sheet, row, column } = model.getSelectedView();
return model.getCellContent(sheet, row, column); 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 ( return (
<Container <Container
@@ -339,15 +346,16 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
verticalAlign={style.alignment ? style.alignment.vertical : "center"} verticalAlign={style.alignment ? style.alignment.vertical : "center"}
canEdit={true} canEdit={true}
numFmt={style.num_fmt} numFmt={style.num_fmt}
showGridLines={model.getShowGridLines(sheet)} showGridLines={model.getShowGridLines(model.getSelectedSheet())}
onToggleShowGridLines={(show) => { onToggleShowGridLines={(show) => {
const sheet = model.getSelectedSheet();
model.setShowGridLines(sheet, show); model.setShowGridLines(sheet, show);
setRedrawId((id) => id + 1); setRedrawId((id) => id + 1);
}} }}
/> />
<FormulaBar <FormulaBar
cellAddress={cellAddress} cellAddress={cellAddress()}
formulaValue={formulaValue} formulaValue={formulaValue()}
onChange={() => { onChange={() => {
setRedrawId((id) => id + 1); setRedrawId((id) => id + 1);
rootRef.current?.focus(); rootRef.current?.focus();

View File

@@ -47,7 +47,6 @@ function Worksheet(props: {
const ignoreScrollEventRef = useRef(false); const ignoreScrollEventRef = useRef(false);
const [display, setDisplay] = useState(false);
const [originalText, setOriginalText] = useState(""); const [originalText, setOriginalText] = useState("");
const { model, workbookState, refresh } = props; const { model, workbookState, refresh } = props;
@@ -143,6 +142,8 @@ function Worksheet(props: {
onPointerUp, onPointerUp,
// onContextMenu, // onContextMenu,
} = usePointer({ } = usePointer({
model,
workbookState,
onCellSelected: (cell: Cell, event: React.MouseEvent) => { onCellSelected: (cell: Cell, event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -315,18 +316,11 @@ function Worksheet(props: {
<SheetContainer <SheetContainer
className="sheet-container" className="sheet-container"
ref={worksheetElement} ref={worksheetElement}
onPointerDown={(event) => { onPointerDown={onPointerDown}
// 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);
}}
onPointerMove={onPointerMove} onPointerMove={onPointerMove}
onPointerUp={onPointerUp} onPointerUp={onPointerUp}
onDoubleClick={(event) => { onDoubleClick={(event) => {
// Starts editing cell
const { sheet, row, column } = model.getSelectedView(); const { sheet, row, column } = model.getSelectedView();
const text = model.getCellContent(sheet, row, column) || ""; const text = model.getCellContent(sheet, row, column) || "";
workbookState.setEditingCell({ workbookState.setEditingCell({
@@ -334,11 +328,10 @@ function Worksheet(props: {
row, row,
column, column,
text, text,
cursor: 0, cursor: text.length,
focus: "cell", focus: "cell",
activeRanges: [], activeRanges: [],
}); });
setDisplay(true);
setOriginalText(text); setOriginalText(text);
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
@@ -354,7 +347,6 @@ function Worksheet(props: {
expand={true} expand={true}
originalText={workbookState.getEditingCell()?.text || originalText} originalText={workbookState.getEditingCell()?.text || originalText}
onEditEnd={(): void => { onEditEnd={(): void => {
setDisplay(false);
props.refresh(); props.refresh();
}} }}
onTextUpdated={(): void => { onTextUpdated={(): void => {