Skip to content

Commit b5ff840

Browse files
authored
feat(ButtonBase): Remove css modules feature flag from ButtonBase (#5222)
* Remove css modules feature flag from ButtonBase * Update snapshots * Create tender-queens-juggle.md * Update snapshot
1 parent 6bf3e9e commit b5ff840

File tree

5 files changed

+114
-3468
lines changed

5 files changed

+114
-3468
lines changed

.changeset/tender-queens-juggle.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+
feat(ButtonBase): Remove css modules feature flag from ButtonBase

packages/react/src/Button/ButtonBase.tsx

Lines changed: 41 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import type {ComponentPropsWithRef} from 'react'
2-
import React, {forwardRef, useMemo} from 'react'
2+
import React, {forwardRef} from 'react'
33
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'
44
import Box from '../Box'
5-
import type {BetterSystemStyleObject} from '../sx'
6-
import {merge} from '../sx'
7-
import {useTheme} from '../ThemeProvider'
85
import type {ButtonProps} from './types'
9-
import {StyledButton} from './types'
10-
import {getVariantStyles, getButtonStyles, getAlignContentSize} from './styles'
6+
import {getAlignContentSize} from './styles'
117
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
128
import {defaultSxProp} from '../utils/defaultSxProp'
139
import {VisuallyHidden} from '../VisuallyHidden'
@@ -18,20 +14,8 @@ import {ConditionalWrapper} from '../internal/components/ConditionalWrapper'
1814
import {AriaStatus} from '../live-region'
1915
import {clsx} from 'clsx'
2016
import classes from './ButtonBase.module.css'
21-
import {useFeatureFlag} from '../FeatureFlags'
2217
import {isElement} from 'react-is'
2318

24-
const iconWrapStyles = {
25-
display: 'flex',
26-
pointerEvents: 'none',
27-
}
28-
29-
const renderVisual = (Visual: React.ElementType | React.ReactElement, loading: boolean, visualName: string) => (
30-
<Box as="span" data-component={visualName} sx={{...iconWrapStyles}}>
31-
{loading ? <Spinner size="small" /> : isElement(Visual) ? Visual : <Visual />}
32-
</Box>
33-
)
34-
3519
const renderModuleVisual = (
3620
Visual: React.ElementType | React.ReactElement,
3721
loading: boolean,
@@ -70,17 +54,9 @@ const ButtonBase = forwardRef(
7054
...rest
7155
} = props
7256

73-
const enabled = useFeatureFlag('primer_react_css_modules_ga')
7457
const innerRef = React.useRef<HTMLButtonElement>(null)
7558
useRefObjectAsForwardedRef(forwardedRef, innerRef)
7659

77-
const {theme} = useTheme()
78-
const baseStyles = useMemo(() => {
79-
return merge.all([getButtonStyles(theme), getVariantStyles(variant, theme)])
80-
}, [theme, variant])
81-
const sxStyles = useMemo(() => {
82-
return merge<BetterSystemStyleObject>(baseStyles, sxProp)
83-
}, [baseStyles, sxProp])
8460
const uuid = useId(id)
8561
const loadingAnnouncementID = `${uuid}-loading-announcement`
8662

@@ -104,131 +80,7 @@ const ButtonBase = forwardRef(
10480
}, [innerRef])
10581
}
10682

