Skip to content

Commit

Permalink
chore(Skeleton): Remove the CSS module feature flag from Skeleton (#5461
Browse files Browse the repository at this point in the history
)

* Remove the CSS module feature flag from Skeleton

* Create thirty-wasps-sleep.md
  • Loading branch information
jonrohan authored Dec 19, 2024
1 parent 5cba52a commit 9bd2f79
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 184 deletions.
5 changes: 5 additions & 0 deletions .changeset/thirty-wasps-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Remove the CSS module feature flag from Skeleton
1 change: 0 additions & 1 deletion packages/react/src/experimental/Skeleton/FeatureFlag.tsx

This file was deleted.

50 changes: 7 additions & 43 deletions packages/react/src/experimental/Skeleton/SkeletonAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
import React, {type CSSProperties} from 'react'
import {getBreakpointDeclarations} from '../../utils/getBreakpointDeclarations'
import {get} from '../../constants'
import {isResponsiveValue} from '../../hooks/useResponsiveValue'
import type {AvatarProps} from '../../Avatar'
import {DEFAULT_AVATAR_SIZE} from '../../Avatar/Avatar'
import {SkeletonBox} from './SkeletonBox'
import classes from './SkeletonAvatar.module.css'
import {clsx} from 'clsx'
import {useFeatureFlag} from '../../FeatureFlags'
import {merge} from '../../sx'
import {CSS_MODULE_FLAG} from './FeatureFlag'

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

const avatarSkeletonStyles = {
'&[data-component="SkeletonAvatar"]': {
borderRadius: '50%',
boxShadow: `0 0 0 1px ${get('colors.avatar.border')}`,
display: 'inline-block',
lineHeight: get('lineHeights.condensedUltra'),
height: 'var(--avatar-size)',
width: 'var(--avatar-size)',
},

'&[data-square]': {
borderRadius: 'clamp(4px, var(--avatar-size) - 24px, 6px)',
},
}

