mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 15:49:53 +00:00
fix(studio): per-property-group intercept routing + drag/resize fixes (#1356)
* fix(core): per-property-group keyframe foundations
Add PropertyGroupName type system (position/scale/size/rotation/visual/other),
PROPERTY_GROUPS constant, classifyPropertyGroup/classifyTweenPropertyGroup
functions. Parser generates group-aware animation IDs, resolves position strings
(+=, -=, <, >), uses numeric matching with 2% tolerance, and preserves IDs
across all mutations.
* fix(core): add split-into-property-groups and replace-with-keyframes mutations
Server-side mutations for atomic property-group splitting and keyframe
replacement. Client commitMutation returns early on changed:false instead
of throwing.
* fix(studio): per-property-group intercept routing + drag/resize fixes
Rewire GSAP runtime bridge for property-group routing: drag sends only {x,y}
to position group, resize routes to scale group via data-hf-studio-original-width,
rotation routes to rotation group. Add resolveGroupTween helper, from-extend
with split-first-then-position-only pattern, autoKeyframeEnabled guards,
GSAP base + delta fix in drag draft, cancel-restores-GSAP-x/y from data attrs.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* Low-level GSAP runtime property readers shared by gsapRuntimeBridge and gsapDragCommit.
|
||||
*/
|
||||
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
|
||||
import { classifyPropertyGroup, type PropertyGroupName } from "@hyperframes/core/gsap-parser";
|
||||
|
||||
interface IframeGsap {
|
||||
getProperty: (el: Element, prop: string) => number;
|
||||
@@ -19,7 +20,8 @@ export function readGsapProperty(
|
||||
const el = iframe.contentDocument?.querySelector(selector);
|
||||
if (!el) return null;
|
||||
const val = Number(gsap.getProperty(el, prop));
|
||||
return Number.isFinite(val) ? Math.round(val) : null;
|
||||
if (!Number.isFinite(val)) return null;
|
||||
return POSITION_PROPS.has(prop) ? Math.round(val) : Math.round(val * 1000) / 1000;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -51,6 +53,7 @@ export function readAllAnimatedProperties(
|
||||
iframe: HTMLIFrameElement | null,
|
||||
selector: string,
|
||||
anim: GsapAnimation,
|
||||
group?: PropertyGroupName,
|
||||
): Record<string, number> {
|
||||
const result: Record<string, number> = {};
|
||||
if (!iframe?.contentWindow) return result;
|
||||
@@ -81,6 +84,13 @@ export function readAllAnimatedProperties(
|
||||
for (const p of Object.keys(anim.properties)) propKeys.add(p);
|
||||
}
|
||||
|
||||
// When a group filter is specified, only keep properties belonging to that group.
|
||||
if (group) {
|
||||
for (const p of propKeys) {
|
||||
if (classifyPropertyGroup(p) !== group) propKeys.delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
for (const prop of propKeys) {
|
||||
const val = Number(gsap.getProperty(el, prop));
|
||||
if (Number.isFinite(val)) {
|
||||
@@ -147,9 +157,13 @@ export function readAllAnimatedProperties(
|
||||
sepia: 0,
|
||||
invert: 0,
|
||||
};
|
||||
// Collect all properties that ANY tween on this element explicitly targets.
|
||||
// Only capture baseline values for these — GSAP reports non-default values
|
||||
// (scaleZ=0, brightness=0) for untouched properties, polluting keyframes.
|
||||
const allTweenedProps = new Set([...propKeys, ...otherTweenProps]);
|
||||
for (const [prop, defaultVal] of Object.entries(UNIVERSAL_BASELINE)) {
|
||||
if (prop in result) continue;
|
||||
if (otherTweenProps.has(prop)) continue;
|
||||
if (!allTweenedProps.has(prop)) continue;
|
||||
const val = Number(gsap.getProperty(el, prop));
|
||||
if (Number.isFinite(val) && Math.round(val * 1000) !== Math.round(defaultVal * 1000)) {
|
||||
result[prop] = Math.round(val * 1000) / 1000;
|
||||
|
||||
Reference in New Issue
Block a user