Skip to content

Commit ed6e947

Browse files
jonrohanjoshblack
andauthored
chore(SegmentedControl): Remove the CSS modules feature flag from the SegmentedControl component (#5933)
Co-authored-by: Josh Black <joshblack@github.com>
1 parent edbb7b9 commit ed6e947

File tree

6 files changed

+55
-247
lines changed

6 files changed

+55
-247
lines changed

.changeset/chilled-camels-obey.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 SegmentedControl component

packages/react/src/SegmentedControl/SegmentedControl.module.css

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@
151151
border-style: solid;
152152
border-width: var(--borderWidth-thin);
153153

154-
/*
155-
innerRadius = outerRadius - distance/2
156-
https://stackoverflow.com/questions/2932146/math-problem-determine-the-corner-radius-of-an-inner-border-based-on-outer-corn
154+
/*
155+
innerRadius = outerRadius - distance/2
156+
https://stackoverflow.com/questions/2932146/math-problem-determine-the-corner-radius-of-an-inner-border-based-on-outer-corn
157157
*/
158158
/* stylelint-disable-next-line primer/borders */
159159
border-radius: calc(var(--segmented-control-outer-radius) - var(--segmented-control-button-bg-inset) / 2);
@@ -197,3 +197,7 @@
197197
content: attr(data-text);
198198
user-select: none;
199199
}
200+
201+
.LeadingIcon {
202+
margin-right: var(--base-size-4);
203+
}

packages/react/src/SegmentedControl/SegmentedControl.tsx

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,16 @@ import {ActionList} from '../ActionList'
77
import {ActionMenu} from '../ActionMenu'
88
import {useTheme} from '../ThemeProvider'
99
import type {SxProp} from '../sx'
10-
import sx, {merge} from '../sx'
1110
import type {ResponsiveValue} from '../hooks/useResponsiveValue'
1211
import {useResponsiveValue} from '../hooks/useResponsiveValue'
1312
import type {WidthOnlyViewportRangeKeys} from '../utils/types/ViewportRangeKeys'
14-
import styled from 'styled-components'
1513
import {defaultSxProp} from '../utils/defaultSxProp'
1614
import {isElement} from 'react-is'
1715

1816
import classes from './SegmentedControl.module.css'
1917

20-
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
21-
import {useFeatureFlag} from '../FeatureFlags'
2218
import {clsx} from 'clsx'
23-
import {SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG} from './getSegmentedControlStyles'
24-
25-
// Needed because passing a ref to `Box` causes a type error
26-
const SegmentedControlList = toggleStyledComponent(
27-
SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG,
28-
'ul',
29-
styled.ul`
30-
${sx};
31-
`,
32-
)
19+
import {BoxWithFallback} from '../internal/components/BoxWithFallback'
3320

3421
type SegmentedControlProps = {
3522
'aria-label'?: string
@@ -46,19 +33,6 @@ type SegmentedControlProps = {
4633
className?: string
4734
} & SxProp
4835

49-
const getSegmentedControlStyles = (props: {isFullWidth?: boolean; size?: SegmentedControlProps['size']}) => ({
50-
backgroundColor: 'segmentedControl.bg',
51-
borderRadius: 2,
52-
border: '1px solid',
53-
borderColor: 'var(--controlTrack-borderColor-rest, transparent)',
54-
display: props.isFullWidth ? 'flex' : 'inline-flex',
55-
fontSize: props.size === 'small' ? 0 : 1,
56-
height: props.size === 'small' ? '28px' : '32px', // TODO: use primitive `control.{small|medium}.size` when it is available
57-
margin: 0,
58-
padding: 0,
59-
width: props.isFullWidth ? '100%' : undefined,
60-
})
61-
6236
const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
6337
'aria-label': ariaLabel,
6438
'aria-labelledby': ariaLabelledby,
@@ -130,9 +104,6 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
130104
return React.isValidElement<SegmentedControlIconButtonProps>(childArg) ? childArg.props['aria-label'] : null
131105
}
132106

133-
const enabled = useFeatureFlag(SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG)
134-
const listSx = enabled ? sxProp : merge(getSegmentedControlStyles({isFullWidth, size}), sxProp as SxProp)
135-
136107
if (!ariaLabel && !ariaLabelledby) {
137108
// eslint-disable-next-line no-console
138109
console.warn(
@@ -183,12 +154,13 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
183154
</>
184155
) : (
185156
// Render a segmented control
186-
<SegmentedControlList
187-
sx={listSx}
157+
<BoxWithFallback
158+
as="ul"
159+
sx={sxProp}
188160
aria-label={ariaLabel}
189161
aria-labelledby={ariaLabelledby}
190162
ref={segmentedControlContainerRef}
191-
className={clsx(enabled && classes.SegmentedControl, className)}
163+
className={clsx(classes.SegmentedControl, className)}
192164
data-full-width={isFullWidth || undefined}
193165
data-size={size}
194166
{...rest}
@@ -210,11 +182,12 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
210182
isUncontrolled && setSelectedIndexInternalState(index)
211183
},
212184
selected: index === selectedIndex,
213-
sx: {
185+
style: {
214186
'--separator-color':
215187
index === selectedIndex || index === selectedIndex - 1 ? 'transparent' : theme?.colors.border.default,
216-
...child.props.sx,
188+
...child.props.style,
217189
},
190+
sx: child.props.sx,
218191
}
219192

220193
// Render the 'hideLabels' variant of the SegmentedControlButton
@@ -255,7 +228,7 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
255228
// Render the children as-is and add the shared child props
256229
return React.cloneElement(child, sharedChildProps)
257230
})}
258-
</SegmentedControlList>
231+
</BoxWithFallback>
259232
)
260233
}
261234

