️(frontend) size the Avatar with CSS instead of useSize

Stop using the useSize hook to compute the Avatar size in JS. Rely
on CSS to size the Avatar responsively instead.

This removes a set of unnecessary re-renders triggered by the
useSize subscription every time the container resized.
This commit is contained in:
lebaudantoine
2026-07-23 18:24:15 +02:00
committed by aleb_the_flash
parent 13c9d3635c
commit 0e3c978af2
2 changed files with 36 additions and 35 deletions
@@ -1,10 +1,7 @@
import type { Participant } from 'livekit-client'
import { styled } from '@/styled-system/jsx'
import { Avatar } from '@/components/Avatar'
import { useIsSpeaking } from '@livekit/components-react'
import { getParticipantBackgroundGradient } from '@/features/rooms/utils/getParticipantBackgroundGradient'
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
import { useMemo } from 'react'
import React, { useMemo } from 'react'
const StyledParticipantPlaceHolder = styled('div', {
base: {
@@ -23,39 +20,36 @@ const StyledAvatarWrapper = styled('div', {
aspectRatio: '1 / 1',
width: 'min(90cqmin, 160px)',
fontSize: 'min(27cqmin, 48px)',
'[data-lk-speaking="true"] &': {
animation: 'pulse 1s infinite',
},
},
})
type ParticipantPlaceholderProps = {
participant: Participant
color: string
displayedNamed: string
}
export const ParticipantPlaceholder = ({
participant,
}: ParticipantPlaceholderProps) => {
const isSpeaking = useIsSpeaking(participant)
const participantColor = getParticipantColor(participant)
const backgroundGradient = useMemo(
() => getParticipantBackgroundGradient(participantColor),
[participantColor]
)
return (
<StyledParticipantPlaceHolder
style={{
backgroundColor: participantColor,
backgroundImage: backgroundGradient,
}}
>
<StyledAvatarWrapper
style={{ animation: isSpeaking ? 'pulse 1s infinite' : undefined }}
export const ParticipantPlaceholder = React.memo(
({ color, displayedNamed }: ParticipantPlaceholderProps) => {
const backgroundGradient = useMemo(
() => getParticipantBackgroundGradient(color),
[color]
)
return (
<StyledParticipantPlaceHolder
style={{
backgroundColor: color,
backgroundImage: backgroundGradient,
}}
>
<Avatar
name={participant.name}
bgColor={participantColor}
context="placeholder"
/>
</StyledAvatarWrapper>
</StyledParticipantPlaceHolder>
)
}
<StyledAvatarWrapper>
<Avatar name={displayedNamed} bgColor={color} context="placeholder" />
</StyledAvatarWrapper>
</StyledParticipantPlaceHolder>
)
}
)
ParticipantPlaceholder.displayName = 'ParticipantPlaceholder'
@@ -1,3 +1,4 @@
import React from 'react'
import {
AudioTrack,
ParticipantTileProps,
@@ -9,7 +10,6 @@ import {
TrackRefContext,
ParticipantContextIfNeeded,
} from '@livekit/components-react'
import React from 'react'
import {
isEqualTrackRef,
isTrackReference,
@@ -26,6 +26,7 @@ import { formatShortcutLabel } from '@/features/shortcuts/formatLabels'
import { KeyboardShortcutHint } from './KeyboardShortcutHint'
import { layoutStore, clearPinnedTrack } from '@/stores/layout'
import { ParticipantMetadata } from './ParticipantMetadata'
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
export function TrackRefContextIfNeeded(
props: React.PropsWithChildren<{
@@ -90,6 +91,8 @@ export const ParticipantTile: (
const isScreenShare = trackReference.source != Track.Source.Camera
const [hasKeyboardFocus, setHasKeyboardFocus] = React.useState(false)
const participantColor = getParticipantColor(trackReference.participant)
const participantName = getParticipantName(trackReference.participant)
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
@@ -141,7 +144,11 @@ export const ParticipantTile: (
)}
<div className="lk-participant-placeholder">
<ParticipantPlaceholder
participant={trackReference.participant}
color={participantColor}
displayedNamed={
trackReference.participant.name ||
trackReference.participant.identity
}
/>
</div>
{!disableMetadata && (