export const SkeletonAvatar: React.FC<SkeletonAvatarProps> = ({
size = DEFAULT_AVATAR_SIZE,
square,
Expand All @@ -40,40 +21,23 @@ export const SkeletonAvatar: React.FC<SkeletonAvatarProps> = ({
}) => {
const responsive = isResponsiveValue(size)
const cssSizeVars = {} as Record<string, string>
const enabled = useFeatureFlag(CSS_MODULE_FLAG)
const avatarSx = responsive
? {
...getBreakpointDeclarations(
size,
'--avatar-size' as keyof React.CSSProperties,
value => `${value || DEFAULT_AVATAR_SIZE}px`,
),
...avatarSkeletonStyles,
}
: {
'--avatar-size': `${size}px`,
...avatarSkeletonStyles,
}

if (enabled) {
if (responsive) {
for (const [key, value] of Object.entries(size)) {
cssSizeVars[`--avatarSize-${key}`] = `${value}px`
}
} else {
cssSizeVars['--avatarSize-regular'] = `${size}px`
if (responsive) {
for (const [key, value] of Object.entries(size)) {
cssSizeVars[`--avatarSize-${key}`] = `${value}px`
}
} else {
cssSizeVars['--avatarSize-regular'] = `${size}px`
}

return (
<SkeletonBox
sx={enabled ? undefined : avatarSx}
className={clsx(className, {[classes.SkeletonAvatar]: enabled})}
className={clsx(className, classes.SkeletonAvatar)}
{...rest}
data-component="SkeletonAvatar"
data-responsive={responsive ? '' : undefined}
data-square={square ? '' : undefined}
style={merge(style as CSSProperties, enabled ? cssSizeVars : {})}
style={merge(style as CSSProperties, cssSizeVars)}
/>
)
}
90 changes: 32 additions & 58 deletions packages/react/src/experimental/Skeleton/SkeletonBox.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import React from 'react'
import styled, {keyframes} from 'styled-components'
import sx, {merge, type SxProp} from '../../sx'
import {get} from '../../constants'
import {type CSSProperties, type HTMLProps} from 'react'
import {toggleStyledComponent} from '../../internal/utils/toggleStyledComponent'
import {merge, type SxProp} from '../../sx'
import {type CSSProperties} from 'react'
import {clsx} from 'clsx'
import classes from './SkeletonBox.module.css'
import {useFeatureFlag} from '../../FeatureFlags'
import {CSS_MODULE_FLAG} from './FeatureFlag'
import {defaultSxProp} from '../../utils/defaultSxProp'
import Box from '../../Box'

type SkeletonBoxProps = {
/** Height of the skeleton "box". Accepts any valid CSS `height` value. */
Expand All @@ -17,62 +14,39 @@ type SkeletonBoxProps = {
/** The className of the skeleton box */
className?: string
} & SxProp &
HTMLProps<HTMLDivElement>

const shimmer = keyframes`
from { mask-position: 200%; }
to { mask-position: 0%; }
`

const StyledSkeletonBox = toggleStyledComponent(
CSS_MODULE_FLAG,
'div',
styled.div<SkeletonBoxProps>`
animation: ${shimmer};
display: block;
background-color: var(--bgColor-muted, ${get('colors.canvas.subtle')});
border-radius: 3px;
height: ${props => props.height || '1rem'};
width: ${props => props.width};
@media (prefers-reduced-motion: no-preference) {
mask-image: linear-gradient(75deg, #000 30%, rgba(0, 0, 0, 0.65) 80%);
mask-size: 200%;
animation: ${shimmer};
animation-duration: 1s;
animation-iteration-count: infinite;
}
@media (forced-colors: active) {
outline: 1px solid transparent;
outline-offset: -1px;
}
${sx};
`,
)
React.ComponentPropsWithoutRef<'div'>

export const SkeletonBox = React.forwardRef<HTMLDivElement, SkeletonBoxProps>(function SkeletonBox(
{height, width, className, style, ...props},
{height, width, className, sx: sxProp = defaultSxProp, style, ...props},
ref,
) {
const enabled = useFeatureFlag(CSS_MODULE_FLAG)
if (sxProp !== defaultSxProp) {
return (
<Box
className={clsx(className, classes.SkeletonBox)}
style={merge(
style as CSSProperties,
{
height,
width,
} as CSSProperties,
)}
{...props}
ref={ref}
/>
)
}

return (
<StyledSkeletonBox
height={enabled ? undefined : height}
width={enabled ? undefined : width}
className={clsx(className, {[classes.SkeletonBox]: enabled})}
style={
enabled
? merge(
style as CSSProperties,
{
height,
width,
} as CSSProperties,
)
: style
}
<div
className={clsx(className, classes.SkeletonBox)}
style={merge(
style as CSSProperties,
{
height,
width,
} as CSSProperties,
)}
{...props}
ref={ref}
/>
Expand Down
88 changes: 6 additions & 82 deletions packages/react/src/experimental/Skeleton/SkeletonText.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React, {type CSSProperties, type HTMLProps} from 'react'
import Box from '../../Box'
import {SkeletonBox} from './SkeletonBox'
import classes from './SkeletonText.module.css'
import {useFeatureFlag} from '../../FeatureFlags'
import {clsx} from 'clsx'
import {merge} from '../../sx'
import {CSS_MODULE_FLAG} from './FeatureFlag'

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

const skeletonTextStyles = {
'&[data-component="SkeletonText"]': {
'--font-size': 'var(--text-body-size-medium, 0.875rem)',
'--line-height': 'var(--text-body-lineHeight-medium, 1.4285)',
'--leading': 'calc(var(--font-size) * var(--line-height) - var(--font-size))',
borderRadius: 'var(--borderRadius-small, 0.1875rem)',
height: 'var(--font-size)',
marginBlock: 'calc(var(--leading) / 2)',
},
'&[data-in-multiline="true"]': {
marginBlockEnd: 'calc(var(--leading) * 2)',
},
'&[data-in-multiline="true"]:last-child': {
maxWidth: '65%',
minWidth: '50px',
marginBottom: 0,
},
'@supports (margin-block: mod(1px, 1px))': {
'&[data-component="SkeletonText"]': {
'--leading': 'mod(var(--font-size) * var(--line-height), var(--font-size))',
},
},
'&[data-text-skeleton-size="display"], &[data-text-skeleton-size="titleLarge"]': {
borderRadius: 'var(--borderRadius-medium, 0.375rem)',
},
'&[data-text-skeleton-size="display"]': {
'--font-size': 'var(--text-display-size, 2.5rem)',
'--line-height': 'var(--text-display-lineHeight, 1.4)',
},
'&[data-text-skeleton-size="titleLarge"]': {
'--font-size': 'var(--text-title-size-large, 2.5rem)',
'--line-height': 'var(--text-title-lineHeight-large, 1.5)',
},
'&[data-text-skeleton-size="titleMedium"]': {
'--font-size': 'var(--text-title-size-medium, 1.25rem)',
'--line-height': 'var(--text-title-lineHeight-medium, 1.6)',
},
'&[data-text-skeleton-size="titleSmall"]': {
'--font-size': 'var(--text-title-size-small, 1rem)',
'--line-height': 'var(--text-title-lineHeight-small, 1.5)',
},
'&[data-text-skeleton-size="subtitle"]': {
'--font-size': 'var(--text-subtitle-size, 1.25rem)',
'--line-height': 'var(--text-subtitle-lineHeight, 1.6)',
},
'&[data-text-skeleton-size="bodyLarge"]': {
'--font-size': 'var(--text-body-size-large, 1rem)',
'--line-height': 'var(--text-body-lineHeight-large, 1.5)',
},
'&[data-text-skeleton-size="bodySmall"]': {
'--font-size': 'var(--text-body-size-small, 0.75rem)',
'--line-height': 'var(--text-body-lineHeight-small, 1.6666)',
},
}

export const SkeletonText: React.FC<SkeletonTextProps> = ({
lines = 1,
maxWidth,
Expand All @@ -81,52 +23,34 @@ export const SkeletonText: React.FC<SkeletonTextProps> = ({
style,
...rest
}) => {
const enabled = useFeatureFlag(CSS_MODULE_FLAG)

if (lines < 2) {
return (
<SkeletonBox
data-component="SkeletonText"
data-text-skeleton-size={size}
width="100%"
className={clsx(className, {[classes.SkeletonText]: enabled})}
sx={
enabled
? {}
: {
maxWidth,
...skeletonTextStyles,
}
}
style={enabled ? merge(style as CSSProperties, {maxWidth} as CSSProperties) : style}
className={clsx(className, classes.SkeletonText)}
style={merge(style as CSSProperties, {maxWidth} as CSSProperties)}
{...rest}
/>
)
} else {
return (
<Box
<div
data-component="multilineContainer"
sx={{
maxWidth,
/* The tiny `paddingBlock` prevents margin collapse between the first skeleton line
* and a bottom margin above it.
*/
paddingBlock: '0.1px',
}}
style={enabled ? merge(style as CSSProperties, {maxWidth, paddingBlock: '0.1px'} as CSSProperties) : style}
style={merge(style as CSSProperties, {maxWidth, paddingBlock: '0.1px'} as CSSProperties)}
>
{Array.from({length: lines}, (_, index) => (
<SkeletonBox
key={index}
data-component="SkeletonText"
data-in-multiline="true"
data-text-skeleton-size={size}
sx={enabled ? {} : skeletonTextStyles}
className={clsx(className, {[classes.SkeletonText]: enabled})}
className={clsx(className, classes.SkeletonText)}
{...rest}
/>
))}
</Box>
</div>
)
}
}

0 comments on commit 9bd2f79

Please sign in to comment.