Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-clocks-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Refactor `Text` to CSS modules behind primer_react_css_modules_team feature flag
36 changes: 36 additions & 0 deletions e2e/components/Text.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ test.describe('Text', () => {
test('default @vrt', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question: Does this mean we only run these tests with the feature flag on? Or do we run it twice, once with and once without

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do we run it twice, once with and once without

Running once with it off and once with it on and comparing them to the same screenshot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh that's smart!

},
},
})

// Default state
expect(await page.screenshot()).toMatchSnapshot(`Text.${story.title}.png`)
})

test('default (styled-system) @vrt', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: false,
},
},
})

// Default state
Expand All @@ -53,6 +72,23 @@ test.describe('Text', () => {
test('axe @aat', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: true,
},
},
})
await expect(page).toHaveNoViolations()
})

test('axe (styled-system) @aat', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: false,
},
},
})
await expect(page).toHaveNoViolations()
})
Expand Down
32 changes: 32 additions & 0 deletions packages/react/src/Text/Text.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.Text {
&:where([data-size='small']) {
font-size: var(--text-body-size-small);
line-height: var(--text-body-lineHeight-small);
}

&:where([data-size='medium']) {
font-size: var(--text-body-size-medium);
line-height: var(--text-body-lineHeight-medium);
}

&:where([data-size='large']) {
font-size: var(--text-body-size-large);
line-height: var(--text-body-lineHeight-large);
}

&:where([data-weight='light']) {
font-weight: var(--base-text-weight-light);
}

&:where([data-weight='normal']) {
font-weight: var(--base-text-weight-normal);
}

&:where([data-weight='medium']) {
font-weight: var(--base-text-weight-medium);
}

&:where([data-weight='semibold']) {
font-weight: var(--base-text-weight-semibold);
}
}
12 changes: 1 addition & 11 deletions packages/react/src/Text/Text.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,15 @@ export default {

export const Default = () => <Text>Default Text</Text>

export const Playground: StoryFn<typeof Text> = args => <Text {...args}>{args.text}</Text>
export const Playground: StoryFn<typeof Text> = args => <Text {...args}>Playground</Text>

Playground.args = {
text: 'Playground',
as: 'span',
size: 'medium',
weight: 'normal',
}

Playground.argTypes = {
text: {
type: 'string',
},
as: {
type: 'string',
},
Expand All @@ -37,12 +33,6 @@ Playground.argTypes = {
disable: true,
},
},
forwardedAs: {
controls: false,
table: {
disable: true,
},
},
size: {
control: {
type: 'radio',
Expand Down
66 changes: 61 additions & 5 deletions packages/react/src/Text/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import cx from 'clsx'
import styled from 'styled-components'
import React, {forwardRef} from 'react'
import type {SystemCommonProps, SystemTypographyProps} from '../constants'
import {COMMON, TYPOGRAPHY} from '../constants'
import type {SxProp} from '../sx'
import sx from '../sx'
import {useFeatureFlag} from '../FeatureFlags'
import Box from '../Box'
import {useRefObjectAsForwardedRef} from '../hooks'
import classes from './Text.module.css'
import type {ComponentProps} from '../utils/types'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'

type StyledTextProps = {
size?: 'large' | 'medium' | 'small'
Expand All @@ -12,10 +19,7 @@ type StyledTextProps = {
SystemCommonProps &
SxProp

const Text = styled.span.attrs<StyledTextProps>(({size, weight}) => ({
'data-size': size,
'data-weight': weight,
}))<StyledTextProps>`
const StyledText = styled.span<StyledTextProps>`
${TYPOGRAPHY};
${COMMON};

Expand Down Expand Up @@ -52,5 +56,57 @@ const Text = styled.span.attrs<StyledTextProps>(({size, weight}) => ({

${sx};
`
export type TextProps = ComponentProps<typeof Text>

const Text = forwardRef(({as: Component = 'span', className, size, weight, ...props}, forwardedRef) => {
const enabled = useFeatureFlag('primer_react_css_modules_team')

const innerRef = React.useRef<HTMLElement>(null)
useRefObjectAsForwardedRef(forwardedRef, innerRef)

if (enabled) {
if (props.sx) {
return (
// @ts-ignore shh
<Box
as={Component}
className={cx(className, classes.Text)}
data-size={size}
data-weight={weight}
{...props}
// @ts-ignore shh
ref={innerRef}
/>
)
}

return (
// @ts-ignore shh
<Component
className={cx(className, classes.Text)}
data-size={size}
data-weight={weight}
{...props}
// @ts-ignore shh
ref={innerRef}
/>
)
}

return (
// @ts-ignore shh
<StyledText
as={Component}
className={className}
data-size={size}
data-weight={weight}
{...props}
// @ts-ignore shh
ref={innerRef}
/>
)
}) as PolymorphicForwardRefComponent<'span', StyledTextProps>

Text.displayName = 'Text'

export type TextProps = ComponentProps<typeof StyledText>
export default Text