FIX: Minimal implementation of browse mode
This commit is contained in:
@@ -1241,10 +1241,20 @@ export default class WorksheetCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private drawActiveRanges(topLeftCell: Cell, bottomRightCell: Cell): void {
|
private drawActiveRanges(topLeftCell: Cell, bottomRightCell: Cell): void {
|
||||||
const activeRanges = this.workbookState.getActiveRanges();
|
let activeRanges = this.workbookState.getActiveRanges();
|
||||||
const activeRangesCount = activeRanges.length;
|
|
||||||
const ctx = this.ctx;
|
const ctx = this.ctx;
|
||||||
ctx.setLineDash([2, 2]);
|
ctx.setLineDash([2, 2]);
|
||||||
|
const referencedRange =
|
||||||
|
this.workbookState.getEditingCell()?.referencedRange || null;
|
||||||
|
if (referencedRange) {
|
||||||
|
activeRanges = activeRanges.concat([
|
||||||
|
{
|
||||||
|
...referencedRange.range,
|
||||||
|
color: "#343423",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
const activeRangesCount = activeRanges.length;
|
||||||
for (let rangeIndex = 0; rangeIndex < activeRangesCount; rangeIndex += 1) {
|
for (let rangeIndex = 0; rangeIndex < activeRangesCount; rangeIndex += 1) {
|
||||||
const range = activeRanges[rangeIndex];
|
const range = activeRanges[rangeIndex];
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,18 @@
|
|||||||
// For those cases we capture the keydown event and stop its propagation.
|
// For those cases we capture the keydown event and stop its propagation.
|
||||||
// As the editor changes content we need to propagate those changes so the spreadsheet can
|
// As the editor changes content we need to propagate those changes so the spreadsheet can
|
||||||
// mark with colors the active ranges or update the formula in the formula bar
|
// mark with colors the active ranges or update the formula in the formula bar
|
||||||
|
//
|
||||||
|
// Events outside the editor might influence the editor
|
||||||
|
// 1. Clicking on a different cell:
|
||||||
|
// * might either terminate the editing
|
||||||
|
// * or add the external cell to the formula
|
||||||
|
// 2. Clicking on a sheet tab would open the new sheet or terminate editing
|
||||||
|
// 3. Clicking somewhere else will finish editing
|
||||||
|
//
|
||||||
|
// Keyboard navigation is also fairly complex. For instance RightArrow might:
|
||||||
|
// 1. End editing and navigate to the cell on the right
|
||||||
|
// 2. Move the cursor to the right
|
||||||
|
// 3. Insert in the formula the cell name on the right
|
||||||
|
|
||||||
import type { Model } from "@ironcalc/wasm";
|
import type { Model } from "@ironcalc/wasm";
|
||||||
import {
|
import {
|
||||||
@@ -65,7 +77,7 @@ const Editor = (options: EditorOptions) => {
|
|||||||
const [height, setHeight] = useState(minimalHeight);
|
const [height, setHeight] = useState(minimalHeight);
|
||||||
const [text, setText] = useState(originalText);
|
const [text, setText] = useState(originalText);
|
||||||
const [styledFormula, setStyledFormula] = useState(
|
const [styledFormula, setStyledFormula] = useState(
|
||||||
getFormulaHTML(model, text).html,
|
getFormulaHTML(model, text, "").html,
|
||||||
);
|
);
|
||||||
|
|
||||||
const formulaRef = useRef<HTMLDivElement>(null);
|
const formulaRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -74,7 +86,7 @@ const Editor = (options: EditorOptions) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setText(originalText);
|
setText(originalText);
|
||||||
setStyledFormula(getFormulaHTML(model, originalText).html);
|
setStyledFormula(getFormulaHTML(model, originalText, "").html);
|
||||||
if (textareaRef.current) {
|
if (textareaRef.current) {
|
||||||
textareaRef.current.value = originalText;
|
textareaRef.current.value = originalText;
|
||||||
}
|
}
|
||||||
@@ -107,7 +119,12 @@ const Editor = (options: EditorOptions) => {
|
|||||||
const cell = workbookState.getEditingCell();
|
const cell = workbookState.getEditingCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
workbookState.clearEditingCell();
|
workbookState.clearEditingCell();
|
||||||
model.setUserInput(cell.sheet, cell.row, cell.column, cell.text);
|
model.setUserInput(
|
||||||
|
cell.sheet,
|
||||||
|
cell.row,
|
||||||
|
cell.column,
|
||||||
|
cell.text + (cell.referencedRange?.str || ""),
|
||||||
|
);
|
||||||
const sign = shiftKey ? -1 : 1;
|
const sign = shiftKey ? -1 : 1;
|
||||||
model.setSelectedCell(cell.row + sign, cell.column);
|
model.setSelectedCell(cell.row + sign, cell.column);
|
||||||
}
|
}
|
||||||
@@ -121,12 +138,17 @@ const Editor = (options: EditorOptions) => {
|
|||||||
const cell = workbookState.getEditingCell();
|
const cell = workbookState.getEditingCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
workbookState.clearEditingCell();
|
workbookState.clearEditingCell();
|
||||||
model.setUserInput(cell.sheet, cell.row, cell.column, cell.text);
|
model.setUserInput(
|
||||||
|
cell.sheet,
|
||||||
|
cell.row,
|
||||||
|
cell.column,
|
||||||
|
cell.text + (cell.referencedRange?.str || ""),
|
||||||
|
);
|
||||||
const sign = shiftKey ? -1 : 1;
|
const sign = shiftKey ? -1 : 1;
|
||||||
model.setSelectedCell(cell.row, cell.column + sign);
|
model.setSelectedCell(cell.row, cell.column + sign);
|
||||||
if (textareaRef.current) {
|
if (textareaRef.current) {
|
||||||
textareaRef.current.value = "";
|
textareaRef.current.value = "";
|
||||||
setStyledFormula(getFormulaHTML(model, "").html);
|
setStyledFormula(getFormulaHTML(model, "", "").html);
|
||||||
}
|
}
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -148,11 +170,16 @@ const Editor = (options: EditorOptions) => {
|
|||||||
// We run this in a timeout because the value is not yet in the textarea
|
// We run this in a timeout because the value is not yet in the textarea
|
||||||
// since we are capturing the keydown event
|
// since we are capturing the keydown event
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const value = textarea.value;
|
|
||||||
const styledFormula = getFormulaHTML(model, value);
|
|
||||||
const cell = workbookState.getEditingCell();
|
const cell = workbookState.getEditingCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
|
// accept whatever is in the referenced range
|
||||||
|
const value = textarea.value;
|
||||||
|
const styledFormula = getFormulaHTML(model, value, "");
|
||||||
|
|
||||||
cell.text = value;
|
cell.text = value;
|
||||||
|
cell.referencedRange = null;
|
||||||
|
cell.cursorStart = textarea.selectionStart;
|
||||||
|
cell.cursorEnd = textarea.selectionEnd;
|
||||||
workbookState.setEditingCell(cell);
|
workbookState.setEditingCell(cell);
|
||||||
|
|
||||||
workbookState.setActiveRanges(styledFormula.activeRanges);
|
workbookState.setActiveRanges(styledFormula.activeRanges);
|
||||||
@@ -176,7 +203,7 @@ const Editor = (options: EditorOptions) => {
|
|||||||
const onChange = useCallback(() => {
|
const onChange = useCallback(() => {
|
||||||
if (textareaRef.current) {
|
if (textareaRef.current) {
|
||||||
textareaRef.current.value = "";
|
textareaRef.current.value = "";
|
||||||
setStyledFormula(getFormulaHTML(model, "").html);
|
setStyledFormula(getFormulaHTML(model, "", "").html);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This happens if the blur hasn't been taken care before by
|
// This happens if the blur hasn't been taken care before by
|
||||||
@@ -184,8 +211,13 @@ const Editor = (options: EditorOptions) => {
|
|||||||
// If we are editing a cell finish that
|
// If we are editing a cell finish that
|
||||||
const cell = workbookState.getEditingCell();
|
const cell = workbookState.getEditingCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
|
model.setUserInput(
|
||||||
|
cell.sheet,
|
||||||
|
cell.row,
|
||||||
|
cell.column,
|
||||||
|
workbookState.getEditingText(),
|
||||||
|
);
|
||||||
workbookState.clearEditingCell();
|
workbookState.clearEditingCell();
|
||||||
model.setUserInput(cell.sheet, cell.row, cell.column, cell.text);
|
|
||||||
}
|
}
|
||||||
onEditEnd();
|
onEditEnd();
|
||||||
}, [model, workbookState, onEditEnd]);
|
}, [model, workbookState, onEditEnd]);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function tokenIsRangeType(token: TokenType): token is Range {
|
|||||||
return typeof token === "object" && "Range" in token;
|
return typeof token === "object" && "Range" in token;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInReferenceMode(text: string, cursor: number): boolean {
|
export function isInReferenceMode(text: string, cursor: number): boolean {
|
||||||
// FIXME
|
// FIXME
|
||||||
// This is a gross oversimplification
|
// This is a gross oversimplification
|
||||||
// Returns true if both are true:
|
// Returns true if both are true:
|
||||||
@@ -102,6 +102,7 @@ export function getColor(index: number, alpha = 1): string {
|
|||||||
function getFormulaHTML(
|
function getFormulaHTML(
|
||||||
model: Model,
|
model: Model,
|
||||||
text: string,
|
text: string,
|
||||||
|
referenceRange: string,
|
||||||
): { html: JSX.Element[]; activeRanges: ActiveRange[] } {
|
): { html: JSX.Element[]; activeRanges: ActiveRange[] } {
|
||||||
let html: JSX.Element[] = [];
|
let html: JSX.Element[] = [];
|
||||||
const activeRanges: ActiveRange[] = [];
|
const activeRanges: ActiveRange[] = [];
|
||||||
@@ -179,6 +180,10 @@ function getFormulaHTML(
|
|||||||
html.push(<span key={index}>{formula.slice(start, end)}</span>);
|
html.push(<span key={index}>{formula.slice(start, end)}</span>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If there is a reference range add it at the end
|
||||||
|
if (referenceRange !== "") {
|
||||||
|
html.push(<span key="reference">{referenceRange}</span>);
|
||||||
|
}
|
||||||
html = [<span key="equals">=</span>].concat(html);
|
html = [<span key="equals">=</span>].concat(html);
|
||||||
} else {
|
} else {
|
||||||
html = [<span key="single">{text}</span>];
|
html = [<span key="single">{text}</span>];
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ function FormulaBar(properties: FormulaBarProps) {
|
|||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
text: formulaValue,
|
text: formulaValue,
|
||||||
cursor: 0,
|
referencedRange: null,
|
||||||
|
cursorStart: formulaValue.length,
|
||||||
|
cursorEnd: formulaValue.length,
|
||||||
focus: "formula-bar",
|
focus: "formula-bar",
|
||||||
activeRanges: [],
|
activeRanges: [],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import {
|
|||||||
headerColumnWidth,
|
headerColumnWidth,
|
||||||
headerRowHeight,
|
headerRowHeight,
|
||||||
} from "./WorksheetCanvas/worksheetCanvas";
|
} from "./WorksheetCanvas/worksheetCanvas";
|
||||||
|
import { isInReferenceMode } from "./editor/util";
|
||||||
import type { Cell } from "./types";
|
import type { Cell } from "./types";
|
||||||
|
import { rangeToStr } from "./util";
|
||||||
import type { WorkbookState } from "./workbookState";
|
import type { WorkbookState } from "./workbookState";
|
||||||
|
|
||||||
interface PointerSettings {
|
interface PointerSettings {
|
||||||
@@ -19,6 +21,7 @@ interface PointerSettings {
|
|||||||
onExtendToEnd: () => void;
|
onExtendToEnd: () => void;
|
||||||
model: Model;
|
model: Model;
|
||||||
workbookState: WorkbookState;
|
workbookState: WorkbookState;
|
||||||
|
refresh: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PointerEvents {
|
interface PointerEvents {
|
||||||
@@ -31,6 +34,7 @@ interface PointerEvents {
|
|||||||
const usePointer = (options: PointerSettings): PointerEvents => {
|
const usePointer = (options: PointerSettings): PointerEvents => {
|
||||||
const isSelecting = useRef(false);
|
const isSelecting = useRef(false);
|
||||||
const isExtending = useRef(false);
|
const isExtending = useRef(false);
|
||||||
|
const isInsertingRef = useRef(false);
|
||||||
|
|
||||||
const onPointerMove = useCallback(
|
const onPointerMove = useCallback(
|
||||||
(event: PointerEvent): void => {
|
(event: PointerEvent): void => {
|
||||||
@@ -40,43 +44,43 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(isSelecting.current || isExtending.current || isInsertingRef.current)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { canvasElement, 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) {
|
if (isSelecting.current) {
|
||||||
const { canvasElement, worksheetCanvas } = options;
|
options.onAreaSelecting(cell);
|
||||||
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");
|
|
||||||
}
|
|
||||||
} else if (isExtending.current) {
|
} 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);
|
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;
|
||||||
|
editingCell.referencedRange.str = rangeToStr(range, 0);
|
||||||
|
workbookState.setEditingCell(editingCell);
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[options],
|
[options],
|
||||||
@@ -94,6 +98,10 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
isExtending.current = false;
|
isExtending.current = false;
|
||||||
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
||||||
options.onExtendToEnd();
|
options.onExtendToEnd();
|
||||||
|
} else if (isInsertingRef.current) {
|
||||||
|
const { worksheetElement } = options;
|
||||||
|
isInsertingRef.current = false;
|
||||||
|
worksheetElement.current?.releasePointerCapture(event.pointerId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[options],
|
[options],
|
||||||
@@ -106,6 +114,7 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
const {
|
const {
|
||||||
canvasElement,
|
canvasElement,
|
||||||
model,
|
model,
|
||||||
|
refresh,
|
||||||
worksheetElement,
|
worksheetElement,
|
||||||
worksheetCanvas,
|
worksheetCanvas,
|
||||||
workbookState,
|
workbookState,
|
||||||
@@ -142,9 +151,8 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if we are editing a cell finish that
|
|
||||||
const editingCell = workbookState.getEditingCell();
|
|
||||||
|
|
||||||
|
const editingCell = workbookState.getEditingCell();
|
||||||
const cell = worksheet.getCellByCoordinates(x, y);
|
const cell = worksheet.getCellByCoordinates(x, y);
|
||||||
if (cell) {
|
if (cell) {
|
||||||
if (editingCell) {
|
if (editingCell) {
|
||||||
@@ -156,6 +164,31 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
// we do nothing
|
// we do nothing
|
||||||
return;
|
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: 0,
|
||||||
|
rowStart: cell.row,
|
||||||
|
rowEnd: cell.row,
|
||||||
|
columnStart: cell.column,
|
||||||
|
columnEnd: cell.column,
|
||||||
|
};
|
||||||
|
editingCell.referencedRange = {
|
||||||
|
range,
|
||||||
|
str: rangeToStr(range, 0),
|
||||||
|
};
|
||||||
|
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();
|
workbookState.clearEditingCell();
|
||||||
model.setUserInput(
|
model.setUserInput(
|
||||||
editingCell.sheet,
|
editingCell.sheet,
|
||||||
@@ -163,6 +196,7 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
editingCell.column,
|
editingCell.column,
|
||||||
editingCell.text,
|
editingCell.text,
|
||||||
);
|
);
|
||||||
|
// we continue to select the new cell
|
||||||
}
|
}
|
||||||
options.onCellSelected(cell, event);
|
options.onCellSelected(cell, event);
|
||||||
isSelecting.current = true;
|
isSelecting.current = true;
|
||||||
|
|||||||
@@ -40,3 +40,21 @@ export const getCellAddress = (selectedArea: Area, selectedCell?: Cell) => {
|
|||||||
selectedArea.rowStart
|
selectedArea.rowStart
|
||||||
}:${columnNameFromNumber(selectedArea.columnEnd)}${selectedArea.rowEnd}`;
|
}:${columnNameFromNumber(selectedArea.columnEnd)}${selectedArea.rowEnd}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function rangeToStr(
|
||||||
|
range: {
|
||||||
|
sheet: number;
|
||||||
|
rowStart: number;
|
||||||
|
rowEnd: number;
|
||||||
|
columnStart: number;
|
||||||
|
columnEnd: number;
|
||||||
|
},
|
||||||
|
referenceSheet: number,
|
||||||
|
): string {
|
||||||
|
const { sheet, rowStart, rowEnd, columnStart, columnEnd } = range;
|
||||||
|
const sheetName = sheet === referenceSheet ? "" : "other!";
|
||||||
|
if (rowStart === rowEnd && columnStart === columnEnd) {
|
||||||
|
return `${sheetName}${columnNameFromNumber(columnStart)}${rowStart}`;
|
||||||
|
}
|
||||||
|
return `${sheetName}${columnNameFromNumber(columnStart)}${rowStart}:${columnNameFromNumber(columnEnd)}${rowEnd}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -149,8 +149,10 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
text: initText,
|
text: initText,
|
||||||
cursor: 0,
|
cursorStart: initText.length,
|
||||||
|
cursorEnd: initText.length,
|
||||||
focus: "cell",
|
focus: "cell",
|
||||||
|
referencedRange: null,
|
||||||
activeRanges: [],
|
activeRanges: [],
|
||||||
});
|
});
|
||||||
setRedrawId((id) => id + 1);
|
setRedrawId((id) => id + 1);
|
||||||
@@ -163,7 +165,9 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
text,
|
text,
|
||||||
cursor: text.length,
|
cursorStart: text.length,
|
||||||
|
cursorEnd: text.length,
|
||||||
|
referencedRange: null,
|
||||||
focus: "cell",
|
focus: "cell",
|
||||||
activeRanges: [],
|
activeRanges: [],
|
||||||
});
|
});
|
||||||
@@ -277,7 +281,7 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
const formulaValue = () => {
|
const formulaValue = () => {
|
||||||
const cell = workbookState.getEditingCell();
|
const cell = workbookState.getEditingCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
return cell.text;
|
return workbookState.getEditingText();
|
||||||
}
|
}
|
||||||
const { sheet, row, column } = model.getSelectedView();
|
const { sheet, row, column } = model.getSelectedView();
|
||||||
return model.getCellContent(sheet, row, column);
|
return model.getCellContent(sheet, row, column);
|
||||||
@@ -295,8 +299,12 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
ref={rootRef}
|
ref={rootRef}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={(event) => {
|
||||||
rootRef.current?.focus();
|
if (!workbookState.getEditingCell()) {
|
||||||
|
rootRef.current?.focus();
|
||||||
|
} else {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar
|
<Toolbar
|
||||||
|
|||||||
@@ -40,6 +40,17 @@ export interface ActiveRange {
|
|||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ReferencedRange {
|
||||||
|
range: {
|
||||||
|
sheet: number;
|
||||||
|
rowStart: number;
|
||||||
|
rowEnd: number;
|
||||||
|
columnStart: number;
|
||||||
|
columnEnd: number;
|
||||||
|
};
|
||||||
|
str: string;
|
||||||
|
}
|
||||||
|
|
||||||
type Focus = "cell" | "formula-bar";
|
type Focus = "cell" | "formula-bar";
|
||||||
|
|
||||||
// The cell that we are editing
|
// The cell that we are editing
|
||||||
@@ -50,7 +61,10 @@ export interface EditingCell {
|
|||||||
// raw text in the editor
|
// raw text in the editor
|
||||||
text: string;
|
text: string;
|
||||||
// position of the cursor
|
// position of the cursor
|
||||||
cursor: number;
|
cursorStart: number;
|
||||||
|
cursorEnd: number;
|
||||||
|
// referenced range
|
||||||
|
referencedRange: ReferencedRange | null;
|
||||||
focus: Focus;
|
focus: Focus;
|
||||||
activeRanges: ActiveRange[];
|
activeRanges: ActiveRange[];
|
||||||
}
|
}
|
||||||
@@ -126,4 +140,12 @@ export class WorkbookState {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getEditingText(): string {
|
||||||
|
const cell = this.cell;
|
||||||
|
if (cell) {
|
||||||
|
return cell.text + (cell.referencedRange?.str || "");
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ function Worksheet(props: {
|
|||||||
} = usePointer({
|
} = usePointer({
|
||||||
model,
|
model,
|
||||||
workbookState,
|
workbookState,
|
||||||
|
refresh,
|
||||||
onCellSelected: (cell: Cell, event: React.MouseEvent) => {
|
onCellSelected: (cell: Cell, event: React.MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@@ -328,8 +329,10 @@ function Worksheet(props: {
|
|||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
text,
|
text,
|
||||||
cursor: text.length,
|
cursorStart: text.length,
|
||||||
|
cursorEnd: text.length,
|
||||||
focus: "cell",
|
focus: "cell",
|
||||||
|
referencedRange: null,
|
||||||
activeRanges: [],
|
activeRanges: [],
|
||||||
});
|
});
|
||||||
setOriginalText(text);
|
setOriginalText(text);
|
||||||
@@ -345,7 +348,7 @@ function Worksheet(props: {
|
|||||||
minimalHeight={"100%"}
|
minimalHeight={"100%"}
|
||||||
display={workbookState.getEditingCell()?.focus === "cell"}
|
display={workbookState.getEditingCell()?.focus === "cell"}
|
||||||
expand={true}
|
expand={true}
|
||||||
originalText={workbookState.getEditingCell()?.text || originalText}
|
originalText={workbookState.getEditingText() || originalText}
|
||||||
onEditEnd={(): void => {
|
onEditEnd={(): void => {
|
||||||
props.refresh();
|
props.refresh();
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user