From 11c455c1592e2d5919fed2cfbe09b2c1917124ed Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 7 Nov 2024 09:28:44 -0800 Subject: [PATCH] feat(Avatar): Remove the CSS modules feature flag from Avatar (#5221) * Refactor Avatar component to only use CSS modules * Use empty string * Create dirty-dodos-applaud.md * ref * Remove ts-ignore * Update snapshot * Remove ref from args * Pass in as prop * Add className to type * Add React.ComponentPropsWithoutRef<'img'> * Remove HTMLProps * Remove unused as * skip as --- .changeset/dirty-dodos-applaud.md | 5 + packages/react/src/Avatar/Avatar.stories.tsx | 6 - packages/react/src/Avatar/Avatar.tsx | 103 +++-------- .../__snapshots__/Token.test.tsx.snap | 164 ++++++++---------- packages/react/src/__tests__/Avatar.test.tsx | 7 +- 5 files changed, 111 insertions(+), 174 deletions(-) create mode 100644 .changeset/dirty-dodos-applaud.md diff --git a/.changeset/dirty-dodos-applaud.md b/.changeset/dirty-dodos-applaud.md new file mode 100644 index 00000000000..f524e18d812 --- /dev/null +++ b/.changeset/dirty-dodos-applaud.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +Remove the CSS modules feature flag from Avatar diff --git a/packages/react/src/Avatar/Avatar.stories.tsx b/packages/react/src/Avatar/Avatar.stories.tsx index 476c118a998..e6088c64e7d 100644 --- a/packages/react/src/Avatar/Avatar.stories.tsx +++ b/packages/react/src/Avatar/Avatar.stories.tsx @@ -63,12 +63,6 @@ Playground.argTypes = { disable: true, }, }, - ref: { - controls: false, - table: { - disable: true, - }, - }, sx: { controls: false, table: { diff --git a/packages/react/src/Avatar/Avatar.tsx b/packages/react/src/Avatar/Avatar.tsx index 4f5f066a147..b8120519df8 100644 --- a/packages/react/src/Avatar/Avatar.tsx +++ b/packages/react/src/Avatar/Avatar.tsx @@ -1,21 +1,15 @@ import {clsx} from 'clsx' import React from 'react' import Box from '../Box' -import styled from 'styled-components' -import {get} from '../constants' -import type {BetterCssProperties, BetterSystemStyleObject, SxProp} from '../sx' -import sx, {merge} from '../sx' -import type {ComponentProps} from '../utils/types' +import type {SxProp} from '../sx' import type {ResponsiveValue} from '../hooks/useResponsiveValue' import {isResponsiveValue} from '../hooks/useResponsiveValue' -import {getBreakpointDeclarations} from '../utils/getBreakpointDeclarations' import {defaultSxProp} from '../utils/defaultSxProp' import classes from './Avatar.module.css' -import {useFeatureFlag} from '../FeatureFlags' export const DEFAULT_AVATAR_SIZE = 20 -type StyledAvatarProps = { +export type AvatarProps = { /** Sets the width and height of the avatar. */ size?: number | ResponsiveValue /** Sets the shape of the avatar to a square if true. If false, the avatar will be circular. */ @@ -24,99 +18,56 @@ type StyledAvatarProps = { src: string /** Provide alt text when the Avatar is used without the user's name next to it. */ alt?: string -} & SxProp - -const StyledAvatar = styled.img.attrs(props => ({ - height: props.size, - width: props.size, -}))` - display: inline-block; - overflow: hidden; // Ensure page layout in Firefox should images fail to load - line-height: ${get('lineHeights.condensedUltra')}; - vertical-align: middle; - // If the avatar is square and size is greater than 24px (at any breakpoint), border-radius will be 6px. Otherwise, it will be 4px. - border-radius: ${props => (props.square ? 'clamp(4px, var(--avatar-size) - 24px, 6px)' : '50%')}; - box-shadow: 0 0 0 1px ${get('colors.avatar.border')}; - height: var(--avatar-size); - width: var(--avatar-size); - ${sx} -` - -export type AvatarProps = ComponentProps + /** Additional class name. */ + className?: string +} & SxProp & + React.ComponentPropsWithoutRef<'img'> const Avatar = React.forwardRef(function Avatar( {alt = '', size = DEFAULT_AVATAR_SIZE, square = false, sx: sxProp = defaultSxProp, className, ...rest}, ref, ) { - const enabled = useFeatureFlag('primer_react_css_modules_ga') const isResponsive = isResponsiveValue(size) - const avatarSx = isResponsive - ? merge( - getBreakpointDeclarations( - size, - '--avatar-size' as keyof React.CSSProperties, - value => `${value || DEFAULT_AVATAR_SIZE}px`, - ), - sxProp as SxProp, - ) - : merge({'--avatar-size': `${size}px`} as React.CSSProperties, sxProp as SxProp) - - if (enabled) { - const cssSizeVars = {} as Record + const cssSizeVars = {} as Record - if (isResponsive) { - for (const [key, value] of Object.entries(size)) { - cssSizeVars[`--avatarSize-${key}`] = `${value}px` - } - } else { - cssSizeVars['--avatarSize-regular'] = `${size}px` - } - - if (sxProp !== defaultSxProp) { - return ( - - ) + if (isResponsive) { + for (const [key, value] of Object.entries(size)) { + cssSizeVars[`--avatarSize-${key}`] = `${value}px` } + } else { + cssSizeVars['--avatarSize-regular'] = `${size}px` + } + if (sxProp !== defaultSxProp) { return ( - {alt} ) } return ( - ) diff --git a/packages/react/src/Token/__tests__/__snapshots__/Token.test.tsx.snap b/packages/react/src/Token/__tests__/__snapshots__/Token.test.tsx.snap index 03df8bfbb06..3449f9106b1 100644 --- a/packages/react/src/Token/__tests__/__snapshots__/Token.test.tsx.snap +++ b/packages/react/src/Token/__tests__/__snapshots__/Token.test.tsx.snap @@ -9,6 +9,13 @@ exports[`Token components AvatarToken renders all sizes 1`] = ` margin-right: 4px; } +.c3 { + width: 16px; + height: 16px; + width: 100%; + height: 100%; +} + .c5 { position: absolute; width: 1px; @@ -22,20 +29,6 @@ exports[`Token components AvatarToken renders all sizes 1`] = ` border-width: 0; } -.c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 16px; - width: 100%; - height: 100%; -} - .c0 { -webkit-align-items: center; -webkit-box-align: center; @@ -175,11 +168,15 @@ exports[`Token components AvatarToken renders all sizes 1`] = ` > @@ -235,6 +232,13 @@ exports[`Token components AvatarToken renders all sizes 2`] = ` margin-right: 4px; } +.c3 { + width: 20px; + height: 20px; + width: 100%; + height: 100%; +} + .c5 { position: absolute; width: 1px; @@ -248,20 +252,6 @@ exports[`Token components AvatarToken renders all sizes 2`] = ` border-width: 0; } -.c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 20px; - width: 100%; - height: 100%; -} - .c0 { -webkit-align-items: center; -webkit-box-align: center; @@ -401,11 +391,15 @@ exports[`Token components AvatarToken renders all sizes 2`] = ` > @@ -461,6 +455,13 @@ exports[`Token components AvatarToken renders all sizes 3`] = ` margin-right: 8px; } +.c3 { + width: 24px; + height: 24px; + width: 100%; + height: 100%; +} + .c5 { position: absolute; width: 1px; @@ -474,20 +475,6 @@ exports[`Token components AvatarToken renders all sizes 3`] = ` border-width: 0; } -.c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 24px; - width: 100%; - height: 100%; -} - .c0 { -webkit-align-items: center; -webkit-box-align: center; @@ -627,11 +614,15 @@ exports[`Token components AvatarToken renders all sizes 3`] = ` > @@ -687,6 +678,13 @@ exports[`Token components AvatarToken renders all sizes 4`] = ` margin-right: 8px; } +.c3 { + width: 32px; + height: 32px; + width: 100%; + height: 100%; +} + .c5 { position: absolute; width: 1px; @@ -700,20 +698,6 @@ exports[`Token components AvatarToken renders all sizes 4`] = ` border-width: 0; } -.c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 32px; - width: 100%; - height: 100%; -} - .c0 { -webkit-align-items: center; -webkit-box-align: center; @@ -855,11 +839,15 @@ exports[`Token components AvatarToken renders all sizes 4`] = ` > @@ -916,15 +904,8 @@ exports[`Token components AvatarToken renders isSelected 1`] = ` } .c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 20px; + width: 20px; + height: 20px; width: 100%; height: 100%; } @@ -1018,11 +999,15 @@ exports[`Token components AvatarToken renders isSelected 1`] = ` > @@ -1044,6 +1029,13 @@ exports[`Token components AvatarToken renders with a remove button 1`] = ` margin-right: 4px; } +.c3 { + width: 20px; + height: 20px; + width: 100%; + height: 100%; +} + .c5 { position: absolute; width: 1px; @@ -1057,20 +1049,6 @@ exports[`Token components AvatarToken renders with a remove button 1`] = ` border-width: 0; } -.c3 { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 50%; - box-shadow: 0 0 0 1px var(--avatar-borderColor,var(--color-avatar-border,rgba(31,35,40,0.15))); - height: var(--avatar-size); - width: var(--avatar-size); - --avatar-size: 20px; - width: 100%; - height: 100%; -} - .c0 { -webkit-align-items: center; -webkit-box-align: center; @@ -1210,11 +1188,15 @@ exports[`Token components AvatarToken renders with a remove button 1`] = ` > diff --git a/packages/react/src/__tests__/Avatar.test.tsx b/packages/react/src/__tests__/Avatar.test.tsx index 1f26fd82535..bc766cb8118 100644 --- a/packages/react/src/__tests__/Avatar.test.tsx +++ b/packages/react/src/__tests__/Avatar.test.tsx @@ -7,7 +7,12 @@ import axe from 'axe-core' import {FeatureFlags} from '../FeatureFlags' describe('Avatar', () => { - behavesAsComponent({Component: Avatar}) + behavesAsComponent({ + Component: Avatar, + options: { + skipAs: true, + }, + }) checkExports('Avatar', { default: Avatar,