From 720a0cc8aed282b2c00db4d4d66bba3140587148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Lenoir?= Date: Wed, 18 Sep 2024 16:00:03 +0200 Subject: [PATCH] fix(Avatar): avatar size + loading skeleton --- .../avatar/src/Avatar/Avatar.styles.ts | 27 +++++++++-------- .../components/avatar/src/Avatar/Avatar.tsx | 17 +++++------ .../components/avatar/src/Avatar/utils.ts | 30 +++++++++++++++++++ .../src/AvatarGroup/AvatarGroup.styles.ts | 2 +- .../avatar/stories/Avatar.stories.tsx | 15 +++++++++- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/packages/components/avatar/src/Avatar/Avatar.styles.ts b/packages/components/avatar/src/Avatar/Avatar.styles.ts index e3e04f0204..2d0bdb206e 100644 --- a/packages/components/avatar/src/Avatar/Avatar.styles.ts +++ b/packages/components/avatar/src/Avatar/Avatar.styles.ts @@ -1,7 +1,12 @@ import { css } from 'emotion'; import tokens from '@contentful/f36-tokens'; import { type AvatarProps } from './Avatar'; -import { applyMuted, avatarColorMap, type ColorVariant } from './utils'; +import { + applyMuted, + avatarColorMap, + getSizeInPixels, + type ColorVariant, +} from './utils'; export const getColorVariantStyles = (colorVariant: ColorVariant) => { const colorToken: string = avatarColorMap[colorVariant]; @@ -16,14 +21,6 @@ export const getColorVariantStyles = (colorVariant: ColorVariant) => { }; }; -export const convertSizeToPixels = (size: AvatarProps['size']) => - ({ - tiny: '20px', - small: '24px', - medium: '32px', - large: '48px', - }[size]); - const getInitialsFontSize = (sizePixels: string) => Math.round(Number(sizePixels.replace('px', '')) / 2); @@ -37,7 +34,8 @@ export const getAvatarStyles = ({ colorVariant: ColorVariant; }) => { const borderRadius = variant === 'app' ? tokens.borderRadiusSmall : '100%'; - const sizePixels = convertSizeToPixels(size); + const finalSize = getSizeInPixels(size); + const isMuted = colorVariant === 'muted'; return { @@ -50,7 +48,7 @@ export const getAvatarStyles = ({ alignItems: 'center', justifyContent: 'center', fontStretch: 'semi-condensed', - fontSize: `${getInitialsFontSize(sizePixels)}px`, + fontSize: `${getInitialsFontSize(size)}px`, }), image: css({ borderRadius, @@ -58,10 +56,13 @@ export const getAvatarStyles = ({ }), root: css({ borderRadius, - height: sizePixels, + height: finalSize, overflow: 'hidden', position: 'relative', - width: sizePixels, + width: finalSize, + svg: { + borderRadius, + }, '&::after': { borderRadius, bottom: 0, diff --git a/packages/components/avatar/src/Avatar/Avatar.tsx b/packages/components/avatar/src/Avatar/Avatar.tsx index a2397db0c0..a73b58d686 100644 --- a/packages/components/avatar/src/Avatar/Avatar.tsx +++ b/packages/components/avatar/src/Avatar/Avatar.tsx @@ -9,10 +9,8 @@ import { type WithEnhancedContent, } from '@contentful/f36-tooltip'; -import { convertSizeToPixels, getAvatarStyles } from './Avatar.styles'; -import type { ColorVariant } from './utils'; - -export type Size = 'tiny' | 'small' | 'medium' | 'large'; +import { getAvatarStyles } from './Avatar.styles'; +import { getSizeInPixels, type Size, type ColorVariant } from './utils'; export type Variant = 'app' | 'user'; @@ -23,9 +21,10 @@ export interface AvatarProps extends CommonProps { */ isLoading?: boolean; /** + * Use the available sizes or a numerical custom one, e.g. '52' or '52px' * @default 'medium' */ - size?: Size; + size?: Size | string; initials?: string; src?: ImageProps['src']; /** @@ -64,8 +63,8 @@ function _Avatar( ) { // Only render the fallback when `src` is undefined or an empty string const isFallback = Boolean(!isLoading && !src); - const styles = getAvatarStyles({ size, variant, colorVariant }); - const sizePixels = convertSizeToPixels(size); + const finalSize = getSizeInPixels(size); + const styles = getAvatarStyles({ size: finalSize, variant, colorVariant }); const content = (
)} {!!icon && {icon}} diff --git a/packages/components/avatar/src/Avatar/utils.ts b/packages/components/avatar/src/Avatar/utils.ts index a7e1277f86..84ee6d6789 100644 --- a/packages/components/avatar/src/Avatar/utils.ts +++ b/packages/components/avatar/src/Avatar/utils.ts @@ -1,4 +1,8 @@ +import { AvatarProps } from './Avatar'; + import tokens from '@contentful/f36-tokens'; +export const SIZES = ['tiny', 'small', 'medium', 'large'] as const; +export type Size = (typeof SIZES)[number]; export type ColorVariant = keyof typeof avatarColorMap; @@ -33,3 +37,29 @@ export function applyMuted(color: string): string { // Eventually we should use `color-mix` // return `color-mix(in srgb, ${color}, ${tokens.colorWhite} 50%)`; } + +export const isSizeVariant = (size: string): size is Size => { + return SIZES.includes(size as Size); +}; + +export const convertSizeToPixels = (size: AvatarProps['size']) => + ({ + tiny: '20px', + small: '24px', + medium: '32px', + large: '48px', + }[size]); + +/** + * Utility function to convert the given size variant/custom size to pixels + * + * @param size The size of the avatar + * @returns the size in pixels, e.g. '32px' + */ +export function getSizeInPixels(size: AvatarProps['size']): string { + return isSizeVariant(size) + ? convertSizeToPixels(size) + : size.includes('px') + ? size + : `${size}px`; +} diff --git a/packages/components/avatar/src/AvatarGroup/AvatarGroup.styles.ts b/packages/components/avatar/src/AvatarGroup/AvatarGroup.styles.ts index 43d44dc263..5c70958350 100644 --- a/packages/components/avatar/src/AvatarGroup/AvatarGroup.styles.ts +++ b/packages/components/avatar/src/AvatarGroup/AvatarGroup.styles.ts @@ -1,7 +1,7 @@ import { css } from 'emotion'; import tokens from '@contentful/f36-tokens'; import { type AvatarProps } from '../Avatar/'; -import { convertSizeToPixels } from '../Avatar/Avatar.styles'; +import { convertSizeToPixels } from '../Avatar/utils'; export const getAvatarGroupStyles = (size: AvatarProps['size']) => { return { diff --git a/packages/components/avatar/stories/Avatar.stories.tsx b/packages/components/avatar/stories/Avatar.stories.tsx index a7152a13e2..9ff2388c0d 100644 --- a/packages/components/avatar/stories/Avatar.stories.tsx +++ b/packages/components/avatar/stories/Avatar.stories.tsx @@ -49,6 +49,17 @@ export const Overview: Story = (args) => { size="large" icon={} /> + } + /> + } + /> = (args) => { + + @@ -186,7 +199,7 @@ export const BorderColors: Story = (args) => { {/* prettier-ignore */} {/* prettier-ignore */} - + {/* prettier-ignore */} {/* prettier-ignore */}