107-
if (enabled) {
108-
if (sxProp !== defaultSxProp) {
109-
return (
110-
<ConditionalWrapper
111-
// If anything is passsed to `loading`, we need the wrapper:
112-
// If we just checked for `loading` as a boolean, the wrapper wouldn't be rendered
113-
// when `loading` is `false`.
114-
// Then, the component re-renders in a way that the button will lose focus when switching between loading states.
115-
if={typeof loading !== 'undefined'}
116-
className={block ? classes.ConditionalWrapper : undefined}
117-
data-loading-wrapper
118-
>
119-
<Box
120-
as={Component}
121-
sx={sxProp}
122-
aria-disabled={loading ? true : undefined}
123-
{...rest}
124-
ref={innerRef}
125-
className={clsx(classes.ButtonBase, className)}
126-
data-block={block ? 'block' : null}
127-
data-inactive={inactive ? true : undefined}
128-
data-loading={Boolean(loading)}
129-
data-no-visuals={!LeadingVisual && !TrailingVisual && !TrailingAction ? true : undefined}
130-
data-size={size}
131-
data-variant={variant}
132-
data-label-wrap={labelWrap}
133-
aria-describedby={[loadingAnnouncementID, ariaDescribedBy]
134-
.filter(descriptionID => Boolean(descriptionID))
135-
.join(' ')}
136-
// aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state.
137-
// We only set it when the button is in a loading state because it will supercede the aria-label when the screen
138-
// reader announces the button name.
139-
aria-labelledby={
140-
loading
141-
? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ')
142-
: ariaLabelledBy
143-
}
144-
id={id}
145-
onClick={loading ? undefined : onClick}
146-
>
147-
{Icon ? (
148-
loading ? (
149-
<Spinner size="small" />
150-
) : isElement(Icon) ? (
151-
Icon
152-
) : (
153-
<Icon />
154-
)
155-
) : (
156-
<>
157-
<Box
158-
as="span"
159-
data-component="buttonContent"
160-
sx={getAlignContentSize(alignContent)}
161-
className={classes.ButtonContent}
162-
>
163-
{
164-
/* If there are no leading/trailing visuals/actions to replace with a loading spinner,
165-
render a loading spiner in place of the button content. */
166-
loading &&
167-
!LeadingVisual &&
168-
!TrailingVisual &&
169-
!TrailingAction &&
170-
renderModuleVisual(Spinner, loading, 'loadingSpinner', false)
171-
}
172-
{
173-
/* Render a leading visual unless the button is in a loading state.
174-
Then replace the leading visual with a loading spinner. */
175-
LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false)
176-
}
177-
{children && (
178-
<span data-component="text" className={classes.Label} id={loading ? `${uuid}-label` : undefined}>
179-
{children}
180-
</span>
181-
)}
182-
{
183-
/* If there is a count, render a counter label unless there is a trailing visual.
184-
Then render the counter label as a trailing visual.
185-
Replace the counter label or the trailing visual with a loading spinner if:
186-
- the button is in a loading state
187-
- there is no leading visual to replace with a loading spinner
188-
*/
189-
count !== undefined && !TrailingVisual
190-
? renderModuleVisual(
191-
() => (
192-
<CounterLabel className={classes.CounterLabel} data-component="ButtonCounter">
193-
{count}
194-
</CounterLabel>
195-
),
196-
Boolean(loading) && !LeadingVisual,
197-
'trailingVisual',
198-
true,
199-
)
200-
: TrailingVisual
201-
? renderModuleVisual(
202-
TrailingVisual,
203-
Boolean(loading) && !LeadingVisual,
204-
'trailingVisual',
205-
false,
206-
)
207-
: null
208-
}
209-
</Box>
210-
{
211-
/* If there is a trailing action, render it unless the button is in a loading state
212-
and there is no leading or trailing visual to replace with a loading spinner. */
213-
TrailingAction &&
214-
renderModuleVisual(
215-
TrailingAction,
216-
Boolean(loading) && !LeadingVisual && !TrailingVisual,
217-
'trailingAction',
218-
false,
219-
)
220-
}
221-
</>
222-
)}
223-
</Box>
224-
{loading && (
225-
<VisuallyHidden>
226-
<AriaStatus id={loadingAnnouncementID}>{loadingAnnouncement}</AriaStatus>
227-
</VisuallyHidden>
228-
)}
229-
</ConditionalWrapper>
230-
)
231-
}
83+
if (sxProp !== defaultSxProp) {
23284
return (
23385
<ConditionalWrapper
23486
// If anything is passsed to `loading`, we need the wrapper:
@@ -239,10 +91,11 @@ const ButtonBase = forwardRef(
23991
className={block ? classes.ConditionalWrapper : undefined}
24092
data-loading-wrapper
24193
>
242-
<Component
94+
<Box
95+
as={Component}
96+
sx={sxProp}
24397
aria-disabled={loading ? true : undefined}
24498
{...rest}
245-
// @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent
24699
ref={innerRef}
247100
className={clsx(classes.ButtonBase, className)}
248101
data-block={block ? 'block' : null}
@@ -262,7 +115,6 @@ const ButtonBase = forwardRef(
262115
loading ? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ') : ariaLabelledBy
263116
}
264117
id={id}
265-
// @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent
266118
onClick={loading ? undefined : onClick}
267119
>
268120
{Icon ? (
@@ -275,7 +127,12 @@ const ButtonBase = forwardRef(
275127
)
276128
) : (
277129
<>
278-
<span data-component="buttonContent" data-align={alignContent} className={classes.ButtonContent}>
130+
<Box
131+
as="span"
132+
data-component="buttonContent"
133+
sx={getAlignContentSize(alignContent)}
134+
className={classes.ButtonContent}
135+
>
279136
{
280137
/* If there are no leading/trailing visuals/actions to replace with a loading spinner,
281138
render a loading spiner in place of the button content. */
@@ -287,7 +144,7 @@ const ButtonBase = forwardRef(
287144
}
288145
{
289146
/* Render a leading visual unless the button is in a loading state.
290-
Then replace the leading visual with a loading spinner. */
147+
Then replace the leading visual with a loading spinner. */
291148
LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false)
292149
}
293150
{children && (
@@ -322,7 +179,7 @@ const ButtonBase = forwardRef(
322179
)
323180
: null
324181
}
325-
</span>
182+
</Box>
326183
{
327184
/* If there is a trailing action, render it unless the button is in a loading state
328185
and there is no leading or trailing visual to replace with a loading spinner. */
@@ -336,7 +193,7 @@ const ButtonBase = forwardRef(
336193
}
337194
</>
338195
)}
339-
</Component>
196+
</Box>
340197
{loading && (
341198
<VisuallyHidden>
342199
<AriaStatus id={loadingAnnouncementID}>{loadingAnnouncement}</AriaStatus>
@@ -345,29 +202,28 @@ const ButtonBase = forwardRef(
345202
</ConditionalWrapper>
346203
)
347204
}
348-
349205
return (
350206
<ConditionalWrapper
351207
// If anything is passsed to `loading`, we need the wrapper:
352208
// If we just checked for `loading` as a boolean, the wrapper wouldn't be rendered
353209
// when `loading` is `false`.
354210
// Then, the component re-renders in a way that the button will lose focus when switching between loading states.
355211
if={typeof loading !== 'undefined'}
356-
sx={{display: block ? 'block' : 'inline-block'}}
212+
className={block ? classes.ConditionalWrapper : undefined}
357213
data-loading-wrapper
358214
>
359-
<StyledButton
360-
as={Component}
361-
sx={sxStyles}
215+
<Component
362216
aria-disabled={loading ? true : undefined}
363217
{...rest}
218+
// @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent
364219
ref={innerRef}
365-
className={className}
220+
className={clsx(classes.ButtonBase, className)}
366221
data-block={block ? 'block' : null}
367222
data-inactive={inactive ? true : undefined}
368223
data-loading={Boolean(loading)}
369224
data-no-visuals={!LeadingVisual && !TrailingVisual && !TrailingAction ? true : undefined}
370225
data-size={size}
226+
data-variant={variant}
371227
data-label-wrap={labelWrap}
372228
aria-describedby={[loadingAnnouncementID, ariaDescribedBy]
373229
.filter(descriptionID => Boolean(descriptionID))
@@ -379,6 +235,7 @@ const ButtonBase = forwardRef(
379235
loading ? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ') : ariaLabelledBy
380236
}
381237
id={id}
238+
// @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent
382239
onClick={loading ? undefined : onClick}
383240
>
384241
{Icon ? (
@@ -391,23 +248,23 @@ const ButtonBase = forwardRef(
391248
)
392249
) : (
393250
<>
394-
<Box as="span" data-component="buttonContent" sx={getAlignContentSize(alignContent)}>
251+
<span data-component="buttonContent" data-align={alignContent} className={classes.ButtonContent}>
395252
{
396253
/* If there are no leading/trailing visuals/actions to replace with a loading spinner,
397254
render a loading spiner in place of the button content. */
398255
loading &&
399256
!LeadingVisual &&
400257
!TrailingVisual &&
401258
!TrailingAction &&
402-
renderVisual(Spinner, loading, 'loadingSpinner')
259+
renderModuleVisual(Spinner, loading, 'loadingSpinner', false)
403260
}
404261
{
405262
/* Render a leading visual unless the button is in a loading state.
406263
Then replace the leading visual with a loading spinner. */
407-
LeadingVisual && renderVisual(LeadingVisual, Boolean(loading), 'leadingVisual')
264+
LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false)
408265
}
409266
{children && (
410-
<span data-component="text" id={loading ? `${uuid}-label` : undefined}>
267+
<span data-component="text" className={classes.Label} id={loading ? `${uuid}-label` : undefined}>
411268
{children}
412269
</span>
413270
)}
@@ -419,25 +276,35 @@ const ButtonBase = forwardRef(
419276
- there is no leading visual to replace with a loading spinner
420277
*/
421278
count !== undefined && !TrailingVisual
422-
? renderVisual(
423-
() => <CounterLabel data-component="ButtonCounter">{count}</CounterLabel>,
279+
? renderModuleVisual(
280+
() => (
281+
<CounterLabel className={classes.CounterLabel} data-component="ButtonCounter">
282+
{count}
283+
</CounterLabel>
284+
),
424285
Boolean(loading) && !LeadingVisual,
425286
'trailingVisual',
287+
true,
426288
)
427289
: TrailingVisual
428-
? renderVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual')
290+
? renderModuleVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual', false)
429291
: null
430292
}
431-
</Box>
293+
</span>
432294
{
433295
/* If there is a trailing action, render it unless the button is in a loading state
434296
and there is no leading or trailing visual to replace with a loading spinner. */
435297
TrailingAction &&
436-
renderVisual(TrailingAction, Boolean(loading) && !LeadingVisual && !TrailingVisual, 'trailingAction')
298+
renderModuleVisual(
299+
TrailingAction,
300+
Boolean(loading) && !LeadingVisual && !TrailingVisual,
301+
'trailingAction',
302+
false,
303+
)
437304
}
438305
</>
439306
)}
440-
</StyledButton>
307+
</Component>
441308
{loading && (
442309
<VisuallyHidden>
443310
<AriaStatus id={loadingAnnouncementID}>{loadingAnnouncement}</AriaStatus>

0 commit comments

Comments
 (0)