@hyperframes/core 0.6.97 → 0.6.98
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/beats/beatDetection.d.ts +22 -0
- package/dist/beats/beatDetection.d.ts.map +1 -0
- package/dist/beats/beatDetection.js +246 -0
- package/dist/beats/beatDetection.js.map +1 -0
- package/dist/beats/beatFile.d.ts +18 -0
- package/dist/beats/beatFile.d.ts.map +1 -0
- package/dist/beats/beatFile.js +112 -0
- package/dist/beats/beatFile.js.map +1 -0
- package/dist/beats/index.d.ts +3 -0
- package/dist/beats/index.d.ts.map +1 -0
- package/dist/beats/index.js +3 -0
- package/dist/beats/index.js.map +1 -0
- package/dist/compiler/htmlBundler.d.ts +0 -9
- package/dist/compiler/htmlBundler.d.ts.map +1 -1
- package/dist/compiler/htmlBundler.js +70 -92
- package/dist/compiler/htmlBundler.js.map +1 -1
- package/dist/compiler/rewriteSubCompPaths.d.ts.map +1 -1
- package/dist/compiler/rewriteSubCompPaths.js +3 -11
- package/dist/compiler/rewriteSubCompPaths.js.map +1 -1
- package/dist/core.types.d.ts +0 -5
- package/dist/core.types.d.ts.map +1 -1
- package/dist/core.types.js +0 -15
- package/dist/core.types.js.map +1 -1
- package/dist/fonts/systemFontLocator.d.ts +1 -0
- package/dist/fonts/systemFontLocator.d.ts.map +1 -1
- package/dist/fonts/systemFontLocator.js +8 -2
- package/dist/fonts/systemFontLocator.js.map +1 -1
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/generators/hyperframes.d.ts.map +1 -1
- package/dist/generators/hyperframes.js +21 -18
- package/dist/generators/hyperframes.js.map +1 -1
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +22 -22
- package/dist/hyperframe.runtime.mjs +22 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lint/hyperframeLinter.d.ts +0 -11
- package/dist/lint/hyperframeLinter.d.ts.map +1 -1
- package/dist/lint/hyperframeLinter.js +0 -73
- package/dist/lint/hyperframeLinter.js.map +1 -1
- package/dist/lint/rules/adapters.d.ts.map +1 -1
- package/dist/lint/rules/adapters.js +9 -15
- package/dist/lint/rules/adapters.js.map +1 -1
- package/dist/lint/rules/composition.d.ts.map +1 -1
- package/dist/lint/rules/composition.js +2 -3
- package/dist/lint/rules/composition.js.map +1 -1
- package/dist/lint/rules/core.d.ts.map +1 -1
- package/dist/lint/rules/core.js +2 -3
- package/dist/lint/rules/core.js.map +1 -1
- package/dist/lint/rules/gsap.d.ts.map +1 -1
- package/dist/lint/rules/gsap.js +13 -67
- package/dist/lint/rules/gsap.js.map +1 -1
- package/dist/lint/utils.d.ts +5 -0
- package/dist/lint/utils.d.ts.map +1 -1
- package/dist/lint/utils.js +64 -0
- package/dist/lint/utils.js.map +1 -1
- package/dist/parsers/gsapParser.d.ts +2 -0
- package/dist/parsers/gsapParser.d.ts.map +1 -1
- package/dist/parsers/gsapParser.js +143 -140
- package/dist/parsers/gsapParser.js.map +1 -1
- package/dist/parsers/gsapSerialize.d.ts +2 -0
- package/dist/parsers/gsapSerialize.d.ts.map +1 -1
- package/dist/parsers/gsapSerialize.js +6 -5
- package/dist/parsers/gsapSerialize.js.map +1 -1
- package/dist/parsers/htmlParser.d.ts.map +1 -1
- package/dist/parsers/htmlParser.js +13 -18
- package/dist/parsers/htmlParser.js.map +1 -1
- package/dist/studio-api/helpers/sourceMutation.d.ts +1 -0
- package/dist/studio-api/helpers/sourceMutation.d.ts.map +1 -1
- package/dist/studio-api/helpers/sourceMutation.js +2 -2
- package/dist/studio-api/helpers/sourceMutation.js.map +1 -1
- package/dist/studio-api/routes/files.d.ts.map +1 -1
- package/dist/studio-api/routes/files.js +60 -48
- package/dist/studio-api/routes/files.js.map +1 -1
- package/dist/studio-api/routes/fonts.d.ts.map +1 -1
- package/dist/studio-api/routes/fonts.js +2 -47
- package/dist/studio-api/routes/fonts.js.map +1 -1
- package/package.json +2 -1
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import * as recast from "recast";
|
|
12
12
|
import { parse as babelParse } from "@babel/parser";
|
|
13
|
+
import { serializeValue as valueToCode, safeJsKey as safeKey, } from "./gsapSerialize";
|
|
13
14
|
export { serializeGsapAnimations, getAnimationsForElementId, validateCompositionGsap, keyframesToGsapAnimations, gsapAnimationsToKeyframes, SUPPORTED_PROPS, SUPPORTED_EASES, } from "./gsapSerialize";
|
|
14
15
|
export { PROPERTY_GROUPS, classifyPropertyGroup, classifyTweenPropertyGroup, } from "./gsapConstants";
|
|
15
16
|
import { classifyPropertyGroup, classifyTweenPropertyGroup } from "./gsapConstants";
|
|
@@ -166,15 +167,17 @@ function collectTargetBindings(ast, scope) {
|
|
|
166
167
|
visitVariableDeclarator(path) {
|
|
167
168
|
const name = path.node.id?.name;
|
|
168
169
|
const selector = selectorFromQueryCall(path.node.init, scope);
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
const scopeNode = enclosingScopeNode(path);
|
|
171
|
+
if (name && selector !== null && scopeNode)
|
|
172
|
+
addBinding(bindings, scopeNode, name, selector);
|
|
171
173
|
this.traverse(path);
|
|
172
174
|
},
|
|
173
175
|
visitAssignmentExpression(path) {
|
|
174
176
|
const left = path.node.left;
|
|
175
177
|
const selector = selectorFromQueryCall(path.node.right, scope);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
const scopeNode = enclosingScopeNode(path);
|
|
179
|
+
if (left?.type === "Identifier" && selector !== null && scopeNode) {
|
|
180
|
+
addBinding(bindings, scopeNode, left.name, selector);
|
|
178
181
|
}
|
|
179
182
|
this.traverse(path);
|
|
180
183
|
},
|
|
@@ -782,7 +785,7 @@ function tweenCallToAnimation(call, scope) {
|
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
787
|
const hasPositionArg = !!call.positionArg;
|
|
785
|
-
const posVal =
|
|
788
|
+
const posVal = call.positionArg ? extractLiteralValue(call.positionArg, scope) : 0;
|
|
786
789
|
const position = typeof posVal === "number" ? posVal : typeof posVal === "string" ? posVal : 0;
|
|
787
790
|
let duration = typeof vars.duration === "number" ? vars.duration : undefined;
|
|
788
791
|
const ease = typeof vars.ease === "string" ? vars.ease : undefined;
|
|
@@ -982,17 +985,6 @@ export function parseGsapScript(script) {
|
|
|
982
985
|
// which preserves every untouched statement. This is what lets us edit tweens
|
|
983
986
|
// in real compositions (variable targets, interleaved `gsap.set`, IIFE wrapper)
|
|
984
987
|
// without regenerating — and discarding — the surrounding code.
|
|
985
|
-
/** Render a model value to the JS source it should emit as. Mirrors gsapSerialize. */
|
|
986
|
-
function valueToCode(value) {
|
|
987
|
-
if (typeof value === "string" && value.startsWith("__raw:"))
|
|
988
|
-
return value.slice(6);
|
|
989
|
-
if (typeof value === "string")
|
|
990
|
-
return JSON.stringify(value);
|
|
991
|
-
return String(value);
|
|
992
|
-
}
|
|
993
|
-
function safeKey(key) {
|
|
994
|
-
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
995
|
-
}
|
|
996
988
|
/**
|
|
997
989
|
* Parse a value/expression snippet into a standalone AST expression node.
|
|
998
990
|
* Uses an assignment (`__hf__ = <code>`) rather than wrapping in parens so an
|
|
@@ -1058,24 +1050,26 @@ function reconcileEditableProperties(varsArg, newProps) {
|
|
|
1058
1050
|
setVarsKey(varsArg, key, value);
|
|
1059
1051
|
}
|
|
1060
1052
|
}
|
|
1053
|
+
function applyEaseUpdate(varsArg, ease) {
|
|
1054
|
+
const kfNode = findKeyframesObjectNode(varsArg);
|
|
1055
|
+
if (kfNode) {
|
|
1056
|
+
setVarsKey(kfNode, "easeEach", ease);
|
|
1057
|
+
removeVarsKey(varsArg, "ease");
|
|
1058
|
+
}
|
|
1059
|
+
else {
|
|
1060
|
+
setVarsKey(varsArg, "ease", ease);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1061
1063
|
function applyUpdatesToCall(call, updates) {
|
|
1062
1064
|
if (updates.properties)
|
|
1063
1065
|
reconcileEditableProperties(call.varsArg, updates.properties);
|
|
1064
|
-
if (updates.fromProperties && call.method === "fromTo") {
|
|
1066
|
+
if (updates.fromProperties && call.method === "fromTo" && call.fromArg) {
|
|
1065
1067
|
reconcileEditableProperties(call.fromArg, updates.fromProperties);
|
|
1066
1068
|
}
|
|
1067
1069
|
if (updates.duration !== undefined)
|
|
1068
1070
|
setVarsKey(call.varsArg, "duration", updates.duration);
|
|
1069
|
-
if (updates.ease !== undefined)
|
|
1070
|
-
|
|
1071
|
-
if (kfNode) {
|
|
1072
|
-
setVarsKey(kfNode, "easeEach", updates.ease);
|
|
1073
|
-
removeVarsKey(call.varsArg, "ease");
|
|
1074
|
-
}
|
|
1075
|
-
else {
|
|
1076
|
-
setVarsKey(call.varsArg, "ease", updates.ease);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1071
|
+
if (updates.ease !== undefined)
|
|
1072
|
+
applyEaseUpdate(call.varsArg, updates.ease);
|
|
1079
1073
|
if (updates.position !== undefined) {
|
|
1080
1074
|
const posIdx = call.method === "fromTo" ? 3 : 2;
|
|
1081
1075
|
call.node.arguments[posIdx] = parseExpr(valueToCode(updates.position));
|
|
@@ -1091,6 +1085,18 @@ function findStatementPath(path) {
|
|
|
1091
1085
|
}
|
|
1092
1086
|
return null;
|
|
1093
1087
|
}
|
|
1088
|
+
function insertAfterAnchor(parsed, newStatement) {
|
|
1089
|
+
const lastCall = parsed.located[parsed.located.length - 1]?.call;
|
|
1090
|
+
const anchorPath = lastCall
|
|
1091
|
+
? findStatementPath(lastCall.path)
|
|
1092
|
+
: findTimelineDeclarationPath(parsed.ast, parsed.timelineVar);
|
|
1093
|
+
if (anchorPath) {
|
|
1094
|
+
anchorPath.insertAfter(newStatement);
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
parsed.ast.program.body.push(newStatement);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1094
1100
|
/** Build the source for a single `tl.method(selector, vars, position)` call. */
|
|
1095
1101
|
function buildTweenStatementCode(timelineVar, anim) {
|
|
1096
1102
|
const selector = JSON.stringify(anim.targetSelector);
|
|
@@ -1130,6 +1136,55 @@ export function updateAnimationInScript(script, animationId, updates) {
|
|
|
1130
1136
|
applyUpdatesToCall(target.call, updates);
|
|
1131
1137
|
return recast.print(parsed.ast).code;
|
|
1132
1138
|
}
|
|
1139
|
+
export function shiftPositionsInScript(script, targetSelector, delta) {
|
|
1140
|
+
let parsed;
|
|
1141
|
+
try {
|
|
1142
|
+
parsed = parseGsapAst(script);
|
|
1143
|
+
}
|
|
1144
|
+
catch (e) {
|
|
1145
|
+
console.warn("[gsap-parser] shiftPositionsInScript parse failed:", e);
|
|
1146
|
+
return script;
|
|
1147
|
+
}
|
|
1148
|
+
let changed = false;
|
|
1149
|
+
for (const entry of parsed.located) {
|
|
1150
|
+
if (entry.animation.targetSelector !== targetSelector)
|
|
1151
|
+
continue;
|
|
1152
|
+
if (typeof entry.animation.position !== "number")
|
|
1153
|
+
continue;
|
|
1154
|
+
const newPos = Math.max(0, Math.round((entry.animation.position + delta) * 1000) / 1000);
|
|
1155
|
+
applyUpdatesToCall(entry.call, { position: newPos });
|
|
1156
|
+
changed = true;
|
|
1157
|
+
}
|
|
1158
|
+
return changed ? recast.print(parsed.ast).code : script;
|
|
1159
|
+
}
|
|
1160
|
+
export function scalePositionsInScript(script, targetSelector, oldStart, oldDuration, newStart, newDuration) {
|
|
1161
|
+
if (oldDuration <= 0 || newDuration <= 0)
|
|
1162
|
+
return script;
|
|
1163
|
+
const ratio = newDuration / oldDuration;
|
|
1164
|
+
let parsed;
|
|
1165
|
+
try {
|
|
1166
|
+
parsed = parseGsapAst(script);
|
|
1167
|
+
}
|
|
1168
|
+
catch (e) {
|
|
1169
|
+
console.warn("[gsap-parser] scalePositionsInScript parse failed:", e);
|
|
1170
|
+
return script;
|
|
1171
|
+
}
|
|
1172
|
+
let changed = false;
|
|
1173
|
+
for (const entry of parsed.located) {
|
|
1174
|
+
if (entry.animation.targetSelector !== targetSelector)
|
|
1175
|
+
continue;
|
|
1176
|
+
if (typeof entry.animation.position !== "number")
|
|
1177
|
+
continue;
|
|
1178
|
+
const newPos = Math.max(0, Math.round((newStart + (entry.animation.position - oldStart) * ratio) * 1000) / 1000);
|
|
1179
|
+
const updates = { position: newPos };
|
|
1180
|
+
if (typeof entry.animation.duration === "number" && entry.animation.duration > 0) {
|
|
1181
|
+
updates.duration = Math.max(0.001, Math.round(entry.animation.duration * ratio * 1000) / 1000);
|
|
1182
|
+
}
|
|
1183
|
+
applyUpdatesToCall(entry.call, updates);
|
|
1184
|
+
changed = true;
|
|
1185
|
+
}
|
|
1186
|
+
return changed ? recast.print(parsed.ast).code : script;
|
|
1187
|
+
}
|
|
1133
1188
|
function updateAnimationSelector(script, animationId, newSelector) {
|
|
1134
1189
|
let parsed;
|
|
1135
1190
|
try {
|
|
@@ -1166,16 +1221,7 @@ export function addAnimationToScript(script, animation) {
|
|
|
1166
1221
|
const id = `anim-${Date.now()}`;
|
|
1167
1222
|
const statementCode = buildTweenStatementCode(parsed.timelineVar, animation);
|
|
1168
1223
|
const newStatement = parseScript(statementCode).program.body[0];
|
|
1169
|
-
|
|
1170
|
-
const anchorPath = lastCall
|
|
1171
|
-
? findStatementPath(lastCall.path)
|
|
1172
|
-
: findTimelineDeclarationPath(parsed.ast, parsed.timelineVar);
|
|
1173
|
-
if (anchorPath) {
|
|
1174
|
-
anchorPath.insertAfter(newStatement);
|
|
1175
|
-
}
|
|
1176
|
-
else {
|
|
1177
|
-
parsed.ast.program.body.push(newStatement);
|
|
1178
|
-
}
|
|
1224
|
+
insertAfterAnchor(parsed, newStatement);
|
|
1179
1225
|
return { script: recast.print(parsed.ast).code, id };
|
|
1180
1226
|
}
|
|
1181
1227
|
export function addAnimationWithKeyframesToScript(script, targetSelector, position, duration, keyframes, ease) {
|
|
@@ -1191,31 +1237,14 @@ export function addAnimationWithKeyframesToScript(script, targetSelector, positi
|
|
|
1191
1237
|
return { script, id: "" };
|
|
1192
1238
|
}
|
|
1193
1239
|
const selector = JSON.stringify(targetSelector);
|
|
1194
|
-
const
|
|
1195
|
-
const propEntries = Object.entries(kf.properties).map(([k, v]) => `${safeKey(k)}: ${valueToCode(v)}`);
|
|
1196
|
-
if (kf.ease)
|
|
1197
|
-
propEntries.push(`ease: ${JSON.stringify(kf.ease)}`);
|
|
1198
|
-
if (kf.auto)
|
|
1199
|
-
propEntries.push(`_auto: 1`);
|
|
1200
|
-
return `${JSON.stringify(`${kf.percentage}%`)}: { ${propEntries.join(", ")} }`;
|
|
1201
|
-
});
|
|
1202
|
-
const kfCode = `{ ${kfEntries.join(", ")} }`;
|
|
1240
|
+
const kfCode = buildKeyframeObjectCode(keyframes);
|
|
1203
1241
|
const varEntries = [`keyframes: ${kfCode}`, `duration: ${valueToCode(duration)}`];
|
|
1204
1242
|
if (ease)
|
|
1205
1243
|
varEntries.push(`ease: ${JSON.stringify(ease)}`);
|
|
1206
1244
|
const posCode = valueToCode(position);
|
|
1207
1245
|
const stmtCode = `${parsed.timelineVar}.to(${selector}, { ${varEntries.join(", ")} }, ${posCode});`;
|
|
1208
1246
|
const newStatement = parseScript(stmtCode).program.body[0];
|
|
1209
|
-
|
|
1210
|
-
const anchorPath = lastCall
|
|
1211
|
-
? findStatementPath(lastCall.path)
|
|
1212
|
-
: findTimelineDeclarationPath(parsed.ast, parsed.timelineVar);
|
|
1213
|
-
if (anchorPath) {
|
|
1214
|
-
anchorPath.insertAfter(newStatement);
|
|
1215
|
-
}
|
|
1216
|
-
else {
|
|
1217
|
-
parsed.ast.program.body.push(newStatement);
|
|
1218
|
-
}
|
|
1247
|
+
insertAfterAnchor(parsed, newStatement);
|
|
1219
1248
|
const result = recast.print(parsed.ast).code;
|
|
1220
1249
|
const reParsed = parseGsapAst(result);
|
|
1221
1250
|
const newId = reParsed.located[reParsed.located.length - 1]?.id ?? "";
|
|
@@ -1434,6 +1463,19 @@ function sortedKeyframes(kfs) {
|
|
|
1434
1463
|
function keyframePropsToCode(kf) {
|
|
1435
1464
|
return Object.entries(kf.properties).map(([k, v]) => `${safeKey(k)}: ${valueToCode(v)}`);
|
|
1436
1465
|
}
|
|
1466
|
+
function buildKeyframeObjectCode(keyframes, options) {
|
|
1467
|
+
const entries = keyframes.map((kf) => {
|
|
1468
|
+
const props = keyframePropsToCode(kf);
|
|
1469
|
+
if (kf.ease)
|
|
1470
|
+
props.push(`ease: ${JSON.stringify(kf.ease)}`);
|
|
1471
|
+
if (kf.auto)
|
|
1472
|
+
props.push(`_auto: 1`);
|
|
1473
|
+
return `${JSON.stringify(`${kf.percentage}%`)}: { ${props.join(", ")} }`;
|
|
1474
|
+
});
|
|
1475
|
+
if (options?.easeEach)
|
|
1476
|
+
entries.push(`easeEach: ${JSON.stringify(options.easeEach)}`);
|
|
1477
|
+
return `{ ${entries.join(", ")} }`;
|
|
1478
|
+
}
|
|
1437
1479
|
/** Remove a named property from an ObjectExpression's properties array. */
|
|
1438
1480
|
function removeVarsKey(varsArg, key) {
|
|
1439
1481
|
if (varsArg?.type !== "ObjectExpression")
|
|
@@ -1481,6 +1523,15 @@ function locateAnimation(script, animationId) {
|
|
|
1481
1523
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
1482
1524
|
return target ? { parsed, target } : null;
|
|
1483
1525
|
}
|
|
1526
|
+
function locateAnimationWithFallback(script, animationId) {
|
|
1527
|
+
const loc = locateAnimation(script, animationId);
|
|
1528
|
+
if (loc)
|
|
1529
|
+
return loc;
|
|
1530
|
+
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1531
|
+
if (convertedId === animationId)
|
|
1532
|
+
return null;
|
|
1533
|
+
return locateAnimation(script, convertedId);
|
|
1534
|
+
}
|
|
1484
1535
|
/** Find the keyframes ObjectExpression node on a tween's varsArg, or null. */
|
|
1485
1536
|
function findKeyframesObjectNode(varsArg) {
|
|
1486
1537
|
const node = findPropertyNode(varsArg, "keyframes");
|
|
@@ -1516,11 +1567,7 @@ function collapseKeyframesToFlat(varsArg, record) {
|
|
|
1516
1567
|
* updateKeyframeInScript.
|
|
1517
1568
|
*/
|
|
1518
1569
|
function locateKeyframeCtx(script, animationId, percentage) {
|
|
1519
|
-
|
|
1520
|
-
if (!loc) {
|
|
1521
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1522
|
-
loc = locateAnimation(script, convertedId);
|
|
1523
|
-
}
|
|
1570
|
+
const loc = locateAnimationWithFallback(script, animationId);
|
|
1524
1571
|
if (!loc)
|
|
1525
1572
|
return null;
|
|
1526
1573
|
const kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
|
|
@@ -1533,21 +1580,13 @@ function locateKeyframeCtx(script, animationId, percentage) {
|
|
|
1533
1580
|
* object. If the percentage already exists, its value is replaced.
|
|
1534
1581
|
*/
|
|
1535
1582
|
export function addKeyframeToScript(script, animationId, percentage, properties, ease, backfillDefaults) {
|
|
1536
|
-
let loc =
|
|
1537
|
-
if (!loc) {
|
|
1538
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1539
|
-
loc = locateAnimation(script, convertedId);
|
|
1540
|
-
}
|
|
1583
|
+
let loc = locateAnimationWithFallback(script, animationId);
|
|
1541
1584
|
if (!loc)
|
|
1542
1585
|
return script;
|
|
1543
1586
|
let kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
|
|
1544
1587
|
if (!kfNode) {
|
|
1545
1588
|
script = convertToKeyframesInScript(script, animationId);
|
|
1546
|
-
loc =
|
|
1547
|
-
if (!loc) {
|
|
1548
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1549
|
-
loc = locateAnimation(script, convertedId);
|
|
1550
|
-
}
|
|
1589
|
+
loc = locateAnimationWithFallback(script, animationId);
|
|
1551
1590
|
if (!loc)
|
|
1552
1591
|
return script;
|
|
1553
1592
|
kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
|
|
@@ -1626,7 +1665,9 @@ export function addKeyframeToScript(script, animationId, percentage, properties,
|
|
|
1626
1665
|
const valObj = prop.value;
|
|
1627
1666
|
if (!valObj || valObj.type !== "ObjectExpression")
|
|
1628
1667
|
continue;
|
|
1629
|
-
const existingKeys = new Set(valObj.properties
|
|
1668
|
+
const existingKeys = new Set(valObj.properties
|
|
1669
|
+
.filter((p) => isObjectProperty(p))
|
|
1670
|
+
.map((p) => propKeyName(p)));
|
|
1630
1671
|
for (const pk of newPropKeys) {
|
|
1631
1672
|
if (existingKeys.has(pk))
|
|
1632
1673
|
continue;
|
|
@@ -1761,11 +1802,7 @@ function insertKeyframesProp(varsArg, fromProps, toProps, easeEach) {
|
|
|
1761
1802
|
* the "to" state for `from()` tweens (the values the DOM would resolve to).
|
|
1762
1803
|
*/
|
|
1763
1804
|
export function convertToKeyframesInScript(script, animationId, resolvedFromValues) {
|
|
1764
|
-
let loc =
|
|
1765
|
-
if (!loc) {
|
|
1766
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1767
|
-
loc = locateAnimation(script, convertedId);
|
|
1768
|
-
}
|
|
1805
|
+
let loc = locateAnimationWithFallback(script, animationId);
|
|
1769
1806
|
if (!loc)
|
|
1770
1807
|
return script;
|
|
1771
1808
|
const anim = loc.target.animation;
|
|
@@ -1792,11 +1829,7 @@ export function convertToKeyframesInScript(script, animationId, resolvedFromValu
|
|
|
1792
1829
|
* last keyframe's properties.
|
|
1793
1830
|
*/
|
|
1794
1831
|
export function removeAllKeyframesFromScript(script, animationId) {
|
|
1795
|
-
let loc =
|
|
1796
|
-
if (!loc) {
|
|
1797
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1798
|
-
loc = locateAnimation(script, convertedId);
|
|
1799
|
-
}
|
|
1832
|
+
let loc = locateAnimationWithFallback(script, animationId);
|
|
1800
1833
|
if (!loc)
|
|
1801
1834
|
return script;
|
|
1802
1835
|
const kfNode = findKeyframesObjectNode(loc.target.call.varsArg);
|
|
@@ -1821,11 +1854,7 @@ export function removeAllKeyframesFromScript(script, animationId) {
|
|
|
1821
1854
|
* Called when the user first edits a dynamically-generated keyframe in the studio.
|
|
1822
1855
|
*/
|
|
1823
1856
|
export function materializeKeyframesInScript(script, animationId, keyframes, easeEach, resolvedSelector) {
|
|
1824
|
-
let loc =
|
|
1825
|
-
if (!loc) {
|
|
1826
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
1827
|
-
loc = locateAnimation(script, convertedId);
|
|
1828
|
-
}
|
|
1857
|
+
let loc = locateAnimationWithFallback(script, animationId);
|
|
1829
1858
|
if (!loc)
|
|
1830
1859
|
return script;
|
|
1831
1860
|
const varsArg = loc.target.call.varsArg;
|
|
@@ -1833,17 +1862,7 @@ export function materializeKeyframesInScript(script, animationId, keyframes, eas
|
|
|
1833
1862
|
if (resolvedSelector && loc.target.call.node.arguments[0]) {
|
|
1834
1863
|
loc.target.call.node.arguments[0] = parseExpr(JSON.stringify(resolvedSelector));
|
|
1835
1864
|
}
|
|
1836
|
-
const
|
|
1837
|
-
for (const kf of sortedKeyframes(keyframes)) {
|
|
1838
|
-
const propEntries = keyframePropsToCode(kf);
|
|
1839
|
-
if (kf.ease)
|
|
1840
|
-
propEntries.push(`ease: ${JSON.stringify(kf.ease)}`);
|
|
1841
|
-
entries.push(`${JSON.stringify(kf.percentage + "%")}: { ${propEntries.join(", ")} }`);
|
|
1842
|
-
}
|
|
1843
|
-
if (easeEach) {
|
|
1844
|
-
entries.push(`easeEach: ${JSON.stringify(easeEach)}`);
|
|
1845
|
-
}
|
|
1846
|
-
const kfObjCode = `{ ${entries.join(", ")} }`;
|
|
1865
|
+
const kfObjCode = buildKeyframeObjectCode(sortedKeyframes(keyframes), { easeEach });
|
|
1847
1866
|
const kfParent = varsArg.properties.find((p) => isObjectProperty(p) && propKeyName(p) === "keyframes");
|
|
1848
1867
|
if (kfParent) {
|
|
1849
1868
|
kfParent.value = parseExpr(kfObjCode);
|
|
@@ -1856,6 +1875,25 @@ export function materializeKeyframesInScript(script, animationId, keyframes, eas
|
|
|
1856
1875
|
return recast.print(loc.parsed.ast).code;
|
|
1857
1876
|
}
|
|
1858
1877
|
// ── Arc Path (motionPath) AST Mutations ──────────────────────────────────
|
|
1878
|
+
function numericXY(props) {
|
|
1879
|
+
const x = props.x;
|
|
1880
|
+
const y = props.y;
|
|
1881
|
+
return typeof x === "number" && typeof y === "number" ? { x, y } : null;
|
|
1882
|
+
}
|
|
1883
|
+
function extractArcWaypoints(anim) {
|
|
1884
|
+
const kfs = anim.keyframes?.keyframes ?? [];
|
|
1885
|
+
const waypoints = kfs.map((kf) => numericXY(kf.properties)).filter((p) => p !== null);
|
|
1886
|
+
if (waypoints.length >= 2)
|
|
1887
|
+
return waypoints;
|
|
1888
|
+
const px = anim.properties.x;
|
|
1889
|
+
const py = anim.properties.y;
|
|
1890
|
+
if (typeof px !== "number" && typeof py !== "number")
|
|
1891
|
+
return waypoints;
|
|
1892
|
+
return [
|
|
1893
|
+
{ x: 0, y: 0 },
|
|
1894
|
+
{ x: typeof px === "number" ? px : 0, y: typeof py === "number" ? py : 0 },
|
|
1895
|
+
];
|
|
1896
|
+
}
|
|
1859
1897
|
function buildMotionPathObjectCode(config) {
|
|
1860
1898
|
const { waypoints, segments, autoRotate } = config;
|
|
1861
1899
|
const hasExplicitControlPoints = segments.some((s) => s.cp1 && s.cp2);
|
|
@@ -1935,25 +1973,7 @@ export function setArcPathInScript(script, animationId, config) {
|
|
|
1935
1973
|
removeVarsKey(varsArg, "motionPath");
|
|
1936
1974
|
return recast.print(loc.parsed.ast).code;
|
|
1937
1975
|
}
|
|
1938
|
-
|
|
1939
|
-
const kfs = anim.keyframes?.keyframes ?? [];
|
|
1940
|
-
const waypoints = [];
|
|
1941
|
-
for (const kf of kfs) {
|
|
1942
|
-
const x = typeof kf.properties.x === "number" ? kf.properties.x : undefined;
|
|
1943
|
-
const y = typeof kf.properties.y === "number" ? kf.properties.y : undefined;
|
|
1944
|
-
if (x !== undefined && y !== undefined)
|
|
1945
|
-
waypoints.push({ x, y });
|
|
1946
|
-
}
|
|
1947
|
-
// For flat tweens with x/y in properties, synthesize start → end waypoints
|
|
1948
|
-
if (waypoints.length < 2) {
|
|
1949
|
-
const px = anim.properties.x;
|
|
1950
|
-
const py = anim.properties.y;
|
|
1951
|
-
if (typeof px === "number" || typeof py === "number") {
|
|
1952
|
-
waypoints.length = 0;
|
|
1953
|
-
waypoints.push({ x: 0, y: 0 });
|
|
1954
|
-
waypoints.push({ x: typeof px === "number" ? px : 0, y: typeof py === "number" ? py : 0 });
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1976
|
+
const waypoints = extractArcWaypoints(anim);
|
|
1957
1977
|
if (waypoints.length < 2)
|
|
1958
1978
|
return script;
|
|
1959
1979
|
// Build segments — use provided segments or create defaults
|
|
@@ -2003,15 +2023,7 @@ export function updateArcSegmentInScript(script, animationId, segmentIndex, upda
|
|
|
2003
2023
|
if (segmentIndex < 0 || segmentIndex >= segments.length)
|
|
2004
2024
|
return script;
|
|
2005
2025
|
segments[segmentIndex] = { ...segments[segmentIndex], ...update };
|
|
2006
|
-
|
|
2007
|
-
const kfs = anim.keyframes?.keyframes ?? [];
|
|
2008
|
-
const waypoints = [];
|
|
2009
|
-
for (const kf of kfs) {
|
|
2010
|
-
const x = typeof kf.properties.x === "number" ? kf.properties.x : undefined;
|
|
2011
|
-
const y = typeof kf.properties.y === "number" ? kf.properties.y : undefined;
|
|
2012
|
-
if (x !== undefined && y !== undefined)
|
|
2013
|
-
waypoints.push({ x, y });
|
|
2014
|
-
}
|
|
2026
|
+
const waypoints = extractArcWaypoints(anim);
|
|
2015
2027
|
if (waypoints.length < 2)
|
|
2016
2028
|
return script;
|
|
2017
2029
|
const motionPathCode = buildMotionPathObjectCode({
|
|
@@ -2043,11 +2055,7 @@ export function removeArcPathFromScript(script, animationId) {
|
|
|
2043
2055
|
*/
|
|
2044
2056
|
// fallow-ignore-next-line complexity
|
|
2045
2057
|
export function splitIntoPropertyGroups(script, animationId) {
|
|
2046
|
-
let loc =
|
|
2047
|
-
if (!loc) {
|
|
2048
|
-
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
2049
|
-
loc = locateAnimation(script, convertedId);
|
|
2050
|
-
}
|
|
2058
|
+
let loc = locateAnimationWithFallback(script, animationId);
|
|
2051
2059
|
if (!loc)
|
|
2052
2060
|
return { script, ids: [animationId] };
|
|
2053
2061
|
const anim = loc.target.animation;
|
|
@@ -2208,15 +2216,10 @@ export function unrollDynamicAnimations(script, animationId, elements) {
|
|
|
2208
2216
|
// Build replacement code: individual tl.to() calls for each element
|
|
2209
2217
|
const calls = [];
|
|
2210
2218
|
for (const el of elements) {
|
|
2211
|
-
const
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
}
|
|
2216
|
-
if (el.easeEach) {
|
|
2217
|
-
kfEntries.push(`easeEach: ${JSON.stringify(el.easeEach)}`);
|
|
2218
|
-
}
|
|
2219
|
-
calls.push(`${loc.parsed.timelineVar}.to(${JSON.stringify(el.selector)}, { keyframes: { ${kfEntries.join(", ")} }, duration: ${duration}, ease: ${JSON.stringify(ease)} }, ${posCode});`);
|
|
2219
|
+
const kfCode = buildKeyframeObjectCode(sortedKeyframes(el.keyframes), {
|
|
2220
|
+
easeEach: el.easeEach,
|
|
2221
|
+
});
|
|
2222
|
+
calls.push(`${loc.parsed.timelineVar}.to(${JSON.stringify(el.selector)}, { keyframes: ${kfCode}, duration: ${duration}, ease: ${JSON.stringify(ease)} }, ${posCode});`);
|
|
2220
2223
|
}
|
|
2221
2224
|
const replacement = calls.join("\n ");
|
|
2222
2225
|
if (loopNode) {
|