@fieldnotes/core 0.54.0 → 0.56.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 +492 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +259 -3
- package/dist/index.d.ts +259 -3
- package/dist/index.js +486 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -249,7 +249,7 @@ interface Tool {
|
|
|
249
249
|
setOptions?(options: object): void;
|
|
250
250
|
onOptionsChange?(listener: () => void): () => void;
|
|
251
251
|
}
|
|
252
|
-
type ToolName = 'hand' | 'select' | 'pencil' | 'eraser' | 'arrow' | 'note' | 'image' | 'text' | 'shape' | 'measure' | 'template' | 'laser';
|
|
252
|
+
type ToolName = 'hand' | 'select' | 'pencil' | 'eraser' | 'arrow' | 'note' | 'image' | 'text' | 'shape' | 'measure' | 'template' | 'laser' | 'ping';
|
|
253
253
|
|
|
254
254
|
declare function snapPoint(point: Point, gridSize: number): Point;
|
|
255
255
|
declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
|
|
@@ -844,6 +844,262 @@ declare class RemoteLaserOverlay {
|
|
|
844
844
|
private renderTrails;
|
|
845
845
|
}
|
|
846
846
|
|
|
847
|
+
interface PingToolOptions {
|
|
848
|
+
name?: string;
|
|
849
|
+
color?: string;
|
|
850
|
+
/** Total pulse animation length in milliseconds. */
|
|
851
|
+
durationMs?: number;
|
|
852
|
+
/** Maximum ripple radius in world units. */
|
|
853
|
+
radius?: number;
|
|
854
|
+
/**
|
|
855
|
+
* Minimum interval between emitted pings. Taps arriving faster are ignored
|
|
856
|
+
* entirely (no local pulse, no emission), so rapid-fire pings cannot starve
|
|
857
|
+
* durable sync traffic.
|
|
858
|
+
*/
|
|
859
|
+
minIntervalMs?: number;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* One emitted ping — the outgoing side of a shared "look here" marker.
|
|
863
|
+
* Emissions carry the world position and the tool's current style so a host
|
|
864
|
+
* can forward them as ephemeral presence without duplicating input handling.
|
|
865
|
+
*/
|
|
866
|
+
interface PingEmission {
|
|
867
|
+
/** World-space ping position. */
|
|
868
|
+
readonly x: number;
|
|
869
|
+
readonly y: number;
|
|
870
|
+
readonly color: string;
|
|
871
|
+
readonly durationMs: number;
|
|
872
|
+
readonly radius: number;
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Tap or click to ping a world position: a short expanding-pulse animation is
|
|
876
|
+
* rendered locally and one `PingEmission` is delivered to `onPing` listeners
|
|
877
|
+
* per accepted tap. Pings are ephemeral by contract: they never create
|
|
878
|
+
* elements, enter undo history, or touch persisted canvas state — hosts
|
|
879
|
+
* forward emissions as presence only.
|
|
880
|
+
*/
|
|
881
|
+
declare class PingTool implements Tool {
|
|
882
|
+
readonly name: string;
|
|
883
|
+
private color;
|
|
884
|
+
private durationMs;
|
|
885
|
+
private radius;
|
|
886
|
+
private minIntervalMs;
|
|
887
|
+
private pings;
|
|
888
|
+
private lastEmitAt;
|
|
889
|
+
private rafId;
|
|
890
|
+
private optionListeners;
|
|
891
|
+
private pingListeners;
|
|
892
|
+
constructor(options?: PingToolOptions);
|
|
893
|
+
private now;
|
|
894
|
+
onActivate(ctx: ToolContext): void;
|
|
895
|
+
onDeactivate(ctx: ToolContext): void;
|
|
896
|
+
getOptions(): PingToolOptions;
|
|
897
|
+
setOptions(options: PingToolOptions): void;
|
|
898
|
+
onOptionsChange(listener: () => void): () => void;
|
|
899
|
+
/**
|
|
900
|
+
* Subscribes to accepted pings. Listeners must not throw; a throwing
|
|
901
|
+
* listener is isolated so it cannot break the tap handling or other
|
|
902
|
+
* listeners.
|
|
903
|
+
*/
|
|
904
|
+
onPing(listener: (emission: PingEmission) => void): () => void;
|
|
905
|
+
onPointerDown(state: PointerState, ctx: ToolContext): void;
|
|
906
|
+
onPointerMove(_state: PointerState, _ctx: ToolContext): void;
|
|
907
|
+
onPointerUp(_state: PointerState, _ctx: ToolContext): void;
|
|
908
|
+
renderOverlay(ctx: CanvasRenderingContext2D): void;
|
|
909
|
+
private ensureAnimating;
|
|
910
|
+
private tick;
|
|
911
|
+
private notifyOptionsChange;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* The wire shape of a map-ping presence payload. Presence data is untyped on
|
|
916
|
+
* the wire, so hosts discriminate on `kind`; `isPingPresence` validates a
|
|
917
|
+
* received payload before it reaches the overlay. Pings are ephemeral by
|
|
918
|
+
* contract: they must travel as presence only — never as elements, undo
|
|
919
|
+
* history, persisted canvas state, or durable operations.
|
|
920
|
+
*/
|
|
921
|
+
interface PingPresence {
|
|
922
|
+
readonly kind: 'ping';
|
|
923
|
+
/** World-space ping position. */
|
|
924
|
+
readonly x: number;
|
|
925
|
+
readonly y: number;
|
|
926
|
+
readonly color?: string;
|
|
927
|
+
readonly durationMs?: number;
|
|
928
|
+
readonly radius?: number;
|
|
929
|
+
}
|
|
930
|
+
declare const PING_PRESENCE_KIND = "ping";
|
|
931
|
+
declare function isPingPresence(data: unknown): data is PingPresence;
|
|
932
|
+
/** Builds the presence payload for one local `PingTool` emission. */
|
|
933
|
+
declare function toPingPresence(emission: PingEmission): PingPresence;
|
|
934
|
+
/**
|
|
935
|
+
* The two viewport capabilities the overlay needs; `Viewport` satisfies it.
|
|
936
|
+
*/
|
|
937
|
+
interface RemotePingOverlayHost {
|
|
938
|
+
registerOverlay(draw: OverlayRenderer): () => void;
|
|
939
|
+
requestRender(): void;
|
|
940
|
+
}
|
|
941
|
+
interface RemotePingOverlayOptions {
|
|
942
|
+
/** Style fallbacks when a payload omits them. */
|
|
943
|
+
color?: string;
|
|
944
|
+
durationMs?: number;
|
|
945
|
+
radius?: number;
|
|
946
|
+
/** Per-sender live-ping cap; oldest pings drop first. Default `8`. */
|
|
947
|
+
maxPingsPerSender?: number;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Renders expanding-pulse pings for remote senders through the viewport
|
|
951
|
+
* overlay registration, independent of the viewer's active tool. Pings are
|
|
952
|
+
* stamped with local receive time (remote clocks are never trusted),
|
|
953
|
+
* self-expire when their animation ends, and a sender's pings disappear
|
|
954
|
+
* immediately on `remove()` — wire that to `presence-leave`/disconnect. The
|
|
955
|
+
* controller never touches elements, history, or persisted state, and it
|
|
956
|
+
* never moves the viewer's camera: pings are visual only.
|
|
957
|
+
*/
|
|
958
|
+
declare class RemotePingOverlay {
|
|
959
|
+
private readonly host;
|
|
960
|
+
private readonly color;
|
|
961
|
+
private readonly durationMs;
|
|
962
|
+
private readonly radius;
|
|
963
|
+
private readonly maxPingsPerSender;
|
|
964
|
+
private readonly pings;
|
|
965
|
+
private unregister;
|
|
966
|
+
private rafId;
|
|
967
|
+
private disposed;
|
|
968
|
+
constructor(host: RemotePingOverlayHost, options?: RemotePingOverlayOptions);
|
|
969
|
+
private now;
|
|
970
|
+
/**
|
|
971
|
+
* Applies a presence payload from `sender` (any opaque per-sender key, e.g.
|
|
972
|
+
* the envelope `from`). Non-ping or malformed payloads are ignored and
|
|
973
|
+
* reported as `false`, so hosts can feed every presence frame through.
|
|
974
|
+
*/
|
|
975
|
+
apply(sender: string, data: unknown): boolean;
|
|
976
|
+
/** Removes a sender's pings immediately (presence-leave/disconnect). */
|
|
977
|
+
remove(sender: string): void;
|
|
978
|
+
/** Removes every ping immediately. */
|
|
979
|
+
clear(): void;
|
|
980
|
+
/** Number of senders with a live (unexpired) ping. */
|
|
981
|
+
get activeSenderCount(): number;
|
|
982
|
+
/** Unregisters the overlay and stops the animation loop. Idempotent. */
|
|
983
|
+
dispose(): void;
|
|
984
|
+
private ensureAnimating;
|
|
985
|
+
private tick;
|
|
986
|
+
private renderPings;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* The one camera capability `PingInput` needs; `Camera` satisfies it. Screen
|
|
991
|
+
* coordinates are element-local (the same space `Camera.screenToWorld`
|
|
992
|
+
* expects).
|
|
993
|
+
*/
|
|
994
|
+
interface PingInputHost {
|
|
995
|
+
screenToWorld(screen: Point): Point;
|
|
996
|
+
}
|
|
997
|
+
interface PingInputOptions {
|
|
998
|
+
/**
|
|
999
|
+
* Opt-in for the long-press gesture. Off by default: a hidden hold-to-ping
|
|
1000
|
+
* gesture surprises users outside shared-canvas products, so hosts enable
|
|
1001
|
+
* it deliberately. The keyboard/programmatic paths (`pingAtPointer`,
|
|
1002
|
+
* `pingAt`) are always available. Default `false`.
|
|
1003
|
+
*/
|
|
1004
|
+
longPressEnabled?: boolean;
|
|
1005
|
+
/** Hold duration before a still press pings. Default `600`. */
|
|
1006
|
+
longPressMs?: number;
|
|
1007
|
+
/** Maximum pointer travel while holding; moving further cancels. Default `8`. */
|
|
1008
|
+
slopPx?: number;
|
|
1009
|
+
/** Emission style forwarded to hosts; matches `PingTool` defaults. */
|
|
1010
|
+
color?: string;
|
|
1011
|
+
durationMs?: number;
|
|
1012
|
+
radius?: number;
|
|
1013
|
+
/**
|
|
1014
|
+
* Minimum interval between emitted pings, shared across the long-press and
|
|
1015
|
+
* keyboard/programmatic paths. Faster pings are dropped entirely. Default
|
|
1016
|
+
* `300`.
|
|
1017
|
+
*/
|
|
1018
|
+
minIntervalMs?: number;
|
|
1019
|
+
/**
|
|
1020
|
+
* Host veto consulted at fire time on every path (e.g. return `false` while
|
|
1021
|
+
* a ping tool is active to avoid double pings). A veto does not consume the
|
|
1022
|
+
* rate-limit interval.
|
|
1023
|
+
*/
|
|
1024
|
+
shouldPing?: () => boolean;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Always-available ping input alongside the active tool: long-press-to-ping
|
|
1028
|
+
* plus keyboard/programmatic pings, independent of `PingTool`.
|
|
1029
|
+
*
|
|
1030
|
+
* `PingInput` is a passive observer by contract. Its DOM pointer listeners are
|
|
1031
|
+
* registered `passive: true` and it never calls `preventDefault`,
|
|
1032
|
+
* `stopPropagation`, or captures pointers, so the active tool, panning, and
|
|
1033
|
+
* pinch navigation behave exactly as if it were absent (with a pencil active,
|
|
1034
|
+
* a still hold pings AND the pencil still draws its dot). It also never
|
|
1035
|
+
* renders: hosts feed emissions into their own `RemotePingOverlay` under a
|
|
1036
|
+
* `'self'` sender key. Pings are ephemeral — no elements, no undo history, no
|
|
1037
|
+
* persisted state, no camera movement.
|
|
1038
|
+
*
|
|
1039
|
+
* The long-press gesture is opt-in via `longPressEnabled` (hosts whose users
|
|
1040
|
+
* would not expect hold-to-ping simply leave it off and keep the keyboard
|
|
1041
|
+
* paths). When enabled, a long-press arms on the first pointer down (mouse
|
|
1042
|
+
* primary button, touch, or pen), fires after `longPressMs` at the original
|
|
1043
|
+
* press position, and
|
|
1044
|
+
* cancels on movement past `slopPx`, a second pointer (two-finger
|
|
1045
|
+
* navigation), or pointer up/cancel/leave. Keyboard support is a capability,
|
|
1046
|
+
* not a binding: hosts call `pingAtPointer()` (last tracked hover position,
|
|
1047
|
+
* world-converted at call time) or `pingAt(world)` from their own shortcut
|
|
1048
|
+
* handling.
|
|
1049
|
+
*/
|
|
1050
|
+
declare class PingInput {
|
|
1051
|
+
private readonly element;
|
|
1052
|
+
private readonly host;
|
|
1053
|
+
private longPressEnabled;
|
|
1054
|
+
private longPressMs;
|
|
1055
|
+
private slopPx;
|
|
1056
|
+
private color;
|
|
1057
|
+
private durationMs;
|
|
1058
|
+
private radius;
|
|
1059
|
+
private minIntervalMs;
|
|
1060
|
+
private shouldPing;
|
|
1061
|
+
private press;
|
|
1062
|
+
private readonly downPointers;
|
|
1063
|
+
private lastPointerScreen;
|
|
1064
|
+
private lastEmitAt;
|
|
1065
|
+
private disposed;
|
|
1066
|
+
private optionListeners;
|
|
1067
|
+
private pingListeners;
|
|
1068
|
+
private readonly handlePointerDown;
|
|
1069
|
+
private readonly handlePointerMove;
|
|
1070
|
+
private readonly handlePointerUp;
|
|
1071
|
+
private readonly handlePointerCancel;
|
|
1072
|
+
private readonly handlePointerLeave;
|
|
1073
|
+
constructor(element: HTMLElement, host: PingInputHost, options?: PingInputOptions);
|
|
1074
|
+
private now;
|
|
1075
|
+
getOptions(): PingInputOptions;
|
|
1076
|
+
setOptions(options: PingInputOptions): void;
|
|
1077
|
+
onOptionsChange(listener: () => void): () => void;
|
|
1078
|
+
/**
|
|
1079
|
+
* Subscribes to emitted pings. Listeners must not throw; a throwing
|
|
1080
|
+
* listener is isolated so it cannot break input handling or other
|
|
1081
|
+
* listeners.
|
|
1082
|
+
*/
|
|
1083
|
+
onPing(listener: (emission: PingEmission) => void): () => void;
|
|
1084
|
+
/**
|
|
1085
|
+
* Pings at the last tracked pointer position (hover moves and presses),
|
|
1086
|
+
* world-converted at call time. Returns `false` when no pointer has been
|
|
1087
|
+
* seen yet, the host vetoes, or the rate limit drops the ping.
|
|
1088
|
+
*/
|
|
1089
|
+
pingAtPointer(): boolean;
|
|
1090
|
+
/** Pings a world position directly. Same veto and rate limit as every path. */
|
|
1091
|
+
pingAt(world: Point): boolean;
|
|
1092
|
+
/** Removes all DOM listeners and cancels any pending press. Idempotent. */
|
|
1093
|
+
dispose(): void;
|
|
1094
|
+
private toLocal;
|
|
1095
|
+
private onPointerDown;
|
|
1096
|
+
private onPointerMove;
|
|
1097
|
+
private onPointerEnd;
|
|
1098
|
+
private cancelPress;
|
|
1099
|
+
private firePress;
|
|
1100
|
+
private emit;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
847
1103
|
interface ActiveFormats {
|
|
848
1104
|
bold: boolean;
|
|
849
1105
|
italic: boolean;
|
|
@@ -1282,6 +1538,6 @@ declare class TemplateTool implements Tool {
|
|
|
1282
1538
|
private notifyOptionsChange;
|
|
1283
1539
|
}
|
|
1284
1540
|
|
|
1285
|
-
declare const VERSION = "0.
|
|
1541
|
+
declare const VERSION = "0.56.0";
|
|
1286
1542
|
|
|
1287
|
-
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, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, 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, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1543
|
+
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, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, 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, 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, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.d.ts
CHANGED
|
@@ -249,7 +249,7 @@ interface Tool {
|
|
|
249
249
|
setOptions?(options: object): void;
|
|
250
250
|
onOptionsChange?(listener: () => void): () => void;
|
|
251
251
|
}
|
|
252
|
-
type ToolName = 'hand' | 'select' | 'pencil' | 'eraser' | 'arrow' | 'note' | 'image' | 'text' | 'shape' | 'measure' | 'template' | 'laser';
|
|
252
|
+
type ToolName = 'hand' | 'select' | 'pencil' | 'eraser' | 'arrow' | 'note' | 'image' | 'text' | 'shape' | 'measure' | 'template' | 'laser' | 'ping';
|
|
253
253
|
|
|
254
254
|
declare function snapPoint(point: Point, gridSize: number): Point;
|
|
255
255
|
declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
|
|
@@ -844,6 +844,262 @@ declare class RemoteLaserOverlay {
|
|
|
844
844
|
private renderTrails;
|
|
845
845
|
}
|
|
846
846
|
|
|
847
|
+
interface PingToolOptions {
|
|
848
|
+
name?: string;
|
|
849
|
+
color?: string;
|
|
850
|
+
/** Total pulse animation length in milliseconds. */
|
|
851
|
+
durationMs?: number;
|
|
852
|
+
/** Maximum ripple radius in world units. */
|
|
853
|
+
radius?: number;
|
|
854
|
+
/**
|
|
855
|
+
* Minimum interval between emitted pings. Taps arriving faster are ignored
|
|
856
|
+
* entirely (no local pulse, no emission), so rapid-fire pings cannot starve
|
|
857
|
+
* durable sync traffic.
|
|
858
|
+
*/
|
|
859
|
+
minIntervalMs?: number;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* One emitted ping — the outgoing side of a shared "look here" marker.
|
|
863
|
+
* Emissions carry the world position and the tool's current style so a host
|
|
864
|
+
* can forward them as ephemeral presence without duplicating input handling.
|
|
865
|
+
*/
|
|
866
|
+
interface PingEmission {
|
|
867
|
+
/** World-space ping position. */
|
|
868
|
+
readonly x: number;
|
|
869
|
+
readonly y: number;
|
|
870
|
+
readonly color: string;
|
|
871
|
+
readonly durationMs: number;
|
|
872
|
+
readonly radius: number;
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Tap or click to ping a world position: a short expanding-pulse animation is
|
|
876
|
+
* rendered locally and one `PingEmission` is delivered to `onPing` listeners
|
|
877
|
+
* per accepted tap. Pings are ephemeral by contract: they never create
|
|
878
|
+
* elements, enter undo history, or touch persisted canvas state — hosts
|
|
879
|
+
* forward emissions as presence only.
|
|
880
|
+
*/
|
|
881
|
+
declare class PingTool implements Tool {
|
|
882
|
+
readonly name: string;
|
|
883
|
+
private color;
|
|
884
|
+
private durationMs;
|
|
885
|
+
private radius;
|
|
886
|
+
private minIntervalMs;
|
|
887
|
+
private pings;
|
|
888
|
+
private lastEmitAt;
|
|
889
|
+
private rafId;
|
|
890
|
+
private optionListeners;
|
|
891
|
+
private pingListeners;
|
|
892
|
+
constructor(options?: PingToolOptions);
|
|
893
|
+
private now;
|
|
894
|
+
onActivate(ctx: ToolContext): void;
|
|
895
|
+
onDeactivate(ctx: ToolContext): void;
|
|
896
|
+
getOptions(): PingToolOptions;
|
|
897
|
+
setOptions(options: PingToolOptions): void;
|
|
898
|
+
onOptionsChange(listener: () => void): () => void;
|
|
899
|
+
/**
|
|
900
|
+
* Subscribes to accepted pings. Listeners must not throw; a throwing
|
|
901
|
+
* listener is isolated so it cannot break the tap handling or other
|
|
902
|
+
* listeners.
|
|
903
|
+
*/
|
|
904
|
+
onPing(listener: (emission: PingEmission) => void): () => void;
|
|
905
|
+
onPointerDown(state: PointerState, ctx: ToolContext): void;
|
|
906
|
+
onPointerMove(_state: PointerState, _ctx: ToolContext): void;
|
|
907
|
+
onPointerUp(_state: PointerState, _ctx: ToolContext): void;
|
|
908
|
+
renderOverlay(ctx: CanvasRenderingContext2D): void;
|
|
909
|
+
private ensureAnimating;
|
|
910
|
+
private tick;
|
|
911
|
+
private notifyOptionsChange;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* The wire shape of a map-ping presence payload. Presence data is untyped on
|
|
916
|
+
* the wire, so hosts discriminate on `kind`; `isPingPresence` validates a
|
|
917
|
+
* received payload before it reaches the overlay. Pings are ephemeral by
|
|
918
|
+
* contract: they must travel as presence only — never as elements, undo
|
|
919
|
+
* history, persisted canvas state, or durable operations.
|
|
920
|
+
*/
|
|
921
|
+
interface PingPresence {
|
|
922
|
+
readonly kind: 'ping';
|
|
923
|
+
/** World-space ping position. */
|
|
924
|
+
readonly x: number;
|
|
925
|
+
readonly y: number;
|
|
926
|
+
readonly color?: string;
|
|
927
|
+
readonly durationMs?: number;
|
|
928
|
+
readonly radius?: number;
|
|
929
|
+
}
|
|
930
|
+
declare const PING_PRESENCE_KIND = "ping";
|
|
931
|
+
declare function isPingPresence(data: unknown): data is PingPresence;
|
|
932
|
+
/** Builds the presence payload for one local `PingTool` emission. */
|
|
933
|
+
declare function toPingPresence(emission: PingEmission): PingPresence;
|
|
934
|
+
/**
|
|
935
|
+
* The two viewport capabilities the overlay needs; `Viewport` satisfies it.
|
|
936
|
+
*/
|
|
937
|
+
interface RemotePingOverlayHost {
|
|
938
|
+
registerOverlay(draw: OverlayRenderer): () => void;
|
|
939
|
+
requestRender(): void;
|
|
940
|
+
}
|
|
941
|
+
interface RemotePingOverlayOptions {
|
|
942
|
+
/** Style fallbacks when a payload omits them. */
|
|
943
|
+
color?: string;
|
|
944
|
+
durationMs?: number;
|
|
945
|
+
radius?: number;
|
|
946
|
+
/** Per-sender live-ping cap; oldest pings drop first. Default `8`. */
|
|
947
|
+
maxPingsPerSender?: number;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Renders expanding-pulse pings for remote senders through the viewport
|
|
951
|
+
* overlay registration, independent of the viewer's active tool. Pings are
|
|
952
|
+
* stamped with local receive time (remote clocks are never trusted),
|
|
953
|
+
* self-expire when their animation ends, and a sender's pings disappear
|
|
954
|
+
* immediately on `remove()` — wire that to `presence-leave`/disconnect. The
|
|
955
|
+
* controller never touches elements, history, or persisted state, and it
|
|
956
|
+
* never moves the viewer's camera: pings are visual only.
|
|
957
|
+
*/
|
|
958
|
+
declare class RemotePingOverlay {
|
|
959
|
+
private readonly host;
|
|
960
|
+
private readonly color;
|
|
961
|
+
private readonly durationMs;
|
|
962
|
+
private readonly radius;
|
|
963
|
+
private readonly maxPingsPerSender;
|
|
964
|
+
private readonly pings;
|
|
965
|
+
private unregister;
|
|
966
|
+
private rafId;
|
|
967
|
+
private disposed;
|
|
968
|
+
constructor(host: RemotePingOverlayHost, options?: RemotePingOverlayOptions);
|
|
969
|
+
private now;
|
|
970
|
+
/**
|
|
971
|
+
* Applies a presence payload from `sender` (any opaque per-sender key, e.g.
|
|
972
|
+
* the envelope `from`). Non-ping or malformed payloads are ignored and
|
|
973
|
+
* reported as `false`, so hosts can feed every presence frame through.
|
|
974
|
+
*/
|
|
975
|
+
apply(sender: string, data: unknown): boolean;
|
|
976
|
+
/** Removes a sender's pings immediately (presence-leave/disconnect). */
|
|
977
|
+
remove(sender: string): void;
|
|
978
|
+
/** Removes every ping immediately. */
|
|
979
|
+
clear(): void;
|
|
980
|
+
/** Number of senders with a live (unexpired) ping. */
|
|
981
|
+
get activeSenderCount(): number;
|
|
982
|
+
/** Unregisters the overlay and stops the animation loop. Idempotent. */
|
|
983
|
+
dispose(): void;
|
|
984
|
+
private ensureAnimating;
|
|
985
|
+
private tick;
|
|
986
|
+
private renderPings;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* The one camera capability `PingInput` needs; `Camera` satisfies it. Screen
|
|
991
|
+
* coordinates are element-local (the same space `Camera.screenToWorld`
|
|
992
|
+
* expects).
|
|
993
|
+
*/
|
|
994
|
+
interface PingInputHost {
|
|
995
|
+
screenToWorld(screen: Point): Point;
|
|
996
|
+
}
|
|
997
|
+
interface PingInputOptions {
|
|
998
|
+
/**
|
|
999
|
+
* Opt-in for the long-press gesture. Off by default: a hidden hold-to-ping
|
|
1000
|
+
* gesture surprises users outside shared-canvas products, so hosts enable
|
|
1001
|
+
* it deliberately. The keyboard/programmatic paths (`pingAtPointer`,
|
|
1002
|
+
* `pingAt`) are always available. Default `false`.
|
|
1003
|
+
*/
|
|
1004
|
+
longPressEnabled?: boolean;
|
|
1005
|
+
/** Hold duration before a still press pings. Default `600`. */
|
|
1006
|
+
longPressMs?: number;
|
|
1007
|
+
/** Maximum pointer travel while holding; moving further cancels. Default `8`. */
|
|
1008
|
+
slopPx?: number;
|
|
1009
|
+
/** Emission style forwarded to hosts; matches `PingTool` defaults. */
|
|
1010
|
+
color?: string;
|
|
1011
|
+
durationMs?: number;
|
|
1012
|
+
radius?: number;
|
|
1013
|
+
/**
|
|
1014
|
+
* Minimum interval between emitted pings, shared across the long-press and
|
|
1015
|
+
* keyboard/programmatic paths. Faster pings are dropped entirely. Default
|
|
1016
|
+
* `300`.
|
|
1017
|
+
*/
|
|
1018
|
+
minIntervalMs?: number;
|
|
1019
|
+
/**
|
|
1020
|
+
* Host veto consulted at fire time on every path (e.g. return `false` while
|
|
1021
|
+
* a ping tool is active to avoid double pings). A veto does not consume the
|
|
1022
|
+
* rate-limit interval.
|
|
1023
|
+
*/
|
|
1024
|
+
shouldPing?: () => boolean;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Always-available ping input alongside the active tool: long-press-to-ping
|
|
1028
|
+
* plus keyboard/programmatic pings, independent of `PingTool`.
|
|
1029
|
+
*
|
|
1030
|
+
* `PingInput` is a passive observer by contract. Its DOM pointer listeners are
|
|
1031
|
+
* registered `passive: true` and it never calls `preventDefault`,
|
|
1032
|
+
* `stopPropagation`, or captures pointers, so the active tool, panning, and
|
|
1033
|
+
* pinch navigation behave exactly as if it were absent (with a pencil active,
|
|
1034
|
+
* a still hold pings AND the pencil still draws its dot). It also never
|
|
1035
|
+
* renders: hosts feed emissions into their own `RemotePingOverlay` under a
|
|
1036
|
+
* `'self'` sender key. Pings are ephemeral — no elements, no undo history, no
|
|
1037
|
+
* persisted state, no camera movement.
|
|
1038
|
+
*
|
|
1039
|
+
* The long-press gesture is opt-in via `longPressEnabled` (hosts whose users
|
|
1040
|
+
* would not expect hold-to-ping simply leave it off and keep the keyboard
|
|
1041
|
+
* paths). When enabled, a long-press arms on the first pointer down (mouse
|
|
1042
|
+
* primary button, touch, or pen), fires after `longPressMs` at the original
|
|
1043
|
+
* press position, and
|
|
1044
|
+
* cancels on movement past `slopPx`, a second pointer (two-finger
|
|
1045
|
+
* navigation), or pointer up/cancel/leave. Keyboard support is a capability,
|
|
1046
|
+
* not a binding: hosts call `pingAtPointer()` (last tracked hover position,
|
|
1047
|
+
* world-converted at call time) or `pingAt(world)` from their own shortcut
|
|
1048
|
+
* handling.
|
|
1049
|
+
*/
|
|
1050
|
+
declare class PingInput {
|
|
1051
|
+
private readonly element;
|
|
1052
|
+
private readonly host;
|
|
1053
|
+
private longPressEnabled;
|
|
1054
|
+
private longPressMs;
|
|
1055
|
+
private slopPx;
|
|
1056
|
+
private color;
|
|
1057
|
+
private durationMs;
|
|
1058
|
+
private radius;
|
|
1059
|
+
private minIntervalMs;
|
|
1060
|
+
private shouldPing;
|
|
1061
|
+
private press;
|
|
1062
|
+
private readonly downPointers;
|
|
1063
|
+
private lastPointerScreen;
|
|
1064
|
+
private lastEmitAt;
|
|
1065
|
+
private disposed;
|
|
1066
|
+
private optionListeners;
|
|
1067
|
+
private pingListeners;
|
|
1068
|
+
private readonly handlePointerDown;
|
|
1069
|
+
private readonly handlePointerMove;
|
|
1070
|
+
private readonly handlePointerUp;
|
|
1071
|
+
private readonly handlePointerCancel;
|
|
1072
|
+
private readonly handlePointerLeave;
|
|
1073
|
+
constructor(element: HTMLElement, host: PingInputHost, options?: PingInputOptions);
|
|
1074
|
+
private now;
|
|
1075
|
+
getOptions(): PingInputOptions;
|
|
1076
|
+
setOptions(options: PingInputOptions): void;
|
|
1077
|
+
onOptionsChange(listener: () => void): () => void;
|
|
1078
|
+
/**
|
|
1079
|
+
* Subscribes to emitted pings. Listeners must not throw; a throwing
|
|
1080
|
+
* listener is isolated so it cannot break input handling or other
|
|
1081
|
+
* listeners.
|
|
1082
|
+
*/
|
|
1083
|
+
onPing(listener: (emission: PingEmission) => void): () => void;
|
|
1084
|
+
/**
|
|
1085
|
+
* Pings at the last tracked pointer position (hover moves and presses),
|
|
1086
|
+
* world-converted at call time. Returns `false` when no pointer has been
|
|
1087
|
+
* seen yet, the host vetoes, or the rate limit drops the ping.
|
|
1088
|
+
*/
|
|
1089
|
+
pingAtPointer(): boolean;
|
|
1090
|
+
/** Pings a world position directly. Same veto and rate limit as every path. */
|
|
1091
|
+
pingAt(world: Point): boolean;
|
|
1092
|
+
/** Removes all DOM listeners and cancels any pending press. Idempotent. */
|
|
1093
|
+
dispose(): void;
|
|
1094
|
+
private toLocal;
|
|
1095
|
+
private onPointerDown;
|
|
1096
|
+
private onPointerMove;
|
|
1097
|
+
private onPointerEnd;
|
|
1098
|
+
private cancelPress;
|
|
1099
|
+
private firePress;
|
|
1100
|
+
private emit;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
847
1103
|
interface ActiveFormats {
|
|
848
1104
|
bold: boolean;
|
|
849
1105
|
italic: boolean;
|
|
@@ -1282,6 +1538,6 @@ declare class TemplateTool implements Tool {
|
|
|
1282
1538
|
private notifyOptionsChange;
|
|
1283
1539
|
}
|
|
1284
1540
|
|
|
1285
|
-
declare const VERSION = "0.
|
|
1541
|
+
declare const VERSION = "0.56.0";
|
|
1286
1542
|
|
|
1287
|
-
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, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, type OverlayRenderer, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoteLaserOverlay, type RemoteLaserOverlayHost, type RemoteLaserOverlayOptions, 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, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1543
|
+
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, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, 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, 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, isNearBezier, isPingPresence, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toLaserTrailPresence, toPingPresence, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|