@fieldnotes/core 0.15.0 → 0.16.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.cjs CHANGED
@@ -3402,16 +3402,64 @@ var BatchCommand = class {
3402
3402
  }
3403
3403
  };
3404
3404
 
3405
+ // src/history/layer-commands.ts
3406
+ var CreateLayerCommand = class {
3407
+ constructor(manager, layer) {
3408
+ this.manager = manager;
3409
+ this.layer = layer;
3410
+ }
3411
+ execute(_store) {
3412
+ this.manager.addLayerDirect(this.layer);
3413
+ }
3414
+ undo(_store) {
3415
+ this.manager.removeLayerDirect(this.layer.id);
3416
+ }
3417
+ };
3418
+ var RemoveLayerCommand = class {
3419
+ constructor(manager, layer) {
3420
+ this.manager = manager;
3421
+ this.layer = layer;
3422
+ }
3423
+ execute(_store) {
3424
+ this.manager.removeLayerDirect(this.layer.id);
3425
+ }
3426
+ undo(_store) {
3427
+ this.manager.addLayerDirect(this.layer);
3428
+ }
3429
+ };
3430
+ var UpdateLayerCommand = class {
3431
+ constructor(manager, layerId, previous, current) {
3432
+ this.manager = manager;
3433
+ this.layerId = layerId;
3434
+ this.previous = previous;
3435
+ this.current = current;
3436
+ }
3437
+ execute(_store) {
3438
+ this.manager.updateLayerDirect(this.layerId, { ...this.current });
3439
+ }
3440
+ undo(_store) {
3441
+ this.manager.updateLayerDirect(this.layerId, { ...this.previous });
3442
+ }
3443
+ };
3444
+
3405
3445
  // src/history/history-recorder.ts
