@fieldnotes/core 0.52.0 → 0.52.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
@@ -572,6 +572,7 @@ declare class Viewport {
572
572
  readonly history: HistoryStack;
573
573
  readonly domLayer: HTMLDivElement;
574
574
  private readonly canvasEl;
575
+ private readonly paintStack;
575
576
  private readonly wrapper;
576
577
  private readonly unsubCamera;
577
578
  private readonly unsubToolChange;
@@ -1157,6 +1158,6 @@ declare class LaserTool implements Tool {
1157
1158
  private notifyOptionsChange;
1158
1159
  }
1159
1160
 
1160
- declare const VERSION = "0.52.0";
1161
+ declare const VERSION = "0.52.1";
1161
1162
 
1162
1163
  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 ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, 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, type RotateDirection, 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, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
package/dist/index.d.ts CHANGED
@@ -572,6 +572,7 @@ declare class Viewport {
572
572
  readonly history: HistoryStack;
573
573
  readonly domLayer: HTMLDivElement;
574
574
  private readonly canvasEl;
575
+ private readonly paintStack;
575
576
  private readonly wrapper;
576
577
  private readonly unsubCamera;
577
578
  private readonly unsubToolChange;
@@ -1157,6 +1158,6 @@ declare class LaserTool implements Tool {
1157
1158
  private notifyOptionsChange;
1158
1159
  }
1159
1160
 
1160
- declare const VERSION = "0.52.0";
1161
+ declare const VERSION = "0.52.1";
1161
1162
 
1162
1163
  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 ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type HtmlExportError, type HtmlExportErrorReason, type HtmlExportOptions, type HtmlExportRenderer, 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, type RotateDirection, 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, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
package/dist/index.js CHANGED
@@ -4834,6 +4834,57 @@ function createDomLayer() {
4834
4834
  });
4835
4835
  return el;
4836
4836
  }
4837
+ function createPaintStack() {
4838
+ const el = createDomLayer();
4839
+ el.dataset["fieldnotesPaintStack"] = "";
4840
+ el.style.transformOrigin = "";
4841
+ return el;
4842
+ }
4843
+
4844
+ // src/canvas/hybrid-render-surface.ts
4845
+ var HybridRenderSurface = class {
4846
+ constructor(root) {
4847
+ this.root = root;
4848
+ }
4849
+ canvases = /* @__PURE__ */ new Map();
4850
+ beginFrame(activeOrders, width, height) {
4851
+ for (const [order, canvas] of this.canvases) {
4852
+ if (!activeOrders.has(order)) {
4853
+ canvas.remove();
4854
+ this.canvases.delete(order);
4855
+ }
4856
+ }
4857
+ for (const order of activeOrders) {
4858
+ const canvas = this.getCanvas(order);
4859
+ if (canvas.width !== width) canvas.width = width;
4860
+ if (canvas.height !== height) canvas.height = height;
4861
+ canvas.style.zIndex = String(order);
4862
+ }
4863
+ }
4864
+ getContext(order) {
4865
+ return this.getCanvas(order).getContext("2d");
4866
+ }
4867
+ clear() {
4868
+ for (const canvas of this.canvases.values()) canvas.remove();
4869
+ this.canvases.clear();
4870
+ }
4871
+ getCanvas(order) {
4872
+ let canvas = this.canvases.get(order);
4873
+ if (canvas) return canvas;
4874
+ canvas = document.createElement("canvas");
4875
+ canvas.dataset["paintOrder"] = String(order);
4876
+ Object.assign(canvas.style, {
4877
+ position: "absolute",
4878
+ inset: "0",
4879
+ width: "100%",
4880
+ height: "100%",
4881
+ pointerEvents: "none"
4882
+ });
4883
+ this.root.appendChild(canvas);
4884
+ this.canvases.set(order, canvas);
4885
+ return canvas;
4886
+ }
4887
+ };
4837
4888
 
4838
4889
  // src/elements/arrow-label-editor.ts
