@fieldnotes/core 0.40.0 → 0.40.2

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
@@ -1048,6 +1048,6 @@ declare class LaserTool implements Tool {
1048
1048
  private notifyOptionsChange;
1049
1049
  }
1050
1050
 
1051
- declare const VERSION = "0.40.0";
1051
+ declare const VERSION = "0.40.2";
1052
1052
 
1053
1053
  export { type ActiveFormats, type AlignEdge, type ArrowElement, 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, LaserTool, type LaserToolOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, 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 StrokeElement, type StrokePoint, type TemplateElement, 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
@@ -1048,6 +1048,6 @@ declare class LaserTool implements Tool {
1048
1048
  private notifyOptionsChange;
1049
1049
  }
1050
1050
 
1051
- declare const VERSION = "0.40.0";
1051
+ declare const VERSION = "0.40.2";
1052
1052
 
1053
1053
  export { type ActiveFormats, type AlignEdge, type ArrowElement, 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, LaserTool, type LaserToolOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, 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 StrokeElement, type StrokePoint, type TemplateElement, 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
@@ -3948,6 +3948,7 @@ var NoteEditor = class {
3948
3948
  inputHandler = null;
3949
3949
  pendingEditId = null;
3950
3950
  onStopCallback = null;
3951
+ onInputCallback = null;
3951
3952
  beginHistory = null;
3952
3953
  commitHistory = null;
3953
3954
  toolbar;
@@ -3965,6 +3966,9 @@ var NoteEditor = class {
3965
3966
  setOnStop(callback) {
3966
3967
  this.onStopCallback = callback;
3967
3968
  }
3969
+ setOnInput(callback) {
3970
+ this.onInputCallback = callback;
3971
+ }
3968
3972
  setHistoryHooks(begin, commit) {
3969
3973
  this.beginHistory = begin;
3970
3974
  this.commitHistory = commit;
@@ -4007,7 +4011,6 @@ var NoteEditor = class {
4007
4011
  cursor: "default"
4008
4012
  });
4009
4013
  this.toolbar?.hide();
4010
- this.beginHistory?.();
4011
4014
  if (textChanged) {
4012
4015
  store.update(this.editingId, { text });
4013
4016
  }
@@ -4036,6 +4039,7 @@ var NoteEditor = class {
4036
4039
  activateEditing(node, elementId, store) {
4037
4040
  this.editingId = elementId;
4038
4041
  this.editingNode = node;
4042
+ this.beginHistory?.();
4039
4043
  node.contentEditable = "true";
4040
4044
  Object.assign(node.style, {
4041
4045
  userSelect: "text",
@@ -4056,6 +4060,7 @@ var NoteEditor = class {
4056
4060
  node.setAttribute("data-fn-empty", String(isNodeEmpty(node)));
4057
4061
  this.inputHandler = () => {
4058
4062
  node.setAttribute("data-fn-empty", String(isNodeEmpty(node)));
4063
+ this.onInputCallback?.(elementId);
4059
4064
  };
4060
4065
  node.addEventListener("input", this.inputHandler);
4061
4066
  this.toolbar?.show(node);
@@ -4682,6 +4687,16 @@ function renderStyledRuns(ctx, runs, startX, startY, maxWidth) {
4682
4687
  }
4683
4688
  }
4684
4689
 
4690
+ // src/canvas/text-canvas-renderer.ts
4691
+ function renderTextOnCanvas(ctx, text) {
4692
+ const pad = 2;
4693
+ ctx.save();
4694
+ ctx.fillStyle = text.color;
4695
+ const runs = parseStyledRuns(text.text ?? "", text.fontSize);
4696
+ renderStyledRuns(ctx, runs, text.position.x + pad, text.position.y + pad, text.size.w - pad * 2);
4697
+ ctx.restore();
4698
+ }
4699
+
4685
4700
  // src/canvas/export-image.ts
4686
4701
  var center = (b) => ({ x: b.x + b.w / 2, y: b.y + b.h / 2 });
4687
4702
  function getStrokeBounds(el) {
@@ -4764,30 +4779,6 @@ function computeBounds(elements, padding) {
4764
4779
  h: maxY - minY + padding * 2
4765
4780
  };
4766
4781
  }
4767
- function renderTextOnCanvas(ctx, text) {
4768
- if (!text.text) return;
4769
- ctx.save();
4770
- ctx.fillStyle = text.color;
4771
- ctx.font = `${text.fontSize}px system-ui, sans-serif`;
4772
- ctx.textBaseline = "top";
4773
- ctx.textAlign = text.textAlign;
4774
- const pad = 2;
4775
- let textX = text.position.x + pad;
4776
- if (text.textAlign === "center") {
4777
- textX = text.position.x + text.size.w / 2;
4778
- } else if (text.textAlign === "right") {
4779
- textX = text.position.x + text.size.w - pad;
4780
- }
4781
- const lineHeight = text.fontSize * 1.4;
4782
- const lines = text.text.split("\n");
4783
- for (let i = 0; i < lines.length; i++) {
4784
- const line = lines[i];
4785
- if (line !== void 0) {
4786
- ctx.fillText(line, textX, text.position.y + pad + i * lineHeight);
4787
- }
4788
- }
4789
- ctx.restore();
4790
- }
4791
4782
  function renderGridForBounds(ctx, grid, bounds) {
4792
4783
  const visibleBounds = {
4793
4784
  minX: bounds.x,
@@ -5009,28 +5000,27 @@ function emitImage(image, dataUri) {
5009
5000
  const { w, h } = image.size;
5010
5001
  return `<image href="${esc(href)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
5011
5002
  }
5012
- function emitText(text) {
5003
+ function emitText(text, rasterScale) {
5013
5004
  if (!text.text) return "";
5014
- const pad = 2;
5015
- let anchor = "start";
5016
- let textX = text.position.x + pad;
5017
- if (text.textAlign === "center") {
5018
- anchor = "middle";
5019
- textX = text.position.x + text.size.w / 2;
5020
- } else if (text.textAlign === "right") {
5021
- anchor = "end";
5022
- textX = text.position.x + text.size.w - pad;
5023
- }
5024
- const lineHeight = text.fontSize * 1.4;
5025
- const lines = text.text.split("\n");
5026
- let out = "";
5027
- for (let i = 0; i < lines.length; i++) {
5028
- const line = lines[i];
5029
- if (line === void 0) continue;
5030
- const y = text.position.y + pad + i * lineHeight;
5031
- out += `<text x="${n(textX)}" y="${n(y)}" font-family="system-ui, sans-serif" font-size="${n(text.fontSize)}" fill="${esc(text.color)}" text-anchor="${anchor}" dominant-baseline="text-before-edge">${esc(line)}</text>`;
5005
+ const { x, y } = text.position;
5006
+ const { w, h } = text.size;
5007
+ if (typeof document === "undefined") return "";
5008
+ const canvas = document.createElement("canvas");
5009
+ canvas.width = Math.max(1, Math.ceil(w * rasterScale));
5010
+ canvas.height = Math.max(1, Math.ceil(h * rasterScale));
5011
+ const ctx = canvas.getContext("2d");
5012
+ if (!ctx) return "";
5013
+ ctx.scale(rasterScale, rasterScale);
5014
+ ctx.translate(-x, -y);
5015
+ renderTextOnCanvas(ctx, text);
5016
+ let dataUri;
5017
+ try {
5018
+ dataUri = canvas.toDataURL();
5019
+ } catch {
5020
+ return "";
5032
5021
  }
5033
- return out;
5022
+ if (!dataUri || !dataUri.startsWith("data:")) return "";
5023
+ return `<image href="${esc(dataUri)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
5034
5024
  }
5035
5025
  function emitNote(note, rasterScale) {
5036
5026
  const { x, y } = note.position;
@@ -5213,7 +5203,7 @@ function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
5213
5203
  case "image":
5214
5204
  return withRotationSvg(el, emitImage(el, imageDataUris.get(el.id)));
5215
5205
  case "text":
5216
- return withRotationSvg(el, emitText(el));
5206
+ return withRotationSvg(el, emitText(el, rasterScale));
5217
5207
  case "note":
5218
5208
  return withRotationSvg(el, emitNote(el, rasterScale));
5219
5209
  case "template":
@@ -5676,10 +5666,9 @@ var DomNodeManager = class {
5676
5666
  cursor: "default",
5677
5667
  userSelect: "none",
5678
5668
  wordWrap: "break-word",
5679
- whiteSpace: "pre-wrap",
5680
5669
  lineHeight: "1.4"
5681
5670
  });
5682
- node.textContent = element.text || "";
5671
+ node.innerHTML = element.text || "";
5683
5672
  const detector = new DoubleTapDetector();
5684
5673
  node.addEventListener("pointerup", (e) => {
5685
5674
  if (detector.feed(e)) {
@@ -5690,8 +5679,9 @@ var DomNodeManager = class {
5690
5679
  });
5691
5680
  }
5692
5681
  if (!this.isEditingElement(element.id)) {
5693
- if (node.textContent !== element.text) {
5694
- node.textContent = element.text || "";
5682
+ const text = element.text || "";
5683
+ if (node.innerHTML !== text) {
5684
+ node.innerHTML = text;
5695
5685
  }
5696
5686
  Object.assign(node.style, {
5697
5687
  fontSize: `${element.fontSize}px`,
@@ -6534,6 +6524,16 @@ var ViewportInteractions = class {
6534
6524
  this.deps.noteEditor.startEditing(node, id, this.deps.store);
6535
6525
  }
6536
6526
  }
6527
+ liveFitHeight(elementId) {
6528
+ const element = this.deps.store.getById(elementId);
6529
+ if (!element || element.type !== "note" && element.type !== "text") return;
6530
+ const node = this.deps.domNodeManager.getNode(elementId);
6531
+ if (!node) return;
6532
+ const measured = node.scrollHeight;
6533
+ if (measured > 0 && measured !== element.size.h) {
6534
+ this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });
6535
+ }
6536
+ }
6537
6537
  fitNoteHeight(elementId) {
6538
6538
  const element = this.deps.store.getById(elementId);
6539
6539
  if (!element || element.type !== "note") return;
@@ -6553,7 +6553,7 @@ var ViewportInteractions = class {
6553
6553
  this.deps.store.remove(elementId);
6554
6554
  return;
6555
6555
  }
6556
- this.fitNoteHeight(elementId);
6556
+ this.liveFitHeight(elementId);
6557
6557
  return;
6558
6558
  }
6559
6559
  if (element.type !== "text") return;
@@ -6561,13 +6561,7 @@ var ViewportInteractions = class {
6561
6561
  this.deps.store.remove(elementId);
6562
6562
  return;
6563
6563
  }
6564
- const node = this.deps.domNodeManager.getNode(elementId);
6565
- if (node && "size" in element) {
6566
- const measured = node.scrollHeight;
6567
- if (measured !== element.size.h) {
6568
- this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });
6569
- }
6570
- }
6564
+ this.liveFitHeight(elementId);
6571
6565
  }
6572
6566
  onTapDown = (e) => {
6573
6567
  this.tapDownX = e.clientX;
@@ -6703,6 +6697,7 @@ var Viewport = class {
6703
6697
  placeholder: options.placeholder
6704
6698
  });
6705
6699
  this.noteEditor.setOnStop((id) => this.interactions.onTextEditStop(id));
6700
+ this.noteEditor.setOnInput((id) => this.interactions.liveFitHeight(id));
6706
6701
  this.arrowLabelEditor = new ArrowLabelEditor();
6707
6702
  this.noteEditor.setHistoryHooks(
6708
6703
  () => this.historyRecorder.begin(),
@@ -9669,7 +9664,7 @@ var LaserTool = class {
9669
9664
  };
9670
9665
 
9671
9666
  // src/index.ts
9672
- var VERSION = "0.40.0";
9667
+ var VERSION = "0.40.2";
9673
9668
  export {
9674
9669
  ArrowTool,
9675
9670
  AutoSave,