Skip to content

Commit 6111046

Browse files
authored
Remove sx prop support from ToggleSwitch (#6627)
1 parent 0127afd commit 6111046

File tree

7 files changed

+127
-71
lines changed

7 files changed

+127
-71
lines changed

.changeset/bright-parents-flow.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@primer/react': major
3+
'@primer/styled-react': minor
4+
---
5+
6+
Update ToggleSwitch component to no longer support sx, add sx wrapper to @primer/styled-react.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
.ToggleSwitch {
2+
display: inline-flex;
3+
align-items: center;
4+
flex-direction: row-reverse;
5+
}
6+
7+
.ToggleSwitch[data-status-label-position='start'] {
8+
flex-direction: row;
9+
}
10+
11+
.StatusText {
12+
margin-left: var(--base-size-8);
13+
margin-right: var(--base-size-8);
14+
position: relative;
15+
color: var(--fgColor-default);
16+
font-size: var(--text-body-size-medium);
17+
cursor: pointer;
18+
}
19+
20+
.StatusText[data-size='small'] {
21+
font-size: var(--text-body-size-small);
22+
}
23+
24+
.StatusText[data-disabled='true'] {
25+
color: var(--fgColor-muted);
26+
cursor: not-allowed;
27+
}
28+
29+
.StatusTextItem {
30+
text-align: right;
31+
}
32+
33+
.StatusTextItem[data-hidden='true'] {
34+
visibility: hidden;
35+
height: 0;
36+
}
37+
38+
.IconContainer {
39+
display: flex;
40+
align-items: center;
41+
width: 100%;
42+
height: 100%;
43+
overflow: hidden;
44+
}
45+
46+
.IconBox {
47+
flex-grow: 1;
48+
flex-shrink: 0;
49+
flex-basis: 50%;
50+
/* stylelint-disable-next-line primer/typography */
51+
line-height: 0;
52+
transition-property: transform;
53+
transition-duration: 80ms;
54+
}
55+
56+
.IconBox[data-type='on'] {
57+
color: var(--control-checked-fgColor-rest, var(--color-switch-track-checked-fg, var(--fgColor-onEmphasis)));
58+
transform: translateX(0);
59+
}
60+
61+
.IconBox[data-type='on'][data-checked='false'] {
62+
transform: translateX(-100%);
63+
}
64+
65+
.IconBox[data-type='on'][data-disabled='true'] {
66+
color: var(
67+
--control-checked-fgColor-disabled,
68+
var(--color-switch-track-checked-disabled-fg, var(--fgColor-onEmphasis))
69+
);
70+
}
71+
72+
.IconBox[data-type='off'] {
73+
color: var(--controlTrack-fgColor-rest, var(--color-switch-track-fg, var(--fgColor-muted)));
74+
transform: translateX(100%);
75+
}
76+
77+
.IconBox[data-type='off'][data-checked='false'] {
78+
transform: translateX(0);
79+
}
80+
81+
.IconBox[data-type='off'][data-disabled='true'] {
82+
color: var(--controlTrack-fgColor-disabled, var(--color-switch-track-disabled-fg, var(--fgColor-onEmphasis)));
83+
}

packages/react/src/ToggleSwitch/ToggleSwitch.tsx

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,21 @@ import type {MouseEventHandler} from 'react'
22
import React, {useCallback, useEffect} from 'react'
33
import styled, {css} from 'styled-components'
44
import {variant} from 'styled-system'
5-
import Box from '../Box'
5+
import {clsx} from 'clsx'
66
import Spinner from '../Spinner'
7-
import Text from '../Text'
87
import {get} from '../constants'
98
import {useProvidedStateOrCreate, useId} from '../hooks'
10-
import type {BetterSystemStyleObject, SxProp} from '../sx'
11-
import sx from '../sx'
129
import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles'
1310
import VisuallyHidden from '../_VisuallyHidden'
1411
import type {CellAlignment} from '../DataTable/column'
1512
import {AriaStatus} from '../live-region'
1613
import useSafeTimeout from '../hooks/useSafeTimeout'
14+
import classes from './ToggleSwitch.module.css'
1715

1816
const TRANSITION_DURATION = '80ms'
1917
const EASE_OUT_QUAD_CURVE = 'cubic-bezier(0.5, 1, 0.89, 1)'
2018

21-
export interface ToggleSwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>, SxProp {
19+
export interface ToggleSwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
2220
/** The id of the DOM node that labels the switch */
2321
['aria-labelledby']: string
2422
/** Uncontrolled - whether the switch is turned on */
@@ -67,7 +65,7 @@ type SwitchButtonProps = {
6765
disabled?: boolean
6866
checked?: boolean
6967
size?: ToggleSwitchProps['size']
70-
} & SxProp
68+
}
7169

7270
type InnerIconProps = {size?: ToggleSwitchProps['size']}
7371

@@ -188,7 +186,6 @@ const SwitchButton = styled.button<SwitchButtonProps>`
188186
}
189187
}}
190188
191-
${sx}
192189
${sizeVariants}
193190
`
194191
const ToggleKnob = styled.div<{checked?: boolean; 'aria-disabled': React.AriaAttributes['aria-disabled']}>`
@@ -231,11 +228,6 @@ const ToggleKnob = styled.div<{checked?: boolean; 'aria-disabled': React.AriaAtt
231228
}}
232229
`
233230

234-
const hiddenTextStyles: BetterSystemStyleObject = {
235-
visibility: 'hidden',
236-
height: 0,
237-
}
238-
239231
const ToggleSwitch = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<ToggleSwitchProps>>(
240232
function ToggleSwitch(props, ref) {
241233
const {
@@ -252,7 +244,7 @@ const ToggleSwitch = React.forwardRef<HTMLButtonElement, React.PropsWithChildren
252244
statusLabelPosition = 'start',
253245
loadingLabelDelay = 2000,
254246
loadingLabel = 'Loading',
255-
sx: sxProp,
247+
className,
256248
...rest
257249
} = props
258250
const isControlled = typeof checked !== 'undefined'
@@ -296,35 +288,28 @@ const ToggleSwitch = React.forwardRef<HTMLButtonElement, React.PropsWithChildren
296288
if (ariaDescribedby) switchButtonDescribedBy = `${switchButtonDescribedBy} ${ariaDescribedby}`
297289

298290
return (
299-
<Box
300-
display="inline-flex"
301-
alignItems="center"
302-
flexDirection={statusLabelPosition === 'start' ? 'row' : 'row-reverse'}
303-
sx={sxProp}
304-
{...rest}
305-
>
291+
<div className={clsx(classes.ToggleSwitch, className)} data-status-label-position={statusLabelPosition} {...rest}>
306292
<VisuallyHidden>
307293
<AriaStatus announceOnShow id={loadingLabelId}>
308294
{isLoadingLabelVisible && loadingLabel}
309295
</AriaStatus>
310296
</VisuallyHidden>
311297

312298
{loading ? <Spinner size="small" srText={null} /> : null}
313-
<Text
314-
color={acceptsInteraction ? 'fg.default' : 'fg.muted'}
315-
fontSize={size === 'small' ? 0 : 1}
316-
mx={2}
299+
<span
300+
className={classes.StatusText}
301+
data-size={size}
302+
data-disabled={!acceptsInteraction}
317303
aria-hidden="true"
318-
sx={{position: 'relative', cursor: acceptsInteraction ? 'pointer' : 'not-allowed'}}
319304
onClick={handleToggleClick}
320305
>
321-
<Box textAlign="right" sx={isOn ? null : hiddenTextStyles}>
306+
<div className={classes.StatusTextItem} data-hidden={!isOn}>
322307
On
323-
</Box>
324-
<Box textAlign="right" sx={isOn ? hiddenTextStyles : null}>
308+
</div>
309+
<div className={classes.StatusTextItem} data-hidden={isOn}>
325310
Off
326-
</Box>
327-
</Text>
311+
</div>
312+
</span>
328313
<SwitchButton
329314
ref={ref}
330315
type={buttonType}
@@ -336,39 +321,17 @@ const ToggleSwitch = React.forwardRef<HTMLButtonElement, React.PropsWithChildren
336321
size={size}
337322
aria-disabled={!acceptsInteraction}
338323
>
339-
<Box aria-hidden="true" display="flex" alignItems="center" width="100%" height="100%" overflow="hidden">
340-
<Box
341-
flexGrow={1}
342-
flexShrink={0}
343-
flexBasis="50%"
344-
color={acceptsInteraction ? 'switchTrack.checked.fg' : 'switchTrack.checked.disabledFg'}
345-
lineHeight="0"
346-
sx={{
347-
transform: `translateX(${isOn ? '0' : '-100%'})`,
348-
transitionProperty: 'transform',
349-
transitionDuration: TRANSITION_DURATION,
350-
}}
351-
>
324+
<div aria-hidden="true" className={classes.IconContainer}>
325+
<div className={classes.IconBox} data-type="on" data-checked={isOn} data-disabled={!acceptsInteraction}>
352326
<LineIcon size={size} />
353-
</Box>
354-
<Box
355-
flexGrow={1}
356-
flexShrink={0}
357-
flexBasis="50%"
358-
color={acceptsInteraction ? 'switchTrack.fg' : 'switchTrack.disabledFg'}
359-
lineHeight="0"
360-
sx={{
361-
transform: `translateX(${isOn ? '100%' : '0'})`,
362-
transitionProperty: 'transform',
363-
transitionDuration: TRANSITION_DURATION,
364-
}}
365-
>
327+
</div>
328+
<div className={classes.IconBox} data-type="off" data-checked={isOn} data-disabled={!acceptsInteraction}>
366329
<CircleIcon size={size} />
367-
</Box>
368-
</Box>
330+
</div>
331+
</div>
369332
<ToggleKnob aria-hidden="true" aria-disabled={!acceptsInteraction} checked={isOn} />
370333
</SwitchButton>
371-
</Box>
334+
</div>
372335
)
373336
},
374337
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.StoryWrapper {
2+
display: grid;
3+
grid-template-columns: max-content auto;
4+
max-width: 20rem;
5+
align-items: center;
6+
justify-content: space-between;
7+
}
Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
import type React from 'react'
2-
import {Box} from '..'
2+
import classes from './ToggleSwitchStoryWrapper.module.css'
33

44
const ToggleSwitchStoryWrapper: React.FC<React.PropsWithChildren> = ({children}) => (
5-
<Box
6-
display="grid"
7-
gridTemplateColumns="max-content auto"
8-
maxWidth="20rem"
9-
alignItems="center"
10-
justifyContent="space-between"
11-
>
12-
{children}
13-
</Box>
5+
<div className={classes.StoryWrapper}>{children}</div>
146
)
157

168
export default ToggleSwitchStoryWrapper

packages/styled-react/src/__tests__/__snapshots__/exports.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
exports[`@primer/styled-react exports 1`] = `
44
[
5+
"ToggleSwitch",
56
"ActionList",
67
"ActionMenu",
78
"Autocomplete",
@@ -46,7 +47,6 @@ exports[`@primer/styled-react exports 1`] = `
4647
"TextInput",
4748
"TextInputWithTokens",
4849
"Timeline",
49-
"ToggleSwitch",
5050
"Token",
5151
"Tooltip",
5252
"Truncate",

packages/styled-react/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import {ToggleSwitch as PrimerToggleSwitch} from '@primer/react'
2+
import {createStyledComponent} from './utils/createStyledComponent'
3+
4+
const ToggleSwitch: ReturnType<typeof createStyledComponent> = /*#__PURE__*/ createStyledComponent(PrimerToggleSwitch)
5+
export {ToggleSwitch}
6+
17
export {
28
ActionList,
39
ActionMenu,
@@ -43,7 +49,6 @@ export {
4349
TextInput,
4450
TextInputWithTokens,
4551
Timeline,
46-
ToggleSwitch,
4752
Token,
4853
Tooltip,
4954
Truncate,

0 commit comments

Comments
 (0)