@fieldnotes/core 0.23.0 → 0.24.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
@@ -602,6 +602,7 @@ interface ViewportOptions {
602
602
  onImageError?: (info: {
603
603
  src: string;
604
604
  elementIds: string[];
605
+ cause?: unknown;
605
606
  }) => void;
606
607
  /** CSS-pixel margin cached beyond the viewport. Default `256`. Set `0` to disable. */
607
608
  panBufferMargin?: number;
@@ -714,7 +715,7 @@ declare class ElementRenderer {
714
715
  private gridBoundsOverride;
715
716
  setStore(store: ElementStore): void;
716
717
  setOnImageLoad(callback: () => void): void;
717
- setOnImageError(callback: (src: string) => void): void;
718
+ setOnImageError(callback: (src: string, cause?: unknown) => void): void;
718
719
  setCamera(camera: Camera): void;
719
720
  setCanvasSize(w: number, h: number): void;
720
721
  setGridBoundsOverride(bounds: {
@@ -1261,6 +1262,6 @@ declare class UpdateLayerCommand implements Command {
1261
1262
  undo(_store: ElementStore): void;
1262
1263
  }
1263
1264
 
1264
- declare const VERSION = "0.23.0";
1265
+ declare const VERSION = "0.24.0";
1265
1266
 
1266
1267
  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 InputHandlerOptions, 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 ShortcutBindings, type ShortcutOptions, type ShortcutsApi, 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, isNoteContentEmpty, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
package/dist/index.d.ts CHANGED
@@ -602,6 +602,7 @@ interface ViewportOptions {
602
602
  onImageError?: (info: {
603
603
  src: string;
604
604
  elementIds: string[];
605
+ cause?: unknown;
605
606
  }) => void;
606
607
  /** CSS-pixel margin cached beyond the viewport. Default `256`. Set `0` to disable. */
607
608
  panBufferMargin?: number;
@@ -714,7 +715,7 @@ declare class ElementRenderer {
714
715
  private gridBoundsOverride;
715
716
  setStore(store: ElementStore): void;
716
717
  setOnImageLoad(callback: () => void): void;
717
- setOnImageError(callback: (src: string) => void): void;
718
+ setOnImageError(callback: (src: string, cause?: unknown) => void): void;
718
719
  setCamera(camera: Camera): void;
719
720
  setCanvasSize(w: number, h: number): void;
720
721
  setGridBoundsOverride(bounds: {
@@ -1261,6 +1262,6 @@ declare class UpdateLayerCommand implements Command {
1261
1262
  undo(_store: ElementStore): void;
1262
1263
  }
1263
1264
 
1264
- declare const VERSION = "0.23.0";
1265
+ declare const VERSION = "0.24.0";
1265
1266
 
1266
1267
  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 InputHandlerOptions, 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 ShortcutBindings, type ShortcutOptions, type ShortcutsApi, 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, isNoteContentEmpty, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
package/dist/index.js CHANGED
@@ -923,16 +923,17 @@ var KeyboardActions = class {
923
923
  this.pasteCount = 0;
924
924
  }
925
925
  paste() {
926
+ if (this.deps.isToolActive()) return;
926
927
  this.flushPendingNudge();
927
- if (this.clipboard.length === 0 || this.deps.isToolActive()) return;
928
+ if (this.clipboard.length === 0) return;
928
929
  const sel = this.selectTool();
929
930
  if (!sel) return;
930
931
  this.pasteCount++;
931
932
  this.insertClones(this.clipboard, this.pasteCount * 20, sel);
932
933
  }
933
934
  duplicate() {
934
- this.flushPendingNudge();
935
935
  if (this.deps.isToolActive()) return;
936
+ this.flushPendingNudge();
936
937
  const sel = this.selectTool();
937
938
  if (!sel) return;
938
939
  const source = [];
@@ -1116,6 +1117,11 @@ function parseBinding(binding) {
1116
1117
  throw new Error(`Invalid shortcut binding "${binding}": unknown modifier "${part}"`);
1117
1118
  }
1118
1119
  }
1120
+ if (parsed.mod && (parsed.ctrl || parsed.meta)) {
1121
+ throw new Error(
1122
+ `Invalid shortcut binding "${binding}": "mod" already means Ctrl or Cmd; don't combine it with ctrl/meta`
1123
+ );
1124
+ }
1119
1125
  return parsed;
1120
1126
  }
1121
1127
  function bindingMatches(p, e, allowShift) {
@@ -1259,6 +1265,10 @@ var InputHandler = class {
1259
1265
  this.inputFilter.reset();
1260
1266
  this.deferredDown = null;
1261
1267
  this.lastPointerEvent = null;
1268
+ if (this.scope === "focus") {
1269
+ this.element.removeAttribute("tabindex");
1270
+ this.element.style.outline = "";
1271
+ }
1262
1272
  }
1263
1273
  bind() {
1264
1274
  const opts = { signal: this.abortController.signal };
@@ -1589,6 +1599,22 @@ var DoubleTapDetector = class {
1589
1599
  }
1590
1600
  };
1591
1601
 
1602
+ // src/core/geometry.ts
1603
+ function distSqToSegment(p, a, b) {
1604
+ const abx = b.x - a.x;
1605
+ const aby = b.y - a.y;
1606
+ const apx = p.x - a.x;
1607
+ const apy = p.y - a.y;
1608
+ const lenSq = abx * abx + aby * aby;
1609
+ if (lenSq === 0) {
1610
+ return apx * apx + apy * apy;
1611
+ }
1612
+ const t = Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq));
1613
+ const dx = p.x - (a.x + t * abx);
1614
+ const dy = p.y - (a.y + t * aby);
1615
+ return dx * dx + dy * dy;
1616
+ }
1617
+
1592
1618
  // src/elements/arrow-geometry.ts
1593
1619
  function getArrowControlPoint(from, to, bend) {
1594
1620
  const midX = (from.x + to.x) / 2;
@@ -1677,16 +1703,7 @@ function bezierPoint(from, cp, to, t) {
1677
1703
  };
1678
1704
  }
1679
1705
  function isNearLine(point, a, b, threshold) {
1680
- const dx = b.x - a.x;
1681
- const dy = b.y - a.y;
1682
- const lenSq = dx * dx + dy * dy;
1683
- if (lenSq === 0) {
1684
- return Math.hypot(point.x - a.x, point.y - a.y) <= threshold;
1685
- }
1686
- const t = Math.max(0, Math.min(1, ((point.x - a.x) * dx + (point.y - a.y) * dy) / lenSq));
1687
- const projX = a.x + t * dx;
1688
- const projY = a.y + t * dy;
1689
- return Math.hypot(point.x - projX, point.y - projY) <= threshold;
1706
+ return distSqToSegment(point, a, b) <= threshold * threshold;
1690
1707
  }
1691
1708
 
1692
1709
  // src/elements/element-bounds.ts
@@ -3117,9 +3134,9 @@ var ElementRenderer = class {
3117
3134
  });
3118
3135
  }
3119
3136
  };
3120
- img.onerror = () => {
3137
+ img.onerror = (event) => {
3121
3138
  this.imageCache.set(src, "failed");
3122
- this.onImageError?.(src);
3139
+ this.onImageError?.(src, event);
3123
3140
  this.onImageLoad?.();
3124
3141
  };
3125
3142
  return null;
@@ -3544,7 +3561,10 @@ var NoteEditor = class {
3544
3561
  this.editingNode.removeAttribute("data-fn-placeholder");
3545
3562
  this.editingNode.removeAttribute("data-fn-empty");
3546
3563
  const text = sanitizeNoteHtml(this.editingNode.innerHTML);
3547
- store.update(this.editingId, { text });
3564
+ const current = store.getById(this.editingId);
3565
+ if (current && (current.type === "note" || current.type === "text") && current.text !== text) {
3566
+ store.update(this.editingId, { text });
3567
+ }
3548
3568
  this.editingNode.contentEditable = "false";
3549
3569
  Object.assign(this.editingNode.style, {
3550
3570
  userSelect: "none",
@@ -5141,13 +5161,13 @@ var Viewport = class {
5141
5161
  this.renderLoop.markAllLayersDirty();
5142
5162
  this.requestRender();
5143
5163
  });
5144
- this.renderer.setOnImageError((src) => {
5164
+ this.renderer.setOnImageError((src, cause) => {
5145
5165
  const elementIds = [];
5146
5166
  for (const el of this.store.getAll()) {
5147
5167
  if (el.type === "image" && el.src === src) elementIds.push(el.id);
5148
5168
  }
5149
5169
  if (options.onImageError) {
5150
- options.onImageError({ src, elementIds });
5170
+ options.onImageError({ src, elementIds, cause });
5151
5171
  } else {
5152
5172
  console.warn(`[fieldnotes] image failed to load: ${src}`);
5153
5173
  }
@@ -5366,6 +5386,10 @@ var Viewport = class {
5366
5386
  this.loadState(parseState(json));
5367
5387
  }
5368
5388
  setTool(name) {
5389
+ if (!this.toolManager.getTool(name)) {
5390
+ console.warn(`[fieldnotes] setTool: no tool registered as "${name}"`);
5391
+ return;
5392
+ }
5369
5393
  this.toolManager.setTool(name, this.toolContext);
5370
5394
  }
5371
5395
  get shortcuts() {
@@ -5862,20 +5886,6 @@ var PencilTool = class {
5862
5886
  };
5863
5887
 
5864
5888
  // src/elements/stroke-hit.ts
5865
- function distSqToSegment(p, a, b) {
5866
- const abx = b.x - a.x;
5867
- const aby = b.y - a.y;
5868
- const apx = p.x - a.x;
5869
- const apy = p.y - a.y;
5870
- const lenSq = abx * abx + aby * aby;
5871
- if (lenSq === 0) {
5872
- return apx * apx + apy * apy;
5873
- }
5874
- const t = Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq));
5875
- const dx = p.x - (a.x + t * abx);
5876
- const dy = p.y - (a.y + t * aby);
5877
- return dx * dx + dy * dy;
5878
- }
5879
5889
  function hitTestStroke(stroke, point, radius) {
5880
5890
  const bounds = getElementBounds(stroke);
5881
5891
  if (!bounds) return false;
@@ -7472,7 +7482,7 @@ var TemplateTool = class {
7472
7482
  };
7473
7483
 
7474
7484
  // src/index.ts
7475
- var VERSION = "0.23.0";
7485
+ var VERSION = "0.24.0";
7476
7486
  export {
7477
7487
  AddElementCommand,
7478
7488
  ArrowTool,