@hyperframes/core 0.7.29 → 0.7.30
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/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/hyperframe.runtime.iife.js +24 -24
- package/dist/runtime/analytics.d.ts +19 -0
- package/dist/runtime/analytics.d.ts.map +1 -0
- package/dist/runtime/analytics.js +31 -0
- package/dist/runtime/analytics.js.map +1 -0
- package/dist/runtime/diagnostics.d.ts +2 -0
- package/dist/runtime/diagnostics.d.ts.map +1 -0
- package/dist/runtime/diagnostics.js +53 -0
- package/dist/runtime/diagnostics.js.map +1 -0
- package/dist/runtime/globals.d.ts +12 -0
- package/dist/runtime/globals.d.ts.map +1 -0
- package/dist/runtime/globals.js +4 -0
- package/dist/runtime/globals.js.map +1 -0
- package/dist/runtime/positionEdits.d.ts +47 -0
- package/dist/runtime/positionEdits.d.ts.map +1 -0
- package/dist/runtime/positionEdits.js +166 -0
- package/dist/runtime/positionEdits.js.map +1 -0
- package/package.json +8 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime analytics — vendor-agnostic event emission via postMessage.
|
|
3
|
+
*
|
|
4
|
+
* The host application decides what to do with events: forward to PostHog,
|
|
5
|
+
* Mixpanel, Amplitude, a custom logger, or nothing at all.
|
|
6
|
+
*/
|
|
7
|
+
export type RuntimeAnalyticsEvent = "composition_loaded" | "composition_played" | "composition_paused" | "composition_seeked" | "composition_ended" | "element_picked" | "position_edit_fold_skipped";
|
|
8
|
+
export type RuntimeAnalyticsProperties = Record<string, string | number | boolean | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Wire the analytics + performance bridge to the runtime's postMessage transport.
|
|
11
|
+
* Called once during runtime bootstrap from `init.ts`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function initRuntimeAnalytics(postMessage: (payload: unknown) => void): void;
|
|
14
|
+
/**
|
|
15
|
+
* Emit an analytics event through the bridge.
|
|
16
|
+
* The host app receives it via postMessage and forwards to its analytics provider.
|
|
17
|
+
*/
|
|
18
|
+
export declare function emitAnalyticsEvent(event: RuntimeAnalyticsEvent, properties?: RuntimeAnalyticsProperties): void;
|
|
19
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/runtime/analytics.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,MAAM,MAAM,qBAAqB,GAC7B,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,gBAAgB,GAChB,4BAA4B,CAAC;AAEjC,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAK1F;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAElF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,qBAAqB,EAC5B,UAAU,CAAC,EAAE,0BAA0B,GACtC,IAAI,CAaN"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { swallow } from "./diagnostics.js";
|
|
2
|
+
// Stored reference to the postRuntimeMessage function, set during init.
|
|
3
|
+
let _postMessage = null;
|
|
4
|
+
/**
|
|
5
|
+
* Wire the analytics + performance bridge to the runtime's postMessage transport.
|
|
6
|
+
* Called once during runtime bootstrap from `init.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export function initRuntimeAnalytics(postMessage) {
|
|
9
|
+
_postMessage = postMessage;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Emit an analytics event through the bridge.
|
|
13
|
+
* The host app receives it via postMessage and forwards to its analytics provider.
|
|
14
|
+
*/
|
|
15
|
+
export function emitAnalyticsEvent(event, properties) {
|
|
16
|
+
if (!_postMessage)
|
|
17
|
+
return;
|
|
18
|
+
try {
|
|
19
|
+
_postMessage({
|
|
20
|
+
source: "hf-preview",
|
|
21
|
+
type: "analytics",
|
|
22
|
+
event,
|
|
23
|
+
properties: properties ?? {},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
// Never let analytics failures affect the runtime
|
|
28
|
+
swallow("runtime.analytics.site1", err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/runtime/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAmBxC,wEAAwE;AACxE,IAAI,YAAY,GAAwC,IAAI,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAuC;IAC1E,YAAY,GAAG,WAAW,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAA4B,EAC5B,UAAuC;IAEvC,IAAI,CAAC,YAAY;QAAE,OAAO;IAC1B,IAAI,CAAC;QACH,YAAY,CAAC;YACX,MAAM,EAAE,YAAY;YACpB,IAAI,EAAE,WAAW;YACjB,KAAK;YACL,UAAU,EAAE,UAAU,IAAI,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kDAAkD;QAClD,OAAO,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/runtime/diagnostics.ts"],"names":[],"mappings":"AA+BA,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAqB5D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime diagnostic helpers for best-effort operations.
|
|
3
|
+
*
|
|
4
|
+
* Many runtime operations (postMessage to a parent frame, `media.play()` /
|
|
5
|
+
* `pause()` / `currentTime=`, timeline `seek()`, anime.js feature detection,
|
|
6
|
+
* etc.) can throw under perfectly normal conditions: the parent frame is
|
|
7
|
+
* cross-origin, autoplay is denied, the media element was just removed from
|
|
8
|
+
* the DOM, the timeline has been disposed, the host page does not include
|
|
9
|
+
* anime.js. The right behaviour in each case is "tried, didn't work, move
|
|
10
|
+
* on" — but emitting nothing makes silent failures invisible to anyone
|
|
11
|
+
* debugging a genuinely broken composition, and the bare `catch {}` shape
|
|
12
|
+
* also trips strict lint configurations on the inlined runtime IIFE.
|
|
13
|
+
*
|
|
14
|
+
* `swallow(label, err)` is the single funnel for these intentional silences.
|
|
15
|
+
* It dispatches to:
|
|
16
|
+
*
|
|
17
|
+
* - `console.debug` with the label, the error, and a `[hyperframes]` prefix
|
|
18
|
+
* when `window.__hfDebug === true` (or the legacy `__HYPERFRAMES_DEBUG`
|
|
19
|
+
* env-style global). Quiet by default; flip the flag in DevTools when
|
|
20
|
+
* hunting a regression.
|
|
21
|
+
* - A custom `__hf.onSwallowed` handler if installed — lets the studio /
|
|
22
|
+
* embeddings collect runtime swallow events without polluting the page
|
|
23
|
+
* console.
|
|
24
|
+
*
|
|
25
|
+
* Production behaviour without either flag set: completely silent, just
|
|
26
|
+
* like the original empty `catch {}`. The shape is also lint-clean — the
|
|
27
|
+
* helper call is a real statement, so no `no-empty` warnings ship in the
|
|
28
|
+
* inlined IIFE.
|
|
29
|
+
*/
|
|
30
|
+
import { getDebugSurface } from "./globals.js";
|
|
31
|
+
export function swallow(label, error) {
|
|
32
|
+
if (typeof window === "undefined")
|
|
33
|
+
return;
|
|
34
|
+
const w = getDebugSurface();
|
|
35
|
+
const handler = w.__hf?.onSwallowed;
|
|
36
|
+
if (handler) {
|
|
37
|
+
try {
|
|
38
|
+
handler({ label, error });
|
|
39
|
+
}
|
|
40
|
+
catch (handlerError) {
|
|
41
|
+
// Don't recurse into swallow() — a consumer hook that throws
|
|
42
|
+
// shouldn't be allowed to take down the runtime, and routing the
|
|
43
|
+
// failure back through swallow() would loop. Drop on the floor;
|
|
44
|
+
// the original error already had its surface above.
|
|
45
|
+
void handlerError;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (w.__hfDebug || w.__HYPERFRAMES_DEBUG) {
|
|
49
|
+
// eslint-disable-next-line no-console -- intentional debug surface
|
|
50
|
+
console.debug(`[hyperframes] ${label} swallowed:`, error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/runtime/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,KAAe;IACpD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO;IAC1C,MAAM,CAAC,GAAG,eAAe,EAAE,CAAC;IAE5B,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC;IACpC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,YAAY,EAAE,CAAC;YACtB,6DAA6D;YAC7D,iEAAiE;YACjE,gEAAgE;YAChE,oDAAoD;YACpD,KAAK,YAAY,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;QACzC,mEAAmE;QACnE,OAAO,CAAC,KAAK,CAAC,iBAAiB,KAAK,aAAa,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface HFDebugSurface {
|
|
2
|
+
__hfDebug?: boolean;
|
|
3
|
+
__HYPERFRAMES_DEBUG?: boolean;
|
|
4
|
+
__hf?: {
|
|
5
|
+
onSwallowed?: (event: {
|
|
6
|
+
label: string;
|
|
7
|
+
error: unknown;
|
|
8
|
+
}) => void;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare function getDebugSurface(): HFDebugSurface;
|
|
12
|
+
//# sourceMappingURL=globals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../../src/runtime/globals.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE;QACL,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,OAAO,CAAA;SAAE,KAAK,IAAI,CAAC;KAClE,CAAC;CACH;AAED,wBAAgB,eAAe,IAAI,cAAc,CAEhD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globals.js","sourceRoot":"","sources":["../../src/runtime/globals.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,eAAe;IAC7B,OAAO,UAA4B,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor position edits (SDK `moveElement`) applied at render time.
|
|
3
|
+
*
|
|
4
|
+
* The SDK's `moveElement` writes `data-x` / `data-y` plus a captured baseline
|
|
5
|
+
* (`data-hf-edit-base-x` / `data-hf-edit-base-y` — the values before the first
|
|
6
|
+
* edit). The runtime renders the edit as the DELTA between the two, via the
|
|
7
|
+
* independent CSS `translate` longhand, so it composes additively with any
|
|
8
|
+
* position the composition itself produces (GSAP tweens, `tl.set`, CSS).
|
|
9
|
+
*
|
|
10
|
+
* Why `translate` and why after timeline bind: GSAP folds a `translate` that
|
|
11
|
+
* is present when it FIRST parses an element into its cached transform (and
|
|
12
|
+
* an absolute tween then discards it on the animated axis — the per-axis loss
|
|
13
|
+
* bug). A `translate` set AFTER that parse is never read, cleared, or baked
|
|
14
|
+
* by GSAP 3.x on subsequent seeks, so a single application at bind time holds
|
|
15
|
+
* for the whole timeline. Before the first apply, the element's transform
|
|
16
|
+
* parse is primed (gsap.getProperty) so tweens and positioned set()s that
|
|
17
|
+
* first RENDER later reuse the cache instead of folding the edit. Known
|
|
18
|
+
* limitation: if GSAP itself loads only after the apply ran, a later tween's
|
|
19
|
+
* first parse still folds the edit (the fold guard then skips re-apply and
|
|
20
|
+
* emits position_edit_fold_skipped instead of double-applying).
|
|
21
|
+
*/
|
|
22
|
+
export declare const EDIT_BASE_X_ATTR = "data-hf-edit-base-x";
|
|
23
|
+
export declare const EDIT_BASE_Y_ATTR = "data-hf-edit-base-y";
|
|
24
|
+
export declare const EDIT_ORIGINAL_TRANSLATE_ATTR = "data-hf-edit-original-translate";
|
|
25
|
+
/** Compose the edit delta with the element's pre-edit translate value. */
|
|
26
|
+
export declare const composeTranslate: (original: string, x: string, y: string) => string;
|
|
27
|
+
/** The element's effective translate: inline if set, computed otherwise ("" = none). */
|
|
28
|
+
export declare const readCurrentTranslate: (el: HTMLElement) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Apply one element's position edit. Idempotent — the pre-edit translate is
|
|
31
|
+
* captured exactly once (into EDIT_ORIGINAL_TRANSLATE_ATTR, empty string
|
|
32
|
+
* meaning "none") on first application, and every application recomputes from
|
|
33
|
+
* that baseline.
|
|
34
|
+
*
|
|
35
|
+
* `force` re-applies even when the previously written translate was clobbered
|
|
36
|
+
* externally — used by editor commits, where the current inline translate is
|
|
37
|
+
* the draft-composed one and must be overwritten.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyPositionEditToElement(el: HTMLElement, opts?: {
|
|
40
|
+
force?: boolean;
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Apply all pending position edits in the document. Returns the number of
|
|
44
|
+
* elements updated.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applyPositionEdits(doc: Document): number;
|
|
47
|
+
//# sourceMappingURL=positionEdits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"positionEdits.d.ts","sourceRoot":"","sources":["../../src/runtime/positionEdits.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AACtD,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AACtD,eAAO,MAAM,4BAA4B,oCAAoC,CAAC;AAkC9E,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAOzE,CAAC;AAqBF,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,GAAI,IAAI,WAAW,KAAG,MAUtD,CAAC;AAYF;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAwB5F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAUxD"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// fallow-ignore-file code-duplication
|
|
2
|
+
// (splitTopLevelWhitespace intentionally mirrors the studio-side copies in
|
|
3
|
+
// manualEditsDom.ts / manualEditsRenderScript.ts — this module ships inside
|
|
4
|
+
// the self-contained runtime bundle and cannot import studio code.)
|
|
5
|
+
/**
|
|
6
|
+
* Editor position edits (SDK `moveElement`) applied at render time.
|
|
7
|
+
*
|
|
8
|
+
* The SDK's `moveElement` writes `data-x` / `data-y` plus a captured baseline
|
|
9
|
+
* (`data-hf-edit-base-x` / `data-hf-edit-base-y` — the values before the first
|
|
10
|
+
* edit). The runtime renders the edit as the DELTA between the two, via the
|
|
11
|
+
* independent CSS `translate` longhand, so it composes additively with any
|
|
12
|
+
* position the composition itself produces (GSAP tweens, `tl.set`, CSS).
|
|
13
|
+
*
|
|
14
|
+
* Why `translate` and why after timeline bind: GSAP folds a `translate` that
|
|
15
|
+
* is present when it FIRST parses an element into its cached transform (and
|
|
16
|
+
* an absolute tween then discards it on the animated axis — the per-axis loss
|
|
17
|
+
* bug). A `translate` set AFTER that parse is never read, cleared, or baked
|
|
18
|
+
* by GSAP 3.x on subsequent seeks, so a single application at bind time holds
|
|
19
|
+
* for the whole timeline. Before the first apply, the element's transform
|
|
20
|
+
* parse is primed (gsap.getProperty) so tweens and positioned set()s that
|
|
21
|
+
* first RENDER later reuse the cache instead of folding the edit. Known
|
|
22
|
+
* limitation: if GSAP itself loads only after the apply ran, a later tween's
|
|
23
|
+
* first parse still folds the edit (the fold guard then skips re-apply and
|
|
24
|
+
* emits position_edit_fold_skipped instead of double-applying).
|
|
25
|
+
*/
|
|
26
|
+
import { emitAnalyticsEvent } from "./analytics.js";
|
|
27
|
+
export const EDIT_BASE_X_ATTR = "data-hf-edit-base-x";
|
|
28
|
+
export const EDIT_BASE_Y_ATTR = "data-hf-edit-base-y";
|
|
29
|
+
export const EDIT_ORIGINAL_TRANSLATE_ATTR = "data-hf-edit-original-translate";
|
|
30
|
+
const num = (value) => {
|
|
31
|
+
const n = parseFloat(value ?? "");
|
|
32
|
+
return Number.isFinite(n) ? n : 0;
|
|
33
|
+
};
|
|
34
|
+
/** Split "10px 20px" / "calc(1px + 2px) 3px" on top-level whitespace only. */
|
|
35
|
+
const splitTopLevelWhitespace = (value) => {
|
|
36
|
+
const parts = [];
|
|
37
|
+
let depth = 0;
|
|
38
|
+
let current = "";
|
|
39
|
+
for (const char of value.trim()) {
|
|
40
|
+
if (char === "(")
|
|
41
|
+
depth += 1;
|
|
42
|
+
if (char === ")")
|
|
43
|
+
depth = Math.max(0, depth - 1);
|
|
44
|
+
if (/\s/.test(char) && depth === 0) {
|
|
45
|
+
if (current)
|
|
46
|
+
parts.push(current);
|
|
47
|
+
current = "";
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
current += char;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (current)
|
|
54
|
+
parts.push(current);
|
|
55
|
+
return parts;
|
|
56
|
+
};
|
|
57
|
+
const PX_VALUE = /^-?(?:\d+(?:\.\d+)?|\.\d+)px$/;
|
|
58
|
+
/** Sum two lengths — numerically when both are plain px, via calc() otherwise. */
|
|
59
|
+
const addLengths = (a, b) => {
|
|
60
|
+
if (PX_VALUE.test(a) && PX_VALUE.test(b))
|
|
61
|
+
return `${parseFloat(a) + parseFloat(b)}px`;
|
|
62
|
+
return `calc(${a} + ${b})`;
|
|
63
|
+
};
|
|
64
|
+
/** Compose the edit delta with the element's pre-edit translate value. */
|
|
65
|
+
export const composeTranslate = (original, x, y) => {
|
|
66
|
+
if (!original || original === "none")
|
|
67
|
+
return `${x} ${y}`;
|
|
68
|
+
const [ox, oy, oz] = splitTopLevelWhitespace(original);
|
|
69
|
+
if (ox === undefined)
|
|
70
|
+
return `${x} ${y}`;
|
|
71
|
+
if (oy === undefined)
|
|
72
|
+
return `${addLengths(ox, x)} ${y}`;
|
|
73
|
+
const z = oz === undefined ? "" : ` ${oz}`;
|
|
74
|
+
return `${addLengths(ox, x)} ${addLengths(oy, y)}${z}`;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Force GSAP (when present) to parse and cache the element's transform BEFORE
|
|
78
|
+
* the edit translate is written. GSAP folds a CSS `translate` it sees at an
|
|
79
|
+
* element's first parse into its cached transform (losing it per-axis on
|
|
80
|
+
* absolute tweens); once the cache exists, later tweens and positioned set()s
|
|
81
|
+
* reuse it and never read the translate again. gsap.getProperty parses
|
|
82
|
+
* without mutating the element. Best-effort — absent or failing GSAP is fine.
|
|
83
|
+
*/
|
|
84
|
+
const primeGsapTransformCache = (el) => {
|
|
85
|
+
try {
|
|
86
|
+
const view = el.ownerDocument.defaultView;
|
|
87
|
+
view?.gsap?.getProperty?.(el, "x");
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// parse priming is an optimization, never a requirement
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
/** The element's effective translate: inline if set, computed otherwise ("" = none). */
|
|
94
|
+
export const readCurrentTranslate = (el) => {
|
|
95
|
+
const inline = el.style.getPropertyValue("translate").trim();
|
|
96
|
+
if (inline)
|
|
97
|
+
return inline === "none" ? "" : inline;
|
|
98
|
+
try {
|
|
99
|
+
const view = el.ownerDocument.defaultView;
|
|
100
|
+
const computed = view ? view.getComputedStyle(el).getPropertyValue("translate").trim() : "";
|
|
101
|
+
return computed === "none" ? "" : computed;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* The translate value this module last wrote per element. When a re-apply
|
|
109
|
+
* (timeline rebind) finds the element's inline translate no longer matching,
|
|
110
|
+
* something else consumed it — in practice GSAP folding it into the cached
|
|
111
|
+
* transform when a lazily-created tween first-parsed the element. Re-setting
|
|
112
|
+
* it then would DOUBLE the offset on every axis the tween doesn't animate, so
|
|
113
|
+
* the non-forced path skips instead (degrading to the documented fold-loss).
|
|
114
|
+
*/
|
|
115
|
+
const lastAppliedTranslate = new WeakMap();
|
|
116
|
+
/**
|
|
117
|
+
* Apply one element's position edit. Idempotent — the pre-edit translate is
|
|
118
|
+
* captured exactly once (into EDIT_ORIGINAL_TRANSLATE_ATTR, empty string
|
|
119
|
+
* meaning "none") on first application, and every application recomputes from
|
|
120
|
+
* that baseline.
|
|
121
|
+
*
|
|
122
|
+
* `force` re-applies even when the previously written translate was clobbered
|
|
123
|
+
* externally — used by editor commits, where the current inline translate is
|
|
124
|
+
* the draft-composed one and must be overwritten.
|
|
125
|
+
*/
|
|
126
|
+
export function applyPositionEditToElement(el, opts) {
|
|
127
|
+
const previous = lastAppliedTranslate.get(el);
|
|
128
|
+
if (!opts?.force &&
|
|
129
|
+
previous !== undefined &&
|
|
130
|
+
el.style.getPropertyValue("translate") !== previous) {
|
|
131
|
+
// Observable signal for the documented degradation — without it, a
|
|
132
|
+
// fold-loss surfaces to users only as "my edit didn't stick".
|
|
133
|
+
emitAnalyticsEvent("position_edit_fold_skipped", {
|
|
134
|
+
hfId: el.getAttribute("data-hf-id"),
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const dx = num(el.getAttribute("data-x")) - num(el.getAttribute(EDIT_BASE_X_ATTR));
|
|
139
|
+
const dy = num(el.getAttribute("data-y")) - num(el.getAttribute(EDIT_BASE_Y_ATTR));
|
|
140
|
+
if (!el.hasAttribute(EDIT_ORIGINAL_TRANSLATE_ATTR)) {
|
|
141
|
+
el.setAttribute(EDIT_ORIGINAL_TRANSLATE_ATTR, readCurrentTranslate(el));
|
|
142
|
+
}
|
|
143
|
+
if (previous === undefined)
|
|
144
|
+
primeGsapTransformCache(el);
|
|
145
|
+
const original = el.getAttribute(EDIT_ORIGINAL_TRANSLATE_ATTR) ?? "";
|
|
146
|
+
const value = composeTranslate(original, `${dx}px`, `${dy}px`);
|
|
147
|
+
el.style.setProperty("translate", value);
|
|
148
|
+
lastAppliedTranslate.set(el, el.style.getPropertyValue("translate"));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Apply all pending position edits in the document. Returns the number of
|
|
152
|
+
* elements updated.
|
|
153
|
+
*/
|
|
154
|
+
export function applyPositionEdits(doc) {
|
|
155
|
+
const marked = doc.querySelectorAll(`[${EDIT_BASE_X_ATTR}], [${EDIT_BASE_Y_ATTR}]`);
|
|
156
|
+
let applied = 0;
|
|
157
|
+
for (let i = 0; i < marked.length; i++) {
|
|
158
|
+
const el = marked[i];
|
|
159
|
+
if (!(el instanceof HTMLElement))
|
|
160
|
+
continue;
|
|
161
|
+
applyPositionEditToElement(el);
|
|
162
|
+
applied += 1;
|
|
163
|
+
}
|
|
164
|
+
return applied;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=positionEdits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"positionEdits.js","sourceRoot":"","sources":["../../src/runtime/positionEdits.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.30",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -75,6 +75,10 @@
|
|
|
75
75
|
"import": "./dist/runtime/clipTree.js",
|
|
76
76
|
"types": "./dist/runtime/clipTree.d.ts"
|
|
77
77
|
},
|
|
78
|
+
"./runtime/position-edits": {
|
|
79
|
+
"import": "./dist/runtime/positionEdits.js",
|
|
80
|
+
"types": "./dist/runtime/positionEdits.d.ts"
|
|
81
|
+
},
|
|
78
82
|
"./runtime/lottie-readiness": {
|
|
79
83
|
"import": "./dist/lottieReadiness.js",
|
|
80
84
|
"types": "./dist/lottieReadiness.d.ts"
|
|
@@ -158,9 +162,9 @@
|
|
|
158
162
|
"bpm-detective": "^2.0.5",
|
|
159
163
|
"linkedom": "^0.18.12",
|
|
160
164
|
"postcss": "^8.5.8",
|
|
161
|
-
"@hyperframes/lint": "0.7.
|
|
162
|
-
"@hyperframes/studio-server": "0.7.
|
|
163
|
-
"@hyperframes/parsers": "0.7.
|
|
165
|
+
"@hyperframes/lint": "0.7.30",
|
|
166
|
+
"@hyperframes/studio-server": "0.7.30",
|
|
167
|
+
"@hyperframes/parsers": "0.7.30"
|
|
164
168
|
},
|
|
165
169
|
"devDependencies": {
|
|
166
170
|
"@types/jsdom": "^28.0.0",
|