@fieldnotes/core 0.10.0 → 0.11.1

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.cjs CHANGED
@@ -398,7 +398,13 @@ function exportState(elements, camera, layers = []) {
398
398
  position: { ...camera.position },
399
399
  zoom: camera.zoom
400
400
  },
401
- elements: elements.map((el) => structuredClone(el)),
401
+ elements: elements.map((el) => {
402
+ const clone = structuredClone(el);
403
+ if (clone.type === "arrow") {
404
+ delete clone.cachedControlPoint;
405
+ }
406
+ return clone;
407
+ }),
402
408
  layers: layers.map((l) => ({ ...l }))
403
409
  };
404
410
  }
@@ -861,6 +867,7 @@ var InputHandler = class {
861
867
  historyRecorder;
862
868
  historyStack;
863
869
  isToolActive = false;
870
+ lastPointerEvent = null;
864
871
  abortController = new AbortController();
865
872
  setToolManager(toolManager, toolContext) {
866
873
  this.toolManager = toolManager;
@@ -868,6 +875,7 @@ var InputHandler = class {
868
875
  }
869
876
  destroy() {
870
877
  this.abortController.abort();
878
+ this.lastPointerEvent = null;
871
879
  }
872
880
  bind() {
873
881
  const opts = { signal: this.abortController.signal };
@@ -903,11 +911,12 @@ var InputHandler = class {
903
911
  this.lastPointer = { x: e.clientX, y: e.clientY };
904
912
  return;
905
913
  }
906
- if (this.activePointers.size === 1 && e.button === 0) {
914
+ if (this.activePointers.size === 1 && (e.button === 0 || e.pointerType === "touch" || e.pointerType === "pen")) {
907
915
  this.dispatchToolDown(e);
908
916
  }
909
917
  };
910
918
  onPointerMove = (e) => {
919
+ this.lastPointerEvent = e;
911
920
  if (this.activePointers.has(e.pointerId)) {
912
921
  this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
913
922
  }
@@ -929,6 +938,10 @@ var InputHandler = class {
929
938
  }
930
939
  };
931
940
  onPointerUp = (e) => {
941
+ try {
942
+ this.element.releasePointerCapture(e.pointerId);
943
+ } catch {
944
+ }
932
945
  this.activePointers.delete(e.pointerId);
933
946
  if (this.activePointers.size < 2) {
934
947
  this.lastPinchDistance = 0;
@@ -961,6 +974,13 @@ var InputHandler = class {
961
974
  onKeyUp = (e) => {
962
975
  if (e.key === " ") {
963
976
  this.spaceHeld = false;
977
+ if (this.activePointers.size === 0) {
978
+ if (this.lastPointerEvent) {
979
+ this.dispatchToolHover(this.lastPointerEvent);
980
+ } else {
981
+ this.toolContext?.setCursor?.("default");
982
+ }
983
+ }
964
984
  }
965
985
  };
966
986
  startPinch() {
@@ -4288,6 +4308,7 @@ var Viewport = class {
4288
4308
  renderLoop;
4289
4309
  domNodeManager;
4290
4310
  interactMode;
4311
+ gridChangeListeners = /* @__PURE__ */ new Set();
4291
4312
  get ctx() {
4292
4313
  return this.canvasEl.getContext("2d");
4293
4314
  }
@@ -4392,6 +4413,22 @@ var Viewport = class {
4392
4413
  this.historyRecorder.commit();
4393
4414
  this.requestRender();
4394
4415
  }
4416
+ getGridInfo() {
4417
+ const grid = this.store.getElementsByType("grid")[0];
4418
+ if (!grid) return null;
4419
+ return {
4420
+ gridType: grid.gridType,
4421
+ hexOrientation: grid.hexOrientation,
4422
+ cellSize: grid.cellSize,
4423
+ cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
4424
+ };
4425
+ }
4426
+ onGridChange(listener) {
4427
+ this.gridChangeListeners.add(listener);
4428
+ return () => {
4429
+ this.gridChangeListeners.delete(listener);
4430
+ };
4431
+ }
4395
4432
  getRenderStats() {
4396
4433
  return this.renderLoop.getStats();
4397
4434
  }
@@ -4544,7 +4581,10 @@ var Viewport = class {
4544
4581
  position: "relative",
4545
4582
  width: "100%",
4546
4583
  height: "100%",
4547
- overflow: "hidden"
4584
+ overflow: "hidden",
4585
+ overscrollBehavior: "none",
4586
+ userSelect: "none",
4587
+ webkitUserSelect: "none"
4548
4588
  });
4549
4589
  return el;
4550
4590
  }
@@ -4592,6 +4632,13 @@ var Viewport = class {
4592
4632
  this.toolContext.gridType = void 0;
4593
4633
  this.toolContext.hexOrientation = void 0;
4594
4634
  }
4635
+ this.notifyGridChangeListeners();
4636
+ }
4637
+ notifyGridChangeListeners() {
4638
+ const info = this.getGridInfo();
4639
+ for (const listener of this.gridChangeListeners) {
4640
+ listener(info);
4641
+ }
4595
4642
  }
4596
4643
  observeResize() {
4597
4644
  if (typeof ResizeObserver === "undefined") return;
@@ -6283,7 +6330,7 @@ var UpdateLayerCommand = class {
6283
6330
  };
6284
6331
 
6285
6332
  // src/index.ts
6286
- var VERSION = "0.10.0";
6333
+ var VERSION = "0.11.0";
6287
6334
  // Annotate the CommonJS export names for ESM import in node:
6288
6335
  0 && (module.exports = {
6289
6336
  AddElementCommand,
package/dist/index.d.cts CHANGED
@@ -423,6 +423,7 @@ declare class InputHandler {
423
423
  private historyRecorder;
424
424
  private historyStack;
425
425
  private isToolActive;
426
+ private lastPointerEvent;
426
427
  private readonly abortController;
427
428
  constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
428
429
  setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
@@ -489,6 +490,12 @@ interface RenderStatsSnapshot {
489
490
  frameCount: number;
490
491
  }
491
492
 
493
+ interface GridInfo {
494
+ gridType: 'square' | 'hex';
495
+ hexOrientation: 'pointy' | 'flat';
496
+ cellSize: number;
497
+ cellRadius: number;
498
+ }
492
499
  interface ViewportOptions {
493
500
  camera?: CameraOptions;
494
501
  background?: BackgroundOptions;
@@ -519,6 +526,7 @@ declare class Viewport {
519
526
  private readonly renderLoop;
520
527
  private readonly domNodeManager;
521
528
  private readonly interactMode;
529
+ private readonly gridChangeListeners;
522
530
  constructor(container: HTMLElement, options?: ViewportOptions);
523
531
  get ctx(): CanvasRenderingContext2D | null;
524
532
  get snapToGrid(): boolean;
@@ -555,6 +563,8 @@ declare class Viewport {
555
563
  }): string;
556
564
  updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
557
565
  removeGrid(): void;
566
+ getGridInfo(): GridInfo | null;
567
+ onGridChange(listener: (info: GridInfo | null) => void): () => void;
558
568
  getRenderStats(): RenderStatsSnapshot;
559
569
  logPerformance(intervalMs?: number): () => void;
560
570
  destroy(): void;
@@ -572,6 +582,7 @@ declare class Viewport {
572
582
  private applyCameraTransform;
573
583
  private syncCanvasSize;
574
584
  private syncGridContext;
585
+ private notifyGridChangeListeners;
575
586
  private observeResize;
576
587
  }
577
588
 
@@ -1109,6 +1120,6 @@ declare class UpdateLayerCommand implements Command {
1109
1120
  undo(_store: ElementStore): void;
1110
1121
  }
1111
1122
 
1112
- declare const VERSION = "0.10.0";
1123
+ declare const VERSION = "0.11.0";
1113
1124
 
1114
- export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
1125
+ export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
package/dist/index.d.ts CHANGED
@@ -423,6 +423,7 @@ declare class InputHandler {
423
423
  private historyRecorder;
424
424
  private historyStack;
425
425
  private isToolActive;
426
+ private lastPointerEvent;
426
427
  private readonly abortController;
427
428
  constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
428
429
  setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
@@ -489,6 +490,12 @@ interface RenderStatsSnapshot {
489
490
  frameCount: number;
490
491
  }
491
492
 
493
+ interface GridInfo {
494
+ gridType: 'square' | 'hex';
495
+ hexOrientation: 'pointy' | 'flat';
496
+ cellSize: number;
497
+ cellRadius: number;
498
+ }
492
499
  interface ViewportOptions {
493
500
  camera?: CameraOptions;
494
501
  background?: BackgroundOptions;
@@ -519,6 +526,7 @@ declare class Viewport {
519
526
  private readonly renderLoop;
520
527
  private readonly domNodeManager;
521
528
  private readonly interactMode;
529
+ private readonly gridChangeListeners;
522
530
  constructor(container: HTMLElement, options?: ViewportOptions);
523
531
  get ctx(): CanvasRenderingContext2D | null;
524
532
  get snapToGrid(): boolean;
@@ -555,6 +563,8 @@ declare class Viewport {
555
563
  }): string;
556
564
  updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
557
565
  removeGrid(): void;
566
+ getGridInfo(): GridInfo | null;
567
+ onGridChange(listener: (info: GridInfo | null) => void): () => void;
558
568
  getRenderStats(): RenderStatsSnapshot;
559
569
  logPerformance(intervalMs?: number): () => void;
560
570
  destroy(): void;
@@ -572,6 +582,7 @@ declare class Viewport {
572
582
  private applyCameraTransform;
573
583
  private syncCanvasSize;
574
584
  private syncGridContext;
585
+ private notifyGridChangeListeners;
575
586
  private observeResize;
576
587
  }
577
588
 
@@ -1109,6 +1120,6 @@ declare class UpdateLayerCommand implements Command {
1109
1120
  undo(_store: ElementStore): void;
1110
1121
  }
1111
1122
 
1112
- declare const VERSION = "0.10.0";
1123
+ declare const VERSION = "0.11.0";
1113
1124
 
1114
- export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
1125
+ export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
package/dist/index.js CHANGED
@@ -292,7 +292,13 @@ function exportState(elements, camera, layers = []) {
292
292
  position: { ...camera.position },
293
293
  zoom: camera.zoom
294
294
  },
295
- elements: elements.map((el) => structuredClone(el)),
295
+ elements: elements.map((el) => {
296
+ const clone = structuredClone(el);
297
+ if (clone.type === "arrow") {
298
+ delete clone.cachedControlPoint;
299
+ }
300
+ return clone;
301
+ }),
296
302
  layers: layers.map((l) => ({ ...l }))
297
303
  };
298
304
  }
@@ -755,6 +761,7 @@ var InputHandler = class {
755
761
  historyRecorder;
756
762
  historyStack;
757
763
  isToolActive = false;
764
+ lastPointerEvent = null;
758
765
  abortController = new AbortController();
759
766
  setToolManager(toolManager, toolContext) {
760
767
  this.toolManager = toolManager;
@@ -762,6 +769,7 @@ var InputHandler = class {
762
769
  }
763
770
  destroy() {
764
771
  this.abortController.abort();
772
+ this.lastPointerEvent = null;
765
773
  }
766
774
  bind() {
767
775
  const opts = { signal: this.abortController.signal };
@@ -797,11 +805,12 @@ var InputHandler = class {
797
805
  this.lastPointer = { x: e.clientX, y: e.clientY };
798
806
  return;
799
807
  }
800
- if (this.activePointers.size === 1 && e.button === 0) {
808
+ if (this.activePointers.size === 1 && (e.button === 0 || e.pointerType === "touch" || e.pointerType === "pen")) {
801
809
  this.dispatchToolDown(e);
802
810
  }
803
811
  };
804
812
  onPointerMove = (e) => {
813
+ this.lastPointerEvent = e;
805
814
  if (this.activePointers.has(e.pointerId)) {
806
815
  this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
807
816
  }
@@ -823,6 +832,10 @@ var InputHandler = class {
823
832
  }
824
833
  };
825
834
  onPointerUp = (e) => {
835
+ try {
836
+ this.element.releasePointerCapture(e.pointerId);
837
+ } catch {
838
+ }
826
839
  this.activePointers.delete(e.pointerId);
827
840
  if (this.activePointers.size < 2) {
828
841
  this.lastPinchDistance = 0;
@@ -855,6 +868,13 @@ var InputHandler = class {
855
868
  onKeyUp = (e) => {
856
869
  if (e.key === " ") {
857
870
  this.spaceHeld = false;
871
+ if (this.activePointers.size === 0) {
872
+ if (this.lastPointerEvent) {
873
+ this.dispatchToolHover(this.lastPointerEvent);
874
+ } else {
875
+ this.toolContext?.setCursor?.("default");
876
+ }
877
+ }
858
878
  }
859
879
  };
860
880
  startPinch() {
@@ -4182,6 +4202,7 @@ var Viewport = class {
4182
4202
  renderLoop;
4183
4203
  domNodeManager;
4184
4204
  interactMode;
4205
+ gridChangeListeners = /* @__PURE__ */ new Set();
4185
4206
  get ctx() {
4186
4207
  return this.canvasEl.getContext("2d");
4187
4208
  }
@@ -4286,6 +4307,22 @@ var Viewport = class {
4286
4307
  this.historyRecorder.commit();
4287
4308
  this.requestRender();
4288
4309
  }
4310
+ getGridInfo() {
4311
+ const grid = this.store.getElementsByType("grid")[0];
4312
+ if (!grid) return null;
4313
+ return {
4314
+ gridType: grid.gridType,
4315
+ hexOrientation: grid.hexOrientation,
4316
+ cellSize: grid.cellSize,
4317
+ cellRadius: grid.gridType === "hex" ? grid.cellSize : grid.cellSize / 2
4318
+ };
4319
+ }
4320
+ onGridChange(listener) {
4321
+ this.gridChangeListeners.add(listener);
4322
+ return () => {
4323
+ this.gridChangeListeners.delete(listener);
4324
+ };
4325
+ }
4289
4326
  getRenderStats() {
4290
4327
  return this.renderLoop.getStats();
4291
4328
  }
@@ -4438,7 +4475,10 @@ var Viewport = class {
4438
4475
  position: "relative",
4439
4476
  width: "100%",
4440
4477
  height: "100%",
4441
- overflow: "hidden"
4478
+ overflow: "hidden",
4479
+ overscrollBehavior: "none",
4480
+ userSelect: "none",
4481
+ webkitUserSelect: "none"
4442
4482
  });
4443
4483
  return el;
4444
4484
  }
@@ -4486,6 +4526,13 @@ var Viewport = class {
4486
4526
  this.toolContext.gridType = void 0;
4487
4527
  this.toolContext.hexOrientation = void 0;
4488
4528
  }
4529
+ this.notifyGridChangeListeners();
4530
+ }
4531
+ notifyGridChangeListeners() {
4532
+ const info = this.getGridInfo();
4533
+ for (const listener of this.gridChangeListeners) {
4534
+ listener(info);
4535
+ }
4489
4536
  }
4490
4537
  observeResize() {
4491
4538
  if (typeof ResizeObserver === "undefined") return;
@@ -6177,7 +6224,7 @@ var UpdateLayerCommand = class {
6177
6224
  };
6178
6225
 
6179
6226
  // src/index.ts
6180
- var VERSION = "0.10.0";
6227
+ var VERSION = "0.11.0";
6181
6228
  export {
6182
6229
  AddElementCommand,
6183
6230
  ArrowTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldnotes/core",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Vanilla TypeScript infinite canvas engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -40,6 +40,7 @@
40
40
  "sdk"
41
41
  ],
42
42
  "devDependencies": {
43
+ "@playwright/test": "^1.60.0",
43
44
  "@vitest/coverage-v8": "^4.1.0",
44
45
  "jsdom": "^29.0.0",
45
46
  "tsup": "^8.5.1",
@@ -48,6 +49,10 @@
48
49
  "scripts": {
49
50
  "build": "tsup",
50
51
  "test": "vitest run",
51
- "test:watch": "vitest"
52
+ "test:watch": "vitest",
53
+ "test:coverage": "vitest run --coverage",
54
+ "test:all": "vitest run --coverage",
55
+ "e2e": "playwright test --config e2e/playwright.config.ts",
56
+ "e2e:update": "playwright test --config e2e/playwright.config.ts --update-snapshots"
52
57
  }
53
58
  }