From 5fa212183ace0388735c7aa05e9bc3955a7970a5 Mon Sep 17 00:00:00 2001 From: Daniel Sauble Date: Tue, 29 Jul 2025 14:22:53 -0700 Subject: [PATCH] Fix animations in the component preview (#33673) Fixes #33869 The Animation page in the Component Preview had a few issues. * The animations only ran once, so you couldn't watch animations below the fold. * The offset math was wrong, so some animated elements were rendered outside of their parent container. * The "animate in from right" elements were defined with an initial `.left()` offset, which overrode the animation behavior. I made fixes to address these issues. In particular, every time you click the active list item, it renders the preview again (which causes the animations to run again). Before: https://github.com/user-attachments/assets/a1fa2e3f-653c-4b83-a6ed-c55ca9c78ad4 After: https://github.com/user-attachments/assets/3623bbbc-9047-4443-b7f3-96bd92f582bf Release Notes: - N/A --- crates/ui/src/styles/animation.rs | 18 +++++++++--------- crates/zed/src/zed/component_preview.rs | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/ui/src/styles/animation.rs b/crates/ui/src/styles/animation.rs index 50c4e0eb0d..0649bee1f8 100644 --- a/crates/ui/src/styles/animation.rs +++ b/crates/ui/src/styles/animation.rs @@ -109,7 +109,7 @@ impl Component for Animation { fn preview(_window: &mut Window, _cx: &mut App) -> Option { let container_size = 128.0; let element_size = 32.0; - let left_offset = element_size - container_size / 2.0; + let offset = container_size / 2.0 - element_size / 2.0; Some( v_flex() .gap_6() @@ -129,7 +129,7 @@ impl Component for Animation { .id("animate-in-from-bottom") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .left(px(offset)) .rounded_md() .bg(gpui::red()) .animate_in(AnimationDirection::FromBottom, false), @@ -148,7 +148,7 @@ impl Component for Animation { .id("animate-in-from-top") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .left(px(offset)) .rounded_md() .bg(gpui::blue()) .animate_in(AnimationDirection::FromTop, false), @@ -167,7 +167,7 @@ impl Component for Animation { .id("animate-in-from-left") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .top(px(offset)) .rounded_md() .bg(gpui::green()) .animate_in(AnimationDirection::FromLeft, false), @@ -186,7 +186,7 @@ impl Component for Animation { .id("animate-in-from-right") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .top(px(offset)) .rounded_md() .bg(gpui::yellow()) .animate_in(AnimationDirection::FromRight, false), @@ -211,7 +211,7 @@ impl Component for Animation { .id("fade-animate-in-from-bottom") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .left(px(offset)) .rounded_md() .bg(gpui::red()) .animate_in(AnimationDirection::FromBottom, true), @@ -230,7 +230,7 @@ impl Component for Animation { .id("fade-animate-in-from-top") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .left(px(offset)) .rounded_md() .bg(gpui::blue()) .animate_in(AnimationDirection::FromTop, true), @@ -249,7 +249,7 @@ impl Component for Animation { .id("fade-animate-in-from-left") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .top(px(offset)) .rounded_md() .bg(gpui::green()) .animate_in(AnimationDirection::FromLeft, true), @@ -268,7 +268,7 @@ impl Component for Animation { .id("fade-animate-in-from-right") .absolute() .size(px(element_size)) - .left(px(left_offset)) + .top(px(offset)) .rounded_md() .bg(gpui::yellow()) .animate_in(AnimationDirection::FromRight, true), diff --git a/crates/zed/src/zed/component_preview.rs b/crates/zed/src/zed/component_preview.rs index 670793cff3..2e57152c62 100644 --- a/crates/zed/src/zed/component_preview.rs +++ b/crates/zed/src/zed/component_preview.rs @@ -105,6 +105,7 @@ enum PreviewPage { struct ComponentPreview { active_page: PreviewPage, active_thread: Option>, + reset_key: usize, component_list: ListState, component_map: HashMap, components: Vec, @@ -188,6 +189,7 @@ impl ComponentPreview { let mut component_preview = Self { active_page, active_thread: None, + reset_key: 0, component_list, component_map: component_registry.component_map(), components: sorted_components, @@ -265,8 +267,13 @@ impl ComponentPreview { } fn set_active_page(&mut self, page: PreviewPage, cx: &mut Context) { - self.active_page = page; - cx.emit(ItemEvent::UpdateTab); + if self.active_page == page { + // Force the current preview page to render again + self.reset_key = self.reset_key.wrapping_add(1); + } else { + self.active_page = page; + cx.emit(ItemEvent::UpdateTab); + } cx.notify(); } @@ -690,6 +697,7 @@ impl ComponentPreview { component.clone(), self.workspace.clone(), self.active_thread.clone(), + self.reset_key, )) .into_any_element() } else { @@ -1041,6 +1049,7 @@ pub struct ComponentPreviewPage { component: ComponentMetadata, workspace: WeakEntity, active_thread: Option>, + reset_key: usize, } impl ComponentPreviewPage { @@ -1048,6 +1057,7 @@ impl ComponentPreviewPage { component: ComponentMetadata, workspace: WeakEntity, active_thread: Option>, + reset_key: usize, // languages: Arc ) -> Self { Self { @@ -1055,6 +1065,7 @@ impl ComponentPreviewPage { component, workspace, active_thread, + reset_key, } } @@ -1155,6 +1166,7 @@ impl ComponentPreviewPage { }; v_flex() + .id(("component-preview", self.reset_key)) .size_full() .flex_1() .px_12()