3406
3446
  var HistoryRecorder = class {
3407
- constructor(store, stack) {
3447
+ constructor(store, stack, layerManager) {
3408
3448
  this.store = store;
3409
3449
  this.stack = stack;
3450
+ this.layerManager = layerManager;
3410
3451
  this.unsubscribers = [
3411
3452
  store.on("add", (el) => this.onAdd(el)),
3412
3453
  store.on("remove", (el) => this.onRemove(el)),
3413
3454
  store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
3414
3455
  ];
3456
+ if (layerManager) {
3457
+ this.unsubscribers.push(
3458
+ layerManager.on("create", (layer) => this.onLayerCreate(layer)),
3459
+ layerManager.on("remove", (layer) => this.onLayerRemove(layer)),
3460
+ layerManager.on("update", ({ previous, current }) => this.onLayerUpdate(previous, current))
3461
+ );
3462
+ }
3415
3463
  }
3416
3464
  recording = true;
3417
3465
  transaction = null;
@@ -3472,6 +3520,21 @@ var HistoryRecorder = class {
3472
3520
  this.stack.push(new UpdateElementCommand(current.id, previous, current));
3473
3521
  }
3474
3522
  }
3523
+ onLayerCreate(layer) {
3524
+ if (!this.recording) return;
3525
+ if (!this.layerManager) return;
3526
+ this.record(new CreateLayerCommand(this.layerManager, layer));
3527
+ }
3528
+ onLayerRemove(layer) {
3529
+ if (!this.recording) return;
3530
+ if (!this.layerManager) return;
3531
+ this.record(new RemoveLayerCommand(this.layerManager, layer));
3532
+ }
3533
+ onLayerUpdate(previous, current) {
3534
+ if (!this.recording) return;
3535
+ if (!this.layerManager) return;
3536
+ this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));
3537
+ }
3475
3538
  flushUpdateSnapshots() {
3476
3539
  const commands = [];
3477
3540
  for (const [id, previous] of this.updateSnapshots) {
@@ -3904,18 +3967,23 @@ var LayerManager = class {
3904
3967
  addLayerDirect(layer) {
3905
3968
  this.layers.set(layer.id, { ...layer });
3906
3969
  this.syncLayerOrder();
3970
+ this.bus.emit("create", { ...layer });
3907
3971
  this.bus.emit("change", null);
3908
3972
  }
3909
3973
  removeLayerDirect(id) {
3974
+ const layer = this.layers.get(id);
3910
3975
  this.layers.delete(id);
3911
3976
  this.syncLayerOrder();
3977
+ if (layer) this.bus.emit("remove", { ...layer });
3912
3978
  this.bus.emit("change", null);
3913
3979
  }
3914
3980
  updateLayerDirect(id, props) {
3915
3981
  const layer = this.layers.get(id);
3916
3982
  if (!layer) return;
3983
+ const previous = { ...layer };
3917
3984
  Object.assign(layer, props);
3918
3985
  if ("order" in props) this.syncLayerOrder();
3986
+ this.bus.emit("update", { previous, current: { ...layer } });
3919
3987
  this.bus.emit("change", null);
3920
3988
  }
3921
3989
  syncLayerOrder() {
@@ -4008,6 +4076,20 @@ var DomNodeManager = class {
4008
4076
  storeHtmlContent(elementId, dom) {
4009
4077
  this.htmlContent.set(elementId, dom);
4010
4078
  }
4079
+ hasContent(elementId) {
4080
+ return this.htmlContent.has(elementId);
4081
+ }
4082
+ resetHtmlContent(elementId) {
4083
+ this.htmlContent.delete(elementId);
4084
+ this.lastSyncedVersion.delete(elementId);
4085
+ this.lastSyncedZIndex.delete(elementId);
4086
+ const node = this.domNodes.get(elementId);
4087
+ if (!node) return;
4088
+ while (node.firstChild) {
4089
+ node.removeChild(node.firstChild);
4090
+ }
4091
+ delete node.dataset["initialized"];
4092
+ }
4011
4093
  syncDomNode(element, zIndex = 0) {
4012
4094
  let node = this.domNodes.get(element.id);
4013
4095
  if (!node) {
@@ -4549,8 +4631,10 @@ var Viewport = class {
4549
4631
  toolbar: options.toolbar
4550
4632
  });
4551
4633
  this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
4634
+ this.onHtmlElementMount = options.onHtmlElementMount;
4635
+ this.dropHandler = options.onDrop;
4552
4636
  this.history = new HistoryStack();
4553
- this.historyRecorder = new HistoryRecorder(this.store, this.history);
4637
+ this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
4554
4638
  this.wrapper = this.createWrapper();
4555
4639
  this.canvasEl = this.createCanvas();
4556
4640
  this.domLayer = this.createDomLayer();
@@ -4670,6 +4754,8 @@ var Viewport = class {
4670
4754
  renderLoop;
4671
4755
  domNodeManager;
4672
4756
  interactMode;
4757
+ onHtmlElementMount;
4758
+ dropHandler;
4673
4759
  gridChangeListeners = /* @__PURE__ */ new Set();
4674
4760
  doubleTapDetector = new DoubleTapDetector();
4675
4761
  tapDownX = 0;
@@ -4713,6 +4799,22 @@ var Viewport = class {
4713
4799
  this.layerManager.setActiveLayer(state.activeLayerId);
4714
4800
  }
4715
4801
  this.domNodeManager.reattachHtmlContent(this.store);
4802
+ if (this.onHtmlElementMount) {
4803
+ for (const el of this.store.getElementsByType("html")) {
4804
+ if (!this.domNodeManager.hasContent(el.id)) {
4805
+ this.domNodeManager.syncDomNode(el);
4806
+ const node = this.domNodeManager.getNode(el.id);
4807
+ if (node) {
4808
+ this.onHtmlElementMount(el.id, el.domId, node);
4809
+ node.dataset["initialized"] = "true";
4810
+ Object.assign(node.style, {
4811
+ overflow: "hidden",
4812
+ pointerEvents: el.interactive ? "auto" : "none"
4813
+ });
4814
+ }
4815
+ }
4816
+ }
4817
+ }
4716
4818
  this.history.clear();
4717
4819
  this.historyRecorder.resume();
4718
4820
  this.camera.moveTo(state.camera.position.x, state.camera.position.y);
@@ -4758,6 +4860,19 @@ var Viewport = class {
4758
4860
  this.requestRender();
4759
4861
  return el.id;
4760
4862
  }
4863
+ removeLayer(id) {
4864
+ this.historyRecorder.begin();
4865
+ this.layerManager.removeLayer(id);
4866
+ this.historyRecorder.commit();
4867
+ }
4868
+ updateHtmlElement(id, newContent) {
4869
+ const el = this.store.getById(id);
4870
+ if (!el) throw new Error(`Element not found: ${id}`);
4871
+ if (el.type !== "html") throw new Error(`Element ${id} is not an HTML element`);
4872
+ this.domNodeManager.resetHtmlContent(id);
4873
+ this.domNodeManager.storeHtmlContent(id, newContent);
4874
+ this.requestRender();
4875
+ }
4761
4876
  addGrid(input) {
4762
4877
  const existing = this.store.getElementsByType("grid")[0];
4763
4878
  this.historyRecorder.begin();
@@ -4909,17 +5024,21 @@ var Viewport = class {
4909
5024
  };
4910
5025
  onDrop = (e) => {
4911
5026
  e.preventDefault();
5027
+ const rect = this.wrapper.getBoundingClientRect();
5028
+ const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
5029
+ const worldPos = this.camera.screenToWorld(screenPos);
5030
+ if (this.dropHandler) {
5031
+ this.dropHandler(e, worldPos);
5032
+ return;
5033
+ }
4912
5034
  const files = e.dataTransfer?.files;
4913
5035
  if (!files) return;
4914
- const rect = this.wrapper.getBoundingClientRect();
4915
5036
  for (const file of files) {
4916
5037
  if (!file.type.startsWith("image/")) continue;
4917
5038
  const reader = new FileReader();
4918
5039
  reader.onload = () => {
4919
5040
  const src = reader.result;
4920
5041
  if (typeof src !== "string") return;
4921
- const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
4922
- const worldPos = this.camera.screenToWorld(screenPos);
4923
5042
  this.addImage(src, worldPos);
4924
5043
  };
4925
5044
  reader.readAsDataURL(file);
@@ -6736,48 +6855,8 @@ var TemplateTool = class {
6736
6855
  }
6737
6856
  };
6738
6857
 
6739
- // src/history/layer-commands.ts
6740
- var CreateLayerCommand = class {
6741
- constructor(manager, layer) {
6742
- this.manager = manager;
6743
- this.layer = layer;
6744
- }
6745
- execute(_store) {
6746
- this.manager.addLayerDirect(this.layer);
6747
- }
6748
- undo(_store) {
6749
- this.manager.removeLayerDirect(this.layer.id);
6750
- }
6751
- };
6752
- var RemoveLayerCommand = class {
6753
- constructor(manager, layer) {
6754
- this.manager = manager;
6755
- this.layer = layer;
6756
- }
6757
- execute(_store) {
6758
- this.manager.removeLayerDirect(this.layer.id);
6759
- }
6760
- undo(_store) {
6761
- this.manager.addLayerDirect(this.layer);
6762
- }
6763
- };
6764
- var UpdateLayerCommand = class {
6765
- constructor(manager, layerId, previous, current) {
6766
- this.manager = manager;
6767
- this.layerId = layerId;
6768
- this.previous = previous;
6769
- this.current = current;
6770
- }
6771
- execute(_store) {
6772
- this.manager.updateLayerDirect(this.layerId, { ...this.current });
6773
- }
6774
- undo(_store) {
6775
- this.manager.updateLayerDirect(this.layerId, { ...this.previous });
6776
- }
6777
- };
6778
-
6779
6858
  // src/index.ts
6780
- var VERSION = "0.15.0";
6859
+ var VERSION = "0.16.0";
6781
6860
  // Annotate the CommonJS export names for ESM import in node:
6782
6861
  0 && (module.exports = {
6783
6862
  AddElementCommand,
package/dist/index.d.cts CHANGED
@@ -270,6 +270,15 @@ declare function snapPoint(point: Point, gridSize: number): Point;
270
270
  declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
271
271
  declare function smartSnap(point: Point, ctx: ToolContext): Point;
272
272
 
273
+ interface LayerManagerEvents {
274
+ change: null;
275
+ create: Layer;
276
+ remove: Layer;
277
+ update: {
278
+ previous: Layer;
279
+ current: Layer;
280
+ };
281
+ }
273
282
  declare class LayerManager {
274
283
  private readonly store;
275
284
  private layers;
@@ -293,7 +302,7 @@ declare class LayerManager {
293
302
  moveElementToLayer(elementId: string, layerId: string): void;
294
303
  snapshot(): Layer[];
295
304
  loadSnapshot(layers: Layer[]): void;
296
- on(event: 'change', callback: () => void): () => void;
305
+ on<K extends keyof LayerManagerEvents>(event: K, callback: (data: LayerManagerEvents[K]) => void): () => void;
297
306
  addLayerDirect(layer: Layer): void;
298
307
  removeLayerDirect(id: string): void;
299
308
  updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void;
@@ -399,11 +408,12 @@ declare class HistoryStack {
399
408
  declare class HistoryRecorder {
400
409
  private readonly store;
401
410
  private readonly stack;
411
+ private readonly layerManager?;
402
412
  private recording;
403
413
  private transaction;
404
414
  private updateSnapshots;
405
415
  private unsubscribers;
406
- constructor(store: ElementStore, stack: HistoryStack);
416
+ constructor(store: ElementStore, stack: HistoryStack, layerManager?: LayerManager | undefined);
407
417
  pause(): void;
408
418
  resume(): void;
409
419
  begin(): void;
@@ -414,6 +424,9 @@ declare class HistoryRecorder {
414
424
  private onAdd;
415
425
  private onRemove;
416
426
  private onUpdate;
427
+ private onLayerCreate;
428
+ private onLayerRemove;
429
+ private onLayerUpdate;
417
430
  private flushUpdateSnapshots;
418
431
  }
419
432
 
@@ -559,6 +572,11 @@ interface ViewportOptions {
559
572
  background?: BackgroundOptions;
560
573
  fontSizePresets?: FontSizePreset[];
561
574
  toolbar?: boolean;
575
+ onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
576
+ onDrop?: (event: DragEvent, worldPosition: {
577
+ x: number;
578
+ y: number;
579
+ }) => void;
562
580
  }
563
581
  declare class Viewport {
564
582
  private readonly container;
@@ -584,6 +602,8 @@ declare class Viewport {
584
602
  private readonly renderLoop;
585
603
  private readonly domNodeManager;
586
604
  private readonly interactMode;
605
+ private readonly onHtmlElementMount?;
606
+ private readonly dropHandler?;
587
607
  private readonly gridChangeListeners;
588
608
  private readonly doubleTapDetector;
589
609
  private tapDownX;
@@ -614,6 +634,8 @@ declare class Viewport {
614
634
  w: number;
615
635
  h: number;
616
636
  }): string;
637
+ removeLayer(id: string): void;
638
+ updateHtmlElement(id: string, newContent: HTMLElement): void;
617
639
  addGrid(input: {
618
640
  gridType?: 'square' | 'hex';
619
641
  hexOrientation?: 'pointy' | 'flat';
@@ -1189,6 +1211,6 @@ declare class UpdateLayerCommand implements Command {
1189
1211
  undo(_store: ElementStore): void;
1190
1212
  }
1191
1213
 
1192
- declare const VERSION = "0.15.0";
1214
+ declare const VERSION = "0.16.0";
1193
1215
 
1194
1216
  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, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, 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, getElementsBoundingBox, 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
@@ -270,6 +270,15 @@ declare function snapPoint(point: Point, gridSize: number): Point;
270
270
  declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
271
271
  declare function smartSnap(point: Point, ctx: ToolContext): Point;
272
272
 
273
+ interface LayerManagerEvents {
274
+ change: null;
275
+ create: Layer;
276
+ remove: Layer;
277
+ update: {
278
+ previous: Layer;
279
+ current: Layer;
280
+ };
281
+ }
273
282
  declare class LayerManager {
274
283
  private readonly store;
275
284
  private layers;
@@ -293,7 +302,7 @@ declare class LayerManager {
293
302
  moveElementToLayer(elementId: string, layerId: string): void;
294
303
  snapshot(): Layer[];
295
304
  loadSnapshot(layers: Layer[]): void;
296
- on(event: 'change', callback: () => void): () => void;
305
+ on<K extends keyof LayerManagerEvents>(event: K, callback: (data: LayerManagerEvents[K]) => void): () => void;
297
306
  addLayerDirect(layer: Layer): void;
298
307
  removeLayerDirect(id: string): void;
299
308
  updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void;
@@ -399,11 +408,12 @@ declare class HistoryStack {
399
408
  declare class HistoryRecorder {
400
409
  private readonly store;
401
410
  private readonly stack;
411
+ private readonly layerManager?;
402
412
  private recording;
403
413
  private transaction;
404
414
  private updateSnapshots;
405
415
  private unsubscribers;
406
- constructor(store: ElementStore, stack: HistoryStack);
416
+ constructor(store: ElementStore, stack: HistoryStack, layerManager?: LayerManager | undefined);
407
417
  pause(): void;
408
418
  resume(): void;
409
419
  begin(): void;
@@ -414,6 +424,9 @@ declare class HistoryRecorder {
414
424
  private onAdd;
415
425
  private onRemove;
416
426
  private onUpdate;
427
+ private onLayerCreate;
428
+ private onLayerRemove;
429
+ private onLayerUpdate;
417
430
  private flushUpdateSnapshots;
418
431
  }
419
432
 
@@ -559,6 +572,11 @@ interface ViewportOptions {
559
572
  background?: BackgroundOptions;
560
573
  fontSizePresets?: FontSizePreset[];
561
574
  toolbar?: boolean;
575
+ onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
576
+ onDrop?: (event: DragEvent, worldPosition: {
577
+ x: number;
578
+ y: number;
579
+ }) => void;
562
580
  }
563
581
  declare class Viewport {
564
582
  private readonly container;
@@ -584,6 +602,8 @@ declare class Viewport {
584
602
  private readonly renderLoop;
585
603
  private readonly domNodeManager;
586
604
  private readonly interactMode;
605
+ private readonly onHtmlElementMount?;
606
+ private readonly dropHandler?;
587
607
  private readonly gridChangeListeners;
588
608
  private readonly doubleTapDetector;
589
609
  private tapDownX;
@@ -614,6 +634,8 @@ declare class Viewport {
614
634
  w: number;
615
635
  h: number;
616
636
  }): string;
637
+ removeLayer(id: string): void;
638
+ updateHtmlElement(id: string, newContent: HTMLElement): void;
617
639
  addGrid(input: {
618
640
  gridType?: 'square' | 'hex';
619
641
  hexOrientation?: 'pointy' | 'flat';
@@ -1189,6 +1211,6 @@ declare class UpdateLayerCommand implements Command {
1189
1211
  undo(_store: ElementStore): void;
1190
1212
  }
1191
1213
 
1192
- declare const VERSION = "0.15.0";
1214
+ declare const VERSION = "0.16.0";
1193
1215
 
1194
1216
  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, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, 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, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
package/dist/index.js CHANGED
@@ -3293,16 +3293,64 @@ var BatchCommand = class {
3293
3293
  }
3294
3294
  };
3295
3295
 
3296
+ // src/history/layer-commands.ts
3297
+ var CreateLayerCommand = class {
3298
+ constructor(manager, layer) {
3299
+ this.manager = manager;
3300
+ this.layer = layer;
3301
+ }
3302
+ execute(_store) {
3303
+ this.manager.addLayerDirect(this.layer);
3304
+ }
3305
+ undo(_store) {
3306
+ this.manager.removeLayerDirect(this.layer.id);
3307
+ }
3308
+ };
3309
+ var RemoveLayerCommand = class {
3310
+ constructor(manager, layer) {
3311
+ this.manager = manager;
3312
+ this.layer = layer;
3313
+ }
3314
+ execute(_store) {
3315
+ this.manager.removeLayerDirect(this.layer.id);
3316
+ }
3317
+ undo(_store) {
3318
+ this.manager.addLayerDirect(this.layer);
3319
+ }
3320
+ };
3321
+ var UpdateLayerCommand = class {
3322
+ constructor(manager, layerId, previous, current) {
3323
+ this.manager = manager;
3324
+ this.layerId = layerId;
3325
+ this.previous = previous;
3326
+ this.current = current;
3327
+ }
3328
+ execute(_store) {
3329
+ this.manager.updateLayerDirect(this.layerId, { ...this.current });
3330
+ }
3331
+ undo(_store) {
3332
+ this.manager.updateLayerDirect(this.layerId, { ...this.previous });
3333
+ }
3334
+ };
3335
+
3296
3336
  // src/history/history-recorder.ts
3297
3337
  var HistoryRecorder = class {
3298
- constructor(store, stack) {
3338
+ constructor(store, stack, layerManager) {
3299
3339
  this.store = store;
3300
3340
  this.stack = stack;
3341
+ this.layerManager = layerManager;
3301
3342
  this.unsubscribers = [
3302
3343
  store.on("add", (el) => this.onAdd(el)),
3303
3344
  store.on("remove", (el) => this.onRemove(el)),
3304
3345
  store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
3305
3346
  ];
3347
+ if (layerManager) {
3348
+ this.unsubscribers.push(
3349
+ layerManager.on("create", (layer) => this.onLayerCreate(layer)),
3350
+ layerManager.on("remove", (layer) => this.onLayerRemove(layer)),
3351
+ layerManager.on("update", ({ previous, current }) => this.onLayerUpdate(previous, current))
3352
+ );
3353
+ }
3306
3354
  }
3307
3355
  recording = true;
3308
3356
  transaction = null;
@@ -3363,6 +3411,21 @@ var HistoryRecorder = class {
3363
3411
  this.stack.push(new UpdateElementCommand(current.id, previous, current));
3364
3412
  }
3365
3413
  }
3414
+ onLayerCreate(layer) {
3415
+ if (!this.recording) return;
3416
+ if (!this.layerManager) return;
3417
+ this.record(new CreateLayerCommand(this.layerManager, layer));
3418
+ }
3419
+ onLayerRemove(layer) {
3420
+ if (!this.recording) return;
3421
+ if (!this.layerManager) return;
3422
+ this.record(new RemoveLayerCommand(this.layerManager, layer));
3423
+ }
3424
+ onLayerUpdate(previous, current) {
3425
+ if (!this.recording) return;
3426
+ if (!this.layerManager) return;
3427
+ this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));
3428
+ }
3366
3429
  flushUpdateSnapshots() {
3367
3430
  const commands = [];
3368
3431
  for (const [id, previous] of this.updateSnapshots) {
@@ -3795,18 +3858,23 @@ var LayerManager = class {
3795
3858
  addLayerDirect(layer) {
3796
3859
  this.layers.set(layer.id, { ...layer });
3797
3860
  this.syncLayerOrder();
3861
+ this.bus.emit("create", { ...layer });
3798
3862
  this.bus.emit("change", null);
3799
3863
  }
3800
3864
  removeLayerDirect(id) {
3865
+ const layer = this.layers.get(id);
3801
3866
  this.layers.delete(id);
3802
3867
  this.syncLayerOrder();
3868
+ if (layer) this.bus.emit("remove", { ...layer });
3803
3869
  this.bus.emit("change", null);
3804
3870
  }
3805
3871
  updateLayerDirect(id, props) {
3806
3872
  const layer = this.layers.get(id);
3807
3873
  if (!layer) return;
3874
+ const previous = { ...layer };
3808
3875
  Object.assign(layer, props);
3809
3876
  if ("order" in props) this.syncLayerOrder();
3877
+ this.bus.emit("update", { previous, current: { ...layer } });
3810
3878
  this.bus.emit("change", null);
3811
3879
  }
3812
3880
  syncLayerOrder() {
@@ -3899,6 +3967,20 @@ var DomNodeManager = class {
3899
3967
  storeHtmlContent(elementId, dom) {
3900
3968
  this.htmlContent.set(elementId, dom);
3901
3969
  }
3970
+ hasContent(elementId) {
3971
+ return this.htmlContent.has(elementId);
3972
+ }
3973
+ resetHtmlContent(elementId) {
3974
+ this.htmlContent.delete(elementId);
3975
+ this.lastSyncedVersion.delete(elementId);
3976
+ this.lastSyncedZIndex.delete(elementId);
3977
+ const node = this.domNodes.get(elementId);
3978
+ if (!node) return;
3979
+ while (node.firstChild) {
3980
+ node.removeChild(node.firstChild);
3981
+ }
3982
+ delete node.dataset["initialized"];
3983
+ }
3902
3984
  syncDomNode(element, zIndex = 0) {
3903
3985
  let node = this.domNodes.get(element.id);
3904
3986
  if (!node) {
@@ -4440,8 +4522,10 @@ var Viewport = class {
4440
4522
  toolbar: options.toolbar
4441
4523
  });
4442
4524
  this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
4525
+ this.onHtmlElementMount = options.onHtmlElementMount;
4526
+ this.dropHandler = options.onDrop;
4443
4527
  this.history = new HistoryStack();
4444
- this.historyRecorder = new HistoryRecorder(this.store, this.history);
4528
+ this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
4445
4529
  this.wrapper = this.createWrapper();
4446
4530
  this.canvasEl = this.createCanvas();
4447
4531
  this.domLayer = this.createDomLayer();
@@ -4561,6 +4645,8 @@ var Viewport = class {
4561
4645
  renderLoop;
4562
4646
  domNodeManager;
4563
4647
  interactMode;
4648
+ onHtmlElementMount;
4649
+ dropHandler;
4564
4650
  gridChangeListeners = /* @__PURE__ */ new Set();
4565
4651
  doubleTapDetector = new DoubleTapDetector();
4566
4652
  tapDownX = 0;
@@ -4604,6 +4690,22 @@ var Viewport = class {
4604
4690
  this.layerManager.setActiveLayer(state.activeLayerId);
4605
4691
  }
4606
4692
  this.domNodeManager.reattachHtmlContent(this.store);
4693
+ if (this.onHtmlElementMount) {
4694
+ for (const el of this.store.getElementsByType("html")) {
4695
+ if (!this.domNodeManager.hasContent(el.id)) {
4696
+ this.domNodeManager.syncDomNode(el);
4697
+ const node = this.domNodeManager.getNode(el.id);
4698
+ if (node) {
4699
+ this.onHtmlElementMount(el.id, el.domId, node);
4700
+ node.dataset["initialized"] = "true";
4701
+ Object.assign(node.style, {
4702
+ overflow: "hidden",
4703
+ pointerEvents: el.interactive ? "auto" : "none"
4704
+ });
4705
+ }
4706
+ }
4707
+ }
4708
+ }
4607
4709
  this.history.clear();
4608
4710
  this.historyRecorder.resume();
4609
4711
  this.camera.moveTo(state.camera.position.x, state.camera.position.y);
@@ -4649,6 +4751,19 @@ var Viewport = class {
4649
4751
  this.requestRender();
4650
4752
  return el.id;
4651
4753
  }
4754
+ removeLayer(id) {
4755
+ this.historyRecorder.begin();
4756
+ this.layerManager.removeLayer(id);
4757
+ this.historyRecorder.commit();
4758
+ }
4759
+ updateHtmlElement(id, newContent) {
4760
+ const el = this.store.getById(id);
4761
+ if (!el) throw new Error(`Element not found: ${id}`);
4762
+ if (el.type !== "html") throw new Error(`Element ${id} is not an HTML element`);
4763
+ this.domNodeManager.resetHtmlContent(id);
4764
+ this.domNodeManager.storeHtmlContent(id, newContent);
4765
+ this.requestRender();
4766
+ }
4652
4767
  addGrid(input) {
4653
4768
  const existing = this.store.getElementsByType("grid")[0];
4654
4769
  this.historyRecorder.begin();
@@ -4800,17 +4915,21 @@ var Viewport = class {
4800
4915
  };
4801
4916
  onDrop = (e) => {
4802
4917
  e.preventDefault();
4918
+ const rect = this.wrapper.getBoundingClientRect();
4919
+ const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
4920
+ const worldPos = this.camera.screenToWorld(screenPos);
4921
+ if (this.dropHandler) {
4922
+ this.dropHandler(e, worldPos);
4923
+ return;
4924
+ }
4803
4925
  const files = e.dataTransfer?.files;
4804
4926
  if (!files) return;
4805
- const rect = this.wrapper.getBoundingClientRect();
4806
4927
  for (const file of files) {
4807
4928
  if (!file.type.startsWith("image/")) continue;
4808
4929
  const reader = new FileReader();
4809
4930
  reader.onload = () => {
4810
4931
  const src = reader.result;
4811
4932
  if (typeof src !== "string") return;
4812
- const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
4813
- const worldPos = this.camera.screenToWorld(screenPos);
4814
4933
  this.addImage(src, worldPos);
4815
4934
  };
4816
4935
  reader.readAsDataURL(file);
@@ -6627,48 +6746,8 @@ var TemplateTool = class {
6627
6746
  }
6628
6747
  };
6629
6748
 
6630
- // src/history/layer-commands.ts
6631
- var CreateLayerCommand = class {
6632
- constructor(manager, layer) {
6633
- this.manager = manager;
6634
- this.layer = layer;
6635
- }
6636
- execute(_store) {
6637
- this.manager.addLayerDirect(this.layer);
6638
- }
6639
- undo(_store) {
6640
- this.manager.removeLayerDirect(this.layer.id);
6641
- }
6642
- };
6643
- var RemoveLayerCommand = class {
6644
- constructor(manager, layer) {
6645
- this.manager = manager;
6646
- this.layer = layer;
6647
- }
6648
- execute(_store) {
6649
- this.manager.removeLayerDirect(this.layer.id);
6650
- }
6651
- undo(_store) {
6652
- this.manager.addLayerDirect(this.layer);
6653
- }
6654
- };
6655
- var UpdateLayerCommand = class {
6656
- constructor(manager, layerId, previous, current) {
6657
- this.manager = manager;
6658
- this.layerId = layerId;
6659
- this.previous = previous;
6660
- this.current = current;
6661
- }
6662
- execute(_store) {
6663
- this.manager.updateLayerDirect(this.layerId, { ...this.current });
6664
- }
6665
- undo(_store) {
6666
- this.manager.updateLayerDirect(this.layerId, { ...this.previous });
6667
- }
6668
- };
6669
-
6670
6749
  // src/index.ts
6671
- var VERSION = "0.15.0";
6750
+ var VERSION = "0.16.0";
6672
6751
  export {
6673
6752
  AddElementCommand,
6674
6753
  ArrowTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldnotes/core",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Vanilla TypeScript infinite canvas engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",