@fieldnotes/core 0.50.1 → 0.50.3

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
@@ -1123,6 +1123,6 @@ declare class LaserTool implements Tool {
1123
1123
  private notifyOptionsChange;
1124
1124
  }
1125
1125
 
1126
- declare const VERSION = "0.50.1";
1126
+ declare const VERSION = "0.50.3";
1127
1127
 
1128
1128
  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, 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
@@ -1123,6 +1123,6 @@ declare class LaserTool implements Tool {
1123
1123
  private notifyOptionsChange;
1124
1124
  }
1125
1125
 
1126
- declare const VERSION = "0.50.1";
1126
+ declare const VERSION = "0.50.3";
1127
1127
 
1128
1128
  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, 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
@@ -2233,6 +2233,9 @@ var MAX_DEPTH = 8;
2233
2233
  function intersects(a, b) {
2234
2234
  return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;
2235
2235
  }
2236
+ function contains(outer, inner) {
2237
+ return inner.x >= outer.x && inner.x + inner.w <= outer.x + outer.w && inner.y >= outer.y && inner.y + inner.h <= outer.y + outer.h;
2238
+ }
2236
2239
  var QuadNode = class _QuadNode {
2237
2240
  constructor(bounds, depth) {
2238
2241
  this.bounds = bounds;
@@ -2285,6 +2288,14 @@ var QuadNode = class _QuadNode {
2285
2288
  }
2286
2289
  }
2287
2290
  }
2291
+ collect(result) {
2292
+ result.push(...this.items);
2293
+ if (this.children) {
2294
+ for (const child of this.children) {
2295
+ child.collect(result);
2296
+ }
2297
+ }
2298
+ }
2288
2299
  getChildIndex(itemBounds) {
2289
2300
  const midX = this.bounds.x + this.bounds.w / 2;
2290
2301
  const midY = this.bounds.y + this.bounds.h / 2;
@@ -2348,6 +2359,7 @@ var Quadtree = class {
2348
2359
  return this._size;
2349
2360
  }
2350
2361
  insert(id, bounds) {
2362
+ this.expandToFit(bounds);
2351
2363
  this.root.insert({ id, bounds });
2352
2364
  this._size++;
2353
2365
  }
@@ -2372,6 +2384,24 @@ var Quadtree = class {
2372
2384
  this.root = new QuadNode(this.worldBounds, 0);
2373
2385
  this._size = 0;
2374
2386
  }
2387
+ expandToFit(bounds) {
2388
+ const current = this.root.bounds;
2389
+ if (contains(current, bounds)) return;
2390
+ const currentRight = current.x + current.w;
2391
+ const currentBottom = current.y + current.h;
2392
+ const requiredWidth = Math.max(currentRight, bounds.x + bounds.w) - Math.min(current.x, bounds.x);
2393
+ const requiredHeight = Math.max(currentBottom, bounds.y + bounds.h) - Math.min(current.y, bounds.y);
2394
+ const width = Math.max(current.w * 2, requiredWidth);
2395
+ const height = Math.max(current.h * 2, requiredHeight);
2396
+ const x = bounds.x < current.x ? currentRight - width : current.x;
2397
+ const y = bounds.y < current.y ? currentBottom - height : current.y;
2398
+ const entries = [];
2399
+ this.root.collect(entries);
2400
+ this.root = new QuadNode({ x, y, w: width, h: height }, 0);
2401
+ for (const entry of entries) {
2402
+ this.root.insert(entry);
2403
+ }
2404
+ }
2375
2405
  };
2376
2406
 
2377
2407
  // src/elements/stroke-smoothing.ts
