@fieldnotes/core 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -85,7 +85,17 @@ interface ShapeElement extends BaseElement {
85
85
  strokeWidth: number;
86
86
  fillColor: string;
87
87
  }
88
- type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement;
88
+ type HexOrientation = 'pointy' | 'flat';
89
+ interface GridElement extends BaseElement {
90
+ type: 'grid';
91
+ gridType: 'square' | 'hex';
92
+ hexOrientation: HexOrientation;
93
+ cellSize: number;
94
+ strokeColor: string;
95
+ strokeWidth: number;
96
+ opacity: number;
97
+ }
98
+ type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
89
99
  type ElementType = CanvasElement['type'];
90
100
 
91
101
  interface Layer {
@@ -437,6 +447,16 @@ declare class Viewport {
437
447
  w: number;
438
448
  h: number;
439
449
  }): string;
450
+ addGrid(input: {
451
+ gridType?: 'square' | 'hex';
452
+ hexOrientation?: 'pointy' | 'flat';
453
+ cellSize?: number;
454
+ strokeColor?: string;
455
+ strokeWidth?: number;
456
+ opacity?: number;
457
+ }): string;
458
+ updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
459
+ removeGrid(): void;
440
460
  destroy(): void;
441
461
  private startRenderLoop;
442
462
  private render;
