@fulate/ui 1.0.5 → 1.0.7
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/README.md +12 -10
- package/dist/authored-path.d.ts +3 -3
- package/dist/editor/capability.d.ts +16 -1
- package/dist/editor/shape.d.ts +18 -3
- package/dist/editor/transform.d.ts +1 -1
- package/dist/floating.d.ts +4 -6
- package/dist/group.d.ts +28 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +263 -85
- package/dist/line/base.d.ts +1 -1
- package/dist/line-tree/index.d.ts +2 -2
- package/dist/line-tree/topology.d.ts +3 -3
- package/dist/line-tree/transform.d.ts +4 -0
- package/dist/polygon.d.ts +1 -1
- package/dist/text/layout.d.ts +0 -2
- package/dist/text/paint.d.ts +0 -10
- package/dist/vector-path.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,8 +133,9 @@ Rectangle、Triangle及其他Shape省略`backgroundColor`/`borderColor`时读取
|
|
|
133
133
|
`skin.lineStroke`。显式值始终优先,Shape的显式`null`关闭绘制,显式字段清回`undefined`后立即重新
|
|
134
134
|
继承Skin。Skin改变只触发现有Root/Layer重绘,不改写element、branch topology或History。
|
|
135
135
|
|
|
136
|
-
LineTree整体resize
|
|
137
|
-
world pose;包括反向scale在内,只有目标anchor改变world位置,其他points
|
|
136
|
+
LineTree整体resize把全部拓扑点按完整仿射写回 authored topology。随后Point移动或插入anchor时在
|
|
137
|
+
同一owner change内保留当前world pose;包括反向scale在内,只有目标anchor改变world位置,其他points
|
|
138
|
+
保持不动。
|
|
138
139
|
|
|
139
140
|
## Text 尺寸与显示
|
|
140
141
|
|
|
@@ -234,14 +235,15 @@ const behavior = {
|
|
|
234
235
|
};
|
|
235
236
|
```
|
|
236
237
|
|
|
237
|
-
`OwnerDirect` 用于不绘制单选 frame、首次位移可直接提升 owner drag 的自定义对象;Group 使用
|
|
238
|
-
`DirectChild` dive,普通 Shape/Line 使用 `Standard`。Transform provider 在 gesture start 捕获 frozen
|
|
239
|
-
reference 与领域 owned state,每帧只纯解析最终 owner change;frame-authored Shape、pose-authored
|
|
240
|
-
Group 与 authored-geometry Line/Polygon/VectorPath 共用 Core reference-transform primitive,结构化
|
|
241
|
-
authored value 不为 caller isolation clone。Group 的稳定 reference 由创建时的 width/height/origin 与
|
|
242
|
-
pose 拥有;当前 content bounds 是只读 local derived view。Line/LineTree 的
|
|
243
|
-
固定world paint padding不贡献ancestor content bounds,但仍进入各自render coverage
|
|
244
|
-
|
|
238
|
+
`OwnerDirect` 用于不绘制单选 frame、首次位移可直接提升 owner drag 的自定义对象;Group 使用
|
|
239
|
+
`DirectChild` dive,普通 Shape/Line 使用 `Standard`。Transform provider 在 gesture start 捕获 frozen
|
|
240
|
+
reference 与领域 owned state,每帧只纯解析最终 owner change;frame-authored Shape、pose-authored
|
|
241
|
+
Group 与 authored-geometry Line/Polygon/VectorPath 共用 Core reference-transform primitive,结构化
|
|
242
|
+
authored value 不为 caller isolation clone。Group 的稳定 reference 由创建时的 width/height/origin 与
|
|
243
|
+
pose 拥有;当前 content bounds 是只读 local derived view。Line/LineTree 的
|
|
244
|
+
固定world paint padding不贡献ancestor content bounds,但仍进入各自render coverage。普通Group
|
|
245
|
+
move/rotate只写自身pose;Group或多选resize/flip递归写入子元素的frame或矢量geometry。group/ungroup
|
|
246
|
+
只转换 local pose,保留 width/path/contour/topology、effect 与 relation 的值和引用。
|
|
245
247
|
|
|
246
248
|
`selectable:false`只限制Editor交互选择,并对该owner分支生效:普通点击、marquee、Select All与
|
|
247
249
|
Group DirectChild下钻都不能进入该分支。公开`Select.select(elements)`和History selection replay由
|
package/dist/authored-path.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAuthoredLineSubpath, type AnchorId, type AuthoredSubpath, type SegmentId } from "@fulate/core";
|
|
2
|
-
import type
|
|
2
|
+
import { type PointView, type Rect } from "@fulate/share";
|
|
3
3
|
export { createAuthoredLineSubpath };
|
|
4
4
|
/** Replace one authored anchor point while retaining its record and all IDs. */
|
|
5
5
|
export declare function replaceAuthoredAnchorPoint(subpath: AuthoredSubpath, anchorId: AnchorId, point: PointView): AuthoredSubpath;
|
|
@@ -22,7 +22,7 @@ export declare function insertAuthoredLineAnchor(subpath: AuthoredSubpath, segme
|
|
|
22
22
|
export declare function replaceAuthoredCubicHandle(subpath: AuthoredSubpath, segmentId: SegmentId, role: "cubic-control-1" | "cubic-control-2", point: PointView): AuthoredSubpath;
|
|
23
23
|
/** Delete one anchor and merge its predecessor directly to its successor. */
|
|
24
24
|
export declare function removeAuthoredAnchor(subpath: AuthoredSubpath, anchorId: AnchorId, minimumAnchorCount?: number): AuthoredSubpath;
|
|
25
|
-
/**
|
|
26
|
-
export declare function
|
|
25
|
+
/** Transform coordinates while retaining every subpath, anchor, segment, and record ID. */
|
|
26
|
+
export declare function transformAuthoredSubpath(subpath: AuthoredSubpath, matrix: DOMMatrixReadOnly): AuthoredSubpath;
|
|
27
27
|
/** Read bounds directly from authored anchor coordinates. */
|
|
28
28
|
export declare function getAuthoredSubpathBounds(subpath: AuthoredSubpath): Readonly<Rect> | null;
|
|
@@ -12,6 +12,11 @@ export interface EditorCapabilityHost {
|
|
|
12
12
|
}
|
|
13
13
|
/** 创建一个不携带字符串 key 或元数据的 capability token。 */
|
|
14
14
|
export declare function defineEditorCapability<T>(): EditorCapabilityToken<T>;
|
|
15
|
+
/**
|
|
16
|
+
* @internal Match one token and check that its provider implements the capability.
|
|
17
|
+
* TypeScript cannot narrow the requested generic from the opaque token identity.
|
|
18
|
+
*/
|
|
19
|
+
export declare function provideEditorCapability<T, Capability>(token: EditorCapabilityToken<T>, supported: EditorCapabilityToken<Capability>, provider: NoInfer<Capability>): T | undefined;
|
|
15
20
|
/** 判断元素是否直接提供 capability 查询入口。 */
|
|
16
21
|
export declare function isEditorCapabilityHost(element: Element): element is Element & EditorCapabilityHost;
|
|
17
22
|
/** @internal 执行一次窄 host 判断和一次 direct capability 查询。 */
|
|
@@ -47,7 +52,11 @@ export interface TransformInteractionCapability<Owned = unknown> {
|
|
|
47
52
|
/** Optional authored/layout bounds used by the editor transform frame. */
|
|
48
53
|
getSelectionFrameBounds?(): Readonly<Rect> | null;
|
|
49
54
|
captureTransformBaseline(): ElementTransformBaseline<Owned>;
|
|
50
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Resolves every owner change for this transform. Composite owners may return
|
|
57
|
+
* multiple child changes; the editor commits the complete result in one batch.
|
|
58
|
+
*/
|
|
59
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<Owned>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
51
60
|
}
|
|
52
61
|
export interface SnapSourceCapability {
|
|
53
62
|
getWorldSnapPointsView(): readonly PointView[];
|
|
@@ -146,5 +155,11 @@ export declare const SelectionBehaviorCapabilityToken: EditorCapabilityToken<Sel
|
|
|
146
155
|
export declare const TransformInteractionCapabilityToken: EditorCapabilityToken<TransformInteractionCapability<unknown>>;
|
|
147
156
|
export declare const SnapSourceCapabilityToken: EditorCapabilityToken<SnapSourceCapability>;
|
|
148
157
|
export declare const PointEditingCapabilityToken: EditorCapabilityToken<PointEditingCapability>;
|
|
158
|
+
/**
|
|
159
|
+
* Resolve the local rectangle used as an editor selection frame. An owner
|
|
160
|
+
* supplied frame is authoritative; owners without one retain a deterministic
|
|
161
|
+
* local visual/layout fallback.
|
|
162
|
+
*/
|
|
163
|
+
export declare function resolveSelectionFrameBounds(element: Element, capability?: TransformInteractionCapability): Readonly<Rect>;
|
|
149
164
|
export declare const ContentEditingCapabilityToken: EditorCapabilityToken<ContentEditingCapability>;
|
|
150
165
|
export {};
|
package/dist/editor/shape.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import { type Layer, type PropertyChanges, type Root, Shape, ShapeProperties, ShapeTransform, type ConnectionPortConfiguration, type ElementOptionPatch, type ElementTransformBaseline, type ReparentTransformIntent, type ShapeOption, type TransformIntent } from "@fulate/core";
|
|
2
|
-
import { Bound } from "@fulate/share";
|
|
2
|
+
import { Bound, type PointView, type Rect } from "@fulate/share";
|
|
3
3
|
import { SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, type EditorCapabilityToken, type SelectionBehaviorCapability, type SnapSourceCapability, type TransformInteractionCapability } from "./capability";
|
|
4
|
+
export interface WorldRectPointsViewCache {
|
|
5
|
+
source: Readonly<Rect> | null;
|
|
6
|
+
a: number;
|
|
7
|
+
b: number;
|
|
8
|
+
c: number;
|
|
9
|
+
d: number;
|
|
10
|
+
e: number;
|
|
11
|
+
f: number;
|
|
12
|
+
points: readonly PointView[] | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function createWorldRectPointsViewCache(): WorldRectPointsViewCache;
|
|
15
|
+
/** Project one stable local frame to a borrowed world-point view. */
|
|
16
|
+
export declare function getWorldRectPointsView(cache: WorldRectPointsViewCache, frame: Readonly<Rect>, matrix: DOMMatrixReadOnly): readonly PointView[];
|
|
4
17
|
/** UI frame-authored Shape 系列共享的 direct Editor provider。 */
|
|
5
18
|
export declare abstract class EditorShape<P extends ShapeProperties = ShapeProperties, O extends ShapeOption<any> = ShapeOption<any>> extends Shape<P, O> implements SelectionBehaviorCapability, TransformInteractionCapability, SnapSourceCapability {
|
|
6
19
|
private connectionPortDecoration;
|
|
20
|
+
private readonly worldSnapPointsCache;
|
|
7
21
|
getEditorCapability<T>(token: EditorCapabilityToken<T>): T | undefined;
|
|
8
22
|
getSelectionBehavior(): {
|
|
9
23
|
readonly mode: SelectionBehaviorMode.Standard;
|
|
@@ -17,11 +31,12 @@ export declare abstract class EditorShape<P extends ShapeProperties = ShapePrope
|
|
|
17
31
|
readonly rotationPivot: "adjustable";
|
|
18
32
|
};
|
|
19
33
|
captureTransformBaseline(): ElementTransformBaseline;
|
|
20
|
-
resolveTransformChange(baseline: Readonly<ElementTransformBaseline>, intent: Readonly<TransformIntent | ReparentTransformIntent>): import("@fulate/core").OwnerPropertyChange;
|
|
34
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly import("@fulate/core").OwnerPropertyChange[];
|
|
35
|
+
getSelectionFrameBounds(): Readonly<Rect> | null;
|
|
21
36
|
setOptions(options?: ElementOptionPatch<O>): this;
|
|
22
37
|
replacePorts(value: ConnectionPortConfiguration): this;
|
|
23
38
|
restorePropertySnapshot(snapshot: Record<string, unknown>): this;
|
|
24
|
-
getWorldSnapPointsView(): readonly
|
|
39
|
+
getWorldSnapPointsView(): readonly PointView[];
|
|
25
40
|
paint(ctx?: CanvasRenderingContext2D): void;
|
|
26
41
|
/** 绘制宿主本体;`paint()` 随后统一绘制 custom Port decoration。 */
|
|
27
42
|
protected paintHost(ctx: CanvasRenderingContext2D): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Element, type ElementOptionPatch, type ElementTransformBaseline, type OwnerPropertyChange, type ReparentTransformIntent, type TransformIntent } from "@fulate/core";
|
|
2
2
|
import { type Rect } from "@fulate/share";
|
|
3
3
|
/** @internal frame-authored provider 共用的纯 resolver。 */
|
|
4
|
-
export declare function resolveFrameTransformChange(owner: Element, baseline: Readonly<ElementTransformBaseline>, intent: Readonly<TransformIntent | ReparentTransformIntent>): OwnerPropertyChange;
|
|
4
|
+
export declare function resolveFrameTransformChange(owner: Element, baseline: Readonly<ElementTransformBaseline>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
5
5
|
/** @internal 捕获一次 owner reference;structured ownedState 直接保留原引用。 */
|
|
6
6
|
export declare function captureElementTransformBaseline<Owned>(owner: Element, writeMode: "frame-authored" | "authored-geometry" | "pose-authored", ownedState: Owned): ElementTransformBaseline<Owned>;
|
|
7
7
|
/** @internal Geometry reference 变化时保持当前 world pose 的最小 frame patch。 */
|
package/dist/floating.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Element
|
|
2
|
-
import { type ComputePositionConfig
|
|
3
|
-
export {
|
|
4
|
-
export type {
|
|
1
|
+
import { Element } from "@fulate/core";
|
|
2
|
+
import { type ComputePositionConfig } from "@floating-ui/core";
|
|
3
|
+
export { flip, offset, shift } from "@floating-ui/core";
|
|
4
|
+
export type { Placement } from "@floating-ui/core";
|
|
5
5
|
export type ComputePositionOptions = Omit<ComputePositionConfig, "platform" | "strategy">;
|
|
6
|
-
/** Creates a Floating UI platform backed by one Fulate Root's world space. */
|
|
7
|
-
export declare function createFloatingPlatform(root: Root): Platform;
|
|
8
6
|
/** Computes world-space coordinates without mutating either element. */
|
|
9
7
|
export declare function computePosition(reference: Element, floating: Element, options?: ComputePositionOptions): Promise<import("@floating-ui/core").ComputePositionReturn>;
|
package/dist/group.d.ts
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
|
-
import { Element, ElementTransform, type BaseElementOption, type ElementTransformBaseline, type ReparentTransformIntent, type TransformIntent } from "@fulate/core";
|
|
2
|
-
import { Bound, type PointView } from "@fulate/share";
|
|
3
|
-
import { SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, type EditorCapabilityToken } from "./editor/capability";
|
|
1
|
+
import { ChangeImpact, Element, ElementTransform, type BaseElementOption, type ElementTransformBaseline, type ReparentTransformIntent, type TransformIntent } from "@fulate/core";
|
|
2
|
+
import { Bound, type BoundingBox, type PointView } from "@fulate/share";
|
|
3
|
+
import { SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, type EditorCapabilityToken, type TransformInteractionCapability } from "./editor/capability";
|
|
4
|
+
interface GroupTransformChildBaseline {
|
|
5
|
+
readonly capability: TransformInteractionCapability;
|
|
6
|
+
readonly baseline: ReturnType<TransformInteractionCapability["captureTransformBaseline"]>;
|
|
7
|
+
}
|
|
8
|
+
interface GroupTransformOwnedState {
|
|
9
|
+
readonly children: readonly GroupTransformChildBaseline[];
|
|
10
|
+
}
|
|
4
11
|
export interface GroupOption extends BaseElementOption<Group> {
|
|
5
12
|
}
|
|
6
13
|
export declare class GroupTransform<E extends Group = Group> extends ElementTransform<E> {
|
|
7
14
|
private localContentBounds;
|
|
15
|
+
private localSelectionFrameBounds;
|
|
8
16
|
protected onChildrenChanged(): void;
|
|
9
17
|
protected onDescendantDirty(_child: ElementTransform, affectsContentBounds: boolean): void;
|
|
10
18
|
private invalidateContentBounds;
|
|
19
|
+
invalidate(impact: ChangeImpact, previousBounds?: Readonly<BoundingBox> | null): void;
|
|
11
20
|
/** @internal Group-local canonical content subtree bounds. */
|
|
12
21
|
getLocalContentBoundsView(): Readonly<Bound> | null;
|
|
22
|
+
/** @internal Group-local selection frame derived from child owner frames. */
|
|
23
|
+
getLocalSelectionFrameBoundsView(): Readonly<Bound> | null;
|
|
13
24
|
/** Group 是 content bounds owner;ancestor 只投影这份 local view。 */
|
|
14
25
|
protected collectContentBoundsInReference(parentMatrix: DOMMatrixReadOnly, _referenceWorldInverse: DOMMatrixReadOnly): Bound;
|
|
15
26
|
/** 只合并真实 content members;不贡献 content bounds 的 branch 返回 null。 */
|
|
16
27
|
protected buildLocalContentBounds(): Bound | null;
|
|
28
|
+
/**
|
|
29
|
+
* Build the frame used by selection/transform/snap. Text-like owners expose
|
|
30
|
+
* authored frame bounds that intentionally exclude paint overflow; owners
|
|
31
|
+
* without that capability retain an explicit content/visual fallback.
|
|
32
|
+
*/
|
|
33
|
+
protected buildLocalSelectionFrameBounds(): Bound | null;
|
|
17
34
|
protected buildLocalHitBounds(): Readonly<Bound>;
|
|
18
35
|
protected containsLocalHitPoint(point: PointView): boolean;
|
|
19
36
|
protected buildVisualBounds(): Readonly<Bound>;
|
|
@@ -25,6 +42,8 @@ export declare class GroupTransform<E extends Group = Group> extends ElementTran
|
|
|
25
42
|
}
|
|
26
43
|
export declare class Group extends Element {
|
|
27
44
|
readonly type = "group";
|
|
45
|
+
private readonly worldSnapPointsCache;
|
|
46
|
+
readonly transform: GroupTransform<this>;
|
|
28
47
|
constructor(options?: GroupOption);
|
|
29
48
|
getEditorCapability<T>(token: EditorCapabilityToken<T>): T | undefined;
|
|
30
49
|
getSelectionBehavior(): {
|
|
@@ -38,7 +57,11 @@ export declare class Group extends Element {
|
|
|
38
57
|
readonly rotate: true;
|
|
39
58
|
readonly rotationPivot: "adjustable";
|
|
40
59
|
};
|
|
41
|
-
captureTransformBaseline(): ElementTransformBaseline<
|
|
42
|
-
|
|
60
|
+
captureTransformBaseline(): ElementTransformBaseline<{
|
|
61
|
+
children: GroupTransformChildBaseline[];
|
|
62
|
+
}>;
|
|
63
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<GroupTransformOwnedState>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly import("@fulate/core").OwnerPropertyChange[];
|
|
43
64
|
getWorldSnapPointsView(): readonly PointView[];
|
|
65
|
+
getSelectionFrameBounds(): Readonly<Bound>;
|
|
44
66
|
}
|
|
67
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { measureTextWidth,
|
|
1
|
+
export { measureTextWidth, subscribeTextMeasurementChanges } from "./text/layout";
|
|
2
2
|
export type { TextLayoutLine, TextLayoutMetrics, TextLayoutOptions, TextLayoutSnapshot } from "./text/layout";
|
|
3
3
|
export { measureTextRun } from "./text/paint";
|
|
4
4
|
export { paintTextBlock } from "./text/paint";
|
|
@@ -22,11 +22,11 @@ export { WorkerSurfacePool } from "./worker-surface";
|
|
|
22
22
|
export type { WorkerSurfaceHandle, WorkerSurfacePoolOptions } from "./worker-surface";
|
|
23
23
|
export { fitWorkspace, workspaceFocusInsetsKey, Workspace, WorkspaceProperties } from "./workspace";
|
|
24
24
|
export type { WorkspaceFocusInsetsSource, WorkspaceFitOptions, WorkspaceJSON, WorkspaceOption } from "./workspace";
|
|
25
|
-
export {
|
|
26
|
-
export type { ComputePositionOptions,
|
|
25
|
+
export { computePosition, flip, offset, shift } from "./floating";
|
|
26
|
+
export type { ComputePositionOptions, Placement } from "./floating";
|
|
27
27
|
export { Group, GroupTransform } from "./group";
|
|
28
28
|
export type { GroupOption } from "./group";
|
|
29
|
-
export { ContentEditingCapabilityToken, PointEditingCapabilityToken, SelectionBehaviorMode, SelectionBehaviorCapabilityToken, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, TransformInteractionCapabilityToken, defineEditorCapability, getEditorCapability, isEditorCapabilityHost } from "./editor/capability";
|
|
29
|
+
export { ContentEditingCapabilityToken, PointEditingCapabilityToken, SelectionBehaviorMode, SelectionBehaviorCapabilityToken, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, TransformInteractionCapabilityToken, defineEditorCapability, getEditorCapability, isEditorCapabilityHost, resolveSelectionFrameBounds } from "./editor/capability";
|
|
30
30
|
export type { ContentEditingCapability, ContentEditingConsumer, ContentEditingSession, EditorCapabilityHost, EditorCapabilityToken, PointControlDescriptor, PointEditRequest, PointEditTarget, PointEditingCapability, PointEditingScope, PointOwnerEdit, SelectionBehavior, SelectionBehaviorCapability, SnapSourceCapability, TransformInteractionCapability, TransformInteractionPolicy } from "./editor/capability";
|
|
31
31
|
export { EditorFrameFlush, getEditorFrameFlush } from "./editor/frame-flush";
|
|
32
32
|
export type { EditorAuthoredGesture, EditorOverlayClient, EditorSpatialClient } from "./editor/frame-flush";
|
|
@@ -37,7 +37,7 @@ export type { RippleOption } from "./ripple";
|
|
|
37
37
|
export { BaseLine, LineTransform, Line } from "./line/index";
|
|
38
38
|
export { connectionPortAccepts, connectEndpoint, disconnectEndpoint, getEndpointRelationIndex, hasConnectionPortCapacity, isEndpointRelationSource, resolveConnectionPortChanges, resolveConnectEndpointChange, resolveDisconnectEndpointChanges, EndpointRelationIndex } from "./connection";
|
|
39
39
|
export type { BindableEndpoint, EndpointConnectionRole, EndpointRef, EndpointRelation, EndpointRelationBinding, EndpointRelationSource } from "./connection";
|
|
40
|
-
export { LineTree, LineTreeProperties, LineTreeTransform, EMPTY_LINE_TREE_TOPOLOGY, DEFAULT_LINE_TREE_BRANCH_STYLE, addLineTreeBranchAtTail, createLineTreeTopology, getLineTreeBranch, getLineTreeBindableEndpoints, getLineTreeEndpointRelationBindings, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, insertLineTreePoint, moveLineTreePoint, removeLineTreeBranch, removeLineTreePoint, remapLineTreeRelations,
|
|
40
|
+
export { LineTree, LineTreeProperties, LineTreeTransform, EMPTY_LINE_TREE_TOPOLOGY, DEFAULT_LINE_TREE_BRANCH_STYLE, addLineTreeBranchAtTail, createLineTreeTopology, getLineTreeBranch, getLineTreeBindableEndpoints, getLineTreeEndpointRelationBindings, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, insertLineTreePoint, moveLineTreePoint, removeLineTreeBranch, removeLineTreePoint, remapLineTreeRelations, transformLineTreeTopology, updateLineTreeBranchStyle } from "./line-tree";
|
|
41
41
|
export type { LineTreeBranch, LineTreeBranchRemoval, LineTreeBranchTailSource, LineTreeBranchStyle, LineTreeBranchVertex, LineTreeOption, LineTreePoint, LineTreeTopology } from "./line-tree";
|
|
42
42
|
export { applyLineTreeTopologyDelta, createLineTreeTopologyDelta } from "./line-tree/history-delta";
|
|
43
43
|
export type { LineTreeTopologyDelta } from "./line-tree/history-delta";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { clearCache, layoutNextLineRange, layoutWithLines, materializeLineRange, measureLineStats, measureNaturalWidth, prepareWithSegments } from "@chenglou/pretext";
|
|
2
|
-
import { ChangeImpact, CustomEvent, Element, ElementProperties, ElementTransform, SKIN_DEFAULTS, Shape, ShapeProperties, ShapeTransform, createAuthoredLineSubpath, createGeometrySnapshot, createLineSubpath, createPathLocalId, evaluatePathSegmentPoint, getElementConnectionPort, getElementConnectionPortPoint, isReparentTransformIntent, resolveAuthoredSubpath, resolveReferenceTransform, resolveReferenceTransformTarget, splitPathSegment } from "@fulate/core";
|
|
2
|
+
import { ChangeImpact, CustomEvent, Element, ElementProperties, ElementTransform, SKIN_DEFAULTS, Shape, ShapeProperties, ShapeTransform, createAuthoredLineSubpath, createGeometrySnapshot, createLineSubpath, createPathLocalId, evaluatePathSegmentPoint, getElementConnectionPort, getElementConnectionPortPoint, isReparentTransformIntent, resolveAuthoredGeometryFramePatch, resolveAuthoredSubpath, resolveReferenceTransform, resolveReferenceTransformTarget, splitPathSegment } from "@fulate/core";
|
|
3
3
|
import { clamp, isFunction, isNil, isNull, isString, isUndefined } from "lodash-es";
|
|
4
|
-
import { Bound, Intersection, createCanvasGradient, createPointView, isGradient, isPointWithinDistance, rectEdgePosition, transformPoint } from "@fulate/share";
|
|
5
|
-
import {
|
|
4
|
+
import { Bound, Intersection, createCanvasGradient, createPointView, isGradient, isIdentityMatrix, isPointWithinDistance, rectEdgePosition, transformPoint } from "@fulate/share";
|
|
5
|
+
import { computePosition as computePosition$1, flip, offset, shift } from "@floating-ui/core";
|
|
6
6
|
import { Easing, Tween } from "@tweenjs/tween.js";
|
|
7
7
|
//#region packages/ui/src/text/layout.ts
|
|
8
8
|
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
@@ -136,10 +136,6 @@ function ellipsizeText(text, maxWidth, font, letterSpacing, force) {
|
|
|
136
136
|
width: measure(value)
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
|
-
/** Fit a single run and append an ellipsis only when it does not fit. */
|
|
140
|
-
function fitTextWithEllipsis(text, maxWidth, font, letterSpacing = 0) {
|
|
141
|
-
return ellipsizeText(text, maxWidth, font, letterSpacing, false).text;
|
|
142
|
-
}
|
|
143
139
|
var PreparedTextLayout = class {
|
|
144
140
|
normalizedText;
|
|
145
141
|
naturalWidth;
|
|
@@ -530,7 +526,7 @@ function updateTextareaPosition(self) {
|
|
|
530
526
|
if (!root) return;
|
|
531
527
|
const { scale, x: vx, y: vy } = root.viewport;
|
|
532
528
|
self.transform.bubbleUpdateTransform();
|
|
533
|
-
const m = self.transform.
|
|
529
|
+
const m = self.transform.getWorldMatrixView();
|
|
534
530
|
const style = self.getResolvedTextStyle();
|
|
535
531
|
const { x: cx, y: cy, h } = getCaretLocalXY(self, ta.selectionStart ?? self.text.length);
|
|
536
532
|
const screenX = (m.a * cx + m.c * cy + m.e) * scale + vx;
|
|
@@ -1124,8 +1120,9 @@ var ConnectionPortDecoration = class {
|
|
|
1124
1120
|
traceCirclePath(ctx, position, DOT_RADIUS);
|
|
1125
1121
|
ctx.fill();
|
|
1126
1122
|
}
|
|
1123
|
+
const worldMatrix = entries.some(({ block }) => block) ? this.host.transform.getWorldMatrixView() : void 0;
|
|
1127
1124
|
for (const entry of entries) {
|
|
1128
|
-
const placement = this.resolveLabelPlacement(entry);
|
|
1125
|
+
const placement = this.resolveLabelPlacement(entry, worldMatrix);
|
|
1129
1126
|
if (!placement) continue;
|
|
1130
1127
|
const { block } = entry;
|
|
1131
1128
|
if (!block) continue;
|
|
@@ -1156,7 +1153,7 @@ var ConnectionPortDecoration = class {
|
|
|
1156
1153
|
height: DOT_RADIUS * 2
|
|
1157
1154
|
});
|
|
1158
1155
|
bounds = bounds ? bounds.merge(dotBounds) : dotBounds;
|
|
1159
|
-
const placement = this.resolveLabelPlacement(entry);
|
|
1156
|
+
const placement = this.resolveLabelPlacement(entry, worldMatrix);
|
|
1160
1157
|
if (!placement?.entry.block) continue;
|
|
1161
1158
|
const textBounds = getTextBlockVisualBounds(placement.entry.block.layout, placement.style, placement.width, placement.height);
|
|
1162
1159
|
if (!textBounds) continue;
|
|
@@ -1182,7 +1179,7 @@ var ConnectionPortDecoration = class {
|
|
|
1182
1179
|
}
|
|
1183
1180
|
return this.entries;
|
|
1184
1181
|
}
|
|
1185
|
-
resolveLabelPlacement(entry) {
|
|
1182
|
+
resolveLabelPlacement(entry, worldMatrix) {
|
|
1186
1183
|
const { slot, block } = entry;
|
|
1187
1184
|
if (!block) return null;
|
|
1188
1185
|
const definition = slot.definition;
|
|
@@ -1194,7 +1191,7 @@ var ConnectionPortDecoration = class {
|
|
|
1194
1191
|
if (width === 0) return null;
|
|
1195
1192
|
const localAlign = slot.edge === "left" ? "right" : slot.edge === "right" ? "left" : "center";
|
|
1196
1193
|
const upright = definition.keepLabelUpright !== false;
|
|
1197
|
-
const worldNormal = upright ? transformVector(
|
|
1194
|
+
const worldNormal = upright ? transformVector(worldMatrix, nx, ny) : null;
|
|
1198
1195
|
const align = worldNormal ? Math.abs(worldNormal.x) >= Math.abs(worldNormal.y) ? worldNormal.x >= 0 ? "left" : "right" : "center" : localAlign;
|
|
1199
1196
|
const style = this.getStyle(entry, align);
|
|
1200
1197
|
const lineHeight = style.fontSize * style.lineHeight;
|
|
@@ -1235,7 +1232,7 @@ var ConnectionPortDecoration = class {
|
|
|
1235
1232
|
width,
|
|
1236
1233
|
height
|
|
1237
1234
|
};
|
|
1238
|
-
const uprightMatrix = upright ? this.buildUprightMatrix(position, nx, ny, width, height) : null;
|
|
1235
|
+
const uprightMatrix = upright ? this.buildUprightMatrix(position, nx, ny, width, height, worldMatrix) : null;
|
|
1239
1236
|
if (upright && !uprightMatrix) return null;
|
|
1240
1237
|
return {
|
|
1241
1238
|
entry,
|
|
@@ -1264,8 +1261,7 @@ var ConnectionPortDecoration = class {
|
|
|
1264
1261
|
entry.styles[align] = style;
|
|
1265
1262
|
return style;
|
|
1266
1263
|
}
|
|
1267
|
-
buildUprightMatrix(position, nx, ny, width, height) {
|
|
1268
|
-
const matrix = this.host.transform.getWorldMatrixView();
|
|
1264
|
+
buildUprightMatrix(position, nx, ny, width, height, matrix) {
|
|
1269
1265
|
const worldPosition = transformPoint(matrix, position);
|
|
1270
1266
|
const normal = transformVector(matrix, nx, ny);
|
|
1271
1267
|
const normalLength = Math.hypot(normal.x, normal.y);
|
|
@@ -1576,9 +1572,13 @@ function resolveConnectionPortChanges(root, changes) {
|
|
|
1576
1572
|
if (Object.is(owner.ports, next)) continue;
|
|
1577
1573
|
const nextIds = new Set(next === false ? [] : next === true ? owner.resolveConnectionPorts(true).map(({ ref }) => ref.portId) : next.map(({ id }) => id));
|
|
1578
1574
|
index ??= getEndpointRelationIndex(root);
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1575
|
+
const previousPortIds = owner.ports === false ? [] : owner.ports === true ? owner.resolveConnectionPorts(true).map(({ ref }) => ref.portId) : owner.ports.map(({ id }) => id);
|
|
1576
|
+
for (const portId of previousPortIds) {
|
|
1577
|
+
if (nextIds.has(portId)) continue;
|
|
1578
|
+
const targeting = index.relationsTargetingPort({
|
|
1579
|
+
elementKey: owner.key,
|
|
1580
|
+
portId
|
|
1581
|
+
});
|
|
1582
1582
|
if (targeting.length > 0) (sources ??= []).push(...targeting);
|
|
1583
1583
|
}
|
|
1584
1584
|
}
|
|
@@ -1604,6 +1604,13 @@ function commitConnectionPortPatch(owner, patch) {
|
|
|
1604
1604
|
function defineEditorCapability() {
|
|
1605
1605
|
return {};
|
|
1606
1606
|
}
|
|
1607
|
+
/**
|
|
1608
|
+
* @internal Match one token and check that its provider implements the capability.
|
|
1609
|
+
* TypeScript cannot narrow the requested generic from the opaque token identity.
|
|
1610
|
+
*/
|
|
1611
|
+
function provideEditorCapability(token, supported, provider) {
|
|
1612
|
+
return token === supported ? provider : void 0;
|
|
1613
|
+
}
|
|
1607
1614
|
/** 判断元素是否直接提供 capability 查询入口。 */
|
|
1608
1615
|
function isEditorCapabilityHost(element) {
|
|
1609
1616
|
return isFunction(element.getEditorCapability);
|
|
@@ -1631,6 +1638,14 @@ var SelectionBehaviorCapabilityToken = defineEditorCapability();
|
|
|
1631
1638
|
var TransformInteractionCapabilityToken = defineEditorCapability();
|
|
1632
1639
|
var SnapSourceCapabilityToken = defineEditorCapability();
|
|
1633
1640
|
var PointEditingCapabilityToken = defineEditorCapability();
|
|
1641
|
+
/**
|
|
1642
|
+
* Resolve the local rectangle used as an editor selection frame. An owner
|
|
1643
|
+
* supplied frame is authoritative; owners without one retain a deterministic
|
|
1644
|
+
* local visual/layout fallback.
|
|
1645
|
+
*/
|
|
1646
|
+
function resolveSelectionFrameBounds(element, capability) {
|
|
1647
|
+
return capability?.getSelectionFrameBounds?.() ?? element.transform.getLocalVisualBoundsView() ?? element.transform.getLayoutReferenceBoundsView();
|
|
1648
|
+
}
|
|
1634
1649
|
var ContentEditingCapabilityToken = defineEditorCapability();
|
|
1635
1650
|
//#endregion
|
|
1636
1651
|
//#region packages/ui/src/editor/transform.ts
|
|
@@ -1664,10 +1679,10 @@ function readElementTransformBaseline(owner, writeMode, ownedState) {
|
|
|
1664
1679
|
}
|
|
1665
1680
|
/** @internal frame-authored provider 共用的纯 resolver。 */
|
|
1666
1681
|
function resolveFrameTransformChange(owner, baseline, intent) {
|
|
1667
|
-
return {
|
|
1682
|
+
return [{
|
|
1668
1683
|
owner,
|
|
1669
1684
|
patch: resolveReferenceTransform(baseline.reference, intent).framePatch
|
|
1670
|
-
};
|
|
1685
|
+
}];
|
|
1671
1686
|
}
|
|
1672
1687
|
/** @internal 捕获一次 owner reference;structured ownedState 直接保留原引用。 */
|
|
1673
1688
|
function captureElementTransformBaseline(owner, writeMode, ownedState) {
|
|
@@ -1703,11 +1718,58 @@ var FRAME_TRANSFORM_POLICY = {
|
|
|
1703
1718
|
rotate: true,
|
|
1704
1719
|
rotationPivot: "adjustable"
|
|
1705
1720
|
};
|
|
1721
|
+
function getRectCorners(rect) {
|
|
1722
|
+
const right = rect.left + rect.width;
|
|
1723
|
+
const bottom = rect.top + rect.height;
|
|
1724
|
+
return [
|
|
1725
|
+
{
|
|
1726
|
+
x: rect.left,
|
|
1727
|
+
y: rect.top
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
x: right,
|
|
1731
|
+
y: rect.top
|
|
1732
|
+
},
|
|
1733
|
+
{
|
|
1734
|
+
x: right,
|
|
1735
|
+
y: bottom
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
x: rect.left,
|
|
1739
|
+
y: bottom
|
|
1740
|
+
}
|
|
1741
|
+
];
|
|
1742
|
+
}
|
|
1743
|
+
function createWorldRectPointsViewCache() {
|
|
1744
|
+
return {
|
|
1745
|
+
source: null,
|
|
1746
|
+
a: NaN,
|
|
1747
|
+
b: NaN,
|
|
1748
|
+
c: NaN,
|
|
1749
|
+
d: NaN,
|
|
1750
|
+
e: NaN,
|
|
1751
|
+
f: NaN,
|
|
1752
|
+
points: null
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
/** Project one stable local frame to a borrowed world-point view. */
|
|
1756
|
+
function getWorldRectPointsView(cache, frame, matrix) {
|
|
1757
|
+
if (cache.source === frame && cache.points && cache.a === matrix.a && cache.b === matrix.b && cache.c === matrix.c && cache.d === matrix.d && cache.e === matrix.e && cache.f === matrix.f) return cache.points;
|
|
1758
|
+
cache.source = frame;
|
|
1759
|
+
cache.a = matrix.a;
|
|
1760
|
+
cache.b = matrix.b;
|
|
1761
|
+
cache.c = matrix.c;
|
|
1762
|
+
cache.d = matrix.d;
|
|
1763
|
+
cache.e = matrix.e;
|
|
1764
|
+
cache.f = matrix.f;
|
|
1765
|
+
return cache.points = getRectCorners(frame).map((point) => transformPoint(matrix, point));
|
|
1766
|
+
}
|
|
1706
1767
|
/** UI frame-authored Shape 系列共享的 direct Editor provider。 */
|
|
1707
|
-
var EditorShape = class extends Shape {
|
|
1768
|
+
var EditorShape = class EditorShape extends Shape {
|
|
1708
1769
|
connectionPortDecoration = null;
|
|
1770
|
+
worldSnapPointsCache = createWorldRectPointsViewCache();
|
|
1709
1771
|
getEditorCapability(token) {
|
|
1710
|
-
return token
|
|
1772
|
+
return provideEditorCapability(token, SelectionBehaviorCapabilityToken, this) ?? provideEditorCapability(token, TransformInteractionCapabilityToken, this) ?? provideEditorCapability(token, SnapSourceCapabilityToken, this);
|
|
1711
1773
|
}
|
|
1712
1774
|
getSelectionBehavior() {
|
|
1713
1775
|
return STANDARD_SELECTION;
|
|
@@ -1721,12 +1783,16 @@ var EditorShape = class extends Shape {
|
|
|
1721
1783
|
resolveTransformChange(baseline, intent) {
|
|
1722
1784
|
return resolveFrameTransformChange(this, baseline, intent);
|
|
1723
1785
|
}
|
|
1786
|
+
getSelectionFrameBounds() {
|
|
1787
|
+
return null;
|
|
1788
|
+
}
|
|
1724
1789
|
setOptions(options) {
|
|
1725
1790
|
if (!options) return this;
|
|
1726
1791
|
if (commitConnectionPortPatch(this, options)) return this;
|
|
1727
1792
|
return super.setOptions(options);
|
|
1728
1793
|
}
|
|
1729
1794
|
replacePorts(value) {
|
|
1795
|
+
if (this.ports === value && EditorShape.getConfiguredPropertyValue(this, "ports") === value) return this;
|
|
1730
1796
|
return this.setOptions({ ports: value });
|
|
1731
1797
|
}
|
|
1732
1798
|
restorePropertySnapshot(snapshot) {
|
|
@@ -1734,6 +1800,8 @@ var EditorShape = class extends Shape {
|
|
|
1734
1800
|
return super.restorePropertySnapshot(snapshot);
|
|
1735
1801
|
}
|
|
1736
1802
|
getWorldSnapPointsView() {
|
|
1803
|
+
const frame = this.getSelectionFrameBounds();
|
|
1804
|
+
if (frame) return getWorldRectPointsView(this.worldSnapPointsCache, frame, this.transform.getWorldMatrixView());
|
|
1737
1805
|
return this.transform.getWorldVisualPointsView();
|
|
1738
1806
|
}
|
|
1739
1807
|
paint(ctx = this.layer.ctx) {
|
|
@@ -2254,24 +2322,18 @@ function removeAuthoredAnchor(subpath, anchorId, minimumAnchorCount = 2) {
|
|
|
2254
2322
|
anchors
|
|
2255
2323
|
};
|
|
2256
2324
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
y: point.y * scaleY
|
|
2261
|
-
};
|
|
2262
|
-
}
|
|
2263
|
-
/** Scale coordinates while retaining every subpath, anchor, segment, and record ID. */
|
|
2264
|
-
function scaleAuthoredSubpath(subpath, scaleX, scaleY) {
|
|
2265
|
-
if (scaleX === 1 && scaleY === 1) return subpath;
|
|
2325
|
+
/** Transform coordinates while retaining every subpath, anchor, segment, and record ID. */
|
|
2326
|
+
function transformAuthoredSubpath(subpath, matrix) {
|
|
2327
|
+
if (isIdentityMatrix(matrix)) return subpath;
|
|
2266
2328
|
return {
|
|
2267
2329
|
...subpath,
|
|
2268
2330
|
anchors: subpath.anchors.map((anchor) => {
|
|
2269
|
-
const point =
|
|
2331
|
+
const point = transformPoint(matrix, anchor.point);
|
|
2270
2332
|
return "control1" in anchor ? {
|
|
2271
2333
|
...anchor,
|
|
2272
2334
|
point,
|
|
2273
|
-
control1:
|
|
2274
|
-
control2:
|
|
2335
|
+
control1: transformPoint(matrix, anchor.control1),
|
|
2336
|
+
control2: transformPoint(matrix, anchor.control2)
|
|
2275
2337
|
} : {
|
|
2276
2338
|
...anchor,
|
|
2277
2339
|
point
|
|
@@ -2410,7 +2472,7 @@ var Polygon = class extends EditorShape {
|
|
|
2410
2472
|
};
|
|
2411
2473
|
}
|
|
2412
2474
|
getEditorCapability(token) {
|
|
2413
|
-
return token
|
|
2475
|
+
return provideEditorCapability(token, PointEditingCapabilityToken, this) ?? super.getEditorCapability(token);
|
|
2414
2476
|
}
|
|
2415
2477
|
resolvePointScope(worldPoint) {
|
|
2416
2478
|
return this.transform.hasPointHint(worldPoint) ? { kind: "owner" } : null;
|
|
@@ -2476,19 +2538,25 @@ var Polygon = class extends EditorShape {
|
|
|
2476
2538
|
}
|
|
2477
2539
|
resolveTransformChange(baseline, intent) {
|
|
2478
2540
|
const transform = resolveReferenceTransform(baseline.reference, intent);
|
|
2479
|
-
const contour =
|
|
2541
|
+
const contour = transformAuthoredSubpath(baseline.ownedState, transform.authoredLocalDelta);
|
|
2480
2542
|
const bounds = contour === baseline.ownedState || contour.anchors.length < 2 ? null : getAuthoredSubpathBounds(contour);
|
|
2481
|
-
|
|
2543
|
+
const framePatch = bounds && intent.bakeGeometry && !isReparentTransformIntent(intent) ? resolveAuthoredGeometryFramePatch(baseline.reference, transform, bounds) : transform.framePatch;
|
|
2544
|
+
const restoredFrameSize = intent.bakeGeometry && !isReparentTransformIntent(intent) && contour === baseline.ownedState ? {
|
|
2545
|
+
width: baseline.reference.frame.width,
|
|
2546
|
+
height: baseline.reference.frame.height
|
|
2547
|
+
} : {};
|
|
2548
|
+
return [{
|
|
2482
2549
|
owner: this,
|
|
2483
2550
|
patch: {
|
|
2484
|
-
...
|
|
2551
|
+
...framePatch,
|
|
2552
|
+
...restoredFrameSize,
|
|
2485
2553
|
contour,
|
|
2486
2554
|
...bounds ? {
|
|
2487
2555
|
width: bounds.width || 1,
|
|
2488
2556
|
height: bounds.height || 1
|
|
2489
2557
|
} : {}
|
|
2490
2558
|
}
|
|
2491
|
-
};
|
|
2559
|
+
}];
|
|
2492
2560
|
}
|
|
2493
2561
|
buildPath(ctx) {
|
|
2494
2562
|
if (this.contour.anchors.length < 3) {
|
|
@@ -2713,7 +2781,7 @@ var VectorPath = class extends EditorShape {
|
|
|
2713
2781
|
};
|
|
2714
2782
|
}
|
|
2715
2783
|
getEditorCapability(token) {
|
|
2716
|
-
return token
|
|
2784
|
+
return provideEditorCapability(token, PointEditingCapabilityToken, this) ?? super.getEditorCapability(token);
|
|
2717
2785
|
}
|
|
2718
2786
|
resolvePointScope(worldPoint) {
|
|
2719
2787
|
return this.transform.hasPointHint(worldPoint) ? { kind: "owner" } : null;
|
|
@@ -2814,21 +2882,25 @@ var VectorPath = class extends EditorShape {
|
|
|
2814
2882
|
}
|
|
2815
2883
|
resolveTransformChange(baseline, intent) {
|
|
2816
2884
|
const transform = resolveReferenceTransform(baseline.reference, intent);
|
|
2817
|
-
const
|
|
2818
|
-
const scaleY = transform.authoredLocalDelta.d;
|
|
2819
|
-
const path = scaleX === 1 && scaleY === 1 ? baseline.ownedState : { subpaths: baseline.ownedState.subpaths.map((subpath) => scaleAuthoredSubpath(subpath, scaleX, scaleY)) };
|
|
2885
|
+
const path = isIdentityMatrix(transform.authoredLocalDelta) ? baseline.ownedState : { subpaths: baseline.ownedState.subpaths.map((subpath) => transformAuthoredSubpath(subpath, transform.authoredLocalDelta)) };
|
|
2820
2886
|
const bounds = path === baseline.ownedState ? null : createVectorPathSnapshot("", 0, path).layoutReferenceBounds;
|
|
2821
|
-
|
|
2887
|
+
const framePatch = bounds && intent.bakeGeometry && !isReparentTransformIntent(intent) ? resolveAuthoredGeometryFramePatch(baseline.reference, transform, bounds) : transform.framePatch;
|
|
2888
|
+
const restoredFrameSize = intent.bakeGeometry && !isReparentTransformIntent(intent) && path === baseline.ownedState ? {
|
|
2889
|
+
width: baseline.reference.frame.width,
|
|
2890
|
+
height: baseline.reference.frame.height
|
|
2891
|
+
} : {};
|
|
2892
|
+
return [{
|
|
2822
2893
|
owner: this,
|
|
2823
2894
|
patch: {
|
|
2824
|
-
...
|
|
2895
|
+
...framePatch,
|
|
2896
|
+
...restoredFrameSize,
|
|
2825
2897
|
path,
|
|
2826
2898
|
...bounds ? {
|
|
2827
2899
|
width: bounds.width || 1,
|
|
2828
2900
|
height: bounds.height || 1
|
|
2829
2901
|
} : {}
|
|
2830
2902
|
}
|
|
2831
|
-
};
|
|
2903
|
+
}];
|
|
2832
2904
|
}
|
|
2833
2905
|
buildPath(ctx) {
|
|
2834
2906
|
this.buildResolvedPath(ctx);
|
|
@@ -3031,7 +3103,7 @@ var Text = class extends Rectangle {
|
|
|
3031
3103
|
super(options, properties, Transform);
|
|
3032
3104
|
}
|
|
3033
3105
|
getEditorCapability(token) {
|
|
3034
|
-
return token
|
|
3106
|
+
return provideEditorCapability(token, ContentEditingCapabilityToken, this) ?? super.getEditorCapability(token);
|
|
3035
3107
|
}
|
|
3036
3108
|
beginContentEditing(consumer) {
|
|
3037
3109
|
if (!this.editable || this.isEditing) return;
|
|
@@ -3440,7 +3512,10 @@ var Image = class extends Bitmap {
|
|
|
3440
3512
|
const pixelRatio = this.renderPixelRatio;
|
|
3441
3513
|
const needW = Math.ceil((this.width || this.naturalWidth) * pixelRatio);
|
|
3442
3514
|
const needH = Math.ceil((this.height || this.naturalHeight) * pixelRatio);
|
|
3443
|
-
if (needW > this.renderSize.w * UPGRADE_RATIO || needH > this.renderSize.h * UPGRADE_RATIO)
|
|
3515
|
+
if (needW > this.renderSize.w * UPGRADE_RATIO || needH > this.renderSize.h * UPGRADE_RATIO) {
|
|
3516
|
+
const nextSize = this.calcAutoSize(this.naturalWidth, this.naturalHeight);
|
|
3517
|
+
if (nextSize.w > this.renderSize.w || nextSize.h > this.renderSize.h) this.loadAndProcess();
|
|
3518
|
+
}
|
|
3444
3519
|
}
|
|
3445
3520
|
loadHTMLImage(src) {
|
|
3446
3521
|
return new Promise((resolve, reject) => {
|
|
@@ -3680,7 +3755,7 @@ function isRect(value) {
|
|
|
3680
3755
|
return typeof rect.x === "number" && typeof rect.y === "number" && typeof rect.width === "number" && typeof rect.height === "number";
|
|
3681
3756
|
}
|
|
3682
3757
|
function getDimensions(element) {
|
|
3683
|
-
const bounds = element.transform.
|
|
3758
|
+
const bounds = element.transform.getWorldVisualBoundsView();
|
|
3684
3759
|
return {
|
|
3685
3760
|
width: element.width ?? bounds.width,
|
|
3686
3761
|
height: element.height ?? bounds.height
|
|
@@ -3688,15 +3763,15 @@ function getDimensions(element) {
|
|
|
3688
3763
|
}
|
|
3689
3764
|
function getClippingRect(root, boundary, rootBoundary) {
|
|
3690
3765
|
if (isRect(boundary)) return boundary;
|
|
3691
|
-
if (boundary instanceof Element) return toRect(boundary.transform.
|
|
3766
|
+
if (boundary instanceof Element) return toRect(boundary.transform.getWorldVisualBoundsView());
|
|
3692
3767
|
if (isRect(rootBoundary)) return rootBoundary;
|
|
3693
|
-
return toRect(root.viewport.
|
|
3768
|
+
return toRect(root.viewport.getWorldRectView());
|
|
3694
3769
|
}
|
|
3695
3770
|
/** Creates a Floating UI platform backed by one Fulate Root's world space. */
|
|
3696
3771
|
function createFloatingPlatform(root) {
|
|
3697
3772
|
return {
|
|
3698
3773
|
getElementRects: ({ reference, floating }) => ({
|
|
3699
|
-
reference: toRect(reference.transform.
|
|
3774
|
+
reference: toRect(reference.transform.getWorldVisualBoundsView()),
|
|
3700
3775
|
floating: {
|
|
3701
3776
|
x: 0,
|
|
3702
3777
|
y: 0,
|
|
@@ -3722,8 +3797,31 @@ function computePosition(reference, floating, options = {}) {
|
|
|
3722
3797
|
}
|
|
3723
3798
|
//#endregion
|
|
3724
3799
|
//#region packages/ui/src/group.ts
|
|
3800
|
+
function rectCorners(rect) {
|
|
3801
|
+
const right = rect.left + rect.width;
|
|
3802
|
+
const bottom = rect.top + rect.height;
|
|
3803
|
+
return [
|
|
3804
|
+
{
|
|
3805
|
+
x: rect.left,
|
|
3806
|
+
y: rect.top
|
|
3807
|
+
},
|
|
3808
|
+
{
|
|
3809
|
+
x: right,
|
|
3810
|
+
y: rect.top
|
|
3811
|
+
},
|
|
3812
|
+
{
|
|
3813
|
+
x: right,
|
|
3814
|
+
y: bottom
|
|
3815
|
+
},
|
|
3816
|
+
{
|
|
3817
|
+
x: rect.left,
|
|
3818
|
+
y: bottom
|
|
3819
|
+
}
|
|
3820
|
+
];
|
|
3821
|
+
}
|
|
3725
3822
|
var GroupTransform = class extends ElementTransform {
|
|
3726
3823
|
localContentBounds;
|
|
3824
|
+
localSelectionFrameBounds;
|
|
3727
3825
|
onChildrenChanged() {
|
|
3728
3826
|
this.invalidateContentBounds();
|
|
3729
3827
|
}
|
|
@@ -3731,14 +3829,25 @@ var GroupTransform = class extends ElementTransform {
|
|
|
3731
3829
|
if (affectsContentBounds) this.invalidateContentBounds();
|
|
3732
3830
|
}
|
|
3733
3831
|
invalidateContentBounds() {
|
|
3734
|
-
this.localContentBounds = void 0;
|
|
3735
3832
|
this.invalidate(ChangeImpact.VisualBounds | ChangeImpact.HitBounds);
|
|
3736
3833
|
}
|
|
3834
|
+
invalidate(impact, previousBounds) {
|
|
3835
|
+
if (impact & (ChangeImpact.LocalGeometry | ChangeImpact.VisualBounds | ChangeImpact.HitBounds)) {
|
|
3836
|
+
this.localContentBounds = void 0;
|
|
3837
|
+
this.localSelectionFrameBounds = void 0;
|
|
3838
|
+
}
|
|
3839
|
+
super.invalidate(impact, previousBounds);
|
|
3840
|
+
}
|
|
3737
3841
|
/** @internal Group-local canonical content subtree bounds. */
|
|
3738
3842
|
getLocalContentBoundsView() {
|
|
3739
3843
|
if (this.localContentBounds !== void 0) return this.localContentBounds;
|
|
3740
3844
|
return this.localContentBounds = this.buildLocalContentBounds();
|
|
3741
3845
|
}
|
|
3846
|
+
/** @internal Group-local selection frame derived from child owner frames. */
|
|
3847
|
+
getLocalSelectionFrameBoundsView() {
|
|
3848
|
+
if (this.localSelectionFrameBounds !== void 0) return this.localSelectionFrameBounds;
|
|
3849
|
+
return this.localSelectionFrameBounds = this.buildLocalSelectionFrameBounds();
|
|
3850
|
+
}
|
|
3742
3851
|
/** Group 是 content bounds owner;ancestor 只投影这份 local view。 */
|
|
3743
3852
|
collectContentBoundsInReference(parentMatrix, _referenceWorldInverse) {
|
|
3744
3853
|
if (!this.element.visible) return null;
|
|
@@ -3766,6 +3875,33 @@ var GroupTransform = class extends ElementTransform {
|
|
|
3766
3875
|
bounds.maxY = Math.min(bounds.maxY, clip.top + clip.height);
|
|
3767
3876
|
return bounds.minX < bounds.maxX && bounds.minY < bounds.maxY ? bounds : null;
|
|
3768
3877
|
}
|
|
3878
|
+
/**
|
|
3879
|
+
* Build the frame used by selection/transform/snap. Text-like owners expose
|
|
3880
|
+
* authored frame bounds that intentionally exclude paint overflow; owners
|
|
3881
|
+
* without that capability retain an explicit content/visual fallback.
|
|
3882
|
+
*/
|
|
3883
|
+
buildLocalSelectionFrameBounds() {
|
|
3884
|
+
const childWorldInverse = this.getChildWorldInverseMatrixView();
|
|
3885
|
+
let bounds = null;
|
|
3886
|
+
for (const child of this.element.children) {
|
|
3887
|
+
if (!child.visible) continue;
|
|
3888
|
+
const localFrame = getEditorCapability(child, TransformInteractionCapabilityToken)?.getSelectionFrameBounds?.();
|
|
3889
|
+
const points = localFrame ? rectCorners(localFrame).map((point) => transformPoint(childWorldInverse, transformPoint(child.transform.getWorldMatrixView(), point))) : (() => {
|
|
3890
|
+
const content = child.transform.getContentBoundsInParentView();
|
|
3891
|
+
return content ? rectCorners(content) : [];
|
|
3892
|
+
})();
|
|
3893
|
+
if (points.length === 0) continue;
|
|
3894
|
+
const childBounds = Bound.fromPoints(points);
|
|
3895
|
+
bounds = bounds ? bounds.merge(childBounds) : childBounds;
|
|
3896
|
+
}
|
|
3897
|
+
const clip = bounds && this.element.getChildClipRect();
|
|
3898
|
+
if (!bounds || !clip) return bounds;
|
|
3899
|
+
bounds.minX = Math.max(bounds.minX, clip.left);
|
|
3900
|
+
bounds.minY = Math.max(bounds.minY, clip.top);
|
|
3901
|
+
bounds.maxX = Math.min(bounds.maxX, clip.left + clip.width);
|
|
3902
|
+
bounds.maxY = Math.min(bounds.maxY, clip.top + clip.height);
|
|
3903
|
+
return bounds.minX < bounds.maxX && bounds.minY < bounds.maxY ? bounds : null;
|
|
3904
|
+
}
|
|
3769
3905
|
buildLocalHitBounds() {
|
|
3770
3906
|
return this.getLocalContentBoundsView();
|
|
3771
3907
|
}
|
|
@@ -3799,16 +3935,18 @@ var GroupTransform = class extends ElementTransform {
|
|
|
3799
3935
|
}
|
|
3800
3936
|
dispose() {
|
|
3801
3937
|
this.localContentBounds = void 0;
|
|
3938
|
+
this.localSelectionFrameBounds = void 0;
|
|
3802
3939
|
super.dispose();
|
|
3803
3940
|
}
|
|
3804
3941
|
};
|
|
3805
3942
|
var Group = class extends Element {
|
|
3806
3943
|
type = "group";
|
|
3944
|
+
worldSnapPointsCache = createWorldRectPointsViewCache();
|
|
3807
3945
|
constructor(options = {}) {
|
|
3808
3946
|
super(options, new ElementProperties(options), GroupTransform);
|
|
3809
3947
|
}
|
|
3810
3948
|
getEditorCapability(token) {
|
|
3811
|
-
return token
|
|
3949
|
+
return provideEditorCapability(token, SelectionBehaviorCapabilityToken, this) ?? provideEditorCapability(token, TransformInteractionCapabilityToken, this) ?? provideEditorCapability(token, SnapSourceCapabilityToken, this);
|
|
3812
3950
|
}
|
|
3813
3951
|
getSelectionBehavior() {
|
|
3814
3952
|
return {
|
|
@@ -3826,14 +3964,29 @@ var Group = class extends Element {
|
|
|
3826
3964
|
};
|
|
3827
3965
|
}
|
|
3828
3966
|
captureTransformBaseline() {
|
|
3829
|
-
|
|
3967
|
+
const children = [];
|
|
3968
|
+
for (const child of this.children) {
|
|
3969
|
+
const capability = getEditorCapability(child, TransformInteractionCapabilityToken);
|
|
3970
|
+
if (!capability) continue;
|
|
3971
|
+
children.push({
|
|
3972
|
+
capability,
|
|
3973
|
+
baseline: capability.captureTransformBaseline()
|
|
3974
|
+
});
|
|
3975
|
+
}
|
|
3976
|
+
return captureElementTransformBaseline(this, "pose-authored", { children });
|
|
3830
3977
|
}
|
|
3831
3978
|
resolveTransformChange(baseline, intent) {
|
|
3979
|
+
if (intent.bakeGeometry && !isReparentTransformIntent(intent)) return baseline.ownedState.children.flatMap(({ capability, baseline }) => capability.resolveTransformChange(baseline, intent));
|
|
3832
3980
|
return resolveFrameTransformChange(this, baseline, intent);
|
|
3833
3981
|
}
|
|
3834
3982
|
getWorldSnapPointsView() {
|
|
3983
|
+
const frame = this.transform.getLocalSelectionFrameBoundsView();
|
|
3984
|
+
if (frame) return getWorldRectPointsView(this.worldSnapPointsCache, frame, this.transform.getWorldMatrixView());
|
|
3835
3985
|
return this.transform.getWorldVisualPointsView();
|
|
3836
3986
|
}
|
|
3987
|
+
getSelectionFrameBounds() {
|
|
3988
|
+
return this.transform.getLocalSelectionFrameBoundsView();
|
|
3989
|
+
}
|
|
3837
3990
|
};
|
|
3838
3991
|
//#endregion
|
|
3839
3992
|
//#region packages/ui/src/editor/frame-flush.ts
|
|
@@ -4694,7 +4847,7 @@ var BaseLine = class extends Element {
|
|
|
4694
4847
|
return bindings;
|
|
4695
4848
|
}
|
|
4696
4849
|
getEditorCapability(token) {
|
|
4697
|
-
return token
|
|
4850
|
+
return provideEditorCapability(token, SelectionBehaviorCapabilityToken, this) ?? provideEditorCapability(token, TransformInteractionCapabilityToken, this) ?? provideEditorCapability(token, SnapSourceCapabilityToken, this);
|
|
4698
4851
|
}
|
|
4699
4852
|
getSelectionBehavior() {
|
|
4700
4853
|
return {
|
|
@@ -4745,16 +4898,19 @@ var BaseLine = class extends Element {
|
|
|
4745
4898
|
}
|
|
4746
4899
|
resolveTransformChange(baseline, intent) {
|
|
4747
4900
|
const effective = isReparentTransformIntent(intent) ? void 0 : baseline.ownedState.effective;
|
|
4748
|
-
const
|
|
4749
|
-
const
|
|
4750
|
-
|
|
4901
|
+
const reference = effective?.reference ?? baseline.reference;
|
|
4902
|
+
const transform = resolveReferenceTransform(reference, intent);
|
|
4903
|
+
const path = transformAuthoredSubpath(effective?.path ?? baseline.ownedState.path, transform.authoredLocalDelta);
|
|
4904
|
+
const bounds = intent.bakeGeometry && !isReparentTransformIntent(intent) && path.anchors.length > 1 ? getAuthoredSubpathBounds(path) : null;
|
|
4905
|
+
const framePatch = bounds ? resolveAuthoredGeometryFramePatch(reference, transform, bounds) : transform.framePatch;
|
|
4906
|
+
return [{
|
|
4751
4907
|
owner: this,
|
|
4752
4908
|
patch: {
|
|
4753
|
-
...
|
|
4909
|
+
...framePatch,
|
|
4754
4910
|
path,
|
|
4755
4911
|
...effective?.relationPatch ? { relations: effective.relationPatch } : {}
|
|
4756
4912
|
}
|
|
4757
|
-
};
|
|
4913
|
+
}];
|
|
4758
4914
|
}
|
|
4759
4915
|
resolveOptions(options) {
|
|
4760
4916
|
const resolved = resolveLinePatch(options);
|
|
@@ -4978,7 +5134,7 @@ var Line = class extends BaseLine {
|
|
|
4978
5134
|
super(options);
|
|
4979
5135
|
}
|
|
4980
5136
|
getEditorCapability(token) {
|
|
4981
|
-
return token
|
|
5137
|
+
return provideEditorCapability(token, PointEditingCapabilityToken, this) ?? super.getEditorCapability(token);
|
|
4982
5138
|
}
|
|
4983
5139
|
resolvePointScope(worldPoint) {
|
|
4984
5140
|
return this.transform.hasPointHint(worldPoint) ? { kind: "owner" } : null;
|
|
@@ -5174,11 +5330,6 @@ function getLineTreeBindableEndpoints(topology, elementKey) {
|
|
|
5174
5330
|
anchorId
|
|
5175
5331
|
} }));
|
|
5176
5332
|
}
|
|
5177
|
-
function getLineTreeEndpointRole(topology, anchorId) {
|
|
5178
|
-
if (!getLineTreePoint(topology, anchorId)) return null;
|
|
5179
|
-
if (getLineTreePointDegrees(topology).get(anchorId) !== 1) return null;
|
|
5180
|
-
return (topology.rootSubpathId === void 0 ? void 0 : getLineTreeBranch(topology, topology.rootSubpathId))?.vertices[0]?.anchorId === anchorId ? "output" : "input";
|
|
5181
|
-
}
|
|
5182
5333
|
function moveLineTreePoint(topology, anchorId, point, relation) {
|
|
5183
5334
|
const index = topology.points.findIndex((candidate) => candidate.anchorId === anchorId);
|
|
5184
5335
|
const current = topology.points[index];
|
|
@@ -5328,16 +5479,13 @@ function updateLineTreeBranchStyle(topology, subpathId, style) {
|
|
|
5328
5479
|
branches
|
|
5329
5480
|
};
|
|
5330
5481
|
}
|
|
5331
|
-
function
|
|
5332
|
-
if (
|
|
5482
|
+
function transformLineTreeTopology(topology, matrix) {
|
|
5483
|
+
if (isIdentityMatrix(matrix)) return topology;
|
|
5333
5484
|
return {
|
|
5334
5485
|
...topology,
|
|
5335
5486
|
points: topology.points.map((point) => ({
|
|
5336
5487
|
...point,
|
|
5337
|
-
point:
|
|
5338
|
-
x: point.point.x * scaleX,
|
|
5339
|
-
y: point.point.y * scaleY
|
|
5340
|
-
}
|
|
5488
|
+
point: transformPoint(matrix, point.point)
|
|
5341
5489
|
}))
|
|
5342
5490
|
};
|
|
5343
5491
|
}
|
|
@@ -5375,12 +5523,14 @@ var LineTreeTransform = class extends ElementTransform {
|
|
|
5375
5523
|
topologySource = null;
|
|
5376
5524
|
pointById = /* @__PURE__ */ new Map();
|
|
5377
5525
|
branchById = /* @__PURE__ */ new Map();
|
|
5526
|
+
endpointRoleById;
|
|
5378
5527
|
junctionAnchorIds = [];
|
|
5379
5528
|
junctionAnchorIdSet = /* @__PURE__ */ new Set();
|
|
5380
5529
|
layoutBounds = null;
|
|
5381
5530
|
resolvedPointById = /* @__PURE__ */ new Map();
|
|
5382
5531
|
worldGeometrySource = null;
|
|
5383
5532
|
worldBranchPoints = [];
|
|
5533
|
+
worldBranchPointsById = /* @__PURE__ */ new Map();
|
|
5384
5534
|
worldPointById = /* @__PURE__ */ new Map();
|
|
5385
5535
|
worldSnapPoints = [];
|
|
5386
5536
|
worldMatrixA = NaN;
|
|
@@ -5395,10 +5545,22 @@ var LineTreeTransform = class extends ElementTransform {
|
|
|
5395
5545
|
this.topologySource = topology;
|
|
5396
5546
|
this.pointById = new Map(topology.points.map((point) => [point.anchorId, point]));
|
|
5397
5547
|
this.branchById = new Map(topology.branches.map((branch) => [branch.subpathId, branch]));
|
|
5548
|
+
this.endpointRoleById = void 0;
|
|
5398
5549
|
this.junctionAnchorIds = getLineTreeJunctionAnchorIds(topology);
|
|
5399
5550
|
this.junctionAnchorIdSet = new Set(this.junctionAnchorIds);
|
|
5400
5551
|
this.layoutBounds = getLineTreeTopologyBounds(topology);
|
|
5401
5552
|
}
|
|
5553
|
+
buildEndpointRoles() {
|
|
5554
|
+
const topology = this.element.topology;
|
|
5555
|
+
const degrees = getLineTreePointDegrees(topology);
|
|
5556
|
+
const rootAnchorId = topology.rootSubpathId === void 0 ? void 0 : this.branchById.get(topology.rootSubpathId)?.vertices[0]?.anchorId;
|
|
5557
|
+
const roles = /* @__PURE__ */ new Map();
|
|
5558
|
+
for (const point of topology.points) {
|
|
5559
|
+
if (degrees.get(point.anchorId) !== 1) continue;
|
|
5560
|
+
roles.set(point.anchorId, point.anchorId === rootAnchorId ? "output" : "input");
|
|
5561
|
+
}
|
|
5562
|
+
return roles;
|
|
5563
|
+
}
|
|
5402
5564
|
getPoint(anchorId) {
|
|
5403
5565
|
this.ensureTopologyViews();
|
|
5404
5566
|
return this.pointById.get(anchorId);
|
|
@@ -5407,6 +5569,11 @@ var LineTreeTransform = class extends ElementTransform {
|
|
|
5407
5569
|
this.ensureTopologyViews();
|
|
5408
5570
|
return this.branchById.get(subpathId);
|
|
5409
5571
|
}
|
|
5572
|
+
getEndpointRole(anchorId) {
|
|
5573
|
+
this.ensureTopologyViews();
|
|
5574
|
+
this.endpointRoleById ??= this.buildEndpointRoles();
|
|
5575
|
+
return this.endpointRoleById.get(anchorId) ?? null;
|
|
5576
|
+
}
|
|
5410
5577
|
getResolvedPoint(anchorId) {
|
|
5411
5578
|
this.getGeometrySnapshot();
|
|
5412
5579
|
return this.resolvedPointById.get(anchorId);
|
|
@@ -5524,14 +5691,17 @@ var LineTreeTransform = class extends ElementTransform {
|
|
|
5524
5691
|
if (vertex.anchorId !== void 0) this.worldPointById.set(vertex.anchorId, world);
|
|
5525
5692
|
return world;
|
|
5526
5693
|
}));
|
|
5694
|
+
this.worldBranchPointsById = /* @__PURE__ */ new Map();
|
|
5695
|
+
snapshot.subpaths.forEach((subpath, index) => {
|
|
5696
|
+
if (subpath.subpathId !== void 0) this.worldBranchPointsById.set(subpath.subpathId, this.worldBranchPoints[index]);
|
|
5697
|
+
});
|
|
5527
5698
|
this.worldSnapPoints = this.element.topology.points.map((point) => {
|
|
5528
5699
|
return this.worldPointById.get(point.anchorId);
|
|
5529
5700
|
});
|
|
5530
5701
|
}
|
|
5531
5702
|
getWorldBranchPointsView(subpathId) {
|
|
5532
5703
|
this.updateWorldPoints();
|
|
5533
|
-
|
|
5534
|
-
return this.worldBranchPoints[index];
|
|
5704
|
+
return this.worldBranchPointsById.get(subpathId);
|
|
5535
5705
|
}
|
|
5536
5706
|
getWorldPointView(anchorId) {
|
|
5537
5707
|
this.updateWorldPoints();
|
|
@@ -5636,7 +5806,7 @@ var LineTree = class extends Element {
|
|
|
5636
5806
|
return this;
|
|
5637
5807
|
}
|
|
5638
5808
|
getEditorCapability(token) {
|
|
5639
|
-
return token
|
|
5809
|
+
return provideEditorCapability(token, SelectionBehaviorCapabilityToken, this) ?? provideEditorCapability(token, TransformInteractionCapabilityToken, this) ?? provideEditorCapability(token, SnapSourceCapabilityToken, this) ?? provideEditorCapability(token, PointEditingCapabilityToken, this);
|
|
5640
5810
|
}
|
|
5641
5811
|
getSelectionBehavior() {
|
|
5642
5812
|
return {
|
|
@@ -5714,20 +5884,28 @@ var LineTree = class extends Element {
|
|
|
5714
5884
|
}
|
|
5715
5885
|
resolveTransformChange(baseline, intent) {
|
|
5716
5886
|
const effective = isReparentTransformIntent(intent) ? void 0 : baseline.ownedState.effective;
|
|
5717
|
-
const
|
|
5718
|
-
|
|
5887
|
+
const bakeGeometry = intent.bakeGeometry && !isReparentTransformIntent(intent);
|
|
5888
|
+
const reference = effective?.reference ?? (bakeGeometry ? {
|
|
5889
|
+
...baseline.reference,
|
|
5890
|
+
writeMode: "authored-geometry"
|
|
5891
|
+
} : baseline.reference);
|
|
5892
|
+
const transform = resolveReferenceTransform(reference, intent);
|
|
5893
|
+
const topology = bakeGeometry ? transformLineTreeTopology(effective?.topology ?? baseline.ownedState.topology, transform.authoredLocalDelta) : effective ? transformLineTreeTopology(effective.topology, transform.authoredLocalDelta) : void 0;
|
|
5894
|
+
const bounds = bakeGeometry && topology ? getLineTreeTopologyBounds(topology) : null;
|
|
5895
|
+
const framePatch = bounds ? resolveAuthoredGeometryFramePatch(reference, transform, bounds) : transform.framePatch;
|
|
5896
|
+
return [{
|
|
5719
5897
|
owner: this,
|
|
5720
5898
|
patch: {
|
|
5721
|
-
...
|
|
5722
|
-
...
|
|
5899
|
+
...framePatch,
|
|
5900
|
+
...topology ? { topology } : {}
|
|
5723
5901
|
}
|
|
5724
|
-
};
|
|
5902
|
+
}];
|
|
5725
5903
|
}
|
|
5726
5904
|
getWorldSnapPointsView() {
|
|
5727
5905
|
return this.transform.getWorldSnapPointsView();
|
|
5728
5906
|
}
|
|
5729
5907
|
getEndpointRole(anchorId) {
|
|
5730
|
-
return
|
|
5908
|
+
return this.transform.getEndpointRole(anchorId);
|
|
5731
5909
|
}
|
|
5732
5910
|
getEndpointRelation(anchorId) {
|
|
5733
5911
|
return this.transform.getPoint(anchorId)?.relation;
|
|
@@ -5748,7 +5926,7 @@ var LineTree = class extends Element {
|
|
|
5748
5926
|
resolveDisconnectEndpointChange(anchorIds, localPositions) {
|
|
5749
5927
|
let topology = this.topology;
|
|
5750
5928
|
for (const anchorId of new Set(anchorIds)) {
|
|
5751
|
-
if (!
|
|
5929
|
+
if (!this.transform.getPoint(anchorId)?.relation) continue;
|
|
5752
5930
|
topology = moveLineTreePoint(topology, anchorId, localPositions?.get(anchorId) ?? this.transform.getResolvedPoint(anchorId).point, void 0);
|
|
5753
5931
|
}
|
|
5754
5932
|
return topology === this.topology ? null : {
|
|
@@ -5833,7 +6011,7 @@ var LineTree = class extends Element {
|
|
|
5833
6011
|
};
|
|
5834
6012
|
}
|
|
5835
6013
|
getBranch(subpathId) {
|
|
5836
|
-
return
|
|
6014
|
+
return this.transform.getBranch(subpathId);
|
|
5837
6015
|
}
|
|
5838
6016
|
resolveSubpathAtWorldPoint(point, preferredSubpathId) {
|
|
5839
6017
|
return this.transform.resolveSubpathAtWorldPoint(point, preferredSubpathId);
|
|
@@ -5967,4 +6145,4 @@ function applyLineTreeTopologyDelta(topology, delta, direction) {
|
|
|
5967
6145
|
};
|
|
5968
6146
|
}
|
|
5969
6147
|
//#endregion
|
|
5970
|
-
export { BaseLine, Bitmap, Circle, CircleTransform, ContentEditingCapabilityToken, DEFAULT_LINE_TREE_BRANCH_STYLE, EMPTY_LINE_TREE_TOPOLOGY, EditorFrameFlush, EndpointRelationIndex, Group, GroupTransform, Image, ImageProperties, ImageTransform, Line, LineTransform, LineTree, LineTreeProperties, LineTreeTransform, PointEditingCapabilityToken, Polygon, PolygonTransform, Rectangle, RectangleProperties, RectangleTransform, RippleOverlay, ScrollView, ScrollViewTransform, SelectionBehaviorCapabilityToken, SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, Text, TextBlock, TextProperties, TextTransform, TransformInteractionCapabilityToken, Triangle, TriangleTransform, VectorPath, VectorPathProperties, VectorPathTransform, WorkerSurfacePool, Workspace, WorkspaceProperties, addLineTreeBranchAtTail, applyLineTreeTopologyDelta,
|
|
6148
|
+
export { BaseLine, Bitmap, Circle, CircleTransform, ContentEditingCapabilityToken, DEFAULT_LINE_TREE_BRANCH_STYLE, EMPTY_LINE_TREE_TOPOLOGY, EditorFrameFlush, EndpointRelationIndex, Group, GroupTransform, Image, ImageProperties, ImageTransform, Line, LineTransform, LineTree, LineTreeProperties, LineTreeTransform, PointEditingCapabilityToken, Polygon, PolygonTransform, Rectangle, RectangleProperties, RectangleTransform, RippleOverlay, ScrollView, ScrollViewTransform, SelectionBehaviorCapabilityToken, SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, Text, TextBlock, TextProperties, TextTransform, TransformInteractionCapabilityToken, Triangle, TriangleTransform, VectorPath, VectorPathProperties, VectorPathTransform, WorkerSurfacePool, Workspace, WorkspaceProperties, addLineTreeBranchAtTail, applyLineTreeTopologyDelta, computePosition, connectEndpoint, connectionPortAccepts, createLineTreeTopology, createLineTreeTopologyDelta, defineEditorCapability, disconnectEndpoint, fitWorkspace, flip, getEditorCapability, getEditorFrameFlush, getEndpointRelationIndex, getLineTreeBindableEndpoints, getLineTreeBranch, getLineTreeEndpointRelationBindings, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, getTextBlockVisualBounds, hasConnectionPortCapacity, insertLineTreePoint, isEditorCapabilityHost, isEndpointRelationSource, measureTextRun, measureTextWidth, moveLineTreePoint, offset, paintTextBlock, remapLineTreeRelations, removeLineTreeBranch, removeLineTreePoint, resolveConnectEndpointChange, resolveConnectionPortChanges, resolveDisconnectEndpointChanges, resolveSelectionFrameBounds, resolveTextStyle, shift, subscribeTextMeasurementChanges, transformLineTreeTopology, updateLineTreeBranchStyle, workspaceFocusInsetsKey };
|
package/dist/line/base.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ export declare abstract class BaseLine extends Element<LineProperties, LineOptio
|
|
|
110
110
|
};
|
|
111
111
|
protected resolvePointPathPatch(path: AuthoredSubpath): LinePatch;
|
|
112
112
|
captureTransformBaseline(): ElementTransformBaseline<LineTransformOwnedState>;
|
|
113
|
-
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<LineTransformOwnedState>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): OwnerPropertyChange;
|
|
113
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<LineTransformOwnedState>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
114
114
|
protected resolveOptions(options: LinePatch): LinePatch;
|
|
115
115
|
get headAnchor(): AuthoredPathAnchor;
|
|
116
116
|
get tailAnchor(): AuthoredPathAnchor;
|
|
@@ -45,7 +45,7 @@ export declare class LineTree extends Element<LineTreeProperties, LineTreeOption
|
|
|
45
45
|
private materializeEffectiveTopology;
|
|
46
46
|
private preservePoseForTopology;
|
|
47
47
|
captureTransformBaseline(): ElementTransformBaseline<LineTreeTransformOwnedState>;
|
|
48
|
-
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<LineTreeTransformOwnedState>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): OwnerPropertyChange;
|
|
48
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<LineTreeTransformOwnedState>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
49
49
|
getWorldSnapPointsView(): readonly PointView[];
|
|
50
50
|
getEndpointRole(anchorId: AnchorId): "input" | "output";
|
|
51
51
|
getEndpointRelation(anchorId: AnchorId): EndpointRelation;
|
|
@@ -70,5 +70,5 @@ export declare class LineTree extends Element<LineTreeProperties, LineTreeOption
|
|
|
70
70
|
protected onDeactivate(root: Root | null, layer: Layer | null): void;
|
|
71
71
|
}
|
|
72
72
|
export { LineTreeTransform } from "./transform";
|
|
73
|
-
export { EMPTY_LINE_TREE_TOPOLOGY, DEFAULT_LINE_TREE_BRANCH_STYLE, addLineTreeBranchAtTail, createLineTreeTopology, getLineTreeBranch, getLineTreeBindableEndpoints, getLineTreeEndpointRelationBindings, getLineTreeEndpointRole, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, insertLineTreePoint, moveLineTreePoint, removeLineTreeBranch, removeLineTreePoint, remapLineTreeRelations,
|
|
73
|
+
export { EMPTY_LINE_TREE_TOPOLOGY, DEFAULT_LINE_TREE_BRANCH_STYLE, addLineTreeBranchAtTail, createLineTreeTopology, getLineTreeBranch, getLineTreeBindableEndpoints, getLineTreeEndpointRelationBindings, getLineTreeEndpointRole, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, insertLineTreePoint, moveLineTreePoint, removeLineTreeBranch, removeLineTreePoint, remapLineTreeRelations, transformLineTreeTopology, updateLineTreeBranchStyle } from "./topology";
|
|
74
74
|
export type { LineTreeBranch, LineTreeBranchRemoval, LineTreeBranchTailSource, LineTreeBranchStyle, LineTreeBranchVertex, LineTreeOption, LineTreePoint, LineTreeTopology } from "./types";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type AnchorId, type SegmentId, type SubpathId } from "@fulate/core";
|
|
2
|
-
import type
|
|
3
|
-
import type { Rect } from "@fulate/share";
|
|
2
|
+
import { type PointView, type Rect } from "@fulate/share";
|
|
4
3
|
import type { LineEndpointRelationPatch } from "../line/base";
|
|
5
4
|
import type { BindableEndpoint, EndpointRelation, EndpointRelationBinding } from "../connection/types";
|
|
6
5
|
import type { LineTreeBranch, LineTreeBranchRemoval, LineTreeBranchStyle, LineTreePoint, LineTreeTopology } from "./types";
|
|
@@ -12,6 +11,7 @@ export declare function getLineTreePoint(topology: LineTreeTopology, anchorId: A
|
|
|
12
11
|
export declare function getLineTreeBranch(topology: LineTreeTopology, subpathId: SubpathId): LineTreeBranch;
|
|
13
12
|
export declare function getLineTreePointReferenceCounts(topology: LineTreeTopology): Map<AnchorId, number>;
|
|
14
13
|
export declare function getLineTreeJunctionAnchorIds(topology: LineTreeTopology): AnchorId[];
|
|
14
|
+
export declare function getLineTreePointDegrees(topology: LineTreeTopology): Map<AnchorId, number>;
|
|
15
15
|
export declare function getLineTreeEndpointRelationBindings(topology: LineTreeTopology, elementKey: string): readonly EndpointRelationBinding[];
|
|
16
16
|
export declare function getLineTreeBindableEndpoints(topology: LineTreeTopology, elementKey: string): readonly BindableEndpoint[];
|
|
17
17
|
export declare function getLineTreeEndpointRole(topology: LineTreeTopology, anchorId: AnchorId): "input" | "output";
|
|
@@ -35,5 +35,5 @@ export declare function addLineTreeBranchAtTail(topology: LineTreeTopology, pare
|
|
|
35
35
|
};
|
|
36
36
|
export declare function removeLineTreeBranch(topology: LineTreeTopology, subpathId: SubpathId): LineTreeBranchRemoval;
|
|
37
37
|
export declare function updateLineTreeBranchStyle(topology: LineTreeTopology, subpathId: SubpathId, style: LineTreeBranchStyle): LineTreeTopology;
|
|
38
|
-
export declare function
|
|
38
|
+
export declare function transformLineTreeTopology(topology: LineTreeTopology, matrix: DOMMatrixReadOnly): LineTreeTopology;
|
|
39
39
|
export declare function remapLineTreeRelations(topology: LineTreeTopology, keyMap: ReadonlyMap<string, string>): LineTreeTopology;
|
|
@@ -6,12 +6,14 @@ export declare class LineTreeTransform<E extends LineTree = LineTree> extends El
|
|
|
6
6
|
private topologySource;
|
|
7
7
|
private pointById;
|
|
8
8
|
private branchById;
|
|
9
|
+
private endpointRoleById;
|
|
9
10
|
private junctionAnchorIds;
|
|
10
11
|
private junctionAnchorIdSet;
|
|
11
12
|
private layoutBounds;
|
|
12
13
|
private resolvedPointById;
|
|
13
14
|
private worldGeometrySource;
|
|
14
15
|
private worldBranchPoints;
|
|
16
|
+
private worldBranchPointsById;
|
|
15
17
|
private worldPointById;
|
|
16
18
|
private worldSnapPoints;
|
|
17
19
|
private worldMatrixA;
|
|
@@ -21,8 +23,10 @@ export declare class LineTreeTransform<E extends LineTree = LineTree> extends El
|
|
|
21
23
|
private worldMatrixE;
|
|
22
24
|
private worldMatrixF;
|
|
23
25
|
private ensureTopologyViews;
|
|
26
|
+
private buildEndpointRoles;
|
|
24
27
|
getPoint(anchorId: AnchorId): LineTreePoint;
|
|
25
28
|
getBranch(subpathId: SubpathId): LineTreeBranch;
|
|
29
|
+
getEndpointRole(anchorId: AnchorId): "input" | "output";
|
|
26
30
|
getResolvedPoint(anchorId: AnchorId): LineTreePoint;
|
|
27
31
|
getJunctionAnchorIds(): readonly AnchorId[];
|
|
28
32
|
isJunctionAnchor(anchorId: AnchorId): boolean;
|
package/dist/polygon.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare class Polygon extends EditorShape<PolygonProperties, PolygonOptio
|
|
|
37
37
|
getPointScopeOutline(_scope: PointEditingScope): any;
|
|
38
38
|
resolvePointEdit(request: PointEditRequest): PointOwnerEdit | null;
|
|
39
39
|
captureTransformBaseline(): ElementTransformBaseline<AuthoredSubpath<import("@fulate/core").AuthoredPathAnchor>>;
|
|
40
|
-
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<AuthoredSubpath>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): OwnerPropertyChange;
|
|
40
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<AuthoredSubpath>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
41
41
|
protected buildPath(ctx: CanvasRenderingContext2D): void;
|
|
42
42
|
protected buildBorderPath(ctx: CanvasRenderingContext2D): void;
|
|
43
43
|
getEdgeSegment(edge: Edge): {
|
package/dist/text/layout.d.ts
CHANGED
|
@@ -38,8 +38,6 @@ export declare function measureTextAlphabeticBaselineOffset(text: string, font:
|
|
|
38
38
|
* `white-space: pre-wrap` keeps the caller's spaces and hard breaks intact.
|
|
39
39
|
*/
|
|
40
40
|
export declare function measureTextWidth(text: string, font: string, letterSpacing?: number): number;
|
|
41
|
-
/** Fit a single run and append an ellipsis only when it does not fit. */
|
|
42
|
-
export declare function fitTextWithEllipsis(text: string, maxWidth: number, font: string, letterSpacing?: number): string;
|
|
43
41
|
declare class PreparedTextLayout {
|
|
44
42
|
readonly text: string;
|
|
45
43
|
readonly font: string;
|
package/dist/text/paint.d.ts
CHANGED
|
@@ -16,16 +16,6 @@ export interface TextDecorationOptions {
|
|
|
16
16
|
thickness?: number;
|
|
17
17
|
}
|
|
18
18
|
export declare function drawTextDecoration(ctx: CanvasRenderingContext2D, opts: TextDecorationOptions): void;
|
|
19
|
-
export interface TextStrokeOptions {
|
|
20
|
-
line: string;
|
|
21
|
-
x: number;
|
|
22
|
-
y: number;
|
|
23
|
-
font: string;
|
|
24
|
-
letterSpacing: number;
|
|
25
|
-
strokeColor: string | CanvasGradient;
|
|
26
|
-
strokeWidth: number;
|
|
27
|
-
}
|
|
28
|
-
export declare function drawTextWithStroke(ctx: CanvasRenderingContext2D, opts: TextStrokeOptions): void;
|
|
29
19
|
export declare function applyTextShadow(ctx: CanvasRenderingContext2D, shadow: ShadowOption): void;
|
|
30
20
|
export declare function clearTextShadow(ctx: CanvasRenderingContext2D): void;
|
|
31
21
|
export interface TextRunMetrics {
|
package/dist/vector-path.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PointView } from "@fulate/share";
|
|
2
2
|
import { ChangeImpact, ShapeProperties, type AuthoredSubpath, type GeometrySnapshot, type OwnerPropertyChange, type PropertyChanges, type ReparentTransformIntent, type ShapeOption, type ShapeOptionPatch, type ElementTransformBaseline, type TransformIntent } from "@fulate/core";
|
|
3
3
|
import { EditorShape, EditorShapeTransform } from "./editor/shape";
|
|
4
4
|
import { type EditorCapabilityToken, type PointControlDescriptor, type PointEditRequest, type PointEditingScope, type PointOwnerEdit } from "./editor/capability";
|
|
@@ -52,7 +52,7 @@ export declare class VectorPath extends EditorShape<VectorPathProperties, Vector
|
|
|
52
52
|
private findSegment;
|
|
53
53
|
private ownerPathChange;
|
|
54
54
|
captureTransformBaseline(): ElementTransformBaseline<VectorPathGeometry>;
|
|
55
|
-
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<VectorPathGeometry>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): OwnerPropertyChange;
|
|
55
|
+
resolveTransformChange(baseline: Readonly<ElementTransformBaseline<VectorPathGeometry>>, intent: Readonly<TransformIntent | ReparentTransformIntent>): readonly OwnerPropertyChange[];
|
|
56
56
|
protected buildPath(ctx: CanvasRenderingContext2D): void;
|
|
57
57
|
}
|
|
58
58
|
export {};
|