From bb1271fcafd8429715c367cc0b4f6e289907913e Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Mon, 27 Jul 2026 22:22:55 -0700 Subject: [PATCH] fix(composer): scope slow reorder pacing to slot travel, not enter/exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The activity pill slot's single top-level 0.9s transition (PILL_REORDER_DURATION_S) applied to every animated value, so the enter/exit fade+scale inherited the slow spring meant only for reorder travel — pills faded/scaled in and out over 0.9s. - Split AnimatedPillSlot's transition per value: `layout` keeps the 0.9s reorder spring unchanged - `opacity` keeps the 0.9s linear tween only while the slot is moving (the mid-move dip keyframes must still land with the layout spring); otherwise it uses a fast 0.18s ease-out for enter/exit - `scale` always uses the fast tween — it only animates on enter/exit - Add PILL_ENTER_EXIT_DURATION_S (0.18s) alongside the reorder constant Co-authored-by: Taylor Ho Signed-off-by: Taylor Ho --- .../features/channels/ui/BotActivityBar.tsx | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/desktop/src/features/channels/ui/BotActivityBar.tsx b/desktop/src/features/channels/ui/BotActivityBar.tsx index 38c73fb51..296a80d73 100644 --- a/desktop/src/features/channels/ui/BotActivityBar.tsx +++ b/desktop/src/features/channels/ui/BotActivityBar.tsx @@ -46,6 +46,12 @@ const TYPING_LABEL_ID = "typing-override"; * keyframes so the fade lands together with the layout switch. */ const PILL_REORDER_DURATION_S = 0.9; +/** + * Enter/exit fade+scale for a pill slot. Deliberately much quicker than the + * reorder spring — the slow reorder pacing must not bleed into membership + * changes, which should feel snappy. + */ +const PILL_ENTER_EXIT_DURATION_S = 0.18; /** * Strip-level hover popover state: ONE active pill and ONE timer for the @@ -475,13 +481,31 @@ function AnimatedPillSlot({ shouldReduceMotion ? { duration: 0 } : { - type: "spring", - duration: PILL_REORDER_DURATION_S, - bounce: 0.15, - opacity: { - type: "tween", + // Only the slot's travel gets the slow reorder pacing; the + // enter/exit fade+scale runs on its own fast tween below. + layout: { + type: "spring", duration: PILL_REORDER_DURATION_S, - ease: "linear", + bounce: 0.15, + }, + // While the slot travels, opacity plays the dip keyframes and + // must land together with the layout spring; otherwise it is + // an enter/exit fade and should be quick. + opacity: isMoving + ? { + type: "tween", + duration: PILL_REORDER_DURATION_S, + ease: "linear", + } + : { + type: "tween", + duration: PILL_ENTER_EXIT_DURATION_S, + ease: "easeOut", + }, + scale: { + type: "tween", + duration: PILL_ENTER_EXIT_DURATION_S, + ease: "easeOut", }, } }