summaryrefslogtreecommitdiff
path: root/web/src/components/grid
diff options
context:
space:
mode:
authorJosh Kingsley <josh@joshkingsley.me>2025-10-29 18:26:41 +0200
committerJosh Kingsley <josh@joshkingsley.me>2025-10-29 18:26:41 +0200
commit7ef8366bfc43775bf26e71e77bddf31af829dfde (patch)
tree38f2551d3676838df5e35c97e5678f89fd75a56f /web/src/components/grid
parent986e65f9ab7122995ae1d647df23d817cecf6816 (diff)
refactor(web): add decorators
Diffstat (limited to 'web/src/components/grid')
-rw-r--r--web/src/components/grid/index.css4
-rw-r--r--web/src/components/grid/index.ts99
2 files changed, 50 insertions, 53 deletions
diff --git a/web/src/components/grid/index.css b/web/src/components/grid/index.css
index 64153ed..c29f55d 100644
--- a/web/src/components/grid/index.css
+++ b/web/src/components/grid/index.css
@@ -33,7 +33,7 @@
display: none;
}
- ntv-grid input[data-edit-cell] {
+ ntv-grid input[data-edit] {
position: absolute;
vertical-align: baseline;
background: var(--color-neutral-800);
@@ -43,7 +43,7 @@
text-align: center;
}
- ntv-grid input[data-edit-cell]:focus-visible {
+ ntv-grid input[data-edit]:focus-visible {
outline: none;
}
}
diff --git a/web/src/components/grid/index.ts b/web/src/components/grid/index.ts
index 2c00eb8..6c7f735 100644
--- a/web/src/components/grid/index.ts
+++ b/web/src/components/grid/index.ts
@@ -1,4 +1,5 @@
-import h, { type CreateElement } from "../../html";
+import NotiveElement, { customElement, eventHandler } from "../../element";
+import h from "../../html";
import { ActiveCellSelection, Selection } from "../../selection";
import { CellRef } from "../../types";
import cellAtCoord from "./cellAtCoord";
@@ -7,7 +8,8 @@ import drawSelection, { SelectionStyles } from "./drawSelection";
import "./index.css";
import { getRenderedCell, RenderedGrid } from "./renderGrid";
-export class NotiveGridElement extends HTMLElement {
+@customElement("ntv-grid")
+export class NotiveGridElement extends NotiveElement {
#internals: ElementInternals = this.attachInternals();
grid?: RenderedGrid;
@@ -23,28 +25,11 @@ export class NotiveGridElement extends HTMLElement {
this.drawSelection();
}
- #ongridselectionchange?: ((event: GridSelectionEvent) => any) | undefined;
+ @eventHandler("ntv:grid:selectionchange")
+ ongridselectionchange?: (event: GridSelectionEvent) => any;
- get ongridselectionchange() {
- return this.#ongridselectionchange;
- }
-
- set ongridselectionchange(
- handler: ((event: GridSelectionEvent) => any) | undefined,
- ) {
- if (this.#ongridselectionchange) {
- this.removeEventListener(
- "ntv:grid:selectionchange",
- this.#ongridselectionchange,
- );
- }
-
- this.#ongridselectionchange = handler;
-
- if (handler) {
- this.addEventListener("ntv:grid:selectionchange", handler);
- }
- }
+ @eventHandler("ntv:grid:cellchange")
+ oncellchange?: (event: GridCellChangeEvent) => any;
canvas: HTMLCanvasElement = h.canvas({
onmousedown: (event) => {
@@ -53,6 +38,12 @@ export class NotiveGridElement extends HTMLElement {
if (!cellRef) return;
this.startSelecting(cellRef);
},
+ ondblclick: (event) => {
+ if (!this.grid) return;
+ const cellRef = this.#mouseEventCellRef(event);
+ if (!cellRef) return;
+ this.startEditing(cellRef);
+ },
});
selectionCanvas: HTMLCanvasElement = h.canvas({
@@ -188,11 +179,9 @@ export class NotiveGridElement extends HTMLElement {
#editingCellRef?: CellRef;
- #editInputEl: HTMLInputElement = h.input({
- dataset: { editCell: "true" },
- onblur: () => {
- this.#finishEditing();
- },
+ #editInput: HTMLInputElement = h.input({
+ dataset: { edit: "true" },
+ onblur: () => this.#finishEditing(),
onkeydown: (event) => {
switch (event.key) {
case "Enter":
@@ -206,50 +195,45 @@ export class NotiveGridElement extends HTMLElement {
},
});
- #canvasDoubleClickCallback(this: NotiveGridElement, event: MouseEvent) {
+ startEditing(cellRef: CellRef) {
if (!this.grid) return;
- const cellRef = this.#mouseEventCellRef(event);
-
- if (!cellRef) return;
-
const cell = getRenderedCell(this.grid, cellRef);
if (!cell) return;
this.#editingCellRef = cellRef;
- this.append(this.#editInputEl);
+ this.append(this.#editInput);
- 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();
+ this.#editInput.value = cell.value || "";
+
+ Object.assign(this.#editInput.style, {
+ left: cell.rect.topLeft.x + 2 + "px",
+ top: cell.rect.topLeft.y + 2 + "px",
+ width: cell.rect.width - 3 + "px",
+ height: cell.rect.height - 3 + "px",
+ });
+
+ this.#editInput.focus();
}
#cancelEditing() {
- this.#editInputEl.remove();
+ this.#editInput.remove();
}
#finishEditing() {
- this.#editInputEl.remove();
+ this.#editInput.remove();
- if (!this.grid) return;
+ if (!this.grid || !this.#editingCellRef) return;
- window.notive.setCellValue(
- this.grid.id,
- this.#editingCellRef!,
- this.#editInputEl.value,
+ this.dispatchEvent(
+ new GridCellChangeEvent(this.#editingCellRef, this.#editInput.value),
);
}
}
-customElements.define("ntv-grid", NotiveGridElement);
-
-export default ((...args: any[]): NotiveGridElement =>
- (h as any)["ntv-grid"](...args)) as CreateElement<NotiveGridElement>;
+export default NotiveGridElement.makeFactory();
export class GridSelectionEvent extends Event {
selection: Selection;
@@ -260,8 +244,21 @@ export class GridSelectionEvent extends Event {
}
}
+export class GridCellChangeEvent extends Event {
+ cellRef: CellRef;
+ value?: string;
+
+ constructor(cellRef: CellRef, value: string | undefined) {
+ super("ntv:grid:cellchange");
+
+ this.cellRef = cellRef;
+ this.value = value;
+ }
+}
+
declare global {
interface HTMLElementEventMap {
"ntv:grid:selectionchange": GridSelectionEvent;
+ "ntv:grid:cellchange": GridCellChangeEvent;
}
}