diff options
| author | Josh Kingsley <josh@joshkingsley.me> | 2025-11-23 19:27:57 +0200 |
|---|---|---|
| committer | Josh Kingsley <josh@joshkingsley.me> | 2025-11-23 19:27:57 +0200 |
| commit | 602145c956bb594ca0d0e10601cc4ad1a71cf70d (patch) | |
| tree | d9f9980bd2054cff5819d01379f5c1c55f8eb66d /packages/web/src/grid.ts | |
| parent | c2a6efb1b761014a90d90373cad47a14054af40b (diff) | |
feat: integrate web and doc packages
Diffstat (limited to 'packages/web/src/grid.ts')
| -rw-r--r-- | packages/web/src/grid.ts | 109 |
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]; + } + }); +} |
