diff options
| author | Josh Kingsley <josh@joshkingsley.me> | 2025-10-26 22:59:39 +0200 |
|---|---|---|
| committer | Josh Kingsley <josh@joshkingsley.me> | 2025-10-26 22:59:39 +0200 |
| commit | 41b9d5840ddb6b484fc9f309a95d80f62832cfeb (patch) | |
| tree | 710ef3e016a0a8ff23f39247561587c5806581f8 /web/src/components/grid/index.ts | |
| parent | 74592676444cdb9bdc2fef5dc8c483667b557a5e (diff) | |
feat(web): editing cells
Diffstat (limited to 'web/src/components/grid/index.ts')
| -rw-r--r-- | web/src/components/grid/index.ts | 80 |
1 files changed, 73 insertions, 7 deletions
diff --git a/web/src/components/grid/index.ts b/web/src/components/grid/index.ts index 7d12a84..204ebea 100644 --- a/web/src/components/grid/index.ts +++ b/web/src/components/grid/index.ts @@ -3,6 +3,7 @@ import { CellRef } from "../../types"; import cellAtCoord from "./cellAtCoord"; import drawGrid, { getGridStyles } from "./drawGrid"; import "./index.css"; +import { getRenderedCell } from "./renderGrid"; class NotiveGridElement extends HTMLElement { #gridId!: string; @@ -20,7 +21,7 @@ class NotiveGridElement extends HTMLElement { return window.notive.getGrid(this.#gridId)!; } - canvasEl: HTMLCanvasElement = h.canvas(); + #canvasEl: HTMLCanvasElement = h.canvas(); connectedCallback() { if (!this.gridId) { @@ -30,17 +31,23 @@ class NotiveGridElement extends HTMLElement { window.addEventListener("ntv:selectionchange", () => this.draw()); window.addEventListener("ntv:grid:change", () => this.draw()); - this.canvasEl.addEventListener( + this.#canvasEl.addEventListener( "mousedown", this.#canvasMouseDownCallback.bind(this), ); - this.append(this.canvasEl); + this.#canvasEl.addEventListener( + "dblclick", + this.#canvasDoubleClickCallback.bind(this), + ); + + this.append(this.#canvasEl); + this.draw(); } draw() { - const ctx = this.canvasEl.getContext("2d"); + const ctx = this.#canvasEl.getContext("2d"); if (!ctx) throw new Error("Unable to get canvas context"); @@ -48,8 +55,8 @@ class NotiveGridElement extends HTMLElement { if (!grid) return; - this.canvasEl.setAttribute("width", grid.rect.width + "px"); - this.canvasEl.setAttribute("height", grid.rect.height + "px"); + this.#canvasEl.setAttribute("width", grid.rect.width + "px"); + this.#canvasEl.setAttribute("height", grid.rect.height + "px"); const styles = getGridStyles(this); @@ -66,7 +73,7 @@ class NotiveGridElement extends HTMLElement { this: NotiveGridElement, event: MouseEvent, ): CellRef | undefined { - const clientRect = this.canvasEl.getBoundingClientRect(); + const clientRect = this.#canvasEl.getBoundingClientRect(); const x = event.x - clientRect.x; const y = event.y - clientRect.y; return cellAtCoord(this.renderedGrid, x, y); @@ -108,6 +115,65 @@ class NotiveGridElement extends HTMLElement { this.#selectionAbortController = undefined; window.notive.finishSelecting(); } + + #editingCellRef?: CellRef; + + #editInputEl: HTMLInputElement = h.input({ + dataset: { editCell: "true" }, + onblur: () => { + this.#finishEditing(); + }, + onkeydown: (event) => { + switch (event.key) { + case "Enter": + this.#finishEditing(); + break; + + case "Escape": + this.#cancelEditing(); + break; + } + }, + }); + + #canvasDoubleClickCallback(this: NotiveGridElement, event: MouseEvent) { + const cellRef = this.#mouseEventCellRef(event); + + if (!cellRef) return; + + const grid = window.notive.getGrid(this.gridId); + + if (!grid) return; + + const cell = getRenderedCell(grid, cellRef); + + if (!cell) return; + + this.#editingCellRef = cellRef; + + this.append(this.#editInputEl); + + this.#editInputEl.value = cell.value || ""; + this.#editInputEl.style.left = cell.rect.topLeft.x + 2 + "px"; + this.#editInputEl.style.top = cell.rect.topLeft.y + 2 + "px"; + this.#editInputEl.style.width = cell.rect.width - 3 + "px"; + this.#editInputEl.style.height = cell.rect.height - 3 + "px"; + this.#editInputEl.focus(); + } + + #cancelEditing() { + this.#editInputEl.remove(); + } + + #finishEditing() { + this.#editInputEl.remove(); + + window.notive.setCellValue( + this.gridId, + this.#editingCellRef!, + this.#editInputEl.value, + ); + } } customElements.define("ntv-grid", NotiveGridElement); |
