@weasel-js/core 1.7.1 → 1.7.2
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 +30 -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
|
@@ -8,16 +8,16 @@ import { geometryDataOp as f } from "../geometryProjection.js";
|
|
|
8
8
|
import { unionBounds as p } from "../../../core/geometry/unionBounds.js";
|
|
9
9
|
import { remapRotatedLeaf as m, translatePoseViaDescriptor as h } from "../../../core/geometry/poseDescriptor.js";
|
|
10
10
|
import { poseDescriptorOf as g } from "../poseDescriptorDep.js";
|
|
11
|
-
import {
|
|
12
|
-
import { DEFAULT_RESIZE_BEHAVIORS as
|
|
13
|
-
import { fixedCornerOf as
|
|
14
|
-
import { rotatePoint as
|
|
15
|
-
import { defaultCommitAdapter as
|
|
16
|
-
import { scenePoseFrame as
|
|
17
|
-
import { boxToBox as
|
|
11
|
+
import { carryPose as _, inPlane as v, invertPlane as y, planeOf as b, selectionLayer as x } from "../planeInput.js";
|
|
12
|
+
import { DEFAULT_RESIZE_BEHAVIORS as S } from "../resize/behaviors/index.js";
|
|
13
|
+
import { fixedCornerOf as C } from "../resize/cornerHandles.js";
|
|
14
|
+
import { rotatePoint as w } from "../rotate/geometry.js";
|
|
15
|
+
import { defaultCommitAdapter as ee } from "../defaultCommitAdapter.js";
|
|
16
|
+
import { scenePoseFrame as te } from "../poseFrame.js";
|
|
17
|
+
import { boxToBox as T } from "@weasel-js/geom";
|
|
18
18
|
//#region src/interactions/actions/defaults/resize.ts
|
|
19
|
-
var
|
|
20
|
-
function
|
|
19
|
+
var E = (e) => e, D = [];
|
|
20
|
+
function O(e) {
|
|
21
21
|
let t = g(e.deps.poseDescriptor), n = e.deps.resizePolicy;
|
|
22
22
|
return n ? {
|
|
23
23
|
behaviors: n.constraints,
|
|
@@ -26,15 +26,15 @@ function D(e) {
|
|
|
26
26
|
geometry: t,
|
|
27
27
|
policy: n
|
|
28
28
|
} : {
|
|
29
|
-
behaviors:
|
|
30
|
-
pointSnap:
|
|
31
|
-
expandIds:
|
|
29
|
+
behaviors: S,
|
|
30
|
+
pointSnap: D,
|
|
31
|
+
expandIds: E,
|
|
32
32
|
geometry: t,
|
|
33
33
|
policy: void 0
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
let i = e.x + e.width / 2, a = e.y + e.height / 2, o =
|
|
36
|
+
function k(e, t, n, r) {
|
|
37
|
+
let i = e.x + e.width / 2, a = e.y + e.height / 2, o = w(e.x, e.y, i, a, t), s = w(e.x + e.width, e.y, i, a, t), c = w(e.x + e.width, e.y + e.height, i, a, t), l = w(e.x, e.y + e.height, i, a, t), u = null, d = null;
|
|
38
38
|
if (n.x !== "free" && n.y !== "free") {
|
|
39
39
|
let e = n.x === "min" && n.y === "min" ? o : n.x === "max" && n.y === "min" ? s : n.x === "max" && n.y === "max" ? c : l, t = n.x === "min" && n.y === "min" ? c : n.x === "max" && n.y === "min" ? l : n.x === "max" && n.y === "max" ? o : s;
|
|
40
40
|
d = {
|
|
@@ -62,7 +62,7 @@ function ee(e, t, n, r) {
|
|
|
62
62
|
modifiers: r
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
function
|
|
65
|
+
function ne(e, t, n, r) {
|
|
66
66
|
if (n.frame === "center") {
|
|
67
67
|
let t = n.worldX - r.center.worldX, i = n.worldY - r.center.worldY;
|
|
68
68
|
return {
|
|
@@ -90,7 +90,7 @@ function te(e, t, n, r) {
|
|
|
90
90
|
height: f
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function
|
|
93
|
+
function re(t, n) {
|
|
94
94
|
let r = (t) => {
|
|
95
95
|
let r = e(n, {
|
|
96
96
|
x: t.worldX,
|
|
@@ -109,7 +109,7 @@ function O(t, n) {
|
|
|
109
109
|
origin: r(t.origin)
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
|
-
function
|
|
112
|
+
function ie(e, n) {
|
|
113
113
|
if (!e) return e;
|
|
114
114
|
let r = t(n, {
|
|
115
115
|
x: e.worldX,
|
|
@@ -121,7 +121,7 @@ function k(e, n) {
|
|
|
121
121
|
worldY: r.y
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
function
|
|
124
|
+
function ae(e, t, n, r, i) {
|
|
125
125
|
if (i !== 0) {
|
|
126
126
|
let e = Math.cos(-i), t = Math.sin(-i), a = e * n - t * r, o = t * n + e * r;
|
|
127
127
|
n = a, r = o;
|
|
@@ -134,7 +134,7 @@ function A(e, t, n, r, i) {
|
|
|
134
134
|
height: c
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
-
var
|
|
137
|
+
var A = v({
|
|
138
138
|
id: "resize",
|
|
139
139
|
label: "Resize",
|
|
140
140
|
eligible: { capability: "transforms-selection" },
|
|
@@ -151,30 +151,33 @@ var j = _({
|
|
|
151
151
|
invoker: {
|
|
152
152
|
timing: "ongoing",
|
|
153
153
|
start(e, t) {
|
|
154
|
-
let g = e.deps.selection,
|
|
155
|
-
if (!g || !
|
|
156
|
-
let
|
|
157
|
-
if (
|
|
158
|
-
let
|
|
159
|
-
if (!
|
|
160
|
-
let { behaviors:
|
|
161
|
-
if (
|
|
162
|
-
let
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
let g = e.deps.selection, v = e.deps.scene, x = e.deps.applyOps, S = e.deps.geometryProjection;
|
|
155
|
+
if (!g || !v) return {};
|
|
156
|
+
let E = g.get();
|
|
157
|
+
if (E.length === 0) return {};
|
|
158
|
+
let D = e.drag?.affordance?.anchor;
|
|
159
|
+
if (!D) return {};
|
|
160
|
+
let { behaviors: A, pointSnap: j, expandIds: M, geometry: N, policy: P } = O(e), F = M(E);
|
|
161
|
+
if (F.length === 0) return {};
|
|
162
|
+
let I = E.length === 1 && (F.length !== 1 || F[0] !== E[0]), L = I ? F : E, R = te(v, e.deps.poseComposition), z = e.deps.view, B = (e, t) => {
|
|
163
|
+
let n = v.get(e)?.layer;
|
|
164
|
+
return R.local(e, _(N, t, n === void 0 ? null : b(z, n)));
|
|
165
|
+
}, V = /* @__PURE__ */ new Map(), H = /* @__PURE__ */ new Map(), U = [];
|
|
166
|
+
for (let e of L) {
|
|
167
|
+
let t = v.get(e);
|
|
165
168
|
if (!t) continue;
|
|
166
|
-
|
|
167
|
-
let n =
|
|
168
|
-
|
|
169
|
+
V.set(e, t.pose);
|
|
170
|
+
let n = _(N, R.world(e), y(b(z, t.layer)));
|
|
171
|
+
H.set(e, n), U.push(N.getBounds(n));
|
|
169
172
|
}
|
|
170
|
-
if (
|
|
171
|
-
let
|
|
173
|
+
if (V.size === 0) return {};
|
|
174
|
+
let W = U.length === 1 ? U[0] : p(U), G = !I && L.length === 1 ? H.get(L[0]) : W, K = I ? 0 : N.getRotation?.(G) ?? 0, q = C(W, D), oe = K === 0 ? q : w(q.x, q.y, W.x + W.width / 2, W.y + W.height / 2, K), J = {
|
|
172
175
|
x: e.drag?.start.x ?? 0,
|
|
173
176
|
y: e.drag?.start.y ?? 0
|
|
174
177
|
}, Y = o(e.deps), X = a(e.deps), Z = {
|
|
175
|
-
draggedIds:
|
|
176
|
-
origin: /* @__PURE__ */ new Map([[
|
|
177
|
-
current: /* @__PURE__ */ new Map([[
|
|
178
|
+
draggedIds: E,
|
|
179
|
+
origin: /* @__PURE__ */ new Map([[E[0], G]]),
|
|
180
|
+
current: /* @__PURE__ */ new Map([[E[0], G]]),
|
|
178
181
|
snap: null,
|
|
179
182
|
modifiers: { ...e.modifiers },
|
|
180
183
|
pointer: {
|
|
@@ -187,35 +190,35 @@ var j = _({
|
|
|
187
190
|
plane: X(),
|
|
188
191
|
adapter: void 0,
|
|
189
192
|
scratch: {}
|
|
190
|
-
},
|
|
191
|
-
for (let e of
|
|
193
|
+
}, se = Z;
|
|
194
|
+
for (let e of A) e.onStart?.(se);
|
|
192
195
|
let Q = {
|
|
193
|
-
writeIds:
|
|
194
|
-
scene:
|
|
195
|
-
frame:
|
|
196
|
-
startPoses:
|
|
197
|
-
startWorlds:
|
|
198
|
-
originBounds:
|
|
199
|
-
anchor:
|
|
196
|
+
writeIds: L,
|
|
197
|
+
scene: v,
|
|
198
|
+
frame: R,
|
|
199
|
+
startPoses: V,
|
|
200
|
+
startWorlds: H,
|
|
201
|
+
originBounds: W,
|
|
202
|
+
anchor: D,
|
|
200
203
|
startWorld: J,
|
|
201
|
-
originRotation:
|
|
202
|
-
fixedWorld:
|
|
204
|
+
originRotation: K,
|
|
205
|
+
fixedWorld: oe,
|
|
203
206
|
previews: /* @__PURE__ */ new Map(),
|
|
204
207
|
overrideEntries: /* @__PURE__ */ new Map(),
|
|
205
|
-
geometry:
|
|
206
|
-
behaviors:
|
|
207
|
-
pointSnap:
|
|
208
|
+
geometry: N,
|
|
209
|
+
behaviors: A,
|
|
210
|
+
pointSnap: j,
|
|
208
211
|
gestureCtx: Z,
|
|
209
|
-
applyOps:
|
|
210
|
-
geometryProjection:
|
|
211
|
-
lifecycle: c(
|
|
212
|
+
applyOps: x,
|
|
213
|
+
geometryProjection: S,
|
|
214
|
+
lifecycle: c(P, "Resize", A)
|
|
212
215
|
}, { lifecycle: $ } = Q;
|
|
213
|
-
$.start(
|
|
214
|
-
let
|
|
216
|
+
$.start(L);
|
|
217
|
+
let ce = () => {
|
|
215
218
|
let e = {
|
|
216
|
-
scene:
|
|
219
|
+
scene: v,
|
|
217
220
|
applyOps: Q.applyOps,
|
|
218
|
-
adapter:
|
|
221
|
+
adapter: ee(v, g.adapterMethods)
|
|
219
222
|
}, t = l(Q.behaviors, Q.gestureCtx);
|
|
220
223
|
if (t === null) return !1;
|
|
221
224
|
if (t !== void 0) return s(e, $, t), !0;
|
|
@@ -230,7 +233,7 @@ var j = _({
|
|
|
230
233
|
if (Q.geometryProjection) {
|
|
231
234
|
let a = Q.scene.get(e);
|
|
232
235
|
if (a) {
|
|
233
|
-
let o = Q.geometry.getBounds(r), s = Q.geometry.getBounds(t), c =
|
|
236
|
+
let o = Q.geometry.getBounds(r), s = Q.geometry.getBounds(t), c = T(o.x, o.y, o.width, o.height, s.x, s.y, s.width, s.height), l = f(Q.geometryProjection, {
|
|
234
237
|
id: e,
|
|
235
238
|
data: a.data,
|
|
236
239
|
pose: r
|
|
@@ -267,7 +270,7 @@ var j = _({
|
|
|
267
270
|
clientX: 0,
|
|
268
271
|
clientY: 0
|
|
269
272
|
}, Q.gestureCtx.view = Y(), Q.gestureCtx.plane = X();
|
|
270
|
-
let a =
|
|
273
|
+
let a = ae(Q.originBounds, Q.anchor, t, n, Q.originRotation), o = Q.gestureCtx;
|
|
271
274
|
for (let e of Q.behaviors) {
|
|
272
275
|
let t = e.onMove?.(o, {
|
|
273
276
|
pose: a,
|
|
@@ -282,39 +285,39 @@ var j = _({
|
|
|
282
285
|
}
|
|
283
286
|
let s = (e) => {
|
|
284
287
|
let t = Q.startWorlds.get(e);
|
|
285
|
-
if (t !== void 0) return
|
|
288
|
+
if (t !== void 0) return I && i(t) !== null ? m(t, Q.originBounds, a) : Q.geometry.remapBounds(t, Q.originBounds, a);
|
|
286
289
|
};
|
|
287
|
-
if (Q.previews.clear(), !
|
|
290
|
+
if (Q.previews.clear(), !I && Q.writeIds.length === 1) {
|
|
288
291
|
let e = Q.writeIds[0], t = s(e);
|
|
289
292
|
if (t === void 0) {
|
|
290
293
|
r(Q);
|
|
291
294
|
return;
|
|
292
295
|
}
|
|
293
296
|
if (Q.originRotation !== 0) {
|
|
294
|
-
let e = a.x + a.width / 2, n = a.y + a.height / 2, r =
|
|
297
|
+
let e = a.x + a.width / 2, n = a.y + a.height / 2, r = C(a, Q.anchor), i = w(r.x, r.y, e, n, Q.originRotation), o = Q.fixedWorld.x - i.x, s = Q.fixedWorld.y - i.y;
|
|
295
298
|
t = h(t, o, s, Q.geometry);
|
|
296
299
|
}
|
|
297
300
|
if (Q.pointSnap.length > 0) {
|
|
298
|
-
let e = Q.originRotation, n = t, r =
|
|
301
|
+
let e = Q.originRotation, n = t, r = k(n, e, Q.anchor, Q.gestureCtx.modifiers), i = Q.gestureCtx.plane ?? null;
|
|
299
302
|
for (let a of Q.pointSnap) {
|
|
300
|
-
let o = i ?
|
|
303
|
+
let o = i ? ie(a.onMove(re(r, i)), i) : a.onMove(r);
|
|
301
304
|
if (o) {
|
|
302
|
-
t =
|
|
305
|
+
t = ne(n, e, o, r);
|
|
303
306
|
break;
|
|
304
307
|
}
|
|
305
308
|
}
|
|
306
309
|
}
|
|
307
|
-
Q.previews.set(e,
|
|
310
|
+
Q.previews.set(e, B(e, t)), Q.gestureCtx.current = /* @__PURE__ */ new Map([[e, t]]);
|
|
308
311
|
} else for (let e of Q.writeIds) {
|
|
309
312
|
let t = s(e);
|
|
310
|
-
t !== void 0 && Q.previews.set(e,
|
|
313
|
+
t !== void 0 && Q.previews.set(e, B(e, t));
|
|
311
314
|
}
|
|
312
315
|
r(Q);
|
|
313
316
|
},
|
|
314
317
|
onEnd(e, t) {
|
|
315
318
|
let r = !1;
|
|
316
319
|
try {
|
|
317
|
-
t === "commit" ? r =
|
|
320
|
+
t === "commit" ? r = ce() : u(Q.behaviors, Q.gestureCtx);
|
|
318
321
|
} finally {
|
|
319
322
|
n(Q), Q.previews.clear(), $.end(r);
|
|
320
323
|
}
|
|
@@ -325,8 +328,8 @@ var j = _({
|
|
|
325
328
|
}
|
|
326
329
|
},
|
|
327
330
|
enabled: () => !0
|
|
328
|
-
},
|
|
331
|
+
}, x);
|
|
329
332
|
//#endregion
|
|
330
|
-
export {
|
|
333
|
+
export { A as resizeAction };
|
|
331
334
|
|
|
332
335
|
//# sourceMappingURL=resize.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resize.js","names":["IDENTITY_EXPAND","ids","EMPTY_POINT_SNAP","resolveDeps","geometry","poseDescriptorOf","ctx","dep","DEFAULT_RESIZE_BEHAVIORS","buildPointSnapContext","cx","pose","cy","tl","rotatePoint","rotation","tr","br","bl","draggedCorner","fixedCorner","anchor","fixedPt","draggedPt","applyPointSnap","result","dx","dy","pin","Dx","Dy","cos","sin","localW","localH","newWidth","newHeight","newCx","newCy","pointSnapToCamera","cam","w","fromPlane","m","p","pointSnapFromPlane","r","toPlane","computeProposedBounds","cs","sn","dxLocal","dyLocal","nx","ob","ny","nw","nh","resizeAction","inPlane","selection","scene","applyOps","geometryProjection","expanded","expandIds","isGroupPath","writeIds","frame","scenePoseFrame","startPoses","startWorlds","leafBounds","id","node","world","originBounds","unionBounds","originPose","originRotation","fixedLocal","fixedCornerOf","fixedWorld","startWorld","readView","gestureViewReader","readPlane","gesturePlaneReader","gestureCtx","ctxAsRect","b","behaviors","scratch","readGestureLifecycle","policy","commitResize","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","committed","sb","db","boxToBox","dataOp","geometryDataOp","nb","createTransformOp","mctx","proposedBounds","behaviorCtx","computePose","sp","poseRotationOf","remapRotatedLeaf","proposedPose","newCenterX","newCenterY","newFixedLocal","newFixedWorld","correctionX","correctionY","translatePoseViaDescriptor","poseAsRect","psCtx","plane","beh","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/resize.ts"],"sourcesContent":["/**\n * `resizeAction` — ongoing Action descriptor for anchor-relative drag resize.\n *\n * ## Status: REAL\n *\n * Performs real anchor-relative resize math for rect-shaped poses. Reads\n * `ctx.drag.affordance.anchor` to determine which corner is fixed, captures\n * start poses, applies per-frame bounds remapping, and commits one batch on\n * end — labeled, transient and observed per the `resizePolicy` dep's\n * lifecycle fields.\n *\n * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep\n *\n * The `resizePolicy` dep carries the behavior options the legacy `useResize`\n * hook exposed (`behaviors`, `pointSnapBehaviors`, `expandIds`). When the dep\n * is registered, this invoker:\n *\n * - Calls `expandIds([id])` at start. When the result expands beyond the\n * starting id, takes the group path (union-AABB origin, per-leaf remap).\n * - Runs `behaviors[]` after the raw anchor-math bounds are computed.\n * Behaviors return `{ pose? }` and rewrite the proposed bounds before\n * they're projected back into pose space.\n * - Runs `pointSnap[]` after the bounds→pose projection. The first non-null\n * `PointSnapResult` wins; this invoker back-solves a pose so the chosen\n * frame's world point lands on the snap target.\n *\n * When the dep is absent the invoker falls back to identity defaults\n * (no behaviors, no snap, `ids => ids` expansion).\n *\n * ## Pose geometry — via the `poseDescriptor` dep\n *\n * Every pose read and rewrite goes through the `poseDescriptor` dep, which\n * `<SceneCanvas>` sources from its `poseDescriptor` prop. Unsourced it is\n * `AUTO_POSE_DESCRIPTOR`, which dispatches per call to `pathPoseDescriptor`\n * for Path-shaped poses and to `RECT_POSE_DESCRIPTOR` for everything else.\n *\n * @see useResize — the React hook this descriptor mirrors.\n * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.\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 type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type {\n GestureContext,\n ModifierState,\n PointSnapBehavior,\n PointSnapContext,\n PointSnapResult,\n ResizeAnchor,\n BoundsConstraint,\n RotatedPose,\n} from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ResizePolicy } from '../depSchema';\nimport { DEFAULT_RESIZE_BEHAVIORS } from '../resize/behaviors';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport { poseRotationOf } from 'core/geometry/poseRotation';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport { fixedCornerOf } from '../resize/cornerHandles';\nimport { rotatePoint } from '../rotate/geometry';\nimport type { Op } from 'core/ops/types';\nimport type { Mat3 } from '@weasel-js/geom';\nimport { boxToBox } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { unionBounds } from 'core/geometry/unionBounds';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { fromPlane, toPlane, type PlaneMap } from 'core/viewport/parallax';\n\n// ---------------------------------------------------------------------------\n// Defaults applied when `resizePolicy` dep is absent. Mirrors the\n// destructuring defaults in `useResize`.\n// ---------------------------------------------------------------------------\n\nconst IDENTITY_EXPAND = (ids: string[]) => ids;\nconst EMPTY_POINT_SNAP: PointSnapBehavior<Bounds>[] = [];\n\nfunction resolveDeps(ctx: InvocationCtx): {\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n expandIds: (ids: string[]) => string[];\n geometry: PoseDescriptor<unknown>;\n policy: ResizePolicy<unknown> | undefined;\n} {\n const geometry = poseDescriptorOf(ctx.deps.poseDescriptor);\n const dep = ctx.deps.resizePolicy as ResizePolicy<unknown> | undefined;\n if (!dep) {\n return {\n // Standard kit behaviors (shift = aspect lock) apply even with no\n // policy wired; consumers opt out via an explicit `behaviors: []`.\n behaviors: DEFAULT_RESIZE_BEHAVIORS as BoundsConstraint<Bounds>[],\n pointSnap: EMPTY_POINT_SNAP,\n expandIds: IDENTITY_EXPAND,\n geometry,\n policy: undefined,\n };\n }\n return {\n behaviors: dep.constraints as unknown as BoundsConstraint<Bounds>[],\n pointSnap: dep.pointSnap as unknown as PointSnapBehavior<Bounds>[],\n expandIds: dep.expandIds,\n geometry,\n policy: dep,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Point-snap math (lifted from `useResize`).\n// ---------------------------------------------------------------------------\n\nfunction buildPointSnapContext<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n anchor: ResizeAnchor,\n modifiers: ModifierState,\n): PointSnapContext<TPose> {\n const cx = pose.x + pose.width / 2;\n const cy = pose.y + pose.height / 2;\n\n const tl = rotatePoint(pose.x, pose.y, cx, cy, rotation);\n const tr = rotatePoint(pose.x + pose.width, pose.y, cx, cy, rotation);\n const br = rotatePoint(pose.x + pose.width, pose.y + pose.height, cx, cy, rotation);\n const bl = rotatePoint(pose.x, pose.y + pose.height, cx, cy, rotation);\n\n let draggedCorner: { worldX: number; worldY: number } | null = null;\n let fixedCorner: { worldX: number; worldY: number } | null = null;\n\n if (anchor.x !== 'free' && anchor.y !== 'free') {\n const fixedPt =\n anchor.x === 'min' && anchor.y === 'min' ? tl :\n anchor.x === 'max' && anchor.y === 'min' ? tr :\n anchor.x === 'max' && anchor.y === 'max' ? br : bl;\n const draggedPt =\n anchor.x === 'min' && anchor.y === 'min' ? br :\n anchor.x === 'max' && anchor.y === 'min' ? bl :\n anchor.x === 'max' && anchor.y === 'max' ? tl : tr;\n fixedCorner = { worldX: fixedPt.x, worldY: fixedPt.y };\n draggedCorner = { worldX: draggedPt.x, worldY: draggedPt.y };\n }\n\n return {\n draggedCorner,\n fixedCorner,\n center: { worldX: cx, worldY: cy },\n origin: { worldX: tl.x, worldY: tl.y },\n rotation,\n anchor,\n proposed: pose,\n modifiers,\n };\n}\n\nfunction applyPointSnap<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n result: PointSnapResult,\n ctx: PointSnapContext<TPose>,\n): TPose {\n if (result.frame === 'center') {\n const dx = result.worldX - ctx.center.worldX;\n const dy = result.worldY - ctx.center.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n if (result.frame === 'origin') {\n const dx = result.worldX - ctx.origin.worldX;\n const dy = result.worldY - ctx.origin.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n const pin = result.frame === 'dragged-corner' ? ctx.fixedCorner : ctx.draggedCorner;\n if (!pin) return pose;\n const Dx = result.worldX - pin.worldX;\n const Dy = result.worldY - pin.worldY;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const localW = Dx * cos + Dy * sin;\n const localH = -Dx * sin + Dy * cos;\n const newWidth = Math.abs(localW);\n const newHeight = Math.abs(localH);\n const newCx = (pin.worldX + result.worldX) / 2;\n const newCy = (pin.worldY + result.worldY) / 2;\n return { ...pose, x: newCx - newWidth / 2, y: newCy - newHeight / 2, width: newWidth, height: newHeight };\n}\n\n/** `ctx`'s points in the camera's world, for a snap rule written against it. */\nfunction pointSnapToCamera<TPose extends Bounds>(\n ctx: PointSnapContext<TPose>,\n m: PlaneMap,\n): PointSnapContext<TPose> {\n const cam = (p: { worldX: number; worldY: number }) => {\n const w = fromPlane(m, { x: p.worldX, y: p.worldY });\n return { worldX: w.x, worldY: w.y };\n };\n return {\n ...ctx,\n draggedCorner: ctx.draggedCorner && cam(ctx.draggedCorner),\n fixedCorner: ctx.fixedCorner && cam(ctx.fixedCorner),\n center: cam(ctx.center),\n origin: cam(ctx.origin),\n };\n}\n\n/** A snap rule's answer, back in the plane the resize works in. */\nfunction pointSnapFromPlane(\n r: PointSnapResult | null | undefined,\n m: PlaneMap,\n): PointSnapResult | null | undefined {\n if (!r) return r;\n const p = toPlane(m, { x: r.worldX, y: r.worldY });\n return { ...r, worldX: p.x, worldY: p.y };\n}\n\n// ---------------------------------------------------------------------------\n// Anchor math (rotated and unrotated).\n// ---------------------------------------------------------------------------\n\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n dx: number,\n dy: number,\n rotation: number,\n): Bounds {\n if (rotation !== 0) {\n const cs = Math.cos(-rotation);\n const sn = Math.sin(-rotation);\n const dxLocal = cs * dx - sn * dy;\n const dyLocal = sn * dx + cs * dy;\n dx = dxLocal;\n dy = dyLocal;\n }\n let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface ResizeScratch {\n /** Ids the gesture writes to. For group expansion this is the leaf set;\n * for the single-id path it's the original selection. */\n writeIds: NodeId[];\n scene: Scene<unknown, string, unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Start poses keyed by write id, as stored — the `from` of each op. */\n startPoses: Map<NodeId, unknown>;\n /** Start poses in world — the frame the anchor math and the drag share. */\n startWorlds: Map<NodeId, unknown>;\n /** Shared origin bounds (union for group/multi-select, own bounds for\n * single). Used as the `src` rect for `geometry.remapBounds`. */\n originBounds: Bounds;\n anchor: ResizeAnchor;\n startWorld: { x: number; y: number };\n /** Rotation captured at gesture start (from `geometry.getRotation?`). */\n originRotation: number;\n /** World-space position of the diagonally opposite corner at start. Used\n * for the rotated-resize fixed-corner pin correction. */\n fixedWorld: { x: number; y: number };\n /** In-flight preview poses buffered during drag. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n geometry: PoseDescriptor<unknown>;\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n /** Gesture context handed to behaviors. Reused across move/end. */\n gestureCtx: GestureContext<unknown>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * the final pose commit routes through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n /** Optional eager-sync seam captured at gesture start. When present, the\n * commit emits a `setData` op per leaf mapping its data-held geometry by\n * the box→box affine the pose underwent. Undefined → pose-only commit. */\n geometryProjection?: GeometryProjection;\n /** Label, history and callbacks from the `resizePolicy` dep. */\n lifecycle: GestureLifecycle;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `resize` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n * Reads optional `resizePolicy` dep when present.\n * Requires `InvocationCtx.drag.affordance` with a `handle:*` kind.\n */\nexport const resizeAction: Action & { requires: string[] } = inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claimed every drag at ambient\n // scope, tying areaSelect's. The resize handles bind it\n // (`selectionTransformBindings`, the `transform` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', '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 geometryProjection = ctx.deps.geometryProjection as GeometryProjection | undefined;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const affordance = ctx.drag?.affordance;\n const anchor = affordance?.anchor;\n if (!anchor) return {};\n\n const { behaviors, pointSnap, expandIds, geometry, policy } = resolveDeps(ctx);\n\n // Group expansion. When the starting selection is a single id but\n // `expandIds` returns a different set, we're in the group path:\n // every leaf is written, and origin bounds is the union AABB.\n // When `expandIds` returns the same list (identity default or no-op),\n // we write the selected ids directly.\n const expanded = expandIds(ids as unknown as string[]);\n if (expanded.length === 0) return {};\n\n const isGroupPath =\n ids.length === 1 && (expanded.length !== 1 || expanded[0] !== (ids[0] as string));\n const writeIds = (isGroupPath ? expanded : (ids as unknown as string[])) as NodeId[];\n\n // Capture start poses + per-leaf bounds. The drag delta is world, so\n // the anchor math runs on world poses; each frame's result is stored\n // back in the node's own parent frame.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const startPoses = new Map<NodeId, unknown>();\n const startWorlds = new Map<NodeId, unknown>();\n const leafBounds: Bounds[] = [];\n for (const id of writeIds) {\n const node = scene.get(id);\n if (!node) continue;\n startPoses.set(id, node.pose);\n const world = frame.world(id);\n startWorlds.set(id, world);\n leafBounds.push(geometry.getBounds(world));\n }\n if (startPoses.size === 0) return {};\n\n // `leafBounds` is non-empty here (startPoses.size === 0 guarded above),\n // and the union branch only runs for length >= 2 → `!` is safe.\n const originBounds = leafBounds.length === 1\n ? leafBounds[0]\n : unionBounds(leafBounds)!;\n\n // Rotation captured only for the single-write-id path; group-resize\n // takes the AABB-frame (unrotated) path even if leaves have rotation.\n const originPose = !isGroupPath && writeIds.length === 1\n ? startWorlds.get(writeIds[0])\n : (originBounds as unknown);\n const originRotation = !isGroupPath\n ? (geometry.getRotation?.(originPose) ?? 0)\n : 0;\n\n const fixedLocal = fixedCornerOf(originBounds, anchor);\n const fixedWorld = originRotation === 0\n ? fixedLocal\n : rotatePoint(\n fixedLocal.x, fixedLocal.y,\n originBounds.x + originBounds.width / 2,\n originBounds.y + originBounds.height / 2,\n originRotation,\n );\n\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n\n // Minimal GestureContext for behaviors. `draggedIds` matches the\n // legacy hook: the starting id (not the expanded leaf set).\n const readView = gestureViewReader(ctx.deps);\n const readPlane = gesturePlaneReader(ctx.deps);\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: ids as unknown as string[],\n origin: new Map<string, unknown>([[ids[0] as string, originPose]]),\n current: new Map<string, unknown>([[ids[0] as string, originPose]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: startWorld.x, worldY: startWorld.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n // `adapter` is unused by the kit's behaviors; cast to satisfy the type.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n\n // Fire behavior onStart hooks (parity with `useResize`).\n const ctxAsRect = gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of behaviors) b.onStart?.(ctxAsRect);\n\n const scratch: ResizeScratch = {\n writeIds,\n scene,\n frame,\n startPoses,\n startWorlds,\n originBounds,\n anchor,\n startWorld,\n originRotation,\n fixedWorld,\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n geometry,\n behaviors,\n pointSnap,\n gestureCtx,\n applyOps,\n geometryProjection,\n lifecycle: readGestureLifecycle(policy, 'Resize', behaviors),\n };\n const { lifecycle } = scratch;\n lifecycle.start(writeIds as string[]);\n\n // Returns whether anything reached the document.\n const commitResize = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n\n if (scratch.previews.size === 0) return false;\n\n // One transform op per write id (from = pre-drag start pose, to =\n // final preview pose), committed as a single batch → one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.writeIds) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.startPoses.get(id);\n if (from === undefined) continue;\n let committed = next;\n // Eager-sync: map data-held geometry by the box→box affine the\n // pose underwent (start-pose bounds → final-pose bounds). Opt-in\n // via the geometryProjection seam; a no-op when the dep is absent.\n if (scratch.geometryProjection) {\n const node = scratch.scene.get(id);\n if (node) {\n const sb = scratch.geometry.getBounds(from);\n const db = scratch.geometry.getBounds(next);\n const m: Mat3 = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(\n scratch.geometryProjection,\n { id: id as string, data: node.data, pose: from },\n m,\n lifecycle.label,\n );\n if (dataOp) {\n ops.push(dataOp);\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (db.width < 0 || db.height < 0) {\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n committed = scratch.geometry.remapBounds(next, db, nb) as typeof next;\n }\n }\n }\n }\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: committed,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n return {\n kind: 'resize',\n onMove(mctx: InvocationCtx): void {\n if (!mctx.drag) return;\n const dx = mctx.drag.current.x - scratch.startWorld.x;\n const dy = mctx.drag.current.y - scratch.startWorld.y;\n\n // Refresh modifiers + pointer on the gesture ctx for behaviors.\n scratch.gestureCtx.modifiers = { ...mctx.modifiers };\n scratch.gestureCtx.pointer = {\n worldX: mctx.drag.current.x,\n worldY: mctx.drag.current.y,\n clientX: 0,\n clientY: 0,\n };\n scratch.gestureCtx.view = readView();\n scratch.gestureCtx.plane = readPlane();\n\n let proposedBounds = computeProposedBounds(\n scratch.originBounds,\n scratch.anchor,\n dx,\n dy,\n scratch.originRotation,\n );\n\n // Behaviors run in bounds-space.\n const behaviorCtx = scratch.gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(behaviorCtx, {\n pose: proposedBounds,\n anchor: scratch.anchor,\n });\n if (!r) continue;\n if (r.pose !== undefined) {\n proposedBounds = {\n x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height,\n };\n }\n }\n\n // Project bounds → pose. For the group path, each leaf is remapped\n // from its own startPose; for single, from the start pose directly.\n //\n // A rotated leaf in a group needs its own frame: `src`/`dst` are\n // world-frame here, unlike the single path where the drag delta was\n // already projected into the leaf's frame, so the naive affine\n // scales the wrong pair of extents. See `remapRotatedLeaf`.\n const computePose = (id: NodeId): unknown => {\n const sp = scratch.startWorlds.get(id);\n if (sp === undefined) return undefined;\n if (isGroupPath && poseRotationOf(sp) !== null) {\n return remapRotatedLeaf(\n sp as RotatedPose, scratch.originBounds, proposedBounds,\n );\n }\n return scratch.geometry.remapBounds(sp, scratch.originBounds, proposedBounds);\n };\n\n // Single-id path: apply rotation correction + point-snap, then\n // store. Group path: rotation correction + point-snap don't apply\n // (group resize is AABB-frame).\n scratch.previews.clear();\n\n if (!isGroupPath && scratch.writeIds.length === 1) {\n const id = scratch.writeIds[0];\n let proposedPose = computePose(id);\n if (proposedPose === undefined) { syncPreviewOverrides(scratch); return; }\n\n if (scratch.originRotation !== 0) {\n const newCenterX = proposedBounds.x + proposedBounds.width / 2;\n const newCenterY = proposedBounds.y + proposedBounds.height / 2;\n const newFixedLocal = fixedCornerOf(proposedBounds, scratch.anchor);\n const newFixedWorld = rotatePoint(\n newFixedLocal.x, newFixedLocal.y,\n newCenterX, newCenterY,\n scratch.originRotation,\n );\n const correctionX = scratch.fixedWorld.x - newFixedWorld.x;\n const correctionY = scratch.fixedWorld.y - newFixedWorld.y;\n proposedPose = translatePoseViaDescriptor(proposedPose, correctionX, correctionY, scratch.geometry);\n }\n\n if (scratch.pointSnap.length > 0) {\n const rotation = scratch.originRotation;\n const poseAsRect = proposedPose as Bounds;\n const psCtx = buildPointSnapContext(\n poseAsRect,\n rotation,\n scratch.anchor,\n scratch.gestureCtx.modifiers,\n );\n // Point snaps are the surface's rules over the camera's world, so\n // on a plane their points cross at this boundary.\n const plane = scratch.gestureCtx.plane ?? null;\n for (const beh of scratch.pointSnap) {\n const result = plane\n ? pointSnapFromPlane(beh.onMove(pointSnapToCamera(psCtx, plane)), plane)\n : beh.onMove(psCtx);\n if (result) {\n proposedPose = applyPointSnap(poseAsRect, rotation, result, psCtx) as unknown;\n break;\n }\n }\n }\n\n scratch.previews.set(id, scratch.frame.local(id, proposedPose));\n scratch.gestureCtx.current = new Map<string, unknown>([[id as string, proposedPose]]);\n } else {\n // Group / multi path: remap each leaf and store.\n for (const id of scratch.writeIds) {\n const next = computePose(id);\n if (next === undefined) continue;\n scratch.previews.set(id, scratch.frame.local(id, next));\n }\n }\n\n syncPreviewOverrides(scratch);\n },\n\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitResize();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\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 /**\n * Always enabled at the descriptor level. The dispatcher's\n * specificity-fallthrough loop treats anything `!== true` as \"skip and\n * try the next match\" — returning `ActionDisabledReason.SelectionRequired`\n * here makes the resize binding silently lose to lower-specificity\n * matches (e.g. ambient `insertAction`), inserting phantom nodes on\n * every drag instead of resizing. The invoker self-guards on empty\n * selection (returns `{}`), so a static `true` here is correct.\n *\n * Fix: previously `() => ActionDisabledReason.SelectionRequired`\n * — that broke every dispatcher-routed resize. See git blame.\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resize.js","names":["IDENTITY_EXPAND","ids","EMPTY_POINT_SNAP","resolveDeps","geometry","poseDescriptorOf","ctx","dep","DEFAULT_RESIZE_BEHAVIORS","buildPointSnapContext","cx","pose","cy","tl","rotatePoint","rotation","tr","br","bl","draggedCorner","fixedCorner","anchor","fixedPt","draggedPt","applyPointSnap","result","dx","dy","pin","Dx","Dy","cos","sin","localW","localH","newWidth","newHeight","newCx","newCy","pointSnapToCamera","cam","w","fromPlane","m","p","pointSnapFromPlane","r","toPlane","computeProposedBounds","cs","sn","dxLocal","dyLocal","nx","ob","ny","nw","nh","resizeAction","inPlane","selection","scene","applyOps","geometryProjection","expanded","expandIds","isGroupPath","writeIds","frame","scenePoseFrame","view","stored","layer","id","carryPose","world","planeOf","startPoses","startWorlds","leafBounds","node","invertPlane","originBounds","unionBounds","originPose","originRotation","fixedLocal","fixedCornerOf","fixedWorld","startWorld","readView","gestureViewReader","readPlane","gesturePlaneReader","gestureCtx","ctxAsRect","b","behaviors","scratch","readGestureLifecycle","policy","commitResize","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","committed","sb","db","boxToBox","dataOp","geometryDataOp","nb","createTransformOp","mctx","proposedBounds","behaviorCtx","computePose","sp","poseRotationOf","remapRotatedLeaf","proposedPose","newCenterX","newCenterY","newFixedLocal","newFixedWorld","correctionX","correctionY","translatePoseViaDescriptor","poseAsRect","psCtx","plane","beh","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/resize.ts"],"sourcesContent":["/**\n * `resizeAction` — ongoing Action descriptor for anchor-relative drag resize.\n *\n * ## Status: REAL\n *\n * Performs real anchor-relative resize math for rect-shaped poses. Reads\n * `ctx.drag.affordance.anchor` to determine which corner is fixed, captures\n * start poses, applies per-frame bounds remapping, and commits one batch on\n * end — labeled, transient and observed per the `resizePolicy` dep's\n * lifecycle fields.\n *\n * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep\n *\n * The `resizePolicy` dep carries the behavior options the legacy `useResize`\n * hook exposed (`behaviors`, `pointSnapBehaviors`, `expandIds`). When the dep\n * is registered, this invoker:\n *\n * - Calls `expandIds([id])` at start. When the result expands beyond the\n * starting id, takes the group path (union-AABB origin, per-leaf remap).\n * - Runs `behaviors[]` after the raw anchor-math bounds are computed.\n * Behaviors return `{ pose? }` and rewrite the proposed bounds before\n * they're projected back into pose space.\n * - Runs `pointSnap[]` after the bounds→pose projection. The first non-null\n * `PointSnapResult` wins; this invoker back-solves a pose so the chosen\n * frame's world point lands on the snap target.\n *\n * When the dep is absent the invoker falls back to identity defaults\n * (no behaviors, no snap, `ids => ids` expansion).\n *\n * ## Pose geometry — via the `poseDescriptor` dep\n *\n * Every pose read and rewrite goes through the `poseDescriptor` dep, which\n * `<SceneCanvas>` sources from its `poseDescriptor` prop. Unsourced it is\n * `AUTO_POSE_DESCRIPTOR`, which dispatches per call to `pathPoseDescriptor`\n * for Path-shaped poses and to `RECT_POSE_DESCRIPTOR` for everything else.\n *\n * @see useResize — the React hook this descriptor mirrors.\n * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.\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 type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type {\n GestureContext,\n ModifierState,\n PointSnapBehavior,\n PointSnapContext,\n PointSnapResult,\n ResizeAnchor,\n BoundsConstraint,\n RotatedPose,\n} from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ResizePolicy } from '../depSchema';\nimport { DEFAULT_RESIZE_BEHAVIORS } from '../resize/behaviors';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport { poseRotationOf } from 'core/geometry/poseRotation';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport { fixedCornerOf } from '../resize/cornerHandles';\nimport { rotatePoint } from '../rotate/geometry';\nimport type { Op } from 'core/ops/types';\nimport type { Mat3 } from '@weasel-js/geom';\nimport { boxToBox } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { unionBounds } from 'core/geometry/unionBounds';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\nimport { fromPlane, toPlane, type PlaneMap } from 'core/viewport/parallax';\n\n// ---------------------------------------------------------------------------\n// Defaults applied when `resizePolicy` dep is absent. Mirrors the\n// destructuring defaults in `useResize`.\n// ---------------------------------------------------------------------------\n\nconst IDENTITY_EXPAND = (ids: string[]) => ids;\nconst EMPTY_POINT_SNAP: PointSnapBehavior<Bounds>[] = [];\n\nfunction resolveDeps(ctx: InvocationCtx): {\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n expandIds: (ids: string[]) => string[];\n geometry: PoseDescriptor<unknown>;\n policy: ResizePolicy<unknown> | undefined;\n} {\n const geometry = poseDescriptorOf(ctx.deps.poseDescriptor);\n const dep = ctx.deps.resizePolicy as ResizePolicy<unknown> | undefined;\n if (!dep) {\n return {\n // Standard kit behaviors (shift = aspect lock) apply even with no\n // policy wired; consumers opt out via an explicit `behaviors: []`.\n behaviors: DEFAULT_RESIZE_BEHAVIORS as BoundsConstraint<Bounds>[],\n pointSnap: EMPTY_POINT_SNAP,\n expandIds: IDENTITY_EXPAND,\n geometry,\n policy: undefined,\n };\n }\n return {\n behaviors: dep.constraints as unknown as BoundsConstraint<Bounds>[],\n pointSnap: dep.pointSnap as unknown as PointSnapBehavior<Bounds>[],\n expandIds: dep.expandIds,\n geometry,\n policy: dep,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Point-snap math (lifted from `useResize`).\n// ---------------------------------------------------------------------------\n\nfunction buildPointSnapContext<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n anchor: ResizeAnchor,\n modifiers: ModifierState,\n): PointSnapContext<TPose> {\n const cx = pose.x + pose.width / 2;\n const cy = pose.y + pose.height / 2;\n\n const tl = rotatePoint(pose.x, pose.y, cx, cy, rotation);\n const tr = rotatePoint(pose.x + pose.width, pose.y, cx, cy, rotation);\n const br = rotatePoint(pose.x + pose.width, pose.y + pose.height, cx, cy, rotation);\n const bl = rotatePoint(pose.x, pose.y + pose.height, cx, cy, rotation);\n\n let draggedCorner: { worldX: number; worldY: number } | null = null;\n let fixedCorner: { worldX: number; worldY: number } | null = null;\n\n if (anchor.x !== 'free' && anchor.y !== 'free') {\n const fixedPt =\n anchor.x === 'min' && anchor.y === 'min' ? tl :\n anchor.x === 'max' && anchor.y === 'min' ? tr :\n anchor.x === 'max' && anchor.y === 'max' ? br : bl;\n const draggedPt =\n anchor.x === 'min' && anchor.y === 'min' ? br :\n anchor.x === 'max' && anchor.y === 'min' ? bl :\n anchor.x === 'max' && anchor.y === 'max' ? tl : tr;\n fixedCorner = { worldX: fixedPt.x, worldY: fixedPt.y };\n draggedCorner = { worldX: draggedPt.x, worldY: draggedPt.y };\n }\n\n return {\n draggedCorner,\n fixedCorner,\n center: { worldX: cx, worldY: cy },\n origin: { worldX: tl.x, worldY: tl.y },\n rotation,\n anchor,\n proposed: pose,\n modifiers,\n };\n}\n\nfunction applyPointSnap<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n result: PointSnapResult,\n ctx: PointSnapContext<TPose>,\n): TPose {\n if (result.frame === 'center') {\n const dx = result.worldX - ctx.center.worldX;\n const dy = result.worldY - ctx.center.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n if (result.frame === 'origin') {\n const dx = result.worldX - ctx.origin.worldX;\n const dy = result.worldY - ctx.origin.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n const pin = result.frame === 'dragged-corner' ? ctx.fixedCorner : ctx.draggedCorner;\n if (!pin) return pose;\n const Dx = result.worldX - pin.worldX;\n const Dy = result.worldY - pin.worldY;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const localW = Dx * cos + Dy * sin;\n const localH = -Dx * sin + Dy * cos;\n const newWidth = Math.abs(localW);\n const newHeight = Math.abs(localH);\n const newCx = (pin.worldX + result.worldX) / 2;\n const newCy = (pin.worldY + result.worldY) / 2;\n return { ...pose, x: newCx - newWidth / 2, y: newCy - newHeight / 2, width: newWidth, height: newHeight };\n}\n\n/** `ctx`'s points in the camera's world, for a snap rule written against it. */\nfunction pointSnapToCamera<TPose extends Bounds>(\n ctx: PointSnapContext<TPose>,\n m: PlaneMap,\n): PointSnapContext<TPose> {\n const cam = (p: { worldX: number; worldY: number }) => {\n const w = fromPlane(m, { x: p.worldX, y: p.worldY });\n return { worldX: w.x, worldY: w.y };\n };\n return {\n ...ctx,\n draggedCorner: ctx.draggedCorner && cam(ctx.draggedCorner),\n fixedCorner: ctx.fixedCorner && cam(ctx.fixedCorner),\n center: cam(ctx.center),\n origin: cam(ctx.origin),\n };\n}\n\n/** A snap rule's answer, back in the plane the resize works in. */\nfunction pointSnapFromPlane(\n r: PointSnapResult | null | undefined,\n m: PlaneMap,\n): PointSnapResult | null | undefined {\n if (!r) return r;\n const p = toPlane(m, { x: r.worldX, y: r.worldY });\n return { ...r, worldX: p.x, worldY: p.y };\n}\n\n// ---------------------------------------------------------------------------\n// Anchor math (rotated and unrotated).\n// ---------------------------------------------------------------------------\n\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n dx: number,\n dy: number,\n rotation: number,\n): Bounds {\n if (rotation !== 0) {\n const cs = Math.cos(-rotation);\n const sn = Math.sin(-rotation);\n const dxLocal = cs * dx - sn * dy;\n const dyLocal = sn * dx + cs * dy;\n dx = dxLocal;\n dy = dyLocal;\n }\n let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface ResizeScratch {\n /** Ids the gesture writes to. For group expansion this is the leaf set;\n * for the single-id path it's the original selection. */\n writeIds: NodeId[];\n scene: Scene<unknown, string, unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Start poses keyed by write id, as stored — the `from` of each op. */\n startPoses: Map<NodeId, unknown>;\n /** Start poses in world — the frame the anchor math and the drag share. */\n startWorlds: Map<NodeId, unknown>;\n /** Shared origin bounds (union for group/multi-select, own bounds for\n * single). Used as the `src` rect for `geometry.remapBounds`. */\n originBounds: Bounds;\n anchor: ResizeAnchor;\n startWorld: { x: number; y: number };\n /** Rotation captured at gesture start (from `geometry.getRotation?`). */\n originRotation: number;\n /** World-space position of the diagonally opposite corner at start. Used\n * for the rotated-resize fixed-corner pin correction. */\n fixedWorld: { x: number; y: number };\n /** In-flight preview poses buffered during drag. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n geometry: PoseDescriptor<unknown>;\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n /** Gesture context handed to behaviors. Reused across move/end. */\n gestureCtx: GestureContext<unknown>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * the final pose commit routes through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n /** Optional eager-sync seam captured at gesture start. When present, the\n * commit emits a `setData` op per leaf mapping its data-held geometry by\n * the box→box affine the pose underwent. Undefined → pose-only commit. */\n geometryProjection?: GeometryProjection;\n /** Label, history and callbacks from the `resizePolicy` dep. */\n lifecycle: GestureLifecycle;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `resize` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n * Reads optional `resizePolicy` dep when present.\n * Requires `InvocationCtx.drag.affordance` with a `handle:*` kind.\n */\nexport const resizeAction: Action & { requires: string[] } = inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claimed every drag at ambient\n // scope, tying areaSelect's. The resize handles bind it\n // (`selectionTransformBindings`, the `transform` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', '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 geometryProjection = ctx.deps.geometryProjection as GeometryProjection | undefined;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const affordance = ctx.drag?.affordance;\n const anchor = affordance?.anchor;\n if (!anchor) return {};\n\n const { behaviors, pointSnap, expandIds, geometry, policy } = resolveDeps(ctx);\n\n // Group expansion. When the starting selection is a single id but\n // `expandIds` returns a different set, we're in the group path:\n // every leaf is written, and origin bounds is the union AABB.\n // When `expandIds` returns the same list (identity default or no-op),\n // we write the selected ids directly.\n const expanded = expandIds(ids as unknown as string[]);\n if (expanded.length === 0) return {};\n\n const isGroupPath =\n ids.length === 1 && (expanded.length !== 1 || expanded[0] !== (ids[0] as string));\n const writeIds = (isGroupPath ? expanded : (ids as unknown as string[])) as NodeId[];\n\n // Capture start poses + per-leaf bounds. The drag delta is world, so\n // the anchor math runs on world poses — carried into the plane the edit\n // is measured in — and each result is carried back to its node's plane\n // and stored in the node's own parent frame.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const view = ctx.deps.view;\n /** A world result for `id`, as stored. */\n const stored = (id: NodeId, world: unknown): unknown => {\n const layer = scene.get(id)?.layer;\n return frame.local(id, carryPose(geometry, world, layer === undefined ? null : planeOf(view, layer)));\n };\n const startPoses = new Map<NodeId, unknown>();\n const startWorlds = new Map<NodeId, unknown>();\n const leafBounds: Bounds[] = [];\n for (const id of writeIds) {\n const node = scene.get(id);\n if (!node) continue;\n startPoses.set(id, node.pose);\n const world = carryPose(geometry, frame.world(id), invertPlane(planeOf(view, node.layer)));\n startWorlds.set(id, world);\n leafBounds.push(geometry.getBounds(world));\n }\n if (startPoses.size === 0) return {};\n\n // `leafBounds` is non-empty here (startPoses.size === 0 guarded above),\n // and the union branch only runs for length >= 2 → `!` is safe.\n const originBounds = leafBounds.length === 1\n ? leafBounds[0]\n : unionBounds(leafBounds)!;\n\n // Rotation captured only for the single-write-id path; group-resize\n // takes the AABB-frame (unrotated) path even if leaves have rotation.\n const originPose = !isGroupPath && writeIds.length === 1\n ? startWorlds.get(writeIds[0])\n : (originBounds as unknown);\n const originRotation = !isGroupPath\n ? (geometry.getRotation?.(originPose) ?? 0)\n : 0;\n\n const fixedLocal = fixedCornerOf(originBounds, anchor);\n const fixedWorld = originRotation === 0\n ? fixedLocal\n : rotatePoint(\n fixedLocal.x, fixedLocal.y,\n originBounds.x + originBounds.width / 2,\n originBounds.y + originBounds.height / 2,\n originRotation,\n );\n\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n\n // Minimal GestureContext for behaviors. `draggedIds` matches the\n // legacy hook: the starting id (not the expanded leaf set).\n const readView = gestureViewReader(ctx.deps);\n const readPlane = gesturePlaneReader(ctx.deps);\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: ids as unknown as string[],\n origin: new Map<string, unknown>([[ids[0] as string, originPose]]),\n current: new Map<string, unknown>([[ids[0] as string, originPose]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: startWorld.x, worldY: startWorld.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n // `adapter` is unused by the kit's behaviors; cast to satisfy the type.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n\n // Fire behavior onStart hooks (parity with `useResize`).\n const ctxAsRect = gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of behaviors) b.onStart?.(ctxAsRect);\n\n const scratch: ResizeScratch = {\n writeIds,\n scene,\n frame,\n startPoses,\n startWorlds,\n originBounds,\n anchor,\n startWorld,\n originRotation,\n fixedWorld,\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n geometry,\n behaviors,\n pointSnap,\n gestureCtx,\n applyOps,\n geometryProjection,\n lifecycle: readGestureLifecycle(policy, 'Resize', behaviors),\n };\n const { lifecycle } = scratch;\n lifecycle.start(writeIds as string[]);\n\n // Returns whether anything reached the document.\n const commitResize = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n\n if (scratch.previews.size === 0) return false;\n\n // One transform op per write id (from = pre-drag start pose, to =\n // final preview pose), committed as a single batch → one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.writeIds) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.startPoses.get(id);\n if (from === undefined) continue;\n let committed = next;\n // Eager-sync: map data-held geometry by the box→box affine the\n // pose underwent (start-pose bounds → final-pose bounds). Opt-in\n // via the geometryProjection seam; a no-op when the dep is absent.\n if (scratch.geometryProjection) {\n const node = scratch.scene.get(id);\n if (node) {\n const sb = scratch.geometry.getBounds(from);\n const db = scratch.geometry.getBounds(next);\n const m: Mat3 = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(\n scratch.geometryProjection,\n { id: id as string, data: node.data, pose: from },\n m,\n lifecycle.label,\n );\n if (dataOp) {\n ops.push(dataOp);\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (db.width < 0 || db.height < 0) {\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n committed = scratch.geometry.remapBounds(next, db, nb) as typeof next;\n }\n }\n }\n }\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: committed,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n return {\n kind: 'resize',\n onMove(mctx: InvocationCtx): void {\n if (!mctx.drag) return;\n const dx = mctx.drag.current.x - scratch.startWorld.x;\n const dy = mctx.drag.current.y - scratch.startWorld.y;\n\n // Refresh modifiers + pointer on the gesture ctx for behaviors.\n scratch.gestureCtx.modifiers = { ...mctx.modifiers };\n scratch.gestureCtx.pointer = {\n worldX: mctx.drag.current.x,\n worldY: mctx.drag.current.y,\n clientX: 0,\n clientY: 0,\n };\n scratch.gestureCtx.view = readView();\n scratch.gestureCtx.plane = readPlane();\n\n let proposedBounds = computeProposedBounds(\n scratch.originBounds,\n scratch.anchor,\n dx,\n dy,\n scratch.originRotation,\n );\n\n // Behaviors run in bounds-space.\n const behaviorCtx = scratch.gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(behaviorCtx, {\n pose: proposedBounds,\n anchor: scratch.anchor,\n });\n if (!r) continue;\n if (r.pose !== undefined) {\n proposedBounds = {\n x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height,\n };\n }\n }\n\n // Project bounds → pose. For the group path, each leaf is remapped\n // from its own startPose; for single, from the start pose directly.\n //\n // A rotated leaf in a group needs its own frame: `src`/`dst` are\n // world-frame here, unlike the single path where the drag delta was\n // already projected into the leaf's frame, so the naive affine\n // scales the wrong pair of extents. See `remapRotatedLeaf`.\n const computePose = (id: NodeId): unknown => {\n const sp = scratch.startWorlds.get(id);\n if (sp === undefined) return undefined;\n if (isGroupPath && poseRotationOf(sp) !== null) {\n return remapRotatedLeaf(\n sp as RotatedPose, scratch.originBounds, proposedBounds,\n );\n }\n return scratch.geometry.remapBounds(sp, scratch.originBounds, proposedBounds);\n };\n\n // Single-id path: apply rotation correction + point-snap, then\n // store. Group path: rotation correction + point-snap don't apply\n // (group resize is AABB-frame).\n scratch.previews.clear();\n\n if (!isGroupPath && scratch.writeIds.length === 1) {\n const id = scratch.writeIds[0];\n let proposedPose = computePose(id);\n if (proposedPose === undefined) { syncPreviewOverrides(scratch); return; }\n\n if (scratch.originRotation !== 0) {\n const newCenterX = proposedBounds.x + proposedBounds.width / 2;\n const newCenterY = proposedBounds.y + proposedBounds.height / 2;\n const newFixedLocal = fixedCornerOf(proposedBounds, scratch.anchor);\n const newFixedWorld = rotatePoint(\n newFixedLocal.x, newFixedLocal.y,\n newCenterX, newCenterY,\n scratch.originRotation,\n );\n const correctionX = scratch.fixedWorld.x - newFixedWorld.x;\n const correctionY = scratch.fixedWorld.y - newFixedWorld.y;\n proposedPose = translatePoseViaDescriptor(proposedPose, correctionX, correctionY, scratch.geometry);\n }\n\n if (scratch.pointSnap.length > 0) {\n const rotation = scratch.originRotation;\n const poseAsRect = proposedPose as Bounds;\n const psCtx = buildPointSnapContext(\n poseAsRect,\n rotation,\n scratch.anchor,\n scratch.gestureCtx.modifiers,\n );\n // Point snaps are the surface's rules over the camera's world, so\n // on a plane their points cross at this boundary.\n const plane = scratch.gestureCtx.plane ?? null;\n for (const beh of scratch.pointSnap) {\n const result = plane\n ? pointSnapFromPlane(beh.onMove(pointSnapToCamera(psCtx, plane)), plane)\n : beh.onMove(psCtx);\n if (result) {\n proposedPose = applyPointSnap(poseAsRect, rotation, result, psCtx) as unknown;\n break;\n }\n }\n }\n\n scratch.previews.set(id, stored(id, proposedPose));\n scratch.gestureCtx.current = new Map<string, unknown>([[id as string, proposedPose]]);\n } else {\n // Group / multi path: remap each leaf and store.\n for (const id of scratch.writeIds) {\n const next = computePose(id);\n if (next === undefined) continue;\n scratch.previews.set(id, stored(id, next));\n }\n }\n\n syncPreviewOverrides(scratch);\n },\n\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitResize();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\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 /**\n * Always enabled at the descriptor level. The dispatcher's\n * specificity-fallthrough loop treats anything `!== true` as \"skip and\n * try the next match\" — returning `ActionDisabledReason.SelectionRequired`\n * here makes the resize binding silently lose to lower-specificity\n * matches (e.g. ambient `insertAction`), inserting phantom nodes on\n * every drag instead of resizing. The invoker self-guards on empty\n * selection (returns `{}`), so a static `true` here is correct.\n *\n * Fix: previously `() => ActionDisabledReason.SelectionRequired`\n * — that broke every dispatcher-routed resize. See git blame.\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|