UPDATE: Dynamic arrays!

This commit is contained in:
Nicolás Hatcher
2025-03-23 01:51:17 +01:00
parent 81e96f1401
commit c78bdb32fd
26 changed files with 1172 additions and 123 deletions

View File

@@ -13,6 +13,7 @@ import type { WorkbookState } from "../workbookState";
type FormulaBarProps = {
cellAddress: string;
formulaValue: string;
isPartOfArray: boolean;
model: Model;
workbookState: WorkbookState;
onChange: () => void;
@@ -23,6 +24,7 @@ function FormulaBar(properties: FormulaBarProps) {
const {
cellAddress,
formulaValue,
isPartOfArray,
model,
onChange,
onTextUpdated,
@@ -62,6 +64,9 @@ function FormulaBar(properties: FormulaBarProps) {
event.stopPropagation();
event.preventDefault();
}}
sx={{
color: isPartOfArray ? "grey" : "black",
}}
>
<Editor
originalText={formulaValue}

View File

@@ -362,6 +362,19 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
return model.getCellContent(sheet, row, column);
};
// returns true if it is either single cell or the root cell of an array
const isRootCellOfArray = () => {
const { sheet, row, column } = model.getSelectedView();
const r = model.getCellArrayStructure(sheet, row, column);
if (r === "SingleCell") {
return false;
}
if ("DynamicMother" in r) {
return false;
}
return true;
};
const getCellStyle = useCallback(() => {
const { sheet, row, column } = model.getSelectedView();
return model.getCellStyle(sheet, row, column);
@@ -705,6 +718,7 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
}}
model={model}
workbookState={workbookState}
isPartOfArray={isRootCellOfArray()}
/>
<Worksheet
model={model}

View File

@@ -14,6 +14,7 @@ import {
LAST_COLUMN,
LAST_ROW,
ROW_HEIGH_SCALE,
cellArrayStructureColor,
outlineBackgroundColor,
outlineColor,
} from "../WorksheetCanvas/constants";
@@ -59,6 +60,8 @@ const Worksheet = forwardRef(
const spacerElement = useRef<HTMLDivElement>(null);
const cellOutline = useRef<HTMLDivElement>(null);
const areaOutline = useRef<HTMLDivElement>(null);
const cellOutlineHandle = useRef<HTMLDivElement>(null);
const cellArrayStructure = useRef<HTMLDivElement>(null);
const extendToOutline = useRef<HTMLDivElement>(null);
const columnResizeGuide = useRef<HTMLDivElement>(null);
const rowResizeGuide = useRef<HTMLDivElement>(null);
@@ -85,6 +88,7 @@ const Worksheet = forwardRef(
const outline = cellOutline.current;
const area = areaOutline.current;
const arrayStructure = cellArrayStructure.current;
const extendTo = extendToOutline.current;
const editor = editorElement.current;
@@ -98,7 +102,8 @@ const Worksheet = forwardRef(
!area ||
!extendTo ||
!scrollElement.current ||
!editor
!editor ||
!arrayStructure
)
return;
// FIXME: This two need to be computed.
@@ -115,6 +120,8 @@ const Worksheet = forwardRef(
rowGuide: rowGuideRef,
columnHeaders: columnHeadersRef,
cellOutline: outline,
cellOutlineHandle: handle,
cellArrayStructure: arrayStructure,
areaOutline: area,
extendToOutline: extendTo,
editor: editor,
@@ -329,6 +336,7 @@ const Worksheet = forwardRef(
/>
</EditorWrapper>
<AreaOutline ref={areaOutline} />
<CellArrayStructure ref={cellArrayStructure} />
<ExtendToOutline ref={extendToOutline} />
<ColumnResizeGuide ref={columnResizeGuide} />
<RowResizeGuide ref={rowResizeGuide} />
@@ -514,6 +522,12 @@ const AreaOutline = styled("div")`
background-color: ${outlineBackgroundColor};
`;
const CellArrayStructure = styled("div")`
position: absolute;
border: 1px solid ${cellArrayStructureColor};
border-radius: 3px;
`;
const CellOutline = styled("div")`
position: absolute;
border: 2px solid ${outlineColor};

View File

@@ -13,6 +13,7 @@ export const defaultTextColor = "#2E414D";
export const outlineColor = "#F2994A";
export const outlineBackgroundColor = "#F2994A1A";
export const cellArrayStructureColor = "#64BDFDA1";
export const LAST_COLUMN = 16_384;
export const LAST_ROW = 1_048_576;

View File

@@ -31,6 +31,8 @@ export interface CanvasSettings {
canvas: HTMLCanvasElement;
cellOutline: HTMLDivElement;
areaOutline: HTMLDivElement;
cellOutlineHandle: HTMLDivElement;
cellArrayStructure: HTMLDivElement;
extendToOutline: HTMLDivElement;
columnGuide: HTMLDivElement;
rowGuide: HTMLDivElement;
@@ -90,6 +92,8 @@ export default class WorksheetCanvas {
cellOutlineHandle: HTMLDivElement;
cellArrayStructure: HTMLDivElement;
extendToOutline: HTMLDivElement;
workbookState: WorkbookState;
@@ -124,6 +128,8 @@ export default class WorksheetCanvas {
this.refresh = options.refresh;
this.cellOutline = options.elements.cellOutline;
this.cellOutlineHandle = options.elements.cellOutlineHandle;
this.cellArrayStructure = options.elements.cellArrayStructure;
this.areaOutline = options.elements.areaOutline;
this.extendToOutline = options.elements.extendToOutline;
this.rowGuide = options.elements.rowGuide;
@@ -1515,16 +1521,20 @@ export default class WorksheetCanvas {
}
private drawCellOutline(): void {
const { cellOutline, areaOutline, cellOutlineHandle } = this;
const { cellArrayStructure, cellOutline, areaOutline, cellOutlineHandle } =
this;
if (this.workbookState.getEditingCell()) {
cellOutline.style.visibility = "hidden";
cellOutlineHandle.style.visibility = "hidden";
areaOutline.style.visibility = "hidden";
cellArrayStructure.style.visibility = "hidden";
return;
}
cellOutline.style.visibility = "visible";
cellOutlineHandle.style.visibility = "visible";
areaOutline.style.visibility = "visible";
// This one is hidden by default
cellArrayStructure.style.visibility = "hidden";
const [selectedSheet, selectedRow, selectedColumn] =
this.model.getSelectedCell();
@@ -1580,6 +1590,34 @@ export default class WorksheetCanvas {
[handleX, handleY] = this.getCoordinatesByCell(rowStart, columnStart);
handleX += this.getColumnWidth(selectedSheet, columnStart);
handleY += this.getRowHeight(selectedSheet, rowStart);
// we draw the array structure if needed only in this case
const arrayStructure = this.model.getCellArrayStructure(
selectedSheet,
selectedRow,
selectedColumn,
);
let array = null;
if (arrayStructure === "SingleCell") {
// nothing to see here
} else if ("DynamicMother" in arrayStructure) {
cellArrayStructure.style.visibility = "visible";
const [arrayWidth, arrayHeight] = arrayStructure.DynamicMother;
array = [selectedRow, selectedColumn, arrayWidth, arrayHeight];
} else {
cellArrayStructure.style.visibility = "visible";
array = arrayStructure.DynamicChild;
}
if (array !== null) {
const [arrayX, arrayY] = this.getCoordinatesByCell(array[0], array[1]);
const [arrayX1, arrayY1] = this.getCoordinatesByCell(
array[0] + array[3],
array[1] + array[2],
);
cellArrayStructure.style.left = `${arrayX}px`;
cellArrayStructure.style.top = `${arrayY}px`;
cellArrayStructure.style.width = `${arrayX1 - arrayX}px`;
cellArrayStructure.style.height = `${arrayY1 - arrayY}px`;
}
} else {
areaOutline.style.visibility = "visible";
cellOutlineHandle.style.visibility = "visible";