hyperframes 0.7.52 → 0.7.54
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/cli.js +612 -219
- package/dist/commands/layout-audit.browser.js +82 -7
- package/dist/hyperframe-runtime.js +22 -22
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +22 -22
- package/dist/studio/assets/{index-DKcziwpY.js → index-CMHYjEZ5.js} +1 -1
- package/dist/studio/assets/index-pRhCpGPz.js +423 -0
- package/dist/studio/assets/{index-B27HFK8R.js → index-uBY329wb.js} +1 -1
- package/dist/studio/{chunk-BA66NM4L.js → chunk-SOTCF4DF.js} +4 -2
- package/dist/studio/chunk-SOTCF4DF.js.map +1 -0
- package/dist/studio/{domEditingLayers-H7LDFIJ7.js → domEditingLayers-2ECJK24D.js} +2 -2
- package/dist/studio/index.html +1 -1
- package/dist/studio/index.js +669 -338
- package/dist/studio/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/studio/assets/index-v3DXednk.js +0 -423
- package/dist/studio/chunk-BA66NM4L.js.map +0 -1
- /package/dist/studio/{domEditingLayers-H7LDFIJ7.js.map → domEditingLayers-2ECJK24D.js.map} +0 -0
package/dist/studio/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveDomEditSelection,
|
|
21
21
|
serializeDomEditTextFields,
|
|
22
22
|
setCompositionSourceMap
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-SOTCF4DF.js";
|
|
24
24
|
|
|
25
25
|
// src/components/nle/NLELayout.tsx
|
|
26
26
|
import {
|
|
@@ -12319,6 +12319,19 @@ function getTimelineToggleTitle(timelineVisible) {
|
|
|
12319
12319
|
return `${timelineVisible ? "Hide" : "Show"} timeline editor (${TIMELINE_TOGGLE_SHORTCUT_LABEL})`;
|
|
12320
12320
|
}
|
|
12321
12321
|
|
|
12322
|
+
// src/utils/gsapSoftReload.ts
|
|
12323
|
+
import { COLOR_GRADING_SOURCE_HIDDEN_ATTR } from "@hyperframes/core/color-grading";
|
|
12324
|
+
|
|
12325
|
+
// src/utils/authoredOpacity.ts
|
|
12326
|
+
import { COLOR_GRADING_AUTHORED_OPACITY_ATTR } from "@hyperframes/core/color-grading";
|
|
12327
|
+
function readStampedAuthoredOpacity(element) {
|
|
12328
|
+
return element.getAttribute(COLOR_GRADING_AUTHORED_OPACITY_ATTR);
|
|
12329
|
+
}
|
|
12330
|
+
function applyAuthoredInlineOpacity(style, authored) {
|
|
12331
|
+
if (authored === "") style.removeProperty("opacity");
|
|
12332
|
+
else style.setProperty("opacity", authored);
|
|
12333
|
+
}
|
|
12334
|
+
|
|
12322
12335
|
// src/utils/gsapSoftReload.ts
|
|
12323
12336
|
var MOTION_PATH_PLUGIN_CDN = "https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/MotionPathPlugin.min.js";
|
|
12324
12337
|
function ensureMotionPathPluginLoaded(iframe) {
|
|
@@ -12379,7 +12392,8 @@ function verifyTimelinesPopulated(win, targetKeys) {
|
|
|
12379
12392
|
}
|
|
12380
12393
|
return Object.keys(timelines).filter((k) => k !== "__proxied").length > 0;
|
|
12381
12394
|
}
|
|
12382
|
-
function applySoftReload(iframe, scriptText,
|
|
12395
|
+
function applySoftReload(iframe, scriptText, options = {}) {
|
|
12396
|
+
const { onAsyncFailure, currentTimeOverride, authoredHtml } = options;
|
|
12383
12397
|
if (!iframe || !scriptText) return "cannot-soft-reload";
|
|
12384
12398
|
const win = iframe.contentWindow;
|
|
12385
12399
|
const doc = iframe.contentDocument;
|
|
@@ -12398,6 +12412,25 @@ function applySoftReload(iframe, scriptText, onAsyncFailure, currentTimeOverride
|
|
|
12398
12412
|
if (gsapScripts.length > 1 && staleScripts.length === 0) return "cannot-soft-reload";
|
|
12399
12413
|
const currentTime = currentTimeOverride ?? win.__player?.getTime?.() ?? 0;
|
|
12400
12414
|
let deferredToAsync = false;
|
|
12415
|
+
let authoredDoc;
|
|
12416
|
+
const findAuthoredSource = (el) => {
|
|
12417
|
+
if (authoredDoc === void 0) {
|
|
12418
|
+
try {
|
|
12419
|
+
authoredDoc = authoredHtml ? new DOMParser().parseFromString(authoredHtml, "text/html") : null;
|
|
12420
|
+
} catch {
|
|
12421
|
+
authoredDoc = null;
|
|
12422
|
+
}
|
|
12423
|
+
}
|
|
12424
|
+
if (!authoredDoc) return null;
|
|
12425
|
+
const hfId = el.getAttribute("data-hf-id");
|
|
12426
|
+
if (hfId) return authoredDoc.querySelector(`[data-hf-id="${hfId}"]`);
|
|
12427
|
+
return el.id ? authoredDoc.getElementById(el.id) : null;
|
|
12428
|
+
};
|
|
12429
|
+
const readAuthoredOpacity = (el) => {
|
|
12430
|
+
const source = findAuthoredSource(el);
|
|
12431
|
+
if (source instanceof HTMLElement) return source.style.opacity;
|
|
12432
|
+
return readStampedAuthoredOpacity(el);
|
|
12433
|
+
};
|
|
12401
12434
|
const doReload = () => {
|
|
12402
12435
|
const timelines = win.__timelines;
|
|
12403
12436
|
const allTargets = [];
|
|
@@ -12432,8 +12465,8 @@ function applySoftReload(iframe, scriptText, onAsyncFailure, currentTimeOverride
|
|
|
12432
12465
|
if (allTargets.length > 0 && win.gsap?.set) {
|
|
12433
12466
|
const saved = [];
|
|
12434
12467
|
for (const el of allTargets) {
|
|
12435
|
-
const
|
|
12436
|
-
if (
|
|
12468
|
+
const styled = el;
|
|
12469
|
+
if (styled.style?.cssText != null) saved.push([styled, styled.style.cssText]);
|
|
12437
12470
|
}
|
|
12438
12471
|
try {
|
|
12439
12472
|
win.gsap.set(allTargets, { clearProps: "all" });
|
|
@@ -12441,9 +12474,14 @@ function applySoftReload(iframe, scriptText, onAsyncFailure, currentTimeOverride
|
|
|
12441
12474
|
}
|
|
12442
12475
|
for (const [el, css2] of saved) {
|
|
12443
12476
|
const s = el.style;
|
|
12444
|
-
if (!s) continue;
|
|
12445
12477
|
s.cssText = css2;
|
|
12446
12478
|
s.removeProperty("transform");
|
|
12479
|
+
const authored = readAuthoredOpacity(el);
|
|
12480
|
+
if (authored !== null) {
|
|
12481
|
+
applyAuthoredInlineOpacity(s, authored);
|
|
12482
|
+
} else if (el.hasAttribute(COLOR_GRADING_SOURCE_HIDDEN_ATTR) && s.getPropertyValue("opacity") === "0" && s.getPropertyPriority("opacity") === "important") {
|
|
12483
|
+
s.removeProperty("opacity");
|
|
12484
|
+
}
|
|
12447
12485
|
}
|
|
12448
12486
|
}
|
|
12449
12487
|
for (const script of staleScripts) script.remove();
|
|
@@ -31263,6 +31301,22 @@ function seekToCurrent(iframe, timeline) {
|
|
|
31263
31301
|
const currentTime = typeof player?.getTime === "function" ? player.getTime() : typeof timeline.time === "function" ? timeline.time() : 0;
|
|
31264
31302
|
player?.seek?.(Number.isFinite(currentTime) ? currentTime : 0);
|
|
31265
31303
|
}
|
|
31304
|
+
function changeTouchesOpacity(change) {
|
|
31305
|
+
if (change.kind === "set" || change.kind === "global-set")
|
|
31306
|
+
return change.props.opacity !== void 0;
|
|
31307
|
+
if (change.kind === "keyframes") return change.keyframes.some((step) => "opacity" in step);
|
|
31308
|
+
return "opacity" in change.props;
|
|
31309
|
+
}
|
|
31310
|
+
function restoreAuthoredOpacityForCapture(tween) {
|
|
31311
|
+
const targets = typeof tween.targets === "function" ? tween.targets() : [];
|
|
31312
|
+
for (const target of targets ?? []) {
|
|
31313
|
+
const el = target;
|
|
31314
|
+
if (!el?.style || typeof el.getAttribute !== "function") continue;
|
|
31315
|
+
const authored = readStampedAuthoredOpacity(el);
|
|
31316
|
+
if (authored === null) continue;
|
|
31317
|
+
applyAuthoredInlineOpacity(el.style, authored);
|
|
31318
|
+
}
|
|
31319
|
+
}
|
|
31266
31320
|
function applyChange(tween, change) {
|
|
31267
31321
|
if (change.kind === "set") return patchSet(tween, change.props);
|
|
31268
31322
|
if (change.kind === "keyframes") return patchKeyframes(tween, change.keyframes);
|
|
@@ -31283,10 +31337,10 @@ function patchRuntimeTweenInPlace(iframe, selector, change, compositionId) {
|
|
|
31283
31337
|
);
|
|
31284
31338
|
if (!resolved) return false;
|
|
31285
31339
|
const { tween, timeline } = resolved;
|
|
31340
|
+
if (changeTouchesOpacity(change)) restoreAuthoredOpacityForCapture(tween);
|
|
31286
31341
|
if (!applyChange(tween, change)) return false;
|
|
31287
31342
|
if (change.kind !== "keyframe-rebuild") {
|
|
31288
31343
|
tween.invalidate?.();
|
|
31289
|
-
timeline.invalidate?.();
|
|
31290
31344
|
}
|
|
31291
31345
|
seekToCurrent(iframe, timeline);
|
|
31292
31346
|
return true;
|
|
@@ -32167,9 +32221,13 @@ async function mutateGsapScript(projectId, sourceFile, mutation) {
|
|
|
32167
32221
|
if (!result.ok) throw new Error(`Failed to update GSAP in ${sourceFile}`);
|
|
32168
32222
|
return result;
|
|
32169
32223
|
}
|
|
32170
|
-
function softReloadOrEscalate(iframe, scriptText, reloadPreview, origin) {
|
|
32224
|
+
function softReloadOrEscalate(iframe, scriptText, reloadPreview, origin, authoredHtml) {
|
|
32171
32225
|
const currentTime = usePlayerStore.getState().currentTime;
|
|
32172
|
-
const result = applySoftReload(iframe, scriptText,
|
|
32226
|
+
const result = applySoftReload(iframe, scriptText, {
|
|
32227
|
+
onAsyncFailure: reloadPreview,
|
|
32228
|
+
currentTimeOverride: currentTime,
|
|
32229
|
+
authoredHtml
|
|
32230
|
+
});
|
|
32173
32231
|
if (result === "applied") return;
|
|
32174
32232
|
trackStudioEvent("gsap_soft_reload_outcome", {
|
|
32175
32233
|
origin,
|
|
@@ -32189,7 +32247,13 @@ function applyPreviewSync(iframe, result, options, reloadPreview) {
|
|
|
32189
32247
|
trackStudioEvent("gsap_instant_patch_fallback", { selector: options.instantPatch.selector });
|
|
32190
32248
|
}
|
|
32191
32249
|
if (options.softReload && result.scriptText) {
|
|
32192
|
-
softReloadOrEscalate(
|
|
32250
|
+
softReloadOrEscalate(
|
|
32251
|
+
iframe,
|
|
32252
|
+
result.scriptText,
|
|
32253
|
+
reloadPreview,
|
|
32254
|
+
"preview_sync",
|
|
32255
|
+
result.after ?? void 0
|
|
32256
|
+
);
|
|
32193
32257
|
} else {
|
|
32194
32258
|
reloadPreview();
|
|
32195
32259
|
}
|
|
@@ -32214,7 +32278,12 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
32214
32278
|
if (options.skipReload) return;
|
|
32215
32279
|
throw error;
|
|
32216
32280
|
}
|
|
32217
|
-
if (result.changed === false)
|
|
32281
|
+
if (result.changed === false) {
|
|
32282
|
+
if (!options.skipReload && options.instantPatch) {
|
|
32283
|
+
applyPreviewSync(previewIframeRef.current, result, options, reloadPreview);
|
|
32284
|
+
}
|
|
32285
|
+
return;
|
|
32286
|
+
}
|
|
32218
32287
|
domEditSaveTimestampRef.current = Date.now();
|
|
32219
32288
|
if (result.before != null && result.after != null) {
|
|
32220
32289
|
await editHistory.recordEdit({ label: options.label, kind: "manual", coalesceKey: options.coalesceKey, files: { [targetPath]: { before: result.before, after: result.after } } });
|
|
@@ -32241,7 +32310,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
32241
32310
|
(after) => {
|
|
32242
32311
|
const script = extractGsapScriptText(after);
|
|
32243
32312
|
if (script) {
|
|
32244
|
-
softReloadOrEscalate(previewIframeRef.current, script, reloadPreview, "sdk_refresh");
|
|
32313
|
+
softReloadOrEscalate(previewIframeRef.current, script, reloadPreview, "sdk_refresh", after);
|
|
32245
32314
|
} else {
|
|
32246
32315
|
reloadPreview();
|
|
32247
32316
|
}
|
|
@@ -32319,6 +32388,21 @@ import { isStudioHoldSet } from "@hyperframes/core/gsap-parser";
|
|
|
32319
32388
|
|
|
32320
32389
|
// src/hooks/gsapRuntimeReaders.ts
|
|
32321
32390
|
import { classifyPropertyGroup as classifyPropertyGroup2 } from "@hyperframes/core/gsap-parser";
|
|
32391
|
+
import {
|
|
32392
|
+
COLOR_GRADING_SOURCE_HIDDEN_ATTR as COLOR_GRADING_SOURCE_HIDDEN_ATTR2,
|
|
32393
|
+
HF_COLOR_GRADING_CANVAS_ID_PREFIX
|
|
32394
|
+
} from "@hyperframes/core/color-grading";
|
|
32395
|
+
function readLiveGsapValue(gsap2, el, prop) {
|
|
32396
|
+
if (prop === "opacity" && el.getAttribute(COLOR_GRADING_SOURCE_HIDDEN_ATTR2) != null && el.id) {
|
|
32397
|
+
const canvas = el.ownerDocument.getElementById(HF_COLOR_GRADING_CANVAS_ID_PREFIX + el.id);
|
|
32398
|
+
const win = el.ownerDocument.defaultView;
|
|
32399
|
+
if (canvas && win) {
|
|
32400
|
+
const val = Number(win.getComputedStyle(canvas).opacity);
|
|
32401
|
+
if (Number.isFinite(val)) return val;
|
|
32402
|
+
}
|
|
32403
|
+
}
|
|
32404
|
+
return Number(gsap2.getProperty(el, prop));
|
|
32405
|
+
}
|
|
32322
32406
|
function readGsapProperty(iframe, selector, prop) {
|
|
32323
32407
|
if (!selector) return null;
|
|
32324
32408
|
const gsap2 = getIframeGsap(iframe);
|
|
@@ -32326,7 +32410,7 @@ function readGsapProperty(iframe, selector, prop) {
|
|
|
32326
32410
|
const el = queryIframeElement(iframe, selector);
|
|
32327
32411
|
if (!el) return null;
|
|
32328
32412
|
try {
|
|
32329
|
-
const val =
|
|
32413
|
+
const val = readLiveGsapValue(gsap2, el, prop);
|
|
32330
32414
|
if (!Number.isFinite(val)) return null;
|
|
32331
32415
|
return POSITION_PROPS.has(prop) ? Math.round(val) : roundTo3(val);
|
|
32332
32416
|
} catch {
|
|
@@ -32376,13 +32460,10 @@ function readAllAnimatedProperties(iframe, selector, anim, group) {
|
|
|
32376
32460
|
} else {
|
|
32377
32461
|
for (const p of Object.keys(anim.properties)) propKeys.add(p);
|
|
32378
32462
|
}
|
|
32379
|
-
|
|
32380
|
-
|
|
32381
|
-
|
|
32382
|
-
|
|
32383
|
-
}
|
|
32384
|
-
for (const prop of propKeys) {
|
|
32385
|
-
const val = Number(gsap2.getProperty(el, prop));
|
|
32463
|
+
const inGroup = (p) => !group || classifyPropertyGroup2(p) === group;
|
|
32464
|
+
const groupedPropKeys = new Set([...propKeys].filter(inGroup));
|
|
32465
|
+
for (const prop of groupedPropKeys) {
|
|
32466
|
+
const val = readLiveGsapValue(gsap2, el, prop);
|
|
32386
32467
|
if (Number.isFinite(val)) {
|
|
32387
32468
|
result[prop] = POSITION_PROPS.has(prop) ? Math.round(val) : roundTo3(val);
|
|
32388
32469
|
}
|
|
@@ -32402,14 +32483,14 @@ function readAllAnimatedProperties(iframe, selector, anim, group) {
|
|
|
32402
32483
|
const vars = child.vars;
|
|
32403
32484
|
if (!vars) continue;
|
|
32404
32485
|
for (const k of Object.keys(vars)) {
|
|
32405
|
-
if (!GSAP_CONFIG_KEYS.has(k)) otherTweenProps.add(k);
|
|
32486
|
+
if (!GSAP_CONFIG_KEYS.has(k) && inGroup(k)) otherTweenProps.add(k);
|
|
32406
32487
|
}
|
|
32407
32488
|
}
|
|
32408
32489
|
}
|
|
32409
32490
|
}
|
|
32410
32491
|
} catch {
|
|
32411
32492
|
}
|
|
32412
|
-
for (const p of
|
|
32493
|
+
for (const p of groupedPropKeys) otherTweenProps.delete(p);
|
|
32413
32494
|
const UNIVERSAL_BASELINE = {
|
|
32414
32495
|
opacity: 1,
|
|
32415
32496
|
scale: 1,
|
|
@@ -32434,11 +32515,11 @@ function readAllAnimatedProperties(iframe, selector, anim, group) {
|
|
|
32434
32515
|
sepia: 0,
|
|
32435
32516
|
invert: 0
|
|
32436
32517
|
};
|
|
32437
|
-
const allTweenedProps = /* @__PURE__ */ new Set([...
|
|
32518
|
+
const allTweenedProps = /* @__PURE__ */ new Set([...groupedPropKeys, ...otherTweenProps]);
|
|
32438
32519
|
for (const [prop, defaultVal] of Object.entries(UNIVERSAL_BASELINE)) {
|
|
32439
32520
|
if (prop in result) continue;
|
|
32440
32521
|
if (!allTweenedProps.has(prop)) continue;
|
|
32441
|
-
const val =
|
|
32522
|
+
const val = readLiveGsapValue(gsap2, el, prop);
|
|
32442
32523
|
if (Number.isFinite(val) && Math.round(val * 1e3) !== Math.round(defaultVal * 1e3)) {
|
|
32443
32524
|
result[prop] = roundTo3(val);
|
|
32444
32525
|
}
|
|
@@ -32467,6 +32548,7 @@ function readAllAnimatedProperties(iframe, selector, anim, group) {
|
|
|
32467
32548
|
}
|
|
32468
32549
|
for (const prop of COMPUTED_BASELINE) {
|
|
32469
32550
|
if (prop in result) continue;
|
|
32551
|
+
if (!inGroup(prop)) continue;
|
|
32470
32552
|
if (otherTweenProps.has(prop)) continue;
|
|
32471
32553
|
const gsapVal = Number(gsap2.getProperty(el, prop));
|
|
32472
32554
|
if (!Number.isFinite(gsapVal)) continue;
|
|
@@ -33437,169 +33519,6 @@ async function tryGsapDragIntercept(selection, offset, animations, iframe, commi
|
|
|
33437
33519
|
}
|
|
33438
33520
|
return true;
|
|
33439
33521
|
}
|
|
33440
|
-
var IDENTITY_ONE_PROPS = /* @__PURE__ */ new Set(["opacity", "autoAlpha", "scale", "scaleX", "scaleY"]);
|
|
33441
|
-
function synthesizeIdentityProps(source) {
|
|
33442
|
-
const id = {};
|
|
33443
|
-
for (const [k, v] of Object.entries(source)) {
|
|
33444
|
-
if (typeof v === "number") id[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
33445
|
-
else id[k] = v;
|
|
33446
|
-
}
|
|
33447
|
-
return id;
|
|
33448
|
-
}
|
|
33449
|
-
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations) {
|
|
33450
|
-
const hasScaleGroup = animations.some((a) => a.propertyGroup === "scale");
|
|
33451
|
-
const resizeGroup = hasScaleGroup ? "scale" : "size";
|
|
33452
|
-
const resolved = await resolveGroupTween(
|
|
33453
|
-
resizeGroup,
|
|
33454
|
-
animations,
|
|
33455
|
-
selection,
|
|
33456
|
-
commitMutation,
|
|
33457
|
-
fetchFallbackAnimations
|
|
33458
|
-
);
|
|
33459
|
-
let anim = resolved?.anim ?? null;
|
|
33460
|
-
if (!anim || anim.method === "set") {
|
|
33461
|
-
const sel = selectorFromSelection(selection);
|
|
33462
|
-
if (!sel) return false;
|
|
33463
|
-
const sizeSet = anim?.method === "set" ? anim : findSizeSetAnimation(animations, sel);
|
|
33464
|
-
if (resizeGroup === "size") {
|
|
33465
|
-
const animatedTween = pickClosestToPlayhead(
|
|
33466
|
-
animations.filter((a) => a.method !== "set" && resolveTweenDuration(a) > 0)
|
|
33467
|
-
);
|
|
33468
|
-
if (animatedTween) {
|
|
33469
|
-
const handled = await commitKeyframedSizeFromResize(
|
|
33470
|
-
selection,
|
|
33471
|
-
size,
|
|
33472
|
-
sel,
|
|
33473
|
-
sizeSet,
|
|
33474
|
-
animatedTween,
|
|
33475
|
-
{ commitMutation, fetchAnimations: fetchFallbackAnimations }
|
|
33476
|
-
);
|
|
33477
|
-
if (handled) return true;
|
|
33478
|
-
}
|
|
33479
|
-
}
|
|
33480
|
-
await commitStaticGsapSize(selection, size, sel, sizeSet, {
|
|
33481
|
-
commitMutation,
|
|
33482
|
-
fetchAnimations: fetchFallbackAnimations
|
|
33483
|
-
});
|
|
33484
|
-
return true;
|
|
33485
|
-
}
|
|
33486
|
-
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
33487
|
-
const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim);
|
|
33488
|
-
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
33489
|
-
const coalesceKey = `gsap:resize:${anim.id}`;
|
|
33490
|
-
const selector = selectorFromSelection(selection);
|
|
33491
|
-
const runtimeProps = selector ? readAllAnimatedProperties(iframe, selector, anim) : {};
|
|
33492
|
-
let resizeProps;
|
|
33493
|
-
if (resizeGroup === "scale") {
|
|
33494
|
-
const el = iframe?.contentDocument?.querySelector(selector ?? "");
|
|
33495
|
-
const origW = Number.parseFloat(el?.getAttribute("data-hf-studio-original-width") ?? "");
|
|
33496
|
-
const cssW = Number.isFinite(origW) && origW > 0 ? origW : 200;
|
|
33497
|
-
const newScale = roundTo3(size.width / cssW);
|
|
33498
|
-
resizeProps = { scale: newScale };
|
|
33499
|
-
} else {
|
|
33500
|
-
resizeProps = {
|
|
33501
|
-
width: Math.round(size.width),
|
|
33502
|
-
height: Math.round(size.height)
|
|
33503
|
-
};
|
|
33504
|
-
}
|
|
33505
|
-
if (!usePlayerStore.getState().autoKeyframeEnabled) {
|
|
33506
|
-
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
33507
|
-
await commitWholePropertyOffset(
|
|
33508
|
-
selection,
|
|
33509
|
-
anim,
|
|
33510
|
-
resizeProps,
|
|
33511
|
-
pct,
|
|
33512
|
-
iframe,
|
|
33513
|
-
{ commitMutation, fetchAnimations: fetchFallbackAnimations },
|
|
33514
|
-
"Resize animation"
|
|
33515
|
-
);
|
|
33516
|
-
return true;
|
|
33517
|
-
}
|
|
33518
|
-
const ct = usePlayerStore.getState().currentTime;
|
|
33519
|
-
const ts = resolveTweenStart(anim);
|
|
33520
|
-
const td = resolveTweenDuration(anim);
|
|
33521
|
-
const outsideRange = ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01);
|
|
33522
|
-
if (!outsideRange) {
|
|
33523
|
-
if (anim.hasUnresolvedKeyframes || anim.hasUnresolvedSelector) {
|
|
33524
|
-
const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection);
|
|
33525
|
-
if (newId) anim = { ...anim, id: newId };
|
|
33526
|
-
} else if (!anim.keyframes) {
|
|
33527
|
-
const resolvedFromValues = selector ? readAllAnimatedProperties(iframe, selector, anim) : void 0;
|
|
33528
|
-
await commitMutation(
|
|
33529
|
-
selection,
|
|
33530
|
-
{ type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues },
|
|
33531
|
-
{ label: "Convert to keyframes for resize", skipReload: true, coalesceKey }
|
|
33532
|
-
);
|
|
33533
|
-
if (fetchFallbackAnimations) {
|
|
33534
|
-
const fresh = await fetchFallbackAnimations();
|
|
33535
|
-
const refreshed = fresh.find(
|
|
33536
|
-
(a) => a.targetSelector === anim.targetSelector && a.keyframes
|
|
33537
|
-
);
|
|
33538
|
-
if (refreshed) anim = refreshed;
|
|
33539
|
-
}
|
|
33540
|
-
}
|
|
33541
|
-
}
|
|
33542
|
-
if (outsideRange && ts !== null) {
|
|
33543
|
-
const kfs = anim.keyframes?.keyframes ?? (() => {
|
|
33544
|
-
const fromProps = anim.method === "from" || anim.method === "fromTo" ? { ...anim.properties } : synthesizeIdentityProps(anim.properties);
|
|
33545
|
-
const toProps = anim.method === "from" ? synthesizeIdentityProps(anim.properties) : { ...anim.properties };
|
|
33546
|
-
return [
|
|
33547
|
-
{ percentage: 0, properties: fromProps },
|
|
33548
|
-
{ percentage: 100, properties: toProps }
|
|
33549
|
-
];
|
|
33550
|
-
})();
|
|
33551
|
-
const newStart = Math.min(ct, ts);
|
|
33552
|
-
const newEnd = Math.max(ct, ts + td);
|
|
33553
|
-
const newDuration = Math.max(0.01, newEnd - newStart);
|
|
33554
|
-
const existingKfs = kfs;
|
|
33555
|
-
const remapped = [];
|
|
33556
|
-
for (const kf of existingKfs) {
|
|
33557
|
-
const absTime = ts + kf.percentage / 100 * td;
|
|
33558
|
-
const newPct = Math.round((absTime - newStart) / newDuration * 1e3) / 10;
|
|
33559
|
-
const props = { ...kf.properties };
|
|
33560
|
-
for (const k of Object.keys(resizeProps)) {
|
|
33561
|
-
if (k in props) continue;
|
|
33562
|
-
if (k === "width" || k === "height") continue;
|
|
33563
|
-
props[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
33564
|
-
}
|
|
33565
|
-
remapped.push({ percentage: newPct, properties: props });
|
|
33566
|
-
}
|
|
33567
|
-
const targetPct = Math.round((ct - newStart) / newDuration * 1e3) / 10;
|
|
33568
|
-
remapped.push({ percentage: targetPct, properties: resizeProps });
|
|
33569
|
-
remapped.sort((a, b) => a.percentage - b.percentage);
|
|
33570
|
-
await commitMutation(
|
|
33571
|
-
selection,
|
|
33572
|
-
{
|
|
33573
|
-
type: "replace-with-keyframes",
|
|
33574
|
-
animationId: anim.id,
|
|
33575
|
-
targetSelector: anim.targetSelector,
|
|
33576
|
-
position: roundTo3(newStart),
|
|
33577
|
-
duration: roundTo3(newDuration),
|
|
33578
|
-
keyframes: remapped
|
|
33579
|
-
},
|
|
33580
|
-
{ label: `Resize (extended to ${ct.toFixed(2)}s)`, softReload: true, coalesceKey }
|
|
33581
|
-
);
|
|
33582
|
-
return true;
|
|
33583
|
-
}
|
|
33584
|
-
const SIZE_PROPS = /* @__PURE__ */ new Set(["width", "height"]);
|
|
33585
|
-
const backfillDefaults = {};
|
|
33586
|
-
for (const k of Object.keys(runtimeProps)) {
|
|
33587
|
-
if (SIZE_PROPS.has(k)) continue;
|
|
33588
|
-
backfillDefaults[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
33589
|
-
}
|
|
33590
|
-
await commitMutation(
|
|
33591
|
-
selection,
|
|
33592
|
-
{
|
|
33593
|
-
type: "add-keyframe",
|
|
33594
|
-
animationId: anim.id,
|
|
33595
|
-
percentage: pct,
|
|
33596
|
-
properties: resizeProps,
|
|
33597
|
-
backfillDefaults
|
|
33598
|
-
},
|
|
33599
|
-
{ label: `Resize (keyframe ${pct}%)`, softReload: true, coalesceKey }
|
|
33600
|
-
);
|
|
33601
|
-
return true;
|
|
33602
|
-
}
|
|
33603
33522
|
async function tryGsapRotationIntercept(selection, angle, animations, iframe, commitMutation, fetchFallbackAnimations) {
|
|
33604
33523
|
const selector = selectorFromSelection(selection);
|
|
33605
33524
|
if (!selector) return false;
|
|
@@ -34558,6 +34477,256 @@ function useDomEditWiring({
|
|
|
34558
34477
|
// src/hooks/useGsapAwareEditing.ts
|
|
34559
34478
|
import { useCallback as useCallback72 } from "react";
|
|
34560
34479
|
|
|
34480
|
+
// src/utils/elementGsap.ts
|
|
34481
|
+
function gsapOf(element) {
|
|
34482
|
+
return element.ownerDocument.defaultView?.gsap;
|
|
34483
|
+
}
|
|
34484
|
+
function setElementGsapPosition(element, x, y) {
|
|
34485
|
+
const gsap2 = gsapOf(element);
|
|
34486
|
+
if (!gsap2?.set) return false;
|
|
34487
|
+
gsap2.set(element, { x, y });
|
|
34488
|
+
return true;
|
|
34489
|
+
}
|
|
34490
|
+
function readElementGsapNumber(element, prop) {
|
|
34491
|
+
const value = Number(gsapOf(element)?.getProperty?.(element, prop));
|
|
34492
|
+
return Number.isFinite(value) ? value : null;
|
|
34493
|
+
}
|
|
34494
|
+
|
|
34495
|
+
// src/hooks/gsapResizeIntercept.ts
|
|
34496
|
+
var IDENTITY_ONE_PROPS = /* @__PURE__ */ new Set(["opacity", "autoAlpha", "scale", "scaleX", "scaleY"]);
|
|
34497
|
+
function synthesizeIdentityProps(source) {
|
|
34498
|
+
const id = {};
|
|
34499
|
+
for (const [k, v] of Object.entries(source)) {
|
|
34500
|
+
if (typeof v === "number") id[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
34501
|
+
else id[k] = v;
|
|
34502
|
+
}
|
|
34503
|
+
return id;
|
|
34504
|
+
}
|
|
34505
|
+
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations) {
|
|
34506
|
+
const hasScaleGroup = animations.some((a) => a.propertyGroup === "scale");
|
|
34507
|
+
const resizeGroup = hasScaleGroup ? "scale" : "size";
|
|
34508
|
+
const resolved = await resolveGroupTween(
|
|
34509
|
+
resizeGroup,
|
|
34510
|
+
animations,
|
|
34511
|
+
selection,
|
|
34512
|
+
commitMutation,
|
|
34513
|
+
fetchFallbackAnimations
|
|
34514
|
+
);
|
|
34515
|
+
let anim = resolved?.anim ?? null;
|
|
34516
|
+
if (!anim || anim.method === "set") {
|
|
34517
|
+
const sel = selectorFromSelection(selection);
|
|
34518
|
+
if (!sel) return false;
|
|
34519
|
+
const sizeSet = anim?.method === "set" ? anim : findSizeSetAnimation(animations, sel);
|
|
34520
|
+
if (resizeGroup === "size") {
|
|
34521
|
+
const animatedTween = pickClosestToPlayhead(
|
|
34522
|
+
animations.filter((a) => a.method !== "set" && resolveTweenDuration(a) > 0)
|
|
34523
|
+
);
|
|
34524
|
+
if (animatedTween) {
|
|
34525
|
+
const handled = await commitKeyframedSizeFromResize(
|
|
34526
|
+
selection,
|
|
34527
|
+
size,
|
|
34528
|
+
sel,
|
|
34529
|
+
sizeSet,
|
|
34530
|
+
animatedTween,
|
|
34531
|
+
{ commitMutation, fetchAnimations: fetchFallbackAnimations }
|
|
34532
|
+
);
|
|
34533
|
+
if (handled) return true;
|
|
34534
|
+
}
|
|
34535
|
+
}
|
|
34536
|
+
await commitStaticGsapSize(selection, size, sel, sizeSet, {
|
|
34537
|
+
commitMutation,
|
|
34538
|
+
fetchAnimations: fetchFallbackAnimations
|
|
34539
|
+
});
|
|
34540
|
+
return true;
|
|
34541
|
+
}
|
|
34542
|
+
const { activeKeyframePct, setActiveKeyframePct } = usePlayerStore.getState();
|
|
34543
|
+
const pct = activeKeyframePct ?? computeCurrentPercentage(selection, anim);
|
|
34544
|
+
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
34545
|
+
const coalesceKey = `gsap:resize:${anim.id}`;
|
|
34546
|
+
const selector = selectorFromSelection(selection);
|
|
34547
|
+
const runtimeProps = selector ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) : {};
|
|
34548
|
+
let resizeProps;
|
|
34549
|
+
let scaleDraftEl = null;
|
|
34550
|
+
let scaleDraftDropPoint = null;
|
|
34551
|
+
let nonUniformScale = false;
|
|
34552
|
+
if (resizeGroup === "scale") {
|
|
34553
|
+
const el = iframe?.contentDocument?.querySelector(selector ?? "");
|
|
34554
|
+
const origW = Number.parseFloat(el?.getAttribute("data-hf-studio-original-width") ?? "");
|
|
34555
|
+
const origH = Number.parseFloat(el?.getAttribute("data-hf-studio-original-height") ?? "");
|
|
34556
|
+
const cssW = Number.isFinite(origW) && origW > 0 ? origW : 200;
|
|
34557
|
+
const cssH = Number.isFinite(origH) && origH > 0 ? origH : cssW;
|
|
34558
|
+
const rawLiveScaleX = readGsapProperty(iframe, selector ?? null, "scaleX") ?? 1;
|
|
34559
|
+
const rawLiveScaleY = readGsapProperty(iframe, selector ?? null, "scaleY") ?? 1;
|
|
34560
|
+
const liveScaleX = rawLiveScaleX > 0 ? rawLiveScaleX : 1;
|
|
34561
|
+
const liveScaleY = rawLiveScaleY > 0 ? rawLiveScaleY : 1;
|
|
34562
|
+
const newScaleX = roundTo3(size.width * liveScaleX / cssW);
|
|
34563
|
+
const newScaleY = roundTo3(size.height * liveScaleY / cssH);
|
|
34564
|
+
nonUniformScale = Math.abs(newScaleX - newScaleY) > 0.01;
|
|
34565
|
+
resizeProps = nonUniformScale ? { scaleX: newScaleX, scaleY: newScaleY } : { scale: newScaleX };
|
|
34566
|
+
scaleDraftEl = el;
|
|
34567
|
+
if (el) {
|
|
34568
|
+
const dropRect = el.getBoundingClientRect();
|
|
34569
|
+
scaleDraftDropPoint = { x: dropRect.x, y: dropRect.y };
|
|
34570
|
+
}
|
|
34571
|
+
} else {
|
|
34572
|
+
resizeProps = {
|
|
34573
|
+
width: Math.round(size.width),
|
|
34574
|
+
height: Math.round(size.height)
|
|
34575
|
+
};
|
|
34576
|
+
}
|
|
34577
|
+
const finalizeScaleResizeCommit = async () => {
|
|
34578
|
+
if (!scaleDraftEl) return;
|
|
34579
|
+
clearStudioBoxSize(scaleDraftEl);
|
|
34580
|
+
if (!scaleDraftDropPoint || !selector) return;
|
|
34581
|
+
const hasLivePositionTween = hasNonHoldTweenForElement(
|
|
34582
|
+
iframe,
|
|
34583
|
+
selector,
|
|
34584
|
+
void 0,
|
|
34585
|
+
POSITION_CHANNELS
|
|
34586
|
+
);
|
|
34587
|
+
if (hasLivePositionTween) {
|
|
34588
|
+
return;
|
|
34589
|
+
}
|
|
34590
|
+
const post = scaleDraftEl.getBoundingClientRect();
|
|
34591
|
+
const residual = { x: scaleDraftDropPoint.x - post.x, y: scaleDraftDropPoint.y - post.y };
|
|
34592
|
+
if (!Number.isFinite(residual.x) || !Number.isFinite(residual.y)) return;
|
|
34593
|
+
if (Math.abs(residual.x) < 0.5 && Math.abs(residual.y) < 0.5) return;
|
|
34594
|
+
const gsapPos = readGsapPositionFromIframe(iframe, selector) ?? { x: 0, y: 0 };
|
|
34595
|
+
const corrected = {
|
|
34596
|
+
x: Math.round(gsapPos.x + residual.x),
|
|
34597
|
+
y: Math.round(gsapPos.y + residual.y)
|
|
34598
|
+
};
|
|
34599
|
+
setElementGsapPosition(scaleDraftEl, corrected.x, corrected.y);
|
|
34600
|
+
const currentAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : resolved?.animations ?? animations;
|
|
34601
|
+
const existingSet = findExistingPositionWrite(currentAnimations, selector);
|
|
34602
|
+
await commitStaticGsapPosition(
|
|
34603
|
+
selection,
|
|
34604
|
+
{ x: corrected.x - gsapPos.x, y: corrected.y - gsapPos.y },
|
|
34605
|
+
gsapPos,
|
|
34606
|
+
selector,
|
|
34607
|
+
existingSet,
|
|
34608
|
+
{
|
|
34609
|
+
commitMutation,
|
|
34610
|
+
fetchAnimations: fetchFallbackAnimations
|
|
34611
|
+
}
|
|
34612
|
+
);
|
|
34613
|
+
};
|
|
34614
|
+
if (!usePlayerStore.getState().autoKeyframeEnabled) {
|
|
34615
|
+
if (activeKeyframePct != null) setActiveKeyframePct(null);
|
|
34616
|
+
await commitWholePropertyOffset(
|
|
34617
|
+
selection,
|
|
34618
|
+
anim,
|
|
34619
|
+
resizeProps,
|
|
34620
|
+
pct,
|
|
34621
|
+
iframe,
|
|
34622
|
+
{ commitMutation, fetchAnimations: fetchFallbackAnimations },
|
|
34623
|
+
"Resize animation"
|
|
34624
|
+
);
|
|
34625
|
+
await finalizeScaleResizeCommit();
|
|
34626
|
+
return true;
|
|
34627
|
+
}
|
|
34628
|
+
const ct = usePlayerStore.getState().currentTime;
|
|
34629
|
+
const ts = resolveTweenStart(anim);
|
|
34630
|
+
const td = resolveTweenDuration(anim);
|
|
34631
|
+
const outsideRange = ts !== null && td > 0 && (ct < ts - 0.01 || ct > ts + td + 0.01);
|
|
34632
|
+
if (!outsideRange) {
|
|
34633
|
+
if (anim.hasUnresolvedKeyframes || anim.hasUnresolvedSelector) {
|
|
34634
|
+
const newId = await materializeIfDynamic(anim, iframe, commitMutation, selection);
|
|
34635
|
+
if (newId) anim = { ...anim, id: newId };
|
|
34636
|
+
} else if (!anim.keyframes) {
|
|
34637
|
+
const resolvedFromValues = selector ? readAllAnimatedProperties(iframe, selector, anim, resizeGroup) : void 0;
|
|
34638
|
+
await commitMutation(
|
|
34639
|
+
selection,
|
|
34640
|
+
{ type: "convert-to-keyframes", animationId: anim.id, resolvedFromValues },
|
|
34641
|
+
{ label: "Convert to keyframes for resize", skipReload: true, coalesceKey }
|
|
34642
|
+
);
|
|
34643
|
+
if (fetchFallbackAnimations) {
|
|
34644
|
+
const fresh = await fetchFallbackAnimations();
|
|
34645
|
+
const refreshed = fresh.find(
|
|
34646
|
+
(a) => a.targetSelector === anim.targetSelector && a.keyframes
|
|
34647
|
+
);
|
|
34648
|
+
if (refreshed) anim = refreshed;
|
|
34649
|
+
}
|
|
34650
|
+
}
|
|
34651
|
+
}
|
|
34652
|
+
if ((outsideRange || nonUniformScale) && ts !== null) {
|
|
34653
|
+
const kfs = anim.keyframes?.keyframes ?? (() => {
|
|
34654
|
+
const fromProps = anim.method === "from" || anim.method === "fromTo" ? { ...anim.properties } : synthesizeIdentityProps(anim.properties);
|
|
34655
|
+
const toProps = anim.method === "from" ? synthesizeIdentityProps(anim.properties) : { ...anim.properties };
|
|
34656
|
+
return [
|
|
34657
|
+
{ percentage: 0, properties: fromProps },
|
|
34658
|
+
{ percentage: 100, properties: toProps }
|
|
34659
|
+
];
|
|
34660
|
+
})();
|
|
34661
|
+
const newStart = Math.min(ct, ts);
|
|
34662
|
+
const newEnd = Math.max(ct, ts + td);
|
|
34663
|
+
const newDuration = Math.max(0.01, newEnd - newStart);
|
|
34664
|
+
const existingKfs = kfs;
|
|
34665
|
+
const remapped = [];
|
|
34666
|
+
for (const kf of existingKfs) {
|
|
34667
|
+
const absTime = ts + kf.percentage / 100 * td;
|
|
34668
|
+
const newPct = Math.round((absTime - newStart) / newDuration * 1e3) / 10;
|
|
34669
|
+
const props = { ...kf.properties };
|
|
34670
|
+
if (nonUniformScale && "scale" in props) {
|
|
34671
|
+
const uniform = props.scale;
|
|
34672
|
+
if (typeof uniform === "number") {
|
|
34673
|
+
props.scaleX = uniform;
|
|
34674
|
+
props.scaleY = uniform;
|
|
34675
|
+
}
|
|
34676
|
+
delete props.scale;
|
|
34677
|
+
}
|
|
34678
|
+
for (const k of Object.keys(resizeProps)) {
|
|
34679
|
+
if (k in props) continue;
|
|
34680
|
+
if (k === "width" || k === "height") continue;
|
|
34681
|
+
props[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
34682
|
+
}
|
|
34683
|
+
remapped.push({ percentage: newPct, properties: props });
|
|
34684
|
+
}
|
|
34685
|
+
const targetPct = Math.round((ct - newStart) / newDuration * 1e3) / 10;
|
|
34686
|
+
const collidingKf = remapped.find((kf) => Math.abs(kf.percentage - targetPct) < 0.05);
|
|
34687
|
+
if (collidingKf) Object.assign(collidingKf.properties, resizeProps);
|
|
34688
|
+
else remapped.push({ percentage: targetPct, properties: resizeProps });
|
|
34689
|
+
remapped.sort((a, b) => a.percentage - b.percentage);
|
|
34690
|
+
await commitMutation(
|
|
34691
|
+
selection,
|
|
34692
|
+
{
|
|
34693
|
+
type: "replace-with-keyframes",
|
|
34694
|
+
animationId: anim.id,
|
|
34695
|
+
targetSelector: anim.targetSelector,
|
|
34696
|
+
position: roundTo3(newStart),
|
|
34697
|
+
duration: roundTo3(newDuration),
|
|
34698
|
+
keyframes: remapped
|
|
34699
|
+
},
|
|
34700
|
+
{
|
|
34701
|
+
label: outsideRange ? `Resize (extended to ${ct.toFixed(2)}s)` : `Resize (keyframe ${Math.round((ct - newStart) / newDuration * 1e3) / 10}%)`,
|
|
34702
|
+
softReload: true,
|
|
34703
|
+
coalesceKey
|
|
34704
|
+
}
|
|
34705
|
+
);
|
|
34706
|
+
await finalizeScaleResizeCommit();
|
|
34707
|
+
return true;
|
|
34708
|
+
}
|
|
34709
|
+
const SIZE_PROPS = /* @__PURE__ */ new Set(["width", "height"]);
|
|
34710
|
+
const backfillDefaults = {};
|
|
34711
|
+
for (const k of Object.keys(runtimeProps)) {
|
|
34712
|
+
if (SIZE_PROPS.has(k)) continue;
|
|
34713
|
+
backfillDefaults[k] = IDENTITY_ONE_PROPS.has(k) ? 1 : 0;
|
|
34714
|
+
}
|
|
34715
|
+
await commitMutation(
|
|
34716
|
+
selection,
|
|
34717
|
+
{
|
|
34718
|
+
type: "add-keyframe",
|
|
34719
|
+
animationId: anim.id,
|
|
34720
|
+
percentage: pct,
|
|
34721
|
+
properties: resizeProps,
|
|
34722
|
+
backfillDefaults
|
|
34723
|
+
},
|
|
34724
|
+
{ label: `Resize (keyframe ${pct}%)`, softReload: true, coalesceKey }
|
|
34725
|
+
);
|
|
34726
|
+
await finalizeScaleResizeCommit();
|
|
34727
|
+
return true;
|
|
34728
|
+
}
|
|
34729
|
+
|
|
34561
34730
|
// src/hooks/useAnimatedPropertyCommit.ts
|
|
34562
34731
|
import { useCallback as useCallback71 } from "react";
|
|
34563
34732
|
import { classifyPropertyGroup as classifyPropertyGroup3 } from "@hyperframes/core/gsap-parser";
|
|
@@ -34593,6 +34762,19 @@ async function maybeAutoKeyframeSet(selection, setAnim, animations, commit) {
|
|
|
34593
34762
|
{ label: "Keyframe 3D transform", softReload: true }
|
|
34594
34763
|
);
|
|
34595
34764
|
}
|
|
34765
|
+
var STATIC_SET_LABELS = {
|
|
34766
|
+
position: "Move layer",
|
|
34767
|
+
scale: "Resize layer",
|
|
34768
|
+
size: "Resize layer",
|
|
34769
|
+
rotation: "Rotate layer",
|
|
34770
|
+
visual: "Set opacity",
|
|
34771
|
+
other: "Set 3D transform"
|
|
34772
|
+
};
|
|
34773
|
+
function staticSetLabel(propEntries) {
|
|
34774
|
+
const groups = new Set(propEntries.map(([k]) => classifyPropertyGroup3(k)));
|
|
34775
|
+
const only = groups.size === 1 ? [...groups][0] : void 0;
|
|
34776
|
+
return only && STATIC_SET_LABELS[only] || "Set properties";
|
|
34777
|
+
}
|
|
34596
34778
|
async function commitSetProps(selection, setAnim, propEntries, selector, animations, commit) {
|
|
34597
34779
|
const properties = Object.fromEntries(propEntries);
|
|
34598
34780
|
const numericProps = {};
|
|
@@ -34609,19 +34791,47 @@ async function commitSetProps(selection, setAnim, propEntries, selector, animati
|
|
|
34609
34791
|
await commit(
|
|
34610
34792
|
selection,
|
|
34611
34793
|
{ type: "update-properties", animationId: setAnim.id, properties },
|
|
34612
|
-
{
|
|
34794
|
+
{
|
|
34795
|
+
label: staticSetLabel(propEntries),
|
|
34796
|
+
softReload: true,
|
|
34797
|
+
...instantPatch ? { instantPatch } : {}
|
|
34798
|
+
}
|
|
34613
34799
|
);
|
|
34614
34800
|
await maybeAutoKeyframeSet(selection, setAnim, animations, commit);
|
|
34615
34801
|
}
|
|
34616
34802
|
async function commitStaticSet(selection, propEntries, selector, animations, commit) {
|
|
34617
34803
|
if (!selector) return;
|
|
34618
|
-
const
|
|
34619
|
-
|
|
34620
|
-
|
|
34621
|
-
|
|
34804
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
34805
|
+
for (const entry of propEntries) {
|
|
34806
|
+
const group = classifyPropertyGroup3(entry[0]);
|
|
34807
|
+
const batch = byGroup.get(group) ?? [];
|
|
34808
|
+
batch.push(entry);
|
|
34809
|
+
byGroup.set(group, batch);
|
|
34810
|
+
}
|
|
34811
|
+
const sets = animations.filter((a) => a.method === "set" && a.targetSelector === selector);
|
|
34812
|
+
const byTargetSet = /* @__PURE__ */ new Map();
|
|
34813
|
+
const newSetBatches = [];
|
|
34814
|
+
for (const [group, batch] of byGroup) {
|
|
34815
|
+
const existingSet = findGroupOwningSet(sets, group);
|
|
34816
|
+
if (existingSet) {
|
|
34817
|
+
byTargetSet.set(existingSet, [...byTargetSet.get(existingSet) ?? [], ...batch]);
|
|
34818
|
+
} else {
|
|
34819
|
+
newSetBatches.push(batch);
|
|
34820
|
+
}
|
|
34821
|
+
}
|
|
34822
|
+
for (const [targetSet, batch] of byTargetSet) {
|
|
34823
|
+
await commitSetProps(selection, targetSet, batch, selector, animations, commit);
|
|
34622
34824
|
}
|
|
34825
|
+
for (const batch of newSetBatches) {
|
|
34826
|
+
await addGlobalStaticSet(selection, batch, selector, commit);
|
|
34827
|
+
}
|
|
34828
|
+
}
|
|
34829
|
+
function findGroupOwningSet(sets, group) {
|
|
34830
|
+
return sets.find((a) => a.propertyGroup === group) ?? sets.find((a) => Object.keys(a.properties).some((k) => classifyPropertyGroup3(k) === group));
|
|
34831
|
+
}
|
|
34832
|
+
async function addGlobalStaticSet(selection, batch, selector, commit) {
|
|
34623
34833
|
const numericProps = {};
|
|
34624
|
-
for (const [k, v] of
|
|
34834
|
+
for (const [k, v] of batch) {
|
|
34625
34835
|
if (typeof v === "number") numericProps[k] = v;
|
|
34626
34836
|
}
|
|
34627
34837
|
await commit(
|
|
@@ -34631,11 +34841,11 @@ async function commitStaticSet(selection, propEntries, selector, animations, com
|
|
|
34631
34841
|
targetSelector: selector,
|
|
34632
34842
|
method: "set",
|
|
34633
34843
|
position: 0,
|
|
34634
|
-
properties: Object.fromEntries(
|
|
34844
|
+
properties: Object.fromEntries(batch),
|
|
34635
34845
|
global: true
|
|
34636
34846
|
},
|
|
34637
34847
|
{
|
|
34638
|
-
label:
|
|
34848
|
+
label: staticSetLabel(batch),
|
|
34639
34849
|
softReload: true,
|
|
34640
34850
|
...Object.keys(numericProps).length > 0 ? {
|
|
34641
34851
|
instantPatch: {
|
|
@@ -42135,8 +42345,8 @@ function cropRectFromInsets(rect, insets, scaleX, scaleY) {
|
|
|
42135
42345
|
function readElementCropInsets(element) {
|
|
42136
42346
|
const inline = element.style.getPropertyValue("clip-path").trim();
|
|
42137
42347
|
const value = inline || element.ownerDocument.defaultView?.getComputedStyle(element).clipPath.trim() || "";
|
|
42138
|
-
|
|
42139
|
-
return
|
|
42348
|
+
if (!value || value === "none") return { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
42349
|
+
return parseInsetClipPathSides(value);
|
|
42140
42350
|
}
|
|
42141
42351
|
function clampInset(value, max) {
|
|
42142
42352
|
if (!Number.isFinite(value)) return 0;
|
|
@@ -42180,9 +42390,62 @@ function resolveCropInsetFromMoveDrag(input) {
|
|
|
42180
42390
|
}
|
|
42181
42391
|
function hugRectForElement(rect, element) {
|
|
42182
42392
|
const insets = readElementCropInsets(element);
|
|
42183
|
-
if (insets.top <= 0 && insets.right <= 0 && insets.bottom <= 0 && insets.left <= 0)
|
|
42393
|
+
if (!insets || insets.top <= 0 && insets.right <= 0 && insets.bottom <= 0 && insets.left <= 0)
|
|
42394
|
+
return rect;
|
|
42184
42395
|
return cropRectFromInsets(rect, insets, rect.editScaleX, rect.editScaleY);
|
|
42185
42396
|
}
|
|
42397
|
+
function readElementCropFrame(element, overlayRect) {
|
|
42398
|
+
const editX = overlayRect.editScaleX > 0 ? overlayRect.editScaleX : 1;
|
|
42399
|
+
const editY = overlayRect.editScaleY > 0 ? overlayRect.editScaleY : 1;
|
|
42400
|
+
const aabb = {
|
|
42401
|
+
angleDeg: 0,
|
|
42402
|
+
left: overlayRect.left,
|
|
42403
|
+
top: overlayRect.top,
|
|
42404
|
+
width: overlayRect.width,
|
|
42405
|
+
height: overlayRect.height,
|
|
42406
|
+
scaleX: editX,
|
|
42407
|
+
scaleY: editY
|
|
42408
|
+
};
|
|
42409
|
+
let transform = "";
|
|
42410
|
+
try {
|
|
42411
|
+
transform = element.ownerDocument.defaultView?.getComputedStyle(element).transform ?? "";
|
|
42412
|
+
} catch {
|
|
42413
|
+
return aabb;
|
|
42414
|
+
}
|
|
42415
|
+
if (!transform || transform === "none") return aabb;
|
|
42416
|
+
const m = /^matrix\(([^)]+)\)$/.exec(transform);
|
|
42417
|
+
if (!m) return aabb;
|
|
42418
|
+
const [a, b, c, d] = m[1].split(",").map((v) => Number.parseFloat(v));
|
|
42419
|
+
if (![a, b, c, d].every(Number.isFinite)) return aabb;
|
|
42420
|
+
const elScaleX = Math.hypot(a, b);
|
|
42421
|
+
const det = a * d - b * c;
|
|
42422
|
+
const elScaleY = elScaleX !== 0 ? det / elScaleX : 1;
|
|
42423
|
+
if (elScaleX <= 0 || elScaleY <= 0) return aabb;
|
|
42424
|
+
const angleDeg = Math.atan2(b, a) * 180 / Math.PI;
|
|
42425
|
+
const scaleX = elScaleX * editX;
|
|
42426
|
+
const scaleY = elScaleY * editY;
|
|
42427
|
+
const width = element.offsetWidth * scaleX;
|
|
42428
|
+
const height = element.offsetHeight * scaleY;
|
|
42429
|
+
if (!(width > 0) || !(height > 0)) return aabb;
|
|
42430
|
+
const cx = overlayRect.left + overlayRect.width / 2;
|
|
42431
|
+
const cy = overlayRect.top + overlayRect.height / 2;
|
|
42432
|
+
return {
|
|
42433
|
+
angleDeg,
|
|
42434
|
+
left: cx - width / 2,
|
|
42435
|
+
top: cy - height / 2,
|
|
42436
|
+
width,
|
|
42437
|
+
height,
|
|
42438
|
+
scaleX,
|
|
42439
|
+
scaleY
|
|
42440
|
+
};
|
|
42441
|
+
}
|
|
42442
|
+
function rotateDeltaIntoFrame(deltaX, deltaY, angleDeg) {
|
|
42443
|
+
if (angleDeg === 0) return { deltaX, deltaY };
|
|
42444
|
+
const rad = -angleDeg * Math.PI / 180;
|
|
42445
|
+
const cos = Math.cos(rad);
|
|
42446
|
+
const sin = Math.sin(rad);
|
|
42447
|
+
return { deltaX: deltaX * cos - deltaY * sin, deltaY: deltaX * sin + deltaY * cos };
|
|
42448
|
+
}
|
|
42186
42449
|
|
|
42187
42450
|
// src/components/editor/domEditOverlayGeometry.ts
|
|
42188
42451
|
function isElementVisibleForOverlay(el) {
|
|
@@ -42501,14 +42764,16 @@ function focusDomEditOverlayElement(element) {
|
|
|
42501
42764
|
function resolveDomEditResizeGesture(input) {
|
|
42502
42765
|
const scaleX = input.scaleX > 0 ? input.scaleX : 1;
|
|
42503
42766
|
const scaleY = input.scaleY > 0 ? input.scaleY : 1;
|
|
42767
|
+
const contentScaleX = input.contentScaleX !== void 0 && input.contentScaleX > 0 ? input.contentScaleX : 1;
|
|
42768
|
+
const contentScaleY = input.contentScaleY !== void 0 && input.contentScaleY > 0 ? input.contentScaleY : 1;
|
|
42504
42769
|
if (input.uniform) {
|
|
42505
|
-
const deltaX = input.dx / scaleX;
|
|
42506
|
-
const deltaY = input.dy / scaleY;
|
|
42770
|
+
const deltaX = input.dx / (scaleX * contentScaleX);
|
|
42771
|
+
const deltaY = input.dy / (scaleY * contentScaleY);
|
|
42507
42772
|
const delta = Math.abs(deltaX) >= Math.abs(deltaY) ? deltaX : deltaY;
|
|
42508
42773
|
const side = Math.max(1, Math.max(input.actualWidth, input.actualHeight) + delta);
|
|
42509
42774
|
return {
|
|
42510
|
-
overlayWidth: Math.max(MIN_RESIZE_EDGE_PX, side * scaleX),
|
|
42511
|
-
overlayHeight: Math.max(MIN_RESIZE_EDGE_PX, side * scaleY),
|
|
42775
|
+
overlayWidth: Math.max(MIN_RESIZE_EDGE_PX, side * scaleX * contentScaleX),
|
|
42776
|
+
overlayHeight: Math.max(MIN_RESIZE_EDGE_PX, side * scaleY * contentScaleY),
|
|
42512
42777
|
width: side,
|
|
42513
42778
|
height: side
|
|
42514
42779
|
};
|
|
@@ -42516,8 +42781,8 @@ function resolveDomEditResizeGesture(input) {
|
|
|
42516
42781
|
return {
|
|
42517
42782
|
overlayWidth: Math.max(MIN_RESIZE_EDGE_PX, input.originWidth + input.dx),
|
|
42518
42783
|
overlayHeight: Math.max(MIN_RESIZE_EDGE_PX, input.originHeight + input.dy),
|
|
42519
|
-
width: Math.max(1, input.actualWidth + input.dx / scaleX),
|
|
42520
|
-
height: Math.max(1, input.actualHeight + input.dy / scaleY)
|
|
42784
|
+
width: Math.max(1, input.actualWidth + input.dx / (scaleX * contentScaleX)),
|
|
42785
|
+
height: Math.max(1, input.actualHeight + input.dy / (scaleY * contentScaleY))
|
|
42521
42786
|
};
|
|
42522
42787
|
}
|
|
42523
42788
|
function pointerAngleDegrees(centerX, centerY, x, y) {
|
|
@@ -42769,7 +43034,7 @@ function OffCanvasIndicators({
|
|
|
42769
43034
|
const selectOffCanvas = async () => {
|
|
42770
43035
|
const el = elements.current.get(r.key);
|
|
42771
43036
|
if (!el) return;
|
|
42772
|
-
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-
|
|
43037
|
+
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-2ECJK24D.js");
|
|
42773
43038
|
const acp = activeCompositionPathRef.current ?? "index.html";
|
|
42774
43039
|
const sel = await resolveDomEditSelection2(el, {
|
|
42775
43040
|
activeCompositionPath: acp,
|
|
@@ -43584,8 +43849,26 @@ function startGesture(kind, e, opts, options) {
|
|
|
43584
43849
|
return false;
|
|
43585
43850
|
const size = readStudioBoxSize(sel.element);
|
|
43586
43851
|
const rotation = { angle: readGsapRotation(sel.element) + readStudioRotation(sel.element).angle };
|
|
43587
|
-
const
|
|
43588
|
-
const
|
|
43852
|
+
const layoutWidth = sel.element.offsetWidth;
|
|
43853
|
+
const layoutHeight = sel.element.offsetHeight;
|
|
43854
|
+
const actualWidth = size.width > 0 ? size.width : layoutWidth > 0 ? layoutWidth : rect.width / rect.editScaleX;
|
|
43855
|
+
const actualHeight = size.height > 0 ? size.height : layoutHeight > 0 ? layoutHeight : rect.height / rect.editScaleY;
|
|
43856
|
+
const rawContentScaleX = rect.width / (rect.editScaleX * actualWidth);
|
|
43857
|
+
const rawContentScaleY = rect.height / (rect.editScaleY * actualHeight);
|
|
43858
|
+
const contentScaleX = Number.isFinite(rawContentScaleX) && rawContentScaleX > 0 ? rawContentScaleX : 1;
|
|
43859
|
+
const contentScaleY = Number.isFinite(rawContentScaleY) && rawContentScaleY > 0 ? rawContentScaleY : 1;
|
|
43860
|
+
let resizeAnchor;
|
|
43861
|
+
if (kind === "resize") {
|
|
43862
|
+
const startBcr = sel.element.getBoundingClientRect();
|
|
43863
|
+
resizeAnchor = {
|
|
43864
|
+
anchorX: startBcr.x,
|
|
43865
|
+
anchorY: startBcr.y,
|
|
43866
|
+
baseGsapX: readElementGsapNumber(sel.element, "x") ?? 0,
|
|
43867
|
+
baseGsapY: readElementGsapNumber(sel.element, "y") ?? 0,
|
|
43868
|
+
pinX: 0,
|
|
43869
|
+
pinY: 0
|
|
43870
|
+
};
|
|
43871
|
+
}
|
|
43589
43872
|
let initialPathOffset = captureStudioPathOffset(sel.element);
|
|
43590
43873
|
let manualEditDragToken;
|
|
43591
43874
|
let pathOffsetMember;
|
|
@@ -43642,6 +43925,9 @@ function startGesture(kind, e, opts, options) {
|
|
|
43642
43925
|
actualRotation: rotation.angle,
|
|
43643
43926
|
editScaleX: rect.editScaleX,
|
|
43644
43927
|
editScaleY: rect.editScaleY,
|
|
43928
|
+
contentScaleX,
|
|
43929
|
+
contentScaleY,
|
|
43930
|
+
resizeAnchor,
|
|
43645
43931
|
manualEditDragToken,
|
|
43646
43932
|
snapContext
|
|
43647
43933
|
};
|
|
@@ -43649,6 +43935,11 @@ function startGesture(kind, e, opts, options) {
|
|
|
43649
43935
|
}
|
|
43650
43936
|
|
|
43651
43937
|
// src/components/editor/useDomEditOverlayGestures.ts
|
|
43938
|
+
function restoreResizeAnchorPin(element, g) {
|
|
43939
|
+
const anchor = g.resizeAnchor;
|
|
43940
|
+
if (!anchor || anchor.pinX === 0 && anchor.pinY === 0) return;
|
|
43941
|
+
setElementGsapPosition(element, anchor.baseGsapX, anchor.baseGsapY);
|
|
43942
|
+
}
|
|
43652
43943
|
function createDomEditOverlayGestureHandlers(opts) {
|
|
43653
43944
|
const setDraftOverlayRect = (next) => {
|
|
43654
43945
|
opts.setOverlayRect(next);
|
|
@@ -43751,7 +44042,8 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
43751
44042
|
actualAngle: g.actualRotation,
|
|
43752
44043
|
snap: e.shiftKey
|
|
43753
44044
|
});
|
|
43754
|
-
|
|
44045
|
+
const draftViaGsap = applyRotationDraftViaGsap(sel.element, rotated.angle);
|
|
44046
|
+
if (!draftViaGsap) {
|
|
43755
44047
|
applyStudioRotationDraft(sel.element, rotated);
|
|
43756
44048
|
}
|
|
43757
44049
|
return;
|
|
@@ -43843,11 +44135,27 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
43843
44135
|
actualHeight: g.actualHeight,
|
|
43844
44136
|
scaleX: g.editScaleX,
|
|
43845
44137
|
scaleY: g.editScaleY,
|
|
44138
|
+
contentScaleX: g.contentScaleX,
|
|
44139
|
+
contentScaleY: g.contentScaleY,
|
|
43846
44140
|
dx,
|
|
43847
44141
|
dy,
|
|
43848
44142
|
uniform: e.shiftKey
|
|
43849
44143
|
});
|
|
43850
44144
|
applyStudioBoxSizeDraft(sel.element, nextSize);
|
|
44145
|
+
const anchor = g.resizeAnchor;
|
|
44146
|
+
if (anchor) {
|
|
44147
|
+
const pinned = sel.element.getBoundingClientRect();
|
|
44148
|
+
const nextPinX = anchor.pinX + (anchor.anchorX - pinned.x);
|
|
44149
|
+
const nextPinY = anchor.pinY + (anchor.anchorY - pinned.y);
|
|
44150
|
+
if (setElementGsapPosition(
|
|
44151
|
+
sel.element,
|
|
44152
|
+
anchor.baseGsapX + nextPinX,
|
|
44153
|
+
anchor.baseGsapY + nextPinY
|
|
44154
|
+
)) {
|
|
44155
|
+
anchor.pinX = nextPinX;
|
|
44156
|
+
anchor.pinY = nextPinY;
|
|
44157
|
+
}
|
|
44158
|
+
}
|
|
43851
44159
|
const overlayEl = opts.overlayRef.current;
|
|
43852
44160
|
const iframe = opts.iframeRef.current;
|
|
43853
44161
|
const refreshed = overlayEl && iframe ? toOverlayRect(overlayEl, iframe, sel.element) : null;
|
|
@@ -43931,6 +44239,7 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
43931
44239
|
return;
|
|
43932
44240
|
}
|
|
43933
44241
|
if (g.kind === "resize" && movedDistance < BLOCKED_MOVE_THRESHOLD_PX) {
|
|
44242
|
+
restoreResizeAnchorPin(sel.element, g);
|
|
43934
44243
|
restoreStudioBoxSize(sel.element, g.initialBoxSize);
|
|
43935
44244
|
endStudioManualEditGesture(sel.element, g.manualEditDragToken);
|
|
43936
44245
|
if (box) {
|
|
@@ -43957,7 +44266,8 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
43957
44266
|
restoreStudioRotation(sel.element, g.initialRotation);
|
|
43958
44267
|
}
|
|
43959
44268
|
};
|
|
43960
|
-
|
|
44269
|
+
const rotationChanged = hasDomEditRotationChanged(g.actualRotation, finalRotation.angle);
|
|
44270
|
+
if (!rotationChanged) {
|
|
43961
44271
|
restoreRotation();
|
|
43962
44272
|
endStudioManualEditGesture(sel.element, g.manualEditDragToken);
|
|
43963
44273
|
return;
|
|
@@ -43965,10 +44275,13 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
43965
44275
|
if (!applyRotationDraftViaGsap(sel.element, finalRotation.angle)) {
|
|
43966
44276
|
applyStudioRotation(sel.element, finalRotation);
|
|
43967
44277
|
}
|
|
43968
|
-
void Promise.resolve(opts.onRotationCommitRef.current(sel, finalRotation)).catch(() => {
|
|
44278
|
+
void Promise.resolve(opts.onRotationCommitRef.current(sel, finalRotation)).catch((error) => {
|
|
44279
|
+
console.error("rotate commit failed", error);
|
|
43969
44280
|
if (g.manualEditDragToken && isStudioManualEditGestureCurrent(sel.element, g.manualEditDragToken))
|
|
43970
44281
|
restoreRotation();
|
|
43971
|
-
}).finally(() =>
|
|
44282
|
+
}).finally(() => {
|
|
44283
|
+
endStudioManualEditGesture(sel.element, g.manualEditDragToken);
|
|
44284
|
+
});
|
|
43972
44285
|
} else if (g.kind === "drag") {
|
|
43973
44286
|
const dx = g.lastSnappedDx ?? e.clientX - g.startX;
|
|
43974
44287
|
const dy = g.lastSnappedDy ?? e.clientY - g.startY;
|
|
@@ -44002,9 +44315,12 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
44002
44315
|
opts.suppressNextBoxClickRef.current = true;
|
|
44003
44316
|
const finalSize = readStudioBoxSize(sel.element);
|
|
44004
44317
|
applyStudioBoxSize(sel.element, finalSize);
|
|
44005
|
-
void Promise.resolve(opts.onBoxSizeCommitRef.current(sel, finalSize)).catch(() => {
|
|
44006
|
-
|
|
44318
|
+
void Promise.resolve(opts.onBoxSizeCommitRef.current(sel, finalSize)).catch((error) => {
|
|
44319
|
+
console.error("resize commit failed", error);
|
|
44320
|
+
if (g.manualEditDragToken && isStudioManualEditGestureCurrent(sel.element, g.manualEditDragToken)) {
|
|
44321
|
+
restoreResizeAnchorPin(sel.element, g);
|
|
44007
44322
|
restoreStudioBoxSize(sel.element, g.initialBoxSize);
|
|
44323
|
+
}
|
|
44008
44324
|
}).finally(() => endStudioManualEditGesture(sel.element, g.manualEditDragToken));
|
|
44009
44325
|
}
|
|
44010
44326
|
};
|
|
@@ -44021,6 +44337,7 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
44021
44337
|
restoreGestureOverlayRect(g);
|
|
44022
44338
|
}
|
|
44023
44339
|
if (g?.mode === "box-size" && sel) {
|
|
44340
|
+
restoreResizeAnchorPin(sel.element, g);
|
|
44024
44341
|
restoreStudioBoxSize(sel.element, g.initialBoxSize);
|
|
44025
44342
|
endStudioManualEditGesture(sel.element, g.manualEditDragToken);
|
|
44026
44343
|
restoreGestureOverlayRect(g);
|
|
@@ -44248,51 +44565,43 @@ function DomEditCropHandles({
|
|
|
44248
44565
|
}) {
|
|
44249
44566
|
const gestureRef = useRef89(null);
|
|
44250
44567
|
const [dragging, setDragging] = useState79(false);
|
|
44251
|
-
const
|
|
44252
|
-
const parsed = readElementCropInsets(
|
|
44253
|
-
|
|
44254
|
-
|
|
44255
|
-
|
|
44256
|
-
|
|
44257
|
-
right: parsed.right,
|
|
44258
|
-
bottom: parsed.bottom,
|
|
44259
|
-
left: parsed.left
|
|
44260
|
-
},
|
|
44261
|
-
radius: parsed.radius
|
|
44262
|
-
};
|
|
44263
|
-
});
|
|
44568
|
+
const cropStateFor = (element) => {
|
|
44569
|
+
const parsed = readElementCropInsets(element);
|
|
44570
|
+
const { radius, ...insets } = parsed ?? { top: 0, right: 0, bottom: 0, left: 0, radius: 0 };
|
|
44571
|
+
return { element, croppable: parsed !== null, insets, radius };
|
|
44572
|
+
};
|
|
44573
|
+
const [state, setState] = useState79(() => cropStateFor(selection.element));
|
|
44264
44574
|
if (state.element !== selection.element) {
|
|
44265
|
-
|
|
44266
|
-
setState({
|
|
44267
|
-
element: selection.element,
|
|
44268
|
-
insets: {
|
|
44269
|
-
top: liveInsets.top,
|
|
44270
|
-
right: liveInsets.right,
|
|
44271
|
-
bottom: liveInsets.bottom,
|
|
44272
|
-
left: liveInsets.left
|
|
44273
|
-
},
|
|
44274
|
-
radius: liveInsets.radius
|
|
44275
|
-
});
|
|
44575
|
+
setState(cropStateFor(selection.element));
|
|
44276
44576
|
}
|
|
44277
44577
|
const hasCrop = state.insets.top > 0 || state.insets.right > 0 || state.insets.bottom > 0 || state.insets.left > 0;
|
|
44278
|
-
const committedRef = useRef89(null);
|
|
44279
|
-
committedRef.current = hasCrop ? buildInsetClipPathSides(state.insets, state.radius) : null;
|
|
44280
44578
|
const liftedRef = useRef89(false);
|
|
44579
|
+
const preLiftInlineClipRef = useRef89("");
|
|
44580
|
+
const committedClipRef = useRef89(null);
|
|
44281
44581
|
useEffect62(() => {
|
|
44282
44582
|
const el = selection.element;
|
|
44583
|
+
if (readElementCropInsets(el) === null) return;
|
|
44584
|
+
preLiftInlineClipRef.current = el.style.getPropertyValue("clip-path");
|
|
44585
|
+
committedClipRef.current = null;
|
|
44283
44586
|
el.style.setProperty("clip-path", "none");
|
|
44284
44587
|
liftedRef.current = true;
|
|
44285
44588
|
return () => {
|
|
44286
44589
|
liftedRef.current = false;
|
|
44287
|
-
|
|
44590
|
+
const committed = committedClipRef.current;
|
|
44591
|
+
const restore = committed !== null ? committed || null : preLiftInlineClipRef.current || null;
|
|
44592
|
+
if (restore) el.style.setProperty("clip-path", restore);
|
|
44288
44593
|
else el.style.removeProperty("clip-path");
|
|
44289
44594
|
};
|
|
44290
44595
|
}, [selection.element]);
|
|
44291
|
-
const
|
|
44292
|
-
const
|
|
44293
|
-
const
|
|
44294
|
-
const
|
|
44295
|
-
|
|
44596
|
+
const frame = readElementCropFrame(selection.element, overlayRect);
|
|
44597
|
+
const width = frame.width / frame.scaleX;
|
|
44598
|
+
const height = frame.height / frame.scaleY;
|
|
44599
|
+
const cropRect = cropRectFromInsets(
|
|
44600
|
+
{ left: 0, top: 0, width: frame.width, height: frame.height },
|
|
44601
|
+
state.insets,
|
|
44602
|
+
frame.scaleX,
|
|
44603
|
+
frame.scaleY
|
|
44604
|
+
);
|
|
44296
44605
|
const startCropGesture = (edge, event) => {
|
|
44297
44606
|
if (!onStyleCommit) return;
|
|
44298
44607
|
event.preventDefault();
|
|
@@ -44304,7 +44613,10 @@ function DomEditCropHandles({
|
|
|
44304
44613
|
startX: event.clientX,
|
|
44305
44614
|
startY: event.clientY,
|
|
44306
44615
|
startInsets: state.insets,
|
|
44307
|
-
didMove: false
|
|
44616
|
+
didMove: false,
|
|
44617
|
+
angleDeg: frame.angleDeg,
|
|
44618
|
+
scaleX: frame.scaleX,
|
|
44619
|
+
scaleY: frame.scaleY
|
|
44308
44620
|
};
|
|
44309
44621
|
setDragging(true);
|
|
44310
44622
|
};
|
|
@@ -44313,12 +44625,17 @@ function DomEditCropHandles({
|
|
|
44313
44625
|
if (!gesture || gesture.pointerId !== event.pointerId) return;
|
|
44314
44626
|
event.preventDefault();
|
|
44315
44627
|
event.stopPropagation();
|
|
44628
|
+
const local = rotateDeltaIntoFrame(
|
|
44629
|
+
event.clientX - gesture.startX,
|
|
44630
|
+
event.clientY - gesture.startY,
|
|
44631
|
+
gesture.angleDeg
|
|
44632
|
+
);
|
|
44316
44633
|
const drag = {
|
|
44317
44634
|
startInsets: gesture.startInsets,
|
|
44318
|
-
deltaX:
|
|
44319
|
-
deltaY:
|
|
44320
|
-
scaleX,
|
|
44321
|
-
scaleY
|
|
44635
|
+
deltaX: local.deltaX,
|
|
44636
|
+
deltaY: local.deltaY,
|
|
44637
|
+
scaleX: gesture.scaleX,
|
|
44638
|
+
scaleY: gesture.scaleY
|
|
44322
44639
|
};
|
|
44323
44640
|
const nextInsets = gesture.edge === "move" ? resolveCropInsetFromMoveDrag(drag) : resolveCropInsetFromEdgeDrag({ ...drag, edge: gesture.edge, width, height });
|
|
44324
44641
|
gesture.didMove = true;
|
|
@@ -44336,9 +44653,12 @@ function DomEditCropHandles({
|
|
|
44336
44653
|
const reLift = () => {
|
|
44337
44654
|
if (liftedRef.current) el.style.setProperty("clip-path", "none");
|
|
44338
44655
|
};
|
|
44339
|
-
|
|
44340
|
-
|
|
44341
|
-
).then(
|
|
44656
|
+
const committedValue = buildInsetClipPathSides(state.insets, state.radius);
|
|
44657
|
+
const cropped = state.insets.top > 0 || state.insets.right > 0 || state.insets.bottom > 0 || state.insets.left > 0;
|
|
44658
|
+
void Promise.resolve(onStyleCommit?.("clip-path", committedValue)).then(() => {
|
|
44659
|
+
committedClipRef.current = cropped ? committedValue : "";
|
|
44660
|
+
reLift();
|
|
44661
|
+
}, reLift);
|
|
44342
44662
|
};
|
|
44343
44663
|
const cancelCropGesture = (event) => {
|
|
44344
44664
|
const gesture = gestureRef.current;
|
|
@@ -44349,101 +44669,104 @@ function DomEditCropHandles({
|
|
|
44349
44669
|
setDragging(false);
|
|
44350
44670
|
setState((prev) => ({ ...prev, insets: gesture.startInsets }));
|
|
44351
44671
|
};
|
|
44352
|
-
|
|
44353
|
-
|
|
44354
|
-
|
|
44355
|
-
|
|
44356
|
-
|
|
44357
|
-
|
|
44358
|
-
|
|
44359
|
-
|
|
44360
|
-
|
|
44361
|
-
|
|
44362
|
-
|
|
44363
|
-
|
|
44672
|
+
if (!state.croppable) return null;
|
|
44673
|
+
return /* @__PURE__ */ jsxs81(
|
|
44674
|
+
"div",
|
|
44675
|
+
{
|
|
44676
|
+
"data-dom-edit-crop-frame": "true",
|
|
44677
|
+
className: "pointer-events-none absolute",
|
|
44678
|
+
style: {
|
|
44679
|
+
left: frame.left,
|
|
44680
|
+
top: frame.top,
|
|
44681
|
+
width: frame.width,
|
|
44682
|
+
height: frame.height,
|
|
44683
|
+
transform: frame.angleDeg !== 0 ? `rotate(${frame.angleDeg}deg)` : void 0
|
|
44684
|
+
},
|
|
44685
|
+
children: [
|
|
44686
|
+
hasCrop && /* @__PURE__ */ jsx97("div", { className: "pointer-events-none absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsx97(
|
|
44364
44687
|
"div",
|
|
44365
44688
|
{
|
|
44366
44689
|
className: "absolute",
|
|
44367
44690
|
style: {
|
|
44368
|
-
left: cropRect.left
|
|
44369
|
-
top: cropRect.top
|
|
44691
|
+
left: cropRect.left,
|
|
44692
|
+
top: cropRect.top,
|
|
44370
44693
|
width: cropRect.width,
|
|
44371
44694
|
height: cropRect.height,
|
|
44372
44695
|
boxShadow: "0 0 0 100000px rgba(8, 8, 12, 0.6)"
|
|
44373
44696
|
}
|
|
44374
44697
|
}
|
|
44375
|
-
)
|
|
44376
|
-
|
|
44377
|
-
|
|
44378
|
-
|
|
44379
|
-
|
|
44380
|
-
|
|
44381
|
-
|
|
44382
|
-
|
|
44383
|
-
|
|
44384
|
-
|
|
44385
|
-
|
|
44386
|
-
|
|
44387
|
-
|
|
44388
|
-
|
|
44389
|
-
|
|
44390
|
-
|
|
44391
|
-
|
|
44392
|
-
|
|
44393
|
-
|
|
44394
|
-
|
|
44395
|
-
|
|
44396
|
-
|
|
44397
|
-
|
|
44398
|
-
|
|
44399
|
-
|
|
44400
|
-
|
|
44401
|
-
|
|
44402
|
-
|
|
44403
|
-
|
|
44404
|
-
|
|
44405
|
-
|
|
44406
|
-
|
|
44407
|
-
|
|
44408
|
-
|
|
44409
|
-
|
|
44410
|
-
|
|
44411
|
-
|
|
44412
|
-
|
|
44413
|
-
|
|
44414
|
-
|
|
44415
|
-
|
|
44416
|
-
|
|
44417
|
-
|
|
44418
|
-
|
|
44419
|
-
|
|
44420
|
-
|
|
44421
|
-
|
|
44422
|
-
|
|
44423
|
-
|
|
44424
|
-
|
|
44425
|
-
|
|
44426
|
-
|
|
44427
|
-
|
|
44428
|
-
|
|
44429
|
-
|
|
44430
|
-
|
|
44431
|
-
|
|
44432
|
-
|
|
44433
|
-
|
|
44434
|
-
|
|
44435
|
-
|
|
44436
|
-
|
|
44437
|
-
|
|
44438
|
-
|
|
44439
|
-
|
|
44440
|
-
|
|
44441
|
-
|
|
44442
|
-
|
|
44443
|
-
|
|
44444
|
-
|
|
44445
|
-
}
|
|
44446
|
-
|
|
44698
|
+
) }),
|
|
44699
|
+
/* @__PURE__ */ jsx97(
|
|
44700
|
+
"div",
|
|
44701
|
+
{
|
|
44702
|
+
"aria-hidden": "true",
|
|
44703
|
+
className: "pointer-events-none absolute border border-dashed border-studio-accent",
|
|
44704
|
+
style: {
|
|
44705
|
+
left: cropRect.left,
|
|
44706
|
+
top: cropRect.top,
|
|
44707
|
+
width: cropRect.width,
|
|
44708
|
+
height: cropRect.height
|
|
44709
|
+
},
|
|
44710
|
+
children: dragging && /* @__PURE__ */ jsxs81(Fragment30, { children: [
|
|
44711
|
+
/* @__PURE__ */ jsx97("div", { className: "absolute inset-y-0 left-1/3 w-px bg-studio-accent/40" }),
|
|
44712
|
+
/* @__PURE__ */ jsx97("div", { className: "absolute inset-y-0 left-2/3 w-px bg-studio-accent/40" }),
|
|
44713
|
+
/* @__PURE__ */ jsx97("div", { className: "absolute inset-x-0 top-1/3 h-px bg-studio-accent/40" }),
|
|
44714
|
+
/* @__PURE__ */ jsx97("div", { className: "absolute inset-x-0 top-2/3 h-px bg-studio-accent/40" })
|
|
44715
|
+
] })
|
|
44716
|
+
}
|
|
44717
|
+
),
|
|
44718
|
+
hasCrop && /* @__PURE__ */ jsx97(
|
|
44719
|
+
"button",
|
|
44720
|
+
{
|
|
44721
|
+
type: "button",
|
|
44722
|
+
"aria-label": "Reposition crop",
|
|
44723
|
+
"data-dom-edit-crop-handle": "true",
|
|
44724
|
+
className: "pointer-events-auto absolute rounded-full border-2 border-studio-accent bg-studio-accent/30 shadow-[0_0_0_1px_rgba(0,0,0,0.4)]",
|
|
44725
|
+
style: {
|
|
44726
|
+
left: cropRect.left + cropRect.width / 2,
|
|
44727
|
+
top: cropRect.top + cropRect.height / 2,
|
|
44728
|
+
width: 22,
|
|
44729
|
+
height: 22,
|
|
44730
|
+
transform: "translate(-50%, -50%)",
|
|
44731
|
+
cursor: "move",
|
|
44732
|
+
touchAction: "none"
|
|
44733
|
+
},
|
|
44734
|
+
onPointerDown: (event) => startCropGesture("move", event),
|
|
44735
|
+
onPointerMove: updateCropGesture,
|
|
44736
|
+
onPointerUp: finishCropGesture,
|
|
44737
|
+
onPointerCancel: cancelCropGesture
|
|
44738
|
+
}
|
|
44739
|
+
),
|
|
44740
|
+
EDGES.map((edge) => {
|
|
44741
|
+
const vertical = edge === "left" || edge === "right";
|
|
44742
|
+
const place = edgeHandlePlacement(edge, cropRect);
|
|
44743
|
+
return /* @__PURE__ */ jsx97(
|
|
44744
|
+
"button",
|
|
44745
|
+
{
|
|
44746
|
+
type: "button",
|
|
44747
|
+
"aria-label": `Crop ${edge}`,
|
|
44748
|
+
"data-dom-edit-crop-handle": "true",
|
|
44749
|
+
className: "pointer-events-auto absolute rounded-full bg-studio-accent shadow-[0_0_0_1px_rgba(0,0,0,0.4)]",
|
|
44750
|
+
style: {
|
|
44751
|
+
left: place.left,
|
|
44752
|
+
top: place.top,
|
|
44753
|
+
width: vertical ? 5 : 26,
|
|
44754
|
+
height: vertical ? 26 : 5,
|
|
44755
|
+
transform: place.transform,
|
|
44756
|
+
cursor: vertical ? "ew-resize" : "ns-resize",
|
|
44757
|
+
touchAction: "none"
|
|
44758
|
+
},
|
|
44759
|
+
onPointerDown: (event) => startCropGesture(edge, event),
|
|
44760
|
+
onPointerMove: updateCropGesture,
|
|
44761
|
+
onPointerUp: finishCropGesture,
|
|
44762
|
+
onPointerCancel: cancelCropGesture
|
|
44763
|
+
},
|
|
44764
|
+
edge
|
|
44765
|
+
);
|
|
44766
|
+
})
|
|
44767
|
+
]
|
|
44768
|
+
}
|
|
44769
|
+
);
|
|
44447
44770
|
}
|
|
44448
44771
|
|
|
44449
44772
|
// src/components/editor/DomEditRotateHandle.tsx
|
|
@@ -44891,6 +45214,14 @@ var DomEditOverlay = memo35(function DomEditOverlay2({
|
|
|
44891
45214
|
const target = event.target;
|
|
44892
45215
|
if (target?.closest('[data-dom-edit-selection-box="true"]')) return;
|
|
44893
45216
|
if (!hoverSelectionRef.current && onMarqueeSelectRef.current && compRect.width > 0) {
|
|
45217
|
+
const iframe = iframeRef.current;
|
|
45218
|
+
const freshTarget = iframe ? getPreviewTargetFromPointer(
|
|
45219
|
+
iframe,
|
|
45220
|
+
event.clientX,
|
|
45221
|
+
event.clientY,
|
|
45222
|
+
activeCompositionPathRef.current
|
|
45223
|
+
) : null;
|
|
45224
|
+
if (freshTarget) return;
|
|
44894
45225
|
const overlayEl = overlayRef.current;
|
|
44895
45226
|
if (overlayEl) {
|
|
44896
45227
|
const oRect = overlayEl.getBoundingClientRect();
|