@@ -469,8 +489,12 @@ declare class ElementRenderer {
469
489
  private store;
470
490
  private imageCache;
471
491
  private onImageLoad;
492
+ private camera;
493
+ private canvasSize;
472
494
  setStore(store: ElementStore): void;
473
495
  setOnImageLoad(callback: () => void): void;
496
+ setCamera(camera: Camera): void;
497
+ setCanvasSize(w: number, h: number): void;
474
498
  isDomElement(element: CanvasElement): boolean;
475
499
  renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
476
500
  private renderStroke;
@@ -480,6 +504,7 @@ declare class ElementRenderer {
480
504
  private renderShape;
481
505
  private fillShapePath;
482
506
  private strokeShapePath;
507
+ private renderGrid;
483
508
  private renderImage;
484
509
  private getImage;
485
510
  }
@@ -562,6 +587,15 @@ interface ShapeInput extends BaseDefaults {
562
587
  fillColor?: string;
563
588
  }
564
589
  declare function createShape(input: ShapeInput): ShapeElement;
590
+ interface GridInput extends BaseDefaults {
591
+ gridType?: 'square' | 'hex';
592
+ hexOrientation?: HexOrientation;
593
+ cellSize?: number;
594
+ strokeColor?: string;
595
+ strokeWidth?: number;
596
+ opacity?: number;
597
+ }
598
+ declare function createGrid(input: GridInput): GridElement;
565
599
  declare function createText(input: TextInput): TextElement;
566
600
 
567
601
  interface Rect {
@@ -824,6 +858,6 @@ declare class UpdateLayerCommand implements Command {
824
858
  undo(_store: ElementStore): void;
825
859
  }
826
860
 
827
- declare const VERSION = "0.6.0";
861
+ declare const VERSION = "0.6.1";
828
862
 
829
- export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
863
+ export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
package/dist/index.d.ts CHANGED
@@ -85,7 +85,17 @@ interface ShapeElement extends BaseElement {
85
85
  strokeWidth: number;
86
86
  fillColor: string;
87
87
  }
88
- type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement;
88
+ type HexOrientation = 'pointy' | 'flat';
89
+ interface GridElement extends BaseElement {
90
+ type: 'grid';
91
+ gridType: 'square' | 'hex';
92
+ hexOrientation: HexOrientation;
93
+ cellSize: number;
94
+ strokeColor: string;
95
+ strokeWidth: number;
96
+ opacity: number;
97
+ }
98
+ type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
89
99
  type ElementType = CanvasElement['type'];
90
100
 
91
101
  interface Layer {
@@ -437,6 +447,16 @@ declare class Viewport {
437
447
  w: number;
438
448
  h: number;
439
449
  }): string;
450
+ addGrid(input: {
451
+ gridType?: 'square' | 'hex';
452
+ hexOrientation?: 'pointy' | 'flat';
453
+ cellSize?: number;
454
+ strokeColor?: string;
455
+ strokeWidth?: number;
456
+ opacity?: number;
457
+ }): string;
458
+ updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
459
+ removeGrid(): void;
440
460
  destroy(): void;
441
461
  private startRenderLoop;
442
462
  private render;
@@ -469,8 +489,12 @@ declare class ElementRenderer {
469
489
  private store;
470
490
  private imageCache;
471
491
  private onImageLoad;
492
+ private camera;
493
+ private canvasSize;
472
494
  setStore(store: ElementStore): void;
473
495
  setOnImageLoad(callback: () => void): void;
496
+ setCamera(camera: Camera): void;
497
+ setCanvasSize(w: number, h: number): void;
474
498
  isDomElement(element: CanvasElement): boolean;
475
499
  renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
476
500
  private renderStroke;
@@ -480,6 +504,7 @@ declare class ElementRenderer {
480
504
  private renderShape;
481
505
  private fillShapePath;
482
506
  private strokeShapePath;
507
+ private renderGrid;
483
508
  private renderImage;
484
509
  private getImage;
485
510
  }
@@ -562,6 +587,15 @@ interface ShapeInput extends BaseDefaults {
562
587
  fillColor?: string;
563
588
  }
564
589
  declare function createShape(input: ShapeInput): ShapeElement;
590
+ interface GridInput extends BaseDefaults {
591
+ gridType?: 'square' | 'hex';
592
+ hexOrientation?: HexOrientation;
593
+ cellSize?: number;
594
+ strokeColor?: string;
595
+ strokeWidth?: number;
596
+ opacity?: number;
597
+ }
598
+ declare function createGrid(input: GridInput): GridElement;
565
599
  declare function createText(input: TextInput): TextElement;
566
600
 
567
601
  interface Rect {
@@ -824,6 +858,6 @@ declare class UpdateLayerCommand implements Command {
824
858
  undo(_store: ElementStore): void;
825
859
  }
826
860
 
827
- declare const VERSION = "0.6.0";
861
+ declare const VERSION = "0.6.1";
828
862
 
829
- export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
863
+ export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
package/dist/index.js CHANGED
@@ -84,7 +84,7 @@ function validateState(data) {
84
84
  ];
85
85
  }
86
86
  }
87
- var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape"]);
87
+ var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape", "grid"]);
88
88
  function validateElement(el) {
89
89
  if (!el || typeof el !== "object") {
90
90
  throw new Error("Invalid element: expected an object");
@@ -205,7 +205,11 @@ var AutoSave = class {
205
205
  if (typeof localStorage === "undefined") return;
206
206
  const layers = this.layerManager?.snapshot() ?? [];
207
207
  const state = exportState(this.store.snapshot(), this.camera, layers);
208
- localStorage.setItem(this.key, JSON.stringify(state));
208
+ try {
209
+ localStorage.setItem(this.key, JSON.stringify(state));
210
+ } catch {
211
+ console.warn("Auto-save failed: storage quota exceeded. State too large for localStorage.");
212
+ }
209
213
  }
210
214
  };
211
215
 
@@ -941,6 +945,118 @@ function smoothToSegments(points) {
941
945
  return segments;
942
946
  }
943
947
 
948
+ // src/elements/grid-renderer.ts
949
+ function getSquareGridLines(bounds, cellSize) {
950
+ if (cellSize <= 0) return { verticals: [], horizontals: [] };
951
+ const verticals = [];
952
+ const startX = Math.floor(bounds.minX / cellSize) * cellSize;
953
+ const endX = Math.ceil(bounds.maxX / cellSize) * cellSize;
954
+ for (let x = startX; x <= endX; x += cellSize) {
955
+ verticals.push(x);
956
+ }
957
+ const horizontals = [];
958
+ const startY = Math.floor(bounds.minY / cellSize) * cellSize;
959
+ const endY = Math.ceil(bounds.maxY / cellSize) * cellSize;
960
+ for (let y = startY; y <= endY; y += cellSize) {
961
+ horizontals.push(y);
962
+ }
963
+ return { verticals, horizontals };
964
+ }
965
+ function getHexVertices(cx, cy, circumradius, orientation) {
966
+ const vertices = [];
967
+ const angleOffset = orientation === "pointy" ? -Math.PI / 2 : 0;
968
+ for (let i = 0; i < 6; i++) {
969
+ const angle = Math.PI / 3 * i + angleOffset;
970
+ vertices.push({
971
+ x: cx + circumradius * Math.cos(angle),
972
+ y: cy + circumradius * Math.sin(angle)
973
+ });
974
+ }
975
+ return vertices;
976
+ }
977
+ function getHexCenters(bounds, circumradius, orientation) {
978
+ if (circumradius <= 0) return [];
979
+ const centers = [];
980
+ if (orientation === "pointy") {
981
+ const hexW = Math.sqrt(3) * circumradius;
982
+ const hexH = 2 * circumradius;
983
+ const rowH = hexH * 0.75;
984
+ const startRow = Math.floor((bounds.minY - circumradius) / rowH);
985
+ const endRow = Math.ceil((bounds.maxY + circumradius) / rowH);
986
+ const startCol = Math.floor((bounds.minX - hexW) / hexW);
987
+ const endCol = Math.ceil((bounds.maxX + hexW) / hexW);
988
+ for (let row = startRow; row <= endRow; row++) {
989
+ const offsetX = row % 2 !== 0 ? hexW / 2 : 0;
990
+ for (let col = startCol; col <= endCol; col++) {
991
+ centers.push({
992
+ x: col * hexW + offsetX,
993
+ y: row * rowH
994
+ });
995
+ }
996
+ }
997
+ } else {
998
+ const hexW = 2 * circumradius;
999
+ const hexH = Math.sqrt(3) * circumradius;
1000
+ const colW = hexW * 0.75;
1001
+ const startCol = Math.floor((bounds.minX - circumradius) / colW);
1002
+ const endCol = Math.ceil((bounds.maxX + circumradius) / colW);
1003
+ const startRow = Math.floor((bounds.minY - hexH) / hexH);
1004
+ const endRow = Math.ceil((bounds.maxY + hexH) / hexH);
1005
+ for (let col = startCol; col <= endCol; col++) {
1006
+ const offsetY = col % 2 !== 0 ? hexH / 2 : 0;
1007
+ for (let row = startRow; row <= endRow; row++) {
1008
+ centers.push({
1009
+ x: col * colW,
1010
+ y: row * hexH + offsetY
1011
+ });
1012
+ }
1013
+ }
1014
+ }
1015
+ return centers;
1016
+ }
1017
+ function renderSquareGrid(ctx, bounds, cellSize, strokeColor, strokeWidth, opacity) {
1018
+ if (cellSize <= 0) return;
1019
+ const { verticals, horizontals } = getSquareGridLines(bounds, cellSize);
1020
+ ctx.save();
1021
+ ctx.strokeStyle = strokeColor;
1022
+ ctx.lineWidth = strokeWidth;
1023
+ ctx.globalAlpha = opacity;
1024
+ ctx.beginPath();
1025
+ for (const x of verticals) {
1026
+ ctx.moveTo(x, bounds.minY);
1027
+ ctx.lineTo(x, bounds.maxY);
1028
+ }
1029
+ for (const y of horizontals) {
1030
+ ctx.moveTo(bounds.minX, y);
1031
+ ctx.lineTo(bounds.maxX, y);
1032
+ }
1033
+ ctx.stroke();
1034
+ ctx.restore();
1035
+ }
1036
+ function renderHexGrid(ctx, bounds, cellSize, orientation, strokeColor, strokeWidth, opacity) {
1037
+ if (cellSize <= 0) return;
1038
+ const centers = getHexCenters(bounds, cellSize, orientation);
1039
+ ctx.save();
1040
+ ctx.strokeStyle = strokeColor;
1041
+ ctx.lineWidth = strokeWidth;
1042
+ ctx.globalAlpha = opacity;
1043
+ ctx.beginPath();
1044
+ for (const center of centers) {
1045
+ const verts = getHexVertices(center.x, center.y, cellSize, orientation);
1046
+ const first = verts[0];
1047
+ if (!first) continue;
1048
+ ctx.moveTo(first.x, first.y);
1049
+ for (let i = 1; i < verts.length; i++) {
1050
+ const v = verts[i];
1051
+ if (!v) continue;
1052
+ ctx.lineTo(v.x, v.y);
1053
+ }
1054
+ ctx.closePath();
1055
+ }
1056
+ ctx.stroke();
1057
+ ctx.restore();
1058
+ }
1059
+
944
1060
  // src/elements/element-renderer.ts
945
1061
  var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "html", "text"]);
946
1062
  var ARROWHEAD_LENGTH = 12;
@@ -949,12 +1065,20 @@ var ElementRenderer = class {
949
1065
  store = null;
950
1066
  imageCache = /* @__PURE__ */ new Map();
951
1067
  onImageLoad = null;
1068
+ camera = null;
1069
+ canvasSize = null;
952
1070
  setStore(store) {
953
1071
  this.store = store;
954
1072
  }
955
1073
  setOnImageLoad(callback) {
956
1074
  this.onImageLoad = callback;
957
1075
  }
1076
+ setCamera(camera) {
1077
+ this.camera = camera;
1078
+ }
1079
+ setCanvasSize(w, h) {
1080
+ this.canvasSize = { w, h };
1081
+ }
958
1082
  isDomElement(element) {
959
1083
  return DOM_ELEMENT_TYPES.has(element.type);
960
1084
  }
@@ -972,6 +1096,9 @@ var ElementRenderer = class {
972
1096
  case "image":
973
1097
  this.renderImage(ctx, element);
974
1098
  break;
1099
+ case "grid":
1100
+ this.renderGrid(ctx, element);
1101
+ break;
975
1102
  }
976
1103
  }
977
1104
  renderStroke(ctx, stroke) {
@@ -1107,6 +1234,42 @@ var ElementRenderer = class {
1107
1234
  }
1108
1235
  }
1109
1236
  }
