diff options
| author | Josh Kingsley <josh@joshkingsley.me> | 2025-10-29 18:26:41 +0200 |
|---|---|---|
| committer | Josh Kingsley <josh@joshkingsley.me> | 2025-10-29 18:26:41 +0200 |
| commit | 7ef8366bfc43775bf26e71e77bddf31af829dfde (patch) | |
| tree | 38f2551d3676838df5e35c97e5678f89fd75a56f /web/src/index.ts | |
| parent | 986e65f9ab7122995ae1d647df23d817cecf6816 (diff) | |
refactor(web): add decorators
Diffstat (limited to 'web/src/index.ts')
| -rw-r--r-- | web/src/index.ts | 215 |
1 files changed, 1 insertions, 214 deletions
diff --git a/web/src/index.ts b/web/src/index.ts index 97cfdf8..4c30907 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -1,214 +1 @@ -import Ratio from "./math/Ratio"; -import { Cell, CellRef, Doc, Grid, mapRowsInRange } from "./types"; -import { ActiveCellSelection, Selection } from "./selection"; -import renderGrid, { - getRenderedCell, - RenderedGrid, -} from "./components/grid/renderGrid"; - -function defaultDoc(): Doc { - const defaultCells: Cell[] = Array.from({ length: 16 }, () => ({ - widthRatio: new Ratio(1, 16), - })); - - return { - grids: [ - { - id: window.crypto.randomUUID(), - baseCellSize: 42, - baseCellWidthRatio: new Ratio(1, 16), - parts: [ - { - rows: Array.from({ length: 4 }, () => ({ - cells: [...defaultCells], - })), - }, - ], - }, - { - id: window.crypto.randomUUID(), - baseCellSize: 42, - baseCellWidthRatio: new Ratio(1, 16), - parts: [ - { - rows: Array.from({ length: 2 }, () => ({ - cells: [...defaultCells], - })), - }, - { - rows: Array.from({ length: 2 }, () => ({ - cells: [...defaultCells], - })), - }, - ], - }, - ], - }; -} - -export default class Notive { - #doc: Doc = defaultDoc(); - - get doc() { - return this.#doc; - } - - #gridsById = Object.fromEntries( - this.#doc.grids.map((grid) => [grid.id, renderGrid(grid)]), - ); - - getGrid(id: string): RenderedGrid | undefined { - return this.#gridsById[id]; - } - - #selection?: Selection; - - get selection() { - return this.#selection; - } - - #pendingSelection?: Selection; - - get pendingSelection() { - return this.#pendingSelection; - } - - selectCell(gridId: string, cellRef: CellRef) { - this.#selection = new ActiveCellSelection(gridId, cellRef); - this.#dispatchSelectionChanged(); - } - - startSelecting(gridId: string, cellRef: CellRef) { - this.#pendingSelection = new ActiveCellSelection(gridId, cellRef); - this.#dispatchSelectionChanged(); - } - - extendSelection(cellRef: CellRef) { - const newSelection = this.pendingSelection?.extend(cellRef); - - if (newSelection !== this.pendingSelection) { - this.#pendingSelection = newSelection; - this.#dispatchSelectionChanged(); - } - } - - finishSelecting() { - this.#selection = this.pendingSelection; - this.#pendingSelection = undefined; - this.#dispatchSelectionChanged(); - } - - #dispatchSelectionChanged() { - window.dispatchEvent(new CustomEvent("ntv:selectionchange")); - } - - subdivideSelection(subdivisions: number) { - const selection = this.selection; - if (!selection) return; - - const grid = this.getGrid(selection.gridId); - if (!grid) return; - - const startCellRef = selection.startCellRef(); - const endCellRef = selection.endCellRef(); - - const startCell = getRenderedCell(grid, startCellRef); - const endCell = getRenderedCell(grid, endCellRef); - if (!startCell || !endCell) return; - - const startRatio = - startCell.startRatio.compare(endCell.startRatio) <= 0 - ? startCell.startRatio - : endCell.startRatio; - - const endRatio = - startCell.endRatio.compare(endCell.endRatio) >= 0 - ? startCell.endRatio - : endCell.endRatio; - - const totalWidth = endRatio.subtract(startRatio); - const subdivisionWidth = totalWidth.divideRatio( - Ratio.fromInteger(subdivisions), - ); - - const newDoc = mapRowsInRange( - this.doc, - selection.gridId, - startCellRef, - endCellRef, - (row, rowRef) => { - const newCells: Cell[] = []; - let currentRatio = Ratio.fromInteger(0); - - for (const cell of row.cells) { - const cellStart = currentRatio; - const cellEnd = currentRatio.add(cell.widthRatio); - - // Cell is entirely before selection - if (cellEnd.compare(startRatio) <= 0) { - newCells.push(cell); - currentRatio = cellEnd; - continue; - } - - // Cell is entirely after selection - if (cellStart.compare(endRatio) >= 0) { - newCells.push(cell); - currentRatio = cellEnd; - continue; - } - - // First cell that overlaps - insert subdivisions - if (newCells.length === 0 || currentRatio.compare(startRatio) < 0) { - for (let i = 0; i < subdivisions; i++) { - newCells.push({ widthRatio: subdivisionWidth }); - } - } - - currentRatio = cellEnd; - } - - return { ...row, cells: newCells }; - }, - ); - - this.#doc = newDoc; - - this.#gridsById = Object.fromEntries( - this.#doc.grids.map((grid) => [grid.id, renderGrid(grid)]), - ); - - window.dispatchEvent( - new CustomEvent("ntv:grid:change", { - detail: { gridId: selection.gridId }, - }), - ); - } - - setCellValue(gridId: string, cellRef: CellRef, value: string | undefined) { - const grid = this.doc.grids.find((grid) => grid.id === gridId); - - if (!grid) return; - - const cell = - grid.parts[cellRef.partIndex].rows[cellRef.rowIndex].cells[ - cellRef.cellIndex - ]; - - grid.parts[cellRef.partIndex].rows[cellRef.rowIndex].cells[ - cellRef.cellIndex - ] = { ...cell, value }; - - this.#gridsById = Object.fromEntries( - this.#doc.grids.map((grid) => [grid.id, renderGrid(grid)]), - ); - - window.dispatchEvent( - new CustomEvent("ntv:grid:change", { - detail: { gridId }, - }), - ); - } -} - -window.notive = new Notive(); +import "./components"; |
