feat(sdk,studio): ws-1.2 — percentage-based removeGsapKeyframe (#1498)

* feat(sdk,studio): ws-1.2 — percentage-based removeGsapKeyframe

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>

* feat(sdk,studio): ws-1.3 — removeGsapProperty SDK op + Studio hook cutover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>

* feat(sdk,studio): ws-1.4 — deleteAllForSelector SDK op + Studio hook cutover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>

* fix(core): cascade-remove GSAP tweens in removeElementFromHtml (WS-2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>

---------

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>
This commit is contained in:
Vance Ingalls
2026-06-17 16:49:47 -07:00
committed by GitHub
co-authored by Miguel Ángel Claude Sonnet 4.6
parent a5016ed416
commit ceb815c318
9 changed files with 317 additions and 96 deletions
@@ -878,6 +878,27 @@ export function removeKeyframeFromScript(
return ms.toString();
}
export function removePropertyFromAnimation(
script: string,
animationId: string,
property: string,
from = false,
): string {
const parsed = parseGsapScriptAcornForWrite(script);
if (!parsed) return script;
const target = parsed.located.find((l) => l.id === animationId);
if (!target) return script;
const { call } = target;
const objNode = from ? (call.method === "fromTo" ? call.fromArg : null) : call.varsArg;
if (!objNode) return script;
const propNode = findPropertyNode(objNode, property);
if (!propNode) return script;
const allProps = (objNode.properties ?? []).filter((p: any) => isObjectProperty(p));
const ms = new MagicString(script);
removeProp(ms, propNode, allProps);
return ms.toString();
}
// ── Label write ops ───────────────────────────────────────────────────────────
export function addLabelToScript(script: string, name: string, position: number): string {
+33 -6
View File
@@ -12,6 +12,8 @@ import type {
} from "../core.types";
import { validateCompositionGsap } from "./gsapSerialize";
import { ensureHfIds } from "./hfIds.js";
import { parseGsapScriptAcornForWrite } from "./gsapParserAcorn.js";
import { removeAnimationFromScript } from "./gsapWriterAcorn.js";
import type { ValidationResult } from "../core.types";
const MEDIA_TYPES = new Set<string>(["video", "image", "audio"]);
@@ -672,15 +674,40 @@ export function addElementToHtml(
};
}
function selectorTargetsId(selector: string, id: string): boolean {
return (
selector === `#${id}` ||
selector === `[data-hf-id="${id}"]` ||
selector === `[data-hf-id='${id}']`
);
}
function stripGsapForId(script: string, elementId: string): string {
const parsed = parseGsapScriptAcornForWrite(script);
if (!parsed) return script;
let current = script;
for (const { id: animId, animation } of parsed.located) {
if (selectorTargetsId(animation.targetSelector, elementId)) {
current = removeAnimationFromScript(current, animId);
}
}
return current;
}
function cascadeRemoveGsapById(doc: Document, elementId: string): void {
for (const script of Array.from(doc.querySelectorAll("script"))) {
const text = script.textContent ?? "";
if (!text.includes("gsap") && !text.includes("ScrollTrigger")) continue;
const updated = stripGsapForId(text, elementId);
if (updated !== text) script.textContent = updated;
}
}
export function removeElementFromHtml(html: string, elementId: string): string {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const el = doc.getElementById(elementId);
if (el) {
el.remove();
}
doc.getElementById(elementId)?.remove();
cascadeRemoveGsapById(doc, elementId);
return "<!DOCTYPE html>\n" + doc.documentElement.outerHTML;
}