1237
+ renderGrid(ctx, grid) {
1238
+ if (!this.canvasSize) return;
1239
+ const cam = this.camera;
1240
+ if (!cam) return;
1241
+ const topLeft = cam.screenToWorld({ x: 0, y: 0 });
1242
+ const bottomRight = cam.screenToWorld({
1243
+ x: this.canvasSize.w,
1244
+ y: this.canvasSize.h
1245
+ });
1246
+ const bounds = {
1247
+ minX: topLeft.x,
1248
+ minY: topLeft.y,
1249
+ maxX: bottomRight.x,
1250
+ maxY: bottomRight.y
1251
+ };
1252
+ if (grid.gridType === "hex") {
1253
+ renderHexGrid(
1254
+ ctx,
1255
+ bounds,
1256
+ grid.cellSize,
1257
+ grid.hexOrientation,
1258
+ grid.strokeColor,
1259
+ grid.strokeWidth,
1260
+ grid.opacity
1261
+ );
1262
+ } else {
1263
+ renderSquareGrid(
1264
+ ctx,
1265
+ bounds,
1266
+ grid.cellSize,
1267
+ grid.strokeColor,
1268
+ grid.strokeWidth,
1269
+ grid.opacity
1270
+ );
1271
+ }
1272
+ }
1110
1273
  renderImage(ctx, image) {
1111
1274
  const img = this.getImage(image.src);
1112
1275
  if (!img) return;
@@ -1549,6 +1712,22 @@ function createShape(input) {
1549
1712
  fillColor: input.fillColor ?? "none"
1550
1713
  };
1551
1714
  }
