@hyperframes/studio 0.8.99 → 0.8.100
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/dist/assets/{hyperframes-player-Rml34FRW.js → hyperframes-player-fWt87gyh.js} +1 -1
- package/dist/assets/{index-C_fi-jTe.js → index-D34Oy5DN.js} +1 -1
- package/dist/assets/{index-CVDArg3m.js → index-D6TjRAvz.js} +176 -176
- package/dist/assets/{index-D9YzDuBx.js → index-DofdzdxJ.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js +423 -312
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/components/editor/PropertyPanel.tsx +3 -3
- package/src/components/editor/domEditOverlayStartGesture.test.ts +83 -0
- package/src/components/editor/domEditOverlayStartGesture.ts +6 -4
- package/src/components/editor/manualOffsetDrag.test.ts +70 -0
- package/src/components/editor/manualOffsetDrag.ts +50 -40
- package/src/components/editor/plainTranslate.test.ts +62 -0
- package/src/components/editor/plainTranslate.ts +85 -0
- package/src/components/editor/propertyPanelTransformCommit.ts +3 -2
- package/src/components/editor/useDomEditNudge.ts +1 -1
- package/src/hooks/elementOffsetStager.ts +33 -2
- package/src/hooks/gsapRuntimeBridge.ts +1 -17
- package/src/hooks/gsapRuntimeKeyframes.ts +35 -0
- package/src/hooks/useDomEditCommits.test.tsx +12 -3
- package/src/hooks/useDomEditCommits.ts +2 -1
- package/src/hooks/useDomEditTextCommits.test.tsx +62 -5
- package/src/hooks/useDomEditTextCommits.ts +35 -35
- package/src/hooks/useDomGeometryCommit.test.tsx +62 -4
- package/src/hooks/useDomGeometryCommits.test.tsx +4 -2
- package/src/hooks/useGsapAwareEditing.test.tsx +46 -18
- package/src/hooks/useGsapAwareEditing.ts +11 -11
package/dist/index.js
CHANGED
|
@@ -32383,6 +32383,334 @@ function computeDraggedGsapPosition(element, studioOffset, fallbackBase) {
|
|
|
32383
32383
|
};
|
|
32384
32384
|
}
|
|
32385
32385
|
|
|
32386
|
+
// src/hooks/gsapRuntimeKeyframes.ts
|
|
32387
|
+
import { buildArcPath } from "@hyperframes/core/gsap-parser-acorn";
|
|
32388
|
+
var FLAT_SKIP_KEYS = /* @__PURE__ */ new Set([
|
|
32389
|
+
"ease",
|
|
32390
|
+
"duration",
|
|
32391
|
+
"delay",
|
|
32392
|
+
"stagger",
|
|
32393
|
+
"motionPath",
|
|
32394
|
+
"overwrite",
|
|
32395
|
+
"immediateRender",
|
|
32396
|
+
"onComplete",
|
|
32397
|
+
"onUpdate",
|
|
32398
|
+
"onStart",
|
|
32399
|
+
"keyframes"
|
|
32400
|
+
]);
|
|
32401
|
+
function timelinesOf(iframe) {
|
|
32402
|
+
if (!iframe?.contentWindow) return null;
|
|
32403
|
+
try {
|
|
32404
|
+
return iframe.contentWindow.__timelines ?? null;
|
|
32405
|
+
} catch {
|
|
32406
|
+
return null;
|
|
32407
|
+
}
|
|
32408
|
+
}
|
|
32409
|
+
function isXY(p) {
|
|
32410
|
+
return !!p && typeof p.x === "number" && typeof p.y === "number";
|
|
32411
|
+
}
|
|
32412
|
+
function isZeroDurationSet(duration) {
|
|
32413
|
+
return !(duration > 0);
|
|
32414
|
+
}
|
|
32415
|
+
function coordsFromMotionPath(mp) {
|
|
32416
|
+
if (!mp || typeof mp !== "object") return null;
|
|
32417
|
+
const obj = mp;
|
|
32418
|
+
const pathVal = Array.isArray(mp) ? mp : obj.path;
|
|
32419
|
+
if (!Array.isArray(pathVal)) return null;
|
|
32420
|
+
const coords = pathVal.filter(isXY).map((p) => ({ x: p.x, y: p.y }));
|
|
32421
|
+
if (coords.length < 2) return null;
|
|
32422
|
+
const curviness = typeof obj.curviness === "number" ? obj.curviness : 1;
|
|
32423
|
+
const autoRotate = typeof obj.autoRotate === "number" ? obj.autoRotate : obj.autoRotate === true;
|
|
32424
|
+
return { coords, curviness, autoRotate, isCubic: obj.type === "cubic" };
|
|
32425
|
+
}
|
|
32426
|
+
function flatTweenKeyframes(vars) {
|
|
32427
|
+
const properties = {};
|
|
32428
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
32429
|
+
if (FLAT_SKIP_KEYS.has(k)) continue;
|
|
32430
|
+
if (typeof v === "number") properties[k] = roundTo3(v);
|
|
32431
|
+
else if (typeof v === "string") properties[k] = v;
|
|
32432
|
+
}
|
|
32433
|
+
if (Object.keys(properties).length === 0) return null;
|
|
32434
|
+
return [
|
|
32435
|
+
{ percentage: 0, properties },
|
|
32436
|
+
{ percentage: 100, properties }
|
|
32437
|
+
];
|
|
32438
|
+
}
|
|
32439
|
+
function readTween(vars) {
|
|
32440
|
+
if (vars.keyframes && typeof vars.keyframes === "object") {
|
|
32441
|
+
const parsed = parsePercentageKeyframes(vars.keyframes);
|
|
32442
|
+
if (parsed) return parsed;
|
|
32443
|
+
}
|
|
32444
|
+
const mp = coordsFromMotionPath(vars.motionPath);
|
|
32445
|
+
if (mp) {
|
|
32446
|
+
const shape = buildArcPath(mp.coords, mp.curviness, mp.autoRotate, mp.isCubic);
|
|
32447
|
+
if (shape) {
|
|
32448
|
+
const n = shape.waypoints.length;
|
|
32449
|
+
const keyframes = shape.waypoints.map((wp, i) => ({
|
|
32450
|
+
percentage: n > 1 ? Math.round(i / (n - 1) * 100) : 0,
|
|
32451
|
+
properties: { x: wp.x, y: wp.y }
|
|
32452
|
+
}));
|
|
32453
|
+
return { keyframes, arcPath: shape.arcPath };
|
|
32454
|
+
}
|
|
32455
|
+
}
|
|
32456
|
+
const flat = flatTweenKeyframes(vars);
|
|
32457
|
+
return flat ? { keyframes: flat } : null;
|
|
32458
|
+
}
|
|
32459
|
+
function matchesElement(tween, el) {
|
|
32460
|
+
if (!tween.targets) return false;
|
|
32461
|
+
for (const t of tween.targets()) {
|
|
32462
|
+
if (t === el || el.id && t.id === el.id) return true;
|
|
32463
|
+
}
|
|
32464
|
+
return false;
|
|
32465
|
+
}
|
|
32466
|
+
function tweenTiming(tween) {
|
|
32467
|
+
const rawStart = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32468
|
+
const rawDur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32469
|
+
return {
|
|
32470
|
+
start: Number.isFinite(rawStart) ? rawStart : 0,
|
|
32471
|
+
duration: Number.isFinite(rawDur) ? rawDur : 0
|
|
32472
|
+
};
|
|
32473
|
+
}
|
|
32474
|
+
function varsCarryChannel(vars, channels) {
|
|
32475
|
+
if (!vars) return false;
|
|
32476
|
+
for (const ch of channels) {
|
|
32477
|
+
if (Object.prototype.hasOwnProperty.call(vars, ch)) return true;
|
|
32478
|
+
}
|
|
32479
|
+
return false;
|
|
32480
|
+
}
|
|
32481
|
+
function keyframeVarsCarryChannel(vars, channels) {
|
|
32482
|
+
const kf = vars?.keyframes;
|
|
32483
|
+
if (!kf || typeof kf !== "object") return false;
|
|
32484
|
+
if (!Array.isArray(kf) && channels.some((ch) => Object.prototype.hasOwnProperty.call(kf, ch)))
|
|
32485
|
+
return true;
|
|
32486
|
+
const steps = Array.isArray(kf) ? kf : Object.values(kf);
|
|
32487
|
+
return steps.some(
|
|
32488
|
+
(step) => step != null && typeof step === "object" && channels.some((ch) => Object.prototype.hasOwnProperty.call(step, ch))
|
|
32489
|
+
);
|
|
32490
|
+
}
|
|
32491
|
+
function resolveRuntimeTween(iframe, selector, kind, compositionId, channels) {
|
|
32492
|
+
const timelines = timelinesOf(iframe);
|
|
32493
|
+
if (!timelines) return null;
|
|
32494
|
+
let targetEl = null;
|
|
32495
|
+
try {
|
|
32496
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32497
|
+
} catch {
|
|
32498
|
+
return null;
|
|
32499
|
+
}
|
|
32500
|
+
if (!targetEl) return null;
|
|
32501
|
+
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
32502
|
+
const wantChannels = channels && channels.length > 0 ? channels : null;
|
|
32503
|
+
let first = null;
|
|
32504
|
+
let channelMatch = null;
|
|
32505
|
+
for (const tlId of tlIds) {
|
|
32506
|
+
const timeline = timelines[tlId];
|
|
32507
|
+
if (!timeline?.getChildren) continue;
|
|
32508
|
+
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
32509
|
+
for (const tween of timeline.getChildren(true)) {
|
|
32510
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32511
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32512
|
+
const isSet = !(dur > 0);
|
|
32513
|
+
if (kind === "set" ? !isSet : isSet) continue;
|
|
32514
|
+
if (wantChannels) {
|
|
32515
|
+
const carries = kind === "set" ? varsCarryChannel(tween.vars, wantChannels) : keyframeVarsCarryChannel(tween.vars, wantChannels);
|
|
32516
|
+
if (carries) {
|
|
32517
|
+
if (channelMatch === null) channelMatch = { tween, timeline };
|
|
32518
|
+
} else if (first === null) {
|
|
32519
|
+
first = { tween, timeline };
|
|
32520
|
+
}
|
|
32521
|
+
continue;
|
|
32522
|
+
}
|
|
32523
|
+
if (first === null) first = { tween, timeline };
|
|
32524
|
+
if (kind === "keyframe" && now2 != null) {
|
|
32525
|
+
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32526
|
+
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return { tween, timeline };
|
|
32527
|
+
}
|
|
32528
|
+
}
|
|
32529
|
+
}
|
|
32530
|
+
return channelMatch ?? first;
|
|
32531
|
+
}
|
|
32532
|
+
function readCarriesChannel(read, channels) {
|
|
32533
|
+
return read.keyframes.some((kf) => channels.some((c) => kf.properties[c] != null));
|
|
32534
|
+
}
|
|
32535
|
+
function readRuntimeKeyframes(iframe, selector, compositionId, requireChannels) {
|
|
32536
|
+
const timelines = timelinesOf(iframe);
|
|
32537
|
+
if (!timelines) return null;
|
|
32538
|
+
let targetEl = null;
|
|
32539
|
+
try {
|
|
32540
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32541
|
+
} catch {
|
|
32542
|
+
return null;
|
|
32543
|
+
}
|
|
32544
|
+
if (!targetEl) return null;
|
|
32545
|
+
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
32546
|
+
if (tlIds.length === 0) return null;
|
|
32547
|
+
let firstRead = null;
|
|
32548
|
+
for (const tlId of tlIds) {
|
|
32549
|
+
const timeline = timelines[tlId];
|
|
32550
|
+
if (!timeline?.getChildren) continue;
|
|
32551
|
+
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
32552
|
+
for (const tween of timeline.getChildren(true)) {
|
|
32553
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32554
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32555
|
+
if (isZeroDurationSet(dur)) continue;
|
|
32556
|
+
const read = readTween(tween.vars);
|
|
32557
|
+
if (!read) continue;
|
|
32558
|
+
if (requireChannels && !readCarriesChannel(read, requireChannels)) continue;
|
|
32559
|
+
if (firstRead === null) firstRead = read;
|
|
32560
|
+
if (now2 != null) {
|
|
32561
|
+
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
32562
|
+
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return read;
|
|
32563
|
+
}
|
|
32564
|
+
}
|
|
32565
|
+
}
|
|
32566
|
+
return firstRead;
|
|
32567
|
+
}
|
|
32568
|
+
function hasNonHoldTweenForElement(iframe, selector, compositionId, channels) {
|
|
32569
|
+
let targetEl = null;
|
|
32570
|
+
try {
|
|
32571
|
+
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
32572
|
+
} catch {
|
|
32573
|
+
return false;
|
|
32574
|
+
}
|
|
32575
|
+
return !!targetEl && hasNonHoldTween(timelinesOf(iframe), targetEl, channels, compositionId);
|
|
32576
|
+
}
|
|
32577
|
+
var POSITION_CHANNELS = [
|
|
32578
|
+
"x",
|
|
32579
|
+
"y",
|
|
32580
|
+
"xPercent",
|
|
32581
|
+
"yPercent",
|
|
32582
|
+
"left",
|
|
32583
|
+
"top",
|
|
32584
|
+
// readTween reads the authored translateX/Y; GSAP normalizes them to x/y only at play time.
|
|
32585
|
+
"translateX",
|
|
32586
|
+
"translateY"
|
|
32587
|
+
];
|
|
32588
|
+
var MOVE_CHANNELS = [...POSITION_CHANNELS, "motionPath"];
|
|
32589
|
+
function gsapWritesChannels(el, channels) {
|
|
32590
|
+
const win = el.ownerDocument.defaultView;
|
|
32591
|
+
return Object.values(win?.__timelines ?? {}).some(
|
|
32592
|
+
(tl) => (tl?.getChildren?.(true) ?? []).some(
|
|
32593
|
+
(tween) => !!tween.vars && matchesElement(tween, el) && (channels.some((ch) => ch in tween.vars) || keyframeVarsCarryChannel(tween.vars, channels))
|
|
32594
|
+
)
|
|
32595
|
+
);
|
|
32596
|
+
}
|
|
32597
|
+
function gsapWritesPosition(el) {
|
|
32598
|
+
const cache2 = el._gsap;
|
|
32599
|
+
return !!cache2?.renderTransform || gsapWritesChannels(el, MOVE_CHANNELS);
|
|
32600
|
+
}
|
|
32601
|
+
function elementHasNonHoldTween(el, channels) {
|
|
32602
|
+
const win = el.ownerDocument.defaultView;
|
|
32603
|
+
return hasNonHoldTween(win?.__timelines ?? null, el, channels);
|
|
32604
|
+
}
|
|
32605
|
+
function hasNonHoldTween(timelines, targetEl, channels, compositionId) {
|
|
32606
|
+
if (!timelines) return false;
|
|
32607
|
+
for (const tlId of compositionId ? [compositionId] : Object.keys(timelines)) {
|
|
32608
|
+
for (const tween of timelines[tlId]?.getChildren?.(true) ?? []) {
|
|
32609
|
+
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
32610
|
+
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
32611
|
+
if (isZeroDurationSet(dur)) continue;
|
|
32612
|
+
if (channels && keyframeVarsCarryChannel(tween.vars, channels)) return true;
|
|
32613
|
+
const read = readTween(tween.vars);
|
|
32614
|
+
if (read && (!channels || readCarriesChannel(read, channels))) return true;
|
|
32615
|
+
}
|
|
32616
|
+
}
|
|
32617
|
+
return false;
|
|
32618
|
+
}
|
|
32619
|
+
function toClipRelative(keyframes, tweenStart, tweenDuration, clip) {
|
|
32620
|
+
if (!clip || clip.duration <= 0) return keyframes;
|
|
32621
|
+
return keyframes.map((kf) => {
|
|
32622
|
+
const abs = toAbsoluteTime(tweenStart, tweenDuration, kf.percentage);
|
|
32623
|
+
return { ...kf, percentage: Math.round((abs - clip.start) / clip.duration * 1e5) / 1e3 };
|
|
32624
|
+
});
|
|
32625
|
+
}
|
|
32626
|
+
function buildEntry(read, start, duration, clip) {
|
|
32627
|
+
return {
|
|
32628
|
+
keyframes: toClipRelative(read.keyframes, start, duration, clip),
|
|
32629
|
+
tweenStart: start,
|
|
32630
|
+
tweenDuration: duration,
|
|
32631
|
+
...read.easeEach ? { easeEach: read.easeEach } : {},
|
|
32632
|
+
...read.arcPath ? { arcPath: read.arcPath } : {}
|
|
32633
|
+
};
|
|
32634
|
+
}
|
|
32635
|
+
function addScanEntry(result, tween, clipById) {
|
|
32636
|
+
if (!tween.targets || !tween.vars) return;
|
|
32637
|
+
const { start, duration } = tweenTiming(tween);
|
|
32638
|
+
if (isZeroDurationSet(duration)) return;
|
|
32639
|
+
const read = readTween(tween.vars);
|
|
32640
|
+
if (!read) return;
|
|
32641
|
+
for (const target of tween.targets()) {
|
|
32642
|
+
const id = target.id;
|
|
32643
|
+
if (id && !result.has(id)) result.set(id, buildEntry(read, start, duration, clipById?.get(id)));
|
|
32644
|
+
}
|
|
32645
|
+
}
|
|
32646
|
+
function scanAllRuntimeKeyframes(iframe, clipById) {
|
|
32647
|
+
const result = /* @__PURE__ */ new Map();
|
|
32648
|
+
const timelines = timelinesOf(iframe);
|
|
32649
|
+
if (!timelines) return result;
|
|
32650
|
+
for (const timeline of Object.values(timelines)) {
|
|
32651
|
+
if (!timeline?.getChildren) continue;
|
|
32652
|
+
for (const tween of timeline.getChildren(true)) addScanEntry(result, tween, clipById);
|
|
32653
|
+
}
|
|
32654
|
+
return result;
|
|
32655
|
+
}
|
|
32656
|
+
|
|
32657
|
+
// src/components/editor/plainTranslate.ts
|
|
32658
|
+
var TERM = /^(-?\d*\.?\d+(?:e[-+]?\d+)?)(px|%)$/i;
|
|
32659
|
+
var SIGN = { "+": 1, "-": -1 };
|
|
32660
|
+
function termPx(term, side) {
|
|
32661
|
+
const match = TERM.exec(term ?? "");
|
|
32662
|
+
return match ? Number(match[1]) * (match[2] === "%" ? side / 100 : 1) : null;
|
|
32663
|
+
}
|
|
32664
|
+
function resolveLength(value, side) {
|
|
32665
|
+
const parts = (/^calc\((.*)\)$/.exec(value)?.[1] ?? value).split(" ");
|
|
32666
|
+
if (parts.length % 2 === 0) return null;
|
|
32667
|
+
let total = termPx(parts[0], side);
|
|
32668
|
+
for (let i = 1; i < parts.length && total !== null; i += 2) {
|
|
32669
|
+
const term = termPx(parts[i + 1], side);
|
|
32670
|
+
const sign = SIGN[parts[i] ?? ""];
|
|
32671
|
+
total = term === null || !sign ? null : total + sign * term;
|
|
32672
|
+
}
|
|
32673
|
+
return total;
|
|
32674
|
+
}
|
|
32675
|
+
function borderBox(cs, size, a, b) {
|
|
32676
|
+
const n = (prop) => Number.parseFloat(cs.getPropertyValue(prop)) || 0;
|
|
32677
|
+
const pad = n(`padding-${a}`) + n(`padding-${b}`) + n(`border-${a}-width`) + n(`border-${b}-width`);
|
|
32678
|
+
return n(size) + (cs.boxSizing === "border-box" ? 0 : pad);
|
|
32679
|
+
}
|
|
32680
|
+
function resolveInTransform(el, x, y) {
|
|
32681
|
+
const style = el.style;
|
|
32682
|
+
const saved2 = [style.getPropertyValue("transform"), style.getPropertyPriority("transform")];
|
|
32683
|
+
style.setProperty("transform", `translate(${x}, ${y})`, "important");
|
|
32684
|
+
try {
|
|
32685
|
+
const resolved2 = el.ownerDocument.defaultView?.getComputedStyle(el).transform ?? "";
|
|
32686
|
+
const matrix = new DOMMatrixReadOnly(resolved2.startsWith("matrix") ? resolved2 : void 0);
|
|
32687
|
+
return { x: matrix.m41, y: matrix.m42 };
|
|
32688
|
+
} finally {
|
|
32689
|
+
style.setProperty("transform", saved2[0] ?? "", saved2[1] ?? "");
|
|
32690
|
+
}
|
|
32691
|
+
}
|
|
32692
|
+
function readTranslatePx(el) {
|
|
32693
|
+
const cs = el.ownerDocument.defaultView?.getComputedStyle(el);
|
|
32694
|
+
const value = el.style.getPropertyValue("translate") || cs?.translate || "none";
|
|
32695
|
+
if (value === "none") return { x: 0, y: 0 };
|
|
32696
|
+
const [x = "0px", y = "0px"] = splitTopLevelWhitespace(value);
|
|
32697
|
+
const px = cs && resolveLength(x, borderBox(cs, "width", "left", "right"));
|
|
32698
|
+
const py = cs && resolveLength(y, borderBox(cs, "height", "top", "bottom"));
|
|
32699
|
+
return px != null && py != null ? { x: px, y: py } : resolveInTransform(el, x, y);
|
|
32700
|
+
}
|
|
32701
|
+
function formatTranslatePx(p) {
|
|
32702
|
+
return `${roundTo3(p.x)}px ${roundTo3(p.y)}px`;
|
|
32703
|
+
}
|
|
32704
|
+
function translatePatch(p) {
|
|
32705
|
+
return { type: "inline-style", property: "translate", value: formatTranslatePx(p) };
|
|
32706
|
+
}
|
|
32707
|
+
function writeTranslatePx(el, p) {
|
|
32708
|
+
el.style.setProperty("translate", formatTranslatePx(p));
|
|
32709
|
+
}
|
|
32710
|
+
function readMoveOffset(el) {
|
|
32711
|
+
return gsapWritesPosition(el) ? readStudioPathOffset(el) : readTranslatePx(el);
|
|
32712
|
+
}
|
|
32713
|
+
|
|
32386
32714
|
// src/components/editor/manualOffsetDrag.ts
|
|
32387
32715
|
function getOffsetDragGsap(element) {
|
|
32388
32716
|
const win = element.ownerDocument.defaultView;
|
|
@@ -32494,14 +32822,15 @@ function measureManualOffsetDragScreenToOffsetMatrix(element, initialOffset, opt
|
|
|
32494
32822
|
if (!Number.isFinite(probeSize) || probeSize <= 0) {
|
|
32495
32823
|
return { ok: false, reason: "Invalid movement probe size." };
|
|
32496
32824
|
}
|
|
32825
|
+
const draw = options.plainTranslate ? writeTranslatePx : applyStudioPathOffsetDraft;
|
|
32497
32826
|
const snapshot3 = captureStudioPathOffset(element);
|
|
32498
32827
|
try {
|
|
32499
|
-
|
|
32828
|
+
draw(element, initialOffset);
|
|
32500
32829
|
const origin = getRectCenter(element);
|
|
32501
32830
|
if (!origin) {
|
|
32502
32831
|
return { ok: false, reason: "Element has no measurable box." };
|
|
32503
32832
|
}
|
|
32504
|
-
|
|
32833
|
+
draw(element, {
|
|
32505
32834
|
x: initialOffset.x + probeSize,
|
|
32506
32835
|
y: initialOffset.y
|
|
32507
32836
|
});
|
|
@@ -32509,7 +32838,7 @@ function measureManualOffsetDragScreenToOffsetMatrix(element, initialOffset, opt
|
|
|
32509
32838
|
if (!probeX) {
|
|
32510
32839
|
return { ok: false, reason: "Element X movement could not be measured." };
|
|
32511
32840
|
}
|
|
32512
|
-
|
|
32841
|
+
draw(element, {
|
|
32513
32842
|
x: initialOffset.x,
|
|
32514
32843
|
y: initialOffset.y + probeSize
|
|
32515
32844
|
});
|
|
@@ -32554,14 +32883,13 @@ function resolveManualOffsetForPointerDelta(input) {
|
|
|
32554
32883
|
};
|
|
32555
32884
|
}
|
|
32556
32885
|
function createManualOffsetDragMember(input) {
|
|
32557
|
-
const
|
|
32558
|
-
input.element
|
|
32559
|
-
input.element.setAttribute("data-hf-drag-initial-offset-y", String(initialOffset.y));
|
|
32886
|
+
const plainTranslate = !!input.gesture && !gsapWritesPosition(input.element);
|
|
32887
|
+
const initialOffset = plainTranslate ? readTranslatePx(input.element) : readAppliedStudioPathOffset(input.element);
|
|
32560
32888
|
const win = input.element.ownerDocument.defaultView;
|
|
32561
|
-
const gsapX = win?.gsap?.getProperty?.(input.element, "x") || 0;
|
|
32562
|
-
const gsapY = win?.gsap?.getProperty?.(input.element, "y") || 0;
|
|
32563
|
-
|
|
32564
|
-
input.element
|
|
32889
|
+
const gsapX = !plainTranslate && win?.gsap?.getProperty?.(input.element, "x") || 0;
|
|
32890
|
+
const gsapY = !plainTranslate && win?.gsap?.getProperty?.(input.element, "y") || 0;
|
|
32891
|
+
const baseGsap = { x: gsapX, y: gsapY };
|
|
32892
|
+
if (!plainTranslate) stampGestureBase(input.element, initialOffset, baseGsap);
|
|
32565
32893
|
if (win?.__timelines) {
|
|
32566
32894
|
const paused = [];
|
|
32567
32895
|
for (const [id, tl] of Object.entries(win.__timelines)) {
|
|
@@ -32581,9 +32909,9 @@ function createManualOffsetDragMember(input) {
|
|
|
32581
32909
|
const gestureToken = beginStudioManualEditGesture(input.element);
|
|
32582
32910
|
const measured = measureManualOffsetDragScreenToOffsetMatrix(input.element, initialOffset, {
|
|
32583
32911
|
scaleX: input.rect.editScaleX,
|
|
32584
|
-
scaleY: input.rect.editScaleY
|
|
32912
|
+
scaleY: input.rect.editScaleY,
|
|
32913
|
+
plainTranslate
|
|
32585
32914
|
});
|
|
32586
|
-
const baseGsap = { x: gsapX, y: gsapY };
|
|
32587
32915
|
if (!measured.ok) {
|
|
32588
32916
|
const scaleX = input.rect.editScaleX || 1;
|
|
32589
32917
|
const scaleY = input.rect.editScaleY || 1;
|
|
@@ -32595,6 +32923,7 @@ function createManualOffsetDragMember(input) {
|
|
|
32595
32923
|
selection: input.selection,
|
|
32596
32924
|
element: input.element,
|
|
32597
32925
|
initialOffset,
|
|
32926
|
+
plainTranslate,
|
|
32598
32927
|
baseGsap,
|
|
32599
32928
|
initialPathOffset,
|
|
32600
32929
|
gestureToken,
|
|
@@ -32610,6 +32939,7 @@ function createManualOffsetDragMember(input) {
|
|
|
32610
32939
|
selection: input.selection,
|
|
32611
32940
|
element: input.element,
|
|
32612
32941
|
initialOffset,
|
|
32942
|
+
plainTranslate,
|
|
32613
32943
|
baseGsap,
|
|
32614
32944
|
initialPathOffset,
|
|
32615
32945
|
gestureToken,
|
|
@@ -32626,24 +32956,27 @@ function resolveManualOffsetDragMemberOffset(member, dx, dy) {
|
|
|
32626
32956
|
dy
|
|
32627
32957
|
});
|
|
32628
32958
|
}
|
|
32959
|
+
function drawMemberOffset(member, offset, commit) {
|
|
32960
|
+
if (member.plainTranslate) writeTranslatePx(member.element, offset);
|
|
32961
|
+
else if (applyOffsetDragDraftViaGsap(member.element, offset, member.baseGsap)) return;
|
|
32962
|
+
else if (commit) applyStudioPathOffset(member.element, offset);
|
|
32963
|
+
else applyStudioPathOffsetDraft(member.element, offset);
|
|
32964
|
+
}
|
|
32629
32965
|
function applyManualOffsetDragDraft(member, dx, dy) {
|
|
32630
32966
|
const offset = resolveManualOffsetDragMemberOffset(member, dx, dy);
|
|
32631
|
-
|
|
32632
|
-
applyStudioPathOffsetDraft(member.element, offset);
|
|
32633
|
-
}
|
|
32967
|
+
drawMemberOffset(member, offset, false);
|
|
32634
32968
|
return offset;
|
|
32635
32969
|
}
|
|
32636
|
-
function
|
|
32637
|
-
|
|
32638
|
-
|
|
32639
|
-
|
|
32640
|
-
|
|
32970
|
+
function stampGestureBase(el, initialOffset, baseGsap) {
|
|
32971
|
+
el.setAttribute("data-hf-drag-gsap-base-x", String(baseGsap.x));
|
|
32972
|
+
el.setAttribute("data-hf-drag-gsap-base-y", String(baseGsap.y));
|
|
32973
|
+
el.setAttribute("data-hf-drag-initial-offset-x", String(initialOffset.x));
|
|
32974
|
+
el.setAttribute("data-hf-drag-initial-offset-y", String(initialOffset.y));
|
|
32641
32975
|
}
|
|
32642
32976
|
function applyManualOffsetCommitValue(member, offset) {
|
|
32643
|
-
|
|
32644
|
-
|
|
32645
|
-
|
|
32646
|
-
}
|
|
32977
|
+
if (!member.plainTranslate)
|
|
32978
|
+
stampGestureBase(member.element, member.initialOffset, member.baseGsap);
|
|
32979
|
+
drawMemberOffset(member, offset, true);
|
|
32647
32980
|
return offset;
|
|
32648
32981
|
}
|
|
32649
32982
|
function applyManualOffsetDragCommit(member, dx, dy) {
|
|
@@ -32654,9 +32987,7 @@ function applyManualOffsetNudgeDraft(member, delta) {
|
|
|
32654
32987
|
x: member.initialOffset.x + delta.x,
|
|
32655
32988
|
y: member.initialOffset.y + delta.y
|
|
32656
32989
|
};
|
|
32657
|
-
|
|
32658
|
-
applyStudioPathOffsetDraft(member.element, offset);
|
|
32659
|
-
}
|
|
32990
|
+
drawMemberOffset(member, offset, false);
|
|
32660
32991
|
return offset;
|
|
32661
32992
|
}
|
|
32662
32993
|
function applyManualOffsetNudgeCommit(member, delta) {
|
|
@@ -32667,7 +32998,9 @@ function applyManualOffsetNudgeCommit(member, delta) {
|
|
|
32667
32998
|
}
|
|
32668
32999
|
function restoreManualOffsetDragMember(member) {
|
|
32669
33000
|
restoreStudioPathOffset(member.element, member.initialPathOffset);
|
|
32670
|
-
|
|
33001
|
+
if (!member.plainTranslate) {
|
|
33002
|
+
getOffsetDragGsap(member.element)?.set(member.element, { ...member.baseGsap });
|
|
33003
|
+
}
|
|
32671
33004
|
endStudioManualEditGesture(member.element, member.gestureToken);
|
|
32672
33005
|
}
|
|
32673
33006
|
function restoreManualOffsetDragMembers(members) {
|
|
@@ -32692,7 +33025,7 @@ function endManualOffsetDragMembers(members) {
|
|
|
32692
33025
|
member.element.removeAttribute("data-hf-drag-initial-offset-y");
|
|
32693
33026
|
member.element.removeAttribute("data-hf-drag-gsap-base-x");
|
|
32694
33027
|
member.element.removeAttribute("data-hf-drag-gsap-base-y");
|
|
32695
|
-
const gsapOwnsPosition = Boolean(getOffsetDragGsap(member.element));
|
|
33028
|
+
const gsapOwnsPosition = !member.plainTranslate && Boolean(getOffsetDragGsap(member.element));
|
|
32696
33029
|
if (gsapOwnsPosition) clearStudioPathOffset(member.element);
|
|
32697
33030
|
settleDraftTranslate(member.element, gsapOwnsPosition);
|
|
32698
33031
|
resumeGsapTimelines(member.element);
|
|
@@ -33345,7 +33678,8 @@ function startGroupDrag(e, opts) {
|
|
|
33345
33678
|
key: item.key,
|
|
33346
33679
|
selection: item.selection,
|
|
33347
33680
|
element: item.element,
|
|
33348
|
-
rect: item.rect
|
|
33681
|
+
rect: item.rect,
|
|
33682
|
+
gesture: "drag"
|
|
33349
33683
|
});
|
|
33350
33684
|
if (!result.ok) {
|
|
33351
33685
|
restoreManualOffsetDragMembers(members);
|
|
@@ -33409,7 +33743,6 @@ function startGesture(kind, e, opts, options) {
|
|
|
33409
33743
|
if (kind === "resize" && (!Number.isFinite(rect.width) || !Number.isFinite(rect.height)))
|
|
33410
33744
|
return false;
|
|
33411
33745
|
const size = readStudioBoxSize(sel.element);
|
|
33412
|
-
const rotation = { angle: readGsapRotation(sel.element) + readStudioRotation(sel.element).angle };
|
|
33413
33746
|
const layoutWidth = sel.element.offsetWidth;
|
|
33414
33747
|
const layoutHeight = sel.element.offsetHeight;
|
|
33415
33748
|
const actualWidth = size.width > 0 ? size.width : layoutWidth > 0 ? layoutWidth : rect.width / rect.editScaleX;
|
|
@@ -33440,7 +33773,8 @@ function startGesture(kind, e, opts, options) {
|
|
|
33440
33773
|
key: selectionCacheKey(sel),
|
|
33441
33774
|
selection: sel,
|
|
33442
33775
|
element: sel.element,
|
|
33443
|
-
rect
|
|
33776
|
+
rect,
|
|
33777
|
+
gesture: "drag"
|
|
33444
33778
|
});
|
|
33445
33779
|
if (!result.ok) {
|
|
33446
33780
|
opts.onBlockedMoveRef.current(result.selection);
|
|
@@ -33469,6 +33803,8 @@ function startGesture(kind, e, opts, options) {
|
|
|
33469
33803
|
manualEditDragToken = beginStudioManualEditGesture(sel.element);
|
|
33470
33804
|
}
|
|
33471
33805
|
}
|
|
33806
|
+
const gsapRotation = pathOffsetMember?.plainTranslate ? 0 : readGsapRotation(sel.element);
|
|
33807
|
+
const rotation = { angle: gsapRotation + readStudioRotation(sel.element).angle };
|
|
33472
33808
|
const overlayBounds = overlayEl?.getBoundingClientRect();
|
|
33473
33809
|
const centerX = (overlayBounds?.left ?? 0) + rect.left + rect.width / 2;
|
|
33474
33810
|
const centerY = (overlayBounds?.top ?? 0) + rect.top + rect.height / 2;
|
|
@@ -34185,7 +34521,7 @@ function useDomEditNudge(params) {
|
|
|
34185
34521
|
if (!targets) return null;
|
|
34186
34522
|
const members = [];
|
|
34187
34523
|
for (const target of targets) {
|
|
34188
|
-
const result = createManualOffsetDragMember(target);
|
|
34524
|
+
const result = createManualOffsetDragMember({ ...target, gesture: "nudge" });
|
|
34189
34525
|
if (!result.ok) {
|
|
34190
34526
|
restoreManualOffsetDragMembers(members);
|
|
34191
34527
|
return null;
|
|
@@ -34375,253 +34711,6 @@ var SnapGuideOverlay = memo23(function SnapGuideOverlay2({
|
|
|
34375
34711
|
// src/components/editor/DomEditCropHandles.tsx
|
|
34376
34712
|
import { useEffect as useEffect44, useRef as useRef65, useState as useState40 } from "react";
|
|
34377
34713
|
|
|
34378
|
-
// src/hooks/gsapRuntimeKeyframes.ts
|
|
34379
|
-
import { buildArcPath } from "@hyperframes/core/gsap-parser-acorn";
|
|
34380
|
-
var FLAT_SKIP_KEYS = /* @__PURE__ */ new Set([
|
|
34381
|
-
"ease",
|
|
34382
|
-
"duration",
|
|
34383
|
-
"delay",
|
|
34384
|
-
"stagger",
|
|
34385
|
-
"motionPath",
|
|
34386
|
-
"overwrite",
|
|
34387
|
-
"immediateRender",
|
|
34388
|
-
"onComplete",
|
|
34389
|
-
"onUpdate",
|
|
34390
|
-
"onStart",
|
|
34391
|
-
"keyframes"
|
|
34392
|
-
]);
|
|
34393
|
-
function timelinesOf(iframe) {
|
|
34394
|
-
if (!iframe?.contentWindow) return null;
|
|
34395
|
-
try {
|
|
34396
|
-
return iframe.contentWindow.__timelines ?? null;
|
|
34397
|
-
} catch {
|
|
34398
|
-
return null;
|
|
34399
|
-
}
|
|
34400
|
-
}
|
|
34401
|
-
function isXY(p) {
|
|
34402
|
-
return !!p && typeof p.x === "number" && typeof p.y === "number";
|
|
34403
|
-
}
|
|
34404
|
-
function isZeroDurationSet(duration) {
|
|
34405
|
-
return !(duration > 0);
|
|
34406
|
-
}
|
|
34407
|
-
function coordsFromMotionPath(mp) {
|
|
34408
|
-
if (!mp || typeof mp !== "object") return null;
|
|
34409
|
-
const obj = mp;
|
|
34410
|
-
const pathVal = Array.isArray(mp) ? mp : obj.path;
|
|
34411
|
-
if (!Array.isArray(pathVal)) return null;
|
|
34412
|
-
const coords = pathVal.filter(isXY).map((p) => ({ x: p.x, y: p.y }));
|
|
34413
|
-
if (coords.length < 2) return null;
|
|
34414
|
-
const curviness = typeof obj.curviness === "number" ? obj.curviness : 1;
|
|
34415
|
-
const autoRotate = typeof obj.autoRotate === "number" ? obj.autoRotate : obj.autoRotate === true;
|
|
34416
|
-
return { coords, curviness, autoRotate, isCubic: obj.type === "cubic" };
|
|
34417
|
-
}
|
|
34418
|
-
function flatTweenKeyframes(vars) {
|
|
34419
|
-
const properties = {};
|
|
34420
|
-
for (const [k, v] of Object.entries(vars)) {
|
|
34421
|
-
if (FLAT_SKIP_KEYS.has(k)) continue;
|
|
34422
|
-
if (typeof v === "number") properties[k] = roundTo3(v);
|
|
34423
|
-
else if (typeof v === "string") properties[k] = v;
|
|
34424
|
-
}
|
|
34425
|
-
if (Object.keys(properties).length === 0) return null;
|
|
34426
|
-
return [
|
|
34427
|
-
{ percentage: 0, properties },
|
|
34428
|
-
{ percentage: 100, properties }
|
|
34429
|
-
];
|
|
34430
|
-
}
|
|
34431
|
-
function readTween(vars) {
|
|
34432
|
-
if (vars.keyframes && typeof vars.keyframes === "object") {
|
|
34433
|
-
const parsed = parsePercentageKeyframes(vars.keyframes);
|
|
34434
|
-
if (parsed) return parsed;
|
|
34435
|
-
}
|
|
34436
|
-
const mp = coordsFromMotionPath(vars.motionPath);
|
|
34437
|
-
if (mp) {
|
|
34438
|
-
const shape = buildArcPath(mp.coords, mp.curviness, mp.autoRotate, mp.isCubic);
|
|
34439
|
-
if (shape) {
|
|
34440
|
-
const n = shape.waypoints.length;
|
|
34441
|
-
const keyframes = shape.waypoints.map((wp, i) => ({
|
|
34442
|
-
percentage: n > 1 ? Math.round(i / (n - 1) * 100) : 0,
|
|
34443
|
-
properties: { x: wp.x, y: wp.y }
|
|
34444
|
-
}));
|
|
34445
|
-
return { keyframes, arcPath: shape.arcPath };
|
|
34446
|
-
}
|
|
34447
|
-
}
|
|
34448
|
-
const flat = flatTweenKeyframes(vars);
|
|
34449
|
-
return flat ? { keyframes: flat } : null;
|
|
34450
|
-
}
|
|
34451
|
-
function matchesElement(tween, el) {
|
|
34452
|
-
if (!tween.targets) return false;
|
|
34453
|
-
for (const t of tween.targets()) {
|
|
34454
|
-
if (t === el || el.id && t.id === el.id) return true;
|
|
34455
|
-
}
|
|
34456
|
-
return false;
|
|
34457
|
-
}
|
|
34458
|
-
function tweenTiming(tween) {
|
|
34459
|
-
const rawStart = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
34460
|
-
const rawDur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
34461
|
-
return {
|
|
34462
|
-
start: Number.isFinite(rawStart) ? rawStart : 0,
|
|
34463
|
-
duration: Number.isFinite(rawDur) ? rawDur : 0
|
|
34464
|
-
};
|
|
34465
|
-
}
|
|
34466
|
-
function varsCarryChannel(vars, channels) {
|
|
34467
|
-
if (!vars) return false;
|
|
34468
|
-
for (const ch of channels) {
|
|
34469
|
-
if (Object.prototype.hasOwnProperty.call(vars, ch)) return true;
|
|
34470
|
-
}
|
|
34471
|
-
return false;
|
|
34472
|
-
}
|
|
34473
|
-
function keyframeVarsCarryChannel(vars, channels) {
|
|
34474
|
-
const kf = vars?.keyframes;
|
|
34475
|
-
if (!kf || typeof kf !== "object") return false;
|
|
34476
|
-
if (!Array.isArray(kf) && channels.some((ch) => Object.prototype.hasOwnProperty.call(kf, ch)))
|
|
34477
|
-
return true;
|
|
34478
|
-
const steps = Array.isArray(kf) ? kf : Object.values(kf);
|
|
34479
|
-
return steps.some(
|
|
34480
|
-
(step) => step != null && typeof step === "object" && channels.some((ch) => Object.prototype.hasOwnProperty.call(step, ch))
|
|
34481
|
-
);
|
|
34482
|
-
}
|
|
34483
|
-
function resolveRuntimeTween(iframe, selector, kind, compositionId, channels) {
|
|
34484
|
-
const timelines = timelinesOf(iframe);
|
|
34485
|
-
if (!timelines) return null;
|
|
34486
|
-
let targetEl = null;
|
|
34487
|
-
try {
|
|
34488
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
34489
|
-
} catch {
|
|
34490
|
-
return null;
|
|
34491
|
-
}
|
|
34492
|
-
if (!targetEl) return null;
|
|
34493
|
-
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
34494
|
-
const wantChannels = channels && channels.length > 0 ? channels : null;
|
|
34495
|
-
let first = null;
|
|
34496
|
-
let channelMatch = null;
|
|
34497
|
-
for (const tlId of tlIds) {
|
|
34498
|
-
const timeline = timelines[tlId];
|
|
34499
|
-
if (!timeline?.getChildren) continue;
|
|
34500
|
-
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
34501
|
-
for (const tween of timeline.getChildren(true)) {
|
|
34502
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
34503
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
34504
|
-
const isSet = !(dur > 0);
|
|
34505
|
-
if (kind === "set" ? !isSet : isSet) continue;
|
|
34506
|
-
if (wantChannels) {
|
|
34507
|
-
const carries = kind === "set" ? varsCarryChannel(tween.vars, wantChannels) : keyframeVarsCarryChannel(tween.vars, wantChannels);
|
|
34508
|
-
if (carries) {
|
|
34509
|
-
if (channelMatch === null) channelMatch = { tween, timeline };
|
|
34510
|
-
} else if (first === null) {
|
|
34511
|
-
first = { tween, timeline };
|
|
34512
|
-
}
|
|
34513
|
-
continue;
|
|
34514
|
-
}
|
|
34515
|
-
if (first === null) first = { tween, timeline };
|
|
34516
|
-
if (kind === "keyframe" && now2 != null) {
|
|
34517
|
-
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
34518
|
-
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return { tween, timeline };
|
|
34519
|
-
}
|
|
34520
|
-
}
|
|
34521
|
-
}
|
|
34522
|
-
return channelMatch ?? first;
|
|
34523
|
-
}
|
|
34524
|
-
function readCarriesChannel(read, channels) {
|
|
34525
|
-
return read.keyframes.some((kf) => channels.some((c) => kf.properties[c] != null));
|
|
34526
|
-
}
|
|
34527
|
-
function readRuntimeKeyframes(iframe, selector, compositionId, requireChannels) {
|
|
34528
|
-
const timelines = timelinesOf(iframe);
|
|
34529
|
-
if (!timelines) return null;
|
|
34530
|
-
let targetEl = null;
|
|
34531
|
-
try {
|
|
34532
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
34533
|
-
} catch {
|
|
34534
|
-
return null;
|
|
34535
|
-
}
|
|
34536
|
-
if (!targetEl) return null;
|
|
34537
|
-
const tlIds = compositionId ? [compositionId] : Object.keys(timelines).filter((k) => typeof timelines[k]?.getChildren === "function");
|
|
34538
|
-
if (tlIds.length === 0) return null;
|
|
34539
|
-
let firstRead = null;
|
|
34540
|
-
for (const tlId of tlIds) {
|
|
34541
|
-
const timeline = timelines[tlId];
|
|
34542
|
-
if (!timeline?.getChildren) continue;
|
|
34543
|
-
const now2 = typeof timeline.time === "function" ? timeline.time() : null;
|
|
34544
|
-
for (const tween of timeline.getChildren(true)) {
|
|
34545
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
34546
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
34547
|
-
if (isZeroDurationSet(dur)) continue;
|
|
34548
|
-
const read = readTween(tween.vars);
|
|
34549
|
-
if (!read) continue;
|
|
34550
|
-
if (requireChannels && !readCarriesChannel(read, requireChannels)) continue;
|
|
34551
|
-
if (firstRead === null) firstRead = read;
|
|
34552
|
-
if (now2 != null) {
|
|
34553
|
-
const start = typeof tween.startTime === "function" ? tween.startTime() : 0;
|
|
34554
|
-
if (now2 >= start - 1e-3 && now2 <= start + dur + 1e-3) return read;
|
|
34555
|
-
}
|
|
34556
|
-
}
|
|
34557
|
-
}
|
|
34558
|
-
return firstRead;
|
|
34559
|
-
}
|
|
34560
|
-
function hasNonHoldTweenForElement(iframe, selector, compositionId, channels) {
|
|
34561
|
-
let targetEl = null;
|
|
34562
|
-
try {
|
|
34563
|
-
targetEl = iframe?.contentDocument?.querySelector(selector) ?? null;
|
|
34564
|
-
} catch {
|
|
34565
|
-
return false;
|
|
34566
|
-
}
|
|
34567
|
-
return !!targetEl && hasNonHoldTween(timelinesOf(iframe), targetEl, channels, compositionId);
|
|
34568
|
-
}
|
|
34569
|
-
function elementHasNonHoldTween(el, channels) {
|
|
34570
|
-
const win = el.ownerDocument.defaultView;
|
|
34571
|
-
return hasNonHoldTween(win?.__timelines ?? null, el, channels);
|
|
34572
|
-
}
|
|
34573
|
-
function hasNonHoldTween(timelines, targetEl, channels, compositionId) {
|
|
34574
|
-
if (!timelines) return false;
|
|
34575
|
-
for (const tlId of compositionId ? [compositionId] : Object.keys(timelines)) {
|
|
34576
|
-
for (const tween of timelines[tlId]?.getChildren?.(true) ?? []) {
|
|
34577
|
-
if (!tween.vars || !matchesElement(tween, targetEl)) continue;
|
|
34578
|
-
const dur = typeof tween.duration === "function" ? tween.duration() : 0;
|
|
34579
|
-
if (isZeroDurationSet(dur)) continue;
|
|
34580
|
-
if (channels && keyframeVarsCarryChannel(tween.vars, channels)) return true;
|
|
34581
|
-
const read = readTween(tween.vars);
|
|
34582
|
-
if (read && (!channels || readCarriesChannel(read, channels))) return true;
|
|
34583
|
-
}
|
|
34584
|
-
}
|
|
34585
|
-
return false;
|
|
34586
|
-
}
|
|
34587
|
-
function toClipRelative(keyframes, tweenStart, tweenDuration, clip) {
|
|
34588
|
-
if (!clip || clip.duration <= 0) return keyframes;
|
|
34589
|
-
return keyframes.map((kf) => {
|
|
34590
|
-
const abs = toAbsoluteTime(tweenStart, tweenDuration, kf.percentage);
|
|
34591
|
-
return { ...kf, percentage: Math.round((abs - clip.start) / clip.duration * 1e5) / 1e3 };
|
|
34592
|
-
});
|
|
34593
|
-
}
|
|
34594
|
-
function buildEntry(read, start, duration, clip) {
|
|
34595
|
-
return {
|
|
34596
|
-
keyframes: toClipRelative(read.keyframes, start, duration, clip),
|
|
34597
|
-
tweenStart: start,
|
|
34598
|
-
tweenDuration: duration,
|
|
34599
|
-
...read.easeEach ? { easeEach: read.easeEach } : {},
|
|
34600
|
-
...read.arcPath ? { arcPath: read.arcPath } : {}
|
|
34601
|
-
};
|
|
34602
|
-
}
|
|
34603
|
-
function addScanEntry(result, tween, clipById) {
|
|
34604
|
-
if (!tween.targets || !tween.vars) return;
|
|
34605
|
-
const { start, duration } = tweenTiming(tween);
|
|
34606
|
-
if (isZeroDurationSet(duration)) return;
|
|
34607
|
-
const read = readTween(tween.vars);
|
|
34608
|
-
if (!read) return;
|
|
34609
|
-
for (const target of tween.targets()) {
|
|
34610
|
-
const id = target.id;
|
|
34611
|
-
if (id && !result.has(id)) result.set(id, buildEntry(read, start, duration, clipById?.get(id)));
|
|
34612
|
-
}
|
|
34613
|
-
}
|
|
34614
|
-
function scanAllRuntimeKeyframes(iframe, clipById) {
|
|
34615
|
-
const result = /* @__PURE__ */ new Map();
|
|
34616
|
-
const timelines = timelinesOf(iframe);
|
|
34617
|
-
if (!timelines) return result;
|
|
34618
|
-
for (const timeline of Object.values(timelines)) {
|
|
34619
|
-
if (!timeline?.getChildren) continue;
|
|
34620
|
-
for (const tween of timeline.getChildren(true)) addScanEntry(result, tween, clipById);
|
|
34621
|
-
}
|
|
34622
|
-
return result;
|
|
34623
|
-
}
|
|
34624
|
-
|
|
34625
34714
|
// src/components/editor/cropResize.ts
|
|
34626
34715
|
var boxOf = (element) => ({
|
|
34627
34716
|
width: element.offsetWidth,
|
|
@@ -42384,19 +42473,6 @@ function getAnimationsForElement(animations, target, element) {
|
|
|
42384
42473
|
}
|
|
42385
42474
|
|
|
42386
42475
|
// src/hooks/gsapRuntimeBridge.ts
|
|
42387
|
-
var POSITION_CHANNELS = [
|
|
42388
|
-
"x",
|
|
42389
|
-
"y",
|
|
42390
|
-
"xPercent",
|
|
42391
|
-
"yPercent",
|
|
42392
|
-
"left",
|
|
42393
|
-
"top",
|
|
42394
|
-
// GSAP normalizes translateX/Y to x/y at play time, but readTween reads the
|
|
42395
|
-
// AUTHORED shape — include them so a hand-authored translateX/Y position tween
|
|
42396
|
-
// still counts as a live position tween.
|
|
42397
|
-
"translateX",
|
|
42398
|
-
"translateY"
|
|
42399
|
-
];
|
|
42400
42476
|
var POSITION_CHANNEL_SET = new Set(POSITION_CHANNELS);
|
|
42401
42477
|
var ROTATION_CHANNELS = ["rotation", "rotationX", "rotationY", "rotationZ"];
|
|
42402
42478
|
var ROTATION_CHANNEL_SET = new Set(ROTATION_CHANNELS);
|
|
@@ -47838,7 +47914,7 @@ function createTransformCommitHandlers({
|
|
|
47838
47914
|
"This element's position can't be edited here yet \u2014 it is driven by its animation"
|
|
47839
47915
|
))
|
|
47840
47916
|
return;
|
|
47841
|
-
const current =
|
|
47917
|
+
const current = readMoveOffset(element.element);
|
|
47842
47918
|
await Promise.resolve(
|
|
47843
47919
|
onSetManualOffset(element, {
|
|
47844
47920
|
x: axis === "x" ? parsed : current.x,
|
|
@@ -64921,7 +64997,7 @@ var PropertyPanel = memo36(function PropertyPanel2(props) {
|
|
|
64921
64997
|
const sourceLabel = element.id ? `#${element.id}` : element.selector ?? "";
|
|
64922
64998
|
const sections = resolveEditingSections(domEditSelectionToFacts(element, gsapAnimations.length));
|
|
64923
64999
|
const showEditableSections = element.capabilities.canEditStyles && sections.style;
|
|
64924
|
-
const manualOffset =
|
|
65000
|
+
const manualOffset = readMoveOffset(element.element);
|
|
64925
65001
|
const manualSize = readStudioBoxSize(element.element);
|
|
64926
65002
|
const resolvedWidth = manualSize.width > 0 ? manualSize.width : parsePxMetricValue(styles.width ?? "") ?? element.boundingBox.width;
|
|
64927
65003
|
const resolvedHeight = manualSize.height > 0 ? manualSize.height : parsePxMetricValue(styles.height ?? "") ?? element.boundingBox.height;
|
|
@@ -73716,10 +73792,6 @@ function canCommitInlineTextSelection(selection, element) {
|
|
|
73716
73792
|
if (selection.isCompositionHost || selection.isInsideLockedComposition) return false;
|
|
73717
73793
|
return canEditElementTextInline(element);
|
|
73718
73794
|
}
|
|
73719
|
-
function ownsCurrentPreviewElement(selection, element, document2) {
|
|
73720
|
-
if (!document2 || !element.isConnected) return false;
|
|
73721
|
-
return element === selection.element && element.ownerDocument === document2;
|
|
73722
|
-
}
|
|
73723
73795
|
async function resyncDomTextSelectionFromPreview(doc, selection, activeCompPath, buildDomSelectionFromTarget, applyDomSelection) {
|
|
73724
73796
|
if (!doc) return;
|
|
73725
73797
|
const refreshed = findElementForSelection(doc, selection, activeCompPath);
|
|
@@ -73742,6 +73814,8 @@ function useDomEditTextCommits({
|
|
|
73742
73814
|
}) {
|
|
73743
73815
|
const latestReadOnlyPreviewRef = useRef142(readOnlyPreview);
|
|
73744
73816
|
latestReadOnlyPreviewRef.current = readOnlyPreview;
|
|
73817
|
+
const latestSelectionRef = useRef142(domEditSelection);
|
|
73818
|
+
latestSelectionRef.current = domEditSelection;
|
|
73745
73819
|
const domTextCommitVersionRef = useRef142(/* @__PURE__ */ new Map());
|
|
73746
73820
|
const domStyleCommitVersionRef = useRef142(/* @__PURE__ */ new Map());
|
|
73747
73821
|
const {
|
|
@@ -73853,18 +73927,32 @@ function useDomEditTextCommits({
|
|
|
73853
73927
|
);
|
|
73854
73928
|
const handleDomRichTextCommit = useCallback123(
|
|
73855
73929
|
async ({ element, html: html2, previousHtml }) => {
|
|
73856
|
-
|
|
73857
|
-
if (latestReadOnlyPreviewRef.current) {
|
|
73930
|
+
const putBack = () => {
|
|
73858
73931
|
if (element.isConnected && element.innerHTML === html2) element.innerHTML = previousHtml;
|
|
73859
|
-
|
|
73932
|
+
};
|
|
73933
|
+
if (latestReadOnlyPreviewRef.current) return putBack();
|
|
73934
|
+
const refuse = (reason) => {
|
|
73935
|
+
console.error("[Studio] text edit not saved:", reason, element);
|
|
73936
|
+
showToast(`Couldn't save the text edit: ${reason}`, "error");
|
|
73937
|
+
putBack();
|
|
73938
|
+
};
|
|
73939
|
+
const doc = previewIframeRef.current?.contentDocument;
|
|
73940
|
+
if (!doc || !element.isConnected || element.ownerDocument !== doc) {
|
|
73941
|
+
return refuse("the text's element is gone from the preview");
|
|
73942
|
+
}
|
|
73943
|
+
const selection = await buildDomSelectionFromTarget(element, {
|
|
73944
|
+
exactTarget: true,
|
|
73945
|
+
skipSourceProbe: true
|
|
73946
|
+
});
|
|
73947
|
+
if (selection?.element !== element) {
|
|
73948
|
+
return refuse("this text was not found in the composition's source");
|
|
73949
|
+
}
|
|
73950
|
+
if (!canCommitInlineTextSelection(selection, element)) {
|
|
73951
|
+
return refuse("this text can't be edited in place");
|
|
73860
73952
|
}
|
|
73861
|
-
if (!canCommitInlineTextSelection(domEditSelection, element)) return;
|
|
73862
|
-
const iframe = previewIframeRef.current;
|
|
73863
|
-
const doc = iframe?.contentDocument;
|
|
73864
|
-
if (!ownsCurrentPreviewElement(domEditSelection, element, doc)) return;
|
|
73865
73953
|
const isLatestTextCommit = bumpDomEditCommitMapVersion(
|
|
73866
73954
|
domTextCommitVersionRef.current,
|
|
73867
|
-
getDomEditTargetKey(
|
|
73955
|
+
getDomEditTargetKey(selection)
|
|
73868
73956
|
);
|
|
73869
73957
|
const operations = [buildDomEditRichTextPatchOperation(html2)];
|
|
73870
73958
|
let appliedHtml = "";
|
|
@@ -73876,7 +73964,7 @@ function useDomEditTextCommits({
|
|
|
73876
73964
|
appliedHtml = element.innerHTML;
|
|
73877
73965
|
},
|
|
73878
73966
|
persist: async () => {
|
|
73879
|
-
await persistDomEditOperations(
|
|
73967
|
+
await persistDomEditOperations(selection, operations, {
|
|
73880
73968
|
label: "Edit text",
|
|
73881
73969
|
skipRefresh: true,
|
|
73882
73970
|
shouldSave: isLatestTextCommit
|
|
@@ -73888,11 +73976,12 @@ function useDomEditTextCommits({
|
|
|
73888
73976
|
element.innerHTML = previousHtml;
|
|
73889
73977
|
}
|
|
73890
73978
|
},
|
|
73891
|
-
onError: (error) => reportDomEditPersistFailure(
|
|
73892
|
-
|
|
73979
|
+
onError: (error) => reportDomEditPersistFailure(selection, operations, error, showToast),
|
|
73980
|
+
// Re-select only what is still selected: the selection may have moved on, or a host cleared it.
|
|
73981
|
+
shouldResync: () => isLatestTextCommit() && latestSelectionRef.current?.element === element,
|
|
73893
73982
|
resync: () => resyncDomTextSelectionFromPreview(
|
|
73894
73983
|
doc,
|
|
73895
|
-
|
|
73984
|
+
selection,
|
|
73896
73985
|
activeCompPath,
|
|
73897
73986
|
buildDomSelectionFromTarget,
|
|
73898
73987
|
applyDomSelection
|
|
@@ -73904,7 +73993,6 @@ function useDomEditTextCommits({
|
|
|
73904
73993
|
activeCompPath,
|
|
73905
73994
|
applyDomSelection,
|
|
73906
73995
|
buildDomSelectionFromTarget,
|
|
73907
|
-
domEditSelection,
|
|
73908
73996
|
persistDomEditOperations,
|
|
73909
73997
|
previewIframeRef,
|
|
73910
73998
|
showToast
|
|
@@ -74122,9 +74210,29 @@ function settleGsapDraftAtGestureStart(el) {
|
|
|
74122
74210
|
const y = Number.parseFloat(el.getAttribute("data-hf-drag-gsap-base-y") ?? "");
|
|
74123
74211
|
if (gsap3 && Number.isFinite(x) && Number.isFinite(y)) gsap3.set(el, { x, y });
|
|
74124
74212
|
}
|
|
74213
|
+
var plainMoveCounter = 0;
|
|
74214
|
+
function stagePlainTranslate(commitPositionPatchToHtml, selection, next, coalesceKey) {
|
|
74215
|
+
const style = selection.element.style;
|
|
74216
|
+
const before = style.getPropertyValue("translate");
|
|
74217
|
+
const patch = translatePatch(next);
|
|
74218
|
+
style.setProperty("translate", patch.value);
|
|
74219
|
+
const rollback = () => {
|
|
74220
|
+
if (style.getPropertyValue("translate") === patch.value) style.setProperty("translate", before);
|
|
74221
|
+
};
|
|
74222
|
+
const key2 = coalesceKey ?? `move:${++plainMoveCounter}`;
|
|
74223
|
+
const options = { label: "Move layer", coalesceKey: key2, coalesceMs: Number.POSITIVE_INFINITY };
|
|
74224
|
+
const save = () => commitPositionPatchToHtml(selection, [patch], options).catch((error) => {
|
|
74225
|
+
rollback();
|
|
74226
|
+
throw error;
|
|
74227
|
+
});
|
|
74228
|
+
return { save, rollback };
|
|
74229
|
+
}
|
|
74125
74230
|
function stageElementOffset({ commitPositionPatchToHtml, showToast, readOnlyPreview }, selection, next, coalesceKey) {
|
|
74126
74231
|
const el = selection.element;
|
|
74127
74232
|
if (readOnlyPreview) return { save: () => Promise.resolve(), rollback: () => void 0 };
|
|
74233
|
+
if (!gsapWritesPosition(el)) {
|
|
74234
|
+
return stagePlainTranslate(commitPositionPatchToHtml, selection, next, coalesceKey);
|
|
74235
|
+
}
|
|
74128
74236
|
const previous = { position: el.style.position, left: el.style.left, top: el.style.top };
|
|
74129
74237
|
const liftMarker = el.getAttribute(LAYER_REVEAL_PRIOR_POSITION_ATTR);
|
|
74130
74238
|
const result = applyElementPositionOffset(el, next);
|
|
@@ -77602,6 +77710,8 @@ function useGsapAwareEditing({
|
|
|
77602
77710
|
);
|
|
77603
77711
|
const handleGsapAwarePathOffsetCommit = useCallback138(
|
|
77604
77712
|
async (selection, next, modifiers) => {
|
|
77713
|
+
if (!gsapWritesPosition(selection.element))
|
|
77714
|
+
return stageElementPositionOffset(selection, next).save();
|
|
77605
77715
|
if (gsapCommitMutation) {
|
|
77606
77716
|
try {
|
|
77607
77717
|
const ownedAnimations = getGsapAnimationsForSelection(selection);
|
|
@@ -77667,6 +77777,7 @@ function useGsapAwareEditing({
|
|
|
77667
77777
|
const offsetMembers = /* @__PURE__ */ new Set();
|
|
77668
77778
|
const preflightResults = await Promise.allSettled(
|
|
77669
77779
|
updates.map(async ({ selection }) => {
|
|
77780
|
+
if (!gsapWritesPosition(selection.element)) return void offsetMembers.add(selection);
|
|
77670
77781
|
const animations = await makeFetchFallback(selection, { failOnFetchError: true })();
|
|
77671
77782
|
preflightAnimations.set(selection, animations);
|
|
77672
77783
|
const outcome = await tryGsapDragIntercept(
|