@fulate/tools 1.0.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.
@@ -0,0 +1,339 @@
1
+ import { Element, Node, type ConnectionPortRef, type OwnerPropertyChange, type Root, type StructureChange } from "@fulate/core";
2
+ import { LineTree, type EndpointConnectionRole, type EndpointRef, type ContentEditingSession, type EditorAuthoredGesture, type PointEditTarget, type PointEditingScope, type LineTreeBranchTailSource, type LineDecoration, type SelectionBehavior, type TransformInteractionCapability } from "@fulate/ui";
3
+ import { type PointView, type Rect } from "@fulate/share";
4
+ import type { HistoryManager, HistoryScope } from "../history";
5
+ import type { LineTool } from "../line";
6
+ import type { Select, SelectedPropertyPatch } from "../select";
7
+ import { type ProjectionOwner, type ResizeHandle, type SelectionOverlayProjection, type SelectionOverlayTarget, type SelectionRotationPivot } from "../select/projection";
8
+ import { type FlipDirection, type ResizeOptions } from "../select/transform";
9
+ import type { PortSnapResult, Snap } from "../select/snap";
10
+ interface SelectedOwner extends ProjectionOwner {
11
+ readonly behavior: SelectionBehavior;
12
+ }
13
+ export interface SelectionIdentity {
14
+ readonly owners: readonly SelectedOwner[];
15
+ readonly interaction: EditorInteractionState;
16
+ }
17
+ interface TransformOwnerRecord {
18
+ readonly owner: Element;
19
+ readonly parent: Node | undefined;
20
+ readonly capability: TransformInteractionCapability;
21
+ readonly baseline: ReturnType<TransformInteractionCapability["captureTransformBaseline"]>;
22
+ }
23
+ interface PointerIntent {
24
+ readonly point: PointView;
25
+ readonly shiftKey: boolean;
26
+ }
27
+ interface PointerGesture {
28
+ update(intent: PointerIntent): void;
29
+ finish(intent?: PointerIntent, cancelled?: boolean): void;
30
+ }
31
+ interface ApplyCommandOptions {
32
+ readonly beforeDrain?: () => void;
33
+ readonly afterHistory?: () => void;
34
+ readonly installSelection?: () => boolean;
35
+ }
36
+ interface LineDrawingSession {
37
+ readonly tool: LineTool;
38
+ readonly resultType: "line" | "lineTree";
39
+ readonly tailDecoration: LineDecoration;
40
+ readonly history: HistoryScope | undefined;
41
+ readonly confirmed: PointView[];
42
+ headTarget: ConnectionPortRef | undefined;
43
+ tailTarget: ConnectionPortRef | undefined;
44
+ preview: PointView | null;
45
+ snap: PortSnapResult | null;
46
+ }
47
+ interface ActivePointTarget {
48
+ readonly ownerKey: string;
49
+ readonly target: PointEditTarget;
50
+ }
51
+ export type SelectControllerState = {
52
+ readonly kind: "idle";
53
+ readonly gesture: MarqueeGesture | null;
54
+ } | {
55
+ readonly kind: "transform";
56
+ readonly gesture: TransformGesture | PivotGesture | SelectionPressGesture | null;
57
+ } | {
58
+ readonly kind: "point";
59
+ readonly ownerKey: string;
60
+ readonly scope: PointEditingScope;
61
+ readonly gesture: PointGesture | SelectionPressGesture | TransformGesture | null;
62
+ readonly activeTarget: ActivePointTarget | null;
63
+ } | {
64
+ readonly kind: "port";
65
+ readonly ownerKey: string;
66
+ readonly scope: PointEditingScope;
67
+ readonly gesture: PointGesture;
68
+ readonly source: EndpointRef;
69
+ readonly activeTarget: ActivePointTarget | null;
70
+ } | {
71
+ readonly kind: "content";
72
+ readonly session: ContentEditingSession;
73
+ readonly history: HistoryScope | undefined;
74
+ };
75
+ type LineTreeDrawingSession = {
76
+ readonly kind: "source-pick";
77
+ readonly tool: LineTool;
78
+ readonly owner: LineTree;
79
+ readonly tailDecoration: LineDecoration;
80
+ hover: LineTreeBranchTailSource | null;
81
+ } | {
82
+ readonly kind: "branch-draw";
83
+ readonly tool: LineTool;
84
+ readonly owner: LineTree;
85
+ readonly source: LineTreeBranchTailSource;
86
+ readonly tailDecoration: LineDecoration;
87
+ readonly confirmed: PointView[];
88
+ tailTarget: ConnectionPortRef | undefined;
89
+ preview: PointView | null;
90
+ snap: PortSnapResult | null;
91
+ };
92
+ export type EditorInteractionState = {
93
+ readonly kind: "select";
94
+ readonly interaction: SelectControllerState;
95
+ readonly selection: readonly Element[];
96
+ readonly pivot: SelectionRotationPivot;
97
+ } | {
98
+ readonly kind: "line-draw";
99
+ readonly session: LineDrawingSession | LineTreeDrawingSession;
100
+ };
101
+ declare class TransformGesture implements PointerGesture {
102
+ readonly controller: EditorInteractionController;
103
+ readonly kind: "move" | "resize" | "rotate";
104
+ readonly start: PointView;
105
+ readonly frame: NonNullable<SelectionOverlayProjection["frame"]>;
106
+ readonly records: readonly TransformOwnerRecord[];
107
+ readonly snapPoints: readonly PointView[];
108
+ readonly movableLineEndpoints: readonly PointView[];
109
+ readonly snapExcludes: readonly Element[];
110
+ readonly rotationPivotWorld: PointView;
111
+ readonly history: HistoryScope | undefined;
112
+ readonly resizeHandle?: ResizeHandle;
113
+ private lastIntent;
114
+ private previousRotationAngle;
115
+ private unwrappedRotationDelta;
116
+ constructor(controller: EditorInteractionController, kind: "move" | "resize" | "rotate", start: PointView, initialIntent: PointerIntent, frame: NonNullable<SelectionOverlayProjection["frame"]>, records: readonly TransformOwnerRecord[], snapPoints: readonly PointView[], movableLineEndpoints: readonly PointView[], snapExcludes: readonly Element[], rotationPivotWorld: PointView, history: HistoryScope | undefined, resizeHandle?: ResizeHandle);
117
+ consumeRotationDelta(point: PointView): number;
118
+ probeForbiddenPort(point: PointView): boolean;
119
+ update(intent: PointerIntent): void;
120
+ ownsCurrentContext(): boolean;
121
+ finishInvalidated(): void;
122
+ finish(intent?: PointerIntent): void;
123
+ }
124
+ declare class PointGesture implements PointerGesture, EditorAuthoredGesture {
125
+ readonly controller: EditorInteractionController;
126
+ readonly ownerKey: string;
127
+ readonly startParent: Node | undefined;
128
+ readonly startTarget: PointEditTarget;
129
+ readonly insertT: number | undefined;
130
+ readonly role: "endpoint" | "vertex" | "segment" | "handle";
131
+ readonly connectionRole: EndpointConnectionRole | null;
132
+ readonly snapExcludes: readonly Element[];
133
+ readonly history: HistoryScope | undefined;
134
+ readonly startPointerWorld: PointView;
135
+ readonly startTargetWorld: PointView;
136
+ private latestIntent;
137
+ private consumedIntent;
138
+ connectionTarget: ConnectionPortRef | undefined;
139
+ connectionTargetOwner: Element | undefined;
140
+ connectionTargetParent: Node | undefined;
141
+ constructor(controller: EditorInteractionController, ownerKey: string, startParent: Node | undefined, startTarget: PointEditTarget, insertT: number | undefined, role: "endpoint" | "vertex" | "segment" | "handle", connectionRole: EndpointConnectionRole | null, snapExcludes: readonly Element[], history: HistoryScope | undefined, startPointerWorld: PointView, startTargetWorld: PointView);
142
+ currentTarget: PointEditTarget;
143
+ ownsCurrentContext(): boolean;
144
+ get connectionSource(): EndpointRef | undefined;
145
+ resolveWorldPoint(pointer: PointView): {
146
+ x: number;
147
+ y: number;
148
+ };
149
+ update(intent: PointerIntent): void;
150
+ consumeLatestIntent(): void;
151
+ finish(intent?: PointerIntent, cancelled?: boolean): void;
152
+ finishInvalidated(): void;
153
+ }
154
+ declare class PivotGesture implements PointerGesture {
155
+ readonly controller: EditorInteractionController;
156
+ readonly owner: Element;
157
+ readonly startPointer: PointView;
158
+ readonly startPivot: PointView;
159
+ private finalPoint;
160
+ constructor(controller: EditorInteractionController, owner: Element, startPointer: PointView, startPivot: PointView);
161
+ update(intent: PointerIntent): void;
162
+ finish(intent?: PointerIntent): void;
163
+ }
164
+ declare class SelectionPressGesture implements PointerGesture {
165
+ readonly controller: EditorInteractionController;
166
+ readonly start: PointerIntent;
167
+ readonly candidate: Element | undefined;
168
+ readonly contentTarget: Element | null;
169
+ readonly directDragOwner?: Element;
170
+ constructor(controller: EditorInteractionController, start: PointerIntent, candidate: Element | undefined, contentTarget: Element | null, directDragOwner?: Element);
171
+ update(intent: PointerIntent): void;
172
+ finish(intent?: PointerIntent, cancelled?: boolean): void;
173
+ }
174
+ declare class MarqueeGesture implements PointerGesture {
175
+ readonly controller: EditorInteractionController;
176
+ readonly start: PointView;
177
+ readonly candidate: Element | undefined;
178
+ readonly additive: boolean;
179
+ readonly initialSelection: readonly Element[];
180
+ private current;
181
+ private moved;
182
+ constructor(controller: EditorInteractionController, start: PointView, candidate: Element | undefined, additive: boolean, initialSelection: readonly Element[]);
183
+ update(intent: PointerIntent): void;
184
+ finish(intent?: PointerIntent, cancelled?: boolean): void;
185
+ }
186
+ export declare class EditorInteractionController {
187
+ readonly select: Select;
188
+ readonly root: Root;
189
+ readonly history: HistoryManager;
190
+ readonly frameFlush: any;
191
+ private readonly cleanups;
192
+ private selectionValue;
193
+ private owners;
194
+ private policy;
195
+ private rotationPivotPreview;
196
+ private selectionFrame;
197
+ private preserveSelectionFrame;
198
+ private projectionState;
199
+ private projectionOwners;
200
+ private projectionMembership;
201
+ private projectionTopology;
202
+ private overlayDirty;
203
+ private pendingSelectionUpdate;
204
+ private pendingSelectionRepair;
205
+ private rotationPivotDisplayOwner;
206
+ private hoveredTarget;
207
+ private hoveredContent;
208
+ private controllerState;
209
+ private pasteTask;
210
+ private pointerWorld;
211
+ marquee: Readonly<Rect> | null;
212
+ constructor(select: Select, root: Root, history: HistoryManager);
213
+ get selection(): readonly Element[];
214
+ get projection(): SelectionOverlayProjection;
215
+ publishConfiguredChange(changed: boolean | undefined): void;
216
+ /** 把纯外部通知排到当前同步命令、回放或 frame completion 返回之后。 */
217
+ private notifySelect;
218
+ get contentHover(): Element<import("@fulate/core").ElementProperties, import("@fulate/core").BaseElementOption<any>, Partial<Omit<import("@fulate/core").BaseElementOption<any>, "key" | "children">>>;
219
+ get overlayTarget(): SelectionOverlayTarget;
220
+ get editorElements(): readonly Element[];
221
+ get snapTool(): Snap | undefined;
222
+ get state(): EditorInteractionState;
223
+ /** @internal Captures the canonical selection and interaction identities. */
224
+ captureSelectionIdentity(): SelectionIdentity;
225
+ /** @internal Makes one concrete clipboard Promise the latest paste intent. */
226
+ beginPaste(task: Promise<void>): void;
227
+ /** @internal Tests whether one paste still owns the captured selection intent. */
228
+ ownsPasteSelection(identity: SelectionIdentity, task: Promise<void>): boolean;
229
+ /** @internal Releases the latest paste intent after its Promise settles. */
230
+ finishPaste(task: Promise<void>): void;
231
+ private get selectState();
232
+ private installSelectState;
233
+ private get activeGesture();
234
+ private set activeGesture(value);
235
+ private get activePointGesture();
236
+ private get pointState();
237
+ private set pointState(value);
238
+ private get activePointTarget();
239
+ private set activePointTarget(value);
240
+ private get contentSession();
241
+ private set contentSession(value);
242
+ private get contentHistory();
243
+ private set contentHistory(value);
244
+ private get lineSession();
245
+ private set lineSession(value);
246
+ private get lineTreeSession();
247
+ private set lineTreeSession(value);
248
+ private get rotationPivotState();
249
+ private installInput;
250
+ private readonly handleSceneChange;
251
+ private sceneChangeAffectsSelection;
252
+ private selectionGeometryIsDirty;
253
+ private invalidatePointTopology;
254
+ private resolvePolicy;
255
+ setSelection(elements: readonly Element[]): void;
256
+ private readonly pointProjectionOwnerIsCurrent;
257
+ private restoreSelectionForHistory;
258
+ private replaceSelection;
259
+ private requestSelectionEnd;
260
+ private pointContextIsCurrent;
261
+ private resolveCurrentPointContext;
262
+ private resolvePointGestureContext;
263
+ pointGestureOwnsCurrentContext(gesture: PointGesture): boolean;
264
+ private setPointState;
265
+ private exitPointState;
266
+ private setActivePointTarget;
267
+ private invalidateOverlay;
268
+ private shouldShowRotationPivot;
269
+ private showRotationPivotForCurrentOwner;
270
+ hasPendingOverlayWork(): boolean;
271
+ flushOverlayProjection(): void;
272
+ hasPendingCompletionWork(): boolean;
273
+ flushCompletionWork(): void;
274
+ resolveCursor(point: PointView | undefined, contentCursor: string): string;
275
+ private updateHover;
276
+ private applyAuthoredBatch;
277
+ private onPointerDown;
278
+ private onPointerMove;
279
+ private onPointerFinish;
280
+ private onDoubleClick;
281
+ private onKeyDown;
282
+ private captureTransformRecords;
283
+ private startTransform;
284
+ promoteSelectionPress(gesture: SelectionPressGesture): TransformGesture | null;
285
+ finishSelectionPress(gesture: SelectionPressGesture): void;
286
+ finishSelectionGesture(gesture: PointerGesture, selection?: readonly Element[]): void;
287
+ consumeTransform(gesture: TransformGesture, intent: PointerIntent): void;
288
+ private startPointGesture;
289
+ consumePoint(gesture: PointGesture, intent: PointerIntent, first: boolean): void;
290
+ deletePointTarget(): boolean;
291
+ nudge(dx: number, dy: number): void;
292
+ setProperties(patch: SelectedPropertyPatch): void;
293
+ private prepareTransformCommandFrame;
294
+ private applyTransformCommand;
295
+ resize(options?: Readonly<ResizeOptions>): void;
296
+ flip(direction: FlipDirection): void;
297
+ previewRotationPivot(owner: Element, point: PointView): void;
298
+ clearRotationPivotPreview(owner: Element): void;
299
+ commitRotationPivot(owner: Element, point: PointView): boolean;
300
+ private resolveRotationPivot;
301
+ setMarquee(rect: Readonly<Rect> | null): void;
302
+ finishPointerGesture(gesture: PointerGesture): void;
303
+ private pointConnectionCandidateIsCurrent;
304
+ finishPointConnectionGesture(gesture: PointGesture): void;
305
+ private beginContentEditing;
306
+ finishContentEditing(discard: boolean): void;
307
+ startLineDrawing(tool: LineTool): void;
308
+ private startLineTreeBranchDrawing;
309
+ private updateLineTreeSourceHover;
310
+ private confirmLineTreeSource;
311
+ private beginLineTreeBranchDraft;
312
+ private updateLineTreePreview;
313
+ private probeLineTreeTail;
314
+ private confirmLineTreePoint;
315
+ private confirmLineTreeBranchDrawing;
316
+ private updateLinePreview;
317
+ private probeLineAnchor;
318
+ private confirmLinePoint;
319
+ stopLineDrawing(): void;
320
+ cancelLineDrawing(): void;
321
+ private confirmLineDrawing;
322
+ getLineDrawingView(tool: LineTool): LineDrawingSession | {
323
+ readonly kind: "branch-draw";
324
+ readonly tool: LineTool;
325
+ readonly owner: LineTree;
326
+ readonly source: LineTreeBranchTailSource;
327
+ readonly tailDecoration: LineDecoration;
328
+ readonly confirmed: PointView[];
329
+ tailTarget: ConnectionPortRef | undefined;
330
+ preview: PointView | null;
331
+ snap: PortSnapResult | null;
332
+ };
333
+ hasLineToolSession(tool: LineTool): boolean;
334
+ applyCommand(ownerEffects: readonly OwnerPropertyChange[], structureEffects: readonly StructureChange[], scope: HistoryScope | undefined, selectionAfter: readonly Element[], options?: ApplyCommandOptions): void;
335
+ finishCurrentInteraction(): void;
336
+ destroy(): void;
337
+ }
338
+ export declare function getEditorInteractionController(root: Root): EditorInteractionController;
339
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Element, ElementTransform } from "@fulate/core";
2
+ /** Tools 画布 overlay surface 始终参与 Layer paint,但从不成为内容命中目标。 */
3
+ export declare class ToolOverlayTransform<E extends Element = Element> extends ElementTransform<E> {
4
+ hasPointHint(): boolean;
5
+ hasInView(): boolean;
6
+ }
@@ -0,0 +1,18 @@
1
+ import { Layer, type LayerOption, type Root } from "@fulate/core";
2
+ /**
3
+ * Rendering and input boundary for editor tools.
4
+ *
5
+ * Tool painters draw outside their node geometry (selection handles,
6
+ * guides, rulers and previews), so dirty-rectangle repainting cannot
7
+ * describe their damage. Keep this layer on the full-frame path and avoid
8
+ * CSS viewport previews that would scale screen-space affordances. While the
9
+ * layer is active, its subtree becomes an interaction scope: content hits
10
+ * remain visible to Root observers without reaching content handlers.
11
+ */
12
+ export declare class EditorLayer extends Layer {
13
+ readonly type = "editor-layer";
14
+ private releaseInteractionScope?;
15
+ constructor(options?: LayerOption);
16
+ protected onActivate(root: Root | null): void;
17
+ protected onDeactivate(root: Root | null): void;
18
+ }
@@ -0,0 +1,88 @@
1
+ import { Element, Node, type ChangeHistorySink, type Root } from "@fulate/core";
2
+ import { LineTree, type LineTreeTopologyDelta } from "@fulate/ui";
3
+ export interface HistoryPropertyChange {
4
+ readonly owner: Element;
5
+ readonly key: string;
6
+ readonly before: unknown;
7
+ readonly after: unknown;
8
+ }
9
+ export interface HistoryPlacement {
10
+ readonly owner: Node | null;
11
+ readonly index: number;
12
+ }
13
+ export interface HistoryPlacementChange {
14
+ readonly node: Node;
15
+ readonly before: HistoryPlacement;
16
+ readonly after: HistoryPlacement;
17
+ }
18
+ /**
19
+ * 已由其 owner 正常提交的外部 authored change。
20
+ * History 只在线性、非重入的 undo/redo 回放中调用这些方法,不负责首次执行。
21
+ * 每个方法只恢复该 change 自己拥有的数据,不得操纵当前 HistoryManager 的栈。
22
+ */
23
+ export interface HistoryChange {
24
+ undo(): void;
25
+ redo(): void;
26
+ }
27
+ export interface EditorHistoryEntry {
28
+ readonly properties: readonly HistoryPropertyChange[];
29
+ readonly lineTrees: readonly HistoryLineTreeChange[];
30
+ readonly placements: readonly HistoryPlacementChange[];
31
+ readonly changes: readonly HistoryChange[];
32
+ readonly selectionBefore: readonly string[];
33
+ readonly selectionAfter: readonly string[];
34
+ }
35
+ export interface HistoryScope extends ChangeHistorySink {
36
+ /** 把已完成的外部 change 加入本 scope;不会立即调用 undo/redo。 */
37
+ record(change: HistoryChange): void;
38
+ /**
39
+ * 完成 semantic scope;返回值只表示 Canvas configured 是否有净变化。
40
+ * 仅有 HistoryChange 时仍形成 entry,但返回 false。
41
+ */
42
+ finish(selectionAfter: readonly Element[]): boolean;
43
+ discard(): void;
44
+ }
45
+ export interface HistorySelectionAdapter {
46
+ finishInteraction(): void;
47
+ getSelection(): readonly Element[];
48
+ hasConfiguredChangeListener(): boolean;
49
+ publishConfiguredChange(): void;
50
+ restoreSelection(elements: readonly Element[]): void;
51
+ completeReplay(type: "select:undo" | "select:redo", elements: readonly Element[], configuredChanged: boolean): void;
52
+ }
53
+ export interface HistoryLineTreeChange {
54
+ readonly owner: LineTree;
55
+ readonly delta: LineTreeTopologyDelta;
56
+ }
57
+ export declare class HistoryManager {
58
+ private readonly root;
59
+ private readonly limit;
60
+ enabled: boolean;
61
+ private undoStack;
62
+ private redoStack;
63
+ private selectionAdapter;
64
+ constructor(root: Root, limit?: number);
65
+ get undoCount(): number;
66
+ get redoCount(): number;
67
+ bindSelection(adapter: HistorySelectionAdapter | null): void;
68
+ openScope(selectionBefore?: readonly Element<import("@fulate/core").ElementProperties, import("@fulate/core").BaseElementOption<any>, Partial<Omit<import("@fulate/core").BaseElementOption<any>, "key" | "children">>>[]): HistoryScope | undefined;
69
+ /** @internal Publishes one completed actual configured semantic change. */
70
+ publishConfiguredChange(changed: boolean | undefined): void;
71
+ /** @internal 只由存在Canvas净变化或外部change的scope完成时写入。 */
72
+ push(entry: EditorHistoryEntry): void;
73
+ clear(): void;
74
+ private buildPropertyChanges;
75
+ private buildStructureChanges;
76
+ private buildLineTreeChanges;
77
+ private replay;
78
+ /**
79
+ * 线性撤销栈顶 entry。当前调用返回前,不得同步重入本 manager 的
80
+ * undo、redo、clear 或 push;HistoryChange 只恢复自己拥有的数据。
81
+ */
82
+ undo(): void;
83
+ /**
84
+ * 线性重做栈顶 entry。当前调用返回前,不得同步重入本 manager 的
85
+ * undo、redo、clear 或 push;HistoryChange 只恢复自己拥有的数据。
86
+ */
87
+ redo(): void;
88
+ }
@@ -0,0 +1,17 @@
1
+ export { checkElement } from "./select/checkElement";
2
+ export { Select } from "./select/index";
3
+ export type { ConnectionGesture, CopyContext, ClipboardDataProducer, DeleteContext, FlipDirection, PasteContext, PasteOptions, PasteParentResolver, ResizeAnchor, ResizeOptions, SelectedPropertyPatch, SelectKeyboardCommands, SelectOption, ToolsConnectionIntent } from "./select/index";
4
+ export { Snap } from "./select/snap";
5
+ export { HistoryManager } from "./history/index";
6
+ export type { EditorHistoryEntry, HistoryChange, HistoryPlacementChange, HistoryPropertyChange, HistoryScope } from "./history/index";
7
+ export { LineTool } from "./line/index";
8
+ export type { LineToolOption } from "./line/index";
9
+ export { Rule } from "./rule/index";
10
+ export type { RuleOption } from "./rule/index";
11
+ export { EditorLayer } from "./editor-layer";
12
+ export { alignElements } from "./select/align";
13
+ export type { AlignType } from "./select/align";
14
+ export { ArrangeType } from "./select/arrange";
15
+ export type { ClipboardPlugin } from "./select/clipboard";
16
+ export { serializeScene, serializeSceneToJSON, deserializeElement, restoreScene, parseFileData, exportToFile, importFromFile } from "@fulate/import";
17
+ export type { ElementFilter, FileData, DeserializeFactories, DeserializeFactory } from "@fulate/import";