@weasel-js/core 1.7.1 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +7 -0
- package/dist/{autoPoseDescriptor-BT_vp9FO.d.ts → autoPoseDescriptor-vCdt55xm.d.ts} +1 -1
- package/dist/{builtins-BSUfH8nU.d.ts → builtins-C-gRyVRx.d.ts} +7 -3
- package/dist/canvas/CursorCoordsHud.js +56 -29
- package/dist/canvas/CursorCoordsHud.js.map +1 -1
- package/dist/canvas/hud.module.js +3 -3
- package/dist/canvas/hud.module.js.map +1 -1
- package/dist/clipboard.d.ts +1 -1
- package/dist/clone.d.ts +2 -2
- package/dist/core/geometry/poseDescriptor.js +10 -15
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/{cornerHandles-CDcZOV8h.d.ts → cornerHandles-BCrDp_mH.d.ts} +1 -1
- package/dist/features/paths/poseDescriptor.js +6 -11
- package/dist/features/paths/poseDescriptor.js.map +1 -1
- package/dist/index.d.ts +22 -17
- package/dist/interactions/actions/defaults/clone.js +64 -53
- package/dist/interactions/actions/defaults/clone.js.map +1 -1
- package/dist/interactions/actions/defaults/move.js +426 -322
- package/dist/interactions/actions/defaults/move.js.map +1 -1
- package/dist/interactions/actions/defaults/resize.js +75 -72
- package/dist/interactions/actions/defaults/resize.js.map +1 -1
- package/dist/interactions/actions/defaults/rotate.js +88 -85
- package/dist/interactions/actions/defaults/rotate.js.map +1 -1
- package/dist/interactions/actions/planeInput.js +82 -69
- package/dist/interactions/actions/planeInput.js.map +1 -1
- package/dist/interactions/actions/resize/autoPoseDescriptor.js +0 -1
- package/dist/interactions/actions/resize/autoPoseDescriptor.js.map +1 -1
- package/dist/{math-CUMxmZzn.d.ts → math-Drrw4ewZ.d.ts} +2 -2
- package/dist/math.d.ts +3 -3
- package/dist/move.d.ts +4 -4
- package/dist/{originProjection-BSn4xiEy.d.ts → originProjection-DEklpDc_.d.ts} +1 -1
- package/dist/{poseDescriptor-CjSXMf8X.d.ts → poseDescriptor-D-OH-tu5.d.ts} +0 -4
- package/dist/renderer.d.ts +4 -4
- package/dist/resize.d.ts +5 -5
- package/dist/style.css +2 -0
- package/dist/{types-CA54-mAZ.d.ts → types-A37hYkeR.d.ts} +4 -2
- package/dist/{types-DSjd6W3n.d.ts → types-B_9g6hMM.d.ts} +1 -1
- package/dist/version.js +1 -1
- package/package.json +16 -14
- package/dist/index.css +0 -2
|
@@ -6,18 +6,18 @@ import { unionAABB as l } from "../../../core/geometry/unionBounds.js";
|
|
|
6
6
|
import { poseDescriptorForNode as u, translatePoseViaDescriptor as d, visualBoundsViaDescriptor as f } from "../../../core/geometry/poseDescriptor.js";
|
|
7
7
|
import { poseDescriptorOf as p } from "../poseDescriptorDep.js";
|
|
8
8
|
import { moveGestureAdapter as m } from "../move/gestureAdapter.js";
|
|
9
|
-
import {
|
|
10
|
-
import { defaultCommitAdapter as
|
|
11
|
-
import { scenePoseFrame as
|
|
12
|
-
import { resolveParams as
|
|
9
|
+
import { carryPose as h, inPlane as g, invertPlane as _, planeOf as v, selectionLayer as y } from "../planeInput.js";
|
|
10
|
+
import { defaultCommitAdapter as b } from "../defaultCommitAdapter.js";
|
|
11
|
+
import { scenePoseFrame as x } from "../poseFrame.js";
|
|
12
|
+
import { resolveParams as S } from "@weasel-js/routing";
|
|
13
13
|
//#region src/interactions/actions/defaults/rotate.ts
|
|
14
|
-
function
|
|
14
|
+
function C(e, t, n, r, i, a, o) {
|
|
15
15
|
let s = e.withRotation(t, n + r);
|
|
16
16
|
if (!o) return s;
|
|
17
17
|
let c = Math.cos(r), l = Math.sin(r), u = i.x - a.x, f = i.y - a.y, p = a.x + u * c - f * l, m = a.y + u * l + f * c;
|
|
18
18
|
return d(s, p - i.x, m - i.y, e);
|
|
19
19
|
}
|
|
20
|
-
var
|
|
20
|
+
var w = g({
|
|
21
21
|
id: "rotate",
|
|
22
22
|
label: "Rotate",
|
|
23
23
|
eligible: { capability: "transforms-selection" },
|
|
@@ -31,52 +31,52 @@ var x = h({
|
|
|
31
31
|
],
|
|
32
32
|
invoker: {
|
|
33
33
|
timing: "ongoing",
|
|
34
|
-
start(d,
|
|
35
|
-
let
|
|
36
|
-
if (!
|
|
37
|
-
let
|
|
38
|
-
if (
|
|
39
|
-
let
|
|
40
|
-
for (let e of
|
|
41
|
-
let t =
|
|
34
|
+
start(d, g) {
|
|
35
|
+
let y = d.deps.selection, w = d.deps.scene, T = d.deps.applyOps, E = S(g?.params), D = g?.behaviors ?? [];
|
|
36
|
+
if (!y || !w) return {};
|
|
37
|
+
let O = y.get();
|
|
38
|
+
if (O.length === 0) return {};
|
|
39
|
+
let k = p(d.deps.poseDescriptor), A = x(w, d.deps.poseComposition), j = /* @__PURE__ */ new Map(), M = /* @__PURE__ */ new Map(), N = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map(), F = [];
|
|
40
|
+
for (let e of O) {
|
|
41
|
+
let t = w.get(e);
|
|
42
42
|
if (!t) continue;
|
|
43
|
-
let n = u(
|
|
43
|
+
let n = u(k, t);
|
|
44
44
|
if (!n.withRotation || n.supportsRotation?.(t.pose) === !1) continue;
|
|
45
|
-
|
|
46
|
-
let r =
|
|
47
|
-
|
|
45
|
+
j.set(e, t.pose);
|
|
46
|
+
let r = h(n, A.world(e), _(v(d.deps.view, t.layer)));
|
|
47
|
+
M.set(e, r);
|
|
48
48
|
let i = n.getBounds(r);
|
|
49
|
-
|
|
49
|
+
N.set(e, {
|
|
50
50
|
x: i.x + i.width / 2,
|
|
51
51
|
y: i.y + i.height / 2
|
|
52
|
-
}),
|
|
52
|
+
}), P.set(e, n.getRotation?.(r) ?? 0), F.push(f(r, n));
|
|
53
53
|
}
|
|
54
|
-
if (
|
|
55
|
-
let
|
|
56
|
-
x:
|
|
57
|
-
y:
|
|
58
|
-
},
|
|
59
|
-
ids:
|
|
60
|
-
scene:
|
|
61
|
-
descriptor:
|
|
62
|
-
frame:
|
|
63
|
-
originPoses:
|
|
64
|
-
originWorlds:
|
|
65
|
-
originCenters:
|
|
66
|
-
originRotations:
|
|
67
|
-
unionCenter:
|
|
68
|
-
startPointerAngle:
|
|
54
|
+
if (j.size === 0) return {};
|
|
55
|
+
let I = l(F), L = {
|
|
56
|
+
x: I.x + I.width / 2,
|
|
57
|
+
y: I.y + I.height / 2
|
|
58
|
+
}, R = Math.atan2(d.world.y - L.y, d.world.x - L.x), z = r(d.deps), B = d.deps.view, V = n(d.deps), H = {
|
|
59
|
+
ids: O,
|
|
60
|
+
scene: w,
|
|
61
|
+
descriptor: k,
|
|
62
|
+
frame: A,
|
|
63
|
+
originPoses: j,
|
|
64
|
+
originWorlds: M,
|
|
65
|
+
originCenters: N,
|
|
66
|
+
originRotations: P,
|
|
67
|
+
unionCenter: L,
|
|
68
|
+
startPointerAngle: R,
|
|
69
69
|
currentDelta: 0,
|
|
70
|
-
useUnionPivot:
|
|
70
|
+
useUnionPivot: O.length > 1 && E?.pivot !== "each",
|
|
71
71
|
previews: /* @__PURE__ */ new Map(),
|
|
72
72
|
overrideEntries: /* @__PURE__ */ new Map(),
|
|
73
|
-
applyOps:
|
|
74
|
-
lifecycle: a(
|
|
75
|
-
behaviors:
|
|
73
|
+
applyOps: T,
|
|
74
|
+
lifecycle: a(E, "Rotate", D),
|
|
75
|
+
behaviors: D,
|
|
76
76
|
gestureCtx: {
|
|
77
|
-
draggedIds: [...
|
|
78
|
-
origin: new Map([...
|
|
79
|
-
current: new Map([...
|
|
77
|
+
draggedIds: [...j.keys()],
|
|
78
|
+
origin: new Map([...M].map(([e, t]) => [e, t])),
|
|
79
|
+
current: new Map([...M].map(([e, t]) => [e, t])),
|
|
80
80
|
snap: null,
|
|
81
81
|
modifiers: { ...d.modifiers },
|
|
82
82
|
pointer: {
|
|
@@ -85,97 +85,100 @@ var x = h({
|
|
|
85
85
|
clientX: 0,
|
|
86
86
|
clientY: 0
|
|
87
87
|
},
|
|
88
|
-
view:
|
|
89
|
-
plane:
|
|
90
|
-
adapter: m(
|
|
88
|
+
view: z(),
|
|
89
|
+
plane: V(),
|
|
90
|
+
adapter: m(w),
|
|
91
91
|
scratch: {}
|
|
92
92
|
}
|
|
93
|
-
}, { lifecycle:
|
|
93
|
+
}, { lifecycle: U } = H, W = (e) => {
|
|
94
94
|
let t = /* @__PURE__ */ new Map();
|
|
95
|
-
for (let [n, r] of
|
|
95
|
+
for (let [n, r] of H.originWorlds) t.set(n, C(H.descriptor, r, H.originRotations.get(n) ?? 0, e, H.originCenters.get(n) ?? {
|
|
96
96
|
x: 0,
|
|
97
97
|
y: 0
|
|
98
|
-
},
|
|
98
|
+
}, H.unionCenter, H.useUnionPivot));
|
|
99
99
|
return t;
|
|
100
|
-
},
|
|
101
|
-
let t =
|
|
102
|
-
for (let [e, n] of t)
|
|
100
|
+
}, G = (e) => {
|
|
101
|
+
let t = W(e);
|
|
102
|
+
for (let [e, n] of t) H.gestureCtx.current.set(e, n);
|
|
103
103
|
return t;
|
|
104
|
-
},
|
|
105
|
-
let n =
|
|
104
|
+
}, K = (e, t) => {
|
|
105
|
+
let n = H.gestureCtx;
|
|
106
106
|
n.modifiers = { ...e.modifiers }, n.pointer = {
|
|
107
107
|
worldX: e.world.x,
|
|
108
108
|
worldY: e.world.y,
|
|
109
109
|
clientX: 0,
|
|
110
110
|
clientY: 0
|
|
111
|
-
}, n.view =
|
|
112
|
-
let r =
|
|
113
|
-
pose:
|
|
111
|
+
}, n.view = z(), n.plane = V();
|
|
112
|
+
let r = H.originWorlds.keys().next().value, i = H.originRotations.get(r) ?? 0, a = t, o = {
|
|
113
|
+
pose: G(t).get(r),
|
|
114
114
|
rotation: i + t
|
|
115
115
|
};
|
|
116
|
-
for (let e of
|
|
116
|
+
for (let e of H.behaviors) {
|
|
117
117
|
let t = e.onMove?.(n, o);
|
|
118
118
|
if (!t || t.pose === void 0) continue;
|
|
119
|
-
let r =
|
|
119
|
+
let r = H.descriptor.getRotation?.(t.pose) ?? 0;
|
|
120
120
|
a = r - i, o = {
|
|
121
121
|
pose: t.pose,
|
|
122
122
|
rotation: r
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
return a;
|
|
126
|
-
},
|
|
126
|
+
}, q = () => {
|
|
127
127
|
let e = {
|
|
128
|
-
scene:
|
|
129
|
-
applyOps:
|
|
130
|
-
adapter:
|
|
128
|
+
scene: w,
|
|
129
|
+
applyOps: H.applyOps,
|
|
130
|
+
adapter: b(w, y.adapterMethods)
|
|
131
131
|
};
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
let t = o(
|
|
132
|
+
if (H.behaviors.length > 0) {
|
|
133
|
+
G(H.currentDelta);
|
|
134
|
+
let t = o(H.behaviors, H.gestureCtx);
|
|
135
135
|
if (t === null) return !1;
|
|
136
|
-
if (t !== void 0) return i(e,
|
|
136
|
+
if (t !== void 0) return i(e, U, t), !0;
|
|
137
137
|
}
|
|
138
|
-
if (
|
|
138
|
+
if (H.currentDelta === 0) return !1;
|
|
139
139
|
let t = [];
|
|
140
|
-
for (let e of
|
|
141
|
-
let n =
|
|
140
|
+
for (let e of H.ids) {
|
|
141
|
+
let n = H.previews.get(e);
|
|
142
142
|
if (n === void 0) continue;
|
|
143
|
-
let r =
|
|
143
|
+
let r = H.originPoses.get(e);
|
|
144
144
|
r !== void 0 && t.push(c({
|
|
145
145
|
id: e,
|
|
146
146
|
from: r,
|
|
147
147
|
to: n,
|
|
148
|
-
label:
|
|
148
|
+
label: U.label
|
|
149
149
|
}));
|
|
150
150
|
}
|
|
151
|
-
return t.length !== 0 && (i(e,
|
|
152
|
-
},
|
|
153
|
-
if (
|
|
154
|
-
|
|
151
|
+
return t.length !== 0 && (i(e, U, t), !0);
|
|
152
|
+
}, J = (e) => {
|
|
153
|
+
if (H.previews.clear(), e !== 0) for (let [t, n] of W(e)) {
|
|
154
|
+
let e = H.scene.get(t)?.layer, r = e === void 0 ? null : v(B, e);
|
|
155
|
+
H.previews.set(t, H.frame.local(t, h(H.descriptor, n, r)));
|
|
156
|
+
}
|
|
157
|
+
t(H);
|
|
155
158
|
};
|
|
156
|
-
for (let e of
|
|
157
|
-
return
|
|
159
|
+
for (let e of D) e.onStart?.(H.gestureCtx);
|
|
160
|
+
return U.start(H.gestureCtx.draggedIds), {
|
|
158
161
|
kind: "rotate",
|
|
159
162
|
onMove(e) {
|
|
160
|
-
let t = Math.atan2(e.world.y -
|
|
161
|
-
|
|
163
|
+
let t = Math.atan2(e.world.y - H.unionCenter.y, e.world.x - H.unionCenter.x) - H.startPointerAngle;
|
|
164
|
+
H.currentDelta = H.behaviors.length > 0 ? K(e, t) : t, J(H.currentDelta);
|
|
162
165
|
},
|
|
163
166
|
onEnd(t, n) {
|
|
164
167
|
let r = !1;
|
|
165
168
|
try {
|
|
166
|
-
n === "commit" ? r =
|
|
169
|
+
n === "commit" ? r = q() : s(H.behaviors, H.gestureCtx);
|
|
167
170
|
} finally {
|
|
168
|
-
e(
|
|
171
|
+
e(H), H.previews.clear(), U.end(r);
|
|
169
172
|
}
|
|
170
173
|
},
|
|
171
|
-
previewIds: () =>
|
|
172
|
-
previewPose: (e) =>
|
|
174
|
+
previewIds: () => H.previews.keys(),
|
|
175
|
+
previewPose: (e) => H.previews.get(e) ?? null
|
|
173
176
|
};
|
|
174
177
|
}
|
|
175
178
|
},
|
|
176
179
|
enabled: () => !0
|
|
177
|
-
},
|
|
180
|
+
}, y);
|
|
178
181
|
//#endregion
|
|
179
|
-
export {
|
|
182
|
+
export { w as rotateAction };
|
|
180
183
|
|
|
181
184
|
//# sourceMappingURL=rotate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rotate.js","names":["applyRotationDelta","rotated","d","pose","originRotation","delta","useUnionPivot","cos","sin","ox","originCenter","unionCenter","oy","nx","ny","translatePoseViaDescriptor","rotateAction","inPlane","selection","ctx","scene","applyOps","params","resolveParams","opts","behaviors","ids","descriptor","poseDescriptorOf","frame","scenePoseFrame","originPoses","originWorlds","originCenters","originRotations","visual","id","node","g","poseDescriptorForNode","world","b","visualBoundsViaDescriptor","union","unionAABB","startPointerAngle","readView","gestureViewReader","readPlane","gesturePlaneReader","scratch","\"pivot\"","readGestureLifecycle","p","moveGestureAdapter","turnedWorlds","out","origin","syncGestureCurrent","turned","shapeDelta","gctx","moveCtx","primary","raw","proposed","r","rotation","commitRotate","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","createTransformOp","recomputePreviews","committed","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/rotate.ts"],"sourcesContent":["/**\n * `rotateAction` — ongoing Action descriptor for pointer-driven rotation.\n *\n * ## Status: REAL (unrotated-pivot path)\n *\n * Implements the core rotation math from `useRotate`:\n * - `start`: captures origin poses + AABB centers; computes start pointer\n * angle around the union center of selected nodes.\n * - `onMove`: derives pointer angle delta from start, applies to each node's\n * origin rotation. In union-pivot mode (multi-selection) orbits each item's\n * center around the union center.\n * - `onEnd('commit')`: builds one `createTransformOp` per node (from =\n * pre-mutation origin pose, to = rotated pose) and commits them as a\n * single batch → one undo entry for the whole drag. Routes through the\n * optional `applyOps` dep (consumer history) when present, else\n * `scene.applyBatch` + `defaultCommitAdapter`.\n * - `onEnd('cancel')`: no scene writes (scene never mutated during drag).\n *\n * ## Constraints vs `useRotate`\n *\n * - Reads and writes poses through the `poseDescriptor` dep; a pose whose\n * descriptor has no `withRotation`, or reports `supportsRotation` false, is\n * left alone.\n * - Behaviors (`opts.behaviors`) see the first rotated node's turned pose; a\n * pose one returns from `onMove` sets the rotation for the whole selection.\n * - No overlay rendering — deferred to Phase 7 overlay surface.\n * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately\n * to keep the invoker self-contained (would need to read shift from onMove ctx).\n * TODO: thread shift from InvocationCtx.modifiers.shift into snap logic.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n poseDescriptorForNode,\n translatePoseViaDescriptor,\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from '../resize/geometry';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { moveGestureAdapter } from '../move/gestureAdapter';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { inPlane, selectionLayer } from '../planeInput';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Apply a rotation delta (radians) to a pose, optionally orbiting the item's\n * center around a shared union center. */\nfunction applyRotationDelta(\n d: PoseDescriptor<unknown>,\n pose: unknown,\n originRotation: number,\n delta: number,\n originCenter: { x: number; y: number },\n unionCenter: { x: number; y: number },\n useUnionPivot: boolean,\n): unknown {\n const rotated = d.withRotation!(pose, originRotation + delta);\n if (!useUnionPivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = originCenter.x - unionCenter.x;\n const oy = originCenter.y - unionCenter.y;\n const nx = unionCenter.x + ox * cos - oy * sin;\n const ny = unionCenter.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - originCenter.x, ny - originCenter.y, d);\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface RotateScratch {\n ids: NodeId[];\n scene: Scene<unknown, string, unknown>;\n descriptor: PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Origin pose for each selected node as stored — the `from` of its op. */\n originPoses: Map<NodeId, unknown>;\n /** Origin pose for each selected node in world — what the gesture turns. */\n originWorlds: Map<NodeId, unknown>;\n /** AABB center for each selected node (from origin pose). */\n originCenters: Map<NodeId, { x: number; y: number }>;\n /** Per-node origin rotation (radians). */\n originRotations: Map<NodeId, number>;\n /** Union center of all selected nodes — the rotation pivot. */\n unionCenter: { x: number; y: number };\n /** Pointer angle around unionCenter at drag start. */\n startPointerAngle: number;\n /** Running delta — updated each onMove, applied once at commit. */\n currentDelta: number;\n /** Use union pivot (multi-select) vs each item's own center. */\n useUnionPivot: boolean;\n /** In-flight preview poses keyed by node id. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * ops-based commits route through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n lifecycle: GestureLifecycle;\n behaviors: RotateBehavior<unknown>[];\n /** Reused gesture context handed to behaviors across the drag. */\n gestureCtx: GestureContext<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `rotate` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n *\n * Implements the unrotated-pivot rotation path from `useRotate`.\n *\n * @see useRotate — the React hook this descriptor mirrors for the rect case.\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding. It used to be a bare `{ kind: 'drag' }`, which made\n // any drag no active tool claimed rotate a non-empty selection. The rotation\n // handle binds it (`selectionTransformBindings`, the `transform` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts): OngoingHandle {\n const selection = ctx.deps.selection as SelectionApi | undefined;\n const scene = ctx.deps.scene as Scene<unknown, string, unknown> | undefined;\n const applyOps = ctx.deps.applyOps as ((ops: Op[], label: string) => void) | undefined;\n const params = resolveParams(opts?.params);\n const behaviors = (opts?.behaviors ?? []) as RotateBehavior<unknown>[];\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const descriptor = poseDescriptorOf(ctx.deps.poseDescriptor);\n // The pivot the pointer orbits is a world point, so every pose the\n // gesture turns is a world pose. Each turned result is stored back in\n // the node's own parent frame at preview and commit alike.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const originPoses = new Map<NodeId, unknown>();\n const originWorlds = new Map<NodeId, unknown>();\n const originCenters = new Map<NodeId, { x: number; y: number }>();\n const originRotations = new Map<NodeId, number>();\n const visual: Bounds[] = [];\n\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const g = poseDescriptorForNode(descriptor, node);\n if (!g.withRotation || g.supportsRotation?.(node.pose) === false) continue;\n originPoses.set(id, node.pose);\n // The pivot is a world point, so every measurement the gesture orbits\n // is taken from the world pose, not the stored one.\n const world = frame.world(id);\n originWorlds.set(id, world);\n const b = g.getBounds(world);\n originCenters.set(id, { x: b.x + b.width / 2, y: b.y + b.height / 2 });\n originRotations.set(id, g.getRotation?.(world) ?? 0);\n visual.push(visualBoundsViaDescriptor(world, g));\n }\n\n if (originPoses.size === 0) return {};\n\n const union = unionAABB(visual)!;\n const unionCenter = { x: union.x + union.width / 2, y: union.y + union.height / 2 };\n const startPointerAngle = Math.atan2(\n ctx.world.y - unionCenter.y,\n ctx.world.x - unionCenter.x,\n );\n\n const readView = gestureViewReader(ctx.deps);\n\n const readPlane = gesturePlaneReader(ctx.deps);\n const scratch: RotateScratch = {\n ids,\n scene,\n descriptor,\n frame,\n originPoses,\n originWorlds,\n originCenters,\n originRotations,\n unionCenter,\n startPointerAngle,\n currentDelta: 0,\n useUnionPivot: ids.length > 1 && params?.['pivot'] !== 'each',\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n applyOps,\n lifecycle: readGestureLifecycle(params, 'Rotate', behaviors),\n behaviors,\n gestureCtx: {\n draggedIds: [...originPoses.keys()] as string[],\n origin: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n current: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n adapter: moveGestureAdapter(scene) as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n },\n };\n const { lifecycle } = scratch;\n\n /** Each rotated node's world pose turned by `delta`. */\n const turnedWorlds = (delta: number): Map<NodeId, unknown> => {\n const out = new Map<NodeId, unknown>();\n for (const [id, origin] of scratch.originWorlds) {\n out.set(id, applyRotationDelta(\n scratch.descriptor,\n origin,\n scratch.originRotations.get(id) ?? 0,\n delta,\n scratch.originCenters.get(id) ?? { x: 0, y: 0 },\n scratch.unionCenter,\n scratch.useUnionPivot,\n ));\n }\n return out;\n };\n\n const syncGestureCurrent = (delta: number): Map<NodeId, unknown> => {\n const turned = turnedWorlds(delta);\n for (const [id, pose] of turned) scratch.gestureCtx.current.set(id as string, pose);\n return turned;\n };\n\n /** The pointer's delta as the behaviors reshape it. */\n const shapeDelta = (moveCtx: InvocationCtx, raw: number): number => {\n const gctx = scratch.gestureCtx;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = { worldX: moveCtx.world.x, worldY: moveCtx.world.y, clientX: 0, clientY: 0 };\n gctx.view = readView();\n gctx.plane = readPlane();\n const primary = scratch.originWorlds.keys().next().value as NodeId;\n const originRotation = scratch.originRotations.get(primary) ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r || r.pose === undefined) continue;\n const rotation = scratch.descriptor.getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n };\n\n // Returns whether anything reached the document.\n const commitRotate = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n if (scratch.behaviors.length > 0) {\n syncGestureCurrent(scratch.currentDelta);\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n }\n if (scratch.currentDelta === 0) return false;\n // One transform op per node: `from` is the origin pose captured at drag\n // start, `to` the rotated preview. A single batch, so one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.originPoses.get(id);\n if (from === undefined) continue;\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: next,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n const recomputePreviews = (delta: number) => {\n scratch.previews.clear();\n if (delta !== 0) {\n for (const [id, turned] of turnedWorlds(delta)) {\n scratch.previews.set(id, scratch.frame.local(id, turned));\n }\n }\n syncPreviewOverrides(scratch);\n };\n\n for (const b of behaviors) b.onStart?.(scratch.gestureCtx);\n lifecycle.start(scratch.gestureCtx.draggedIds);\n\n return {\n kind: 'rotate',\n onMove(moveCtx: InvocationCtx): void {\n const pointerAngle = Math.atan2(\n moveCtx.world.y - scratch.unionCenter.y,\n moveCtx.world.x - scratch.unionCenter.x,\n );\n const raw = pointerAngle - scratch.startPointerAngle;\n scratch.currentDelta = scratch.behaviors.length > 0 ? shapeDelta(moveCtx, raw) : raw;\n recomputePreviews(scratch.currentDelta);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitRotate();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rotate.js","names":["applyRotationDelta","rotated","d","pose","originRotation","delta","useUnionPivot","cos","sin","ox","originCenter","unionCenter","oy","nx","ny","translatePoseViaDescriptor","rotateAction","inPlane","selection","ctx","scene","applyOps","params","resolveParams","opts","behaviors","ids","descriptor","poseDescriptorOf","frame","scenePoseFrame","originPoses","originWorlds","originCenters","originRotations","visual","id","node","g","poseDescriptorForNode","world","carryPose","invertPlane","planeOf","b","visualBoundsViaDescriptor","union","unionAABB","startPointerAngle","readView","gestureViewReader","view","readPlane","gesturePlaneReader","scratch","\"pivot\"","readGestureLifecycle","p","moveGestureAdapter","turnedWorlds","out","origin","syncGestureCurrent","turned","shapeDelta","gctx","moveCtx","primary","raw","proposed","r","rotation","commitRotate","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","createTransformOp","recomputePreviews","layer","own","committed","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/rotate.ts"],"sourcesContent":["/**\n * `rotateAction` — ongoing Action descriptor for pointer-driven rotation.\n *\n * ## Status: REAL (unrotated-pivot path)\n *\n * Implements the core rotation math from `useRotate`:\n * - `start`: captures origin poses + AABB centers; computes start pointer\n * angle around the union center of selected nodes.\n * - `onMove`: derives pointer angle delta from start, applies to each node's\n * origin rotation. In union-pivot mode (multi-selection) orbits each item's\n * center around the union center.\n * - `onEnd('commit')`: builds one `createTransformOp` per node (from =\n * pre-mutation origin pose, to = rotated pose) and commits them as a\n * single batch → one undo entry for the whole drag. Routes through the\n * optional `applyOps` dep (consumer history) when present, else\n * `scene.applyBatch` + `defaultCommitAdapter`.\n * - `onEnd('cancel')`: no scene writes (scene never mutated during drag).\n *\n * ## Constraints vs `useRotate`\n *\n * - Reads and writes poses through the `poseDescriptor` dep; a pose whose\n * descriptor has no `withRotation`, or reports `supportsRotation` false, is\n * left alone.\n * - Behaviors (`opts.behaviors`) see the first rotated node's turned pose; a\n * pose one returns from `onMove` sets the rotation for the whole selection.\n * - No overlay rendering — deferred to Phase 7 overlay surface.\n * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately\n * to keep the invoker self-contained (would need to read shift from onMove ctx).\n * TODO: thread shift from InvocationCtx.modifiers.shift into snap logic.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n poseDescriptorForNode,\n translatePoseViaDescriptor,\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from '../resize/geometry';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { moveGestureAdapter } from '../move/gestureAdapter';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Apply a rotation delta (radians) to a pose, optionally orbiting the item's\n * center around a shared union center. */\nfunction applyRotationDelta(\n d: PoseDescriptor<unknown>,\n pose: unknown,\n originRotation: number,\n delta: number,\n originCenter: { x: number; y: number },\n unionCenter: { x: number; y: number },\n useUnionPivot: boolean,\n): unknown {\n const rotated = d.withRotation!(pose, originRotation + delta);\n if (!useUnionPivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = originCenter.x - unionCenter.x;\n const oy = originCenter.y - unionCenter.y;\n const nx = unionCenter.x + ox * cos - oy * sin;\n const ny = unionCenter.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - originCenter.x, ny - originCenter.y, d);\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface RotateScratch {\n ids: NodeId[];\n scene: Scene<unknown, string, unknown>;\n descriptor: PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Origin pose for each selected node as stored — the `from` of its op. */\n originPoses: Map<NodeId, unknown>;\n /** Origin pose for each selected node in world — what the gesture turns. */\n originWorlds: Map<NodeId, unknown>;\n /** AABB center for each selected node (from origin pose). */\n originCenters: Map<NodeId, { x: number; y: number }>;\n /** Per-node origin rotation (radians). */\n originRotations: Map<NodeId, number>;\n /** Union center of all selected nodes — the rotation pivot. */\n unionCenter: { x: number; y: number };\n /** Pointer angle around unionCenter at drag start. */\n startPointerAngle: number;\n /** Running delta — updated each onMove, applied once at commit. */\n currentDelta: number;\n /** Use union pivot (multi-select) vs each item's own center. */\n useUnionPivot: boolean;\n /** In-flight preview poses keyed by node id. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * ops-based commits route through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n lifecycle: GestureLifecycle;\n behaviors: RotateBehavior<unknown>[];\n /** Reused gesture context handed to behaviors across the drag. */\n gestureCtx: GestureContext<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `rotate` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n *\n * Implements the unrotated-pivot rotation path from `useRotate`.\n *\n * @see useRotate — the React hook this descriptor mirrors for the rect case.\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding. It used to be a bare `{ kind: 'drag' }`, which made\n // any drag no active tool claimed rotate a non-empty selection. The rotation\n // handle binds it (`selectionTransformBindings`, the `transform` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts): OngoingHandle {\n const selection = ctx.deps.selection as SelectionApi | undefined;\n const scene = ctx.deps.scene as Scene<unknown, string, unknown> | undefined;\n const applyOps = ctx.deps.applyOps as ((ops: Op[], label: string) => void) | undefined;\n const params = resolveParams(opts?.params);\n const behaviors = (opts?.behaviors ?? []) as RotateBehavior<unknown>[];\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const descriptor = poseDescriptorOf(ctx.deps.poseDescriptor);\n // The pivot the pointer orbits is a world point, so every pose the\n // gesture turns is a world pose. Each turned result is stored back in\n // the node's own parent frame at preview and commit alike.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const originPoses = new Map<NodeId, unknown>();\n const originWorlds = new Map<NodeId, unknown>();\n const originCenters = new Map<NodeId, { x: number; y: number }>();\n const originRotations = new Map<NodeId, number>();\n const visual: Bounds[] = [];\n\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const g = poseDescriptorForNode(descriptor, node);\n if (!g.withRotation || g.supportsRotation?.(node.pose) === false) continue;\n originPoses.set(id, node.pose);\n // The pivot is a world point, so every measurement the gesture orbits\n // is taken from the world pose, not the stored one — carried into the\n // plane the edit is measured in, where the pointer's angle is read.\n const world = carryPose(g, frame.world(id), invertPlane(planeOf(ctx.deps.view, node.layer)));\n originWorlds.set(id, world);\n const b = g.getBounds(world);\n originCenters.set(id, { x: b.x + b.width / 2, y: b.y + b.height / 2 });\n originRotations.set(id, g.getRotation?.(world) ?? 0);\n visual.push(visualBoundsViaDescriptor(world, g));\n }\n\n if (originPoses.size === 0) return {};\n\n const union = unionAABB(visual)!;\n const unionCenter = { x: union.x + union.width / 2, y: union.y + union.height / 2 };\n const startPointerAngle = Math.atan2(\n ctx.world.y - unionCenter.y,\n ctx.world.x - unionCenter.x,\n );\n\n const readView = gestureViewReader(ctx.deps);\n const view = ctx.deps.view;\n\n const readPlane = gesturePlaneReader(ctx.deps);\n const scratch: RotateScratch = {\n ids,\n scene,\n descriptor,\n frame,\n originPoses,\n originWorlds,\n originCenters,\n originRotations,\n unionCenter,\n startPointerAngle,\n currentDelta: 0,\n useUnionPivot: ids.length > 1 && params?.['pivot'] !== 'each',\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n applyOps,\n lifecycle: readGestureLifecycle(params, 'Rotate', behaviors),\n behaviors,\n gestureCtx: {\n draggedIds: [...originPoses.keys()] as string[],\n origin: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n current: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n adapter: moveGestureAdapter(scene) as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n },\n };\n const { lifecycle } = scratch;\n\n /** Each rotated node's world pose turned by `delta`. */\n const turnedWorlds = (delta: number): Map<NodeId, unknown> => {\n const out = new Map<NodeId, unknown>();\n for (const [id, origin] of scratch.originWorlds) {\n out.set(id, applyRotationDelta(\n scratch.descriptor,\n origin,\n scratch.originRotations.get(id) ?? 0,\n delta,\n scratch.originCenters.get(id) ?? { x: 0, y: 0 },\n scratch.unionCenter,\n scratch.useUnionPivot,\n ));\n }\n return out;\n };\n\n const syncGestureCurrent = (delta: number): Map<NodeId, unknown> => {\n const turned = turnedWorlds(delta);\n for (const [id, pose] of turned) scratch.gestureCtx.current.set(id as string, pose);\n return turned;\n };\n\n /** The pointer's delta as the behaviors reshape it. */\n const shapeDelta = (moveCtx: InvocationCtx, raw: number): number => {\n const gctx = scratch.gestureCtx;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = { worldX: moveCtx.world.x, worldY: moveCtx.world.y, clientX: 0, clientY: 0 };\n gctx.view = readView();\n gctx.plane = readPlane();\n const primary = scratch.originWorlds.keys().next().value as NodeId;\n const originRotation = scratch.originRotations.get(primary) ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r || r.pose === undefined) continue;\n const rotation = scratch.descriptor.getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n };\n\n // Returns whether anything reached the document.\n const commitRotate = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n if (scratch.behaviors.length > 0) {\n syncGestureCurrent(scratch.currentDelta);\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n }\n if (scratch.currentDelta === 0) return false;\n // One transform op per node: `from` is the origin pose captured at drag\n // start, `to` the rotated preview. A single batch, so one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.originPoses.get(id);\n if (from === undefined) continue;\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: next,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n const recomputePreviews = (delta: number) => {\n scratch.previews.clear();\n if (delta !== 0) {\n for (const [id, turned] of turnedWorlds(delta)) {\n const layer = scratch.scene.get(id)?.layer;\n const own = layer === undefined ? null : planeOf(view, layer);\n scratch.previews.set(id, scratch.frame.local(id, carryPose(scratch.descriptor, turned, own)));\n }\n }\n syncPreviewOverrides(scratch);\n };\n\n for (const b of behaviors) b.onStart?.(scratch.gestureCtx);\n lifecycle.start(scratch.gestureCtx.draggedIds);\n\n return {\n kind: 'rotate',\n onMove(moveCtx: InvocationCtx): void {\n const pointerAngle = Math.atan2(\n moveCtx.world.y - scratch.unionCenter.y,\n moveCtx.world.x - scratch.unionCenter.x,\n );\n const raw = pointerAngle - scratch.startPointerAngle;\n scratch.currentDelta = scratch.behaviors.length > 0 ? shapeDelta(moveCtx, raw) : raw;\n recomputePreviews(scratch.currentDelta);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitRotate();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
import { deriveParallaxView as e, fromPlane as t, planeMap as n,
|
|
2
|
-
import { asNodeId as
|
|
1
|
+
import { deriveParallaxView as e, fromPlane as t, planeMap as n, planeToPlane as r, rectFromPlane as i, rectToPlane as a, toPlane as o } from "../../core/viewport/parallax.js";
|
|
2
|
+
import { asNodeId as s } from "../../core/scene/types.js";
|
|
3
3
|
//#region src/interactions/actions/planeInput.ts
|
|
4
|
-
var
|
|
4
|
+
var c = (e, t) => t ? e.scene?.get(s(t))?.layer : void 0, l = (e, t) => {
|
|
5
5
|
let n = e.selection;
|
|
6
6
|
for (let r of [...t?.targetIds ?? [], ...n?.get() ?? []]) {
|
|
7
|
-
let t =
|
|
7
|
+
let t = c(e, r);
|
|
8
8
|
if (t !== void 0) return t;
|
|
9
9
|
}
|
|
10
|
-
},
|
|
11
|
-
function
|
|
10
|
+
}, u = (e) => e.insert?.layer?.(), d = (e) => c(e, e.editAnchors?.editingId);
|
|
11
|
+
function f(e, t) {
|
|
12
|
+
return e?.planeOf?.(t) ?? null;
|
|
13
|
+
}
|
|
14
|
+
function p(e) {
|
|
15
|
+
return e && r(e, null);
|
|
16
|
+
}
|
|
17
|
+
function m(e, t, n) {
|
|
18
|
+
if (n === null) return t;
|
|
19
|
+
let r = e.getBounds(t);
|
|
20
|
+
return e.remapBounds(t, r, a(n, r));
|
|
21
|
+
}
|
|
22
|
+
function h(e, t) {
|
|
12
23
|
let n = e.invoker;
|
|
13
24
|
if (!n) return e;
|
|
14
|
-
let r = e.requires ?? [],
|
|
25
|
+
let r = e.requires ?? [], i = [.../* @__PURE__ */ new Set([
|
|
15
26
|
...r,
|
|
16
27
|
"scene",
|
|
17
28
|
"selection",
|
|
@@ -19,41 +30,39 @@ function u(e, t) {
|
|
|
19
30
|
])];
|
|
20
31
|
return n.timing === "immediate" ? {
|
|
21
32
|
...e,
|
|
22
|
-
requires:
|
|
33
|
+
requires: i,
|
|
23
34
|
invoker: {
|
|
24
35
|
timing: "immediate",
|
|
25
|
-
run(e,
|
|
26
|
-
let
|
|
27
|
-
if (
|
|
28
|
-
let s =
|
|
36
|
+
run(e, i) {
|
|
37
|
+
let a = g(e, t(e), r, null);
|
|
38
|
+
if (a === null) return n.run(e, i);
|
|
39
|
+
let s = i?.worldX, c = i?.worldY, l = typeof s == "number" && typeof c == "number" ? o(a.map(), {
|
|
29
40
|
x: s,
|
|
30
41
|
y: c
|
|
31
42
|
}) : null;
|
|
32
|
-
n.run(
|
|
33
|
-
...
|
|
43
|
+
n.run(a.deps, l ? {
|
|
44
|
+
...i,
|
|
34
45
|
worldX: l.x,
|
|
35
46
|
worldY: l.y
|
|
36
|
-
} :
|
|
47
|
+
} : i);
|
|
37
48
|
}
|
|
38
49
|
}
|
|
39
50
|
} : {
|
|
40
51
|
...e,
|
|
41
|
-
requires:
|
|
52
|
+
requires: i,
|
|
42
53
|
invoker: {
|
|
43
54
|
timing: "ongoing",
|
|
44
55
|
start(e, i) {
|
|
45
|
-
let a =
|
|
46
|
-
return a === null ? n.start(e, i) :
|
|
56
|
+
let a = g(e.deps, t(e.deps, e.drag?.affordance), r, e.drag?.start ?? null);
|
|
57
|
+
return a === null ? n.start(e, i) : v(n.start(a.carry(e), i), a);
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
};
|
|
50
61
|
}
|
|
51
|
-
function
|
|
52
|
-
let
|
|
53
|
-
if (a === void 0 || !
|
|
54
|
-
let
|
|
55
|
-
if (u() === void 0) return null;
|
|
56
|
-
let d = {
|
|
62
|
+
function g(i, a, s, c) {
|
|
63
|
+
let l = i.scene, u = i.view;
|
|
64
|
+
if (a === void 0 || !l || !u || !l.layers.some((e) => e.parallax !== void 0)) return null;
|
|
65
|
+
let d = (e) => l.layers.find((t) => t.id === e)?.parallax, f = () => d(a), p = {
|
|
57
66
|
scale: {
|
|
58
67
|
x: 1,
|
|
59
68
|
y: 1
|
|
@@ -62,99 +71,103 @@ function d(r, a, o, s) {
|
|
|
62
71
|
x: 0,
|
|
63
72
|
y: 0
|
|
64
73
|
}
|
|
65
|
-
},
|
|
66
|
-
let e =
|
|
67
|
-
return e ? n(
|
|
68
|
-
},
|
|
74
|
+
}, m = () => {
|
|
75
|
+
let e = f();
|
|
76
|
+
return e ? n(u.get(), e) : p;
|
|
77
|
+
}, h = Object.defineProperties(Object.create(u), {
|
|
69
78
|
get: { value: () => {
|
|
70
|
-
let t =
|
|
79
|
+
let t = f(), n = u.get();
|
|
71
80
|
return t ? e(n, t) : n;
|
|
72
81
|
} },
|
|
73
|
-
plane: { value:
|
|
74
|
-
|
|
82
|
+
plane: { value: m },
|
|
83
|
+
planeOf: { value: (e) => {
|
|
84
|
+
let t = f(), i = d(e), a = u.get();
|
|
85
|
+
return r(t ? n(a, t) : null, i ? n(a, i) : null);
|
|
86
|
+
} }
|
|
87
|
+
}), g = Object.create(i), v = (e, t) => Object.defineProperty(g, e, {
|
|
75
88
|
value: t,
|
|
76
89
|
enumerable: !0
|
|
77
90
|
});
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
let
|
|
82
|
-
|
|
83
|
-
let
|
|
91
|
+
v("view", h);
|
|
92
|
+
let y = s.includes("nodeAtPoint") ? i.nodeAtPoint : void 0;
|
|
93
|
+
y && v("nodeAtPoint", ((e, n) => y(t(m(), e), n)));
|
|
94
|
+
let b = s.includes("snap") ? i.snap : void 0;
|
|
95
|
+
b && v("snap", { point: (e) => o(m(), b.point(t(m(), e))) });
|
|
96
|
+
let x = c ? o(m(), c) : null, S = _();
|
|
84
97
|
return {
|
|
85
|
-
map:
|
|
86
|
-
deps:
|
|
98
|
+
map: m,
|
|
99
|
+
deps: g,
|
|
87
100
|
carry(e) {
|
|
88
|
-
let t =
|
|
101
|
+
let t = m(), n = {
|
|
89
102
|
...e,
|
|
90
|
-
world:
|
|
103
|
+
world: o(t, e.world)
|
|
91
104
|
};
|
|
92
105
|
if (e.drag) {
|
|
93
|
-
let r =
|
|
106
|
+
let r = x ?? o(t, e.drag.start), i = o(t, e.drag.current), a = e.drag.affordance;
|
|
94
107
|
n.drag = {
|
|
95
108
|
...e.drag,
|
|
96
109
|
start: r,
|
|
97
|
-
current:
|
|
110
|
+
current: i,
|
|
98
111
|
delta: {
|
|
99
|
-
x:
|
|
100
|
-
y:
|
|
112
|
+
x: i.x - r.x,
|
|
113
|
+
y: i.y - r.y
|
|
101
114
|
},
|
|
102
|
-
...e.drag.points ? { points:
|
|
103
|
-
...
|
|
104
|
-
...
|
|
105
|
-
fixedPoint:
|
|
115
|
+
...e.drag.points ? { points: S(e.drag.points, t) } : {},
|
|
116
|
+
...a?.fixedPoint ? { affordance: {
|
|
117
|
+
...a,
|
|
118
|
+
fixedPoint: o(t, a.fixedPoint)
|
|
106
119
|
} } : {}
|
|
107
120
|
};
|
|
108
121
|
}
|
|
109
|
-
return e.deps && (n.deps =
|
|
122
|
+
return e.deps && (n.deps = g), n;
|
|
110
123
|
}
|
|
111
124
|
};
|
|
112
125
|
}
|
|
113
|
-
function
|
|
126
|
+
function _() {
|
|
114
127
|
let e = null, t = null, n = [];
|
|
115
|
-
return (r,
|
|
116
|
-
let
|
|
117
|
-
(r !== e || !
|
|
128
|
+
return (r, i) => {
|
|
129
|
+
let a = t !== null && t.scale.x === i.scale.x && t.scale.y === i.scale.y && t.offset.x === i.offset.x && t.offset.y === i.offset.y;
|
|
130
|
+
(r !== e || !a || r.length < n.length) && (e = r, n = []), t = i;
|
|
118
131
|
for (let e = n.length; e < r.length; e++) n.push({
|
|
119
132
|
...r[e],
|
|
120
|
-
...i
|
|
133
|
+
...o(i, r[e])
|
|
121
134
|
});
|
|
122
135
|
return n.slice();
|
|
123
136
|
};
|
|
124
137
|
}
|
|
125
|
-
function
|
|
138
|
+
function v(e, t) {
|
|
126
139
|
let n = { ...e };
|
|
127
140
|
return e.onMove && (n.onMove = (n) => e.onMove(t.carry(n))), e.onEnd && (n.onEnd = (n, r) => e.onEnd(t.carry(n), r)), e.overlay && (n.overlay = () => {
|
|
128
141
|
let n = e.overlay();
|
|
129
|
-
return n &&
|
|
142
|
+
return n && y(n, t.map());
|
|
130
143
|
}), n;
|
|
131
144
|
}
|
|
132
|
-
function
|
|
133
|
-
let
|
|
145
|
+
function y(e, n) {
|
|
146
|
+
let r = (e) => t(n, e);
|
|
134
147
|
switch (e.kind) {
|
|
135
148
|
case "marquee": return {
|
|
136
149
|
...e,
|
|
137
|
-
start:
|
|
138
|
-
current:
|
|
150
|
+
start: r(e.start),
|
|
151
|
+
current: r(e.current)
|
|
139
152
|
};
|
|
140
153
|
case "lasso": return {
|
|
141
154
|
...e,
|
|
142
|
-
vertices: e.vertices.map(
|
|
143
|
-
current:
|
|
155
|
+
vertices: e.vertices.map(r),
|
|
156
|
+
current: r(e.current)
|
|
144
157
|
};
|
|
145
158
|
case "polyline": return {
|
|
146
159
|
...e,
|
|
147
|
-
points: e.points.map(
|
|
160
|
+
points: e.points.map(r)
|
|
148
161
|
};
|
|
149
162
|
case "insertPreview": return {
|
|
150
163
|
...e,
|
|
151
|
-
bounds:
|
|
152
|
-
extras:
|
|
153
|
-
...e.anchorPoint ? { anchorPoint:
|
|
164
|
+
bounds: i(n, e.bounds),
|
|
165
|
+
extras: b(e.extras, n),
|
|
166
|
+
...e.anchorPoint ? { anchorPoint: r(e.anchorPoint) } : {}
|
|
154
167
|
};
|
|
155
168
|
}
|
|
156
169
|
}
|
|
157
|
-
function
|
|
170
|
+
function b(e, n) {
|
|
158
171
|
if (typeof e != "object" || !e) return e;
|
|
159
172
|
let r = e, i = (e) => t(n, e), a = (e) => typeof e == "number" ? e / ((n.scale.x + n.scale.y) / 2) : e, o = { ...r };
|
|
160
173
|
return r.a && r.b && (o.a = i(r.a), o.b = i(r.b)), r.center && (o.center = i(r.center)), "radius" in r && (o.radius = a(r.radius)), "outerRadius" in r && (o.outerRadius = a(r.outerRadius)), Array.isArray(r.samples) && (o.samples = r.samples.map((e) => ({
|
|
@@ -163,6 +176,6 @@ function h(e, n) {
|
|
|
163
176
|
}))), o;
|
|
164
177
|
}
|
|
165
178
|
//#endregion
|
|
166
|
-
export {
|
|
179
|
+
export { m as carryPose, d as editingLayer, h as inPlane, u as insertLayer, p as invertPlane, f as planeOf, l as selectionLayer };
|
|
167
180
|
|
|
168
181
|
//# sourceMappingURL=planeInput.js.map
|