@fieldnotes/core 0.4.0 → 0.5.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
@@ -43,6 +43,7 @@ interface NoteElement extends BaseElement {
43
43
  size: Size;
44
44
  text: string;
45
45
  backgroundColor: string;
46
+ textColor: string;
46
47
  }
47
48
  interface Binding {
48
49
  elementId: string;
@@ -100,6 +101,8 @@ declare function exportState(elements: CanvasElement[], camera: {
100
101
  }): CanvasState;
101
102
  declare function parseState(json: string): CanvasState;
102
103
 
104
+ declare function snapPoint(point: Point, gridSize: number): Point;
105
+
103
106
  interface ElementUpdateEvent {
104
107
  previous: CanvasElement;
105
108
  current: CanvasElement;
@@ -202,6 +205,8 @@ interface ToolContext {
202
205
  switchTool?: (name: string) => void;
203
206
  editElement?: (id: string) => void;
204
207
  setCursor?: (cursor: string) => void;
208
+ snapToGrid?: boolean;
209
+ gridSize?: number;
205
210
  }
206
211
  interface PointerState {
207
212
  x: number;
@@ -352,12 +357,16 @@ declare class Viewport {
352
357
  readonly toolContext: ToolContext;
353
358
  private resizeObserver;
354
359
  private animFrameId;
360
+ private _snapToGrid;
361
+ private readonly _gridSize;
355
362
  private needsRender;
356
363
  private domNodes;
357
364
  private htmlContent;
358
365
  private interactingElementId;
359
366
  constructor(container: HTMLElement, options?: ViewportOptions);
360
367
  get ctx(): CanvasRenderingContext2D | null;
368
+ get snapToGrid(): boolean;
369
+ setSnapToGrid(enabled: boolean): void;
361
370
  requestRender(): void;
362
371
  exportState(): CanvasState;
363
372
  exportJSON(): string;
@@ -455,6 +464,7 @@ interface NoteInput extends BaseDefaults {
455
464
  size?: Size;
456
465
  text?: string;
457
466
  backgroundColor?: string;
467
+ textColor?: string;
458
468
  }
459
469
  interface ArrowInput extends BaseDefaults {
460
470
  from: Point;
@@ -610,6 +620,7 @@ declare class SelectTool implements Tool {
610
620
  get isMarqueeActive(): boolean;
611
621
  onActivate(ctx: ToolContext): void;
612
622
  onDeactivate(ctx: ToolContext): void;
623
+ private snap;
613
624
  onPointerDown(state: PointerState, ctx: ToolContext): void;
614
625
  onPointerMove(state: PointerState, ctx: ToolContext): void;
615
626
  onPointerUp(_state: PointerState, ctx: ToolContext): void;
@@ -654,11 +665,13 @@ declare class ArrowTool implements Tool {
654
665
 
655
666
  interface NoteToolOptions {
656
667
  backgroundColor?: string;
668
+ textColor?: string;
657
669
  size?: Size;
658
670
  }
659
671
  declare class NoteTool implements Tool {
660
672
  readonly name = "note";
661
673
  private backgroundColor;
674
+ private textColor;
662
675
  private size;
663
676
  constructor(options?: NoteToolOptions);
664
677
  setOptions(options: NoteToolOptions): void;
@@ -725,10 +738,11 @@ declare class ShapeTool implements Tool {
725
738
  onPointerUp(_state: PointerState, ctx: ToolContext): void;
726
739
  renderOverlay(ctx: CanvasRenderingContext2D): void;
727
740
  private computeRect;
741
+ private snap;
728
742
  private onKeyDown;
729
743
  private onKeyUp;
730
744
  }
731
745
 
732
- declare const VERSION = "0.4.0";
746
+ declare const VERSION = "0.5.0";
733
747
 
734
- 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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, 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, 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, unbindArrow, updateBoundArrow };
748
+ 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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, 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, 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 };
package/dist/index.d.ts CHANGED
@@ -43,6 +43,7 @@ interface NoteElement extends BaseElement {
43
43
  size: Size;
44
44
  text: string;
45
45
  backgroundColor: string;
46
+ textColor: string;
46
47
  }
47
48
  interface Binding {
48
49
  elementId: string;
@@ -100,6 +101,8 @@ declare function exportState(elements: CanvasElement[], camera: {
100
101
  }): CanvasState;
101
102
  declare function parseState(json: string): CanvasState;
102
103
 
104
+ declare function snapPoint(point: Point, gridSize: number): Point;
105
+
103
106
  interface ElementUpdateEvent {
104
107
  previous: CanvasElement;
105
108
  current: CanvasElement;
@@ -202,6 +205,8 @@ interface ToolContext {
202
205
  switchTool?: (name: string) => void;
203
206
  editElement?: (id: string) => void;
204
207
  setCursor?: (cursor: string) => void;
208
+ snapToGrid?: boolean;
209
+ gridSize?: number;
205
210
  }
206
211
  interface PointerState {
207
212
  x: number;
@@ -352,12 +357,16 @@ declare class Viewport {
352
357
  readonly toolContext: ToolContext;
353
358
  private resizeObserver;
354
359
  private animFrameId;
360
+ private _snapToGrid;
361
+ private readonly _gridSize;
355
362
  private needsRender;
356
363
  private domNodes;
357
364
  private htmlContent;
358
365
  private interactingElementId;
359
366
  constructor(container: HTMLElement, options?: ViewportOptions);
360
367
  get ctx(): CanvasRenderingContext2D | null;
368
+ get snapToGrid(): boolean;
369
+ setSnapToGrid(enabled: boolean): void;
361
370
  requestRender(): void;
362
371
  exportState(): CanvasState;
363
372
  exportJSON(): string;
@@ -455,6 +464,7 @@ interface NoteInput extends BaseDefaults {
455
464
  size?: Size;
456
465
  text?: string;
457
466
  backgroundColor?: string;
467
+ textColor?: string;
458
468
  }
459
469
  interface ArrowInput extends BaseDefaults {
460
470
  from: Point;
@@ -610,6 +620,7 @@ declare class SelectTool implements Tool {
610
620
  get isMarqueeActive(): boolean;
611
621
  onActivate(ctx: ToolContext): void;
612
622
  onDeactivate(ctx: ToolContext): void;
623
+ private snap;
613
624
  onPointerDown(state: PointerState, ctx: ToolContext): void;
614
625
  onPointerMove(state: PointerState, ctx: ToolContext): void;
615
626
  onPointerUp(_state: PointerState, ctx: ToolContext): void;
@@ -654,11 +665,13 @@ declare class ArrowTool implements Tool {
654
665
 
655
666
  interface NoteToolOptions {
656
667
  backgroundColor?: string;
668
+ textColor?: string;
657
669
  size?: Size;
658
670
  }
659
671
  declare class NoteTool implements Tool {
660
672
  readonly name = "note";
661
673
  private backgroundColor;
674
+ private textColor;
662
675
  private size;
663
676
  constructor(options?: NoteToolOptions);
664
677
  setOptions(options: NoteToolOptions): void;
@@ -725,10 +738,11 @@ declare class ShapeTool implements Tool {
725
738
  onPointerUp(_state: PointerState, ctx: ToolContext): void;
726
739
  renderOverlay(ctx: CanvasRenderingContext2D): void;
727
740
  private computeRect;
741
+ private snap;
728
742
  private onKeyDown;
729
743
  private onKeyUp;
730
744
  }
731
745
 
732
- declare const VERSION = "0.4.0";
746
+ declare const VERSION = "0.5.0";
733
747
 
734
- 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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, 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, 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, unbindArrow, updateBoundArrow };
748
+ 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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, 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, 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 };
package/dist/index.js CHANGED
@@ -114,6 +114,17 @@ function migrateElement(obj) {
114
114
  if (obj["type"] === "shape" && typeof obj["shape"] !== "string") {
115
115
  obj["shape"] = "rectangle";
116
116
  }
117
+ if (obj["type"] === "note" && typeof obj["textColor"] !== "string") {
118
+ obj["textColor"] = "#000000";
119
+ }
120
+ }
121
+
122
+ // src/core/snap.ts
123
+ function snapPoint(point, gridSize) {
124
+ return {
125
+ x: Math.round(point.x / gridSize) * gridSize || 0,
126
+ y: Math.round(point.y / gridSize) * gridSize || 0
127
+ };
117
128
  }
118
129
 
119
130
  // src/core/auto-save.ts
@@ -1421,7 +1432,8 @@ function createNote(input) {
1421
1432
  locked: input.locked ?? false,
1422
1433
  size: input.size ?? { w: 200, h: 100 },
1423
1434
  text: input.text ?? "",
1424
- backgroundColor: input.backgroundColor ?? "#ffeb3b"
1435
+ backgroundColor: input.backgroundColor ?? "#ffeb3b",
1436
+ textColor: input.textColor ?? "#000000"
1425
1437
  };
1426
1438
  }
1427
1439
  function createArrow(input) {
@@ -1497,6 +1509,7 @@ var Viewport = class {
1497
1509
  this.container = container;
1498
1510
  this.camera = new Camera(options.camera);
1499
1511
  this.background = new Background(options.background);
1512
+ this._gridSize = options.background?.spacing ?? 24;
1500
1513
  this.store = new ElementStore();
1501
1514
  this.toolManager = new ToolManager();
1502
1515
  this.renderer = new ElementRenderer();
@@ -1519,7 +1532,9 @@ var Viewport = class {
1519
1532
  editElement: (id) => this.startEditingElement(id),
1520
1533
  setCursor: (cursor) => {
1521
1534
  this.wrapper.style.cursor = cursor;
1522
- }
1535
+ },
1536
+ snapToGrid: false,
1537
+ gridSize: this._gridSize
1523
1538
  };
1524
1539
  this.inputHandler = new InputHandler(this.wrapper, this.camera, {
1525
1540
  toolManager: this.toolManager,
@@ -1564,6 +1579,8 @@ var Viewport = class {
1564
1579
  toolContext;
1565
1580
  resizeObserver = null;
1566
1581
  animFrameId = 0;
1582
+ _snapToGrid = false;
1583
+ _gridSize;
1567
1584
  needsRender = true;
1568
1585
  domNodes = /* @__PURE__ */ new Map();
1569
1586
  htmlContent = /* @__PURE__ */ new Map();
@@ -1571,6 +1588,13 @@ var Viewport = class {
1571
1588
  get ctx() {
1572
1589
  return this.canvasEl.getContext("2d");
1573
1590
  }
1591
+ get snapToGrid() {
1592
+ return this._snapToGrid;
1593
+ }
1594
+ setSnapToGrid(enabled) {
1595
+ this._snapToGrid = enabled;
1596
+ this.toolContext.snapToGrid = enabled;
1597
+ }
1574
1598
  requestRender() {
1575
1599
  this.needsRender = true;
1576
1600
  }
@@ -1820,6 +1844,7 @@ var Viewport = class {
1820
1844
  node.dataset["initialized"] = "true";
1821
1845
  Object.assign(node.style, {
1822
1846
  backgroundColor: element.backgroundColor,
1847
+ color: element.textColor,
1823
1848
  padding: "8px",
1824
1849
  borderRadius: "4px",
1825
1850
  boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
@@ -1841,6 +1866,7 @@ var Viewport = class {
1841
1866
  node.textContent = element.text || "";
1842
1867
  }
1843
1868
  node.style.backgroundColor = element.backgroundColor;
1869
+ node.style.color = element.textColor;
1844
1870
  }
1845
1871
  }
1846
1872
  if (element.type === "image") {
@@ -2317,10 +2343,13 @@ var SelectTool = class {
2317
2343
  this.mode = { type: "idle" };
2318
2344
  ctx.setCursor?.("default");
2319
2345
  }
2346
+ snap(point, ctx) {
2347
+ return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
2348
+ }
2320
2349
  onPointerDown(state, ctx) {
2321
2350
  this.ctx = ctx;
2322
2351
  const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2323
- this.lastWorld = world;
2352
+ this.lastWorld = this.snap(world, ctx);
2324
2353
  this.currentWorld = world;
2325
2354
  const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);
2326
2355
  if (arrowHit) {
@@ -2373,9 +2402,10 @@ var SelectTool = class {
2373
2402
  }
2374
2403
  if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
2375
2404
  ctx.setCursor?.("move");
2376
- const dx = world.x - this.lastWorld.x;
2377
- const dy = world.y - this.lastWorld.y;
2378
- this.lastWorld = world;
2405
+ const snapped = this.snap(world, ctx);
2406
+ const dx = snapped.x - this.lastWorld.x;
2407
+ const dy = snapped.y - this.lastWorld.y;
2408
+ this.lastWorld = snapped;
2379
2409
  for (const id of this._selectedIds) {
2380
2410
  const el = ctx.store.getById(id);
2381
2411
  if (!el || el.locked) continue;
@@ -2724,7 +2754,7 @@ var ArrowTool = class {
2724
2754
  this.fromBinding = { elementId: target.id };
2725
2755
  this.fromTarget = target;
2726
2756
  } else {
2727
- this.start = world;
2757
+ this.start = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
2728
2758
  this.fromBinding = void 0;
2729
2759
  this.fromTarget = null;
2730
2760
  }
@@ -2741,7 +2771,7 @@ var ArrowTool = class {
2741
2771
  this.end = getElementCenter(target);
2742
2772
  this.toTarget = target;
2743
2773
  } else {
2744
- this.end = world;
2774
+ this.end = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
2745
2775
  this.toTarget = null;
2746
2776
  }
2747
2777
  ctx.requestRender();
@@ -2819,13 +2849,16 @@ var ArrowTool = class {
2819
2849
  var NoteTool = class {
2820
2850
  name = "note";
2821
2851
  backgroundColor;
2852
+ textColor;
2822
2853
  size;
2823
2854
  constructor(options = {}) {
2824
2855
  this.backgroundColor = options.backgroundColor ?? "#ffeb3b";
2856
+ this.textColor = options.textColor ?? "#000000";
2825
2857
  this.size = options.size ?? { w: 200, h: 100 };
2826
2858
  }
2827
2859
  setOptions(options) {
2828
2860
  if (options.backgroundColor !== void 0) this.backgroundColor = options.backgroundColor;
2861
+ if (options.textColor !== void 0) this.textColor = options.textColor;
2829
2862
  if (options.size !== void 0) this.size = options.size;
2830
2863
  }
2831
2864
  onPointerDown(_state, _ctx) {
@@ -2833,11 +2866,15 @@ var NoteTool = class {
2833
2866
  onPointerMove(_state, _ctx) {
2834
2867
  }
2835
2868
  onPointerUp(state, ctx) {
2836
- const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2869
+ let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2870
+ if (ctx.snapToGrid && ctx.gridSize) {
2871
+ world = snapPoint(world, ctx.gridSize);
2872
+ }
2837
2873
  const note = createNote({
2838
2874
  position: world,
2839
2875
  size: { ...this.size },
2840
- backgroundColor: this.backgroundColor
2876
+ backgroundColor: this.backgroundColor,
2877
+ textColor: this.textColor
2841
2878
  });
2842
2879
  ctx.store.add(note);
2843
2880
  ctx.requestRender();
@@ -2873,7 +2910,10 @@ var TextTool = class {
2873
2910
  onPointerMove(_state, _ctx) {
2874
2911
  }
2875
2912
  onPointerUp(state, ctx) {
2876
- const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2913
+ let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2914
+ if (ctx.snapToGrid && ctx.gridSize) {
2915
+ world = snapPoint(world, ctx.gridSize);
2916
+ }
2877
2917
  const textEl = createText({
2878
2918
  position: world,
2879
2919
  fontSize: this.fontSize,
@@ -2955,12 +2995,12 @@ var ShapeTool = class {
2955
2995
  }
2956
2996
  onPointerDown(state, ctx) {
2957
2997
  this.drawing = true;
2958
- this.start = ctx.camera.screenToWorld({ x: state.x, y: state.y });
2998
+ this.start = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
2959
2999
  this.end = { ...this.start };
2960
3000
  }
2961
3001
  onPointerMove(state, ctx) {
2962
3002
  if (!this.drawing) return;
2963
- this.end = ctx.camera.screenToWorld({ x: state.x, y: state.y });
3003
+ this.end = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
2964
3004
  ctx.requestRender();
2965
3005
  }
2966
3006
  onPointerUp(_state, ctx) {
@@ -3024,6 +3064,9 @@ var ShapeTool = class {
3024
3064
  }
3025
3065
  return { position: { x, y }, size: { w, h } };
3026
3066
  }
3067
+ snap(point, ctx) {
3068
+ return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
3069
+ }
3027
3070
  onKeyDown = (e) => {
3028
3071
  if (e.key === "Shift") this.shiftHeld = true;
3029
3072
  };
@@ -3033,7 +3076,7 @@ var ShapeTool = class {
3033
3076
  };
3034
3077
 
3035
3078
  // src/index.ts
3036
- var VERSION = "0.4.0";
3079
+ var VERSION = "0.5.0";
3037
3080
  export {
3038
3081
  AddElementCommand,
3039
3082
  ArrowTool,
@@ -3084,6 +3127,7 @@ export {
3084
3127
  isBindable,
3085
3128
  isNearBezier,
3086
3129
  parseState,
3130
+ snapPoint,
3087
3131
  unbindArrow,
3088
3132
  updateBoundArrow
3089
3133
  };