@fieldnotes/core 0.45.0 → 0.46.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.d.cts CHANGED
@@ -162,6 +162,14 @@ interface ElementUpdateEvent {
162
162
  previous: CanvasElement;
163
163
  current: CanvasElement;
164
164
  }
165
+ interface ElementChangeMeta {
166
+ /**
167
+ * Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo
168
+ * history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied
169
+ * change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.
170
+ */
171
+ origin?: string;
172
+ }
165
173
  interface ElementStoreEvents {
166
174
  add: CanvasElement;
167
175
  remove: CanvasElement;
@@ -184,19 +192,19 @@ declare class ElementStore {
184
192
  type: T;
185
193
  }>[];
186
194
  private indexBounds;
187
- add(element: CanvasElement): void;
188
- update(id: string, partial: Partial<CanvasElement>): void;
189
- remove(id: string): void;
190
- clear(): void;
195
+ add(element: CanvasElement, meta?: ElementChangeMeta): void;
196
+ update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void;
197
+ remove(id: string, meta?: ElementChangeMeta): void;
198
+ clear(meta?: ElementChangeMeta): void;
191
199
  snapshot(): CanvasElement[];
192
- loadSnapshot(elements: CanvasElement[]): void;
200
+ loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void;
193
201
  bringToFront(id: string): void;
194
202
  sendToBack(id: string): void;
195
203
  bringForward(id: string): void;
196
204
  sendBackward(id: string): void;
197
205
  queryRect(rect: Bounds): CanvasElement[];
198
206
  queryPoint(point: Point): CanvasElement[];
199
- on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
207
+ on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void): () => void;
200
208
  onChange(listener: () => void): () => void;
201
209
  }
202
210
 
@@ -1105,6 +1113,6 @@ declare class LaserTool implements Tool {
1105
1113
  private notifyOptionsChange;
1106
1114
  }
1107
1115
 
1108
- declare const VERSION = "0.45.0";
1116
+ declare const VERSION = "0.46.1";
1109
1117
 
1110
- export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
1118
+ export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
package/dist/index.d.ts CHANGED
@@ -162,6 +162,14 @@ interface ElementUpdateEvent {
162
162
  previous: CanvasElement;
163
163
  current: CanvasElement;
164
164
  }
165
+ interface ElementChangeMeta {
166
+ /**
167
+ * Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo
168
+ * history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied
169
+ * change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.
170
+ */
171
+ origin?: string;
172
+ }
165
173
  interface ElementStoreEvents {
166
174
  add: CanvasElement;
167
175
  remove: CanvasElement;
@@ -184,19 +192,19 @@ declare class ElementStore {
184
192
  type: T;
185
193
  }>[];
186
194
  private indexBounds;
187
- add(element: CanvasElement): void;
188
- update(id: string, partial: Partial<CanvasElement>): void;
189
- remove(id: string): void;
190
- clear(): void;
195
+ add(element: CanvasElement, meta?: ElementChangeMeta): void;
196
+ update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void;
197
+ remove(id: string, meta?: ElementChangeMeta): void;
198
+ clear(meta?: ElementChangeMeta): void;
191
199
  snapshot(): CanvasElement[];
192
- loadSnapshot(elements: CanvasElement[]): void;
200
+ loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void;
193
201
  bringToFront(id: string): void;
194
202
  sendToBack(id: string): void;
195
203
  bringForward(id: string): void;
196
204
  sendBackward(id: string): void;
197
205
  queryRect(rect: Bounds): CanvasElement[];
198
206
  queryPoint(point: Point): CanvasElement[];
199
- on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
207
+ on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void): () => void;
200
208
  onChange(listener: () => void): () => void;
201
209
  }
202
210
 
@@ -1105,6 +1113,6 @@ declare class LaserTool implements Tool {
1105
1113
  private notifyOptionsChange;
1106
1114
  }
1107
1115
 
