@oh-just-another/state 0.59.0 → 0.61.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/CHANGELOG.md +189 -0
- package/README.md +6 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/actions/actionArrange.js +4 -4
- package/dist/actions/actionArrange.js.map +1 -1
- package/dist/actions/actionClipboard.d.ts.map +1 -1
- package/dist/actions/actionClipboard.js +5 -0
- package/dist/actions/actionClipboard.js.map +1 -1
- package/dist/actions/actionKeyboard.d.ts.map +1 -1
- package/dist/actions/actionKeyboard.js +79 -11
- package/dist/actions/actionKeyboard.js.map +1 -1
- package/dist/actions/actionMode.d.ts +2 -0
- package/dist/actions/actionMode.d.ts.map +1 -1
- package/dist/actions/actionMode.js +81 -27
- package/dist/actions/actionMode.js.map +1 -1
- package/dist/actions/actionSelection.d.ts.map +1 -1
- package/dist/actions/actionSelection.js +1 -0
- package/dist/actions/actionSelection.js.map +1 -1
- package/dist/actions/actionView.d.ts +6 -0
- package/dist/actions/actionView.d.ts.map +1 -1
- package/dist/actions/actionView.js +19 -1
- package/dist/actions/actionView.js.map +1 -1
- package/dist/actions/actionZoom.d.ts.map +1 -1
- package/dist/actions/actionZoom.js +5 -0
- package/dist/actions/actionZoom.js.map +1 -1
- package/dist/actions/index.d.ts +3 -3
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +3 -3
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/registry.d.ts.map +1 -1
- package/dist/actions/registry.js +13 -0
- package/dist/actions/registry.js.map +1 -1
- package/dist/actions/types.d.ts +10 -1
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js.map +1 -1
- package/dist/built-in-handlers.d.ts +8 -0
- package/dist/built-in-handlers.d.ts.map +1 -1
- package/dist/built-in-handlers.js +31 -16
- package/dist/built-in-handlers.js.map +1 -1
- package/dist/clipboard.d.ts +0 -14
- package/dist/clipboard.d.ts.map +1 -1
- package/dist/clipboard.js +1 -1
- package/dist/clipboard.js.map +1 -1
- package/dist/constants.d.ts +253 -18
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +255 -2
- package/dist/constants.js.map +1 -1
- package/dist/dom-events.d.ts +1 -2
- package/dist/dom-events.d.ts.map +1 -1
- package/dist/dom-events.js.map +1 -1
- package/dist/editor/animation-scene.d.ts +15 -0
- package/dist/editor/animation-scene.d.ts.map +1 -1
- package/dist/editor/animation-scene.js +159 -0
- package/dist/editor/animation-scene.js.map +1 -1
- package/dist/editor/applies/create.d.ts +0 -6
- package/dist/editor/applies/create.d.ts.map +1 -1
- package/dist/editor/applies/create.js +1 -1
- package/dist/editor/applies/create.js.map +1 -1
- package/dist/editor/applies/link-move.d.ts +0 -8
- package/dist/editor/applies/link-move.d.ts.map +1 -1
- package/dist/editor/applies/link-move.js +1 -1
- package/dist/editor/applies/link-move.js.map +1 -1
- package/dist/editor/event-fanout.d.ts +6 -6
- package/dist/editor/event-fanout.d.ts.map +1 -1
- package/dist/editor/event-fanout.js +8 -8
- package/dist/editor/event-fanout.js.map +1 -1
- package/dist/editor/hit-test.d.ts +8 -0
- package/dist/editor/hit-test.d.ts.map +1 -1
- package/dist/editor/hit-test.js +31 -16
- package/dist/editor/hit-test.js.map +1 -1
- package/dist/editor/interaction-state.d.ts +184 -0
- package/dist/editor/interaction-state.d.ts.map +1 -0
- package/dist/editor/interaction-state.js +139 -0
- package/dist/editor/interaction-state.js.map +1 -0
- package/dist/editor/link-handle-drag.d.ts +172 -0
- package/dist/editor/link-handle-drag.d.ts.map +1 -0
- package/dist/editor/link-handle-drag.js +369 -0
- package/dist/editor/link-handle-drag.js.map +1 -0
- package/dist/editor/pointer-binding.d.ts +9 -11
- package/dist/editor/pointer-binding.d.ts.map +1 -1
- package/dist/editor/pointer-binding.js +1247 -909
- package/dist/editor/pointer-binding.js.map +1 -1
- package/dist/editor/public/brush.d.ts +93 -13
- package/dist/editor/public/brush.d.ts.map +1 -1
- package/dist/editor/public/brush.js +240 -22
- package/dist/editor/public/brush.js.map +1 -1
- package/dist/editor/public/cursor.d.ts +1 -15
- package/dist/editor/public/cursor.d.ts.map +1 -1
- package/dist/editor/public/cursor.js +17 -7
- package/dist/editor/public/cursor.js.map +1 -1
- package/dist/editor/public/eraser.d.ts +55 -0
- package/dist/editor/public/eraser.d.ts.map +1 -0
- package/dist/editor/public/eraser.js +65 -0
- package/dist/editor/public/eraser.js.map +1 -0
- package/dist/editor/public/laser.d.ts +38 -0
- package/dist/editor/public/laser.d.ts.map +1 -0
- package/dist/editor/public/laser.js +42 -0
- package/dist/editor/public/laser.js.map +1 -0
- package/dist/editor/public/placement.d.ts.map +1 -1
- package/dist/editor/public/placement.js +9 -1
- package/dist/editor/public/placement.js.map +1 -1
- package/dist/editor/public/selection-ops.d.ts +12 -0
- package/dist/editor/public/selection-ops.d.ts.map +1 -1
- package/dist/editor/public/selection-ops.js +19 -1
- package/dist/editor/public/selection-ops.js.map +1 -1
- package/dist/editor/public/stroke-eraser-coverage.d.ts +37 -0
- package/dist/editor/public/stroke-eraser-coverage.d.ts.map +1 -0
- package/dist/editor/public/stroke-eraser-coverage.js +168 -0
- package/dist/editor/public/stroke-eraser-coverage.js.map +1 -0
- package/dist/editor/public/stroke-eraser.d.ts +50 -0
- package/dist/editor/public/stroke-eraser.d.ts.map +1 -0
- package/dist/editor/public/stroke-eraser.js +176 -0
- package/dist/editor/public/stroke-eraser.js.map +1 -0
- package/dist/editor/public/stroke-smoothing.d.ts +21 -0
- package/dist/editor/public/stroke-smoothing.d.ts.map +1 -0
- package/dist/editor/public/stroke-smoothing.js +37 -0
- package/dist/editor/public/stroke-smoothing.js.map +1 -0
- package/dist/editor/public/tool-ops.d.ts +130 -0
- package/dist/editor/public/tool-ops.d.ts.map +1 -0
- package/dist/editor/public/tool-ops.js +392 -0
- package/dist/editor/public/tool-ops.js.map +1 -0
- package/dist/editor/public/z-order.d.ts +1 -12
- package/dist/editor/public/z-order.d.ts.map +1 -1
- package/dist/editor/public/z-order.js +1 -1
- package/dist/editor/public/z-order.js.map +1 -1
- package/dist/editor/public/zoom-pan.d.ts +9 -0
- package/dist/editor/public/zoom-pan.d.ts.map +1 -1
- package/dist/editor/public/zoom-pan.js +31 -0
- package/dist/editor/public/zoom-pan.js.map +1 -1
- package/dist/editor/render-orchestrator.d.ts +180 -5
- package/dist/editor/render-orchestrator.d.ts.map +1 -1
- package/dist/editor/render-orchestrator.js +516 -353
- package/dist/editor/render-orchestrator.js.map +1 -1
- package/dist/editor/text-edit.d.ts +136 -0
- package/dist/editor/text-edit.d.ts.map +1 -0
- package/dist/editor/text-edit.js +328 -0
- package/dist/editor/text-edit.js.map +1 -0
- package/dist/editor-events.d.ts +5 -5
- package/dist/editor-events.d.ts.map +1 -1
- package/dist/editor.d.ts +560 -250
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1650 -743
- package/dist/editor.js.map +1 -1
- package/dist/handle.d.ts +0 -2
- package/dist/handle.d.ts.map +1 -1
- package/dist/handle.js +0 -6
- package/dist/handle.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/modes.d.ts +34 -1
- package/dist/modes.d.ts.map +1 -1
- package/dist/modes.js.map +1 -1
- package/dist/overlay.d.ts +98 -21
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +442 -116
- package/dist/overlay.js.map +1 -1
- package/dist/search.d.ts +37 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +45 -0
- package/dist/search.js.map +1 -0
- package/package.json +5 -4
package/dist/editor.d.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { type Actor } from "xstate";
|
|
2
2
|
import type { Bounds, FileId, ElementId, Vec2 } from "@oh-just-another/types";
|
|
3
3
|
import type { SpatialGrid } from "@oh-just-another/scene";
|
|
4
|
-
import { type FractionalIndex, type BrushPoint, type Link, type Patch, type Scene, type Element, type GridStyle, type TextStyle } from "@oh-just-another/scene";
|
|
5
|
-
import { type AnnotationId, type CommentId, type LinkId, type LayerId } from "@oh-just-another/types";
|
|
4
|
+
import { type FractionalIndex, type BrushPoint, type Link, type Patch, type Scene, type Element, type GridStyle, type ImageCrop, type TextStyle } from "@oh-just-another/scene";
|
|
5
|
+
import { type AnnotationId, type Color, type CommentId, type LinkId, type LayerId } from "@oh-just-another/types";
|
|
6
6
|
import { ElementCache, type RenderTarget, type TextShaper, type Rasterizer } from "@oh-just-another/renderer-core";
|
|
7
7
|
import { type HistoryOptions, type HistoryProvider, type TransactionHandle } from "@oh-just-another/history";
|
|
8
8
|
import { type FileDropHandler } from "./file-drop.js";
|
|
9
9
|
import { interactionMachine, type InteractionContext, type InteractionEmit, type PressTarget } from "./machine.js";
|
|
10
|
-
import type { Mode } from "./modes.js";
|
|
10
|
+
import type { ActiveTool, Mode } from "./modes.js";
|
|
11
11
|
import type { EditorEvents } from "./editor-events.js";
|
|
12
12
|
import { GifPlaybackController } from "./editor/gif-playback.js";
|
|
13
13
|
import { LongPressController } from "./editor/long-press.js";
|
|
14
14
|
import { PinchController } from "./editor/pinch.js";
|
|
15
|
-
import { type
|
|
15
|
+
import { InteractionState, type AnnotationDrag, type ContainerHover, type EdgePreview, type GroupResizeOrigin, type HoveredLinkTarget, type LinkDragFromAnchor, type PanGesture, type RotateGestureOrigin } from "./editor/interaction-state.js";
|
|
16
|
+
import { type BrushSettings, type BrushStrokeState } from "./editor/public/brush.js";
|
|
17
|
+
import { type EraseStrokeState } from "./editor/public/eraser.js";
|
|
18
|
+
import { type LaserStroke } from "./editor/public/laser.js";
|
|
16
19
|
import type { CursorRole, CursorSpec } from "./editor/public/cursor.js";
|
|
20
|
+
import { type ConvertTarget, type CropHandle, type SpawnDirection } from "./editor/public/tool-ops.js";
|
|
17
21
|
import { type AlignEdge, type DistributeAxis, type FlipAxis } from "./editor/applies/arrange.js";
|
|
18
22
|
import { type PeerCursor, type PeerSelection } from "./overlay.js";
|
|
19
23
|
import * as Selection from "./selection.js";
|
|
@@ -52,7 +56,14 @@ export interface EditorOptions {
|
|
|
52
56
|
*/
|
|
53
57
|
readonly onAfterRender?: () => void;
|
|
54
58
|
readonly initialScene: Scene;
|
|
55
|
-
readonly
|
|
59
|
+
readonly initialTool?: Mode;
|
|
60
|
+
/**
|
|
61
|
+
* Start the editor in read-only / view mode. Pointer edits (create /
|
|
62
|
+
* move / resize / rotate / delete) and non-`viewMode` actions are gated;
|
|
63
|
+
* pan / zoom / select still work. Toggle at runtime via
|
|
64
|
+
* {@link Editor.setReadOnly}. Defaults to `false`.
|
|
65
|
+
*/
|
|
66
|
+
readonly readOnly?: boolean;
|
|
56
67
|
/**
|
|
57
68
|
* Pre-existing history backend, or options for the default
|
|
58
69
|
* `History` (linear stack). Any `HistoryProvider` implementation
|
|
@@ -127,6 +138,21 @@ export type TileComposeFn = (scene: Scene, mainTarget: RenderTarget, options: {
|
|
|
127
138
|
after: Bounds | null;
|
|
128
139
|
}>;
|
|
129
140
|
readonly zoomBucket: number;
|
|
141
|
+
/**
|
|
142
|
+
* Elements omitted from tile rasterisation (stroke-eraser preview and
|
|
143
|
+
* per-element hide). The compositor invalidates the tiles an element
|
|
144
|
+
* touches when it enters/leaves the set.
|
|
145
|
+
*/
|
|
146
|
+
readonly hideElements?: ReadonlySet<ElementId>;
|
|
147
|
+
/**
|
|
148
|
+
* Persistent spatial index over the scene's current element world-AABBs,
|
|
149
|
+
* when the editor maintains one (large scenes, shared with the hit-test
|
|
150
|
+
* path). A tile compositor that supports it (`renderViaTiles`) queries the
|
|
151
|
+
* index for per-tile element selection instead of scanning every shape in
|
|
152
|
+
* every layer. Omitted for small scenes; compositors must fall back to a
|
|
153
|
+
* full scan when absent.
|
|
154
|
+
*/
|
|
155
|
+
readonly index?: SpatialGrid;
|
|
130
156
|
}) => void;
|
|
131
157
|
/**
|
|
132
158
|
* Top-level interaction controller. Owns the scene + selection state, wires
|
|
@@ -155,7 +181,15 @@ export declare class Editor {
|
|
|
155
181
|
* View-only — never persisted or recorded in history.
|
|
156
182
|
*/
|
|
157
183
|
debugHitZones: boolean;
|
|
158
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Read-only / view mode. When true the pointer paths that create,
|
|
186
|
+
* move, resize, rotate or delete are gated (pan / zoom / select stay
|
|
187
|
+
* live) and the action registry only runs actions flagged
|
|
188
|
+
* `viewMode`. View-only — never persisted or recorded in history.
|
|
189
|
+
* Read via {@link readOnly}; flip via {@link setReadOnly}.
|
|
190
|
+
*/
|
|
191
|
+
private _readOnly;
|
|
192
|
+
actor: Actor<typeof interactionMachine>;
|
|
159
193
|
private readonly listeners;
|
|
160
194
|
/**
|
|
161
195
|
* Typed event surface. Specific events (`mode`, `selection`,
|
|
@@ -178,74 +212,31 @@ export declare class Editor {
|
|
|
178
212
|
_scene: Scene;
|
|
179
213
|
_selection: Selection.Selection;
|
|
180
214
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
215
|
+
* Ephemeral interaction / gesture state (previews, gesture origins,
|
|
216
|
+
* transient modifiers). Single source of truth for the short-lived fields
|
|
217
|
+
* the pointer handlers, render orchestrator and container-ops read/write
|
|
218
|
+
* while a gesture is in flight. The public fields below delegate to it so
|
|
219
|
+
* external writers keep referencing `editor.<field>` unchanged.
|
|
185
220
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
moved: boolean;
|
|
191
|
-
} | null;
|
|
221
|
+
readonly interaction: InteractionState;
|
|
222
|
+
/** Snapshot of an in-progress annotation-pin drag. */
|
|
223
|
+
get annotationDrag(): AnnotationDrag | null;
|
|
224
|
+
set annotationDrag(v: AnnotationDrag | null);
|
|
192
225
|
/** Live preview while drawing a new shape; null when not drawing. */
|
|
193
|
-
drawingPreview: Bounds | null;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
* during the drag). Null when no such drag is in flight. */
|
|
208
|
-
linkDragFromAnchor: {
|
|
209
|
-
fromElement: ElementId;
|
|
210
|
-
fromWorld: Vec2;
|
|
211
|
-
/** Named anchor the gesture started on — drives the click-to-create
|
|
212
|
-
* direction (outward normal) and the source link endpoint. */
|
|
213
|
-
anchorName: string;
|
|
214
|
-
origin: Vec2;
|
|
215
|
-
moved: boolean;
|
|
216
|
-
} | null;
|
|
217
|
-
/**
|
|
218
|
-
* Element being hovered while draw-edge mode is active. Drives the port-
|
|
219
|
-
* overlay render so the user sees attachment points. `null` outside
|
|
220
|
-
* draw-edge mode or when the pointer is over empty canvas.
|
|
221
|
-
*/
|
|
222
|
-
hoveredLinkTarget: {
|
|
223
|
-
elementId: ElementId;
|
|
224
|
-
activeAnchor: string | null;
|
|
225
|
-
outlinePoint?: Vec2 | undefined;
|
|
226
|
-
/**
|
|
227
|
-
* What the drop will produce, for clear pre-drop feedback (standard):
|
|
228
|
-
* - `"point"` → fixed attach to a specific dot (highlight the dot);
|
|
229
|
-
* - `"element"` → floating attach to the whole shape (highlight the
|
|
230
|
-
* element). Mirrors `snapLinkEndpoint`: an anchor within threshold →
|
|
231
|
-
* point, otherwise floating.
|
|
232
|
-
*/
|
|
233
|
-
mode: "point" | "element";
|
|
234
|
-
} | null;
|
|
235
|
-
/**
|
|
236
|
-
* Last idle cursor position (world) in select mode — the overlay grows the
|
|
237
|
-
* SINGLE selected element's link-start dot nearest it
|
|
238
|
-
* (`ANCHOR_DOT_HOVER_GROW_RADIUS`). Reset to null on press / gesture.
|
|
239
|
-
*/
|
|
240
|
-
hoverCursorWorld: Vec2 | null;
|
|
241
|
-
/**
|
|
242
|
-
* When a link is dropped on empty canvas, the edge is created with a
|
|
243
|
-
* free `point` end and this records where, so the host can pop a
|
|
244
|
-
* mini shape-picker at that spot (standard). Picking a shape re-points the
|
|
245
|
-
* end to the new element; dismissing (Esc / click-away) leaves the free
|
|
246
|
-
* end on the canvas. `null` when no menu is pending.
|
|
247
|
-
*/
|
|
248
|
-
private pendingLinkDropMenu;
|
|
226
|
+
get drawingPreview(): Bounds | null;
|
|
227
|
+
set drawingPreview(v: Bounds | null);
|
|
228
|
+
/** Live preview of an edge being drawn. */
|
|
229
|
+
get edgePreview(): EdgePreview | null;
|
|
230
|
+
set edgePreview(v: EdgePreview | null);
|
|
231
|
+
/** Active "drag a link from a start-anchor" gesture. */
|
|
232
|
+
get linkDragFromAnchor(): LinkDragFromAnchor | null;
|
|
233
|
+
set linkDragFromAnchor(v: LinkDragFromAnchor | null);
|
|
234
|
+
/** Element hovered while draw-edge mode is active (drives the port overlay). */
|
|
235
|
+
get hoveredLinkTarget(): HoveredLinkTarget | null;
|
|
236
|
+
set hoveredLinkTarget(v: HoveredLinkTarget | null);
|
|
237
|
+
/** Last idle cursor position (world) in select mode — grows the nearest dot. */
|
|
238
|
+
get hoverCursorWorld(): Vec2 | null;
|
|
239
|
+
set hoverCursorWorld(v: Vec2 | null);
|
|
249
240
|
/**
|
|
250
241
|
* Currently selected links (connectors). Links are first-class members
|
|
251
242
|
* of the selection: they coexist with selected elements, join Cmd+A and
|
|
@@ -271,8 +262,9 @@ export declare class Editor {
|
|
|
271
262
|
/**
|
|
272
263
|
* Mid-drag preview state when the user is dragging an edge endpoint.
|
|
273
264
|
* Drawn as an overlay line + handle dot so the user sees the target.
|
|
265
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
274
266
|
*/
|
|
275
|
-
linkEndpointDrag: {
|
|
267
|
+
get linkEndpointDrag(): {
|
|
276
268
|
linkId: LinkId;
|
|
277
269
|
side: "from" | "to";
|
|
278
270
|
toPoint: Vec2;
|
|
@@ -283,83 +275,40 @@ export declare class Editor {
|
|
|
283
275
|
* began on a segment midpoint and will splice a new waypoint on the
|
|
284
276
|
* first move (so a no-move click adds nothing). Live-mutated through the
|
|
285
277
|
* gesture transaction → one undo step per drag.
|
|
278
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
286
279
|
*/
|
|
287
|
-
linkWaypointDrag: {
|
|
280
|
+
get linkWaypointDrag(): {
|
|
288
281
|
linkId: LinkId;
|
|
289
282
|
index: number;
|
|
290
283
|
pendingInsert: boolean;
|
|
291
284
|
} | null;
|
|
292
285
|
/**
|
|
293
|
-
* Host-managed elbow segment drag. `
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
286
|
+
* Host-managed elbow segment drag. `axis` is the segment's orientation.
|
|
287
|
+
* Dragging pins the segment's perpendicular coordinate into
|
|
288
|
+
* `Link.fixedSegments`; the reroute pass re-flows the rest. One undo
|
|
289
|
+
* step via the gesture tx.
|
|
290
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
297
291
|
*/
|
|
298
|
-
linkSegmentDrag: {
|
|
292
|
+
get linkSegmentDrag(): {
|
|
299
293
|
linkId: LinkId;
|
|
300
294
|
axis: "h" | "v";
|
|
301
295
|
at: number;
|
|
302
296
|
} | null;
|
|
303
297
|
/** Live lasso bounds during a rubber-band select gesture. */
|
|
304
|
-
lassoPreview: Bounds | null;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
* fans out when this map is populated.
|
|
319
|
-
*/
|
|
320
|
-
groupMoveOrigin: ReadonlyMap<ElementId, Vec2> | null;
|
|
321
|
-
/**
|
|
322
|
-
* Press-time snapshot of connectors that must follow a multi-element
|
|
323
|
-
* drag rigidly — both endpoints bound to moved elements, carrying
|
|
324
|
-
* absolute geometry (waypoints / fixedSegments / routedPoints). Each
|
|
325
|
-
* frame translates from these originals so the shift never compounds.
|
|
326
|
-
* Cleared on gesture commit / cancel alongside `groupMoveOrigin`.
|
|
327
|
-
*/
|
|
328
|
-
groupLinkMoveOrigin: ReadonlyMap<LinkId, Link> | null;
|
|
329
|
-
/**
|
|
330
|
-
* Per-shape snapshot for a group-resize gesture — `bounds` is the
|
|
331
|
-
* shape's world AABB at press-down. Editor scales the relative
|
|
332
|
-
* position / size against the combined bounds delta each frame.
|
|
333
|
-
*/
|
|
334
|
-
groupResizeOrigin: {
|
|
335
|
-
readonly combined: Bounds;
|
|
336
|
-
readonly elements: ReadonlyMap<ElementId, {
|
|
337
|
-
readonly position: Vec2;
|
|
338
|
-
readonly bounds: Bounds;
|
|
339
|
-
readonly scale: Vec2;
|
|
340
|
-
}>;
|
|
341
|
-
readonly links: ReadonlyMap<LinkId, Link>;
|
|
342
|
-
} | null;
|
|
343
|
-
/**
|
|
344
|
-
* Press-time snapshot for a rotate gesture: the pivot (selection bbox centre)
|
|
345
|
-
* and every member's pristine `position` / `rotation`. Each frame rotates
|
|
346
|
-
* from this baseline so the cumulative angle never drifts. Cleared on gesture
|
|
347
|
-
* end (commit / cancel).
|
|
348
|
-
*/
|
|
349
|
-
rotateGestureOrigin: {
|
|
350
|
-
readonly pivot: Vec2;
|
|
351
|
-
readonly origin: ReadonlyMap<ElementId, {
|
|
352
|
-
readonly position: Vec2;
|
|
353
|
-
readonly rotation: number;
|
|
354
|
-
}>;
|
|
355
|
-
} | null;
|
|
356
|
-
/**
|
|
357
|
-
* Pristine shape snapshot for a single-shape text resize, captured on
|
|
358
|
-
* the gesture's first tick. Font scaling is computed against this base
|
|
359
|
-
* so it never compounds across pointermove ticks. Cleared on gesture
|
|
360
|
-
* end (commit / cancel).
|
|
361
|
-
*/
|
|
362
|
-
private _resizeOriginElement;
|
|
298
|
+
get lassoPreview(): Bounds | null;
|
|
299
|
+
set lassoPreview(v: Bounds | null);
|
|
300
|
+
/** Snapshot of every selected shape's `position` at press-down (multi-drag). */
|
|
301
|
+
get groupMoveOrigin(): ReadonlyMap<ElementId, Vec2> | null;
|
|
302
|
+
set groupMoveOrigin(v: ReadonlyMap<ElementId, Vec2> | null);
|
|
303
|
+
/** Press-time snapshot of connectors that follow a multi-element drag rigidly. */
|
|
304
|
+
get groupLinkMoveOrigin(): ReadonlyMap<LinkId, Link> | null;
|
|
305
|
+
set groupLinkMoveOrigin(v: ReadonlyMap<LinkId, Link> | null);
|
|
306
|
+
/** Per-shape snapshot for a group-resize gesture. */
|
|
307
|
+
get groupResizeOrigin(): GroupResizeOrigin | null;
|
|
308
|
+
set groupResizeOrigin(v: GroupResizeOrigin | null);
|
|
309
|
+
/** Press-time snapshot for a rotate gesture. */
|
|
310
|
+
get rotateGestureOrigin(): RotateGestureOrigin | null;
|
|
311
|
+
set rotateGestureOrigin(v: RotateGestureOrigin | null);
|
|
363
312
|
/**
|
|
364
313
|
* Active layer — new shapes created via `addElement` / `applyCreate` land
|
|
365
314
|
* here when their input doesn't specify a `layerId`. Defaults to the
|
|
@@ -375,21 +324,6 @@ export declare class Editor {
|
|
|
375
324
|
private readonly snapEngine;
|
|
376
325
|
/** Snap threshold in world units. */
|
|
377
326
|
private readonly snapThreshold;
|
|
378
|
-
/**
|
|
379
|
-
* Transient flag set by the host while a snap-suppress modifier
|
|
380
|
-
* (Cmd / Ctrl) is held during a drag — lets the user pull a shape off
|
|
381
|
-
* the grid for one gesture without toggling snap off. Read by the
|
|
382
|
-
* move / resize / create wrappers; never persisted.
|
|
383
|
-
*/
|
|
384
|
-
private snapSuppressed;
|
|
385
|
-
/**
|
|
386
|
-
* Transient transform-modifier state mirrored from the host while a drag is
|
|
387
|
-
* in flight. `alt` resizes symmetrically about the centre; `shift` locks the
|
|
388
|
-
* resize aspect ratio or constrains a move to a single axis. Read by the
|
|
389
|
-
* move / resize wrappers; never persisted.
|
|
390
|
-
*/
|
|
391
|
-
private transformAltKey;
|
|
392
|
-
private transformShiftKey;
|
|
393
327
|
/**
|
|
394
328
|
* In-editor style memory for copy-style / paste-style. Holds the visual
|
|
395
329
|
* `style` (fill / stroke / dash / …) captured from a shape; `null` until a
|
|
@@ -417,36 +351,37 @@ export declare class Editor {
|
|
|
417
351
|
* escape, click outside the group's descendants, or `cancelInteraction`.
|
|
418
352
|
*/
|
|
419
353
|
_enteredGroup: ElementId | null;
|
|
420
|
-
/**
|
|
421
|
-
* Double-click detection state. Updated on every non-drag pointer
|
|
422
|
-
* up; the next pointer-up within `DOUBLE_CLICK_MS` and within
|
|
423
|
-
* `DOUBLE_CLICK_TOLERANCE_PX` of `lastClickWorldPoint` counts as a
|
|
424
|
-
* double-click. Used to trigger group drill-down (enter isolation).
|
|
425
|
-
*/
|
|
426
|
-
private lastClickAt;
|
|
427
|
-
private lastClickWorldPoint;
|
|
428
|
-
/**
|
|
429
|
-
* Separate double-click tracker for link edit handles (waypoint /
|
|
430
|
-
* segment). Kept apart from `lastClickAt` because a handle press
|
|
431
|
-
* returns early in `onDown` (begin-drag) and never reaches the up-side
|
|
432
|
-
* double-click path that updates `lastClickAt`. Updated by
|
|
433
|
-
* `isHandleDoubleClick` on each handle press.
|
|
434
|
-
*/
|
|
435
|
-
private lastHandleClickAt;
|
|
436
|
-
private lastHandleClickWorld;
|
|
437
354
|
/**
|
|
438
355
|
* In-progress brush stroke. Hosts push points via
|
|
439
356
|
* `extendBrushStroke`; the overlay reads it through
|
|
440
357
|
* `pendingBrushStroke` to draw a live preview.
|
|
441
358
|
*/
|
|
442
|
-
brushStroke: BrushStrokeState | null;
|
|
359
|
+
get brushStroke(): BrushStrokeState | null;
|
|
360
|
+
set brushStroke(v: BrushStrokeState | null);
|
|
361
|
+
/**
|
|
362
|
+
* The in-progress brush stroke run through the SAME commit pipeline
|
|
363
|
+
* `commitBrushStroke` applies on release (see {@link brushCommitPoints}:
|
|
364
|
+
* raw catch-up point + Catmull-Rom resample), so the stroke reads exactly
|
|
365
|
+
* as it will land in the scene instead of snapping on release. A fresh
|
|
366
|
+
* object each call (points diverge from `brushStroke.points`), so the
|
|
367
|
+
* overlay memo repaints every move that grows the stroke.
|
|
368
|
+
*/
|
|
369
|
+
private get brushPreviewStroke();
|
|
370
|
+
/** In-progress eraser stroke (pending-delete set), or null between strokes. */
|
|
371
|
+
get eraseStroke(): EraseStrokeState | null;
|
|
372
|
+
set eraseStroke(v: EraseStrokeState | null);
|
|
373
|
+
/** Ids swept by the current eraser stroke — previewed dimmed, deleted on release. */
|
|
374
|
+
get pendingErase(): ReadonlySet<ElementId>;
|
|
375
|
+
/** Live laser-pointer trails (ephemeral, fading). Empty when none active. */
|
|
376
|
+
get laserStrokes(): readonly LaserStroke[];
|
|
443
377
|
/**
|
|
444
378
|
* Last world-space pointer position observed by the host's onMove
|
|
445
379
|
* handler. `paste()` uses it as the default drop target so a fresh
|
|
446
380
|
* paste lands under the cursor instead of overlapping the originals.
|
|
447
381
|
* `null` until the pointer first enters the host.
|
|
448
382
|
*/
|
|
449
|
-
lastPointerWorld: Vec2 | null;
|
|
383
|
+
get lastPointerWorld(): Vec2 | null;
|
|
384
|
+
set lastPointerWorld(v: Vec2 | null);
|
|
450
385
|
/** Host-registered custom cursor images per role (see `setCursorOverride`). */
|
|
451
386
|
private readonly cursorOverrides;
|
|
452
387
|
/**
|
|
@@ -465,6 +400,23 @@ export declare class Editor {
|
|
|
465
400
|
* pass would never visibly apply.
|
|
466
401
|
*/
|
|
467
402
|
lastRenderedEnteredGroup: ElementId | null;
|
|
403
|
+
/**
|
|
404
|
+
* Whether the last paint had eraser-dim active — paired with
|
|
405
|
+
* `lastRenderedScene` like {@link lastRenderedEnteredGroup}. When an eraser
|
|
406
|
+
* stroke ENDS by cancel (Esc), the marked shapes un-dim without a scene
|
|
407
|
+
* change, so the dirty-rect diff is empty and the dim would linger on screen;
|
|
408
|
+
* this lets that active→inactive transition force one full repaint.
|
|
409
|
+
*/
|
|
410
|
+
lastRenderedEraseActive: boolean;
|
|
411
|
+
/**
|
|
412
|
+
* Set whenever an eraser move actually CHANGES the marked / cut set (a new
|
|
413
|
+
* shape marked, un-marked, or a brush point cut). Gates the forced full
|
|
414
|
+
* repaint during erasing: only the frames that change the preview repaint the
|
|
415
|
+
* whole scene; a slowly-moving or stopped cursor over already-covered area
|
|
416
|
+
* skips the expensive main pass (only the overlay cursor / trail refresh).
|
|
417
|
+
* Cleared after each paint.
|
|
418
|
+
*/
|
|
419
|
+
private eraseDirty;
|
|
468
420
|
/**
|
|
469
421
|
* Fractional-order compaction scheduler (microtask-coalesced).
|
|
470
422
|
* Triggered from every `notify()`; only does real work when at
|
|
@@ -483,7 +435,8 @@ export declare class Editor {
|
|
|
483
435
|
* gestures, set in onDown when press lands on a shape and cleared
|
|
484
436
|
* in onUp / cancel.
|
|
485
437
|
*/
|
|
486
|
-
dragElementId: ElementId | null;
|
|
438
|
+
get dragElementId(): ElementId | null;
|
|
439
|
+
set dragElementId(v: ElementId | null);
|
|
487
440
|
/**
|
|
488
441
|
* Element that the current press added to the selection additively
|
|
489
442
|
* (shift / meta click on an unselected shape). The press promotes it
|
|
@@ -491,17 +444,16 @@ export declare class Editor {
|
|
|
491
444
|
* otherwise `SELECT_TOGGLE` it straight back off, so it consults this
|
|
492
445
|
* to skip that redundant toggle. Reset at every press-down.
|
|
493
446
|
*/
|
|
494
|
-
additivePressAdded: ElementId | null;
|
|
447
|
+
get additivePressAdded(): ElementId | null;
|
|
448
|
+
set additivePressAdded(v: ElementId | null);
|
|
495
449
|
/**
|
|
496
450
|
* Live container highlight: the container shape the dragged item is
|
|
497
451
|
* currently hovering over. Drawn by the overlay as a dashed
|
|
498
452
|
* accent rect on the container's drop-zone so the user sees where the
|
|
499
453
|
* shape will land after release.
|
|
500
454
|
*/
|
|
501
|
-
containerHover:
|
|
502
|
-
|
|
503
|
-
dropZone: Bounds;
|
|
504
|
-
} | null;
|
|
455
|
+
get containerHover(): ContainerHover | null;
|
|
456
|
+
set containerHover(v: ContainerHover | null);
|
|
505
457
|
/**
|
|
506
458
|
* Remote peer cursors / selections, pushed in by the host (typically
|
|
507
459
|
* a `bindAwareness(editor, awareness)` helper in `@collab`). The
|
|
@@ -521,7 +473,7 @@ export declare class Editor {
|
|
|
521
473
|
* two or more entries we enter a pinch / pan gesture and bypass the
|
|
522
474
|
* interaction machine — `pinchOrigin` holds the baseline.
|
|
523
475
|
*/
|
|
524
|
-
|
|
476
|
+
get activePointers(): Map<number, Vec2>;
|
|
525
477
|
/**
|
|
526
478
|
* One-finger-pan candidate: set at pointer-down when a TOUCH press lands
|
|
527
479
|
* on empty canvas in select mode. A tap (no movement) still falls through
|
|
@@ -529,7 +481,8 @@ export declare class Editor {
|
|
|
529
481
|
* this to a real pan instead of a marquee lasso (mobile convention).
|
|
530
482
|
* Screen-space origin point.
|
|
531
483
|
*/
|
|
532
|
-
touchPanCandidate: Vec2 | null;
|
|
484
|
+
get touchPanCandidate(): Vec2 | null;
|
|
485
|
+
set touchPanCandidate(v: Vec2 | null);
|
|
533
486
|
pinch: PinchController;
|
|
534
487
|
/** Bridge for the container-ops helpers. Built lazily in constructor. */
|
|
535
488
|
private containerOpsRef;
|
|
@@ -539,7 +492,8 @@ export declare class Editor {
|
|
|
539
492
|
* "grab" / "grabbing". Wires a window-level keydown/keyup listener
|
|
540
493
|
* in `bindPointerEvents`.
|
|
541
494
|
*/
|
|
542
|
-
spaceHeld: boolean;
|
|
495
|
+
get spaceHeld(): boolean;
|
|
496
|
+
set spaceHeld(v: boolean);
|
|
543
497
|
/**
|
|
544
498
|
* Host-supplied tile compositor — when set (via
|
|
545
499
|
* `EditorOptions.useTileCache` + `tileCompose`), the per-frame
|
|
@@ -570,6 +524,10 @@ export declare class Editor {
|
|
|
570
524
|
* toolbar as a lock affordance next to the active tool.
|
|
571
525
|
*/
|
|
572
526
|
private _toolLocked;
|
|
527
|
+
/** The tool active before the current one — `activeTool.lastActiveTool`. */
|
|
528
|
+
private _lastActiveTool;
|
|
529
|
+
/** Cached `activeTool` value object; rebuilt only when a component changes. */
|
|
530
|
+
private _activeToolCache;
|
|
573
531
|
/**
|
|
574
532
|
* Host-extensible file-drop dispatch. Built-ins (image / scene
|
|
575
533
|
* JSON) register themselves at editor construction; hosts add
|
|
@@ -589,20 +547,16 @@ export declare class Editor {
|
|
|
589
547
|
* only treat right-click releases as potential context-menu
|
|
590
548
|
* triggers (Space + left-drag never opens a menu).
|
|
591
549
|
*/
|
|
592
|
-
panGesture:
|
|
593
|
-
|
|
594
|
-
button: number;
|
|
595
|
-
startPoint: Vec2;
|
|
596
|
-
lastPoint: Vec2;
|
|
597
|
-
moved: boolean;
|
|
598
|
-
} | null;
|
|
550
|
+
get panGesture(): PanGesture | null;
|
|
551
|
+
set panGesture(v: PanGesture | null);
|
|
599
552
|
/**
|
|
600
553
|
* Set on a right-click pointerdown so the upcoming native
|
|
601
554
|
* `contextmenu` event can be unconditionally preventDefault'ed
|
|
602
555
|
* (the gesture decides whether to fire the menu manually on
|
|
603
556
|
* pointerup based on whether the user dragged).
|
|
604
557
|
*/
|
|
605
|
-
suppressNextContextMenu: boolean;
|
|
558
|
+
get suppressNextContextMenu(): boolean;
|
|
559
|
+
set suppressNextContextMenu(v: boolean);
|
|
606
560
|
/**
|
|
607
561
|
* Long-press tracking. Starts on `pointerdown`; cancelled on
|
|
608
562
|
* `pointermove > LONG_PRESS_MAX_MOVEMENT_PX` or `pointerup` before
|
|
@@ -622,13 +576,13 @@ export declare class Editor {
|
|
|
622
576
|
* in the constructor from `EditorOptions.inputMode` (default `"auto"`
|
|
623
577
|
* uses `matchMedia('(pointer: coarse)')`).
|
|
624
578
|
*/
|
|
625
|
-
private
|
|
626
|
-
private
|
|
627
|
-
private
|
|
628
|
-
private
|
|
579
|
+
private inputMode;
|
|
580
|
+
private handleHitSlop;
|
|
581
|
+
private edgeHandleHitSlop;
|
|
582
|
+
private edgeHitThreshold;
|
|
629
583
|
/** Link-start anchor-dot grab/click hit radii — touch-enlarged in touch mode. */
|
|
630
|
-
|
|
631
|
-
|
|
584
|
+
anchorStartHitSlop: number;
|
|
585
|
+
anchorClickRadius: number;
|
|
632
586
|
readonly _history: HistoryProvider;
|
|
633
587
|
/** Open transaction during a single drag/resize gesture. */
|
|
634
588
|
gestureTx: TransactionHandle | null;
|
|
@@ -646,13 +600,72 @@ export declare class Editor {
|
|
|
646
600
|
* The controller calls back through the narrow `GestureRef` bridge
|
|
647
601
|
* built lazily below.
|
|
648
602
|
*/
|
|
649
|
-
private
|
|
603
|
+
private gestures;
|
|
604
|
+
/**
|
|
605
|
+
* Owns the inline text-edit session (edited shape, pending creation,
|
|
606
|
+
* origin snapshot, live selection, drag anchor and caret blink).
|
|
607
|
+
* Editor keeps thin delegate wrappers so the public API is unchanged.
|
|
608
|
+
*/
|
|
609
|
+
private textEdit;
|
|
610
|
+
/**
|
|
611
|
+
* Owns the link edit-handle drags (waypoint / segment / endpoint) and
|
|
612
|
+
* the handle double-click detector. Editor keeps thin delegate
|
|
613
|
+
* wrappers so the public API is unchanged.
|
|
614
|
+
*/
|
|
615
|
+
private linkHandles;
|
|
650
616
|
constructor(options: EditorOptions);
|
|
651
|
-
/**
|
|
617
|
+
/**
|
|
618
|
+
* Build the interaction controllers (gestures, text edit, link-handle
|
|
619
|
+
* drag, long-press, pinch) and the container-ops bridge. Each wires to a
|
|
620
|
+
* narrow getter/setter surface over the editor's mutable fields, so the
|
|
621
|
+
* controllers live in their own modules without importing Editor. The
|
|
622
|
+
* getters/setters in the object literals rebind `this`, so a single
|
|
623
|
+
* `self` alias captures the Editor reference for all of them.
|
|
624
|
+
*/
|
|
625
|
+
private initControllers;
|
|
626
|
+
/**
|
|
627
|
+
* Install process-global hooks the host opted into: a custom text shaper
|
|
628
|
+
* and rasterizer for the WebGL2 backend, plus the scene text measurer that
|
|
629
|
+
* routes through the renderer's own metrics so selection boxes hug text.
|
|
630
|
+
*/
|
|
631
|
+
private initGlobalHooks;
|
|
632
|
+
/**
|
|
633
|
+
* Resolve the input mode (`touch` vs `mouse`, `auto` reads the coarse-
|
|
634
|
+
* pointer media query) and the derived hit slops / thresholds once.
|
|
635
|
+
*/
|
|
636
|
+
private initInputMode;
|
|
637
|
+
/**
|
|
638
|
+
* Create and start the interaction state-machine actor, wire its render /
|
|
639
|
+
* emit subscriptions, register the built-in file-drop handlers, and apply
|
|
640
|
+
* the initial mode.
|
|
641
|
+
*/
|
|
642
|
+
private initActor;
|
|
643
|
+
/**
|
|
644
|
+
* Last {@link observableSnapshot} object, reused while none of its slices
|
|
645
|
+
* have flipped. `null` until the first snapshot is built.
|
|
646
|
+
*/
|
|
647
|
+
private snapshotCache;
|
|
648
|
+
/**
|
|
649
|
+
* Snapshot used by event-fanout. Kept private — internal API.
|
|
650
|
+
*
|
|
651
|
+
* Memoized by slice identity: `notify()` fires on many mutations that touch
|
|
652
|
+
* no observable slice (annotation focus, cursor pushes, viewport-only re-arm),
|
|
653
|
+
* so rebuilding the object every call is pure churn on the hot drag path.
|
|
654
|
+
* We reuse the cached object whenever all six slices compare equal (refs for
|
|
655
|
+
* mode/selection/selectedLinks/scene — scene uses structural sharing so a new
|
|
656
|
+
* ref iff something changed — plus the two history booleans), and only
|
|
657
|
+
* allocate a fresh one on a real flip. `fanOutEvents` sees identical values
|
|
658
|
+
* either way, so emitted events are unchanged.
|
|
659
|
+
*/
|
|
652
660
|
private observableSnapshot;
|
|
653
661
|
get scene(): Scene;
|
|
654
662
|
get selection(): Selection.Selection;
|
|
655
|
-
|
|
663
|
+
/**
|
|
664
|
+
* The active tool as a single value object (`{ type, locked,
|
|
665
|
+
* lastActiveTool }`) — the one source of truth for the current tool.
|
|
666
|
+
* The reference is stable between changes (safe for React deps).
|
|
667
|
+
*/
|
|
668
|
+
get activeTool(): ActiveTool;
|
|
656
669
|
get history(): HistoryProvider;
|
|
657
670
|
get canUndo(): boolean;
|
|
658
671
|
get canRedo(): boolean;
|
|
@@ -740,14 +753,25 @@ export declare class Editor {
|
|
|
740
753
|
* values can be eyeballed. View-only — not recorded in history.
|
|
741
754
|
*/
|
|
742
755
|
setDebugHitZones(on: boolean): void;
|
|
756
|
+
/**
|
|
757
|
+
* Read-only / view mode flag. `true` gates pointer edits and
|
|
758
|
+
* non-`viewMode` actions while leaving pan / zoom / select live.
|
|
759
|
+
*/
|
|
760
|
+
get readOnly(): boolean;
|
|
761
|
+
/**
|
|
762
|
+
* Enter / leave read-only (view) mode. Notifies subscribers so the UI
|
|
763
|
+
* can re-render disabled chrome, and repaints (no visual diff today, but
|
|
764
|
+
* keeps the contract symmetric with other view toggles). Idempotent.
|
|
765
|
+
*/
|
|
766
|
+
setReadOnly(on: boolean): void;
|
|
767
|
+
/** Toggle read-only (view) mode. */
|
|
768
|
+
toggleReadOnly(): void;
|
|
743
769
|
/** Whether the background grid is enabled for the scene. */
|
|
744
770
|
get gridEnabled(): boolean;
|
|
745
771
|
/** Show/hide the background grid (`g`). Persists in the viewport, not in history. */
|
|
746
772
|
setGridVisible(on: boolean): void;
|
|
747
773
|
/** Toggle the background grid on/off. */
|
|
748
774
|
toggleGrid(): void;
|
|
749
|
-
/** Whether the active draw-mode sticks after a create (toolbar lock). */
|
|
750
|
-
get toolLocked(): boolean;
|
|
751
775
|
/** All currently-selected link (connector) ids. */
|
|
752
776
|
get selectedLinks(): LinkSelection.LinkSelection;
|
|
753
777
|
/**
|
|
@@ -783,14 +807,19 @@ export declare class Editor {
|
|
|
783
807
|
*/
|
|
784
808
|
dispatchFileDrop(file: File, worldPoint: Vec2): Promise<boolean>;
|
|
785
809
|
/**
|
|
786
|
-
* Toggle the tool
|
|
787
|
-
* after each successful shape create — the user keeps drawing
|
|
810
|
+
* Toggle the tool lock (`activeTool.locked`). With `true`, draw tools
|
|
811
|
+
* persist after each successful shape create — the user keeps drawing
|
|
788
812
|
* rectangles without re-pressing R. With `false` (default), the
|
|
789
813
|
* editor reverts to `select` after each create.
|
|
790
814
|
*/
|
|
791
815
|
setToolLocked(locked: boolean): void;
|
|
792
|
-
private
|
|
793
|
-
|
|
816
|
+
private maybeRevertToolAfterCreate;
|
|
817
|
+
/**
|
|
818
|
+
* Switch the active tool. The single entry point for tool changes —
|
|
819
|
+
* toolbar buttons and hotkeys reach it through the action registry.
|
|
820
|
+
* Records the outgoing tool in `activeTool.lastActiveTool`.
|
|
821
|
+
*/
|
|
822
|
+
setActiveTool(mode: Mode): void;
|
|
794
823
|
/** Undo the latest record. No-op if there is nothing to undo. */
|
|
795
824
|
undo(): boolean;
|
|
796
825
|
/** Redo the undone record. */
|
|
@@ -902,11 +931,10 @@ export declare class Editor {
|
|
|
902
931
|
* cleared by `commitTextEdit` / `cancelTextEdit`. The host overlay
|
|
903
932
|
* (`<TextEditorOverlay>` in `@react-ui`) subscribes via `editor`
|
|
904
933
|
* and renders a `<textarea>` positioned over the shape.
|
|
934
|
+
* State lives in `TextEditController`; this is a delegate.
|
|
905
935
|
*/
|
|
906
|
-
private _editingTextElement;
|
|
907
936
|
get editingTextElement(): ElementId | null;
|
|
908
937
|
/** Link whose caption is being edited inline (double-click), or null. */
|
|
909
|
-
private _editingLinkCaption;
|
|
910
938
|
get editingLinkCaption(): LinkId | null;
|
|
911
939
|
/**
|
|
912
940
|
* Frame whose NAME (header label) is being edited inline (double-click
|
|
@@ -915,29 +943,6 @@ export declare class Editor {
|
|
|
915
943
|
*/
|
|
916
944
|
private _editingFrameName;
|
|
917
945
|
get editingFrameName(): ElementId | null;
|
|
918
|
-
/**
|
|
919
|
-
* When the `draw-text` tool just placed a shape and opened its
|
|
920
|
-
* editor, this holds that shape's id until the first commit. A
|
|
921
|
-
* pending creation isn't in history yet: committing non-empty text
|
|
922
|
-
* records a single add patch (whole shape = one undo); committing
|
|
923
|
-
* empty / cancelling removes it with no history entry at all.
|
|
924
|
-
*/
|
|
925
|
-
private _pendingTextCreate;
|
|
926
|
-
/**
|
|
927
|
-
* Snapshot of the shape at edit start. Used to revert on cancel and
|
|
928
|
-
* as the `before` of the single commit patch. `null` for a pending
|
|
929
|
-
* creation (the shape didn't exist yet).
|
|
930
|
-
*/
|
|
931
|
-
private _textEditOrigin;
|
|
932
|
-
/**
|
|
933
|
-
* Live selection inside the edited text, mirrored from the hidden
|
|
934
|
-
* `<textarea>` (`start`/`end` are source offsets, `dir` is the
|
|
935
|
-
* anchored end). The caret is `dir === "backward" ? start : end`.
|
|
936
|
-
*/
|
|
937
|
-
private _textSel;
|
|
938
|
-
/** Anchor offset for a canvas drag-select inside the edited text. */
|
|
939
|
-
private _textDragAnchor;
|
|
940
|
-
private readonly caretBlink;
|
|
941
946
|
get editingTextSelection(): {
|
|
942
947
|
start: number;
|
|
943
948
|
end: number;
|
|
@@ -963,7 +968,11 @@ export declare class Editor {
|
|
|
963
968
|
commitLinkCaptionEdit(text: string): void;
|
|
964
969
|
/** Cancel link caption editing without changing the label. */
|
|
965
970
|
cancelLinkCaptionEdit(): void;
|
|
966
|
-
/**
|
|
971
|
+
/**
|
|
972
|
+
* World-space anchor point for a link's caption — the same shared geometry
|
|
973
|
+
* the renderer places the pill at (`linkLabelAnchor` over the drawn
|
|
974
|
+
* polyline), so the inline editor opens exactly over the label.
|
|
975
|
+
*/
|
|
967
976
|
linkLabelWorld(id: LinkId): Vec2 | null;
|
|
968
977
|
beginTextEdit(id: ElementId): void;
|
|
969
978
|
/**
|
|
@@ -1013,15 +1022,6 @@ export declare class Editor {
|
|
|
1013
1022
|
extendTextSelectionToPoint(worldPoint: Vec2): void;
|
|
1014
1023
|
/** End a canvas drag-select (clears the drag anchor). */
|
|
1015
1024
|
endTextDragSelect(): void;
|
|
1016
|
-
/** Build the editable layout for a text shape using the main target's metrics. */
|
|
1017
|
-
private editingTextLayout;
|
|
1018
|
-
/**
|
|
1019
|
-
* A measure callback bound to a shape's font, using the main target's
|
|
1020
|
-
* `measureText` — the SAME source the renderer draws with (WebGL2
|
|
1021
|
-
* reports MSDF advances) and the bounder measures with. Caret /
|
|
1022
|
-
* selection geometry therefore lines up exactly with the glyphs.
|
|
1023
|
-
*/
|
|
1024
|
-
private measureFor;
|
|
1025
1025
|
/**
|
|
1026
1026
|
* World-space caret + selection geometry for the overlay pass.
|
|
1027
1027
|
* Returns `null` when not editing. The caret is `null` while blinked
|
|
@@ -1064,7 +1064,22 @@ export declare class Editor {
|
|
|
1064
1064
|
* the tool is locked.
|
|
1065
1065
|
*/
|
|
1066
1066
|
createTextAt(worldPoint: Vec2): ElementId;
|
|
1067
|
-
|
|
1067
|
+
/** Current brush paint settings (line colour, fill, opacity, width). */
|
|
1068
|
+
private _brushSettings;
|
|
1069
|
+
get brushSettings(): BrushSettings;
|
|
1070
|
+
/**
|
|
1071
|
+
* Update one or more brush paint settings (e.g. from the drawing panel). New
|
|
1072
|
+
* strokes pick them up on commit; the width also drives the pressure curve and
|
|
1073
|
+
* the eraser radius. Merges over the current settings.
|
|
1074
|
+
*/
|
|
1075
|
+
setBrushSettings(patch: Partial<BrushSettings>): void;
|
|
1076
|
+
/**
|
|
1077
|
+
* Start a brush stroke. `pointerType` (a `PointerEvent.pointerType`) decides
|
|
1078
|
+
* the pressure source: a pen has a real pressure channel and is honoured
|
|
1079
|
+
* verbatim (the default, which also keeps programmatic callers exact); mouse
|
|
1080
|
+
* and touch have none, so pressure is simulated from pointer speed.
|
|
1081
|
+
*/
|
|
1082
|
+
beginBrushStroke(world: Vec2, pressure?: number, pointerType?: string): void;
|
|
1068
1083
|
extendBrushStroke(world: Vec2, pressure?: number): void;
|
|
1069
1084
|
commitBrushStroke(): ElementId | null;
|
|
1070
1085
|
cancelBrushStroke(): void;
|
|
@@ -1072,7 +1087,59 @@ export declare class Editor {
|
|
|
1072
1087
|
get pendingBrushStroke(): {
|
|
1073
1088
|
readonly origin: Vec2;
|
|
1074
1089
|
readonly points: readonly BrushPoint[];
|
|
1090
|
+
readonly pressures: readonly number[];
|
|
1091
|
+
readonly baseWidth: number;
|
|
1092
|
+
readonly lastRaw: BrushPoint & {
|
|
1093
|
+
readonly pressure: number;
|
|
1094
|
+
};
|
|
1075
1095
|
} | null;
|
|
1096
|
+
/**
|
|
1097
|
+
* Start an eraser stroke at `world`, seeding it with the shape under it so a
|
|
1098
|
+
* plain click erases. With `restore` (Alt held at press) it seeds nothing —
|
|
1099
|
+
* the gesture is in un-mark mode, and there's nothing marked yet to rescue.
|
|
1100
|
+
*/
|
|
1101
|
+
beginEraseStroke(world: Vec2, restore?: boolean, strokeErase?: boolean): void;
|
|
1102
|
+
/**
|
|
1103
|
+
* Incrementally mark the brush points erased by the eraser segment `a → b`
|
|
1104
|
+
* (world). Iterates the current brushes and grows `stroke.erased` in place —
|
|
1105
|
+
* O(points) per move (each already-erased point is skipped), so a long drag
|
|
1106
|
+
* no longer costs O(points × path length) per frame. Radius is the on-screen
|
|
1107
|
+
* eraser ring converted to world units.
|
|
1108
|
+
*/
|
|
1109
|
+
private markStrokeEraseSegment;
|
|
1110
|
+
/**
|
|
1111
|
+
* Extend the eraser stroke to `world`, sweeping shapes along the segment.
|
|
1112
|
+
* `restore` (Alt held) un-marks swept shapes instead of marking them.
|
|
1113
|
+
*/
|
|
1114
|
+
extendEraseStroke(world: Vec2, restore?: boolean): void;
|
|
1115
|
+
/**
|
|
1116
|
+
* Commit the eraser stroke — delete every swept shape in ONE undo step (with
|
|
1117
|
+
* their attached links). No-op delete when nothing was swept. Returns the
|
|
1118
|
+
* count removed.
|
|
1119
|
+
*/
|
|
1120
|
+
commitEraseStroke(): number;
|
|
1121
|
+
/** Abort the eraser stroke without deleting anything. */
|
|
1122
|
+
cancelEraseStroke(): void;
|
|
1123
|
+
/** True only while the pointer is down in laser mode (a trail is being laid). */
|
|
1124
|
+
get laserDrawing(): boolean;
|
|
1125
|
+
/** Start a laser trail at `world` (ephemeral — never enters the scene). */
|
|
1126
|
+
beginLaserStroke(world: Vec2): void;
|
|
1127
|
+
/** Append a point to the active laser trail (no-op unless drawing). */
|
|
1128
|
+
extendLaserStroke(world: Vec2): void;
|
|
1129
|
+
/** End the active laser trail — it keeps fading via the animation tick. */
|
|
1130
|
+
endLaserStroke(): void;
|
|
1131
|
+
/**
|
|
1132
|
+
* True while any laser trail OR eraser trail still has visible points (drives
|
|
1133
|
+
* the fade tick — so the trail keeps melting after the pointer stops).
|
|
1134
|
+
*/
|
|
1135
|
+
hasActiveLaser(): boolean;
|
|
1136
|
+
/** Live eraser drag trail (ephemeral, fading). Empty when none active. */
|
|
1137
|
+
get eraserTrail(): readonly LaserStroke[];
|
|
1138
|
+
/**
|
|
1139
|
+
* Drop expired laser/eraser trail points (called once per frame before paint).
|
|
1140
|
+
* Self-terminating: once both arrays empty the animation tick stops.
|
|
1141
|
+
*/
|
|
1142
|
+
private pruneLaser;
|
|
1076
1143
|
arrangeAsGrid(opts?: {
|
|
1077
1144
|
cols?: number;
|
|
1078
1145
|
gap?: number;
|
|
@@ -1106,6 +1173,14 @@ export declare class Editor {
|
|
|
1106
1173
|
*/
|
|
1107
1174
|
duplicateSelectedInPlace(anchorId?: ElementId | null): ElementId | null;
|
|
1108
1175
|
setSelection(ids: Iterable<ElementId>): void;
|
|
1176
|
+
/**
|
|
1177
|
+
* Programmatically select a single link by id (or clear the link
|
|
1178
|
+
* selection with `null`), clearing the element selection so the link
|
|
1179
|
+
* becomes the sole selection. Used by host navigation (search / jump-to)
|
|
1180
|
+
* to frame an edge with {@link zoomToSelection}. No-op when nothing
|
|
1181
|
+
* would change.
|
|
1182
|
+
*/
|
|
1183
|
+
selectLink(id: LinkId | null): void;
|
|
1109
1184
|
selectAll(): void;
|
|
1110
1185
|
/**
|
|
1111
1186
|
* Internal clipboard. Stored as deep-cloned snapshots so subsequent
|
|
@@ -1145,6 +1220,186 @@ export declare class Editor {
|
|
|
1145
1220
|
/** Whether a style has been copied and can be pasted. */
|
|
1146
1221
|
get hasStyleClipboard(): boolean;
|
|
1147
1222
|
updateStyle(ids: Iterable<ElementId>, partial: Partial<TextStyle>): void;
|
|
1223
|
+
/**
|
|
1224
|
+
* Re-base the width of committed brush strokes (`style.strokeWidth` has no
|
|
1225
|
+
* effect on brushes — their widths are baked per point). Scales every baked
|
|
1226
|
+
* point width proportionally and records the new `baseWidth`, keeping the
|
|
1227
|
+
* stroke's pressure profile. One undo step. Read-only editors ignore it.
|
|
1228
|
+
*/
|
|
1229
|
+
setBrushWidth(ids: Iterable<ElementId>, width: number): void;
|
|
1230
|
+
/**
|
|
1231
|
+
* Apply a partial text style (bold / italic / colour / decoration) to the
|
|
1232
|
+
* character range `[from, to)` of a single text element, producing styled
|
|
1233
|
+
* runs (rich text). One undo step. No-op when the id isn't a text shape or
|
|
1234
|
+
* the range is empty. Read-only editors ignore it. Use this — rather than
|
|
1235
|
+
* `updateStyle` — to style only PART of a text block (e.g. the current
|
|
1236
|
+
* inline-edit selection).
|
|
1237
|
+
*/
|
|
1238
|
+
applyTextStyleToRange(id: ElementId, from: number, to: number, partial: Partial<TextStyle>): void;
|
|
1239
|
+
/**
|
|
1240
|
+
* The fill (or stroke, per `role`) colour of the top-most shape under the
|
|
1241
|
+
* world point, or `null` on empty canvas. Pure read — no mutation.
|
|
1242
|
+
*/
|
|
1243
|
+
pickColorAt(worldPoint: Vec2, role?: "fill" | "stroke"): Color | null;
|
|
1244
|
+
/** One-shot callback armed by {@link beginEyedropperPick}; consumes the next canvas click. */
|
|
1245
|
+
private pendingEyedropperPick;
|
|
1246
|
+
/** `true` while a colour-picker pipette is armed and waiting for a canvas click. */
|
|
1247
|
+
get isEyedropperArmed(): boolean;
|
|
1248
|
+
/**
|
|
1249
|
+
* Arm the eyedropper for a one-shot canvas pick that routes the sampled colour
|
|
1250
|
+
* to `onPick` (e.g. a colour-picker swatch) instead of the selection fill. Does
|
|
1251
|
+
* NOT change the tool mode — the next canvas press is intercepted by
|
|
1252
|
+
* {@link applyEyedropperAt}. Cancelled by a mode switch or an empty-canvas click.
|
|
1253
|
+
*/
|
|
1254
|
+
beginEyedropperPick(onPick: (color: Color) => void): void;
|
|
1255
|
+
/**
|
|
1256
|
+
* Sample the colour under `worldPoint`. When a pipette pick is armed (see
|
|
1257
|
+
* {@link beginEyedropperPick}), route the colour to that callback and disarm.
|
|
1258
|
+
* Otherwise apply it as the current selection's fill (programmatic path).
|
|
1259
|
+
* Returns the sampled colour, or `null` on empty canvas. Read-only editors
|
|
1260
|
+
* sample but don't mutate.
|
|
1261
|
+
*/
|
|
1262
|
+
applyEyedropperAt(worldPoint: Vec2): Color | null;
|
|
1263
|
+
/**
|
|
1264
|
+
* Convert every convertible selected shape (rectangle / ellipse / diamond)
|
|
1265
|
+
* to `target`, preserving position, size and style. One undo step; no-op
|
|
1266
|
+
* when nothing applies. See {@link ConvertTarget}.
|
|
1267
|
+
*/
|
|
1268
|
+
convertSelection(target: ConvertTarget): void;
|
|
1269
|
+
/**
|
|
1270
|
+
* Flowchart auto-generate: clone the single selected node offset in
|
|
1271
|
+
* `direction` and connect the two with a fresh link. Selects the new node.
|
|
1272
|
+
* No-op unless exactly one element is selected. One undo step.
|
|
1273
|
+
*/
|
|
1274
|
+
spawnConnectedNode(direction: SpawnDirection): void;
|
|
1275
|
+
/**
|
|
1276
|
+
* Pending flowchart-create session, or `null` when idle. Holds the ORIGINAL
|
|
1277
|
+
* source id + direction, the current sibling `count`, and the pending
|
|
1278
|
+
* `elements` + `links` (a PREVIEW — not yet in the scene / history). Grown by
|
|
1279
|
+
* {@link growFlowchart}, committed by {@link commitFlowchart}, discarded by
|
|
1280
|
+
* {@link cancelFlowchart}.
|
|
1281
|
+
*/
|
|
1282
|
+
private flowchartSession;
|
|
1283
|
+
/**
|
|
1284
|
+
* Grow the flowchart-create preview one step in `direction`. Starts a session
|
|
1285
|
+
* (count = 1) when idle or when the direction changes; otherwise bumps the
|
|
1286
|
+
* sibling count up to {@link FLOWCHART_MAX_SIBLINGS}. Recomputes the pending
|
|
1287
|
+
* nodes/links from the ORIGINAL source each call. PREVIEW ONLY — never
|
|
1288
|
+
* touches the scene or history until {@link commitFlowchart}. No-op in
|
|
1289
|
+
* read-only mode or unless exactly one element is selected.
|
|
1290
|
+
*/
|
|
1291
|
+
growFlowchart(direction: SpawnDirection): void;
|
|
1292
|
+
/**
|
|
1293
|
+
* Commit the pending flowchart-create preview: add every pending node + link
|
|
1294
|
+
* to the scene as ONE undo step, select the first new node, clear the
|
|
1295
|
+
* session. Returns the first new node's id, or `null` when no session is
|
|
1296
|
+
* active.
|
|
1297
|
+
*/
|
|
1298
|
+
commitFlowchart(): ElementId | null;
|
|
1299
|
+
/** Discard the pending flowchart-create preview without committing. */
|
|
1300
|
+
cancelFlowchart(): void;
|
|
1301
|
+
/**
|
|
1302
|
+
* The pending flowchart-create preview (nodes + links), or `null` when no
|
|
1303
|
+
* session is active. Read by the render snapshot to paint the preview on the
|
|
1304
|
+
* overlay. Reference-stable between renders (only changes on grow / commit /
|
|
1305
|
+
* cancel) so the overlay memo doesn't thrash.
|
|
1306
|
+
*/
|
|
1307
|
+
get flowchartPreview(): {
|
|
1308
|
+
readonly elements: readonly Element[];
|
|
1309
|
+
readonly links: readonly Link[];
|
|
1310
|
+
} | null;
|
|
1311
|
+
/**
|
|
1312
|
+
* Move the selection to an adjacent node. With exactly one element selected,
|
|
1313
|
+
* prefers a graph neighbour (linked node) best aligned with `direction`;
|
|
1314
|
+
* falls back to the spatial {@link selectClosest} when no neighbour lies that
|
|
1315
|
+
* way. No-op unless exactly one element is selected.
|
|
1316
|
+
*/
|
|
1317
|
+
navigateFlowchart(direction: "left" | "right" | "up" | "down"): void;
|
|
1318
|
+
/**
|
|
1319
|
+
* Live image-crop session, or `null` when not cropping. Excalidraw-style:
|
|
1320
|
+
* the crop frame IS the element's visible box, and the user drags edge /
|
|
1321
|
+
* corner handles inward (hides pixels) or the image body (pans the source).
|
|
1322
|
+
*
|
|
1323
|
+
* - `id` — the image being cropped.
|
|
1324
|
+
* - `crop` — pending normalised source rect.
|
|
1325
|
+
* - `position` / `width` / `height` — the pending element box (world position
|
|
1326
|
+
* + local size); a handle drag moves them, a body pan leaves them fixed.
|
|
1327
|
+
* - `drag` — the active gesture, or `null` when only hovering.
|
|
1328
|
+
* - `dragStartWorld` — pointer world position at drag start (body pan basis).
|
|
1329
|
+
*
|
|
1330
|
+
* Seeded on {@link beginImageCrop}; committed by {@link commitImageCrop} (one
|
|
1331
|
+
* undo step), abandoned by {@link cancelImageCrop}.
|
|
1332
|
+
*/
|
|
1333
|
+
cropSession: {
|
|
1334
|
+
id: ElementId;
|
|
1335
|
+
crop: ImageCrop;
|
|
1336
|
+
position: Vec2;
|
|
1337
|
+
width: number;
|
|
1338
|
+
height: number;
|
|
1339
|
+
drag: {
|
|
1340
|
+
kind: "handle";
|
|
1341
|
+
handle: CropHandle;
|
|
1342
|
+
} | {
|
|
1343
|
+
kind: "body";
|
|
1344
|
+
} | null;
|
|
1345
|
+
dragStartWorld: Vec2 | null;
|
|
1346
|
+
} | null;
|
|
1347
|
+
/** The image-crop session (read-only accessor for UI / overlay). */
|
|
1348
|
+
get imageCropSession(): {
|
|
1349
|
+
readonly id: ElementId;
|
|
1350
|
+
readonly crop: ImageCrop;
|
|
1351
|
+
readonly position: Vec2;
|
|
1352
|
+
readonly width: number;
|
|
1353
|
+
readonly height: number;
|
|
1354
|
+
} | null;
|
|
1355
|
+
/**
|
|
1356
|
+
* Enter crop mode for the image `id`, seeding the pending crop / box from its
|
|
1357
|
+
* current state (or the full image). No-op for non-image shapes or in
|
|
1358
|
+
* read-only. Typically triggered by a double-click on an image.
|
|
1359
|
+
*/
|
|
1360
|
+
beginImageCrop(id: ElementId): void;
|
|
1361
|
+
/**
|
|
1362
|
+
* Hit-test `worldPoint` against the pending crop chrome: a crop handle when
|
|
1363
|
+
* within {@link CROP_HANDLE_HIT_RADIUS} (screen px, zoom-compensated) of one,
|
|
1364
|
+
* `"body"` when inside the window, else `null`. Returns `null` when not
|
|
1365
|
+
* cropping.
|
|
1366
|
+
*/
|
|
1367
|
+
cropHandleAtWorld(worldPoint: Vec2): CropHandle | "body" | null;
|
|
1368
|
+
/** Begin dragging crop handle `handle` from `worldPoint`. */
|
|
1369
|
+
beginImageCropHandle(handle: CropHandle, worldPoint: Vec2): void;
|
|
1370
|
+
/** Begin panning the image body under the fixed window from `worldPoint`. */
|
|
1371
|
+
beginImageCropBody(worldPoint: Vec2): void;
|
|
1372
|
+
/**
|
|
1373
|
+
* Update the active crop drag to `worldPoint` — resize the window (handle) or
|
|
1374
|
+
* pan the source (body). Geometry is recomputed from the ORIGINAL element so
|
|
1375
|
+
* it stays stable across many moves. No-op when no drag is active.
|
|
1376
|
+
*/
|
|
1377
|
+
updateImageCropDrag(worldPoint: Vec2): void;
|
|
1378
|
+
/** Finish the current crop drag (keeps the pending crop / box). */
|
|
1379
|
+
endImageCropDrag(): void;
|
|
1380
|
+
/** Apply the pending crop + box and leave crop mode. One undo step. */
|
|
1381
|
+
commitImageCrop(): void;
|
|
1382
|
+
/** Abandon the crop session without changing the image. */
|
|
1383
|
+
cancelImageCrop(): void;
|
|
1384
|
+
/**
|
|
1385
|
+
* Synthetic element carrying the PENDING crop box (position / size) over the
|
|
1386
|
+
* original element's rotation / scale — the frame the user currently sees.
|
|
1387
|
+
* Used to project the crop frame and handles.
|
|
1388
|
+
*/
|
|
1389
|
+
private pendingCropElement;
|
|
1390
|
+
/**
|
|
1391
|
+
* World-space corners (clockwise) of the pending crop frame, or `null` when
|
|
1392
|
+
* not cropping. The frame is the pending element box mapped through its
|
|
1393
|
+
* local→world transform (so rotation / scale are honoured).
|
|
1394
|
+
*/
|
|
1395
|
+
private cropFrameCorners;
|
|
1396
|
+
/**
|
|
1397
|
+
* Ghost-image overlay descriptor for the crop session: the ORIGINAL element
|
|
1398
|
+
* (its transform + live bitmap handle) and the virtual full-image LOCAL rect
|
|
1399
|
+
* the whole bitmap occupies. `null` when not cropping. The overlay paints the
|
|
1400
|
+
* full bitmap faintly over this rect so hidden parts stay visible.
|
|
1401
|
+
*/
|
|
1402
|
+
private cropGhost;
|
|
1148
1403
|
/**
|
|
1149
1404
|
* Update non-style text properties (`fontSize`, `fontFamily`,
|
|
1150
1405
|
* `maxWidth`) on every selected text shape. Non-text shapes are
|
|
@@ -1253,6 +1508,13 @@ export declare class Editor {
|
|
|
1253
1508
|
zoomToFit(padding?: number): void;
|
|
1254
1509
|
/** Fit the camera to the current selection (standard `⌥2`). No-op when empty. */
|
|
1255
1510
|
zoomToSelection(padding?: number): void;
|
|
1511
|
+
/**
|
|
1512
|
+
* Center the camera on the current selection for a reveal / jump-to (search
|
|
1513
|
+
* navigation). Unlike {@link zoomToSelection}, it does NOT fill the screen —
|
|
1514
|
+
* a small match keeps its size and is merely centered; the zoom only drops to
|
|
1515
|
+
* fit an oversized match. No-op when the selection is empty.
|
|
1516
|
+
*/
|
|
1517
|
+
revealSelection(padding?: number): void;
|
|
1256
1518
|
/**
|
|
1257
1519
|
* Select the nearest interactable top-level element in `direction` from the
|
|
1258
1520
|
* current selection's centre (or the viewport centre when nothing is
|
|
@@ -1429,7 +1691,22 @@ export declare class Editor {
|
|
|
1429
1691
|
* selected, you can see".
|
|
1430
1692
|
*/
|
|
1431
1693
|
computeHiddenElements(): ReadonlySet<ElementId> | undefined;
|
|
1694
|
+
/**
|
|
1695
|
+
* Live stroke-erase preview: while a Shift-held eraser gesture drags, the
|
|
1696
|
+
* fragments each touched brush WOULD become, plus the set of touched
|
|
1697
|
+
* originals to hide in the main pass. `null` outside a stroke-erase gesture
|
|
1698
|
+
* or when the path touches no brush. Recomputed each frame from the
|
|
1699
|
+
* path-so-far — never mutates the scene or history.
|
|
1700
|
+
*/
|
|
1701
|
+
private computeStrokeErasePreview;
|
|
1432
1702
|
computeDimElements(enteredGroupId: ElementId): ReadonlySet<ElementId>;
|
|
1703
|
+
/**
|
|
1704
|
+
* Dim set fed to the renderer: group-isolation dim UNION the eraser's
|
|
1705
|
+
* pending-delete set (shapes swept by the current eraser stroke are shown
|
|
1706
|
+
* dimmed so the user sees what release will delete). `undefined` when neither
|
|
1707
|
+
* is active, keeping the fast tile-cache render path.
|
|
1708
|
+
*/
|
|
1709
|
+
private computeDimSet;
|
|
1433
1710
|
/**
|
|
1434
1711
|
* Enter a group — subsequent hits inside this group return children
|
|
1435
1712
|
* directly instead of the group root. `null` exits group-edit mode.
|
|
@@ -1671,6 +1948,11 @@ export declare class Editor {
|
|
|
1671
1948
|
* transaction so the whole drag is one undo step.
|
|
1672
1949
|
*/
|
|
1673
1950
|
beginWaypointDrag(linkId: LinkId, index: number, insert: boolean): void;
|
|
1951
|
+
/** Caption (label pill) drag along the selected link's path. */
|
|
1952
|
+
get isDraggingLabel(): boolean;
|
|
1953
|
+
beginLabelDrag(linkId: LinkId): void;
|
|
1954
|
+
updateLabelDrag(world: Vec2): void;
|
|
1955
|
+
endLabelDrag(): void;
|
|
1674
1956
|
/** Live update of the dragged waypoint to `world`. */
|
|
1675
1957
|
updateWaypointDrag(world: Vec2): void;
|
|
1676
1958
|
/**
|
|
@@ -1817,19 +2099,47 @@ export declare class Editor {
|
|
|
1817
2099
|
*/
|
|
1818
2100
|
runLayout(parentId: ElementId): Patch | null;
|
|
1819
2101
|
/**
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
2102
|
+
* Derived elbow-route cache, keyed by link — the source of truth for
|
|
2103
|
+
* A*-routed corners, living OUTSIDE the immutable `Scene`. Each entry holds
|
|
2104
|
+
* the routed interior `points` (between from/to) plus the `sig` of the
|
|
2105
|
+
* inputs it was computed from (endpoint refs + bound-shape bounds +
|
|
2106
|
+
* fixedSegments), so an unchanged link short-circuits the reroute.
|
|
2107
|
+
*
|
|
2108
|
+
* `rerouteElbows` still MIRRORS `points` onto `Link.routedPoints` in
|
|
2109
|
+
* `_scene` because three readers still consume the baked field: the render
|
|
2110
|
+
* path (`getLinkPath` in `renderer-core`), the headless `getLinkPath`, and
|
|
2111
|
+
* serialization (`schema.ts`). The mirror is compat-only derived state — no
|
|
2112
|
+
* history push / notify.
|
|
2113
|
+
*
|
|
2114
|
+
* TODO(fable R7a): drop the `_scene` mirror once (a) the render path reads
|
|
2115
|
+
* routes from this cache via the `RenderSnapshot`, and (b) headless
|
|
2116
|
+
* `getLinkPath` / serialization stop depending on baked `routedPoints`.
|
|
2117
|
+
* That eviction changes headless geometry, serialized output, and
|
|
2118
|
+
* collab-synced fields, so it spans the scene / serialization / renderer /
|
|
2119
|
+
* headless goldens and must land as its own cross-package change — out of
|
|
2120
|
+
* scope for this state-only pass.
|
|
2121
|
+
*/
|
|
2122
|
+
private readonly elbowRoutes;
|
|
2123
|
+
/**
|
|
2124
|
+
* Choke-point reroute (standard model): recompute the route for every
|
|
2125
|
+
* orthogonal link whose inputs changed since the last pass, store it in the
|
|
2126
|
+
* derived {@link elbowRoutes} cache, and mirror it onto `_scene`. Runs once
|
|
2127
|
+
* per frame before paint — derived state, so no history push / notify (would
|
|
2128
|
+
* loop). Cheap when nothing moved (signature short-circuit).
|
|
1823
2129
|
*/
|
|
1824
|
-
private
|
|
2130
|
+
private rerouteElbows;
|
|
1825
2131
|
/**
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
-
*
|
|
1830
|
-
*
|
|
2132
|
+
* Collect everything {@link renderEditor} paints from into a flat
|
|
2133
|
+
* {@link RenderSnapshot}. Resolves the derived viewport / dirty-rect / dim /
|
|
2134
|
+
* hide inputs and the shared spatial index up front (same order the
|
|
2135
|
+
* orchestrator used to call them in), so the paint pass stays side-effect
|
|
2136
|
+
* free and the orchestrator stays decoupled from this class.
|
|
2137
|
+
*
|
|
2138
|
+
* `computeDirtyWorld` is order-sensitive (it diffs against
|
|
2139
|
+
* `lastRenderedScene` and populates `tileDirtyElements`); it runs here and
|
|
2140
|
+
* the `lastRendered*` bookkeeping is applied in `render()` after the paint.
|
|
1831
2141
|
*/
|
|
1832
|
-
private
|
|
2142
|
+
private buildRenderSnapshot;
|
|
1833
2143
|
private render;
|
|
1834
2144
|
}
|
|
1835
2145
|
/** Distance from point `p` to the finite segment `a`–`b` (world space). */
|