fix(studio): surface fromTo from-state in GSAP design panel (#1122)

* fix(studio): surface fromTo from-state in GSAP design panel

Closes #1121.

The core already parsed, serialized, and mutated fromProperties end to end
(gsapParser.ts, applyUpdatesToCall, buildTweenStatementCode). The panel
never wired it in — AnimationCard only read animation.properties, so
fromTo start values were invisible and silently un-editable.

Changes:
- files.ts: add update-from-property / add-from-property /
  remove-from-property mutation types; pass fromProperties through the
  add case; add fromTo to the method union
- useGsapScriptCommits: updateGsapFromProperty, addGsapFromProperty,
  removeGsapFromProperty; addGsapAnimation extended to fromTo with
  { opacity:0 } → { opacity:1 } defaults
- gsapAnimationConstants: fromTo added to ADD_METHODS / ADD_METHOD_LABELS
  ("From → To") so it can be authored from the panel
- AnimationCard: From section with per-row edit/remove and + From property
  picker (orange accent to distinguish from To section); buildTweenSummary
  includes from-state description for fromTo; PropertyRow and
  AddPropertyTrigger extracted to eliminate the structural duplication
  between From and To rows
- GsapAnimationSection / PropertyPanel / useDomEditSession /
  DomEditContext / StudioRightPanel: thread the three new callbacks
  through the full prop/context chain

* test(studio): add API-level tests for fromProperties mutation routes

Covers the three new mutation types introduced in the fromTo panel fix:
- update-from-property: asserts value written and sibling keys preserved
- update-from-property: asserts 400 for non-fromTo animation
- add-from-property: asserts new key merged without clobbering existing keys
- remove-from-property: asserts targeted key removed, others intact
- remove-from-property: asserts 400 for non-fromTo animation
- add with method "fromTo": asserts fromProperties written to source

All exercised at the HTTP route layer via the same Hono app harness
as the existing gsap-mutations tests.
This commit is contained in:
Miguel Ángel
2026-05-29 13:18:05 -04:00
committed by GitHub
parent 62475b7649
commit 6a0c9a5e22
10 changed files with 590 additions and 77 deletions
+31 -1
View File
@@ -215,6 +215,9 @@ export function useDomEditSession({
addGsapAnimation,
addGsapProperty,
removeGsapProperty,
updateGsapFromProperty,
addGsapFromProperty,
removeGsapFromProperty,
} = useGsapScriptCommits({
projectIdRef,
activeCompPath,
@@ -288,7 +291,7 @@ export function useDomEditSession({
);
const handleGsapAddAnimation = useCallback(
(method: "to" | "from" | "set") => {
(method: "to" | "from" | "set" | "fromTo") => {
if (!domEditSelection) return;
addGsapAnimation(domEditSelection, method, currentTime);
},
@@ -311,6 +314,30 @@ export function useDomEditSession({
[domEditSelection, removeGsapProperty],
);
const handleGsapUpdateFromProperty = useCallback(
(animId: string, prop: string, value: number | string) => {
if (!domEditSelection) return;
updateGsapFromProperty(domEditSelection, animId, prop, value);
},
[domEditSelection, updateGsapFromProperty],
);
const handleGsapAddFromProperty = useCallback(
(animId: string, prop: string) => {
if (!domEditSelection) return;
addGsapFromProperty(domEditSelection, animId, prop);
},
[domEditSelection, addGsapFromProperty],
);
const handleGsapRemoveFromProperty = useCallback(
(animId: string, prop: string) => {
if (!domEditSelection) return;
removeGsapFromProperty(domEditSelection, animId, prop);
},
[domEditSelection, removeGsapFromProperty],
);
// Sync selection from preview document on load / refresh
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
@@ -443,5 +470,8 @@ export function useDomEditSession({
handleGsapAddAnimation,
handleGsapAddProperty,
handleGsapRemoveProperty,
handleGsapUpdateFromProperty,
handleGsapAddFromProperty,
handleGsapRemoveFromProperty,
};
}
@@ -210,7 +210,11 @@ export function useGsapScriptCommits({
);
const addGsapAnimation = useCallback(
async (selection: DomEditSelection, method: "to" | "from" | "set", currentTime?: number) => {
async (
selection: DomEditSelection,
method: "to" | "from" | "set" | "fromTo",
currentTime?: number,
) => {
const { selector, autoId } = ensureElementAddressable(selection);
if (autoId) {
@@ -238,10 +242,11 @@ export function useGsapScriptCommits({
}
const start = currentTime ?? (Number.parseFloat(selection.dataAttributes.start ?? "0") || 0);
const defaults: Record<string, Record<string, number>> = {
const toDefaults: Record<string, Record<string, number>> = {
from: { opacity: 0 },
to: { opacity: 1 },
set: { opacity: 1 },
fromTo: { opacity: 1 },
};
await commitMutation(
@@ -253,7 +258,8 @@ export function useGsapScriptCommits({
position: start,
duration: method === "set" ? undefined : 0.5,
ease: method === "set" ? undefined : "power2.out",
properties: defaults[method] ?? { opacity: 1 },
properties: toDefaults[method] ?? { opacity: 1 },
fromProperties: method === "fromTo" ? { opacity: 0 } : undefined,
},
{ label: `Add GSAP ${method} animation` },
);
@@ -292,6 +298,48 @@ export function useGsapScriptCommits({
[commitMutation],
);
const updateGsapFromProperty = useCallback(
(
selection: DomEditSelection,
animationId: string,
property: string,
value: number | string,
) => {
void commitMutation(
selection,
{ type: "update-from-property", animationId, property, value },
{
label: `Edit GSAP from-${property}`,
coalesceKey: `gsap:${animationId}:from:${property}`,
},
);
},
[commitMutation],
);
const addGsapFromProperty = useCallback(
(selection: DomEditSelection, animationId: string, property: string) => {
const defaultValue = PROPERTY_DEFAULTS[property] ?? 0;
void commitMutation(
selection,
{ type: "add-from-property", animationId, property, defaultValue },
{ label: `Add GSAP from-${property}` },
);
},
[commitMutation],
);
const removeGsapFromProperty = useCallback(
(selection: DomEditSelection, animationId: string, property: string) => {
void commitMutation(
selection,
{ type: "remove-from-property", animationId, property },
{ label: `Remove GSAP from-${property}` },
);
},
[commitMutation],
);
return {
updateGsapProperty,
updateGsapMeta,
@@ -299,5 +347,8 @@ export function useGsapScriptCommits({
addGsapAnimation,
addGsapProperty,
removeGsapProperty,
updateGsapFromProperty,
addGsapFromProperty,
removeGsapFromProperty,
};
}