refactor(app): collapse the wrapped voice avatar render branches into one (#1970)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-24 12:55:22 +02:00
1 parent cf3a31ac42
commit 52282bfccf
1 file changed
+33 -49
@@ -544,7 +544,7 @@ export const VoiceParticipantWrappedAvatarList: React.FC<VoiceParticipantWrapped
[avatarSize], [avatarSize],
); );
const shouldAnimateAvatarChanges = !Accessibility.useReducedMotion; const shouldAnimateAvatarChanges = !Accessibility.useReducedMotion;
const {slots: animatedSlots, onSlotAnimationComplete} = useWrappedAvatarSlots( const {slots: avatarSlots, onSlotAnimationComplete} = useWrappedAvatarSlots(
sortedEntries, sortedEntries,
shouldAnimateAvatarChanges, shouldAnimateAvatarChanges,
); );
@@ -583,22 +583,38 @@ export const VoiceParticipantWrappedAvatarList: React.FC<VoiceParticipantWrapped
), ),
[avatarSize, guildId], [avatarSize, guildId],
); );
const finalAvatarNodes = sortedEntries.map((entry) => ( const avatarSlotNodes = avatarSlots.map((slot) => {
// biome-ignore lint/a11y/noStaticElementInteractions: wrapped voice avatars expose a pointer-only context menu. const isCollapsed = slot.phase === 'exiting';
<div const isEntering = slot.phase === 'entering';
key={`${entry.userId}:${entry.connectionId}`} return (
className={styles.wrapAvatarSlot} <motion.div
onContextMenu={(event) => handleContextMenu(event, entry)} key={shouldAnimateAvatarChanges ? `${slot.key}:motion` : `${slot.key}:static`}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar-slot" className={clsx(styles.wrapAvatarSlot, shouldAnimateAvatarChanges && styles.wrapAvatarSlotAnimated)}
> onContextMenu={(event) => handleContextMenu(event, slot.entry)}
<div initial={shouldAnimateAvatarChanges && isEntering ? {width: 0, flexBasis: 0} : false}
className={styles.wrapAvatar} animate={
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar" shouldAnimateAvatarChanges
? {width: isCollapsed ? 0 : slotSize, flexBasis: isCollapsed ? 0 : slotSize}
: undefined
}
transition={WRAPPED_AVATAR_SLOT_TRANSITION}
onAnimationComplete={() => onSlotAnimationComplete(slot.key, slot.phase)}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar-slot"
> >
{renderAvatar(entry)} <motion.div
</div> className={clsx(styles.wrapAvatar, shouldAnimateAvatarChanges && styles.wrapAvatarAnimated)}
</div> initial={shouldAnimateAvatarChanges && isEntering ? {opacity: 0, scale: 0.92} : false}
)); animate={
shouldAnimateAvatarChanges ? {opacity: isCollapsed ? 0 : 1, scale: isCollapsed ? 0.9 : 1} : undefined
}
transition={WRAPPED_AVATAR_POP_TRANSITION}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar"
>
{renderAvatar(slot.entry)}
</motion.div>
</motion.div>
);
});
return ( return (
<div <div
ref={containerRef} ref={containerRef}
@@ -606,39 +622,7 @@ export const VoiceParticipantWrappedAvatarList: React.FC<VoiceParticipantWrapped
style={listStyle} style={listStyle}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-container" data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-container"
> >
{shouldAnimateAvatarChanges {avatarSlotNodes}
? animatedSlots.map((slot) => {
const isCollapsed = slot.phase === 'exiting';
return (
<motion.div
key={slot.key}
className={clsx(styles.wrapAvatarSlot, styles.wrapAvatarSlotAnimated)}
onContextMenu={(event) => handleContextMenu(event, slot.entry)}
initial={slot.phase === 'entering' ? {width: 0, flexBasis: 0} : false}
animate={{
width: isCollapsed ? 0 : slotSize,
flexBasis: isCollapsed ? 0 : slotSize,
}}
transition={WRAPPED_AVATAR_SLOT_TRANSITION}
onAnimationComplete={() => onSlotAnimationComplete(slot.key, slot.phase)}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar-slot.motion"
>
<motion.div
className={clsx(styles.wrapAvatar, styles.wrapAvatarAnimated)}
initial={slot.phase === 'entering' ? {opacity: 0, scale: 0.92} : false}
animate={{
opacity: isCollapsed ? 0 : 1,
scale: isCollapsed ? 0.9 : 1,
}}
transition={WRAPPED_AVATAR_POP_TRANSITION}
data-flx="voice.voice-participant-avatar-list.voice-participant-wrapped-avatar-list.wrap-avatar.motion"
>
{renderAvatar(slot.entry)}
</motion.div>
</motion.div>
);
})
: finalAvatarNodes}
</div> </div>
); );
}, },