diff --git a/.changeset/lemon-files-complain.md b/.changeset/lemon-files-complain.md
new file mode 100644
index 00000000000..2fcaf67849e
--- /dev/null
+++ b/.changeset/lemon-files-complain.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Remove CSS modules feature flag from ButtonGroup
diff --git a/.changeset/mean-plants-cover.md b/.changeset/mean-plants-cover.md
new file mode 100644
index 00000000000..f28776936e4
--- /dev/null
+++ b/.changeset/mean-plants-cover.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Remove CSS modules feature flag from Details
diff --git a/.changeset/two-apples-juggle.md b/.changeset/two-apples-juggle.md
new file mode 100644
index 00000000000..dfa6dca0054
--- /dev/null
+++ b/.changeset/two-apples-juggle.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Remove CSS modules feature flag from Radio
diff --git a/.changeset/two-jokes-compete.md b/.changeset/two-jokes-compete.md
new file mode 100644
index 00000000000..aa9ef5878cf
--- /dev/null
+++ b/.changeset/two-jokes-compete.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Remove the CSS module feature flag from Pagehead
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-colorblind-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-colorblind-linux.png
new file mode 100644
index 00000000000..0d98488a13b
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-colorblind-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-dimmed-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-dimmed-linux.png
new file mode 100644
index 00000000000..c1aa5490e02
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-dimmed-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-high-contrast-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-high-contrast-linux.png
new file mode 100644
index 00000000000..bcf4048a588
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-high-contrast-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-linux.png
new file mode 100644
index 00000000000..0d98488a13b
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-tritanopia-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-tritanopia-linux.png
new file mode 100644
index 00000000000..0d98488a13b
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-dark-tritanopia-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-colorblind-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-colorblind-linux.png
new file mode 100644
index 00000000000..0a4942ddf89
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-colorblind-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-high-contrast-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-high-contrast-linux.png
new file mode 100644
index 00000000000..2359588a9c5
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-high-contrast-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-linux.png
new file mode 100644
index 00000000000..0a4942ddf89
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-linux.png differ
diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-tritanopia-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-tritanopia-linux.png
new file mode 100644
index 00000000000..0a4942ddf89
Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-SX-Prop-light-tritanopia-linux.png differ
diff --git a/e2e/components/ButtonGroup.test.ts b/e2e/components/ButtonGroup.test.ts
index 243f070df7f..38c79d95c69 100644
--- a/e2e/components/ButtonGroup.test.ts
+++ b/e2e/components/ButtonGroup.test.ts
@@ -142,4 +142,32 @@ test.describe('ButtonGroup', () => {
})
}
})
+
+ test.describe('SX Prop', () => {
+ for (const theme of themes) {
+ test.describe(theme, () => {
+ test('default @vrt', async ({page}) => {
+ await visit(page, {
+ id: 'components-buttongroup-devonly--sx-prop',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+
+ // Default state
+ expect(await page.screenshot()).toMatchSnapshot(`ButtonGroup.SX Prop.${theme}.png`)
+ })
+
+ test('axe @aat', async ({page}) => {
+ await visit(page, {
+ id: 'components-buttongroup-devonly--sx-prop',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+ await expect(page).toHaveNoViolations()
+ })
+ })
+ }
+ })
})
diff --git a/packages/react/src/ButtonGroup/ButtonGroup.dev.stories.tsx b/packages/react/src/ButtonGroup/ButtonGroup.dev.stories.tsx
index c0d2f2645b7..6dc85d48472 100644
--- a/packages/react/src/ButtonGroup/ButtonGroup.dev.stories.tsx
+++ b/packages/react/src/ButtonGroup/ButtonGroup.dev.stories.tsx
@@ -63,3 +63,11 @@ export const LinkButtonWithIconButtons = () => (
)
+
+export const SxProp = () => (
+
+
+
+
+
+)
diff --git a/packages/react/src/ButtonGroup/ButtonGroup.tsx b/packages/react/src/ButtonGroup/ButtonGroup.tsx
index e3cc3e0632a..0869e1e1b92 100644
--- a/packages/react/src/ButtonGroup/ButtonGroup.tsx
+++ b/packages/react/src/ButtonGroup/ButtonGroup.tsx
@@ -1,109 +1,25 @@
-import styled from 'styled-components'
-import React from 'react'
-import sx from '../sx'
-import type {ComponentProps} from '../utils/types'
+import React, {type PropsWithChildren} from 'react'
+import {type SxProp} from '../sx'
import classes from './ButtonGroup.module.css'
-import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
import {clsx} from 'clsx'
-import {useFeatureFlag} from '../FeatureFlags'
import {FocusKeys, useFocusZone} from '../hooks/useFocusZone'
import {useProvidedRefOrCreate} from '../hooks'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'
+import Box from '../Box'
+import {defaultSxProp} from '../utils/defaultSxProp'
-const StyledButtonGroup = toggleStyledComponent(
- 'primer_react_css_modules_ga',
- 'div',
- styled.div`
- display: inline-flex;
- vertical-align: middle;
- isolation: isolate;
-
- & > *:not([data-loading-wrapper]) {
- /* stylelint-disable-next-line primer/spacing */
- margin-inline-end: -1px;
- position: relative;
-
- /* reset border-radius */
- button,
- a {
- border-radius: 0;
- }
-
- &:first-child {
- button,
- a {
- border-top-left-radius: var(--borderRadius-medium);
- border-bottom-left-radius: var(--borderRadius-medium);
- }
- }
-
- &:last-child {
- button,
- a {
- border-top-right-radius: var(--borderRadius-medium);
- border-bottom-right-radius: var(--borderRadius-medium);
- }
- }
-
- &:focus,
- &:active,
- &:hover {
- z-index: 1;
- }
- }
-
- /* this is a workaround until portal based tooltips are fully removed from dotcom */
- &:has(div:last-child:empty) {
- button,
- a {
- border-radius: var(--borderRadius-medium);
- }
- }
-
- /* if child is loading button */
- & > *[data-loading-wrapper] {
- /* stylelint-disable-next-line primer/spacing */
- margin-inline-end: -1px;
- position: relative;
- /* reset border-radius */
- button,
- a {
- border-radius: 0;
- }
-
- &:focus,
- &:active,
- &:hover {
- z-index: 1;
- }
- &:first-child {
- button,
- a {
- border-top-left-radius: var(--borderRadius-medium);
- border-bottom-left-radius: var(--borderRadius-medium);
- }
- }
-
- &:last-child {
- button,
- a {
- border-top-right-radius: var(--borderRadius-medium);
- border-bottom-right-radius: var(--borderRadius-medium);
- }
- }
- }
-
- ${sx};
- `,
-)
-
-export type ButtonGroupProps = ComponentProps
+export type ButtonGroupProps = {
+ /** The role of the group */
+ role?: string
+ /** className passed in for styling */
+ className?: string
+} & PropsWithChildren &
+ SxProp
const ButtonGroup = React.forwardRef(function ButtonGroup(
- {children, className, role, ...rest},
+ {children, className, role, sx, ...rest},
forwardRef,
) {
- const enabled = useFeatureFlag('primer_react_css_modules_ga')
const buttons = React.Children.map(children, (child, index) => {child}
)
const buttonRef = useProvidedRefOrCreate(forwardRef as React.RefObject)
@@ -114,17 +30,18 @@ const ButtonGroup = React.forwardRef(function But
focusOutBehavior: 'wrap',
})
+ if (sx !== defaultSxProp) {
+ return (
+
+ {buttons}
+
+ )
+ }
+
return (
-
+
{buttons}
-
+
)
}) as PolymorphicForwardRefComponent<'div', ButtonGroupProps>
diff --git a/packages/react/src/Details/Details.tsx b/packages/react/src/Details/Details.tsx
index bc2a4c30909..4a001484b8e 100644
--- a/packages/react/src/Details/Details.tsx
+++ b/packages/react/src/Details/Details.tsx
@@ -1,33 +1,13 @@
import React, {useEffect, useState, type ComponentPropsWithoutRef, type ReactElement} from 'react'
-import styled from 'styled-components'
import type {SxProp} from '../sx'
-import sx from '../sx'
-import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
-import {useFeatureFlag} from '../FeatureFlags'
import {clsx} from 'clsx'
import classes from './Details.module.css'
import {useMergedRefs} from '../internal/hooks/useMergedRefs'
-
-const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga'
-
-const StyledDetails = toggleStyledComponent(
- CSS_MODULES_FEATURE_FLAG,
- 'details',
- styled.details`
- & > summary {
- list-style: none;
- }
- & > summary::-webkit-details-marker {
- display: none;
- }
-
- ${sx};
- `,
-)
+import {defaultSxProp} from '../utils/defaultSxProp'
+import Box from '../Box'
const Root = React.forwardRef(
- ({className, children, ...rest}, forwardRef): ReactElement => {
- const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
+ ({className, children, sx: sxProp = defaultSxProp, ...rest}, forwardRef): ReactElement => {
const detailsRef = React.useRef(null)
const ref = useMergedRefs(forwardRef, detailsRef)
const [hasSummary, setHasSummary] = useState(false)
@@ -60,12 +40,22 @@ const Root = React.forwardRef(
}
}, [])
+ if (sxProp !== defaultSxProp) {
+ return (
+
+ {/* Include default summary if summary is not provided */}
+ {!hasSummary && {'See Details'}}
+ {children}
+
+ )
+ }
+
return (
-
+
{/* Include default summary if summary is not provided */}
{!hasSummary && {'See Details'}}
{children}
-
+
)
},
)
diff --git a/packages/react/src/Details/__tests__/Details.test.tsx b/packages/react/src/Details/__tests__/Details.test.tsx
index 28be85e0945..8be6801cae8 100644
--- a/packages/react/src/Details/__tests__/Details.test.tsx
+++ b/packages/react/src/Details/__tests__/Details.test.tsx
@@ -7,7 +7,7 @@ import {behavesAsComponent, checkExports} from '../../utils/testing'
import axe from 'axe-core'
describe('Details', () => {
- behavesAsComponent({Component: Details})
+ behavesAsComponent({Component: Details, options: {skipAs: true}})
checkExports('Details', {
default: Details,
diff --git a/packages/react/src/Pagehead/Pagehead.stories.tsx b/packages/react/src/Pagehead/Pagehead.stories.tsx
index ceea390c631..7213dbf414e 100644
--- a/packages/react/src/Pagehead/Pagehead.stories.tsx
+++ b/packages/react/src/Pagehead/Pagehead.stories.tsx
@@ -35,22 +35,4 @@ Playground.argTypes = {
options: ['div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
},
},
- forwardedAs: {
- controls: false,
- table: {
- disable: true,
- },
- },
- ref: {
- controls: false,
- table: {
- disable: true,
- },
- },
- theme: {
- controls: false,
- table: {
- disable: true,
- },
- },
}
diff --git a/packages/react/src/Pagehead/Pagehead.test.tsx b/packages/react/src/Pagehead/Pagehead.test.tsx
index 0c1fc8bad2b..d4844cdc75a 100644
--- a/packages/react/src/Pagehead/Pagehead.test.tsx
+++ b/packages/react/src/Pagehead/Pagehead.test.tsx
@@ -1,6 +1,5 @@
import React from 'react'
import Pagehead from '../Pagehead'
-import theme from '../theme'
import {behavesAsComponent, checkExports} from '../utils/testing'
import {render as HTMLRender} from '@testing-library/react'
import axe from 'axe-core'
@@ -13,7 +12,7 @@ describe('Pagehead', () => {
})
it('should have no axe violations', async () => {
- const {container} = HTMLRender(Pagehead)
+ const {container} = HTMLRender(Pagehead)
const results = await axe.run(container)
expect(results).toHaveNoViolations()
})
diff --git a/packages/react/src/Pagehead/Pagehead.tsx b/packages/react/src/Pagehead/Pagehead.tsx
index 3aeb74dcfaf..7f762bf1883 100644
--- a/packages/react/src/Pagehead/Pagehead.tsx
+++ b/packages/react/src/Pagehead/Pagehead.tsx
@@ -1,42 +1,22 @@
-import styled from 'styled-components'
-import React, {type ComponentProps} from 'react'
+import React from 'react'
import {clsx} from 'clsx'
-import {get} from '../constants'
-import sx, {type SxProp} from '../sx'
-import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
+import {type SxProp} from '../sx'
import classes from './Pagehead.module.css'
-import {useFeatureFlag} from '../FeatureFlags'
+import {defaultSxProp} from '../utils/defaultSxProp'
+import Box from '../Box'
-const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga'
-
-/**
- * @deprecated
- */
-const StyledComponentPagehead = toggleStyledComponent(
- CSS_MODULES_FEATURE_FLAG,
- 'div',
- styled.div`
- position: relative;
- padding-top: ${get('space.4')};
- padding-bottom: ${get('space.4')};
- margin-bottom: ${get('space.4')};
- border-bottom: 1px solid ${get('colors.border.default')};
- ${sx};
- `,
-)
-
-const Pagehead = ({className, ...rest}: PageheadProps) => {
- const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
-
- if (enabled) {
- return
+const Pagehead = ({className, sx: sxProp = defaultSxProp, ...rest}: PageheadProps) => {
+ if (sxProp !== defaultSxProp || rest.as) {
+ return
}
-
- return
+ return
}
/**
* @deprecated
*/
-export type PageheadProps = ComponentProps & SxProp
+export type PageheadProps = SxProp &
+ React.ComponentPropsWithoutRef<'div'> & {
+ as?: React.ElementType
+ }
export default Pagehead
diff --git a/packages/react/src/Pagehead/Pagehead.types.test.tsx b/packages/react/src/Pagehead/Pagehead.types.test.tsx
index df691989646..d4d46581f1c 100644
--- a/packages/react/src/Pagehead/Pagehead.types.test.tsx
+++ b/packages/react/src/Pagehead/Pagehead.types.test.tsx
@@ -4,7 +4,3 @@ import Pagehead from '../Pagehead'
export function shouldAcceptCallWithNoProps() {
return
}
-
-export function shouldNotAcceptSystemProps() {
- return
-}
diff --git a/packages/react/src/Radio/Radio.tsx b/packages/react/src/Radio/Radio.tsx
index 33edae3fd17..be740965bc7 100644
--- a/packages/react/src/Radio/Radio.tsx
+++ b/packages/react/src/Radio/Radio.tsx
@@ -1,18 +1,13 @@
-import styled from 'styled-components'
import type {ChangeEventHandler, InputHTMLAttributes, ReactElement} from 'react'
import React, {useContext} from 'react'
import type {SxProp} from '../sx'
-import sx from '../sx'
import type {FormValidationStatus} from '../utils/types/FormValidationStatus'
import {RadioGroupContext} from '../RadioGroup/RadioGroup'
-import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles'
-import {get} from '../constants'
-import {sharedCheckboxAndRadioStyles} from '../internal/utils/sharedCheckboxAndRadioStyles'
-import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
-import {useFeatureFlag} from '../FeatureFlags'
import {clsx} from 'clsx'
import classes from './Radio.module.css'
import sharedClasses from '../Checkbox/shared.module.css'
+import {defaultSxProp} from '../utils/defaultSxProp'
+import Box from '../Box'
export type RadioProps = {
/**
@@ -47,42 +42,6 @@ export type RadioProps = {
} & InputHTMLAttributes &
SxProp
-const StyledRadio = toggleStyledComponent(
- 'primer_react_css_modules_ga',
- 'input',
- styled.input`
- ${sharedCheckboxAndRadioStyles};
- border-radius: var(--borderRadius-full, 100vh);
- transition:
- background-color,
- border-color 80ms cubic-bezier(0.33, 1, 0.68, 1); /* checked -> unchecked - add 120ms delay to fully see animation-out */
-
- &:checked {
- border-width: var(--base-size-4, 4px);
- border-color: var(
- --control-checked-bgColor-rest,
- ${get('colors.accent.fg')}
- ); /* using bgColor here to avoid a border change in dark high contrast */
- background-color: var(--control-checked-fgColor-rest, ${get('colors.fg.onEmphasis')});
-
- &:disabled {
- cursor: not-allowed;
- border-color: ${get('colors.fg.muted')};
- background-color: ${get('colors.fg.muted')};
- }
- }
-
- ${getGlobalFocusStyles()};
-
- @media (forced-colors: active) {
- background-color: canvastext;
- border-color: canvastext;
- }
-
- ${sx}
- `,
-)
-
/**
* An accessible, native radio component for selecting one option from a list.
*/
@@ -93,7 +52,7 @@ const Radio = React.forwardRef(
disabled,
name: nameProp,
onChange,
- sx: sxProp,
+ sx: sxProp = defaultSxProp,
required,
validationStatus,
value,
@@ -103,7 +62,6 @@ const Radio = React.forwardRef(
ref,
): ReactElement => {
const radioGroupContext = useContext(RadioGroupContext)
- const enabled = useFeatureFlag('primer_react_css_modules_ga')
const handleOnChange: ChangeEventHandler = e => {
radioGroupContext?.onChange && radioGroupContext.onChange(e)
onChange && onChange(e)
@@ -117,8 +75,32 @@ const Radio = React.forwardRef(
)
}
+ if (sxProp !== defaultSxProp) {
+ return (
+ // eslint-disable-next-line github/a11y-role-supports-aria-props
+
+ )
+ }
+
return (
- (
required={required}
aria-required={required ? 'true' : 'false'}
aria-invalid={validationStatus === 'error' ? 'true' : 'false'}
- sx={sxProp}
onChange={handleOnChange}
- className={clsx(className, {
- [sharedClasses.Input]: enabled,
- [classes.Radio]: enabled,
- })}
+ className={clsx(className, sharedClasses.Input, classes.Radio)}
{...rest}
/>
)
diff --git a/packages/react/src/__tests__/Radio.test.tsx b/packages/react/src/__tests__/Radio.test.tsx
index 7fdad2d5e83..310329b71b8 100644
--- a/packages/react/src/__tests__/Radio.test.tsx
+++ b/packages/react/src/__tests__/Radio.test.tsx
@@ -14,7 +14,7 @@ describe('Radio', () => {
jest.resetAllMocks()
})
- behavesAsComponent({Component: Radio, toRender: () => })
+ behavesAsComponent({options: {skipAs: true}, Component: Radio, toRender: () => })
checkExports('Radio', {
default: Radio,