@fieldnotes/core 0.59.0 → 0.60.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 +152 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +152 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -410,6 +410,7 @@ declare class ToolManager {
|
|
|
410
410
|
private tools;
|
|
411
411
|
private current;
|
|
412
412
|
private changeListeners;
|
|
413
|
+
private registerListeners;
|
|
413
414
|
get activeTool(): Tool | null;
|
|
414
415
|
get toolNames(): string[];
|
|
415
416
|
register(tool: Tool): void;
|
|
@@ -419,6 +420,7 @@ declare class ToolManager {
|
|
|
419
420
|
handlePointerMove(state: PointerState, ctx: ToolContext): void;
|
|
420
421
|
handlePointerUp(state: PointerState, ctx: ToolContext): void;
|
|
421
422
|
onChange(listener: (name: string) => void): () => void;
|
|
423
|
+
onRegister(listener: (tool: Tool) => void): () => void;
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
interface Command {
|
|
@@ -558,6 +560,11 @@ declare function getElementStyle(element: CanvasElement): ElementStyle;
|
|
|
558
560
|
|
|
559
561
|
type RotateDirection = 'cw' | 'ccw';
|
|
560
562
|
|
|
563
|
+
interface SelectionStyleDetails {
|
|
564
|
+
common: ElementStyle;
|
|
565
|
+
applicable: readonly (keyof ElementStyle)[];
|
|
566
|
+
mixed: readonly (keyof ElementStyle)[];
|
|
567
|
+
}
|
|
561
568
|
type AlignEdge = 'left' | 'center-x' | 'right' | 'top' | 'middle' | 'bottom';
|
|
562
569
|
type DistributeAxis = 'horizontal' | 'vertical';
|
|
563
570
|
|
|
@@ -637,6 +644,11 @@ declare class Viewport {
|
|
|
637
644
|
private minimap;
|
|
638
645
|
private readonly htmlRenderers;
|
|
639
646
|
private readonly resizeListeners;
|
|
647
|
+
private readonly selectionListeners;
|
|
648
|
+
private detachSelectionSource;
|
|
649
|
+
private unsubToolRegister;
|
|
650
|
+
private pendingSelectionPrune;
|
|
651
|
+
private unsubRecorderEnd;
|
|
640
652
|
constructor(container: HTMLElement, options?: ViewportOptions);
|
|
641
653
|
get ctx(): CanvasRenderingContext2D | null;
|
|
642
654
|
get snapToGrid(): boolean;
|
|
@@ -730,12 +742,34 @@ declare class Viewport {
|
|
|
730
742
|
getGridInfo(): GridInfo | null;
|
|
731
743
|
onGridChange(listener: (info: GridInfo | null) => void): () => void;
|
|
732
744
|
private getSelectTool;
|
|
745
|
+
private pruneSelection;
|
|
746
|
+
private handleRemovedElement;
|
|
747
|
+
private static isSelectionSource;
|
|
748
|
+
private emitSelectionChange;
|
|
749
|
+
private attachSelectionSource;
|
|
750
|
+
/**
|
|
751
|
+
* getSelectedIds() and the onSelectionChange emitter never surface stale ids:
|
|
752
|
+
* once the enclosing history transaction completes, both reflect
|
|
753
|
+
* the current selection.
|
|
754
|
+
*/
|
|
733
755
|
getSelectedIds(): string[];
|
|
734
756
|
runAction(action: string): void;
|
|
735
757
|
canPaste(): boolean;
|
|
736
758
|
openContextMenu(screenPos: Point): void;
|
|
759
|
+
/**
|
|
760
|
+
* Persistent, viewport-owned selection-change emitter. Subscribing works
|
|
761
|
+
* regardless of whether a select tool is registered yet; it forwards
|
|
762
|
+
* events from whichever select tool is currently attached via
|
|
763
|
+
* `toolManager.onRegister`. Never delivers stale ids once the enclosing
|
|
764
|
+
* history transaction completes.
|
|
765
|
+
*/
|
|
737
766
|
onSelectionChange(listener: () => void): () => void;
|
|
738
767
|
getSelectionStyle(): ElementStyle | null;
|
|
768
|
+
/**
|
|
769
|
+
* Unlike `getSelectionStyle()` — which returns `{}` for a style-less
|
|
770
|
+
* selection — this returns `null` when no style field is applicable.
|
|
771
|
+
*/
|
|
772
|
+
getSelectionStyleDetails(): SelectionStyleDetails | null;
|
|
739
773
|
applyStyleToSelection(style: ElementStyle): void;
|
|
740
774
|
groupSelection(): void;
|
|
741
775
|
ungroupSelection(): void;
|
|
@@ -1755,6 +1789,6 @@ declare class TemplateTool implements Tool {
|
|
|
1755
1789
|
private notifyOptionsChange;
|
|
1756
1790
|
}
|
|
1757
1791
|
|
|
1758
|
-
declare const VERSION = "0.
|
|
1792
|
+
declare const VERSION = "0.60.0";
|
|
1759
1793
|
|
|
1760
|
-
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, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, 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, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1794
|
+
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, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type SelectionStyleDetails, 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, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.d.ts
CHANGED
|
@@ -410,6 +410,7 @@ declare class ToolManager {
|
|
|
410
410
|
private tools;
|
|
411
411
|
private current;
|
|
412
412
|
private changeListeners;
|
|
413
|
+
private registerListeners;
|
|
413
414
|
get activeTool(): Tool | null;
|
|
414
415
|
get toolNames(): string[];
|
|
415
416
|
register(tool: Tool): void;
|
|
@@ -419,6 +420,7 @@ declare class ToolManager {
|
|
|
419
420
|
handlePointerMove(state: PointerState, ctx: ToolContext): void;
|
|
420
421
|
handlePointerUp(state: PointerState, ctx: ToolContext): void;
|
|
421
422
|
onChange(listener: (name: string) => void): () => void;
|
|
423
|
+
onRegister(listener: (tool: Tool) => void): () => void;
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
interface Command {
|
|
@@ -558,6 +560,11 @@ declare function getElementStyle(element: CanvasElement): ElementStyle;
|
|
|
558
560
|
|
|
559
561
|
type RotateDirection = 'cw' | 'ccw';
|
|
560
562
|
|
|
563
|
+
interface SelectionStyleDetails {
|
|
564
|
+
common: ElementStyle;
|
|
565
|
+
applicable: readonly (keyof ElementStyle)[];
|
|
566
|
+
mixed: readonly (keyof ElementStyle)[];
|
|
567
|
+
}
|
|
561
568
|
type AlignEdge = 'left' | 'center-x' | 'right' | 'top' | 'middle' | 'bottom';
|
|
562
569
|
type DistributeAxis = 'horizontal' | 'vertical';
|
|
563
570
|
|
|
@@ -637,6 +644,11 @@ declare class Viewport {
|
|
|
637
644
|
private minimap;
|
|
638
645
|
private readonly htmlRenderers;
|
|
639
646
|
private readonly resizeListeners;
|
|
647
|
+
private readonly selectionListeners;
|
|
648
|
+
private detachSelectionSource;
|
|
649
|
+
private unsubToolRegister;
|
|
650
|
+
private pendingSelectionPrune;
|
|
651
|
+
private unsubRecorderEnd;
|
|
640
652
|
constructor(container: HTMLElement, options?: ViewportOptions);
|
|
641
653
|
get ctx(): CanvasRenderingContext2D | null;
|
|
642
654
|
get snapToGrid(): boolean;
|
|
@@ -730,12 +742,34 @@ declare class Viewport {
|
|
|
730
742
|
getGridInfo(): GridInfo | null;
|
|
731
743
|
onGridChange(listener: (info: GridInfo | null) => void): () => void;
|
|
732
744
|
private getSelectTool;
|
|
745
|
+
private pruneSelection;
|
|
746
|
+
private handleRemovedElement;
|
|
747
|
+
private static isSelectionSource;
|
|
748
|
+
private emitSelectionChange;
|
|
749
|
+
private attachSelectionSource;
|
|
750
|
+
/**
|
|
751
|
+
* getSelectedIds() and the onSelectionChange emitter never surface stale ids:
|
|
752
|
+
* once the enclosing history transaction completes, both reflect
|
|
753
|
+
* the current selection.
|
|
754
|
+
*/
|
|
733
755
|
getSelectedIds(): string[];
|
|
734
756
|
runAction(action: string): void;
|
|
735
757
|
canPaste(): boolean;
|
|
736
758
|
openContextMenu(screenPos: Point): void;
|
|
759
|
+
/**
|
|
760
|
+
* Persistent, viewport-owned selection-change emitter. Subscribing works
|
|
761
|
+
* regardless of whether a select tool is registered yet; it forwards
|
|
762
|
+
* events from whichever select tool is currently attached via
|
|
763
|
+
* `toolManager.onRegister`. Never delivers stale ids once the enclosing
|
|
764
|
+
* history transaction completes.
|
|
765
|
+
*/
|
|
737
766
|
onSelectionChange(listener: () => void): () => void;
|
|
738
767
|
getSelectionStyle(): ElementStyle | null;
|
|
768
|
+
/**
|
|
769
|
+
* Unlike `getSelectionStyle()` — which returns `{}` for a style-less
|
|
770
|
+
* selection — this returns `null` when no style field is applicable.
|
|
771
|
+
*/
|
|
772
|
+
getSelectionStyleDetails(): SelectionStyleDetails | null;
|
|
739
773
|
applyStyleToSelection(style: ElementStyle): void;
|
|
740
774
|
groupSelection(): void;
|
|
741
775
|
ungroupSelection(): void;
|
|
@@ -1755,6 +1789,6 @@ declare class TemplateTool implements Tool {
|
|
|
1755
1789
|
private notifyOptionsChange;
|
|
1756
1790
|
}
|
|
1757
1791
|
|
|
1758
|
-
declare const VERSION = "0.
|
|
1792
|
+
declare const VERSION = "0.60.0";
|
|
1759
1793
|
|
|
1760
|
-
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, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, 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, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1794
|
+
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, LASER_TRAIL_PRESENCE_KIND, LaserTool, type LaserToolOptions, type LaserTrailEmission, type LaserTrailPresence, type Layer, LayerManager, LocalStorageAdapter, MEASURE_PRESENCE_KIND, type MeasureEmission, type MeasurePresence, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, MinimapController, type MinimapControllerOptions, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PING_PRESENCE_KIND, PencilTool, type PencilToolOptions, type PingEmission, PingInput, type PingInputHost, type PingInputOptions, type PingPresence, PingTool, type PingToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, RemoteMeasureOverlay, type RemoteMeasureOverlayHost, type RemoteMeasureOverlayOptions, RemotePingOverlay, type RemotePingOverlayHost, type RemotePingOverlayOptions, type RenderStatsSnapshot, type RotateDirection, SelectTool, type SelectionStyleDetails, 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, isLaserTrailPresence, isMeasurePresence, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toMeasurePresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.js
CHANGED
|
@@ -5170,6 +5170,7 @@ var ToolManager = class {
|
|
|
5170
5170
|
tools = /* @__PURE__ */ new Map();
|
|
5171
5171
|
current = null;
|
|
5172
5172
|
changeListeners = /* @__PURE__ */ new Set();
|
|
5173
|
+
registerListeners = /* @__PURE__ */ new Set();
|
|
5173
5174
|
get activeTool() {
|
|
5174
5175
|
return this.current;
|
|
5175
5176
|
}
|
|
@@ -5178,6 +5179,7 @@ var ToolManager = class {
|
|
|
5178
5179
|
}
|
|
5179
5180
|
register(tool) {
|
|
5180
5181
|
this.tools.set(tool.name, tool);
|
|
5182
|
+
this.registerListeners.forEach((fn) => fn(tool));
|
|
5181
5183
|
}
|
|
5182
5184
|
getTool(name) {
|
|
5183
5185
|
return this.tools.get(name);
|
|
@@ -5203,6 +5205,10 @@ var ToolManager = class {
|
|
|
5203
5205
|
this.changeListeners.add(listener);
|
|
5204
5206
|
return () => this.changeListeners.delete(listener);
|
|
5205
5207
|
}
|
|
5208
|
+
onRegister(listener) {
|
|
5209
|
+
this.registerListeners.add(listener);
|
|
5210
|
+
return () => this.registerListeners.delete(listener);
|
|
5211
|
+
}
|
|
5206
5212
|
};
|
|
5207
5213
|
|
|
5208
5214
|
// src/history/history-stack.ts
|
|
@@ -5394,6 +5400,7 @@ var HistoryRecorder = class {
|
|
|
5394
5400
|
generation = 0;
|
|
5395
5401
|
updateSnapshots = /* @__PURE__ */ new Map();
|
|
5396
5402
|
unsubscribers;
|
|
5403
|
+
transactionEndListeners = /* @__PURE__ */ new Set();
|
|
5397
5404
|
pause() {
|
|
5398
5405
|
this.recording = false;
|
|
5399
5406
|
}
|
|
@@ -5411,19 +5418,35 @@ var HistoryRecorder = class {
|
|
|
5411
5418
|
get currentTransactionId() {
|
|
5412
5419
|
return this.transaction !== null ? this.generation : null;
|
|
5413
5420
|
}
|
|
5421
|
+
onTransactionEnd(listener) {
|
|
5422
|
+
this.transactionEndListeners.add(listener);
|
|
5423
|
+
return () => this.transactionEndListeners.delete(listener);
|
|
5424
|
+
}
|
|
5425
|
+
notifyTransactionEnd() {
|
|
5426
|
+
for (const listener of this.transactionEndListeners) {
|
|
5427
|
+
try {
|
|
5428
|
+
listener();
|
|
5429
|
+
} catch {
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
}
|
|
5414
5433
|
commit() {
|
|
5415
5434
|
if (!this.transaction) return;
|
|
5416
5435
|
const finalCommands = this.flushUpdateSnapshots();
|
|
5417
5436
|
const all = [...this.transaction, ...finalCommands];
|
|
5418
5437
|
this.transaction = null;
|
|
5419
5438
|
this.updateSnapshots.clear();
|
|
5420
|
-
if (all.length
|
|
5421
|
-
|
|
5422
|
-
|
|
5439
|
+
if (all.length > 0) {
|
|
5440
|
+
const first = all[0];
|
|
5441
|
+
this.stack.push(all.length === 1 && first ? first : new BatchCommand(all));
|
|
5442
|
+
}
|
|
5443
|
+
this.notifyTransactionEnd();
|
|
5423
5444
|
}
|
|
5424
5445
|
rollback() {
|
|
5446
|
+
const wasOpen = this.transaction !== null;
|
|
5425
5447
|
this.transaction = null;
|
|
5426
5448
|
this.updateSnapshots.clear();
|
|
5449
|
+
if (wasOpen) this.notifyTransactionEnd();
|
|
5427
5450
|
}
|
|
5428
5451
|
destroy() {
|
|
5429
5452
|
this.unsubscribers.forEach((fn) => fn());
|
|
@@ -7715,6 +7738,14 @@ function rotateElementPatch(el, bounds, pivot, delta) {
|
|
|
7715
7738
|
}
|
|
7716
7739
|
|
|
7717
7740
|
// src/canvas/selection-ops.ts
|
|
7741
|
+
var STYLE_FIELDS = [
|
|
7742
|
+
"color",
|
|
7743
|
+
"fillColor",
|
|
7744
|
+
"strokeWidth",
|
|
7745
|
+
"opacity",
|
|
7746
|
+
"fontSize",
|
|
7747
|
+
"strokeStyle"
|
|
7748
|
+
];
|
|
7718
7749
|
function sharedValue(values) {
|
|
7719
7750
|
const present = values.filter((v) => v !== void 0);
|
|
7720
7751
|
if (present.length === 0) return void 0;
|
|
@@ -7749,6 +7780,42 @@ var SelectionOps = class {
|
|
|
7749
7780
|
if (strokeStyle !== void 0) result.strokeStyle = strokeStyle;
|
|
7750
7781
|
return result;
|
|
7751
7782
|
}
|
|
7783
|
+
/**
|
|
7784
|
+
* Unlike `getStyle()` — which returns `{}` for a selection whose elements
|
|
7785
|
+
* have no applicable style fields (e.g. images) — this returns `null` when
|
|
7786
|
+
* no field is applicable, so callers can distinguish "nothing to show" from
|
|
7787
|
+
* "everything shared but empty".
|
|
7788
|
+
*/
|
|
7789
|
+
getStyleDetails() {
|
|
7790
|
+
const ids = this.deps.getSelectedIds();
|
|
7791
|
+
if (ids.length === 0) return null;
|
|
7792
|
+
const styles = [];
|
|
7793
|
+
for (const id of ids) {
|
|
7794
|
+
const el = this.deps.store.getById(id);
|
|
7795
|
+
if (el) styles.push(getElementStyle(el));
|
|
7796
|
+
}
|
|
7797
|
+
if (styles.length === 0) return null;
|
|
7798
|
+
const common = {};
|
|
7799
|
+
const applicable = [];
|
|
7800
|
+
const mixed = [];
|
|
7801
|
+
for (const field of STYLE_FIELDS) {
|
|
7802
|
+
const allValues = styles.map((s) => s[field]);
|
|
7803
|
+
const values = [];
|
|
7804
|
+
for (const v of allValues) {
|
|
7805
|
+
if (v !== void 0) values.push(v);
|
|
7806
|
+
}
|
|
7807
|
+
if (values.length === 0) continue;
|
|
7808
|
+
applicable.push(field);
|
|
7809
|
+
const distinct = new Set(values);
|
|
7810
|
+
if (distinct.size > 1) {
|
|
7811
|
+
mixed.push(field);
|
|
7812
|
+
} else {
|
|
7813
|
+
common[field] = values[0];
|
|
7814
|
+
}
|
|
7815
|
+
}
|
|
7816
|
+
if (applicable.length === 0) return null;
|
|
7817
|
+
return { common, applicable, mixed };
|
|
7818
|
+
}
|
|
7752
7819
|
applyStyle(style) {
|
|
7753
7820
|
const ids = this.deps.getSelectedIds();
|
|
7754
7821
|
if (ids.length === 0) return;
|
|
@@ -8123,7 +8190,7 @@ var ViewportInteractions = class {
|
|
|
8123
8190
|
var EMPTY_IDS = [];
|
|
8124
8191
|
function noop() {
|
|
8125
8192
|
}
|
|
8126
|
-
var Viewport = class {
|
|
8193
|
+
var Viewport = class _Viewport {
|
|
8127
8194
|
constructor(container, options = {}) {
|
|
8128
8195
|
this.container = container;
|
|
8129
8196
|
this.camera = new Camera(options.camera);
|
|
@@ -8132,6 +8199,13 @@ var Viewport = class {
|
|
|
8132
8199
|
this.store = new ElementStore();
|
|
8133
8200
|
this.layerManager = new LayerManager(this.store);
|
|
8134
8201
|
this.toolManager = new ToolManager();
|
|
8202
|
+
this.unsubToolRegister = this.toolManager.onRegister((tool) => {
|
|
8203
|
+
if (_Viewport.isSelectionSource(tool)) this.attachSelectionSource(tool);
|
|
8204
|
+
});
|
|
8205
|
+
const existingSelect = this.getSelectTool();
|
|
8206
|
+
if (existingSelect && _Viewport.isSelectionSource(existingSelect)) {
|
|
8207
|
+
this.attachSelectionSource(existingSelect);
|
|
8208
|
+
}
|
|
8135
8209
|
this.renderer = new ElementRenderer();
|
|
8136
8210
|
this.renderer.setStore(this.store);
|
|
8137
8211
|
this.renderer.setCamera(this.camera);
|
|
@@ -8166,6 +8240,11 @@ var Viewport = class {
|
|
|
8166
8240
|
this.dropHandler = options.onDrop;
|
|
8167
8241
|
this.history = new HistoryStack();
|
|
8168
8242
|
this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
|
|
8243
|
+
this.unsubRecorderEnd = this.historyRecorder.onTransactionEnd(() => {
|
|
8244
|
+
if (!this.pendingSelectionPrune) return;
|
|
8245
|
+
this.pendingSelectionPrune = false;
|
|
8246
|
+
this.pruneSelection();
|
|
8247
|
+
});
|
|
8169
8248
|
this.selectionOps = new SelectionOps({
|
|
8170
8249
|
store: this.store,
|
|
8171
8250
|
recorder: this.historyRecorder,
|
|
@@ -8285,6 +8364,7 @@ var Viewport = class {
|
|
|
8285
8364
|
this.domNodeManager.removeDomNode(el.id);
|
|
8286
8365
|
this.renderLoop.markLayerDirty(el.layerId);
|
|
8287
8366
|
this.requestRender();
|
|
8367
|
+
this.handleRemovedElement(el.id);
|
|
8288
8368
|
}),
|
|
8289
8369
|
this.store.on("update", ({ previous, current }) => {
|
|
8290
8370
|
if (current.type === "grid") this.gridController.syncContext();
|
|
@@ -8299,6 +8379,7 @@ var Viewport = class {
|
|
|
8299
8379
|
this.renderLoop.markAllLayersDirty();
|
|
8300
8380
|
this.gridController.syncContext();
|
|
8301
8381
|
this.requestRender();
|
|
8382
|
+
this.pruneSelection();
|
|
8302
8383
|
})
|
|
8303
8384
|
];
|
|
8304
8385
|
this.layerManager.on("change", () => {
|
|
@@ -8368,6 +8449,13 @@ var Viewport = class {
|
|
|
8368
8449
|
minimap = null;
|
|
8369
8450
|
htmlRenderers = /* @__PURE__ */ new Map();
|
|
8370
8451
|
resizeListeners = /* @__PURE__ */ new Set();
|
|
8452
|
+
selectionListeners = /* @__PURE__ */ new Set();
|
|
8453
|
+
detachSelectionSource = null;
|
|
8454
|
+
unsubToolRegister = () => {
|
|
8455
|
+
};
|
|
8456
|
+
pendingSelectionPrune = false;
|
|
8457
|
+
unsubRecorderEnd = () => {
|
|
8458
|
+
};
|
|
8371
8459
|
get ctx() {
|
|
8372
8460
|
return this.canvasEl.getContext("2d");
|
|
8373
8461
|
}
|
|
@@ -8626,6 +8714,42 @@ var Viewport = class {
|
|
|
8626
8714
|
getSelectTool() {
|
|
8627
8715
|
return this.toolManager.getTool("select");
|
|
8628
8716
|
}
|
|
8717
|
+
pruneSelection() {
|
|
8718
|
+
const tool = this.getSelectTool();
|
|
8719
|
+
if (!tool) return;
|
|
8720
|
+
const ids = tool.selectedIds;
|
|
8721
|
+
const filtered = ids.filter((id) => this.store.getById(id) !== void 0);
|
|
8722
|
+
if (filtered.length !== ids.length) tool.setSelection(filtered);
|
|
8723
|
+
}
|
|
8724
|
+
handleRemovedElement(id) {
|
|
8725
|
+
if (!this.getSelectedIds().includes(id)) return;
|
|
8726
|
+
if (this.historyRecorder.currentTransactionId !== null) {
|
|
8727
|
+
this.pendingSelectionPrune = true;
|
|
8728
|
+
return;
|
|
8729
|
+
}
|
|
8730
|
+
this.pruneSelection();
|
|
8731
|
+
}
|
|
8732
|
+
static isSelectionSource(tool) {
|
|
8733
|
+
const candidate = tool;
|
|
8734
|
+
return tool.name === "select" && typeof candidate.onSelectionChange === "function" && typeof candidate.setSelection === "function";
|
|
8735
|
+
}
|
|
8736
|
+
emitSelectionChange() {
|
|
8737
|
+
for (const listener of this.selectionListeners) {
|
|
8738
|
+
try {
|
|
8739
|
+
listener();
|
|
8740
|
+
} catch {
|
|
8741
|
+
}
|
|
8742
|
+
}
|
|
8743
|
+
}
|
|
8744
|
+
attachSelectionSource(tool) {
|
|
8745
|
+
this.detachSelectionSource?.();
|
|
8746
|
+
this.detachSelectionSource = tool.onSelectionChange(() => this.emitSelectionChange());
|
|
8747
|
+
}
|
|
8748
|
+
/**
|
|
8749
|
+
* getSelectedIds() and the onSelectionChange emitter never surface stale ids:
|
|
8750
|
+
* once the enclosing history transaction completes, both reflect
|
|
8751
|
+
* the current selection.
|
|
8752
|
+
*/
|
|
8629
8753
|
getSelectedIds() {
|
|
8630
8754
|
return this.getSelectTool()?.selectedIds ?? EMPTY_IDS;
|
|
8631
8755
|
}
|
|
@@ -8659,13 +8783,29 @@ var Viewport = class {
|
|
|
8659
8783
|
if (items.length === 0) return;
|
|
8660
8784
|
this.contextMenu.open(items, screenPos);
|
|
8661
8785
|
}
|
|
8786
|
+
/**
|
|
8787
|
+
* Persistent, viewport-owned selection-change emitter. Subscribing works
|
|
8788
|
+
* regardless of whether a select tool is registered yet; it forwards
|
|
8789
|
+
* events from whichever select tool is currently attached via
|
|
8790
|
+
* `toolManager.onRegister`. Never delivers stale ids once the enclosing
|
|
8791
|
+
* history transaction completes.
|
|
8792
|
+
*/
|
|
8662
8793
|
onSelectionChange(listener) {
|
|
8663
|
-
|
|
8664
|
-
return
|
|
8794
|
+
this.selectionListeners.add(listener);
|
|
8795
|
+
return () => {
|
|
8796
|
+
this.selectionListeners.delete(listener);
|
|
8797
|
+
};
|
|
8665
8798
|
}
|
|
8666
8799
|
getSelectionStyle() {
|
|
8667
8800
|
return this.selectionOps.getStyle();
|
|
8668
8801
|
}
|
|
8802
|
+
/**
|
|
8803
|
+
* Unlike `getSelectionStyle()` — which returns `{}` for a style-less
|
|
8804
|
+
* selection — this returns `null` when no style field is applicable.
|
|
8805
|
+
*/
|
|
8806
|
+
getSelectionStyleDetails() {
|
|
8807
|
+
return this.selectionOps.getStyleDetails();
|
|
8808
|
+
}
|
|
8669
8809
|
applyStyleToSelection(style) {
|
|
8670
8810
|
this.selectionOps.applyStyle(style);
|
|
8671
8811
|
}
|
|
@@ -8714,6 +8854,11 @@ var Viewport = class {
|
|
|
8714
8854
|
this.inputHandler.destroy();
|
|
8715
8855
|
this.unsubCamera();
|
|
8716
8856
|
this.unsubToolChange();
|
|
8857
|
+
this.unsubToolRegister();
|
|
8858
|
+
this.unsubRecorderEnd();
|
|
8859
|
+
this.detachSelectionSource?.();
|
|
8860
|
+
this.detachSelectionSource = null;
|
|
8861
|
+
this.selectionListeners.clear();
|
|
8717
8862
|
this.unsubStore.forEach((fn) => fn());
|
|
8718
8863
|
this.resizeObserver?.disconnect();
|
|
8719
8864
|
this.resizeObserver = null;
|
|
@@ -12315,7 +12460,7 @@ var PingTool = class {
|
|
|
12315
12460
|
};
|
|
12316
12461
|
|
|
12317
12462
|
// src/index.ts
|
|
12318
|
-
var VERSION = "0.
|
|
12463
|
+
var VERSION = "0.60.0";
|
|
12319
12464
|
export {
|
|
12320
12465
|
ArrowTool,
|
|
12321
12466
|
AutoSave,
|