Skip to content

Commit 7bbdcab

Browse files
jonrohanfrancineluccahussam-i-am
authored
chore(ActionList, NavList): Remove the CSS modules feature flag from ActionList and related components (#6090)
Co-authored-by: Marie Lucca <[email protected]> Co-authored-by: Hussam Ghazzi <[email protected]>
1 parent e4f0fc6 commit 7bbdcab

23 files changed

+2035
-5116
lines changed

.changeset/eighty-turtles-repair.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 modules feature flag from the ActionList and related components

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react/jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
testMatch: ['<rootDir>/**/*.test.[jt]s?(x)', '!**/*.types.test.[jt]s?(x)'],
1717
modulePathIgnorePatterns: [
1818
'<rootDir>/src/ActionBar/',
19+
'<rootDir>/src/ActionList/',
1920
'<rootDir>/src/AnchoredOverlay/',
2021
'<rootDir>/src/Banner/',
2122
'<rootDir>/src/Blankslate/',
@@ -27,6 +28,7 @@ module.exports = {
2728
'<rootDir>/src/CircleOcticon/',
2829
'<rootDir>/src/DataTable/',
2930
'<rootDir>/src/FeatureFlags/',
31+
'<rootDir>/src/NavList/',
3032
'<rootDir>/src/ProgressBar/',
3133
'<rootDir>/src/Radio/',
3234
'<rootDir>/src/RadioGroup/',

packages/react/src/ActionList/ActionList.module.css

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,17 @@
103103

104104
/* state */
105105

106+
@media (forced-colors: active) {
107+
:focus,
108+
&:focus-visible,
109+
/* stylelint-disable-next-line selector-no-qualifying-type */
110+
> a.focus-visible,
111+
&[data-is-active-descendant] {
112+
/* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */
113+
outline: solid 1px transparent !important;
114+
}
115+
}
116+
106117
&:not(:has([aria-disabled], [disabled]), [aria-disabled='true'], [data-has-subitem='true']) {
107118
@media (hover: hover) {
108119
&:hover,
@@ -373,6 +384,13 @@
373384
mask-position: center;
374385
animation: checkmarkOut 80ms cubic-bezier(0.65, 0, 0.35, 1); /* forwards; slightly snappier animation out */
375386
}
387+
388+
@media (forced-colors: active) {
389+
/* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */
390+
391+
/* background-color will be overriden but border-width is a workaround */
392+
border-width: var(--borderWidth-thin);
393+
}
376394
}
377395

378396
&[aria-checked='true'],
@@ -389,6 +407,13 @@
389407
transition: visibility 0s linear 0s;
390408
animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
391409
}
410+
411+
@media (forced-colors: active) {
412+
/* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips
413+
background-color will be overriden but border-width is a workaround */
414+
/* stylelint-disable-next-line primer/borders */
415+
border-width: 8px;
416+
}
392417
}
393418

394419
& .SingleSelectCheckmark {

packages/react/src/ActionList/ActionList.test.tsx

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import {describe, it, expect, vi} from 'vitest'
12
import {render as HTMLRender} from '@testing-library/react'
23
import userEvent from '@testing-library/user-event'
34
import axe from 'axe-core'
45
import theme from '../theme'
56
import {ActionList} from '.'
6-
import {behavesAsComponent, checkExports} from '../utils/testing'
77
import {BaseStyles, ThemeProvider} from '..'
88

99
function SimpleActionList(): JSX.Element {
@@ -26,38 +26,16 @@ function SimpleActionList(): JSX.Element {
2626
}
2727

2828
describe('ActionList', () => {
29-
behavesAsComponent({
30-
Component: ActionList,
31-
options: {skipAs: true, skipSx: true},
32-
toRender: () => <ActionList />,
33-
})
34-
35-
behavesAsComponent({
36-
Component: ActionList.Divider,
37-
options: {skipAs: true, skipSx: true},
38-
toRender: () => <ActionList.Divider />,
39-
})
40-
41-
behavesAsComponent({
42-
Component: ActionList.TrailingAction,
43-
options: {skipAs: true, skipSx: true},
44-
toRender: () => <ActionList.TrailingAction label="Action">Action</ActionList.TrailingAction>,
45-
})
46-
47-
checkExports('ActionList', {
48-
default: undefined,
49-
ActionList,
50-
})
51-
52-
it('should have no axe violations', async () => {
29+
// toHaveNoViolations is a custom matcher from jest-axe
30+
it.skip('should have no axe violations', async () => {
5331
const {container} = HTMLRender(<SimpleActionList />)
5432
const results = await axe.run(container)
5533
expect(results).toHaveNoViolations()
5634
})
5735

5836
it('should throw when selected is provided without a selectionVariant on parent', async () => {
5937
// we expect console.error to be called, so we suppress that in the test
60-
const mockError = jest.spyOn(console, 'error').mockImplementation(() => jest.fn())
38+
const mockError = vi.spyOn(console, 'error').mockImplementation(() => vi.fn())
6139

6240
expect(() => {
6341
HTMLRender(

packages/react/src/ActionList/Description.test.tsx

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import {expect, it, describe} from 'vitest'
12
import {render as HTMLRender} from '@testing-library/react'
23
import {ActionList} from '.'
3-
import {FeatureFlags} from '../FeatureFlags'
44

55
describe('ActionList.Description', () => {
66
it('should render the description as inline without truncation by default', () => {
@@ -14,9 +14,9 @@ describe('ActionList.Description', () => {
1414

1515
const description = getByText('Item 1 description')
1616
expect(description.tagName).toBe('SPAN')
17-
expect(description).toHaveStyleRule('flex-basis', 'auto')
18-
expect(description).not.toHaveStyleRule('overflow', 'ellipsis')
19-
expect(description).not.toHaveStyleRule('white-space', 'nowrap')
17+
expect(description).toHaveStyle('flex-basis: auto')
18+
expect(description).not.toHaveStyle('overflow: ellipsis')
19+
expect(description).not.toHaveStyle('white-space: nowrap')
2020
})
2121
it('should render the description as `Truncate` when truncate is true', () => {
2222
const {getByText} = HTMLRender(
@@ -30,10 +30,10 @@ describe('ActionList.Description', () => {
3030
const description = getByText('Item 1 description')
3131
expect(description.tagName).toBe('DIV')
3232
expect(description).toHaveAttribute('title', 'Item 1 description')
33-
expect(description).toHaveStyleRule('flex-basis', '0')
34-
expect(description).toHaveStyleRule('text-overflow', 'ellipsis')
35-
expect(description).toHaveStyleRule('overflow', 'hidden')
36-
expect(description).toHaveStyleRule('white-space', 'nowrap')
33+
expect(description).toHaveStyle('flex-basis: auto')
34+
expect(description).toHaveStyle('text-overflow: ellipsis')
35+
expect(description).toHaveStyle('overflow: hidden')
36+
expect(description).toHaveStyle('white-space: nowrap')
3737
})
3838
it('should render the description in a new line when variant is block', () => {
3939
const {getByText} = HTMLRender(
@@ -46,7 +46,10 @@ describe('ActionList.Description', () => {
4646

4747
const description = getByText('Item 1 description')
4848
expect(description.tagName).toBe('SPAN')
49-
expect(description.parentElement).toHaveAttribute('data-component', 'ActionList.Item--DividerContainer')
49+
expect(description.parentElement?.parentElement).toHaveAttribute(
50+
'data-component',
51+
'ActionList.Item--DividerContainer',
52+
)
5053
})
5154
it('should support a custom `className`', () => {
5255
const Element = () => {
@@ -58,20 +61,6 @@ describe('ActionList.Description', () => {
5861
</ActionList>
5962
)
6063
}
61-
const FeatureFlagElement = () => {
62-
return (
63-
<FeatureFlags
64-
flags={{
65-
primer_react_css_modules_ga: true,
66-
}}
67-
>
68-
<Element />
69-
</FeatureFlags>
70-
)
71-
}
72-
expect(
73-
HTMLRender(<FeatureFlagElement />).container.querySelector('span[data-component="ActionList.Description"]'),
74-
).toHaveClass('test-class-name')
7564
expect(
7665
HTMLRender(<Element />).container.querySelector('span[data-component="ActionList.Description"]'),
7766
).toHaveClass('test-class-name')
Lines changed: 28 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import React from 'react'
2-
import Box from '../Box'
32
import Truncate from '../Truncate'
43
import type {SxProp} from '../sx'
5-
import {merge} from '../sx'
64
import {ItemContext} from './shared'
7-
import {useFeatureFlag} from '../FeatureFlags'
85
import classes from './ActionList.module.css'
9-
import {clsx} from 'clsx'
106
import {defaultSxProp} from '../utils/defaultSxProp'
11-
import {actionListCssModulesFlag} from './featureflag'
7+
import {BoxWithFallback} from '../internal/components/BoxWithFallback'
8+
import {clsx} from 'clsx'
129

1310
export type ActionListDescriptionProps = {
1411
/**
@@ -32,102 +29,33 @@ export const Description: React.FC<React.PropsWithChildren<ActionListDescription
3229
truncate,
3330
...props
3431
}) => {
35-
const styles = {
36-
fontSize: 0,
37-
lineHeight: '16px',
38-
flexGrow: 1,
39-
flexBasis: variant === 'inline' && !truncate ? 'auto' : 0,
40-
minWidth: 0,
41-
marginLeft: variant === 'block' ? 0 : 2,
42-
color: 'fg.muted',
43-
'li[aria-disabled="true"] &[data-component="ActionList.Description"]': {color: 'inherit'},
44-
'li[data-variant="danger"]:hover &[data-component="ActionList.Description"], li[data-variant="danger"]:active &[data-component="ActionList.Description"]':
45-
{color: 'inherit'},
46-
}
47-
4832
const {blockDescriptionId, inlineDescriptionId} = React.useContext(ItemContext)
4933

50-
const enabled = useFeatureFlag(actionListCssModulesFlag)
51-
52-
if (enabled) {
53-
if (sx !== defaultSxProp) {
54-
if (variant === 'block' || !truncate) {
55-
return (
56-
<Box
57-
as="span"
58-
sx={merge(styles, sx as SxProp)}
59-
id={variant === 'block' ? blockDescriptionId : inlineDescriptionId}
60-
className={className}
61-
data-component="ActionList.Description"
62-
>
63-
{props.children}
64-
</Box>
65-
)
66-
} else {
67-
return (
68-
<Truncate
69-
id={inlineDescriptionId}
70-
className={className}
71-
sx={merge(styles, sx as SxProp)}
72-
title={props.children as string}
73-
inline={true}
74-
maxWidth="100%"
75-
data-component="ActionList.Description"
76-
>
77-
{props.children}
78-
</Truncate>
79-
)
80-
}
81-
}
82-
if (variant === 'block' || !truncate) {
83-
return (
84-
<span
85-
className={clsx(className, classes.Description)}
86-
data-component="ActionList.Description"
87-
id={variant === 'block' ? blockDescriptionId : inlineDescriptionId}
88-
>
89-
{props.children}
90-
</span>
91-
)
92-
} else {
93-
return (
94-
<Truncate
95-
id={inlineDescriptionId}
96-
className={clsx(className, classes.Description)}
97-
title={props.children as string}
98-
inline={true}
99-
maxWidth="100%"
100-
data-component="ActionList.Description"
101-
data-truncate={truncate}
102-
>
103-
{props.children}
104-
</Truncate>
105-
)
106-
}
34+
if (variant === 'block' || !truncate) {
35+
return (
36+
<BoxWithFallback
37+
as="span"
38+
sx={sx}
39+
id={variant === 'block' ? blockDescriptionId : inlineDescriptionId}
40+
className={clsx(className, classes.Description)}
41+
data-component="ActionList.Description"
42+
>
43+
{props.children}
44+
</BoxWithFallback>
45+
)
46+
} else {
47+
return (
48+
<Truncate
49+
id={inlineDescriptionId}
50+
className={clsx(className, classes.Description)}
51+
sx={sx}
52+
title={props.children as string}
53+
inline={true}
54+
maxWidth="100%"
55+
data-component="ActionList.Description"
56+
>
57+
{props.children}
58+
</Truncate>
59+
)
10760
}
108-
109-
return variant === 'block' || !truncate ? (
110-
<Box
111-
as="span"
112-
sx={merge(styles, sx as SxProp)}
113-
id={variant === 'block' ? blockDescriptionId : inlineDescriptionId}
114-
className={className}
115-
data-component="ActionList.Description"
116-
>
117-
{props.children}
118-
</Box>
119-
) : (
120-
<Truncate
121-
id={inlineDescriptionId}
122-
className={className}
123-
sx={merge(styles, sx as SxProp)}
124-
title={props.children as string}
125-
inline={true}
126-
maxWidth="100%"
127-
data-component="ActionList.Description"
128-
>
129-
{props.children}
130-
</Truncate>
131-
)
13261
}
133-
Description.displayName = 'ActionList.Description'

0 commit comments

Comments
 (0)