packages/react/src/SegmentedControl/SegmentedControlButton.tsx

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
import type {ButtonHTMLAttributes} from 'react'
22
import React from 'react'
33
import type {IconProps} from '@primer/octicons-react'
4-
import styled from 'styled-components'
5-
import Box from '../Box'
64
import type {SxProp} from '../sx'
7-
import sx, {merge} from '../sx'
8-
import {
9-
getSegmentedControlButtonStyles,
10-
getSegmentedControlListItemStyles,
11-
SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG,
12-
} from './getSegmentedControlStyles'
135
import {defaultSxProp} from '../utils/defaultSxProp'
146
import {isElement} from 'react-is'
15-
import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles'
16-
import {useFeatureFlag} from '../FeatureFlags'
177

188
import classes from './SegmentedControl.module.css'
199
import {clsx} from 'clsx'
20-
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
10+
import {BoxWithFallback} from '../internal/components/BoxWithFallback'
2111

2212
export type SegmentedControlButtonProps = {
2313
/** The visible label rendered in the button */
@@ -31,43 +21,35 @@ export type SegmentedControlButtonProps = {
3121
} & SxProp &
3222
ButtonHTMLAttributes<HTMLButtonElement | HTMLLIElement>
3323

34-
const SegmentedControlButtonStyled = toggleStyledComponent(
35-
SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG,
36-
'button',
37-
styled.button`
38-
${getGlobalFocusStyles('-1px')};
39-
${sx};
40-
`,
41-
)
42-
4324
const SegmentedControlButton: React.FC<React.PropsWithChildren<SegmentedControlButtonProps>> = ({
4425
children,
4526
leadingIcon: LeadingIcon,
4627
selected,
4728
sx: sxProp = defaultSxProp,
4829
className,
30+
// Note: this value is read in the `SegmentedControl` component to determine which button is selected but we do not need to apply it to an underlying element
31+
defaultSelected: _defaultSelected,
4932
...rest
5033
}) => {
51-
const enabled = useFeatureFlag(SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG)
52-
const mergedSx = enabled ? sxProp : merge(getSegmentedControlListItemStyles(), sxProp as SxProp)
53-
5434
return (
55-
<Box as="li" sx={mergedSx} className={clsx(enabled && classes.Item)} data-selected={selected || undefined}>
56-
<SegmentedControlButtonStyled
35+
<BoxWithFallback as="li" sx={sxProp} className={clsx(classes.Item)} data-selected={selected ? '' : undefined}>
36+
<BoxWithFallback
37+
as="button"
5738
aria-current={selected}
58-
sx={enabled ? undefined : getSegmentedControlButtonStyles({selected, children})}
59-
className={clsx(enabled && classes.Button, className)}
39+
className={clsx(classes.Button, className)}
6040
type="button"
6141
{...rest}
6242
>
63-
<span className={clsx(enabled ? classes.Content : 'segmentedControl-content')}>
64-
{LeadingIcon && <Box mr={1}>{isElement(LeadingIcon) ? LeadingIcon : <LeadingIcon />}</Box>}
65-
<Box className={clsx(enabled ? classes.Text : 'segmentedControl-text')} data-text={children}>
43+
<span className={clsx(classes.Content, 'segmentedControl-content')}>
44+
{LeadingIcon && (
45+
<div className={classes.LeadingIcon}>{isElement(LeadingIcon) ? LeadingIcon : <LeadingIcon />}</div>
46+
)}
47+
<div className={clsx(classes.Text, 'segmentedControl-text')} data-text={children}>
6648
{children}
67-
</Box>
49+
</div>
6850
</span>
69-
</SegmentedControlButtonStyled>
70-
</Box>
51+
</BoxWithFallback>
52+
</BoxWithFallback>
7153
)
7254
}
7355

packages/react/src/SegmentedControl/SegmentedControlIconButton.tsx

Lines changed: 19 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,15 @@
11
import type {ButtonHTMLAttributes} from 'react'
22
import React from 'react'
33
import type {IconProps} from '@primer/octicons-react'
4-
import styled from 'styled-components'
54
import type {SxProp} from '../sx'
6-
import sx, {merge} from '../sx'
7-
import {
8-
getSegmentedControlButtonStyles,
9-
getSegmentedControlListItemStyles,
10-
SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG,
11-
} from './getSegmentedControlStyles'
12-
import Box from '../Box'
135
import {defaultSxProp} from '../utils/defaultSxProp'
146
import {isElement} from 'react-is'
15-
import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles'
167
import {useFeatureFlag} from '../FeatureFlags'
178
import type {TooltipDirection} from '../TooltipV2'
189
import classes from './SegmentedControl.module.css'
1910
import {clsx} from 'clsx'
20-
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
2111
import {Tooltip} from '../TooltipV2'
12+
import {BoxWithFallback} from '../internal/components/BoxWithFallback'
2213

2314
export type SegmentedControlIconButtonProps = {
2415
'aria-label': string
@@ -35,15 +26,6 @@ export type SegmentedControlIconButtonProps = {
3526
} & SxProp &
3627
ButtonHTMLAttributes<HTMLButtonElement | HTMLLIElement>
3728

38-
const SegmentedControlIconButtonStyled = toggleStyledComponent(
39-
SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG,
40-
'button',
41-
styled.button`
42-
${getGlobalFocusStyles('-1px')};
43-
${sx};
44-
`,
45-
)
46-
4729
export const SegmentedControlIconButton: React.FC<React.PropsWithChildren<SegmentedControlIconButtonProps>> = ({
4830
'aria-label': ariaLabel,
4931
icon: Icon,
@@ -54,67 +36,54 @@ export const SegmentedControlIconButton: React.FC<React.PropsWithChildren<Segmen
5436
tooltipDirection,
5537
...rest
5638
}) => {
57-
const enabled = useFeatureFlag(SEGMENTED_CONTROL_CSS_MODULES_FEATURE_FLAG)
58-
const mergedSx = enabled
59-
? sxProp
60-
: merge(
61-
{
62-
width: '32px', // TODO: use primitive `control.medium.size` when it is available
63-
...getSegmentedControlListItemStyles(),
64-
},
65-
sxProp as SxProp,
66-
)
67-
6839
const tooltipFlagEnabled = useFeatureFlag('primer_react_segmented_control_tooltip')
6940
if (tooltipFlagEnabled) {
7041
return (
71-
<Box
42+
<BoxWithFallback
7243
as="li"
73-
sx={mergedSx}
74-
className={clsx(enabled && classes.Item, className)}
44+
sx={sxProp}
45+
className={clsx(classes.Item, className)}
7546
data-selected={selected || undefined}
7647
>
7748
<Tooltip
7849
type={description ? undefined : 'label'}
7950
text={description ? description : ariaLabel}
8051
direction={tooltipDirection}
8152
>
82-
<SegmentedControlIconButtonStyled
53+
<BoxWithFallback
54+
as="button"
8355
aria-current={selected}
8456
// If description is provided, we will use the tooltip to describe the button, so we need to keep the aria-label to label the button.
8557
aria-label={description ? ariaLabel : undefined}
86-
sx={enabled ? undefined : getSegmentedControlButtonStyles({selected})}
87-
className={clsx(enabled && classes.Button, enabled && classes.IconButton)}
58+
className={clsx(classes.Button, classes.IconButton)}
8859
{...rest}
8960
>
90-
<span className={clsx(enabled ? classes.Content : 'segmentedControl-content')}>
61+
<span className={clsx(classes.Content, 'segmentedControl-content')}>
9162
{isElement(Icon) ? Icon : <Icon />}
9263
</span>
93-
</SegmentedControlIconButtonStyled>
64+
</BoxWithFallback>
9465
</Tooltip>
95-
</Box>
66+
</BoxWithFallback>
9667
)
9768
} else {
9869
// This can be removed when primer_react_segmented_control_tooltip feature flag is GA-ed.
9970
return (
100-
<Box
71+
<BoxWithFallback
10172
as="li"
102-
sx={mergedSx}
103-
className={clsx(enabled && classes.Item, className)}
73+
sx={sxProp}
74+
className={clsx(classes.Item, className)}
10475
data-selected={selected || undefined}
10576
>
106-
<SegmentedControlIconButtonStyled
77+
<BoxWithFallback
78+
as="button"
10779
aria-label={ariaLabel}
10880
aria-current={selected}
109-
sx={enabled ? undefined : getSegmentedControlButtonStyles({selected})}
110-
className={clsx(enabled && classes.Button, enabled && classes.IconButton)}
81+
className={clsx(classes.Button, classes.IconButton)}
11182
{...rest}
11283
>
113-
<span className={clsx(enabled ? classes.Content : 'segmentedControl-content')}>
114-
{isElement(Icon) ? Icon : <Icon />}
115-
</span>
116-
</SegmentedControlIconButtonStyled>
117-
</Box>
84+
<span className={clsx(classes.Content, 'segmentedControl-content')}>{isElement(Icon) ? Icon : <Icon />}</span>
85+
</BoxWithFallback>
86+
</BoxWithFallback>
11887
)
11988
}
12089
}

0 commit comments

Comments
 (0)