@oh-just-another/state 0.58.0 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +158 -0
- package/README.md +78 -27
- package/dist/.tsbuildinfo +1 -1
- package/dist/actions/actionArrange.d.ts +13 -0
- package/dist/actions/actionArrange.d.ts.map +1 -0
- package/dist/actions/actionArrange.js +130 -0
- package/dist/actions/actionArrange.js.map +1 -0
- package/dist/actions/actionClipboard.d.ts +2 -0
- package/dist/actions/actionClipboard.d.ts.map +1 -1
- package/dist/actions/actionClipboard.js +32 -1
- package/dist/actions/actionClipboard.js.map +1 -1
- package/dist/actions/actionKeyboard.d.ts.map +1 -1
- package/dist/actions/actionKeyboard.js +77 -9
- package/dist/actions/actionKeyboard.js.map +1 -1
- package/dist/actions/actionMode.d.ts +4 -0
- package/dist/actions/actionMode.d.ts.map +1 -1
- package/dist/actions/actionMode.js +54 -0
- 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/actionText.d.ts +5 -0
- package/dist/actions/actionText.d.ts.map +1 -0
- package/dist/actions/actionText.js +37 -0
- package/dist/actions/actionText.js.map +1 -0
- package/dist/actions/actionView.d.ts +6 -0
- package/dist/actions/actionView.d.ts.map +1 -1
- package/dist/actions/actionView.js +20 -2
- 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 +6 -4
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +6 -4
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/registry.d.ts.map +1 -1
- package/dist/actions/registry.js +17 -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/auto-layout-scheduler.d.ts +1 -3
- package/dist/auto-layout-scheduler.d.ts.map +1 -1
- package/dist/auto-layout-scheduler.js +1 -2
- package/dist/auto-layout-scheduler.js.map +1 -1
- package/dist/built-in-handlers.d.ts.map +1 -1
- package/dist/built-in-handlers.js +14 -1
- 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 +208 -41
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +210 -25
- package/dist/constants.js.map +1 -1
- package/dist/dom-events.d.ts +8 -2
- package/dist/dom-events.d.ts.map +1 -1
- package/dist/dom-events.js +12 -0
- package/dist/dom-events.js.map +1 -1
- package/dist/editor/animation-scene.d.ts +36 -0
- package/dist/editor/animation-scene.d.ts.map +1 -0
- package/dist/editor/animation-scene.js +194 -0
- package/dist/editor/animation-scene.js.map +1 -0
- package/dist/editor/animation.d.ts +43 -0
- package/dist/editor/animation.d.ts.map +1 -0
- package/dist/editor/animation.js +80 -0
- package/dist/editor/animation.js.map +1 -0
- package/dist/editor/applies/arrange.d.ts +46 -0
- package/dist/editor/applies/arrange.d.ts.map +1 -0
- package/dist/editor/applies/arrange.js +162 -0
- package/dist/editor/applies/arrange.js.map +1 -0
- 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/edge.d.ts +8 -1
- package/dist/editor/applies/edge.d.ts.map +1 -1
- package/dist/editor/applies/edge.js +31 -1
- package/dist/editor/applies/edge.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/applies/move.d.ts +6 -0
- package/dist/editor/applies/move.d.ts.map +1 -1
- package/dist/editor/applies/move.js +6 -0
- package/dist/editor/applies/move.js.map +1 -1
- package/dist/editor/applies/resize.d.ts +26 -5
- package/dist/editor/applies/resize.d.ts.map +1 -1
- package/dist/editor/applies/resize.js +91 -13
- package/dist/editor/applies/resize.js.map +1 -1
- package/dist/editor/caret-blink.d.ts +18 -0
- package/dist/editor/caret-blink.d.ts.map +1 -0
- package/dist/editor/caret-blink.js +42 -0
- package/dist/editor/caret-blink.js.map +1 -0
- package/dist/editor/container-ops.d.ts.map +1 -1
- package/dist/editor/container-ops.js +2 -2
- package/dist/editor/container-ops.js.map +1 -1
- package/dist/editor/dirty-rect.d.ts +23 -0
- package/dist/editor/dirty-rect.d.ts.map +1 -0
- package/dist/editor/dirty-rect.js +115 -0
- package/dist/editor/dirty-rect.js.map +1 -0
- package/dist/editor/gif-playback.d.ts +45 -0
- package/dist/editor/gif-playback.d.ts.map +1 -0
- package/dist/editor/gif-playback.js +125 -0
- package/dist/editor/gif-playback.js.map +1 -0
- package/dist/editor/hit-test.d.ts +3 -3
- package/dist/editor/hit-test.d.ts.map +1 -1
- package/dist/editor/hit-test.js +40 -15
- 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 +152 -0
- package/dist/editor/link-handle-drag.d.ts.map +1 -0
- package/dist/editor/link-handle-drag.js +300 -0
- package/dist/editor/link-handle-drag.js.map +1 -0
- package/dist/editor/long-press.d.ts.map +1 -1
- package/dist/editor/long-press.js +2 -2
- package/dist/editor/long-press.js.map +1 -1
- package/dist/editor/pinch.d.ts.map +1 -1
- package/dist/editor/pinch.js +6 -6
- package/dist/editor/pinch.js.map +1 -1
- 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 +1191 -890
- package/dist/editor/pointer-binding.js.map +1 -1
- package/dist/editor/public/arrange-group.d.ts +3 -9
- package/dist/editor/public/arrange-group.d.ts.map +1 -1
- package/dist/editor/public/arrange-group.js +4 -6
- package/dist/editor/public/arrange-group.js.map +1 -1
- package/dist/editor/public/brush.d.ts +31 -12
- package/dist/editor/public/brush.d.ts.map +1 -1
- package/dist/editor/public/brush.js +66 -17
- package/dist/editor/public/brush.js.map +1 -1
- package/dist/editor/public/clipboard.d.ts +2 -4
- package/dist/editor/public/clipboard.d.ts.map +1 -1
- package/dist/editor/public/clipboard.js +2 -4
- package/dist/editor/public/clipboard.js.map +1 -1
- package/dist/editor/public/cursor.d.ts +29 -0
- package/dist/editor/public/cursor.d.ts.map +1 -0
- package/dist/editor/public/cursor.js +146 -0
- package/dist/editor/public/cursor.js.map +1 -0
- 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/frame-name.d.ts +20 -0
- package/dist/editor/public/frame-name.d.ts.map +1 -0
- package/dist/editor/public/frame-name.js +54 -0
- package/dist/editor/public/frame-name.js.map +1 -0
- package/dist/editor/public/image-insert.d.ts +1 -1
- package/dist/editor/public/image-insert.d.ts.map +1 -1
- 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/layers.d.ts.map +1 -1
- package/dist/editor/public/layers.js +2 -2
- package/dist/editor/public/layers.js.map +1 -1
- package/dist/editor/public/link.d.ts +11 -2
- package/dist/editor/public/link.d.ts.map +1 -1
- package/dist/editor/public/link.js +70 -2
- package/dist/editor/public/link.js.map +1 -1
- package/dist/editor/public/placement.d.ts +60 -2
- package/dist/editor/public/placement.d.ts.map +1 -1
- package/dist/editor/public/placement.js +193 -2
- package/dist/editor/public/placement.js.map +1 -1
- package/dist/editor/public/selection-ops.d.ts +35 -1
- package/dist/editor/public/selection-ops.d.ts.map +1 -1
- package/dist/editor/public/selection-ops.js +97 -2
- 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/text-edit.d.ts +1 -10
- package/dist/editor/public/text-edit.d.ts.map +1 -1
- package/dist/editor/public/text-edit.js +2 -16
- package/dist/editor/public/text-edit.js.map +1 -1
- 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 +5 -5
- package/dist/editor/public/z-order.js.map +1 -1
- package/dist/editor/public/zoom-pan.d.ts +15 -4
- package/dist/editor/public/zoom-pan.d.ts.map +1 -1
- package/dist/editor/public/zoom-pan.js +39 -7
- package/dist/editor/public/zoom-pan.js.map +1 -1
- package/dist/editor/render-orchestrator.d.ts +177 -5
- package/dist/editor/render-orchestrator.d.ts.map +1 -1
- package/dist/editor/render-orchestrator.js +519 -358
- package/dist/editor/render-orchestrator.js.map +1 -1
- package/dist/editor/resize-helpers.d.ts +21 -5
- package/dist/editor/resize-helpers.d.ts.map +1 -1
- package/dist/editor/resize-helpers.js +59 -19
- package/dist/editor/resize-helpers.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/viewport-helpers.d.ts.map +1 -1
- package/dist/editor/viewport-helpers.js +3 -3
- package/dist/editor/viewport-helpers.js.map +1 -1
- package/dist/editor-events.d.ts +1 -1
- package/dist/editor-events.d.ts.map +1 -1
- package/dist/editor.d.ts +603 -346
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1843 -1630
- package/dist/editor.js.map +1 -1
- package/dist/file-drop.d.ts.map +1 -1
- package/dist/file-drop.js +1 -2
- package/dist/file-drop.js.map +1 -1
- package/dist/frame-helpers.d.ts.map +1 -1
- package/dist/frame-helpers.js +5 -5
- package/dist/frame-helpers.js.map +1 -1
- package/dist/group-helpers.d.ts.map +1 -1
- package/dist/group-helpers.js +4 -4
- package/dist/group-helpers.js.map +1 -1
- package/dist/handle.d.ts +59 -6
- package/dist/handle.d.ts.map +1 -1
- package/dist/handle.js +99 -7
- package/dist/handle.js.map +1 -1
- package/dist/hotkeys-binding.d.ts +26 -0
- package/dist/hotkeys-binding.d.ts.map +1 -0
- package/dist/hotkeys-binding.js +35 -0
- package/dist/hotkeys-binding.js.map +1 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/link-selection.d.ts +3 -5
- package/dist/link-selection.d.ts.map +1 -1
- package/dist/link-selection.js +3 -12
- package/dist/link-selection.js.map +1 -1
- package/dist/machine.d.ts +27 -1
- package/dist/machine.d.ts.map +1 -1
- package/dist/machine.js +38 -0
- package/dist/machine.js.map +1 -1
- package/dist/modes.d.ts +15 -1
- package/dist/modes.d.ts.map +1 -1
- package/dist/modes.js.map +1 -1
- package/dist/overlay.d.ts +92 -6
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +582 -125
- 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/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +2 -10
- package/dist/selection.js.map +1 -1
- package/dist/util.d.ts +8 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +17 -0
- package/dist/util.js.map +1 -0
- package/package.json +7 -7
package/dist/editor.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
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
10
|
import type { Mode } from "./modes.js";
|
|
11
11
|
import type { EditorEvents } from "./editor-events.js";
|
|
12
|
+
import { GifPlaybackController } from "./editor/gif-playback.js";
|
|
12
13
|
import { LongPressController } from "./editor/long-press.js";
|
|
13
14
|
import { PinchController } from "./editor/pinch.js";
|
|
14
|
-
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";
|
|
19
|
+
import type { CursorRole, CursorSpec } from "./editor/public/cursor.js";
|
|
20
|
+
import { type ConvertTarget, type CropHandle, type SpawnDirection } from "./editor/public/tool-ops.js";
|
|
21
|
+
import { type AlignEdge, type DistributeAxis, type FlipAxis } from "./editor/applies/arrange.js";
|
|
15
22
|
import { type PeerCursor, type PeerSelection } from "./overlay.js";
|
|
16
23
|
import * as Selection from "./selection.js";
|
|
17
24
|
import * as LinkSelection from "./link-selection.js";
|
|
@@ -50,10 +57,17 @@ export interface EditorOptions {
|
|
|
50
57
|
readonly onAfterRender?: () => void;
|
|
51
58
|
readonly initialScene: Scene;
|
|
52
59
|
readonly initialMode?: 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;
|
|
53
67
|
/**
|
|
54
68
|
* Pre-existing history backend, or options for the default
|
|
55
69
|
* `History` (linear stack). Any `HistoryProvider` implementation
|
|
56
|
-
* works — `@oh-just-another/collab` ships `
|
|
70
|
+
* works — `@oh-just-another/collab` ships `CollabHistory` that wraps
|
|
57
71
|
* `Y.UndoManager` for CRDT-aware undo in collaborative sessions.
|
|
58
72
|
*/
|
|
59
73
|
readonly history?: HistoryProvider | HistoryOptions;
|
|
@@ -124,6 +138,15 @@ export type TileComposeFn = (scene: Scene, mainTarget: RenderTarget, options: {
|
|
|
124
138
|
after: Bounds | null;
|
|
125
139
|
}>;
|
|
126
140
|
readonly zoomBucket: number;
|
|
141
|
+
/**
|
|
142
|
+
* Persistent spatial index over the scene's current element world-AABBs,
|
|
143
|
+
* when the editor maintains one (large scenes, shared with the hit-test
|
|
144
|
+
* path). A tile compositor that supports it (`renderViaTiles`) queries the
|
|
145
|
+
* index for per-tile element selection instead of scanning every shape in
|
|
146
|
+
* every layer. Omitted for small scenes; compositors must fall back to a
|
|
147
|
+
* full scan when absent.
|
|
148
|
+
*/
|
|
149
|
+
readonly index?: SpatialGrid;
|
|
127
150
|
}) => void;
|
|
128
151
|
/**
|
|
129
152
|
* Top-level interaction controller. Owns the scene + selection state, wires
|
|
@@ -138,29 +161,7 @@ export type GroupSelectedResult = {
|
|
|
138
161
|
readonly kind: "grouped";
|
|
139
162
|
readonly groupId: ElementId;
|
|
140
163
|
};
|
|
141
|
-
|
|
142
|
-
* Stable keys for cursor states a host can override with a custom image via
|
|
143
|
-
* {@link Editor.setCursorOverride}. Each maps to one outcome of `computeCursor`.
|
|
144
|
-
*/
|
|
145
|
-
export type CursorRole = "default" | "pan-ready" | "pan-active" | "move" | "draw" | "text" | "link-start" | "link-handle" | "annotation" | "resize-nwse" | "resize-nesw" | "resize-ns" | "resize-ew";
|
|
146
|
-
/**
|
|
147
|
-
* A custom cursor: either a raw CSS `cursor` value, or an image with an
|
|
148
|
-
* optional `@2x` variant (DPR-aware via `image-set`), hotspot, and keyword
|
|
149
|
-
* fallback.
|
|
150
|
-
*/
|
|
151
|
-
export type CursorSpec = string | {
|
|
152
|
-
/** 1x image URL or data-URL. */
|
|
153
|
-
readonly url: string;
|
|
154
|
-
/** Optional 2x image for hi-DPI (retina) — emitted via `image-set`. */
|
|
155
|
-
readonly url2x?: string;
|
|
156
|
-
/** Hotspot offset (px) within the image; defaults to (0, 0). */
|
|
157
|
-
readonly hotspot?: {
|
|
158
|
-
readonly x: number;
|
|
159
|
-
readonly y: number;
|
|
160
|
-
};
|
|
161
|
-
/** Keyword shown if the image can't load / is too large. */
|
|
162
|
-
readonly fallback?: string;
|
|
163
|
-
};
|
|
164
|
+
export type { CursorRole, CursorSpec };
|
|
164
165
|
export declare class Editor {
|
|
165
166
|
readonly host: HTMLElement;
|
|
166
167
|
readonly mainTarget: RenderTarget;
|
|
@@ -175,11 +176,14 @@ export declare class Editor {
|
|
|
175
176
|
*/
|
|
176
177
|
debugHitZones: boolean;
|
|
177
178
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
179
|
+
* Read-only / view mode. When true the pointer paths that create,
|
|
180
|
+
* move, resize, rotate or delete are gated (pan / zoom / select stay
|
|
181
|
+
* live) and the action registry only runs actions flagged
|
|
182
|
+
* `viewMode`. View-only — never persisted or recorded in history.
|
|
183
|
+
* Read via {@link readOnly}; flip via {@link setReadOnly}.
|
|
180
184
|
*/
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
private _readOnly;
|
|
186
|
+
actor: Actor<typeof interactionMachine>;
|
|
183
187
|
private readonly listeners;
|
|
184
188
|
/**
|
|
185
189
|
* Typed event surface. Specific events (`mode`, `selection`,
|
|
@@ -193,7 +197,7 @@ export declare class Editor {
|
|
|
193
197
|
private readonly events;
|
|
194
198
|
/**
|
|
195
199
|
* Last-emitted snapshot of every observable slice. Used by
|
|
196
|
-
* `fanOutEvents`
|
|
200
|
+
* `fanOutEvents` to decide which
|
|
197
201
|
* typed events to fire on each `notify()` — only the slices
|
|
198
202
|
* whose identity changed since the previous notify get an event.
|
|
199
203
|
*/
|
|
@@ -202,74 +206,31 @@ export declare class Editor {
|
|
|
202
206
|
_scene: Scene;
|
|
203
207
|
_selection: Selection.Selection;
|
|
204
208
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
+
* Ephemeral interaction / gesture state (previews, gesture origins,
|
|
210
|
+
* transient modifiers). Single source of truth for the short-lived fields
|
|
211
|
+
* the pointer handlers, render orchestrator and container-ops read/write
|
|
212
|
+
* while a gesture is in flight. The public fields below delegate to it so
|
|
213
|
+
* external writers keep referencing `editor.<field>` unchanged.
|
|
209
214
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
moved: boolean;
|
|
215
|
-
} | null;
|
|
215
|
+
readonly interaction: InteractionState;
|
|
216
|
+
/** Snapshot of an in-progress annotation-pin drag. */
|
|
217
|
+
get annotationDrag(): AnnotationDrag | null;
|
|
218
|
+
set annotationDrag(v: AnnotationDrag | null);
|
|
216
219
|
/** Live preview while drawing a new shape; null when not drawing. */
|
|
217
|
-
drawingPreview: Bounds | null;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
* during the drag). Null when no such drag is in flight. */
|
|
232
|
-
linkDragFromAnchor: {
|
|
233
|
-
fromElement: ElementId;
|
|
234
|
-
fromWorld: Vec2;
|
|
235
|
-
/** Named anchor the gesture started on — drives the click-to-create
|
|
236
|
-
* direction (outward normal) and the source link endpoint. */
|
|
237
|
-
anchorName: string;
|
|
238
|
-
origin: Vec2;
|
|
239
|
-
moved: boolean;
|
|
240
|
-
} | null;
|
|
241
|
-
/**
|
|
242
|
-
* Element being hovered while draw-edge mode is active. Drives the port-
|
|
243
|
-
* overlay render so the user sees attachment points. `null` outside
|
|
244
|
-
* draw-edge mode or when the pointer is over empty canvas.
|
|
245
|
-
*/
|
|
246
|
-
hoveredLinkTarget: {
|
|
247
|
-
elementId: ElementId;
|
|
248
|
-
activeAnchor: string | null;
|
|
249
|
-
outlinePoint?: Vec2 | undefined;
|
|
250
|
-
/**
|
|
251
|
-
* What the drop will produce, for clear pre-drop feedback (standard):
|
|
252
|
-
* - `"point"` → fixed attach to a specific dot (highlight the dot);
|
|
253
|
-
* - `"element"` → floating attach to the whole shape (highlight the
|
|
254
|
-
* element). Mirrors `snapLinkEndpoint`: an anchor within threshold →
|
|
255
|
-
* point, otherwise floating.
|
|
256
|
-
*/
|
|
257
|
-
mode: "point" | "element";
|
|
258
|
-
} | null;
|
|
259
|
-
/**
|
|
260
|
-
* Last idle cursor position (world) in select mode — the overlay grows the
|
|
261
|
-
* SINGLE selected element's link-start dot nearest it
|
|
262
|
-
* (`ANCHOR_DOT_HOVER_GROW_RADIUS`). Reset to null on press / gesture.
|
|
263
|
-
*/
|
|
264
|
-
hoverCursorWorld: Vec2 | null;
|
|
265
|
-
/**
|
|
266
|
-
* When a link is dropped on empty canvas, the edge is created with a
|
|
267
|
-
* free `point` end and this records where, so the host can pop a
|
|
268
|
-
* mini shape-picker at that spot (standard). Picking a shape re-points the
|
|
269
|
-
* end to the new element; dismissing (Esc / click-away) leaves the free
|
|
270
|
-
* end on the canvas. `null` when no menu is pending.
|
|
271
|
-
*/
|
|
272
|
-
private pendingLinkDropMenu;
|
|
220
|
+
get drawingPreview(): Bounds | null;
|
|
221
|
+
set drawingPreview(v: Bounds | null);
|
|
222
|
+
/** Live preview of an edge being drawn. */
|
|
223
|
+
get edgePreview(): EdgePreview | null;
|
|
224
|
+
set edgePreview(v: EdgePreview | null);
|
|
225
|
+
/** Active "drag a link from a start-anchor" gesture. */
|
|
226
|
+
get linkDragFromAnchor(): LinkDragFromAnchor | null;
|
|
227
|
+
set linkDragFromAnchor(v: LinkDragFromAnchor | null);
|
|
228
|
+
/** Element hovered while draw-edge mode is active (drives the port overlay). */
|
|
229
|
+
get hoveredLinkTarget(): HoveredLinkTarget | null;
|
|
230
|
+
set hoveredLinkTarget(v: HoveredLinkTarget | null);
|
|
231
|
+
/** Last idle cursor position (world) in select mode — grows the nearest dot. */
|
|
232
|
+
get hoverCursorWorld(): Vec2 | null;
|
|
233
|
+
set hoverCursorWorld(v: Vec2 | null);
|
|
273
234
|
/**
|
|
274
235
|
* Currently selected links (connectors). Links are first-class members
|
|
275
236
|
* of the selection: they coexist with selected elements, join Cmd+A and
|
|
@@ -295,8 +256,9 @@ export declare class Editor {
|
|
|
295
256
|
/**
|
|
296
257
|
* Mid-drag preview state when the user is dragging an edge endpoint.
|
|
297
258
|
* Drawn as an overlay line + handle dot so the user sees the target.
|
|
259
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
298
260
|
*/
|
|
299
|
-
linkEndpointDrag: {
|
|
261
|
+
get linkEndpointDrag(): {
|
|
300
262
|
linkId: LinkId;
|
|
301
263
|
side: "from" | "to";
|
|
302
264
|
toPoint: Vec2;
|
|
@@ -307,70 +269,40 @@ export declare class Editor {
|
|
|
307
269
|
* began on a segment midpoint and will splice a new waypoint on the
|
|
308
270
|
* first move (so a no-move click adds nothing). Live-mutated through the
|
|
309
271
|
* gesture transaction → one undo step per drag.
|
|
272
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
310
273
|
*/
|
|
311
|
-
linkWaypointDrag: {
|
|
274
|
+
get linkWaypointDrag(): {
|
|
312
275
|
linkId: LinkId;
|
|
313
276
|
index: number;
|
|
314
277
|
pendingInsert: boolean;
|
|
315
278
|
} | null;
|
|
316
279
|
/**
|
|
317
|
-
* Host-managed elbow segment drag. `
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
280
|
+
* Host-managed elbow segment drag. `axis` is the segment's orientation.
|
|
281
|
+
* Dragging pins the segment's perpendicular coordinate into
|
|
282
|
+
* `Link.fixedSegments`; the reroute pass re-flows the rest. One undo
|
|
283
|
+
* step via the gesture tx.
|
|
284
|
+
* State lives in `LinkHandleDragController`; this is a delegate.
|
|
321
285
|
*/
|
|
322
|
-
linkSegmentDrag: {
|
|
286
|
+
get linkSegmentDrag(): {
|
|
323
287
|
linkId: LinkId;
|
|
324
288
|
axis: "h" | "v";
|
|
325
289
|
at: number;
|
|
326
290
|
} | null;
|
|
327
291
|
/** Live lasso bounds during a rubber-band select gesture. */
|
|
328
|
-
lassoPreview: Bounds | null;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
* fans out when this map is populated.
|
|
343
|
-
*/
|
|
344
|
-
groupMoveOrigin: ReadonlyMap<ElementId, Vec2> | null;
|
|
345
|
-
/**
|
|
346
|
-
* Press-time snapshot of connectors that must follow a multi-element
|
|
347
|
-
* drag rigidly — both endpoints bound to moved elements, carrying
|
|
348
|
-
* absolute geometry (waypoints / fixedSegments / routedPoints). Each
|
|
349
|
-
* frame translates from these originals so the shift never compounds.
|
|
350
|
-
* Cleared on gesture commit / cancel alongside `groupMoveOrigin`.
|
|
351
|
-
*/
|
|
352
|
-
groupLinkMoveOrigin: ReadonlyMap<LinkId, Link> | null;
|
|
353
|
-
/**
|
|
354
|
-
* Per-shape snapshot for a group-resize gesture — `bounds` is the
|
|
355
|
-
* shape's world AABB at press-down. Editor scales the relative
|
|
356
|
-
* position / size against the combined bounds delta each frame.
|
|
357
|
-
*/
|
|
358
|
-
groupResizeOrigin: {
|
|
359
|
-
readonly combined: Bounds;
|
|
360
|
-
readonly elements: ReadonlyMap<ElementId, {
|
|
361
|
-
readonly position: Vec2;
|
|
362
|
-
readonly bounds: Bounds;
|
|
363
|
-
readonly scale: Vec2;
|
|
364
|
-
}>;
|
|
365
|
-
readonly links: ReadonlyMap<LinkId, Link>;
|
|
366
|
-
} | null;
|
|
367
|
-
/**
|
|
368
|
-
* Pristine shape snapshot for a single-shape text resize, captured on
|
|
369
|
-
* the gesture's first tick. Font scaling is computed against this base
|
|
370
|
-
* so it never compounds across pointermove ticks. Cleared on gesture
|
|
371
|
-
* end (commit / cancel).
|
|
372
|
-
*/
|
|
373
|
-
private _resizeOriginElement;
|
|
292
|
+
get lassoPreview(): Bounds | null;
|
|
293
|
+
set lassoPreview(v: Bounds | null);
|
|
294
|
+
/** Snapshot of every selected shape's `position` at press-down (multi-drag). */
|
|
295
|
+
get groupMoveOrigin(): ReadonlyMap<ElementId, Vec2> | null;
|
|
296
|
+
set groupMoveOrigin(v: ReadonlyMap<ElementId, Vec2> | null);
|
|
297
|
+
/** Press-time snapshot of connectors that follow a multi-element drag rigidly. */
|
|
298
|
+
get groupLinkMoveOrigin(): ReadonlyMap<LinkId, Link> | null;
|
|
299
|
+
set groupLinkMoveOrigin(v: ReadonlyMap<LinkId, Link> | null);
|
|
300
|
+
/** Per-shape snapshot for a group-resize gesture. */
|
|
301
|
+
get groupResizeOrigin(): GroupResizeOrigin | null;
|
|
302
|
+
set groupResizeOrigin(v: GroupResizeOrigin | null);
|
|
303
|
+
/** Press-time snapshot for a rotate gesture. */
|
|
304
|
+
get rotateGestureOrigin(): RotateGestureOrigin | null;
|
|
305
|
+
set rotateGestureOrigin(v: RotateGestureOrigin | null);
|
|
374
306
|
/**
|
|
375
307
|
* Active layer — new shapes created via `addElement` / `applyCreate` land
|
|
376
308
|
* here when their input doesn't specify a `layerId`. Defaults to the
|
|
@@ -387,12 +319,11 @@ export declare class Editor {
|
|
|
387
319
|
/** Snap threshold in world units. */
|
|
388
320
|
private readonly snapThreshold;
|
|
389
321
|
/**
|
|
390
|
-
*
|
|
391
|
-
* (
|
|
392
|
-
*
|
|
393
|
-
* move / resize / create wrappers; never persisted.
|
|
322
|
+
* In-editor style memory for copy-style / paste-style. Holds the visual
|
|
323
|
+
* `style` (fill / stroke / dash / …) captured from a shape; `null` until a
|
|
324
|
+
* copy happens. Not the OS clipboard — a lightweight per-editor buffer.
|
|
394
325
|
*/
|
|
395
|
-
private
|
|
326
|
+
private styleClipboard;
|
|
396
327
|
/**
|
|
397
328
|
* Persistent world-bounds cache shared with `renderScene` for viewport
|
|
398
329
|
* culling. Object-identity keyed — invalidates automatically whenever
|
|
@@ -414,36 +345,37 @@ export declare class Editor {
|
|
|
414
345
|
* escape, click outside the group's descendants, or `cancelInteraction`.
|
|
415
346
|
*/
|
|
416
347
|
_enteredGroup: ElementId | null;
|
|
417
|
-
/**
|
|
418
|
-
* Double-click detection state. Updated on every non-drag pointer
|
|
419
|
-
* up; the next pointer-up within `DOUBLE_CLICK_MS` and within
|
|
420
|
-
* `DOUBLE_CLICK_TOLERANCE_PX` of `lastClickWorldPoint` counts as a
|
|
421
|
-
* double-click. Used to trigger group drill-down (enter isolation).
|
|
422
|
-
*/
|
|
423
|
-
private lastClickAt;
|
|
424
|
-
private lastClickWorldPoint;
|
|
425
|
-
/**
|
|
426
|
-
* Separate double-click tracker for link edit handles (waypoint /
|
|
427
|
-
* segment). Kept apart from `lastClickAt` because a handle press
|
|
428
|
-
* returns early in `onDown` (begin-drag) and never reaches the up-side
|
|
429
|
-
* double-click path that updates `lastClickAt`. Updated by
|
|
430
|
-
* `isHandleDoubleClick` on each handle press.
|
|
431
|
-
*/
|
|
432
|
-
private lastHandleClickAt;
|
|
433
|
-
private lastHandleClickWorld;
|
|
434
348
|
/**
|
|
435
349
|
* In-progress brush stroke. Hosts push points via
|
|
436
350
|
* `extendBrushStroke`; the overlay reads it through
|
|
437
351
|
* `pendingBrushStroke` to draw a live preview.
|
|
438
352
|
*/
|
|
439
|
-
brushStroke: BrushStrokeState | null;
|
|
353
|
+
get brushStroke(): BrushStrokeState | null;
|
|
354
|
+
set brushStroke(v: BrushStrokeState | null);
|
|
355
|
+
/**
|
|
356
|
+
* The in-progress brush stroke with its captured vertices Catmull-Rom-smoothed
|
|
357
|
+
* for the LIVE overlay preview — the SAME resampler `commitBrushStroke` applies
|
|
358
|
+
* on release (see {@link smoothBrushPoints}), so the stroke reads smooth while
|
|
359
|
+
* drawn instead of snapping from an angular polyline to a curve on release. A
|
|
360
|
+
* fresh object each call (points diverge from `brushStroke.points`), so the
|
|
361
|
+
* overlay memo repaints every move that grows the stroke.
|
|
362
|
+
*/
|
|
363
|
+
private get brushPreviewStroke();
|
|
364
|
+
/** In-progress eraser stroke (pending-delete set), or null between strokes. */
|
|
365
|
+
get eraseStroke(): EraseStrokeState | null;
|
|
366
|
+
set eraseStroke(v: EraseStrokeState | null);
|
|
367
|
+
/** Ids swept by the current eraser stroke — previewed dimmed, deleted on release. */
|
|
368
|
+
get pendingErase(): ReadonlySet<ElementId>;
|
|
369
|
+
/** Live laser-pointer trails (ephemeral, fading). Empty when none active. */
|
|
370
|
+
get laserStrokes(): readonly LaserStroke[];
|
|
440
371
|
/**
|
|
441
372
|
* Last world-space pointer position observed by the host's onMove
|
|
442
373
|
* handler. `paste()` uses it as the default drop target so a fresh
|
|
443
374
|
* paste lands under the cursor instead of overlapping the originals.
|
|
444
375
|
* `null` until the pointer first enters the host.
|
|
445
376
|
*/
|
|
446
|
-
lastPointerWorld: Vec2 | null;
|
|
377
|
+
get lastPointerWorld(): Vec2 | null;
|
|
378
|
+
set lastPointerWorld(v: Vec2 | null);
|
|
447
379
|
/** Host-registered custom cursor images per role (see `setCursorOverride`). */
|
|
448
380
|
private readonly cursorOverrides;
|
|
449
381
|
/**
|
|
@@ -462,17 +394,32 @@ export declare class Editor {
|
|
|
462
394
|
* pass would never visibly apply.
|
|
463
395
|
*/
|
|
464
396
|
lastRenderedEnteredGroup: ElementId | null;
|
|
397
|
+
/**
|
|
398
|
+
* Whether the last paint had eraser-dim active — paired with
|
|
399
|
+
* `lastRenderedScene` like {@link lastRenderedEnteredGroup}. When an eraser
|
|
400
|
+
* stroke ENDS by cancel (Esc), the marked shapes un-dim without a scene
|
|
401
|
+
* change, so the dirty-rect diff is empty and the dim would linger on screen;
|
|
402
|
+
* this lets that active→inactive transition force one full repaint.
|
|
403
|
+
*/
|
|
404
|
+
lastRenderedEraseActive: boolean;
|
|
405
|
+
/**
|
|
406
|
+
* Set whenever an eraser move actually CHANGES the marked / cut set (a new
|
|
407
|
+
* shape marked, un-marked, or a brush point cut). Gates the forced full
|
|
408
|
+
* repaint during erasing: only the frames that change the preview repaint the
|
|
409
|
+
* whole scene; a slowly-moving or stopped cursor over already-covered area
|
|
410
|
+
* skips the expensive main pass (only the overlay cursor / trail refresh).
|
|
411
|
+
* Cleared after each paint.
|
|
412
|
+
*/
|
|
413
|
+
private eraseDirty;
|
|
465
414
|
/**
|
|
466
415
|
* Fractional-order compaction scheduler (microtask-coalesced).
|
|
467
416
|
* Triggered from every `notify()`; only does real work when at
|
|
468
417
|
* least one shape/edge order string crossed AUTO_COMPACT_THRESHOLD.
|
|
469
|
-
* See `./auto-compact.ts` for the extracted logic.
|
|
470
418
|
*/
|
|
471
419
|
private readonly autoCompactScheduler;
|
|
472
420
|
/**
|
|
473
421
|
* Auto-layout scheduler — microtask-coalesced re-run of every
|
|
474
|
-
* shape carrying `metadata.autoLayout`.
|
|
475
|
-
* `./auto-layout-scheduler.ts` for the extracted logic.
|
|
422
|
+
* shape carrying `metadata.autoLayout`.
|
|
476
423
|
*/
|
|
477
424
|
private readonly autoLayoutScheduler;
|
|
478
425
|
/**
|
|
@@ -482,7 +429,8 @@ export declare class Editor {
|
|
|
482
429
|
* gestures, set in onDown when press lands on a shape and cleared
|
|
483
430
|
* in onUp / cancel.
|
|
484
431
|
*/
|
|
485
|
-
dragElementId: ElementId | null;
|
|
432
|
+
get dragElementId(): ElementId | null;
|
|
433
|
+
set dragElementId(v: ElementId | null);
|
|
486
434
|
/**
|
|
487
435
|
* Element that the current press added to the selection additively
|
|
488
436
|
* (shift / meta click on an unselected shape). The press promotes it
|
|
@@ -490,17 +438,16 @@ export declare class Editor {
|
|
|
490
438
|
* otherwise `SELECT_TOGGLE` it straight back off, so it consults this
|
|
491
439
|
* to skip that redundant toggle. Reset at every press-down.
|
|
492
440
|
*/
|
|
493
|
-
additivePressAdded: ElementId | null;
|
|
441
|
+
get additivePressAdded(): ElementId | null;
|
|
442
|
+
set additivePressAdded(v: ElementId | null);
|
|
494
443
|
/**
|
|
495
444
|
* Live container highlight: the container shape the dragged item is
|
|
496
445
|
* currently hovering over. Drawn by the overlay as a dashed
|
|
497
446
|
* accent rect on the container's drop-zone so the user sees where the
|
|
498
447
|
* shape will land after release.
|
|
499
448
|
*/
|
|
500
|
-
containerHover:
|
|
501
|
-
|
|
502
|
-
dropZone: Bounds;
|
|
503
|
-
} | null;
|
|
449
|
+
get containerHover(): ContainerHover | null;
|
|
450
|
+
set containerHover(v: ContainerHover | null);
|
|
504
451
|
/**
|
|
505
452
|
* Remote peer cursors / selections, pushed in by the host (typically
|
|
506
453
|
* a `bindAwareness(editor, awareness)` helper in `@collab`). The
|
|
@@ -520,7 +467,7 @@ export declare class Editor {
|
|
|
520
467
|
* two or more entries we enter a pinch / pan gesture and bypass the
|
|
521
468
|
* interaction machine — `pinchOrigin` holds the baseline.
|
|
522
469
|
*/
|
|
523
|
-
|
|
470
|
+
get activePointers(): Map<number, Vec2>;
|
|
524
471
|
/**
|
|
525
472
|
* One-finger-pan candidate: set at pointer-down when a TOUCH press lands
|
|
526
473
|
* on empty canvas in select mode. A tap (no movement) still falls through
|
|
@@ -528,9 +475,10 @@ export declare class Editor {
|
|
|
528
475
|
* this to a real pan instead of a marquee lasso (mobile convention).
|
|
529
476
|
* Screen-space origin point.
|
|
530
477
|
*/
|
|
531
|
-
touchPanCandidate: Vec2 | null;
|
|
478
|
+
get touchPanCandidate(): Vec2 | null;
|
|
479
|
+
set touchPanCandidate(v: Vec2 | null);
|
|
532
480
|
pinch: PinchController;
|
|
533
|
-
/** Bridge for
|
|
481
|
+
/** Bridge for the container-ops helpers. Built lazily in constructor. */
|
|
534
482
|
private containerOpsRef;
|
|
535
483
|
/**
|
|
536
484
|
* Space-bar held → next pointer drag pans the canvas instead of
|
|
@@ -538,7 +486,8 @@ export declare class Editor {
|
|
|
538
486
|
* "grab" / "grabbing". Wires a window-level keydown/keyup listener
|
|
539
487
|
* in `bindPointerEvents`.
|
|
540
488
|
*/
|
|
541
|
-
spaceHeld: boolean;
|
|
489
|
+
get spaceHeld(): boolean;
|
|
490
|
+
set spaceHeld(v: boolean);
|
|
542
491
|
/**
|
|
543
492
|
* Host-supplied tile compositor — when set (via
|
|
544
493
|
* `EditorOptions.useTileCache` + `tileCompose`), the per-frame
|
|
@@ -588,20 +537,16 @@ export declare class Editor {
|
|
|
588
537
|
* only treat right-click releases as potential context-menu
|
|
589
538
|
* triggers (Space + left-drag never opens a menu).
|
|
590
539
|
*/
|
|
591
|
-
panGesture:
|
|
592
|
-
|
|
593
|
-
button: number;
|
|
594
|
-
startPoint: Vec2;
|
|
595
|
-
lastPoint: Vec2;
|
|
596
|
-
moved: boolean;
|
|
597
|
-
} | null;
|
|
540
|
+
get panGesture(): PanGesture | null;
|
|
541
|
+
set panGesture(v: PanGesture | null);
|
|
598
542
|
/**
|
|
599
543
|
* Set on a right-click pointerdown so the upcoming native
|
|
600
544
|
* `contextmenu` event can be unconditionally preventDefault'ed
|
|
601
545
|
* (the gesture decides whether to fire the menu manually on
|
|
602
546
|
* pointerup based on whether the user dragged).
|
|
603
547
|
*/
|
|
604
|
-
suppressNextContextMenu: boolean;
|
|
548
|
+
get suppressNextContextMenu(): boolean;
|
|
549
|
+
set suppressNextContextMenu(v: boolean);
|
|
605
550
|
/**
|
|
606
551
|
* Long-press tracking. Starts on `pointerdown`; cancelled on
|
|
607
552
|
* `pointermove > LONG_PRESS_MAX_MOVEMENT_PX` or `pointerup` before
|
|
@@ -621,13 +566,13 @@ export declare class Editor {
|
|
|
621
566
|
* in the constructor from `EditorOptions.inputMode` (default `"auto"`
|
|
622
567
|
* uses `matchMedia('(pointer: coarse)')`).
|
|
623
568
|
*/
|
|
624
|
-
private
|
|
625
|
-
private
|
|
626
|
-
private
|
|
627
|
-
private
|
|
569
|
+
private inputMode;
|
|
570
|
+
private handleHitSlop;
|
|
571
|
+
private edgeHandleHitSlop;
|
|
572
|
+
private edgeHitThreshold;
|
|
628
573
|
/** Link-start anchor-dot grab/click hit radii — touch-enlarged in touch mode. */
|
|
629
|
-
|
|
630
|
-
|
|
574
|
+
anchorStartHitSlop: number;
|
|
575
|
+
anchorClickRadius: number;
|
|
631
576
|
readonly _history: HistoryProvider;
|
|
632
577
|
/** Open transaction during a single drag/resize gesture. */
|
|
633
578
|
gestureTx: TransactionHandle | null;
|
|
@@ -642,13 +587,66 @@ export declare class Editor {
|
|
|
642
587
|
/**
|
|
643
588
|
* Wraps gesture lifecycle (transaction open/commit/cancel +
|
|
644
589
|
* post-create mode revert) so editor.ts doesn't carry the bodies.
|
|
645
|
-
*
|
|
646
|
-
* controller calls back through the narrow `GestureRef` bridge
|
|
590
|
+
* The controller calls back through the narrow `GestureRef` bridge
|
|
647
591
|
* built lazily below.
|
|
648
592
|
*/
|
|
649
|
-
private
|
|
593
|
+
private gestures;
|
|
594
|
+
/**
|
|
595
|
+
* Owns the inline text-edit session (edited shape, pending creation,
|
|
596
|
+
* origin snapshot, live selection, drag anchor and caret blink).
|
|
597
|
+
* Editor keeps thin delegate wrappers so the public API is unchanged.
|
|
598
|
+
*/
|
|
599
|
+
private textEdit;
|
|
600
|
+
/**
|
|
601
|
+
* Owns the link edit-handle drags (waypoint / segment / endpoint) and
|
|
602
|
+
* the handle double-click detector. Editor keeps thin delegate
|
|
603
|
+
* wrappers so the public API is unchanged.
|
|
604
|
+
*/
|
|
605
|
+
private linkHandles;
|
|
650
606
|
constructor(options: EditorOptions);
|
|
651
|
-
/**
|
|
607
|
+
/**
|
|
608
|
+
* Build the interaction controllers (gestures, text edit, link-handle
|
|
609
|
+
* drag, long-press, pinch) and the container-ops bridge. Each wires to a
|
|
610
|
+
* narrow getter/setter surface over the editor's mutable fields, so the
|
|
611
|
+
* controllers live in their own modules without importing Editor. The
|
|
612
|
+
* getters/setters in the object literals rebind `this`, so a single
|
|
613
|
+
* `self` alias captures the Editor reference for all of them.
|
|
614
|
+
*/
|
|
615
|
+
private initControllers;
|
|
616
|
+
/**
|
|
617
|
+
* Install process-global hooks the host opted into: a custom text shaper
|
|
618
|
+
* and rasterizer for the WebGL2 backend, plus the scene text measurer that
|
|
619
|
+
* routes through the renderer's own metrics so selection boxes hug text.
|
|
620
|
+
*/
|
|
621
|
+
private initGlobalHooks;
|
|
622
|
+
/**
|
|
623
|
+
* Resolve the input mode (`touch` vs `mouse`, `auto` reads the coarse-
|
|
624
|
+
* pointer media query) and the derived hit slops / thresholds once.
|
|
625
|
+
*/
|
|
626
|
+
private initInputMode;
|
|
627
|
+
/**
|
|
628
|
+
* Create and start the interaction state-machine actor, wire its render /
|
|
629
|
+
* emit subscriptions, register the built-in file-drop handlers, and apply
|
|
630
|
+
* the initial mode.
|
|
631
|
+
*/
|
|
632
|
+
private initActor;
|
|
633
|
+
/**
|
|
634
|
+
* Last {@link observableSnapshot} object, reused while none of its slices
|
|
635
|
+
* have flipped. `null` until the first snapshot is built.
|
|
636
|
+
*/
|
|
637
|
+
private snapshotCache;
|
|
638
|
+
/**
|
|
639
|
+
* Snapshot used by event-fanout. Kept private — internal API.
|
|
640
|
+
*
|
|
641
|
+
* Memoized by slice identity: `notify()` fires on many mutations that touch
|
|
642
|
+
* no observable slice (annotation focus, cursor pushes, viewport-only re-arm),
|
|
643
|
+
* so rebuilding the object every call is pure churn on the hot drag path.
|
|
644
|
+
* We reuse the cached object whenever all six slices compare equal (refs for
|
|
645
|
+
* mode/selection/selectedLinks/scene — scene uses structural sharing so a new
|
|
646
|
+
* ref iff something changed — plus the two history booleans), and only
|
|
647
|
+
* allocate a fresh one on a real flip. `fanOutEvents` sees identical values
|
|
648
|
+
* either way, so emitted events are unchanged.
|
|
649
|
+
*/
|
|
652
650
|
private observableSnapshot;
|
|
653
651
|
get scene(): Scene;
|
|
654
652
|
get selection(): Selection.Selection;
|
|
@@ -740,9 +738,24 @@ export declare class Editor {
|
|
|
740
738
|
* values can be eyeballed. View-only — not recorded in history.
|
|
741
739
|
*/
|
|
742
740
|
setDebugHitZones(on: boolean): void;
|
|
743
|
-
/**
|
|
741
|
+
/**
|
|
742
|
+
* Read-only / view mode flag. `true` gates pointer edits and
|
|
743
|
+
* non-`viewMode` actions while leaving pan / zoom / select live.
|
|
744
|
+
*/
|
|
745
|
+
get readOnly(): boolean;
|
|
746
|
+
/**
|
|
747
|
+
* Enter / leave read-only (view) mode. Notifies subscribers so the UI
|
|
748
|
+
* can re-render disabled chrome, and repaints (no visual diff today, but
|
|
749
|
+
* keeps the contract symmetric with other view toggles). Idempotent.
|
|
750
|
+
*/
|
|
751
|
+
setReadOnly(on: boolean): void;
|
|
752
|
+
/** Toggle read-only (view) mode. */
|
|
753
|
+
toggleReadOnly(): void;
|
|
754
|
+
/** Whether the background grid is enabled for the scene. */
|
|
755
|
+
get gridEnabled(): boolean;
|
|
756
|
+
/** Show/hide the background grid (`g`). Persists in the viewport, not in history. */
|
|
744
757
|
setGridVisible(on: boolean): void;
|
|
745
|
-
/** Toggle background grid
|
|
758
|
+
/** Toggle the background grid on/off. */
|
|
746
759
|
toggleGrid(): void;
|
|
747
760
|
/** Whether the active draw-mode sticks after a create (toolbar lock). */
|
|
748
761
|
get toolLocked(): boolean;
|
|
@@ -817,7 +830,7 @@ export declare class Editor {
|
|
|
817
830
|
width: number;
|
|
818
831
|
height: number;
|
|
819
832
|
position: Vec2;
|
|
820
|
-
image?: HTMLImageElement;
|
|
833
|
+
image?: ImageBitmap | HTMLImageElement;
|
|
821
834
|
animated?: boolean;
|
|
822
835
|
fileId?: FileId;
|
|
823
836
|
animationKind?: string;
|
|
@@ -831,24 +844,12 @@ export declare class Editor {
|
|
|
831
844
|
* current frame of natively-animated elements. Self-terminates
|
|
832
845
|
* when no animated shapes remain.
|
|
833
846
|
*
|
|
834
|
-
* Lifecycle managed by the `AnimationTick` helper
|
|
835
|
-
*
|
|
836
|
-
* `
|
|
837
|
-
*/
|
|
838
|
-
/** EMA of animation-tick render cost (ms) — drives the adaptive throttle. */
|
|
839
|
-
private gifRenderCostEma;
|
|
840
|
-
/** Wall-clock of the last animation-tick render — for the interval throttle. */
|
|
841
|
-
private lastGifTickMs;
|
|
842
|
-
private readonly animationTick;
|
|
843
|
-
private hasAnimatedElement;
|
|
844
|
-
/**
|
|
845
|
-
* True when at least one animated shape's world AABB intersects the
|
|
846
|
-
* current viewport. Drives viewport-culling of the animation tick —
|
|
847
|
-
* off-screen GIFs don't burn decode / render cost, and the wall-clock
|
|
848
|
-
* frame selection means they show the right frame the moment they
|
|
849
|
-
* scroll back in.
|
|
847
|
+
* Lifecycle managed by the `AnimationTick` helper.
|
|
848
|
+
* `insertImage({animated:true})` and `loadScene` start the tick;
|
|
849
|
+
* `dispose()` stops it.
|
|
850
850
|
*/
|
|
851
|
-
private
|
|
851
|
+
private readonly animation;
|
|
852
|
+
private hasAnimatedElement;
|
|
852
853
|
/**
|
|
853
854
|
* Re-arm the animation tick after a change that may have brought an
|
|
854
855
|
* animated shape into (or out of) view — pan / zoom / scene edit.
|
|
@@ -856,29 +857,12 @@ export declare class Editor {
|
|
|
856
857
|
* `isAnimated()` is false, so this is cheap to call from `notify()`.
|
|
857
858
|
*/
|
|
858
859
|
private maybeAnimate;
|
|
859
|
-
/**
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
*
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
* a runtime view, rebuilt on insert / rehydrate.
|
|
866
|
-
*/
|
|
867
|
-
private readonly playbackState;
|
|
868
|
-
/** Element id currently hovered — a hovered heavy GIF keeps playing
|
|
869
|
-
* (its auto-stop timer is held off). Set by the pointer hover path. */
|
|
870
|
-
private hoveredAnimatedId;
|
|
871
|
-
private static nowMs;
|
|
872
|
-
private static prefersReducedMotion;
|
|
873
|
-
/**
|
|
874
|
-
* Seed playback for a freshly-animated shape. Start paused (frozen on
|
|
875
|
-
* frame 0) when the user prefers reduced motion; playing otherwise.
|
|
876
|
-
*/
|
|
877
|
-
private initPlayback;
|
|
878
|
-
/** Playback timestamp fed to the renderer's animation clock for a
|
|
879
|
-
* shape: wall-clock when unmanaged, play offset when playing, the
|
|
880
|
-
* frozen frame when paused. */
|
|
881
|
-
private playbackClock;
|
|
860
|
+
/**
|
|
861
|
+
* Per-shape GIF playback state (auto-stop + reduced-motion). Extracted into
|
|
862
|
+
* a controller; the Editor keeps the orchestration (scene iteration,
|
|
863
|
+
* animation tick, render scheduling) and delegates state ops here.
|
|
864
|
+
*/
|
|
865
|
+
readonly gifPlayback: GifPlaybackController;
|
|
882
866
|
/**
|
|
883
867
|
* Toggle GIF playback for a shape — wired to a click on an animated
|
|
884
868
|
* image (resume after auto-stop, play after reduced-motion). Resuming
|
|
@@ -908,25 +892,6 @@ export declare class Editor {
|
|
|
908
892
|
elementId: ElementId;
|
|
909
893
|
mode: "point" | "element";
|
|
910
894
|
} | null;
|
|
911
|
-
/**
|
|
912
|
-
* Freeze heavy GIFs after `GIF_AUTOSTOP_MS` of continuous play.
|
|
913
|
-
* Light GIFs (small byte payload) loop forever. Called from the tick
|
|
914
|
-
* before each animation render.
|
|
915
|
-
*/
|
|
916
|
-
private autoStopHeavyGifs;
|
|
917
|
-
/**
|
|
918
|
-
* Restore transient `animationData` for animated image shapes after
|
|
919
|
-
* a scene load. The raw GIF bytes don't survive serialisation
|
|
920
|
-
* (`serializeScene` strips the ArrayBuffer), but they're persisted
|
|
921
|
-
* in `Scene.files` via the shape's `fileId`. Here we copy the bytes
|
|
922
|
-
* back onto `shape.animationData` so the registered animation
|
|
923
|
-
* adapter (host-side, e.g. the gifuct decoder) can produce frames.
|
|
924
|
-
*
|
|
925
|
-
* Applied directly to `_scene` (no history entry — this is an
|
|
926
|
-
* internal rehydration, not a user edit). No-op for shapes that
|
|
927
|
-
* already carry live `animationData` or lack a resolvable file.
|
|
928
|
-
*/
|
|
929
|
-
private rehydrateAnimatedImages;
|
|
930
895
|
/**
|
|
931
896
|
* Drag-to-place flow for palette templates. Adds the shape to the
|
|
932
897
|
* scene immediately so the user sees it dragging under the cursor,
|
|
@@ -948,11 +913,10 @@ export declare class Editor {
|
|
|
948
913
|
* cleared by `commitTextEdit` / `cancelTextEdit`. The host overlay
|
|
949
914
|
* (`<TextEditorOverlay>` in `@react-ui`) subscribes via `editor`
|
|
950
915
|
* and renders a `<textarea>` positioned over the shape.
|
|
916
|
+
* State lives in `TextEditController`; this is a delegate.
|
|
951
917
|
*/
|
|
952
|
-
private _editingTextElement;
|
|
953
918
|
get editingTextElement(): ElementId | null;
|
|
954
919
|
/** Link whose caption is being edited inline (double-click), or null. */
|
|
955
|
-
private _editingLinkCaption;
|
|
956
920
|
get editingLinkCaption(): LinkId | null;
|
|
957
921
|
/**
|
|
958
922
|
* Frame whose NAME (header label) is being edited inline (double-click
|
|
@@ -961,30 +925,6 @@ export declare class Editor {
|
|
|
961
925
|
*/
|
|
962
926
|
private _editingFrameName;
|
|
963
927
|
get editingFrameName(): ElementId | null;
|
|
964
|
-
/**
|
|
965
|
-
* When the `draw-text` tool just placed a shape and opened its
|
|
966
|
-
* editor, this holds that shape's id until the first commit. A
|
|
967
|
-
* pending creation isn't in history yet: committing non-empty text
|
|
968
|
-
* records a single add patch (whole shape = one undo); committing
|
|
969
|
-
* empty / cancelling removes it with no history entry at all.
|
|
970
|
-
*/
|
|
971
|
-
private _pendingTextCreate;
|
|
972
|
-
/**
|
|
973
|
-
* Snapshot of the shape at edit start. Used to revert on cancel and
|
|
974
|
-
* as the `before` of the single commit patch. `null` for a pending
|
|
975
|
-
* creation (the shape didn't exist yet).
|
|
976
|
-
*/
|
|
977
|
-
private _textEditOrigin;
|
|
978
|
-
/**
|
|
979
|
-
* Live selection inside the edited text, mirrored from the hidden
|
|
980
|
-
* `<textarea>` (`start`/`end` are source offsets, `dir` is the
|
|
981
|
-
* anchored end). The caret is `dir === "backward" ? start : end`.
|
|
982
|
-
*/
|
|
983
|
-
private _textSel;
|
|
984
|
-
/** Anchor offset for a canvas drag-select inside the edited text. */
|
|
985
|
-
private _textDragAnchor;
|
|
986
|
-
private _caretBlinkOn;
|
|
987
|
-
private _caretBlinkTimer;
|
|
988
928
|
get editingTextSelection(): {
|
|
989
929
|
start: number;
|
|
990
930
|
end: number;
|
|
@@ -995,10 +935,6 @@ export declare class Editor {
|
|
|
995
935
|
get caretBlinkOn(): boolean;
|
|
996
936
|
/** `true` while a canvas drag-select inside the edited text is active. */
|
|
997
937
|
get isTextDragging(): boolean;
|
|
998
|
-
private startCaretBlink;
|
|
999
|
-
private stopCaretBlink;
|
|
1000
|
-
/** Reset the caret to solid (called on type / move so it never blinks off mid-action). */
|
|
1001
|
-
private wakeCaret;
|
|
1002
938
|
/**
|
|
1003
939
|
* Begin editing a text shape's body. No-op when the shape doesn't
|
|
1004
940
|
* exist or isn't a text shape. Concurrent edits commit themselves
|
|
@@ -1064,15 +1000,6 @@ export declare class Editor {
|
|
|
1064
1000
|
extendTextSelectionToPoint(worldPoint: Vec2): void;
|
|
1065
1001
|
/** End a canvas drag-select (clears the drag anchor). */
|
|
1066
1002
|
endTextDragSelect(): void;
|
|
1067
|
-
/** Build the editable layout for a text shape using the main target's metrics. */
|
|
1068
|
-
private editingTextLayout;
|
|
1069
|
-
/**
|
|
1070
|
-
* A measure callback bound to a shape's font, using the main target's
|
|
1071
|
-
* `measureText` — the SAME source the renderer draws with (WebGL2
|
|
1072
|
-
* reports MSDF advances) and the bounder measures with. Caret /
|
|
1073
|
-
* selection geometry therefore lines up exactly with the glyphs.
|
|
1074
|
-
*/
|
|
1075
|
-
private measureFor;
|
|
1076
1003
|
/**
|
|
1077
1004
|
* World-space caret + selection geometry for the overlay pass.
|
|
1078
1005
|
* Returns `null` when not editing. The caret is `null` while blinked
|
|
@@ -1115,6 +1042,15 @@ export declare class Editor {
|
|
|
1115
1042
|
* the tool is locked.
|
|
1116
1043
|
*/
|
|
1117
1044
|
createTextAt(worldPoint: Vec2): ElementId;
|
|
1045
|
+
/** Current brush paint settings (line colour, fill, opacity, width). */
|
|
1046
|
+
private _brushSettings;
|
|
1047
|
+
get brushSettings(): BrushSettings;
|
|
1048
|
+
/**
|
|
1049
|
+
* Update one or more brush paint settings (e.g. from the drawing panel). New
|
|
1050
|
+
* strokes pick them up on commit; the width also drives the pressure curve and
|
|
1051
|
+
* the eraser radius. Merges over the current settings.
|
|
1052
|
+
*/
|
|
1053
|
+
setBrushSettings(patch: Partial<BrushSettings>): void;
|
|
1118
1054
|
beginBrushStroke(world: Vec2, pressure?: number): void;
|
|
1119
1055
|
extendBrushStroke(world: Vec2, pressure?: number): void;
|
|
1120
1056
|
commitBrushStroke(): ElementId | null;
|
|
@@ -1124,6 +1060,53 @@ export declare class Editor {
|
|
|
1124
1060
|
readonly origin: Vec2;
|
|
1125
1061
|
readonly points: readonly BrushPoint[];
|
|
1126
1062
|
} | null;
|
|
1063
|
+
/**
|
|
1064
|
+
* Start an eraser stroke at `world`, seeding it with the shape under it so a
|
|
1065
|
+
* plain click erases. With `restore` (Alt held at press) it seeds nothing —
|
|
1066
|
+
* the gesture is in un-mark mode, and there's nothing marked yet to rescue.
|
|
1067
|
+
*/
|
|
1068
|
+
beginEraseStroke(world: Vec2, restore?: boolean, strokeErase?: boolean): void;
|
|
1069
|
+
/**
|
|
1070
|
+
* Incrementally mark the brush points erased by the eraser segment `a → b`
|
|
1071
|
+
* (world). Iterates the current brushes and grows `stroke.erased` in place —
|
|
1072
|
+
* O(points) per move (each already-erased point is skipped), so a long drag
|
|
1073
|
+
* no longer costs O(points × path length) per frame. Radius is the on-screen
|
|
1074
|
+
* eraser ring converted to world units.
|
|
1075
|
+
*/
|
|
1076
|
+
private markStrokeEraseSegment;
|
|
1077
|
+
/**
|
|
1078
|
+
* Extend the eraser stroke to `world`, sweeping shapes along the segment.
|
|
1079
|
+
* `restore` (Alt held) un-marks swept shapes instead of marking them.
|
|
1080
|
+
*/
|
|
1081
|
+
extendEraseStroke(world: Vec2, restore?: boolean): void;
|
|
1082
|
+
/**
|
|
1083
|
+
* Commit the eraser stroke — delete every swept shape in ONE undo step (with
|
|
1084
|
+
* their attached links). No-op delete when nothing was swept. Returns the
|
|
1085
|
+
* count removed.
|
|
1086
|
+
*/
|
|
1087
|
+
commitEraseStroke(): number;
|
|
1088
|
+
/** Abort the eraser stroke without deleting anything. */
|
|
1089
|
+
cancelEraseStroke(): void;
|
|
1090
|
+
/** True only while the pointer is down in laser mode (a trail is being laid). */
|
|
1091
|
+
get laserDrawing(): boolean;
|
|
1092
|
+
/** Start a laser trail at `world` (ephemeral — never enters the scene). */
|
|
1093
|
+
beginLaserStroke(world: Vec2): void;
|
|
1094
|
+
/** Append a point to the active laser trail (no-op unless drawing). */
|
|
1095
|
+
extendLaserStroke(world: Vec2): void;
|
|
1096
|
+
/** End the active laser trail — it keeps fading via the animation tick. */
|
|
1097
|
+
endLaserStroke(): void;
|
|
1098
|
+
/**
|
|
1099
|
+
* True while any laser trail OR eraser trail still has visible points (drives
|
|
1100
|
+
* the fade tick — so the trail keeps melting after the pointer stops).
|
|
1101
|
+
*/
|
|
1102
|
+
hasActiveLaser(): boolean;
|
|
1103
|
+
/** Live eraser drag trail (ephemeral, fading). Empty when none active. */
|
|
1104
|
+
get eraserTrail(): readonly LaserStroke[];
|
|
1105
|
+
/**
|
|
1106
|
+
* Drop expired laser/eraser trail points (called once per frame before paint).
|
|
1107
|
+
* Self-terminating: once both arrays empty the animation tick stops.
|
|
1108
|
+
*/
|
|
1109
|
+
private pruneLaser;
|
|
1127
1110
|
arrangeAsGrid(opts?: {
|
|
1128
1111
|
cols?: number;
|
|
1129
1112
|
gap?: number;
|
|
@@ -1157,6 +1140,14 @@ export declare class Editor {
|
|
|
1157
1140
|
*/
|
|
1158
1141
|
duplicateSelectedInPlace(anchorId?: ElementId | null): ElementId | null;
|
|
1159
1142
|
setSelection(ids: Iterable<ElementId>): void;
|
|
1143
|
+
/**
|
|
1144
|
+
* Programmatically select a single link by id (or clear the link
|
|
1145
|
+
* selection with `null`), clearing the element selection so the link
|
|
1146
|
+
* becomes the sole selection. Used by host navigation (search / jump-to)
|
|
1147
|
+
* to frame an edge with {@link zoomToSelection}. No-op when nothing
|
|
1148
|
+
* would change.
|
|
1149
|
+
*/
|
|
1150
|
+
selectLink(id: LinkId | null): void;
|
|
1160
1151
|
selectAll(): void;
|
|
1161
1152
|
/**
|
|
1162
1153
|
* Internal clipboard. Stored as deep-cloned snapshots so subsequent
|
|
@@ -1185,7 +1176,190 @@ export declare class Editor {
|
|
|
1185
1176
|
*
|
|
1186
1177
|
* No-op when `ids` is empty or none of the targeted shapes exist.
|
|
1187
1178
|
*/
|
|
1179
|
+
/**
|
|
1180
|
+
* Capture the visual style of the first selected element into the style
|
|
1181
|
+
* buffer, for a later {@link pasteSelectionStyle}. No-op / clears nothing
|
|
1182
|
+
* when the selection is empty.
|
|
1183
|
+
*/
|
|
1184
|
+
copySelectionStyle(): void;
|
|
1185
|
+
/** Apply the copied style (if any) to every selected element. One undo step. */
|
|
1186
|
+
pasteSelectionStyle(): void;
|
|
1187
|
+
/** Whether a style has been copied and can be pasted. */
|
|
1188
|
+
get hasStyleClipboard(): boolean;
|
|
1188
1189
|
updateStyle(ids: Iterable<ElementId>, partial: Partial<TextStyle>): void;
|
|
1190
|
+
/**
|
|
1191
|
+
* Apply a partial text style (bold / italic / colour / decoration) to the
|
|
1192
|
+
* character range `[from, to)` of a single text element, producing styled
|
|
1193
|
+
* runs (rich text). One undo step. No-op when the id isn't a text shape or
|
|
1194
|
+
* the range is empty. Read-only editors ignore it. Use this — rather than
|
|
1195
|
+
* `updateStyle` — to style only PART of a text block (e.g. the current
|
|
1196
|
+
* inline-edit selection).
|
|
1197
|
+
*/
|
|
1198
|
+
applyTextStyleToRange(id: ElementId, from: number, to: number, partial: Partial<TextStyle>): void;
|
|
1199
|
+
/**
|
|
1200
|
+
* The fill (or stroke, per `role`) colour of the top-most shape under the
|
|
1201
|
+
* world point, or `null` on empty canvas. Pure read — no mutation.
|
|
1202
|
+
*/
|
|
1203
|
+
pickColorAt(worldPoint: Vec2, role?: "fill" | "stroke"): Color | null;
|
|
1204
|
+
/** One-shot callback armed by {@link beginEyedropperPick}; consumes the next canvas click. */
|
|
1205
|
+
private pendingEyedropperPick;
|
|
1206
|
+
/** `true` while a colour-picker pipette is armed and waiting for a canvas click. */
|
|
1207
|
+
get isEyedropperArmed(): boolean;
|
|
1208
|
+
/**
|
|
1209
|
+
* Arm the eyedropper for a one-shot canvas pick that routes the sampled colour
|
|
1210
|
+
* to `onPick` (e.g. a colour-picker swatch) instead of the selection fill. Does
|
|
1211
|
+
* NOT change the tool mode — the next canvas press is intercepted by
|
|
1212
|
+
* {@link applyEyedropperAt}. Cancelled by a mode switch or an empty-canvas click.
|
|
1213
|
+
*/
|
|
1214
|
+
beginEyedropperPick(onPick: (color: Color) => void): void;
|
|
1215
|
+
/**
|
|
1216
|
+
* Sample the colour under `worldPoint`. When a pipette pick is armed (see
|
|
1217
|
+
* {@link beginEyedropperPick}), route the colour to that callback and disarm.
|
|
1218
|
+
* Otherwise (legacy tool path) apply it as the current selection's fill and
|
|
1219
|
+
* revert to `select` mode. Returns the sampled colour, or `null` on empty
|
|
1220
|
+
* canvas. Read-only editors sample but don't mutate.
|
|
1221
|
+
*/
|
|
1222
|
+
applyEyedropperAt(worldPoint: Vec2): Color | null;
|
|
1223
|
+
/**
|
|
1224
|
+
* Convert every convertible selected shape (rectangle / ellipse / diamond)
|
|
1225
|
+
* to `target`, preserving position, size and style. One undo step; no-op
|
|
1226
|
+
* when nothing applies. See {@link ConvertTarget}.
|
|
1227
|
+
*/
|
|
1228
|
+
convertSelection(target: ConvertTarget): void;
|
|
1229
|
+
/**
|
|
1230
|
+
* Flowchart auto-generate: clone the single selected node offset in
|
|
1231
|
+
* `direction` and connect the two with a fresh link. Selects the new node.
|
|
1232
|
+
* No-op unless exactly one element is selected. One undo step.
|
|
1233
|
+
*/
|
|
1234
|
+
spawnConnectedNode(direction: SpawnDirection): void;
|
|
1235
|
+
/**
|
|
1236
|
+
* Pending flowchart-create session, or `null` when idle. Holds the ORIGINAL
|
|
1237
|
+
* source id + direction, the current sibling `count`, and the pending
|
|
1238
|
+
* `elements` + `links` (a PREVIEW — not yet in the scene / history). Grown by
|
|
1239
|
+
* {@link growFlowchart}, committed by {@link commitFlowchart}, discarded by
|
|
1240
|
+
* {@link cancelFlowchart}.
|
|
1241
|
+
*/
|
|
1242
|
+
private flowchartSession;
|
|
1243
|
+
/**
|
|
1244
|
+
* Grow the flowchart-create preview one step in `direction`. Starts a session
|
|
1245
|
+
* (count = 1) when idle or when the direction changes; otherwise bumps the
|
|
1246
|
+
* sibling count up to {@link FLOWCHART_MAX_SIBLINGS}. Recomputes the pending
|
|
1247
|
+
* nodes/links from the ORIGINAL source each call. PREVIEW ONLY — never
|
|
1248
|
+
* touches the scene or history until {@link commitFlowchart}. No-op in
|
|
1249
|
+
* read-only mode or unless exactly one element is selected.
|
|
1250
|
+
*/
|
|
1251
|
+
growFlowchart(direction: SpawnDirection): void;
|
|
1252
|
+
/**
|
|
1253
|
+
* Commit the pending flowchart-create preview: add every pending node + link
|
|
1254
|
+
* to the scene as ONE undo step, select the first new node, clear the
|
|
1255
|
+
* session. Returns the first new node's id, or `null` when no session is
|
|
1256
|
+
* active.
|
|
1257
|
+
*/
|
|
1258
|
+
commitFlowchart(): ElementId | null;
|
|
1259
|
+
/** Discard the pending flowchart-create preview without committing. */
|
|
1260
|
+
cancelFlowchart(): void;
|
|
1261
|
+
/**
|
|
1262
|
+
* The pending flowchart-create preview (nodes + links), or `null` when no
|
|
1263
|
+
* session is active. Read by the render snapshot to paint the preview on the
|
|
1264
|
+
* overlay. Reference-stable between renders (only changes on grow / commit /
|
|
1265
|
+
* cancel) so the overlay memo doesn't thrash.
|
|
1266
|
+
*/
|
|
1267
|
+
get flowchartPreview(): {
|
|
1268
|
+
readonly elements: readonly Element[];
|
|
1269
|
+
readonly links: readonly Link[];
|
|
1270
|
+
} | null;
|
|
1271
|
+
/**
|
|
1272
|
+
* Move the selection to an adjacent node. With exactly one element selected,
|
|
1273
|
+
* prefers a graph neighbour (linked node) best aligned with `direction`;
|
|
1274
|
+
* falls back to the spatial {@link selectClosest} when no neighbour lies that
|
|
1275
|
+
* way. No-op unless exactly one element is selected.
|
|
1276
|
+
*/
|
|
1277
|
+
navigateFlowchart(direction: "left" | "right" | "up" | "down"): void;
|
|
1278
|
+
/**
|
|
1279
|
+
* Live image-crop session, or `null` when not cropping. Excalidraw-style:
|
|
1280
|
+
* the crop frame IS the element's visible box, and the user drags edge /
|
|
1281
|
+
* corner handles inward (hides pixels) or the image body (pans the source).
|
|
1282
|
+
*
|
|
1283
|
+
* - `id` — the image being cropped.
|
|
1284
|
+
* - `crop` — pending normalised source rect.
|
|
1285
|
+
* - `position` / `width` / `height` — the pending element box (world position
|
|
1286
|
+
* + local size); a handle drag moves them, a body pan leaves them fixed.
|
|
1287
|
+
* - `drag` — the active gesture, or `null` when only hovering.
|
|
1288
|
+
* - `dragStartWorld` — pointer world position at drag start (body pan basis).
|
|
1289
|
+
*
|
|
1290
|
+
* Seeded on {@link beginImageCrop}; committed by {@link commitImageCrop} (one
|
|
1291
|
+
* undo step), abandoned by {@link cancelImageCrop}.
|
|
1292
|
+
*/
|
|
1293
|
+
cropSession: {
|
|
1294
|
+
id: ElementId;
|
|
1295
|
+
crop: ImageCrop;
|
|
1296
|
+
position: Vec2;
|
|
1297
|
+
width: number;
|
|
1298
|
+
height: number;
|
|
1299
|
+
drag: {
|
|
1300
|
+
kind: "handle";
|
|
1301
|
+
handle: CropHandle;
|
|
1302
|
+
} | {
|
|
1303
|
+
kind: "body";
|
|
1304
|
+
} | null;
|
|
1305
|
+
dragStartWorld: Vec2 | null;
|
|
1306
|
+
} | null;
|
|
1307
|
+
/** The image-crop session (read-only accessor for UI / overlay). */
|
|
1308
|
+
get imageCropSession(): {
|
|
1309
|
+
readonly id: ElementId;
|
|
1310
|
+
readonly crop: ImageCrop;
|
|
1311
|
+
readonly position: Vec2;
|
|
1312
|
+
readonly width: number;
|
|
1313
|
+
readonly height: number;
|
|
1314
|
+
} | null;
|
|
1315
|
+
/**
|
|
1316
|
+
* Enter crop mode for the image `id`, seeding the pending crop / box from its
|
|
1317
|
+
* current state (or the full image). No-op for non-image shapes or in
|
|
1318
|
+
* read-only. Typically triggered by a double-click on an image.
|
|
1319
|
+
*/
|
|
1320
|
+
beginImageCrop(id: ElementId): void;
|
|
1321
|
+
/**
|
|
1322
|
+
* Hit-test `worldPoint` against the pending crop chrome: a crop handle when
|
|
1323
|
+
* within {@link CROP_HANDLE_HIT_RADIUS} (screen px, zoom-compensated) of one,
|
|
1324
|
+
* `"body"` when inside the window, else `null`. Returns `null` when not
|
|
1325
|
+
* cropping.
|
|
1326
|
+
*/
|
|
1327
|
+
cropHandleAtWorld(worldPoint: Vec2): CropHandle | "body" | null;
|
|
1328
|
+
/** Begin dragging crop handle `handle` from `worldPoint`. */
|
|
1329
|
+
beginImageCropHandle(handle: CropHandle, worldPoint: Vec2): void;
|
|
1330
|
+
/** Begin panning the image body under the fixed window from `worldPoint`. */
|
|
1331
|
+
beginImageCropBody(worldPoint: Vec2): void;
|
|
1332
|
+
/**
|
|
1333
|
+
* Update the active crop drag to `worldPoint` — resize the window (handle) or
|
|
1334
|
+
* pan the source (body). Geometry is recomputed from the ORIGINAL element so
|
|
1335
|
+
* it stays stable across many moves. No-op when no drag is active.
|
|
1336
|
+
*/
|
|
1337
|
+
updateImageCropDrag(worldPoint: Vec2): void;
|
|
1338
|
+
/** Finish the current crop drag (keeps the pending crop / box). */
|
|
1339
|
+
endImageCropDrag(): void;
|
|
1340
|
+
/** Apply the pending crop + box and leave crop mode. One undo step. */
|
|
1341
|
+
commitImageCrop(): void;
|
|
1342
|
+
/** Abandon the crop session without changing the image. */
|
|
1343
|
+
cancelImageCrop(): void;
|
|
1344
|
+
/**
|
|
1345
|
+
* Synthetic element carrying the PENDING crop box (position / size) over the
|
|
1346
|
+
* original element's rotation / scale — the frame the user currently sees.
|
|
1347
|
+
* Used to project the crop frame and handles.
|
|
1348
|
+
*/
|
|
1349
|
+
private pendingCropElement;
|
|
1350
|
+
/**
|
|
1351
|
+
* World-space corners (clockwise) of the pending crop frame, or `null` when
|
|
1352
|
+
* not cropping. The frame is the pending element box mapped through its
|
|
1353
|
+
* local→world transform (so rotation / scale are honoured).
|
|
1354
|
+
*/
|
|
1355
|
+
private cropFrameCorners;
|
|
1356
|
+
/**
|
|
1357
|
+
* Ghost-image overlay descriptor for the crop session: the ORIGINAL element
|
|
1358
|
+
* (its transform + live bitmap handle) and the virtual full-image LOCAL rect
|
|
1359
|
+
* the whole bitmap occupies. `null` when not cropping. The overlay paints the
|
|
1360
|
+
* full bitmap faintly over this rect so hidden parts stay visible.
|
|
1361
|
+
*/
|
|
1362
|
+
private cropGhost;
|
|
1189
1363
|
/**
|
|
1190
1364
|
* Update non-style text properties (`fontSize`, `fontFamily`,
|
|
1191
1365
|
* `maxWidth`) on every selected text shape. Non-text shapes are
|
|
@@ -1196,6 +1370,12 @@ export declare class Editor {
|
|
|
1196
1370
|
fontFamily?: string;
|
|
1197
1371
|
maxWidth?: number;
|
|
1198
1372
|
}): void;
|
|
1373
|
+
/**
|
|
1374
|
+
* Step the font size of every selected text shape up or down by one gentle
|
|
1375
|
+
* multiplicative increment (each shape relative to its own size). One
|
|
1376
|
+
* undoable step; no-op when no text is selected.
|
|
1377
|
+
*/
|
|
1378
|
+
adjustSelectionFontSize(direction: "increase" | "decrease"): void;
|
|
1199
1379
|
/**
|
|
1200
1380
|
* Set (or clear, with `null`) the element-level hyperlink (`href`) on
|
|
1201
1381
|
* every shape in `ids`. Single undo step. Pass a raw user string — it
|
|
@@ -1229,6 +1409,32 @@ export declare class Editor {
|
|
|
1229
1409
|
bringForward(id?: ElementId): void;
|
|
1230
1410
|
/** Move the target shape one step toward the bottom of its layer. */
|
|
1231
1411
|
sendBackward(id?: ElementId): void;
|
|
1412
|
+
/**
|
|
1413
|
+
* Mirror the current selection about its bounding-box centre on the given
|
|
1414
|
+
* axis — `horizontal` flips left↔right, `vertical` flips top↔bottom. A single
|
|
1415
|
+
* element flips about its own centre. One undoable step.
|
|
1416
|
+
*/
|
|
1417
|
+
flipSelection(axis: FlipAxis): void;
|
|
1418
|
+
/**
|
|
1419
|
+
* Align the selection to the given edge / centre line of its bounding box
|
|
1420
|
+
* (e.g. `left` flushes every shape's left edge; `h-center` lines up
|
|
1421
|
+
* horizontal centres). Needs two or more elements. One undoable step.
|
|
1422
|
+
*/
|
|
1423
|
+
alignSelection(edge: AlignEdge): void;
|
|
1424
|
+
/**
|
|
1425
|
+
* Evenly space the selection along the given axis so the gaps between
|
|
1426
|
+
* adjacent shapes are equal; the outermost shapes stay put. Needs three or
|
|
1427
|
+
* more elements. One undoable step.
|
|
1428
|
+
*/
|
|
1429
|
+
distributeSelection(axis: DistributeAxis): void;
|
|
1430
|
+
/**
|
|
1431
|
+
* Rotate the whole selection by `delta` radians about its bounding-box centre
|
|
1432
|
+
* (a single shape turns about its own centre). One undoable step. The live
|
|
1433
|
+
* rotate gesture drives the same maths from a press-time snapshot.
|
|
1434
|
+
*/
|
|
1435
|
+
rotateSelection(delta: number): void;
|
|
1436
|
+
/** Apply a batch of arrange patches as a single undoable step. */
|
|
1437
|
+
private commitArrange;
|
|
1232
1438
|
compactLayerZOrder(layerId?: LayerId, options?: {
|
|
1233
1439
|
recordHistory?: boolean;
|
|
1234
1440
|
}): void;
|
|
@@ -1262,6 +1468,13 @@ export declare class Editor {
|
|
|
1262
1468
|
zoomToFit(padding?: number): void;
|
|
1263
1469
|
/** Fit the camera to the current selection (standard `⌥2`). No-op when empty. */
|
|
1264
1470
|
zoomToSelection(padding?: number): void;
|
|
1471
|
+
/**
|
|
1472
|
+
* Center the camera on the current selection for a reveal / jump-to (search
|
|
1473
|
+
* navigation). Unlike {@link zoomToSelection}, it does NOT fill the screen —
|
|
1474
|
+
* a small match keeps its size and is merely centered; the zoom only drops to
|
|
1475
|
+
* fit an oversized match. No-op when the selection is empty.
|
|
1476
|
+
*/
|
|
1477
|
+
revealSelection(padding?: number): void;
|
|
1265
1478
|
/**
|
|
1266
1479
|
* Select the nearest interactable top-level element in `direction` from the
|
|
1267
1480
|
* current selection's centre (or the viewport centre when nothing is
|
|
@@ -1273,7 +1486,7 @@ export declare class Editor {
|
|
|
1273
1486
|
zoomAt(factor: number, anchorWorld: Vec2): void;
|
|
1274
1487
|
setViewportSize(width: number, height: number): void;
|
|
1275
1488
|
setGrid(patch: {
|
|
1276
|
-
|
|
1489
|
+
enabled?: boolean;
|
|
1277
1490
|
style?: GridStyle;
|
|
1278
1491
|
snap?: boolean;
|
|
1279
1492
|
}): void;
|
|
@@ -1288,13 +1501,20 @@ export declare class Editor {
|
|
|
1288
1501
|
*/
|
|
1289
1502
|
setSnapSuppressed(suppressed: boolean): void;
|
|
1290
1503
|
/**
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
* (
|
|
1294
|
-
*
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1504
|
+
* Host hook: mirror the Alt / Shift modifier state so an in-flight resize or
|
|
1505
|
+
* move reacts to it — `alt` resizes about the centre, `shift` locks the
|
|
1506
|
+
* resize aspect ratio (or constrains a move to one axis). The app wires
|
|
1507
|
+
* keydown/keyup of the modifiers to this. Idempotent; never touches history.
|
|
1508
|
+
*/
|
|
1509
|
+
setTransformModifiers(mods: {
|
|
1510
|
+
readonly alt: boolean;
|
|
1511
|
+
readonly shift: boolean;
|
|
1512
|
+
}): void;
|
|
1513
|
+
/**
|
|
1514
|
+
* True when a gesture should snap. Snapping is coupled to grid display:
|
|
1515
|
+
* it is active only while the grid is enabled (`gridEnabled`) — snapping to
|
|
1516
|
+
* a hidden grid is confusing. `snapToGrid` is an extra programmatic opt-out;
|
|
1517
|
+
* the suppress modifier (Cmd/Ctrl) bypasses snapping for the current gesture.
|
|
1298
1518
|
*/
|
|
1299
1519
|
private snapActive;
|
|
1300
1520
|
/** World-unit spacing the current gesture snaps to. */
|
|
@@ -1350,16 +1570,6 @@ export declare class Editor {
|
|
|
1350
1570
|
* out of sync. `worldPoint` defaults to the last known pointer position.
|
|
1351
1571
|
*/
|
|
1352
1572
|
refreshCursor(worldPoint?: Vec2): void;
|
|
1353
|
-
/**
|
|
1354
|
-
* The CSS cursor for the current state. Priority: active gesture → text edit → pan affordance →
|
|
1355
|
-
* draw tool → idle hover hit-test. Pure read of editor state; no side effects.
|
|
1356
|
-
*/
|
|
1357
|
-
private computeCursor;
|
|
1358
|
-
/**
|
|
1359
|
-
* Resolve a cursor role to a CSS `cursor` value: a host-registered custom
|
|
1360
|
-
* image (via {@link setCursorOverride}) if present, else `fallbackKeyword`.
|
|
1361
|
-
*/
|
|
1362
|
-
private resolveCursor;
|
|
1363
1573
|
/**
|
|
1364
1574
|
* Register (or clear, with `null`) a custom cursor image for a state role.
|
|
1365
1575
|
* The image is shown wherever `computeCursor` resolves that role; pass a
|
|
@@ -1369,12 +1579,11 @@ export declare class Editor {
|
|
|
1369
1579
|
*/
|
|
1370
1580
|
setCursorOverride(role: CursorRole, spec: CursorSpec | null): void;
|
|
1371
1581
|
/**
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
* exactly where a press would begin a link.
|
|
1582
|
+
* Read-only lookup of a host-registered cursor override. Used by the cursor
|
|
1583
|
+
* module to resolve a role without exposing the mutable override map (mutate
|
|
1584
|
+
* only via {@link setCursorOverride}, so `refreshCursor` stays in sync).
|
|
1376
1585
|
*/
|
|
1377
|
-
|
|
1586
|
+
getCursorOverride(role: CursorRole): CursorSpec | undefined;
|
|
1378
1587
|
/** True when the given layer exists and is marked `locked`. */
|
|
1379
1588
|
private isLayerLocked;
|
|
1380
1589
|
/**
|
|
@@ -1418,8 +1627,7 @@ export declare class Editor {
|
|
|
1418
1627
|
* Topmost group ancestor of `shape` (walks parentId chain, returns
|
|
1419
1628
|
* the highest `type === "group"` parent). `null` if `shape` has no
|
|
1420
1629
|
* group ancestor. Used by drill-down: a double-click on a shape
|
|
1421
|
-
* with a group ancestor enters that group.
|
|
1422
|
-
* `./group-helpers.ts`.
|
|
1630
|
+
* with a group ancestor enters that group.
|
|
1423
1631
|
*/
|
|
1424
1632
|
private topGroupAncestor;
|
|
1425
1633
|
/**
|
|
@@ -1443,7 +1651,22 @@ export declare class Editor {
|
|
|
1443
1651
|
* selected, you can see".
|
|
1444
1652
|
*/
|
|
1445
1653
|
computeHiddenElements(): ReadonlySet<ElementId> | undefined;
|
|
1654
|
+
/**
|
|
1655
|
+
* Live stroke-erase preview: while a Shift-held eraser gesture drags, the
|
|
1656
|
+
* fragments each touched brush WOULD become, plus the set of touched
|
|
1657
|
+
* originals to hide in the main pass. `null` outside a stroke-erase gesture
|
|
1658
|
+
* or when the path touches no brush. Recomputed each frame from the
|
|
1659
|
+
* path-so-far — never mutates the scene or history.
|
|
1660
|
+
*/
|
|
1661
|
+
private computeStrokeErasePreview;
|
|
1446
1662
|
computeDimElements(enteredGroupId: ElementId): ReadonlySet<ElementId>;
|
|
1663
|
+
/**
|
|
1664
|
+
* Dim set fed to the renderer: group-isolation dim UNION the eraser's
|
|
1665
|
+
* pending-delete set (shapes swept by the current eraser stroke are shown
|
|
1666
|
+
* dimmed so the user sees what release will delete). `undefined` when neither
|
|
1667
|
+
* is active, keeping the fast tile-cache render path.
|
|
1668
|
+
*/
|
|
1669
|
+
private computeDimSet;
|
|
1447
1670
|
/**
|
|
1448
1671
|
* Enter a group — subsequent hits inside this group return children
|
|
1449
1672
|
* directly instead of the group root. `null` exits group-edit mode.
|
|
@@ -1583,6 +1806,13 @@ export declare class Editor {
|
|
|
1583
1806
|
* grouping is the explicit "lock the ratio" gesture).
|
|
1584
1807
|
*/
|
|
1585
1808
|
selectionIsAspectLocked(): boolean;
|
|
1809
|
+
/**
|
|
1810
|
+
* Per-frame rotate during a grip drag: turn the press-time snapshot by
|
|
1811
|
+
* `deltaAngle` about its pivot. Shift snaps the swept angle to
|
|
1812
|
+
* {@link ROTATE_SNAP_RADIANS} steps. Recorded as gesture patches (one undo
|
|
1813
|
+
* step on commit).
|
|
1814
|
+
*/
|
|
1815
|
+
private applyRotate;
|
|
1586
1816
|
private applyGroupResize;
|
|
1587
1817
|
private applyResize;
|
|
1588
1818
|
private applyCreate;
|
|
@@ -1808,9 +2038,8 @@ export declare class Editor {
|
|
|
1808
2038
|
/**
|
|
1809
2039
|
* Typed event surface — subscribe to a specific slice (`mode`,
|
|
1810
2040
|
* `selection`, `scene`, `history`, `viewport`) or the umbrella
|
|
1811
|
-
* `change`.
|
|
1812
|
-
*
|
|
1813
|
-
* `subscribe()` still works and fires in lock-step.
|
|
2041
|
+
* `change`. For callers that only care about one dimension;
|
|
2042
|
+
* `subscribe()` fires in lock-step with these.
|
|
1814
2043
|
*/
|
|
1815
2044
|
on<K extends keyof EditorEvents>(event: K, fn: EditorEvents[K]): () => void;
|
|
1816
2045
|
off<K extends keyof EditorEvents>(event: K, fn: EditorEvents[K]): void;
|
|
@@ -1825,20 +2054,48 @@ export declare class Editor {
|
|
|
1825
2054
|
*/
|
|
1826
2055
|
runLayout(parentId: ElementId): Patch | null;
|
|
1827
2056
|
/**
|
|
1828
|
-
*
|
|
1829
|
-
*
|
|
1830
|
-
*
|
|
2057
|
+
* Derived elbow-route cache, keyed by link — the source of truth for
|
|
2058
|
+
* A*-routed corners, living OUTSIDE the immutable `Scene`. Each entry holds
|
|
2059
|
+
* the routed interior `points` (between from/to) plus the `sig` of the
|
|
2060
|
+
* inputs it was computed from (endpoint refs + bound-shape bounds +
|
|
2061
|
+
* fixedSegments), so an unchanged link short-circuits the reroute.
|
|
2062
|
+
*
|
|
2063
|
+
* `rerouteElbows` still MIRRORS `points` onto `Link.routedPoints` in
|
|
2064
|
+
* `_scene` because three readers still consume the baked field: the render
|
|
2065
|
+
* path (`getLinkPath` in `renderer-core`), the headless `getLinkPath`, and
|
|
2066
|
+
* serialization (`schema.ts`). The mirror is compat-only derived state — no
|
|
2067
|
+
* history push / notify.
|
|
2068
|
+
*
|
|
2069
|
+
* TODO(fable R7a): drop the `_scene` mirror once (a) the render path reads
|
|
2070
|
+
* routes from this cache via the `RenderSnapshot`, and (b) headless
|
|
2071
|
+
* `getLinkPath` / serialization stop depending on baked `routedPoints`.
|
|
2072
|
+
* That eviction changes headless geometry, serialized output, and
|
|
2073
|
+
* collab-synced fields, so it spans the scene / serialization / renderer /
|
|
2074
|
+
* headless goldens and must land as its own cross-package change — out of
|
|
2075
|
+
* scope for this state-only pass.
|
|
2076
|
+
*/
|
|
2077
|
+
private readonly elbowRoutes;
|
|
2078
|
+
/**
|
|
2079
|
+
* Choke-point reroute (standard model): recompute the route for every
|
|
2080
|
+
* orthogonal link whose inputs changed since the last pass, store it in the
|
|
2081
|
+
* derived {@link elbowRoutes} cache, and mirror it onto `_scene`. Runs once
|
|
2082
|
+
* per frame before paint — derived state, so no history push / notify (would
|
|
2083
|
+
* loop). Cheap when nothing moved (signature short-circuit).
|
|
1831
2084
|
*/
|
|
1832
|
-
private
|
|
1833
|
-
private elbowSignature;
|
|
2085
|
+
private rerouteElbows;
|
|
1834
2086
|
/**
|
|
1835
|
-
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
2087
|
+
* Collect everything {@link renderEditor} paints from into a flat
|
|
2088
|
+
* {@link RenderSnapshot}. Resolves the derived viewport / dirty-rect / dim /
|
|
2089
|
+
* hide inputs and the shared spatial index up front (same order the
|
|
2090
|
+
* orchestrator used to call them in), so the paint pass stays side-effect
|
|
2091
|
+
* free and the orchestrator stays decoupled from this class.
|
|
2092
|
+
*
|
|
2093
|
+
* `computeDirtyWorld` is order-sensitive (it diffs against
|
|
2094
|
+
* `lastRenderedScene` and populates `tileDirtyElements`); it runs here and
|
|
2095
|
+
* the `lastRendered*` bookkeeping is applied in `render()` after the paint.
|
|
1840
2096
|
*/
|
|
1841
|
-
private
|
|
2097
|
+
private buildRenderSnapshot;
|
|
1842
2098
|
private render;
|
|
1843
2099
|
}
|
|
2100
|
+
/** Distance from point `p` to the finite segment `a`–`b` (world space). */
|
|
1844
2101
|
//# sourceMappingURL=editor.d.ts.map
|