Skip to content

Commit 09a5d80

Browse files
authored
Adds size prop to the SegmentedControl (#2347)
* adds small size variant and updates stories * updates component docs * updates snapshot * adds changeset
1 parent 0805aaa commit 09a5d80

File tree

6 files changed

+42
-12
lines changed

6 files changed

+42
-12
lines changed

.changeset/large-trains-press.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+
Adds a `size` prop to the SegmentedControl component. Users can choose between 'medium' (default), and 'small'. More sizes can be added when/if we find we need them.

docs/content/SegmentedControl.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ const Controlled = () => {
3939
render(Controlled)
4040
```
4141

42+
### Small
43+
44+
```jsx live
45+
<SegmentedControl aria-label="File view" size="small">
46+
<SegmentedControl.Button defaultSelected>Preview</SegmentedControl.Button>
47+
<SegmentedControl.Button>Raw</SegmentedControl.Button>
48+
<SegmentedControl.Button>Blame</SegmentedControl.Button>
49+
</SegmentedControl>
50+
```
51+
4252
### With icons and labels
4353

4454
```jsx live
@@ -210,6 +220,7 @@ render(Controlled)
210220
type="boolean"
211221
description="Whether the segment is selected. This is used for controlled SegmentedControls, and needs to be updated using the onChange handler on SegmentedControl."
212222
/>
223+
<PropsTableRow name="selected" type="'small' | 'medium'" description="The size of the buttons" />
213224
<PropsTableRow
214225
name="defaultSelected"
215226
type="boolean"

src/SegmentedControl/SegmentedControl.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,24 @@ type SegmentedControlProps = {
2424
fullWidth?: boolean | ResponsiveValue<boolean>
2525
/** The handler that gets called when a segment is selected */
2626
onChange?: (selectedIndex: number) => void
27+
/** The size of the buttons */
28+
size?: 'small' | 'medium'
2729
/** Configure alternative ways to render the control when it gets rendered in tight spaces */
2830
variant?: 'default' | Partial<Record<WidthOnlyViewportRangeKeys, 'hideLabels' | 'dropdown' | 'default'>>
2931
} & SxProp
3032

31-
const getSegmentedControlStyles = (isFullWidth?: boolean) => ({
33+
const getSegmentedControlStyles = (props: {isFullWidth?: boolean; size?: SegmentedControlProps['size']}) => ({
3234
backgroundColor: 'segmentedControl.bg',
3335
borderColor: 'border.default',
3436
borderRadius: 2,
3537
borderStyle: 'solid',
3638
borderWidth: 1,
37-
display: isFullWidth ? 'flex' : 'inline-flex',
38-
height: '32px', // TODO: use primitive `control.medium.size` when it is available
39+
display: props.isFullWidth ? 'flex' : 'inline-flex',
40+
fontSize: props.size === 'small' ? 0 : 1,
41+
height: props.size === 'small' ? '28px' : '32px', // TODO: use primitive `control.{small|medium}.size` when it is available
3942
margin: 0,
4043
padding: 0,
41-
width: isFullWidth ? '100%' : undefined
44+
width: props.isFullWidth ? '100%' : undefined
4245
})
4346

4447
const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
@@ -47,6 +50,7 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
4750
children,
4851
fullWidth,
4952
onChange,
53+
size,
5054
sx: sxProp = {},
5155
variant,
5256
...rest
@@ -91,7 +95,7 @@ const Root: React.FC<React.PropsWithChildren<SegmentedControlProps>> = ({
9195

9296
return React.isValidElement<SegmentedControlIconButtonProps>(childArg) ? childArg.props['aria-label'] : null
9397
}
94-
const listSx = merge(getSegmentedControlStyles(isFullWidth), sxProp as SxProp)
98+
const listSx = merge(getSegmentedControlStyles({isFullWidth, size}), sxProp as SxProp)
9599

96100
if (!ariaLabel && !ariaLabelledby) {
97101
// eslint-disable-next-line no-console

src/SegmentedControl/__snapshots__/SegmentedControl.test.tsx.snap

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ exports[`SegmentedControl renders consistently 1`] = `
1010
flex-grow: 1;
1111
margin-top: -1px;
1212
margin-bottom: -1px;
13-
height: 32px;
1413
--separator-color: transparent;
1514
}
1615
@@ -45,7 +44,6 @@ exports[`SegmentedControl renders consistently 1`] = `
4544
flex-grow: 1;
4645
margin-top: -1px;
4746
margin-bottom: -1px;
48-
height: 32px;
4947
--separator-color: #d0d7de;
5048
}
5149
@@ -82,7 +80,7 @@ exports[`SegmentedControl renders consistently 1`] = `
8280
color: currentColor;
8381
cursor: pointer;
8482
font-family: inherit;
85-
font-size: 14px;
83+
font-size: inherit;
8684
font-weight: 600;
8785
padding: 0;
8886
height: 100%;
@@ -145,7 +143,7 @@ exports[`SegmentedControl renders consistently 1`] = `
145143
color: currentColor;
146144
cursor: pointer;
147145
font-family: inherit;
148-
font-size: 14px;
146+
font-size: inherit;
149147
font-weight: 400;
150148
padding: var(--segmented-control-button-bg-inset);
151149
height: 100%;
@@ -216,7 +214,7 @@ exports[`SegmentedControl renders consistently 1`] = `
216214
color: currentColor;
217215
cursor: pointer;
218216
font-family: inherit;
219-
font-size: 14px;
217+
font-size: inherit;
220218
font-weight: 400;
221219
padding: var(--segmented-control-button-bg-inset);
222220
height: 100%;
@@ -286,6 +284,7 @@ exports[`SegmentedControl renders consistently 1`] = `
286284
display: -webkit-inline-flex;
287285
display: -ms-inline-flexbox;
288286
display: inline-flex;
287+
font-size: 14px;
289288
height: 32px;
290289
margin: 0;
291290
padding: 0;

src/SegmentedControl/examples.stories.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Args = {
1212
fullWidthAtNarrow?: boolean
1313
fullWidthAtRegular?: boolean
1414
fullWidthAtWide?: boolean
15+
size?: 'small' | 'medium'
1516
variantAtNarrow: ResponsiveVariantOptions
1617
variantAtRegular: ResponsiveVariantOptions
1718
variantAtWide: ResponsiveVariantOptions
@@ -72,6 +73,13 @@ export default {
7273
type: 'boolean'
7374
}
7475
},
76+
size: {
77+
defaultValue: 'medium',
78+
control: {
79+
type: 'radio',
80+
options: ['small', 'medium']
81+
}
82+
},
7583
variantAtNarrow: {
7684
name: 'variant.narrow',
7785
defaultValue: 'default',
@@ -116,6 +124,7 @@ export const Default = (args: Args) => (
116124
aria-label="File view"
117125
fullWidth={parseFullWidthFromArgs(args)}
118126
variant={parseVariantFromArgs(args)}
127+
size={args.size}
119128
>
120129
<SegmentedControl.Button selected>Preview</SegmentedControl.Button>
121130
<SegmentedControl.Button>Raw</SegmentedControl.Button>
@@ -135,6 +144,7 @@ export const Controlled = (args: Args) => {
135144
onChange={handleChange}
136145
fullWidth={parseFullWidthFromArgs(args)}
137146
variant={parseVariantFromArgs(args)}
147+
size={args.size}
138148
>
139149
<SegmentedControl.Button selected={selectedIndex === 0}>Preview</SegmentedControl.Button>
140150
<SegmentedControl.Button selected={selectedIndex === 1}>Raw</SegmentedControl.Button>
@@ -151,6 +161,7 @@ export const WithIconsAndLabels = (args: Args) => (
151161
aria-label="File view"
152162
fullWidth={parseFullWidthFromArgs(args)}
153163
variant={parseVariantFromArgs(args)}
164+
size={args.size}
154165
>
155166
<SegmentedControl.Button selected leadingIcon={EyeIcon}>
156167
Preview
@@ -169,6 +180,7 @@ export const IconsOnly = (args: Args) => (
169180
aria-label="File view"
170181
fullWidth={parseFullWidthFromArgs(args)}
171182
variant={parseVariantFromArgs(args)}
183+
size={args.size}
172184
>
173185
<SegmentedControl.IconButton selected icon={EyeIcon} aria-label="Preview" />
174186
<SegmentedControl.IconButton icon={FileCodeIcon} aria-label="Raw" />

src/SegmentedControl/getSegmentedControlStyles.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const getSegmentedControlButtonStyles = (
3737
color: 'currentColor',
3838
cursor: 'pointer',
3939
fontFamily: 'inherit',
40-
fontSize: 1,
40+
fontSize: 'inherit',
4141
fontWeight: props?.selected ? 'bold' : 'normal',
4242
padding: props?.selected ? 0 : 'var(--segmented-control-button-bg-inset)',
4343
height: '100%',
@@ -114,7 +114,6 @@ export const getSegmentedControlListItemStyles = () => ({
114114
flexGrow: 1,
115115
marginTop: '-1px',
116116
marginBottom: '-1px',
117-
height: '32px', // TODO: use primitive `control.medium.size` when it is available
118117
':not(:last-child)': borderedSegment,
119118
...directChildLayoutAdjustments
120119
})

0 commit comments

Comments
 (0)