1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

fix: wrap the UserAvatar component in forwardRef (#8461)

This fixes another one of the warnings we have in our tests and is
probably a sane change to make anyway.
This commit is contained in:
Thomas Heartman 2024-10-16 14:58:34 +02:00 committed by GitHub
parent fe09ae214f
commit cb0a26941b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 77 additions and 64 deletions

View File

@ -1,8 +1,16 @@
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import type { IGroupUser } from 'interfaces/group'; import type { IGroupUser } from 'interfaces/group';
import { useMemo } from 'react'; import {
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar'; // usage type ForwardRefExoticComponent,
type FunctionComponent,
type RefAttributes,
useMemo,
} from 'react';
import {
type IUserAvatarProps,
UserAvatar,
} from 'component/common/UserAvatar/UserAvatar';
import { objectId } from 'utils/objectId'; import { objectId } from 'utils/objectId';
import millify from 'millify'; import millify from 'millify';
@ -14,6 +22,12 @@ const StyledAvatars = styled('div')(({ theme }) => ({
justifyContent: 'start', justifyContent: 'start',
})); }));
export type AvatarComponentType =
| FunctionComponent<IUserAvatarProps>
| ForwardRefExoticComponent<
IUserAvatarProps & RefAttributes<HTMLDivElement>
>;
export const AvatarComponent = styled(UserAvatar)(({ theme }) => ({ export const AvatarComponent = styled(UserAvatar)(({ theme }) => ({
outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`, outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
margin: 0, margin: 0,
@ -21,7 +35,7 @@ export const AvatarComponent = styled(UserAvatar)(({ theme }) => ({
'&:hover': { '&:hover': {
outlineColor: theme.palette.primary.main, outlineColor: theme.palette.primary.main,
}, },
})); })) as AvatarComponentType;
type User = { type User = {
name: string; name: string;
@ -32,7 +46,7 @@ type User = {
type AvatarGroupProps = { type AvatarGroupProps = {
users: User[]; users: User[];
avatarLimit?: number; avatarLimit?: number;
AvatarComponent?: typeof UserAvatar; AvatarComponent?: AvatarComponentType;
className?: string; className?: string;
}; };
@ -44,7 +58,7 @@ export const AvatarGroup = ({ ...props }: AvatarGroupProps) => (
); );
type AvatarGroupInnerProps = Omit<AvatarGroupProps, 'AvatarComponent'> & { type AvatarGroupInnerProps = Omit<AvatarGroupProps, 'AvatarComponent'> & {
AvatarComponent: typeof UserAvatar; AvatarComponent: AvatarComponentType;
}; };
const MAX_OVERFLOW_DISPLAY_NUMBER = 99; const MAX_OVERFLOW_DISPLAY_NUMBER = 99;

View File

@ -1,12 +1,14 @@
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import type { ProjectSchemaOwners } from 'openapi'; import type { ProjectSchemaOwners } from 'openapi';
import type { UserAvatar } from '../UserAvatar/UserAvatar'; import {
import { AvatarGroup } from '../AvatarGroup/AvatarGroup'; type AvatarComponentType,
AvatarGroup,
} from '../AvatarGroup/AvatarGroup';
type Props = { type Props = {
users: ProjectSchemaOwners; users: ProjectSchemaOwners;
avatarLimit?: number; avatarLimit?: number;
AvatarComponent?: typeof UserAvatar; AvatarComponent?: AvatarComponentType;
className?: string; className?: string;
}; };
export const AvatarGroupFromOwners: React.FC<Props> = ({ users, ...props }) => { export const AvatarGroupFromOwners: React.FC<Props> = ({ users, ...props }) => {

View File

@ -6,7 +6,7 @@ import {
type Theme, type Theme,
} from '@mui/material'; } from '@mui/material';
import type { IUser } from 'interfaces/user'; import type { IUser } from 'interfaces/user';
import type { FC } from 'react'; import { forwardRef } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { HtmlTooltip } from '../HtmlTooltip/HtmlTooltip'; import { HtmlTooltip } from '../HtmlTooltip/HtmlTooltip';
const StyledAvatar = styled(Avatar)(({ theme }) => ({ const StyledAvatar = styled(Avatar)(({ theme }) => ({
@ -60,63 +60,60 @@ const TooltipMainContent = styled('div')(({ theme }) => ({
fontSize: theme.typography.body1.fontSize, fontSize: theme.typography.body1.fontSize,
})); }));
export const UserAvatar: FC<IUserAvatarProps> = ({ export const UserAvatar = forwardRef<HTMLDivElement, IUserAvatarProps>(
user, ({ user, src, className, sx, children, disableTooltip, ...props }, ref) => {
src, let fallback: string | undefined;
className, if (!children && user) {
sx, fallback = user?.name || user?.email || user?.username;
children, if (fallback?.includes(' ')) {
disableTooltip, fallback = `${fallback.split(' ')[0][0]}${
...props fallback.split(' ')[1][0]
}) => { }`.toUpperCase();
let fallback: string | undefined; } else if (fallback) {
if (!children && user) { fallback = fallback[0].toUpperCase();
fallback = user?.name || user?.email || user?.username; }
if (fallback?.includes(' ')) {
fallback = `${fallback.split(' ')[0][0]}${
fallback.split(' ')[1][0]
}`.toUpperCase();
} else if (fallback) {
fallback = fallback[0].toUpperCase();
} }
}
const Avatar = ( const Avatar = (
<StyledAvatar <StyledAvatar
className={className} ref={ref}
sx={sx} className={className}
{...props} sx={sx}
data-loading {...props}
alt={user?.name || user?.email || user?.username || 'Gravatar'} data-loading
src={src || user?.imageUrl} alt={user?.name || user?.email || user?.username || 'Gravatar'}
> src={src || user?.imageUrl}
<ConditionallyRender
condition={Boolean(fallback)}
show={fallback}
elseShow={children}
/>
</StyledAvatar>
);
const tooltip = disableTooltip ? undefined : tooltipContent(user);
if (tooltip) {
return (
<HtmlTooltip
arrow
describeChild
title={
<>
<TooltipSecondaryContent>
{tooltip.secondary}
</TooltipSecondaryContent>
<TooltipMainContent>{tooltip.main}</TooltipMainContent>
</>
}
> >
{Avatar} <ConditionallyRender
</HtmlTooltip> condition={Boolean(fallback)}
show={fallback}
elseShow={children}
/>
</StyledAvatar>
); );
}
return Avatar; const tooltip = disableTooltip ? undefined : tooltipContent(user);
}; if (tooltip) {
return (
<HtmlTooltip
arrow
describeChild
title={
<>
<TooltipSecondaryContent>
{tooltip.secondary}
</TooltipSecondaryContent>
<TooltipMainContent>
{tooltip.main}
</TooltipMainContent>
</>
}
>
{Avatar}
</HtmlTooltip>
);
}
return Avatar;
},
);