@@ -3593,7 +3623,7 @@ function renderSquareGrid(ctx, bounds, cellSize, strokeColor, strokeWidth, opaci
3593
3623
  ctx.save();
3594
3624
  ctx.strokeStyle = strokeColor;
3595
3625
  ctx.lineWidth = strokeWidth;
3596
- ctx.globalAlpha = opacity;
3626
+ ctx.globalAlpha *= opacity;
3597
3627
  ctx.beginPath();
3598
3628
  for (const x of verticals) {
3599
3629
  ctx.moveTo(x, bounds.minY);
@@ -3624,7 +3654,7 @@ function renderHexGrid(ctx, bounds, cellSize, orientation, strokeColor, strokeWi
3624
3654
  ctx.save();
3625
3655
  ctx.strokeStyle = strokeColor;
3626
3656
  ctx.lineWidth = strokeWidth;
3627
- ctx.globalAlpha = opacity;
3657
+ ctx.globalAlpha *= opacity;
3628
3658
  ctx.beginPath();
3629
3659
  if (orientation === "pointy") {
3630
3660
  const hexW = Math.sqrt(3) * cellSize;
@@ -5384,41 +5414,70 @@ async function exportImage(store, options = {}, layerManager) {
5384
5414
  const renderer = new ElementRenderer();
5385
5415
  renderer.setStore(store);
5386
5416
  const grids = [];
5387
- for (const el of visibleElements) {
5388
- if (el.type === "grid") {
5389
- grids.push(el);
5390
- continue;
5391
- }
5417
+ const renderElement = (target, el) => {
5392
5418
  if (el.type === "note") {
5393
5419
  const b = getElementBounds(el);
5394
- withRotation(ctx, el, b ? center(b) : el.position, () => renderNoteOnCanvas(ctx, el));
5395
- continue;
5420
+ withRotation(target, el, b ? center(b) : el.position, () => renderNoteOnCanvas(target, el));
5421
+ return;
5396
5422
  }
5397
5423
  if (el.type === "text") {
5398
5424
  const b = getElementBounds(el);
5399
- withRotation(ctx, el, b ? center(b) : el.position, () => renderTextOnCanvas(ctx, el));
5400
- continue;
5425
+ withRotation(target, el, b ? center(b) : el.position, () => renderTextOnCanvas(target, el));
5426
+ return;
5401
5427
  }
5402
5428
  if (el.type === "html") {
5403
- continue;
5429
+ return;
5404
5430
  }
5405
5431
  if (el.type === "image") {
5406
5432
  const img = imageCache.get(el.id);
5407
5433
  if (img) {
5408
5434
  const b = getElementBounds(el);
5409
5435
  withRotation(
5410
- ctx,
5436
+ target,
5411
5437
  el,
5412
5438
  b ? center(b) : el.position,
5413
- () => ctx.drawImage(img, el.position.x, el.position.y, el.size.w, el.size.h)
5439
+ () => target.drawImage(img, el.position.x, el.position.y, el.size.w, el.size.h)
5414
5440
  );
5415
5441
  }
5442
+ return;
5443
+ }
5444
+ renderer.renderCanvasElement(target, el);
5445
+ };
5446
+ const layerGroups = /* @__PURE__ */ new Map();
5447
+ for (const el of visibleElements) {
5448
+ if (el.type === "grid") {
5449
+ grids.push(el);
5450
+ continue;
5451
+ }
5452
+ const group = layerGroups.get(el.layerId) ?? [];
5453
+ group.push(el);
5454
+ layerGroups.set(el.layerId, group);
5455
+ }
5456
+ for (const [layerId, elements] of layerGroups) {
5457
+ const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;
5458
+ if (opacity === 1) {
5459
+ for (const el of elements) renderElement(ctx, el);
5416
5460
  continue;
5417
5461
  }
5418
- renderer.renderCanvasElement(ctx, el);
5462
+ const layerCanvas = document.createElement("canvas");
5463
+ layerCanvas.width = canvas.width;
5464
+ layerCanvas.height = canvas.height;
5465
+ const layerCtx = layerCanvas.getContext("2d");
5466
+ if (!layerCtx) continue;
5467
+ layerCtx.scale(scale, scale);
5468
+ layerCtx.translate(-bounds.x, -bounds.y);
5469
+ for (const el of elements) renderElement(layerCtx, el);
5470
+ ctx.save();
5471
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
5472
+ ctx.globalAlpha = opacity;
5473
+ ctx.drawImage(layerCanvas, 0, 0);
5474
+ ctx.restore();
5419
5475
  }
5420
5476
  for (const grid of grids) {
5477
+ ctx.save();
5478
+ ctx.globalAlpha = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;
5421
5479
  renderGridForBounds(ctx, grid, bounds);
5480
+ ctx.restore();
5422
5481
  }
5423
5482
  return new Promise((resolve) => {
5424
5483
  canvas.toBlob((blob) => resolve(blob), "image/png");
@@ -5738,11 +5797,19 @@ async function exportSvg(store, options = {}, layerManager) {
5738
5797
  if (options.background) {
5739
5798
  body += `<rect x="${n(bounds.x)}" y="${n(bounds.y)}" width="${n(bounds.w)}" height="${n(bounds.h)}" fill="${esc(options.background)}" />`;
5740
5799
  }
5800
+ const layerBodies = /* @__PURE__ */ new Map();
5741
5801
  for (const el of visibleElements) {
5742
- body += emitElement(el, imageDataUris, rasterScale, firstGrid, store);
5802
+ const emitted = emitElement(el, imageDataUris, rasterScale, firstGrid, store);
5803
+ layerBodies.set(el.layerId, (layerBodies.get(el.layerId) ?? "") + emitted);
5804
+ }
5805
+ for (const [layerId, emitted] of layerBodies) {
5806
+ const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;
5807
+ body += opacity === 1 || emitted === "" ? emitted : `<g opacity="${n(opacity)}">${emitted}</g>`;
5743
5808
  }
5744
5809
  for (const grid of grids) {
5745
- body += emitGrid(grid, bounds);
5810
+ const emitted = emitGrid(grid, bounds);
5811
+ const opacity = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;
5812
+ body += opacity === 1 ? emitted : `<g opacity="${n(opacity)}">${emitted}</g>`;
5746
5813
  }
5747
5814
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${n(bounds.w)}" height="${n(bounds.h)}" viewBox="${n(bounds.x)} ${n(bounds.y)} ${n(bounds.w)} ${n(bounds.h)}">${body}</svg>`;
5748
5815
  }
@@ -6061,6 +6128,7 @@ var DomNodeManager = class {
6061
6128
  getVersion;
6062
6129
  lastSyncedVersion = /* @__PURE__ */ new Map();
6063
6130
  lastSyncedZIndex = /* @__PURE__ */ new Map();
6131
+ lastSyncedOpacity = /* @__PURE__ */ new Map();
6064
6132
  constructor(deps) {
6065
6133
  this.domLayer = deps.domLayer;
6066
6134
  this.onEditRequest = deps.onEditRequest;
@@ -6080,6 +6148,7 @@ var DomNodeManager = class {
6080
6148
  this.htmlContent.delete(elementId);
6081
6149
  this.lastSyncedVersion.delete(elementId);
6082
6150
  this.lastSyncedZIndex.delete(elementId);
6151
+ this.lastSyncedOpacity.delete(elementId);
6083
6152
  const node = this.domNodes.get(elementId);
6084
6153
  if (!node) return;
6085
6154
  while (node.firstChild) {
@@ -6087,7 +6156,7 @@ var DomNodeManager = class {
6087
6156
  }
6088
6157
  delete node.dataset["initialized"];
6089
6158
  }
6090
- syncDomNode(element, zIndex = 0) {
6159
+ syncDomNode(element, zIndex = 0, opacity = 1) {
6091
6160
  let node = this.domNodes.get(element.id);
6092
6161
  if (!node) {
6093
6162
  node = document.createElement("div");
@@ -6102,13 +6171,15 @@ var DomNodeManager = class {
6102
6171
  const currentVersion = this.getVersion(element.id);
6103
6172
  const lastVersion = this.lastSyncedVersion.get(element.id);
6104
6173
  const lastZ = this.lastSyncedZIndex.get(element.id);
6105
- if (lastVersion === currentVersion && lastZ === zIndex) {
6174
+ const lastOpacity = this.lastSyncedOpacity.get(element.id);
6175
+ if (lastVersion === currentVersion && lastZ === zIndex && lastOpacity === opacity) {
6106
6176
  return;
6107
6177
  }
6108
6178
  }
6109
6179
  if (this.getVersion) {
6110
6180
  this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
6111
6181
  this.lastSyncedZIndex.set(element.id, zIndex);
6182
+ this.lastSyncedOpacity.set(element.id, opacity);
6112
6183
  }
6113
6184
  const size = "size" in element ? element.size : null;
6114
6185
  Object.assign(node.style, {
@@ -6118,6 +6189,7 @@ var DomNodeManager = class {
6118
6189
  width: size ? `${size.w}px` : "auto",
6119
6190
  height: size ? `${size.h}px` : "auto",
6120
6191
  zIndex: String(zIndex),
6192
+ opacity: String(opacity),
6121
6193
  transform: element.rotation ? `rotate(${element.rotation}rad)` : "",
6122
6194
  transformOrigin: "50% 50%"
6123
6195
  });
@@ -6131,6 +6203,7 @@ var DomNodeManager = class {
6131
6203
  this.htmlContent.delete(id);
6132
6204
  this.lastSyncedVersion.delete(id);
6133
6205
  this.lastSyncedZIndex.delete(id);
6206
+ this.lastSyncedOpacity.delete(id);
6134
6207
  const node = this.domNodes.get(id);
6135
6208
  if (node) {
6136
6209
  node.remove();
@@ -6143,6 +6216,7 @@ var DomNodeManager = class {
6143
6216
  this.htmlContent.clear();
6144
6217
  this.lastSyncedVersion.clear();
6145
6218
  this.lastSyncedZIndex.clear();
6219
+ this.lastSyncedOpacity.clear();
6146
6220
  }
6147
6221
  reattachHtmlContent(store) {
6148
6222
  for (const el of store.getElementsByType("html")) {
@@ -6381,11 +6455,12 @@ var RenderLoop = class {
6381
6455
  }
6382
6456
  markAllLayersDirty() {
6383
6457
  this.layerCache.markAllDirty();
6458
+ this.gridCacheDirty = true;
6384
6459
  }
6385
6460
  getStats() {
6386
6461
  return this.stats.getSnapshot();
6387
6462
  }
6388
- compositeLayerCache(ctx, layerId) {
6463
+ compositeLayerCache(ctx, layerId, opacity) {
6389
6464
  const cached = this.layerCache.getCanvas(layerId);
6390
6465
  const offset = this.marginViewport.compositeOffset(
6391
6466
  this.camera.position.x,
@@ -6393,6 +6468,7 @@ var RenderLoop = class {
6393
6468
  );
6394
6469
  ctx.save();
6395
6470
  ctx.setTransform(1, 0, 0, 1, 0, 0);
6471
+ ctx.globalAlpha = opacity;
6396
6472
  ctx.drawImage(cached, offset.x, offset.y);
6397
6473
  ctx.restore();
6398
6474
  }
@@ -6472,11 +6548,12 @@ var RenderLoop = class {
6472
6548
  continue;
6473
6549
  }
6474
6550
  if (this.renderer.isDomElement(element)) {
6551
+ const layerOpacity = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;
6475
6552
  const elBounds = getElementBounds(element);
6476
6553
  if (elBounds && !boundsIntersect(elBounds, cullingRect)) {
6477
6554
  this.domNodeManager.hideDomNode(element.id);
6478
6555
  } else {
6479
- this.domNodeManager.syncDomNode(element, domZIndex++);
6556
+ this.domNodeManager.syncDomNode(element, domZIndex++, layerOpacity);
6480
6557
  }
6481
6558
  continue;
6482
6559
  }
@@ -6493,15 +6570,16 @@ var RenderLoop = class {
6493
6570
  }
6494
6571
  for (const [layerId, elements] of this.layerGroups) {
6495
6572
  const isActiveDrawingLayer = layerId === this.activeDrawingLayerId;
6573
+ const layerOpacity = this.layerManager.getLayer?.(layerId)?.opacity ?? 1;
6496
6574
  if (!this.layerCache.isDirty(layerId)) {
6497
6575
  const compT0 = performance.now();
6498
- this.compositeLayerCache(ctx, layerId);
6576
+ this.compositeLayerCache(ctx, layerId, layerOpacity);
6499
6577
  compositeMs += performance.now() - compT0;
6500
6578
  continue;
6501
6579
  }
6502
6580
  if (isActiveDrawingLayer) {
6503
6581
  const compT0 = performance.now();
6504
- this.compositeLayerCache(ctx, layerId);
6582
+ this.compositeLayerCache(ctx, layerId, layerOpacity);
6505
6583
  compositeMs += performance.now() - compT0;
6506
6584
  continue;
6507
6585
  }
@@ -6521,7 +6599,7 @@ var RenderLoop = class {
6521
6599
  this.layerCache.markClean(layerId);
6522
6600
  layersMs += performance.now() - layerT0;
6523
6601
  const compT0 = performance.now();
6524
- this.compositeLayerCache(ctx, layerId);
6602
+ this.compositeLayerCache(ctx, layerId, layerOpacity);
6525
6603
  compositeMs += performance.now() - compT0;
6526
6604
  }
6527
6605
  }
@@ -6545,7 +6623,10 @@ var RenderLoop = class {
6545
6623
  this.marginViewport.applyRenderTransform(gc);
6546
6624
  try {
6547
6625
  for (const grid of gridElements) {
6626
+ gc.save();
6627
+ gc.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;
6548
6628
  this.renderer.renderCanvasElement(gc, grid);
6629
+ gc.restore();
6549
6630
  }
6550
6631
  } finally {
6551
6632
  gc.restore();
@@ -6566,7 +6647,10 @@ var RenderLoop = class {
6566
6647
  ctx.restore();
6567
6648
  } else {
6568
6649
  for (const grid of gridElements) {
6650
+ ctx.save();
6651
+ ctx.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;
6569
6652
  this.renderer.renderCanvasElement(ctx, grid);
6653
+ ctx.restore();
6570
6654
  }
6571
6655
  }
6572
6656
  gridMs = performance.now() - gridT0;
@@ -7471,6 +7555,7 @@ var Viewport = class {
7471
7555
  ];
7472
7556
  this.layerManager.on("change", () => {
7473
7557
  this.toolContext.activeLayerId = this.layerManager.activeLayerId;
7558
+ this.renderLoop.markAllLayersDirty();
7474
7559
  this.minimap?.scheduleDraw();
7475
7560
  this.requestRender();
7476
7561
  });
@@ -10534,7 +10619,7 @@ var LaserTool = class {
10534
10619
  };
10535
10620
 
10536
10621
  // src/index.ts
10537
- var VERSION = "0.50.1";
10622
+ var VERSION = "0.50.3";
10538
10623
  export {
10539
10624
  ArrowTool,
10540
10625
  AutoSave,