1715
+ function createGrid(input) {
1716
+ return {
1717
+ id: createId("grid"),
1718
+ type: "grid",
1719
+ position: input.position ?? { x: 0, y: 0 },
1720
+ zIndex: input.zIndex ?? 0,
1721
+ locked: input.locked ?? false,
1722
+ layerId: input.layerId ?? "",
1723
+ gridType: input.gridType ?? "square",
1724
+ hexOrientation: input.hexOrientation ?? "pointy",
1725
+ cellSize: input.cellSize ?? 40,
1726
+ strokeColor: input.strokeColor ?? "#000000",
1727
+ strokeWidth: input.strokeWidth ?? 1,
1728
+ opacity: input.opacity ?? 1
1729
+ };
1730
+ }
1552
1731
  function createText(input) {
1553
1732
  return {
1554
1733
  id: createId("text"),
@@ -1726,6 +1905,7 @@ var Viewport = class {
1726
1905
  this.toolManager = new ToolManager();
1727
1906
  this.renderer = new ElementRenderer();
1728
1907
  this.renderer.setStore(this.store);
1908
+ this.renderer.setCamera(this.camera);
1729
1909
  this.renderer.setOnImageLoad(() => this.requestRender());
1730
1910
  this.noteEditor = new NoteEditor();
1731
1911
  this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
@@ -1872,6 +2052,34 @@ var Viewport = class {
1872
2052
  this.requestRender();
1873
2053
  return el.id;
1874
2054
  }
2055
+ addGrid(input) {
2056
+ const existing = this.store.getElementsByType("grid")[0];
2057
+ this.historyRecorder.begin();
2058
+ if (existing) {
2059
+ this.store.remove(existing.id);
2060
+ }
2061
+ const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
2062
+ this.store.add(grid);
2063
+ this.historyRecorder.commit();
2064
+ this.requestRender();
2065
+ return grid.id;
2066
+ }
2067
+ updateGrid(updates) {
2068
+ const grid = this.store.getElementsByType("grid")[0];
2069
+ if (!grid) return;
2070
+ this.historyRecorder.begin();
2071
+ this.store.update(grid.id, updates);
2072
+ this.historyRecorder.commit();
2073
+ this.requestRender();
2074
+ }
2075
+ removeGrid() {
2076
+ const grid = this.store.getElementsByType("grid")[0];
2077
+ if (!grid) return;
2078
+ this.historyRecorder.begin();
2079
+ this.store.remove(grid.id);
2080
+ this.historyRecorder.commit();
2081
+ this.requestRender();
2082
+ }
1875
2083
  destroy() {
1876
2084
  cancelAnimationFrame(this.animFrameId);
1877
2085
  this.stopInteracting();
@@ -1903,6 +2111,7 @@ var Viewport = class {
1903
2111
  const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
1904
2112
  ctx.save();
1905
2113
  ctx.scale(dpr, dpr);
2114
+ this.renderer.setCanvasSize(this.canvasEl.clientWidth, this.canvasEl.clientHeight);
1906
2115
  this.background.render(ctx, this.camera);
1907
2116
  ctx.save();
1908
2117
  ctx.translate(this.camera.position.x, this.camera.position.y);
@@ -2889,6 +3098,7 @@ var SelectTool = class {
2889
3098
  for (const el of ctx.store.getAll()) {
2890
3099
  if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
2891
3100
  if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
3101
+ if (el.type === "grid") continue;
2892
3102
  const bounds = this.getElementBounds(el);
2893
3103
  if (bounds && this.rectsOverlap(marquee, bounds)) {
2894
3104
  ids.push(el.id);
@@ -2925,11 +3135,13 @@ var SelectTool = class {
2925
3135
  for (const el of elements) {
2926
3136
  if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
2927
3137
  if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
3138
+ if (el.type === "grid") continue;
2928
3139
  if (this.isInsideBounds(world, el)) return el;
2929
3140
  }
2930
3141
  return null;
2931
3142
  }
2932
3143
  isInsideBounds(point, el) {
3144
+ if (el.type === "grid") return false;
2933
3145
  if ("size" in el) {
2934
3146
  const s = el.size;
2935
3147
  return point.x >= el.position.x && point.x <= el.position.x + s.w && point.y >= el.position.y && point.y <= el.position.y + s.h;
@@ -3355,7 +3567,7 @@ var UpdateLayerCommand = class {
3355
3567
  };
3356
3568
 
3357
3569
  // src/index.ts
3358
- var VERSION = "0.6.0";
3570
+ var VERSION = "0.6.1";
3359
3571
  export {
3360
3572
  AddElementCommand,
3361
3573
  ArrowTool,
@@ -3389,6 +3601,7 @@ export {
3389
3601
  Viewport,
3390
3602
  clearStaleBindings,
3391
3603
  createArrow,
3604
+ createGrid,
3392
3605
  createHtmlElement,
3393
3606
  createId,
3394
3607
  createImage,