4839
4890
  var ArrowLabelEditor = class {
@@ -6452,6 +6503,7 @@ var DoubleTapDetector = class {
6452
6503
  // src/canvas/dom-node-manager.ts
6453
6504
  var DomNodeManager = class {
6454
6505
  domNodes = /* @__PURE__ */ new Map();
6506
+ strata = /* @__PURE__ */ new Map();
6455
6507
  htmlContent = /* @__PURE__ */ new Map();
6456
6508
  domLayer;
6457
6509
  onEditRequest;
@@ -6460,6 +6512,7 @@ var DomNodeManager = class {
6460
6512
  lastSyncedVersion = /* @__PURE__ */ new Map();
6461
6513
  lastSyncedZIndex = /* @__PURE__ */ new Map();
6462
6514
  lastSyncedOpacity = /* @__PURE__ */ new Map();
6515
+ cameraTransform = "";
6463
6516
  constructor(deps) {
6464
6517
  this.domLayer = deps.domLayer;
6465
6518
  this.onEditRequest = deps.onEditRequest;
@@ -6469,6 +6522,11 @@ var DomNodeManager = class {
6469
6522
  getNode(id) {
6470
6523
  return this.domNodes.get(id);
6471
6524
  }
6525
+ setCameraTransform(transform) {
6526
+ if (transform === this.cameraTransform) return;
6527
+ this.cameraTransform = transform;
6528
+ for (const stratum of this.strata.values()) stratum.style.transform = transform;
6529
+ }
6472
6530
  storeHtmlContent(elementId, dom) {
6473
6531
  this.htmlContent.set(elementId, dom);
6474
6532
  }
@@ -6496,7 +6554,7 @@ var DomNodeManager = class {
6496
6554
  position: "absolute",
6497
6555
  pointerEvents: "auto"
6498
6556
  });
6499
- this.domLayer.appendChild(node);
6557
+ this.getStratum(zIndex).appendChild(node);
6500
6558
  this.domNodes.set(element.id, node);
6501
6559
  } else if (this.getVersion) {
6502
6560
  const currentVersion = this.getVersion(element.id);
@@ -6507,6 +6565,15 @@ var DomNodeManager = class {
6507
6565
  return;
6508
6566
  }
6509
6567
  }
6568
+ if (node.parentElement !== this.getStratum(zIndex)) {
6569
+ const previousStratum = node.parentElement;
6570
+ this.getStratum(zIndex).appendChild(node);
6571
+ if (previousStratum?.childElementCount === 0) {
6572
+ const previousOrder = Number(previousStratum.dataset["paintOrder"]);
6573
+ previousStratum.remove();
6574
+ this.strata.delete(previousOrder);
6575
+ }
6576
+ }
6510
6577
  if (this.getVersion) {
6511
6578
  this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
6512
6579
  this.lastSyncedZIndex.set(element.id, zIndex);
@@ -6528,7 +6595,10 @@ var DomNodeManager = class {
6528
6595
  }
6529
6596
  hideDomNode(id) {
6530
6597
  const node = this.domNodes.get(id);
6531
- if (node) node.style.display = "none";
6598
+ if (node) {
6599
+ node.style.display = "none";
6600
+ this.lastSyncedVersion.delete(id);
6601
+ }
6532
6602
  }
6533
6603
  removeDomNode(id) {
6534
6604
  this.htmlContent.delete(id);
@@ -6537,8 +6607,14 @@ var DomNodeManager = class {
6537
6607
  this.lastSyncedOpacity.delete(id);
6538
6608
  const node = this.domNodes.get(id);
6539
6609
  if (node) {
6610
+ const stratum = node.parentElement;
6540
6611
  node.remove();
6541
6612
  this.domNodes.delete(id);
6613
+ if (stratum?.childElementCount === 0) {
6614
+ const order = Number(stratum.dataset["paintOrder"]);
6615
+ stratum.remove();
6616
+ this.strata.delete(order);
6617
+ }
6542
6618
  }
6543
6619
  }
6544
6620
  clearDomNodes() {
@@ -6548,6 +6624,27 @@ var DomNodeManager = class {
6548
6624
  this.lastSyncedVersion.clear();
6549
6625
  this.lastSyncedZIndex.clear();
6550
6626
  this.lastSyncedOpacity.clear();
6627
+ for (const stratum of this.strata.values()) stratum.remove();
6628
+ this.strata.clear();
6629
+ }
6630
+ getStratum(order) {
6631
+ let stratum = this.strata.get(order);
6632
+ if (stratum) return stratum;
6633
+ stratum = document.createElement("div");
6634
+ stratum.dataset["paintOrder"] = String(order);
6635
+ Object.assign(stratum.style, {
6636
+ position: "absolute",
6637
+ inset: "0",
6638
+ width: "100%",
6639
+ height: "100%",
6640
+ pointerEvents: "none",
6641
+ transformOrigin: "0 0",
6642
+ transform: this.cameraTransform,
6643
+ zIndex: String(order)
6644
+ });
6645
+ this.domLayer.appendChild(stratum);
6646
+ this.strata.set(order, stratum);
6647
+ return stratum;
6551
6648
  }
6552
6649
  reattachHtmlContent(store) {
6553
6650
  for (const el of store.getElementsByType("html")) {
@@ -6729,6 +6826,7 @@ var RenderLoop = class {
6729
6826
  domNodeManager;
6730
6827
  layerCache;
6731
6828
  marginViewport;
6829
+ hybridSurface;
6732
6830
  activeDrawingLayerId = null;
6733
6831
  gridCacheDirty = true;
6734
6832
  // set on recenter/viewport-change; consumed by the grid block
@@ -6748,6 +6846,7 @@ var RenderLoop = class {
6748
6846
  this.domNodeManager = deps.domNodeManager;
6749
6847
  this.layerCache = deps.layerCache;
6750
6848
  this.marginViewport = deps.marginViewport;
6849
+ this.hybridSurface = deps.hybridSurface;
6751
6850
  }
6752
6851
  requestRender() {
6753
6852
  this.needsRender = true;
@@ -6868,9 +6967,19 @@ var RenderLoop = class {
6868
6967
  h: cullBounds.h + cullPad * 2
6869
6968
  };
6870
6969
  const allElements = this.store.getAll();
6970
+ const visibleElements = allElements.filter(
6971
+ (element) => this.layerManager.isLayerVisible(element.layerId)
6972
+ );
6973
+ const firstDomIndex = visibleElements.findIndex(
6974
+ (element) => this.renderer.isDomElement(element)
6975
+ );
6976
+ const hybridActive = firstDomIndex >= 0 && visibleElements.slice(firstDomIndex + 1).some((element) => !this.renderer.isDomElement(element));
6977
+ const hybridCanvasRuns = /* @__PURE__ */ new Map();
6978
+ const hybridOrders = /* @__PURE__ */ new Set();
6979
+ let activeHybridOrder = null;
6871
6980
  this.layerGroups.clear();
6872
6981
  const gridElements = [];
6873
- let domZIndex = 0;
6982
+ let paintOrder = 0;
6874
6983
  for (const element of allElements) {
6875
6984
  if (!this.layerManager.isLayerVisible(element.layerId)) {
6876
6985
  if (this.renderer.isDomElement(element)) {
@@ -6878,16 +6987,29 @@ var RenderLoop = class {
6878
6987
  }
6879
6988
  continue;
6880
6989
  }
6990
+ const order = ++paintOrder;
6881
6991
  if (this.renderer.isDomElement(element)) {
6992
+ activeHybridOrder = null;
6882
6993
  const layerOpacity = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;
6883
6994
  const elBounds = getElementBounds(element);
6884
6995
  if (elBounds && !boundsIntersect(elBounds, cullingRect)) {
6885
6996
  this.domNodeManager.hideDomNode(element.id);
6886
6997
  } else {
6887
- this.domNodeManager.syncDomNode(element, domZIndex++, layerOpacity);
6998
+ this.domNodeManager.syncDomNode(element, order, layerOpacity);
6888
6999
  }
6889
7000
  continue;
6890
7001
  }
7002
+ if (hybridActive && paintOrder > firstDomIndex + 1 && element.type !== "grid") {
7003
+ activeHybridOrder ??= order;
7004
+ let run = hybridCanvasRuns.get(activeHybridOrder);
7005
+ if (!run) {
7006
+ run = [];
7007
+ hybridCanvasRuns.set(activeHybridOrder, run);
7008
+ hybridOrders.add(activeHybridOrder);
7009
+ }
7010
+ run.push(element);
7011
+ continue;
7012
+ }
6891
7013
  if (element.type === "grid") {
6892
7014
  gridElements.push(element);
6893
7015
  continue;
@@ -6899,6 +7021,10 @@ var RenderLoop = class {
6899
7021
  }
6900
7022
  group.push(element);
6901
7023
  }
7024
+ const activeTool = this.toolManager.activeTool;
7025
+ const overlayOrder = visibleElements.length + 1;
7026
+ if (hybridActive && activeTool?.renderOverlay) hybridOrders.add(overlayOrder);
7027
+ this.hybridSurface.beginFrame(hybridOrders, this.canvasEl.width, this.canvasEl.height);
6902
7028
  for (const [layerId, elements] of this.layerGroups) {
6903
7029
  const isActiveDrawingLayer = layerId === this.activeDrawingLayerId;
6904
7030
  const layerOpacity = this.layerManager.getLayer?.(layerId)?.opacity ?? 1;
@@ -6988,9 +7114,37 @@ var RenderLoop = class {
6988
7114
  } else {
6989
7115
  this.lastGridRefs = [];
6990
7116
  }
7117
+ for (const [order, elements] of hybridCanvasRuns) {
7118
+ const hybridCtx = this.hybridSurface.getContext(order);
7119
+ if (!hybridCtx) continue;
7120
+ hybridCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);
7121
+ hybridCtx.save();
7122
+ hybridCtx.scale(dpr, dpr);
7123
+ hybridCtx.translate(this.camera.position.x, this.camera.position.y);
7124
+ hybridCtx.scale(this.camera.zoom, this.camera.zoom);
7125
+ for (const element of elements) {
7126
+ const elBounds = getElementBounds(element);
7127
+ if (elBounds && !boundsIntersect(elBounds, cullingRect)) continue;
7128
+ hybridCtx.save();
7129
+ hybridCtx.globalAlpha = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;
7130
+ this.renderer.renderCanvasElement(hybridCtx, element);
7131
+ hybridCtx.restore();
7132
+ }
7133
+ hybridCtx.restore();
7134
+ }
6991
7135
  const overlayT0 = performance.now();
6992
- const activeTool = this.toolManager.activeTool;
6993
- if (activeTool?.renderOverlay) {
7136
+ if (hybridActive && activeTool?.renderOverlay) {
7137
+ const overlayCtx = this.hybridSurface.getContext(overlayOrder);
7138
+ if (overlayCtx) {
7139
+ overlayCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);
7140
+ overlayCtx.save();
7141
+ overlayCtx.scale(dpr, dpr);
7142
+ overlayCtx.translate(this.camera.position.x, this.camera.position.y);
7143
+ overlayCtx.scale(this.camera.zoom, this.camera.zoom);
7144
+ activeTool.renderOverlay(overlayCtx);
7145
+ overlayCtx.restore();
7146
+ }
7147
+ } else if (activeTool?.renderOverlay) {
6994
7148
  activeTool.renderOverlay(ctx);
6995
7149
  }
6996
7150
  const overlayMs = performance.now() - overlayT0;
@@ -7741,8 +7895,11 @@ var Viewport = class {
7741
7895
  });
7742
7896
  this.wrapper = createWrapper();
7743
7897
  this.canvasEl = createCanvas();
7898
+ this.paintStack = createPaintStack();
7744
7899
  this.domLayer = createDomLayer();
7900
+ this.domLayer.style.zIndex = "2147483647";
7745
7901
  this.wrapper.appendChild(this.canvasEl);
7902
+ this.wrapper.appendChild(this.paintStack);
7746
7903
  this.wrapper.appendChild(this.domLayer);
7747
7904
  this.container.appendChild(this.wrapper);
7748
7905
  this.toolContext = {
@@ -7812,11 +7969,12 @@ var Viewport = class {
7812
7969
  this.minimap.scheduleDraw();
7813
7970
  }
7814
7971
  this.domNodeManager = new DomNodeManager({
7815
- domLayer: this.domLayer,
7972
+ domLayer: this.paintStack,
7816
7973
  onEditRequest: (id) => this.interactions.startEditingElement(id),
7817
7974
  isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
7818
7975
  getVersion: (id) => this.store.getVersion(id)
7819
7976
  });
7977
+ this.domNodeManager.setCameraTransform(this.camera.toCSSTransform());
7820
7978
  this.interactMode = new InteractMode({
7821
7979
  getNode: (id) => this.domNodeManager.getNode(id)
7822
7980
  });
@@ -7837,7 +7995,8 @@ var Viewport = class {
7837
7995
  layerManager: this.layerManager,
7838
7996
  domNodeManager: this.domNodeManager,
7839
7997
  layerCache,
7840
- marginViewport: this.marginViewport
7998
+ marginViewport: this.marginViewport,
7999
+ hybridSurface: new HybridRenderSurface(this.paintStack)
7841
8000
  });
7842
8001
  this.unsubCamera = this.camera.onChange(() => {
7843
8002
  this.applyCameraTransform();
@@ -7924,6 +8083,7 @@ var Viewport = class {
7924
8083
  history;
7925
8084
  domLayer;
7926
8085
  canvasEl;
8086
+ paintStack;
7927
8087
  wrapper;
7928
8088
  unsubCamera;
7929
8089
  unsubToolChange;
@@ -8279,7 +8439,9 @@ var Viewport = class {
8279
8439
  }
8280
8440
  }
8281
8441
  applyCameraTransform() {
8282
- this.domLayer.style.transform = this.camera.toCSSTransform();
8442
+ const transform = this.camera.toCSSTransform();
8443
+ this.domLayer.style.transform = transform;
8444
+ this.domNodeManager.setCameraTransform(transform);
8283
8445
  }
8284
8446
  syncCanvasSize() {
8285
8447
  const rect = this.container.getBoundingClientRect();
@@ -10960,7 +11122,7 @@ var LaserTool = class {
10960
11122
  };
10961
11123
 
10962
11124
  // src/index.ts
10963
- var VERSION = "0.52.0";
11125
+ var VERSION = "0.52.1";
10964
11126
  export {
10965
11127
  ArrowTool,
10966
11128
  AutoSave,