@hyperframes/sdk 0.8.193 → 0.8.194
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.
|
@@ -16,6 +16,9 @@ import type { ParsedDocument } from "./model.js";
|
|
|
16
16
|
* property is a no-op in applyOne, so this is safe against fresh-base misses.)
|
|
17
17
|
*/
|
|
18
18
|
export declare function applyOverrideSet(parsed: ParsedDocument, overrides: OverrideSet): void;
|
|
19
|
+
export declare function isElementSnapshotOverride(key: string, value: OverrideSet[string]): value is Record<string, unknown> & {
|
|
20
|
+
siblingIndex: number;
|
|
21
|
+
};
|
|
19
22
|
interface ApplyOptions {
|
|
20
23
|
/** Keep a copy of each removed element an inline script looks up (stored deletes replayed onto a base). */
|
|
21
24
|
keepScriptTargets?: boolean;
|
|
@@ -122,6 +122,29 @@ export function applyOverrideSet(parsed, overrides) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
applyPatchesToDocument(parsed, patches, { keepScriptTargets: true });
|
|
125
|
+
restoreOverridePositions(parsed, overrides);
|
|
126
|
+
}
|
|
127
|
+
export function isElementSnapshotOverride(key, value) {
|
|
128
|
+
if (value === null || typeof value !== "object")
|
|
129
|
+
return false;
|
|
130
|
+
return /^\/elements\/[^/]+$/.test(keyToPath(key) ?? "") && typeof value.siblingIndex === "number";
|
|
131
|
+
}
|
|
132
|
+
function restoreOverridePositions(parsed, overrides) {
|
|
133
|
+
const positions = [];
|
|
134
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
135
|
+
if (!isElementSnapshotOverride(key, value) || typeof value.childNodeIndex !== "number")
|
|
136
|
+
continue;
|
|
137
|
+
const el = findById(parsed.document, key);
|
|
138
|
+
if (!el?.parentElement)
|
|
139
|
+
continue;
|
|
140
|
+
positions.push({ el, parent: el.parentElement, childNodeIndex: value.childNodeIndex });
|
|
141
|
+
}
|
|
142
|
+
// Detach every restored sibling so inserting one cannot shift another's saved position.
|
|
143
|
+
for (const { el } of positions)
|
|
144
|
+
el.remove();
|
|
145
|
+
for (const { el, parent, childNodeIndex } of positions.sort((a, b) => a.childNodeIndex - b.childNodeIndex)) {
|
|
146
|
+
parent.insertBefore(el, parent.childNodes[childNodeIndex] ?? null);
|
|
147
|
+
}
|
|
125
148
|
}
|
|
126
149
|
/** Keep a deleted node a script looks up: serialize writes it back hidden, so the script finds it. */
|
|
127
150
|
function keepDelete(parsed, el) {
|
|
@@ -235,7 +258,7 @@ function applyOne(parsed, patch, p, options) {
|
|
|
235
258
|
keepDelete(parsed, el);
|
|
236
259
|
el?.remove();
|
|
237
260
|
}
|
|
238
|
-
else if (patch.op === "add" && patch.value) {
|
|
261
|
+
else if ((patch.op === "add" || patch.op === "replace") && patch.value) {
|
|
239
262
|
const v = patch.value;
|
|
240
263
|
const parent = v.parentId
|
|
241
264
|
? findById(parsed.document, v.parentId)
|
|
@@ -248,6 +271,8 @@ function applyOne(parsed, patch, p, options) {
|
|
|
248
271
|
const node = tmp.firstElementChild;
|
|
249
272
|
if (!node)
|
|
250
273
|
return;
|
|
274
|
+
if (patch.op === "replace")
|
|
275
|
+
findById(parsed.document, p.id)?.remove();
|
|
251
276
|
const children = Array.from(parent.children);
|
|
252
277
|
const ref = children[v.siblingIndex] ?? null;
|
|
253
278
|
parent.insertBefore(node, ref);
|
package/dist/session.js
CHANGED
|
@@ -12,14 +12,14 @@ import { buildRoots, flatElements, parsedAnimationIds } from "./document.js";
|
|
|
12
12
|
import { syncFixFor, syncOffsetOf } from "./engine/syncTiming.js";
|
|
13
13
|
import { parseMutable } from "./engine/model.js";
|
|
14
14
|
import { applyOp, validateOp } from "./engine/mutate.js";
|
|
15
|
-
import { getGsapScripts, resolveScoped, declarationCarriers } from "./engine/model.js";
|
|
15
|
+
import { getGsapScripts, resolveScoped, declarationCarriers, getSiblingIndex, } from "./engine/model.js";
|
|
16
16
|
import { extractGsapLabels } from "@hyperframes/core/gsap-parser-acorn";
|
|
17
17
|
import { stripEmbeddedRuntimeScripts } from "@hyperframes/core/compiler/html-document";
|
|
18
18
|
import { readClipTiming } from "@hyperframes/core/composition-contract";
|
|
19
19
|
import { readDeclaredDefaults, validateVariables, scanVariableUsage, } from "@hyperframes/core/variables";
|
|
20
20
|
import { readVariableDeclarations } from "./engine/variableModel.js";
|
|
21
21
|
import { serializeDocument } from "./engine/serialize.js";
|
|
22
|
-
import { applyPatchesToDocument, applyOverrideSet } from "./engine/apply-patches.js";
|
|
22
|
+
import { applyPatchesToDocument, applyOverrideSet, isElementSnapshotOverride, } from "./engine/apply-patches.js";
|
|
23
23
|
import { buildPatchEvent, pathToKey } from "./engine/patches.js";
|
|
24
24
|
import { createHistory } from "./history.js";
|
|
25
25
|
import { createPersistQueue } from "./persist-queue.js";
|
|
@@ -276,9 +276,9 @@ class CompositionImpl {
|
|
|
276
276
|
allLabels = scripts.flatMap((script) => extractGsapLabels(script));
|
|
277
277
|
this._gsapLabelCache = scripts.length ? { scripts: [...scripts], labels: allLabels } : null;
|
|
278
278
|
}
|
|
279
|
-
// refId
|
|
280
|
-
// contract owns parsing, canonical
|
|
281
|
-
// legacy data-end
|
|
279
|
+
// refId resolves as a bare hf-id (top level first), unlike the runtime's
|
|
280
|
+
// composition-scoped `id` lookup. The shared contract owns parsing, canonical
|
|
281
|
+
// duration preference, clamping, and legacy data-end; this adapter only supplies lookup.
|
|
282
282
|
const timingCache = new Map();
|
|
283
283
|
const visiting = new Set();
|
|
284
284
|
const resolveTiming = (el) => {
|
|
@@ -488,6 +488,7 @@ class CompositionImpl {
|
|
|
488
488
|
for (const p of forward) {
|
|
489
489
|
const key = pathToKey(p.path);
|
|
490
490
|
if (key !== null) {
|
|
491
|
+
delete this.overrides[key];
|
|
491
492
|
this.overrides[key] =
|
|
492
493
|
p.op === "remove"
|
|
493
494
|
? null
|
|
@@ -649,7 +650,20 @@ class CompositionImpl {
|
|
|
649
650
|
}
|
|
650
651
|
// ── T3 embedded-mode extras ──────────────────────────────────────────────────
|
|
651
652
|
getOverrides() {
|
|
652
|
-
|
|
653
|
+
const overrides = { ...this.overrides };
|
|
654
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
655
|
+
if (!isElementSnapshotOverride(key, value))
|
|
656
|
+
continue;
|
|
657
|
+
const el = resolveScoped(this.parsed.document, key);
|
|
658
|
+
if (el?.parentElement) {
|
|
659
|
+
overrides[key] = {
|
|
660
|
+
...value,
|
|
661
|
+
siblingIndex: getSiblingIndex(el),
|
|
662
|
+
childNodeIndex: Array.from(el.parentElement.childNodes).indexOf(el),
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return overrides;
|
|
653
667
|
}
|
|
654
668
|
// fallow-ignore-next-line complexity
|
|
655
669
|
applyPatches(patches, opts) {
|
|
@@ -665,6 +679,7 @@ class CompositionImpl {
|
|
|
665
679
|
for (const p of patches) {
|
|
666
680
|
const key = pathToKey(p.path);
|
|
667
681
|
if (key !== null) {
|
|
682
|
+
delete this.overrides[key];
|
|
668
683
|
this.overrides[key] =
|
|
669
684
|
p.op === "remove"
|
|
670
685
|
? null
|
|
@@ -716,8 +731,6 @@ export async function openComposition(html, opts) {
|
|
|
716
731
|
// the authored base values are readable. getVariableValue({ base: true })
|
|
717
732
|
// serves them for the rest of the session (undo-to-base restores).
|
|
718
733
|
const baseVariableDefaults = declaredDefaults(parsed);
|
|
719
|
-
// T3 embedded: replay the stored override-set onto the base in one pass,
|
|
720
|
-
// so the session exposes the user's exact edited state — not the template.
|
|
721
734
|
if (opts?.overrides)
|
|
722
735
|
applyOverrideSet(parsed, opts.overrides);
|
|
723
736
|
const session = new CompositionImpl(parsed, opts ?? {}, baseVariableDefaults);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.194",
|
|
4
4
|
"description": "Headless, framework-neutral HyperFrames composition editing engine",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"linkedom": "^0.18.12",
|
|
47
|
-
"@hyperframes/
|
|
48
|
-
"@hyperframes/
|
|
47
|
+
"@hyperframes/core": "0.8.194",
|
|
48
|
+
"@hyperframes/parsers": "0.8.194"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "^25.0.10",
|