Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,13 @@ class SetElementAnimationBuildsCommand implements EditorCommand {
selectedIds.has(elementId),
);
if (orderedSelectedIds.length === 0) return page;
const existingBuilds = getPageAnimationBuilds(page);
const existingByElementId = new Map(
getPageAnimationBuilds(page).map((build) => [build.elementId, build]),
existingBuilds.map((build) => [build.elementId, build]),
);
const retainedBuilds = getPageAnimationBuilds(page).filter(
(build) => !selectedIds.has(build.elementId) && pageElementIds.has(build.elementId),
);
const nextBuilds = orderedSelectedIds.map((elementId) => {
const updatedByElementId = new Map(orderedSelectedIds.map((elementId) => {
const existing = existingByElementId.get(elementId);
return {
return [elementId, {
id: existing?.id ?? this.createBuildId(elementId),
elementId,
effect: this.patch.effect,
Expand All @@ -60,9 +58,18 @@ class SetElementAnimationBuildsCommand implements EditorCommand {
? { lineDrawDirection: this.patch.lineDrawDirection }
: {}),
...(this.patch.mediaAction ? { mediaAction: this.patch.mediaAction } : {}),
};
}] as const;
}));
const nextBuilds = existingBuilds.flatMap((build) => {
if (!pageElementIds.has(build.elementId)) return [];
if (!selectedIds.has(build.elementId)) return [build];
const updated = updatedByElementId.get(build.elementId);
if (!updated) return [];
updatedByElementId.delete(build.elementId);
return [updated];
});
return { ...page, animationBuilds: [...retainedBuilds, ...nextBuilds] };
nextBuilds.push(...updatedByElementId.values());
return { ...page, animationBuilds: nextBuilds };
}),
updatedAt: projectMutationUtils.getProjectUpdatedAt(),
};
Expand Down
32 changes: 32 additions & 0 deletions apps/editor/tests/unit/domain/commands/basicCommands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,38 @@ describe('editor commands', () => {
expect(project.pages[0]?.animationBuilds).toBeUndefined();
});

it('updates an existing animation build without changing build order or neighboring builds', () => {
const project = new basicCommands.SetElementAnimationBuildsCommand(
'page-1',
['image-hero', 'text-subtitle', 'text-title'],
(elementId) => `build-${elementId}`,
{ effect: 'reveal', trigger: 'on-click', delayMs: 0 },
).execute(sampleProject.createSampleProject());
const previousBuilds = project.pages[0]?.animationBuilds;

const next = new basicCommands.SetElementAnimationBuildsCommand(
'page-1',
['text-subtitle'],
(elementId) => `replacement-${elementId}`,
{ effect: 'dissolve', trigger: 'after-previous', delayMs: 500 },
).execute(project);

expect(next.pages[0]?.animationBuilds?.map((build) => build.elementId)).toEqual([
'image-hero',
'text-subtitle',
'text-title',
]);
expect(next.pages[0]?.animationBuilds?.[1]).toEqual({
id: 'build-text-subtitle',
elementId: 'text-subtitle',
effect: 'dissolve',
trigger: 'after-previous',
delayMs: 500,
});
expect(next.pages[0]?.animationBuilds?.[0]).toBe(previousBuilds?.[0]);
expect(next.pages[0]?.animationBuilds?.[2]).toBe(previousBuilds?.[2]);
});

it('removes an element animation build without affecting other builds', () => {
const project = new basicCommands.SetElementAnimationBuildsCommand(
'page-1',
Expand Down
5 changes: 5 additions & 0 deletions tests/e2e/editor/animation-mixed-sequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export const animationMixedSequence = {
await page.getByRole('button', { name: 'Move Typing headline animation up' }).click();
await expect(page.getByRole('listitem', { name: /Build 1: Typing headline/ })).toBeVisible();
await expect(page.getByRole('listitem', { name: /Build 2: Arrow/ })).toBeVisible();
await page.getByLabel('Effect for Typing headline').selectOption('dissolve');
await expect(page.getByRole('listitem', { name: /Build 1: Typing headline/ })).toBeVisible();
await expect(page.getByRole('listitem', { name: /Build 2: Arrow/ })).toBeVisible();
await expect(page.getByLabel('Effect for Typing headline')).toHaveValue('dissolve');
await expect(page.getByLabel('Effect for Arrow')).toHaveValue('line-draw');
await page.getByLabel('Start for Typing headline').selectOption('after-transition');
await page.getByLabel('Start for Arrow').selectOption('after-previous');
const canvasFrame = page.getByTestId('slide-canvas-frame');
Expand Down
Loading