1108
- declare const VERSION = "0.45.0";
1116
+ declare const VERSION = "0.46.1";
1109
1117
 
1110
- export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
1118
+ export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
package/dist/index.js CHANGED
@@ -612,8 +612,20 @@ var InputFilter = class _InputFilter {
612
612
 
613
613
  // src/elements/create-id.ts
614
614
  var counter = 0;
615
+ function randomClientComponent() {
616
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
617
+ const bytes = new Uint8Array(8);
618
+ crypto.getRandomValues(bytes);
619
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
620
+ }
621
+ return Math.random().toString(36).slice(2, 14);
622
+ }
623
+ var CLIENT = randomClientComponent();
624
+ function formatId(prefix, time, counter2, client) {
625
+ return `${prefix}_${time}_${counter2}_${client}`;
626
+ }
615
627
  function createId(prefix) {
616
- return `${prefix}_${Date.now().toString(36)}_${(counter++).toString(36)}`;
628
+ return formatId(prefix, Date.now().toString(36), (counter++).toString(36), CLIENT);
617
629
  }
618
630
 
619
631
  // src/core/geometry.ts
@@ -2146,6 +2158,7 @@ var Background = class {
2146
2158
  };
2147
2159
 
2148
2160
  // src/core/event-bus.ts
2161
+ var EMPTY_META = Object.freeze({});
2149
2162
  var EventBus = class {
2150
2163
  listeners = /* @__PURE__ */ new Map();
2151
2164
  on(event, listener) {
@@ -2161,10 +2174,10 @@ var EventBus = class {
2161
2174
  off(event, listener) {
2162
2175
  this.listeners.get(event)?.delete(listener);
2163
2176
  }
2164
- emit(event, data) {
2177
+ emit(event, data, meta = EMPTY_META) {
2165
2178
  this.listeners.get(event)?.forEach((listener) => {
2166
2179
  try {
2167
- listener(data);
2180
+ listener(data, meta);
2168
2181
  } catch (err) {
2169
2182
  console.error(`[fieldnotes] listener error for "${String(event)}"`, err);
2170
2183
  }
@@ -2484,15 +2497,15 @@ var ElementStore = class {
2484
2497
  const angle = element.rotation ?? 0;
2485
2498
  return angle === 0 ? bounds : rotatedAABB(bounds, angle);
2486
2499
  }
2487
- add(element) {
2500
+ add(element, meta) {
2488
2501
  this.sortedCache = null;
2489
2502
  this._versions.set(element.id, 0);
2490
2503
  this.elements.set(element.id, element);
2491
2504
  const bounds = this.indexBounds(element);
2492
2505
  if (bounds) this.spatialIndex.insert(element.id, bounds);
2493
- this.bus.emit("add", element);
2506
+ this.bus.emit("add", element, meta);
2494
2507
  }
2495
- update(id, partial) {
2508
+ update(id, partial, meta) {
2496
2509
  const existing = this.elements.get(id);
2497
2510
  if (!existing) return;
2498
2511
  this.sortedCache = null;
@@ -2519,28 +2532,28 @@ var ElementStore = class {
2519
2532
  if (newBounds) {
2520
2533
  this.spatialIndex.update(id, newBounds);
2521
2534
  }
2522
- this.bus.emit("update", { previous: existing, current: updated });
2535
+ this.bus.emit("update", { previous: existing, current: updated }, meta);
2523
2536
  }
2524
- remove(id) {
2537
+ remove(id, meta) {
2525
2538
  const element = this.elements.get(id);
2526
2539
  if (!element) return;
2527
2540
  this.sortedCache = null;
2528
2541
  this._versions.delete(id);
2529
2542
  this.elements.delete(id);
2530
2543
  this.spatialIndex.remove(id);
2531
- this.bus.emit("remove", element);
2544
+ this.bus.emit("remove", element, meta);
2532
2545
  }
2533
- clear() {
2546
+ clear(meta) {
2534
2547
  this.sortedCache = null;
2535
2548
  this._versions.clear();
2536
2549
  this.elements.clear();
2537
2550
  this.spatialIndex.clear();
2538
- this.bus.emit("clear", null);
2551
+ this.bus.emit("clear", null, meta);
2539
2552
  }
2540
2553
  snapshot() {
2541
2554
  return this.getAll().map((el) => ({ ...el }));
2542
2555
  }
2543
- loadSnapshot(elements) {
2556
+ loadSnapshot(elements, meta) {
2544
2557
  this.sortedCache = null;
2545
2558
  this._versions.clear();
2546
2559
  this.elements.clear();
@@ -2557,9 +2570,9 @@ var ElementStore = class {
2557
2570
  el.cachedControlPoint = getArrowControlPoint(el.from, el.to, el.bend);
2558
2571
  }
2559
2572
  }
2560
- this.bus.emit("clear", null);
2573
+ this.bus.emit("clear", null, meta);
2561
2574
  for (const el of elements) {
2562
- this.bus.emit("add", el);
2575
+ this.bus.emit("add", el, meta);
2563
2576
  }
2564
2577
  }
2565
2578
  bringToFront(id) {
@@ -4834,15 +4847,18 @@ var UpdateLayerCommand = class {
4834
4847
  };
4835
4848
 
4836
4849
  // src/history/history-recorder.ts
4850
+ function isExternalChange(meta) {
4851
+ return meta.origin !== void 0 && meta.origin !== "local";
4852
+ }
4837
4853
  var HistoryRecorder = class {
4838
4854
  constructor(store, stack, layerManager) {
4839
4855
  this.store = store;
4840
4856
  this.stack = stack;
4841
4857
  this.layerManager = layerManager;
4842
4858
  this.unsubscribers = [
4843
- store.on("add", (el) => this.onAdd(el)),
4844
- store.on("remove", (el) => this.onRemove(el)),
4845
- store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
4859
+ store.on("add", (el, meta) => this.onAdd(el, meta)),
4860
+ store.on("remove", (el, meta) => this.onRemove(el, meta)),
4861
+ store.on("update", ({ previous, current }, meta) => this.onUpdate(previous, current, meta))
4846
4862
  ];
4847
4863
  if (layerManager) {
4848
4864
  this.unsubscribers.push(
@@ -4898,18 +4914,21 @@ var HistoryRecorder = class {
4898
4914
  this.stack.push(command);
4899
4915
  }
4900
4916
  }
4901
- onAdd(element) {
4917
+ onAdd(element, meta) {
4918
+ if (isExternalChange(meta)) return;
4902
4919
  if (!this.recording) return;
4903
4920
  this.record(new AddElementCommand(element));
4904
4921
  }
4905
- onRemove(element) {
4922
+ onRemove(element, meta) {
4923
+ if (isExternalChange(meta)) return;
4906
4924
  if (!this.recording) return;
4907
4925
  if (this.transaction && this.updateSnapshots.has(element.id)) {
4908
4926
  this.updateSnapshots.delete(element.id);
4909
4927
  }
4910
4928
  this.record(new RemoveElementCommand(element));
4911
4929
  }
4912
- onUpdate(previous, current) {
4930
+ onUpdate(previous, current, meta) {
4931
+ if (isExternalChange(meta)) return;
4913
4932
  if (!this.recording) return;
4914
4933
  if (this.transaction) {
4915
4934
  if (!this.updateSnapshots.has(current.id)) {
@@ -10081,7 +10100,7 @@ var LaserTool = class {
10081
10100
  };
10082
10101
 
10083
10102
  // src/index.ts
10084
- var VERSION = "0.45.0";
10103
+ var VERSION = "0.46.1";
10085
10104
  export {
10086
10105
  ArrowTool,
10087
10106
  AutoSave,