Skip to content

Commit 50c230f

Browse files
authored
refactor(styled-react): update how we re-export components (#6726)
1 parent 99f3a36 commit 50c230f

27 files changed

+996
-318
lines changed

.changeset/chubby-colts-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/styled-react': patch
3+
---
4+
5+
Refactor ToggleSwitch export type to match original type from @primer/react

.changeset/great-hats-serve.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+
Add ProgressBarItemProps and ProgressBarItemProps type exports to @primer/react

.changeset/metal-cups-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/styled-react': patch
3+
---
4+
5+
Remove several components that have no sx usage

.changeset/nine-cobras-talk.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+
Add ToggleSwitchProps type to package exports

eslint.config.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const config = defineConfig([
4242
'contributor-docs/adrs/*',
4343
'examples/codesandbox/**/*',
4444
'packages/react/src/utils/polymorphic.ts',
45+
'packages/styled-react/src/polymorphic.d.ts',
4546
'**/storybook-static',
4647
'**/CHANGELOG.md',
4748
'**/node_modules/**/*',
@@ -376,6 +377,22 @@ const config = defineConfig([
376377
'@typescript-eslint/triple-slash-reference': 'off',
377378
},
378379
},
380+
381+
// packages/styled-react overrides
382+
{
383+
files: ['packages/styled-react/**/*.{ts,tsx}'],
384+
rules: {
385+
'primer-react/no-unnecessary-components': 'off',
386+
},
387+
},
388+
{
389+
files: ['packages/styled-react/**/*.test.{ts,tsx}'],
390+
rules: {
391+
'github/a11y-aria-label-is-well-formatted': 'off',
392+
'github/a11y-svg-has-accessible-name': 'off',
393+
'primer-react/direct-slot-children': 'off',
394+
},
395+
},
379396
])
380397

381398
export default tseslint.config(config)

package-lock.json

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

packages/react/src/ProgressBar/ProgressBar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ type StyledProgressContainerProps = {
1616
animated?: boolean
1717
} & SxProp
1818

19-
export type ProgressBarItems = React.HTMLAttributes<HTMLSpanElement> & {
19+
export type ProgressBarItemProps = React.HTMLAttributes<HTMLSpanElement> & {
2020
'aria-label'?: string
2121
className?: string
2222
} & ProgressProp &
2323
SxProp
2424

25-
export const Item = forwardRef<HTMLSpanElement, ProgressBarItems>(
25+
export const Item = forwardRef<HTMLSpanElement, ProgressBarItemProps>(
2626
(
2727
{
2828
progress,

packages/react/src/ProgressBar/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ProgressBar as Bar, Item} from './ProgressBar'
22

3-
export type {ProgressBarProps} from './ProgressBar'
3+
export type {ProgressBarProps, ProgressBarItemProps} from './ProgressBar'
44

55
/**
66
* Collection of ProgressBar related components.

packages/react/src/ToggleSwitch/ToggleSwitch.tsx

Lines changed: 121 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -72,135 +72,133 @@ const LineIcon: React.FC<React.PropsWithChildren<InnerIconProps>> = ({size}) =>
7272
</svg>
7373
)
7474

75-
const ToggleSwitch = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<ToggleSwitchProps>>(
76-
function ToggleSwitch(props, ref) {
77-
const {
78-
'aria-labelledby': ariaLabelledby,
79-
'aria-describedby': ariaDescribedby,
80-
defaultChecked,
81-
disabled,
82-
loading,
83-
checked,
84-
onChange,
85-
onClick,
86-
buttonType = 'button',
87-
size = 'medium',
88-
statusLabelPosition = 'start',
89-
loadingLabelDelay = 2000,
90-
loadingLabel = 'Loading',
91-
className,
92-
...rest
93-
} = props
94-
const isControlled = typeof checked !== 'undefined'
95-
const [isOn, setIsOn] = useProvidedStateOrCreate<boolean>(checked, onChange, Boolean(defaultChecked))
96-
const acceptsInteraction = !disabled && !loading
97-
98-
const [isLoadingLabelVisible, setIsLoadingLabelVisible] = React.useState(false)
99-
const loadingLabelId = useId('loadingLabel')
100-
101-
const {safeSetTimeout} = useSafeTimeout()
102-
103-
const handleToggleClick: MouseEventHandler = useCallback(
104-
e => {
105-
if (disabled || loading) return
106-
107-
if (!isControlled) {
108-
setIsOn(!isOn)
109-
}
110-
onClick && onClick(e)
111-
},
112-
[disabled, isControlled, loading, onClick, setIsOn, isOn],
113-
)
114-
115-
useEffect(() => {
116-
if (onChange && isControlled && !disabled) {
117-
onChange(Boolean(checked))
75+
const ToggleSwitch = React.forwardRef<HTMLButtonElement, ToggleSwitchProps>(function ToggleSwitch(props, ref) {
76+
const {
77+
'aria-labelledby': ariaLabelledby,
78+
'aria-describedby': ariaDescribedby,
79+
defaultChecked,
80+
disabled,
81+
loading,
82+
checked,
83+
onChange,
84+
onClick,
85+
buttonType = 'button',
86+
size = 'medium',
87+
statusLabelPosition = 'start',
88+
loadingLabelDelay = 2000,
89+
loadingLabel = 'Loading',
90+
className,
91+
...rest
92+
} = props
93+
const isControlled = typeof checked !== 'undefined'
94+
const [isOn, setIsOn] = useProvidedStateOrCreate<boolean>(checked, onChange, Boolean(defaultChecked))
95+
const acceptsInteraction = !disabled && !loading
96+
97+
const [isLoadingLabelVisible, setIsLoadingLabelVisible] = React.useState(false)
98+
const loadingLabelId = useId('loadingLabel')
99+
100+
const {safeSetTimeout} = useSafeTimeout()
101+
102+
const handleToggleClick: MouseEventHandler = useCallback(
103+
e => {
104+
if (disabled || loading) return
105+
106+
if (!isControlled) {
107+
setIsOn(!isOn)
118108
}
119-
}, [onChange, checked, isControlled, disabled])
120-
121-
useEffect(() => {
122-
if (!loading && isLoadingLabelVisible) {
123-
setIsLoadingLabelVisible(false)
124-
} else if (loading && !isLoadingLabelVisible) {
125-
safeSetTimeout(() => {
126-
setIsLoadingLabelVisible(true)
127-
}, loadingLabelDelay)
128-
}
129-
}, [loading, isLoadingLabelVisible, loadingLabelDelay, safeSetTimeout])
130-
131-
let switchButtonDescribedBy = loadingLabelId
132-
if (ariaDescribedby) switchButtonDescribedBy = `${switchButtonDescribedBy} ${ariaDescribedby}`
133-
134-
return (
135-
<div className={clsx(classes.ToggleSwitch, className)} data-status-label-position={statusLabelPosition} {...rest}>
136-
<VisuallyHidden>
137-
<AriaStatus announceOnShow id={loadingLabelId}>
138-
{isLoadingLabelVisible && loadingLabel}
139-
</AriaStatus>
140-
</VisuallyHidden>
141-
142-
{loading ? (
143-
<div className={classes.LoadingSpinner} data-status-label-position={statusLabelPosition}>
144-
<Spinner size="small" srText={null} />
145-
</div>
146-
) : null}
147-
148-
<span
149-
className={classes.StatusText}
150-
data-size={size}
151-
data-disabled={!acceptsInteraction}
152-
aria-hidden="true"
153-
onClick={handleToggleClick}
154-
>
155-
<span className={classes.StatusTextItem} data-hidden={!isOn}>
156-
On
157-
</span>
158-
<span className={classes.StatusTextItem} data-hidden={isOn}>
159-
Off
160-
</span>
109+
onClick && onClick(e)
110+
},
111+
[disabled, isControlled, loading, onClick, setIsOn, isOn],
112+
)
113+
114+
useEffect(() => {
115+
if (onChange && isControlled && !disabled) {
116+
onChange(Boolean(checked))
117+
}
118+
}, [onChange, checked, isControlled, disabled])
119+
120+
useEffect(() => {
121+
if (!loading && isLoadingLabelVisible) {
122+
setIsLoadingLabelVisible(false)
123+
} else if (loading && !isLoadingLabelVisible) {
124+
safeSetTimeout(() => {
125+
setIsLoadingLabelVisible(true)
126+
}, loadingLabelDelay)
127+
}
128+
}, [loading, isLoadingLabelVisible, loadingLabelDelay, safeSetTimeout])
129+
130+
let switchButtonDescribedBy = loadingLabelId
131+
if (ariaDescribedby) switchButtonDescribedBy = `${switchButtonDescribedBy} ${ariaDescribedby}`
132+
133+
return (
134+
<div className={clsx(classes.ToggleSwitch, className)} data-status-label-position={statusLabelPosition} {...rest}>
135+
<VisuallyHidden>
136+
<AriaStatus announceOnShow id={loadingLabelId}>
137+
{isLoadingLabelVisible && loadingLabel}
138+
</AriaStatus>
139+
</VisuallyHidden>
140+
141+
{loading ? (
142+
<div className={classes.LoadingSpinner} data-status-label-position={statusLabelPosition}>
143+
<Spinner size="small" srText={null} />
144+
</div>
145+
) : null}
146+
147+
<span
148+
className={classes.StatusText}
149+
data-size={size}
150+
data-disabled={!acceptsInteraction}
151+
aria-hidden="true"
152+
onClick={handleToggleClick}
153+
>
154+
<span className={classes.StatusTextItem} data-hidden={!isOn}>
155+
On
161156
</span>
162-
163-
<button
164-
ref={ref}
165-
// eslint-disable-next-line react/button-has-type
166-
type={buttonType}
167-
className={classes.SwitchButton}
168-
data-size={size}
169-
data-checked={isOn}
170-
data-disabled={!acceptsInteraction}
171-
onClick={handleToggleClick}
172-
aria-labelledby={ariaLabelledby}
173-
aria-describedby={isLoadingLabelVisible || ariaDescribedby ? switchButtonDescribedBy : undefined}
174-
aria-pressed={isOn}
175-
aria-disabled={!acceptsInteraction}
176-
>
177-
<div className={classes.SwitchButtonContent} aria-hidden="true">
178-
<div
179-
className={`${classes.IconContainer} ${classes.LineIconContainer}`}
180-
data-checked={isOn}
181-
data-disabled={!acceptsInteraction}
182-
>
183-
<LineIcon size={size} />
184-
</div>
185-
<div
186-
className={`${classes.IconContainer} ${classes.CircleIconContainer}`}
187-
data-checked={isOn}
188-
data-disabled={!acceptsInteraction}
189-
>
190-
<CircleIcon size={size} />
191-
</div>
157+
<span className={classes.StatusTextItem} data-hidden={isOn}>
158+
Off
159+
</span>
160+
</span>
161+
162+
<button
163+
ref={ref}
164+
// eslint-disable-next-line react/button-has-type
165+
type={buttonType}
166+
className={classes.SwitchButton}
167+
data-size={size}
168+
data-checked={isOn}
169+
data-disabled={!acceptsInteraction}
170+
onClick={handleToggleClick}
171+
aria-labelledby={ariaLabelledby}
172+
aria-describedby={isLoadingLabelVisible || ariaDescribedby ? switchButtonDescribedBy : undefined}
173+
aria-pressed={isOn}
174+
aria-disabled={!acceptsInteraction}
175+
>
176+
<div className={classes.SwitchButtonContent} aria-hidden="true">
177+
<div
178+
className={`${classes.IconContainer} ${classes.LineIconContainer}`}
179+
data-checked={isOn}
180+
data-disabled={!acceptsInteraction}
181+
>
182+
<LineIcon size={size} />
192183
</div>
193184
<div
194-
className={classes.ToggleKnob}
185+
className={`${classes.IconContainer} ${classes.CircleIconContainer}`}
195186
data-checked={isOn}
196187
data-disabled={!acceptsInteraction}
197-
aria-hidden="true"
198-
/>
199-
</button>
200-
</div>
201-
)
202-
},
203-
)
188+
>
189+
<CircleIcon size={size} />
190+
</div>
191+
</div>
192+
<div
193+
className={classes.ToggleKnob}
194+
data-checked={isOn}
195+
data-disabled={!acceptsInteraction}
196+
aria-hidden="true"
197+
/>
198+
</button>
199+
</div>
200+
)
201+
})
204202

205203
if (__DEV__) {
206204
ToggleSwitch.displayName = 'ToggleSwitch'

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ exports[`@primer/react > should not update exports without a semver change 1`] =
118118
"Portal",
119119
"type PortalProps",
120120
"ProgressBar",
121+
"type ProgressBarItemProps",
121122
"type ProgressBarProps",
122123
"Radio",
123124
"RadioGroup",
@@ -177,6 +178,7 @@ exports[`@primer/react > should not update exports without a semver change 1`] =
177178
"type TimelineItemsProps",
178179
"type TimelineProps",
179180
"ToggleSwitch",
181+
"type ToggleSwitchProps",
180182
"Token",
181183
"type TokenProps",
182184
"Tooltip",

0 commit comments

Comments
 (0)