summaryrefslogtreecommitdiff
path: root/packages/web/src/grid.ts
diff options
context:
space:
mode:
authorJosh Kingsley <josh@joshkingsley.me>2025-11-23 19:27:57 +0200
committerJosh Kingsley <josh@joshkingsley.me>2025-11-23 19:27:57 +0200
commit602145c956bb594ca0d0e10601cc4ad1a71cf70d (patch)
treed9f9980bd2054cff5819d01379f5c1c55f8eb66d /packages/web/src/grid.ts
parentc2a6efb1b761014a90d90373cad47a14054af40b (diff)
feat: integrate web and doc packages
Diffstat (limited to 'packages/web/src/grid.ts')
-rw-r--r--packages/web/src/grid.ts109
1 files changed, 109 insertions, 0 deletions
diff --git a/packages/web/src/grid.ts b/packages/web/src/grid.ts
new file mode 100644
index 0000000..e849803
--- /dev/null
+++ b/packages/web/src/grid.ts
@@ -0,0 +1,109 @@
+import { produce } from "immer";
+import renderGrid, { getRenderedCell } from "./components/grid/renderGrid";
+import { getSelectionRange, GridSelection } from "./components/grid/selection";
+import Ratio from "./math/Ratio";
+import { Cell, Grid, renderedRowIndexToRef } from "./types";
+
+export function getSelectedSubdivisionsCount(
+ grid: Grid,
+ selection: GridSelection,
+): number | undefined {
+ const renderedGrid = renderGrid(grid);
+
+ const [startCellRef, endCellRef] = getSelectionRange(selection);
+ const startCell = getRenderedCell(renderedGrid, startCellRef);
+ const endCell = getRenderedCell(renderedGrid, endCellRef);
+
+ if (!startCell || !endCell) throw new Error("Invalid cell refs");
+
+ const startRenderedRowIndex = Math.min(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const endRenderedRowIndex = Math.max(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const startRatio = Ratio.min(startCell.startRatio, endCell.startRatio);
+ const endRatio = Ratio.max(startCell.endRatio, endCell.endRatio);
+
+ return Math.min(
+ ...renderedGrid.renderedRows
+ .slice(startRenderedRowIndex, endRenderedRowIndex + 1)
+ .map((row) => {
+ const startCellIndex = row.renderedCells.findIndex((cell) =>
+ cell.startRatio.equals(startRatio),
+ );
+
+ const endCellIndex = row.renderedCells.findLastIndex((cell) =>
+ cell.endRatio.equals(endRatio),
+ );
+
+ return endCellIndex - startCellIndex + 1;
+ }),
+ );
+}
+
+export function changeSelectedSubdivisions(
+ grid: Grid,
+ selection: GridSelection,
+ subdivisions: number,
+): Grid {
+ const renderedGrid = renderGrid(grid);
+ const [startCellRef, endCellRef] = getSelectionRange(selection);
+ const startCell = getRenderedCell(renderedGrid, startCellRef);
+ const endCell = getRenderedCell(renderedGrid, endCellRef);
+ if (!startCell || !endCell) throw new Error("Invalid cell refs");
+
+ const startRenderedRowIndex = Math.min(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const endRenderedRowIndex = Math.max(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const startRatio = Ratio.min(startCell.startRatio, endCell.startRatio);
+ const endRatio = Ratio.max(startCell.endRatio, endCell.endRatio);
+ const selectedWidthRatio = endRatio.subtract(startRatio);
+ const widthRatio = selectedWidthRatio.divideRatio(
+ Ratio.fromInteger(subdivisions),
+ );
+
+ return produce(grid, (draft) => {
+ for (
+ let renderedRowIndex = startRenderedRowIndex;
+ renderedRowIndex <= endRenderedRowIndex;
+ renderedRowIndex++
+ ) {
+ const renderedRow = renderedGrid.renderedRows[renderedRowIndex];
+
+ const startCellIndex = renderedRow.renderedCells.findIndex((cell) =>
+ cell.startRatio.equals(startRatio),
+ );
+
+ const endCellIndex = renderedRow.renderedCells.findLastIndex((cell) =>
+ cell.endRatio.equals(endRatio),
+ );
+
+ const { partIndex, rowIndex } = renderedRowIndexToRef(
+ grid,
+ renderedRowIndex,
+ );
+
+ const row = draft.parts[partIndex].rows[rowIndex];
+ const previousCells = row.cells.slice(0, startCellIndex);
+ const nextCells = row.cells.slice(endCellIndex + 1);
+
+ const newCells: Cell[] = Array.from({ length: subdivisions }, () => ({
+ widthRatio,
+ }));
+
+ row.cells = [...previousCells, ...newCells, ...nextCells];
+ }
+ });
+}