Skip to content

Commit 9272a8c

Browse files
authored
Remove the CSS module feature flag from SkeletonAvatar SkeletonBox and SkeletonText (#5787)
1 parent 1555b1b commit 9272a8c

File tree

8 files changed

+59
-216
lines changed

8 files changed

+59
-216
lines changed

.changeset/young-months-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": minor
3+
---
4+
5+
Remove the CSS module feature flag from SkeletonAvatar SkeletonBox and SkeletonText

packages/react/src/experimental/Skeleton/FeatureFlag.tsx

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
import React, {type CSSProperties} from 'react'
2-
import {getBreakpointDeclarations} from '../../utils/getBreakpointDeclarations'
3-
import {get} from '../../constants'
42
import {isResponsiveValue} from '../../hooks/useResponsiveValue'
53
import type {AvatarProps} from '../../Avatar'
64
import {DEFAULT_AVATAR_SIZE} from '../../Avatar/Avatar'
75
import {SkeletonBox} from './SkeletonBox'
86
import classes from './SkeletonAvatar.module.css'
97
import {clsx} from 'clsx'
10-
import {useFeatureFlag} from '../../FeatureFlags'
118
import {merge} from '../../sx'
12-
import {CSS_MODULE_FLAG} from './FeatureFlag'
139

1410
export type SkeletonAvatarProps = Pick<AvatarProps, 'size' | 'square'> & {
1511
/** Class name for custom styling */
1612
className?: string
1713
} & Omit<React.HTMLProps<HTMLDivElement>, 'size'>
1814

19-
const avatarSkeletonStyles = {
20-
'&[data-component="SkeletonAvatar"]': {
21-
borderRadius: '50%',
22-
boxShadow: `0 0 0 1px ${get('colors.avatar.border')}`,
23-
display: 'inline-block',
24-
lineHeight: get('lineHeights.condensedUltra'),
25-
height: 'var(--avatar-size)',
26-
width: 'var(--avatar-size)',
27-
},
28-
29-
'&[data-square]': {
30-
borderRadius: 'clamp(4px, var(--avatar-size) - 24px, 6px)',
31-
},
32-
}
33-
3415
export const SkeletonAvatar: React.FC<SkeletonAvatarProps> = ({
3516
size = DEFAULT_AVATAR_SIZE,
3617
square,
@@ -40,40 +21,23 @@ export const SkeletonAvatar: React.FC<SkeletonAvatarProps> = ({
4021
}) => {
4122
const responsive = isResponsiveValue(size)
4223
const cssSizeVars = {} as Record<string, string>
43-
const enabled = useFeatureFlag(CSS_MODULE_FLAG)
44-
const avatarSx = responsive
45-
? {
46-
...getBreakpointDeclarations(
47-
size,
48-
'--avatar-size' as keyof React.CSSProperties,
49-
value => `${value || DEFAULT_AVATAR_SIZE}px`,
50-
),
51-
...avatarSkeletonStyles,
52-
}
53-
: {
54-
'--avatar-size': `${size}px`,
55-
...avatarSkeletonStyles,
56-
}
5724

58-
if (enabled) {
59-
if (responsive) {
60-
for (const [key, value] of Object.entries(size)) {
61-
cssSizeVars[`--avatarSize-${key}`] = `${value}px`
62-
}
63-
} else {
64-
cssSizeVars['--avatarSize-regular'] = `${size}px`
25+
if (responsive) {
26+
for (const [key, value] of Object.entries(size)) {
27+
cssSizeVars[`--avatarSize-${key}`] = `${value}px`
6528
}
29+
} else {
30+
cssSizeVars['--avatarSize-regular'] = `${size}px`
6631
}
6732

6833
return (
6934
<SkeletonBox
70-
sx={enabled ? undefined : avatarSx}
71-
className={clsx(className, {[classes.SkeletonAvatar]: enabled})}
35+
className={clsx(className, classes.SkeletonAvatar)}
7236
{...rest}
7337
data-component="SkeletonAvatar"
7438
data-responsive={responsive ? '' : undefined}
7539
data-square={square ? '' : undefined}
76-
style={merge(style as CSSProperties, enabled ? cssSizeVars : {})}
40+
style={merge(style as CSSProperties, cssSizeVars)}
7741
/>
7842
)
7943
}

packages/react/src/experimental/Skeleton/SkeletonBox.tsx

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import React from 'react'
2-
import styled, {keyframes} from 'styled-components'
3-
import sx, {merge, type SxProp} from '../../sx'
4-
import {get} from '../../constants'
5-
import {type CSSProperties, type HTMLProps} from 'react'
6-
import {toggleStyledComponent} from '../../internal/utils/toggleStyledComponent'
2+
import {merge, type SxProp} from '../../sx'
3+
import {type CSSProperties} from 'react'
74
import {clsx} from 'clsx'
85
import classes from './SkeletonBox.module.css'
9-
import {useFeatureFlag} from '../../FeatureFlags'
10-
import {CSS_MODULE_FLAG} from './FeatureFlag'
6+
import {defaultSxProp} from '../../utils/defaultSxProp'
7+
import Box from '../../Box'
118

129
type SkeletonBoxProps = {
1310
/** Height of the skeleton "box". Accepts any valid CSS `height` value. */
@@ -17,62 +14,40 @@ type SkeletonBoxProps = {
1714
/** The className of the skeleton box */
1815
className?: string
1916
} & SxProp &
20-
HTMLProps<HTMLDivElement>
21-
22-
const shimmer = keyframes`
23-
from { mask-position: 200%; }
24-
to { mask-position: 0%; }
25-
`
26-
27-
const StyledSkeletonBox = toggleStyledComponent(
28-
CSS_MODULE_FLAG,
29-
'div',
30-
styled.div<SkeletonBoxProps>`
31-
animation: ${shimmer};
32-
display: block;
33-
background-color: var(--skeletonLoader-bgColor, ${get('colors.canvas.subtle')});
34-
border-radius: 3px;
35-
height: ${props => props.height || '1rem'};
36-
width: ${props => props.width};
37-
38-
@media (prefers-reduced-motion: no-preference) {
39-
mask-image: linear-gradient(75deg, #000 30%, rgba(0, 0, 0, 0.65) 80%);
40-
mask-size: 200%;
41-
animation: ${shimmer};
42-
animation-duration: 1s;
43-
animation-iteration-count: infinite;
44-
}
45-
46-
@media (forced-colors: active) {
47-
outline: 1px solid transparent;
48-
outline-offset: -1px;
49-
}
50-
51-
${sx};
52-
`,
53-
)
17+
React.ComponentPropsWithoutRef<'div'>
5418

5519
export const SkeletonBox = React.forwardRef<HTMLDivElement, SkeletonBoxProps>(function SkeletonBox(
56-
{height, width, className, style, ...props},
20+
{height, width, className, style, sx: sxProp = defaultSxProp, ...props},
5721
ref,
5822
) {
59-
const enabled = useFeatureFlag(CSS_MODULE_FLAG)
23+
if (sxProp !== defaultSxProp) {
24+
return (
25+
<Box
26+
as="div"
27+
className={clsx(className, classes.SkeletonBox)}
28+
style={merge(
29+
style as CSSProperties,
30+
{
31+
height,
32+
width,
33+
} as CSSProperties,
34+
)}
35+
{...props}
36+
ref={ref}
37+
sx={sxProp}
38+
/>
39+
)
40+
}
6041
return (
61-
<StyledSkeletonBox
62-
height={enabled ? undefined : height}
63-
width={enabled ? undefined : width}
64-
className={clsx(className, {[classes.SkeletonBox]: enabled})}
65-
style={
66-
enabled
67-
? merge(
68-
style as CSSProperties,
69-
{
70-
height,
71-
width,
72-
} as CSSProperties,
73-
)
74-
: style
75-
}
42+
<div
43+
className={clsx(className, classes.SkeletonBox)}
44+
style={merge(
45+
style as CSSProperties,
46+
{
47+
height,
48+
width,
49+
} as CSSProperties,
50+
)}
7651
{...props}
7752
ref={ref}
7853
/>

packages/react/src/experimental/Skeleton/SkeletonText.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,8 @@
6363
--line-height: var(--text-body-lineHeight-small);
6464
}
6565
}
66+
67+
.SkeletonTextWrapper {
68+
/* stylelint-disable-next-line primer/spacing */
69+
padding-block: 0.1px;
70+
}
Lines changed: 7 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import React, {type CSSProperties, type HTMLProps} from 'react'
2-
import Box from '../../Box'
32
import {SkeletonBox} from './SkeletonBox'
43
import classes from './SkeletonText.module.css'
5-
import {useFeatureFlag} from '../../FeatureFlags'
64
import {clsx} from 'clsx'
75
import {merge} from '../../sx'
8-
import {CSS_MODULE_FLAG} from './FeatureFlag'
96

107
type SkeletonTextProps = {
118
/** Size of the text that the skeleton is replacing. */
@@ -18,61 +15,6 @@ type SkeletonTextProps = {
1815
className?: string
1916
} & Omit<HTMLProps<HTMLDivElement>, 'size'>
2017

21-
const skeletonTextStyles = {
22-
'&[data-component="SkeletonText"]': {
23-
'--font-size': 'var(--text-body-size-medium, 0.875rem)',
24-
'--line-height': 'var(--text-body-lineHeight-medium, 1.4285)',
25-
'--leading': 'calc(var(--font-size) * var(--line-height) - var(--font-size))',
26-
borderRadius: 'var(--borderRadius-small, 0.1875rem)',
27-
height: 'var(--font-size)',
28-
marginBlock: 'calc(var(--leading) / 2)',
29-
},
30-
'&[data-in-multiline="true"]': {
31-
marginBlockEnd: 'calc(var(--leading) * 2)',
32-
},
33-
'&[data-in-multiline="true"]:last-child': {
34-
maxWidth: '65%',
35-
minWidth: '50px',
36-
marginBottom: 0,
37-
},
38-
'@supports (margin-block: mod(1px, 1px))': {
39-
'&[data-component="SkeletonText"]': {
40-
'--leading': 'mod(var(--font-size) * var(--line-height), var(--font-size))',
41-
},
42-
},
43-
'&[data-text-skeleton-size="display"], &[data-text-skeleton-size="titleLarge"]': {
44-
borderRadius: 'var(--borderRadius-medium, 0.375rem)',
45-
},
46-
'&[data-text-skeleton-size="display"]': {
47-
'--font-size': 'var(--text-display-size, 2.5rem)',
48-
'--line-height': 'var(--text-display-lineHeight, 1.4)',
49-
},
50-
'&[data-text-skeleton-size="titleLarge"]': {
51-
'--font-size': 'var(--text-title-size-large, 2.5rem)',
52-
'--line-height': 'var(--text-title-lineHeight-large, 1.5)',
53-
},
54-
'&[data-text-skeleton-size="titleMedium"]': {
55-
'--font-size': 'var(--text-title-size-medium, 1.25rem)',
56-
'--line-height': 'var(--text-title-lineHeight-medium, 1.6)',
57-
},
58-
'&[data-text-skeleton-size="titleSmall"]': {
59-
'--font-size': 'var(--text-title-size-small, 1rem)',
60-
'--line-height': 'var(--text-title-lineHeight-small, 1.5)',
61-
},
62-
'&[data-text-skeleton-size="subtitle"]': {
63-
'--font-size': 'var(--text-subtitle-size, 1.25rem)',
64-
'--line-height': 'var(--text-subtitle-lineHeight, 1.6)',
65-
},
66-
'&[data-text-skeleton-size="bodyLarge"]': {
67-
'--font-size': 'var(--text-body-size-large, 1rem)',
68-
'--line-height': 'var(--text-body-lineHeight-large, 1.5)',
69-
},
70-
'&[data-text-skeleton-size="bodySmall"]': {
71-
'--font-size': 'var(--text-body-size-small, 0.75rem)',
72-
'--line-height': 'var(--text-body-lineHeight-small, 1.6666)',
73-
},
74-
}
75-
7618
export const SkeletonText: React.FC<SkeletonTextProps> = ({
7719
lines = 1,
7820
maxWidth,
@@ -81,52 +23,35 @@ export const SkeletonText: React.FC<SkeletonTextProps> = ({
8123
style,
8224
...rest
8325
}) => {
84-
const enabled = useFeatureFlag(CSS_MODULE_FLAG)
85-
8626
if (lines < 2) {
8727
return (
8828
<SkeletonBox
8929
data-component="SkeletonText"
9030
data-text-skeleton-size={size}
9131
width="100%"
92-
className={clsx(className, {[classes.SkeletonText]: enabled})}
93-
sx={
94-
enabled
95-
? {}
96-
: {
97-
maxWidth,
98-
...skeletonTextStyles,
99-
}
100-
}
101-
style={enabled ? merge(style as CSSProperties, {maxWidth} as CSSProperties) : style}
32+
className={clsx(className, classes.SkeletonText)}
33+
style={merge(style as CSSProperties, {maxWidth} as CSSProperties)}
10234
{...rest}
10335
/>
10436
)
10537
} else {
10638
return (
107-
<Box
39+
<div
10840
data-component="multilineContainer"
109-
sx={{
110-
maxWidth,
111-
/* The tiny `paddingBlock` prevents margin collapse between the first skeleton line
112-
* and a bottom margin above it.
113-
*/
114-
paddingBlock: '0.1px',
115-
}}
116-
style={enabled ? merge(style as CSSProperties, {maxWidth, paddingBlock: '0.1px'} as CSSProperties) : style}
41+
className={classes.SkeletonTextWrapper}
42+
style={merge(style as CSSProperties, {maxWidth} as CSSProperties)}
11743
>
11844
{Array.from({length: lines}, (_, index) => (
11945
<SkeletonBox
12046
key={index}
12147
data-component="SkeletonText"
12248
data-in-multiline="true"
12349
data-text-skeleton-size={size}
124-
sx={enabled ? {} : skeletonTextStyles}
125-
className={clsx(className, {[classes.SkeletonText]: enabled})}
50+
className={clsx(className, classes.SkeletonText)}
12651
{...rest}
12752
/>
12853
))}
129-
</Box>
54+
</div>
13055
)
13156
}
13257
}
Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
import {render} from '@testing-library/react'
22
import React from 'react'
3-
import {FeatureFlags} from '../../../FeatureFlags'
43
import {SkeletonBox} from '../SkeletonBox'
54

65
describe('SkeletonBox', () => {
76
it('should support `className` on the outermost element', () => {
8-
const Element = () => <SkeletonBox className={'test-class-name'} />
9-
const FeatureFlagElement = () => {
10-
return (
11-
<FeatureFlags
12-
flags={{
13-
primer_react_css_modules_staff: true,
14-
primer_react_css_modules_ga: true,
15-
}}
16-
>
17-
<Element />
18-
</FeatureFlags>
19-
)
20-
}
21-
expect(render(<Element />).container.firstChild).toHaveClass('test-class-name')
22-
expect(render(<FeatureFlagElement />).container.firstChild).toHaveClass('test-class-name')
7+
expect(render(<SkeletonBox className={'test-class-name'} />).container.firstChild).toHaveClass('test-class-name')
238
})
249
})
Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
import {render} from '@testing-library/react'
22
import React from 'react'
3-
import {FeatureFlags} from '../../../FeatureFlags'
43
import {SkeletonText} from '../SkeletonText'
54

65
describe('SkeletonText', () => {
76
it('should support `className` on the outermost element', () => {
8-
const Element = () => <SkeletonText className={'test-class-name'} />
9-
const FeatureFlagElement = () => {
10-
return (
11-
<FeatureFlags
12-
flags={{
13-
primer_react_css_modules_staff: true,
14-
primer_react_css_modules_ga: true,
15-
}}
16-
>
17-
<Element />
18-
</FeatureFlags>
19-
)
20-
}
21-
expect(render(<Element />).container.firstChild).toHaveClass('test-class-name')
22-
expect(render(<FeatureFlagElement />).container.firstChild).toHaveClass('test-class-name')
7+
expect(render(<SkeletonText className={'test-class-name'} />).container.firstChild).toHaveClass('test-class-name')
238
})
249
})

0 commit comments

Comments
 (0)