diff --git a/.changeset/tidy-clocks-marry.md b/.changeset/tidy-clocks-marry.md
new file mode 100644
index 00000000000..1ef03228e3f
--- /dev/null
+++ b/.changeset/tidy-clocks-marry.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Refactor `Text` to CSS modules behind primer_react_css_modules_team feature flag
diff --git a/e2e/components/Text.test.ts b/e2e/components/Text.test.ts
index 031a4adf876..3749c6e2139 100644
--- a/e2e/components/Text.test.ts
+++ b/e2e/components/Text.test.ts
@@ -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,
+ },
+ },
+ })
+
+ // 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
@@ -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()
})
diff --git a/packages/react/src/Text/Text.module.css b/packages/react/src/Text/Text.module.css
new file mode 100644
index 00000000000..6b7b5552bcc
--- /dev/null
+++ b/packages/react/src/Text/Text.module.css
@@ -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);
+ }
+}
diff --git a/packages/react/src/Text/Text.stories.tsx b/packages/react/src/Text/Text.stories.tsx
index 361b30d70b9..5ee7d3514c8 100644
--- a/packages/react/src/Text/Text.stories.tsx
+++ b/packages/react/src/Text/Text.stories.tsx
@@ -9,19 +9,15 @@ export default {
export const Default = () => Default Text
-export const Playground: StoryFn = args => {args.text}
+export const Playground: StoryFn = args => Playground
Playground.args = {
- text: 'Playground',
as: 'span',
size: 'medium',
weight: 'normal',
}
Playground.argTypes = {
- text: {
- type: 'string',
- },
as: {
type: 'string',
},
@@ -37,12 +33,6 @@ Playground.argTypes = {
disable: true,
},
},
- forwardedAs: {
- controls: false,
- table: {
- disable: true,
- },
- },
size: {
control: {
type: 'radio',
diff --git a/packages/react/src/Text/Text.tsx b/packages/react/src/Text/Text.tsx
index d74320cddb8..543cadde3c2 100644
--- a/packages/react/src/Text/Text.tsx
+++ b/packages/react/src/Text/Text.tsx
@@ -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'
@@ -12,10 +19,7 @@ type StyledTextProps = {
SystemCommonProps &
SxProp
-const Text = styled.span.attrs(({size, weight}) => ({
- 'data-size': size,
- 'data-weight': weight,
-}))`
+const StyledText = styled.span`
${TYPOGRAPHY};
${COMMON};
@@ -52,5 +56,57 @@ const Text = styled.span.attrs(({size, weight}) => ({
${sx};
`
-export type TextProps = ComponentProps
+
+const Text = forwardRef(({as: Component = 'span', className, size, weight, ...props}, forwardedRef) => {
+ const enabled = useFeatureFlag('primer_react_css_modules_team')
+
+ const innerRef = React.useRef(null)
+ useRefObjectAsForwardedRef(forwardedRef, innerRef)
+
+ if (enabled) {
+ if (props.sx) {
+ return (
+ // @ts-ignore shh
+
+ )
+ }
+
+ return (
+ // @ts-ignore shh
+
+ )
+ }
+
+ return (
+ // @ts-ignore shh
+
+ )
+}) as PolymorphicForwardRefComponent<'span', StyledTextProps>
+
+Text.displayName = 'Text'
+
+export type TextProps = ComponentProps
export default Text