1
1
import { clsx } from 'clsx'
2
2
import React , { forwardRef , useEffect } from 'react'
3
- import styled from 'styled-components'
4
3
import { AlertIcon , InfoIcon , StopIcon , CheckCircleIcon , XIcon } from '@primer/octicons-react'
5
4
import { Button , IconButton , type ButtonProps } from '../Button'
6
- import { get } from '../constants'
7
5
import { VisuallyHidden } from '../VisuallyHidden'
8
6
import { useMergedRefs } from '../internal/hooks/useMergedRefs'
9
- import { useFeatureFlag } from '../FeatureFlags'
10
7
import classes from './Banner.module.css'
11
- import { toggleStyledComponent } from '../internal/utils/toggleStyledComponent'
12
8
import type { ForwardRefComponent as PolymorphicForwardRefComponent } from '../utils/polymorphic'
13
9
14
10
type BannerVariant = 'critical' | 'info' | 'success' | 'upsell' | 'warning'
@@ -88,8 +84,6 @@ const labels: Record<BannerVariant, string> = {
88
84
warning : 'Warning' ,
89
85
}
90
86
91
- const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga'
92
-
93
87
export const Banner = React . forwardRef < HTMLElement , BannerProps > ( function Banner (
94
88
{
95
89
'aria-label' : label ,
@@ -111,7 +105,6 @@ export const Banner = React.forwardRef<HTMLElement, BannerProps>(function Banner
111
105
const hasActions = primaryAction || secondaryAction
112
106
const bannerRef = React . useRef < HTMLElement > ( null )
113
107
const ref = useMergedRefs ( forwardRef , bannerRef )
114
- const enabled = useFeatureFlag ( CSS_MODULES_FEATURE_FLAG )
115
108
const supportsCustomIcon = variant === 'info' || variant === 'upsell'
116
109
117
110
if ( __DEV__ ) {
@@ -137,40 +130,19 @@ export const Banner = React.forwardRef<HTMLElement, BannerProps>(function Banner
137
130
}
138
131
139
132
return (
140
- < StyledBanner
133
+ < section
141
134
{ ...rest }
142
135
aria-label = { label ?? labels [ variant ] }
143
- as = "section"
144
- className = { clsx ( className , {
145
- [ classes . Banner ] : enabled ,
146
- } ) }
136
+ className = { clsx ( className , classes . Banner ) }
147
137
data-dismissible = { onDismiss ? '' : undefined }
148
138
data-title-hidden = { hideTitle ? '' : undefined }
149
139
data-variant = { variant }
150
140
tabIndex = { - 1 }
151
141
ref = { ref }
152
142
>
153
- { ! enabled ? < style > { BannerContainerQuery } </ style > : null }
154
- < div
155
- className = { clsx ( {
156
- BannerIcon : ! enabled ,
157
- [ classes . BannerIcon ] : enabled ,
158
- } ) }
159
- >
160
- { icon && supportsCustomIcon ? icon : iconForVariant [ variant ] }
161
- </ div >
162
- < div
163
- className = { clsx ( {
164
- BannerContainer : ! enabled ,
165
- [ classes . BannerContainer ] : enabled ,
166
- } ) }
167
- >
168
- < div
169
- className = { clsx ( {
170
- BannerContent : ! enabled ,
171
- [ classes . BannerContent ] : enabled ,
172
- } ) }
173
- >
143
+ < div className = { classes . BannerIcon } > { icon && supportsCustomIcon ? icon : iconForVariant [ variant ] } </ div >
144
+ < div className = { classes . BannerContainer } >
145
+ < div className = { classes . BannerContent } >
174
146
{ title ? (
175
147
hideTitle ? (
176
148
< VisuallyHidden >
@@ -189,221 +161,15 @@ export const Banner = React.forwardRef<HTMLElement, BannerProps>(function Banner
189
161
< IconButton
190
162
aria-label = "Dismiss banner"
191
163
onClick = { onDismiss }
192
- className = { clsx ( {
193
- BannerDismiss : ! enabled ,
194
- [ classes . BannerDismiss ] : enabled ,
195
- } ) }
164
+ className = { classes . BannerDismiss }
196
165
icon = { XIcon }
197
166
variant = "invisible"
198
167
/>
199
168
) : null }
200
- </ StyledBanner >
169
+ </ section >
201
170
)
202
171
} )
203
172
204
- const StyledBanner = toggleStyledComponent (
205
- CSS_MODULES_FEATURE_FLAG ,
206
- /**
207
- * For styling, it's important that the icons and the text have the same height
208
- * for alignment to occur in multi-line scenarios. Currently, we use a
209
- * line-height of `20px` so that means that the height of icons should match
210
- * that value.
211
- */
212
- 'div' ,
213
- styled . div `
214
- display: grid;
215
- grid-template-columns: auto minmax(0, 1fr) auto;
216
- align-items: start;
217
- background-color: var(--banner-bgColor);
218
- border: var(--borderWidth-thin, 1px) solid var(--banner-borderColor);
219
- padding: var(--base-size-8, 0.5rem);
220
- border-radius: var(--borderRadius-medium, ${ get ( 'radii.2' ) } );
221
-
222
- @supports (container-type: inline-size) {
223
- container: banner / inline-size;
224
- }
225
-
226
- &[data-variant='critical'] {
227
- --banner-bgColor: ${ get ( 'colors.danger.subtle' ) } ;
228
- --banner-borderColor: ${ get ( 'colors.danger.muted' ) } ;
229
- --banner-icon-fgColor: ${ get ( 'colors.danger.fg' ) } ;
230
- }
231
-
232
- &[data-variant='info'] {
233
- --banner-bgColor: ${ get ( 'colors.accent.subtle' ) } ;
234
- --banner-borderColor: ${ get ( 'colors.accent.muted' ) } ;
235
- --banner-icon-fgColor: ${ get ( 'colors.accent.fg' ) } ;
236
- }
237
-
238
- &[data-variant='success'] {
239
- --banner-bgColor: ${ get ( 'colors.success.subtle' ) } ;
240
- --banner-borderColor: ${ get ( 'colors.success.muted' ) } ;
241
- --banner-icon-fgColor: ${ get ( 'colors.success.fg' ) } ;
242
- }
243
-
244
- &[data-variant='upsell'] {
245
- --banner-bgColor: var(--bgColor-upsell-muted, ${ get ( 'colors.done.subtle' ) } );
246
- --banner-borderColor: var(--borderColor-upsell-muted, ${ get ( 'colors.done.muted' ) } );
247
- --banner-icon-fgColor: var(--fgColor-upsell-muted, ${ get ( 'colors.done.fg' ) } );
248
- }
249
-
250
- &[data-variant='warning'] {
251
- --banner-bgColor: ${ get ( 'colors.attention.subtle' ) } ;
252
- --banner-borderColor: ${ get ( 'colors.attention.muted' ) } ;
253
- --banner-icon-fgColor: ${ get ( 'colors.attention.fg' ) } ;
254
- }
255
-
256
- /* BannerIcon ------------------------------------------------------------- */
257
-
258
- .BannerIcon {
259
- display: grid;
260
- place-items: center;
261
- padding: var(--base-size-8, 0.5rem);
262
- }
263
-
264
- .BannerIcon svg {
265
- color: var(--banner-icon-fgColor);
266
- fill: var(--banner-icon-fgColor);
267
- /* 20px is the line box height of the trailing action buttons */
268
- height: var(--base-size-20, 1.25rem);
269
- }
270
-
271
- &[data-title-hidden=''] .BannerIcon svg {
272
- height: var(--base-size-16, 1rem);
273
- }
274
-
275
- /* BannerContainer -------------------------------------------------------- */
276
-
277
- .BannerContainer {
278
- font-size: var(--text-body-size-medium, 0.875rem);
279
- align-items: start;
280
- line-height: var(--text-body-lineHeight-medium, calc(20 / 14));
281
- row-gap: var(--base-size-4, 0.25rem);
282
- column-gap: var(--base-size-4, 0.25rem);
283
- }
284
-
285
- & :where(.BannerContainer) {
286
- display: flex;
287
- flex-wrap: wrap;
288
- justify-content: space-between;
289
- }
290
-
291
- &[data-dismissible]:not([data-title-hidden='']) .BannerContainer {
292
- display: grid;
293
- grid-template-columns: auto;
294
- grid-template-rows: auto;
295
- }
296
-
297
- /* BannerContent ---------------------------------------------------------- */
298
-
299
- .BannerContent {
300
- display: grid;
301
- row-gap: var(--base-size-4, 0.25rem);
302
- grid-column-start: 1;
303
- margin-block: var(--base-size-8, 0.5rem);
304
- }
305
-
306
- &[data-title-hidden=''] .BannerContent {
307
- margin-block: var(--base-size-6, 0.375rem);
308
- }
309
-
310
- @media screen and (min-width: 544px) {
311
- .BannerContent {
312
- flex: 1 1 0%;
313
- }
314
- }
315
-
316
- .BannerTitle {
317
- margin: 0;
318
- font-size: inherit;
319
- font-weight: var(--base-text-weight-semibold, 600);
320
- }
321
-
322
- /* BannerActions ---------------------------------------------------------- */
323
- .BannerActionsContainer {
324
- display: flex;
325
- column-gap: var(--base-size-12, 0.5rem);
326
- align-items: center;
327
- }
328
-
329
- .BannerActions :where([data-primary-action='trailing']) {
330
- display: none;
331
- }
332
-
333
- @media screen and (min-width: 544px) {
334
- .BannerActions :where([data-primary-action='trailing']) {
335
- display: flex;
336
- }
337
-
338
- .BannerActions :where([data-primary-action='leading']) {
339
- display: none;
340
- }
341
- }
342
-
343
- &[data-dismissible]:not([data-title-hidden]) .BannerActions {
344
- margin-block-end: var(--base-size-6, 0.375rem);
345
- }
346
-
347
- &[data-dismissible]:not([data-title-hidden]) .BannerActionsContainer[data-primary-action='trailing'] {
348
- display: none;
349
- }
350
-
351
- &[data-dismissible]:not([data-title-hidden]) .BannerActionsContainer[data-primary-action='leading'] {
352
- display: flex;
353
- }
354
-
355
- /* BannerDismiss ---------------------------------------------------------- */
356
-
357
- .BannerDismiss {
358
- display: grid;
359
- place-items: center;
360
- padding: var(--base-size-8, 0.5rem);
361
- margin-inline-start: var(--base-size-4, 0.25rem);
362
- }
363
-
364
- .BannerDismiss svg {
365
- color: var(--banner-icon-fgColor);
366
- }
367
- ` ,
368
- )
369
-
370
- const BannerContainerQuery = `
371
- @container banner (max-width: 500px) {
372
- .BannerContainer {
373
- display: grid;
374
- grid-template-rows: auto auto;
375
- }
376
-
377
- .BannerActions {
378
- margin-block-end: var(--size-small, 0.375rem);
379
- }
380
-
381
- .BannerActions [data-primary-action="trailing"] {
382
- display: none;
383
- }
384
-
385
- .BannerActions [data-primary-action="leading"] {
386
- display: flex;
387
- }
388
- }
389
-
390
- @container banner (min-width: 500px) {
391
- .BannerContainer {
392
- display: grid;
393
- grid-template-columns: auto auto;
394
- }
395
-
396
- .BannerActions [data-primary-action="trailing"] {
397
- display: flex;
398
- min-height: var(--base-size-32, 2rem);
399
- }
400
-
401
- .BannerActions [data-primary-action="leading"] {
402
- display: none;
403
- }
404
- }
405
- `
406
-
407
173
type HeadingElement = 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
408
174
409
175
export type BannerTitleProps < As extends HeadingElement > = {
@@ -413,16 +179,8 @@ export type BannerTitleProps<As extends HeadingElement> = {
413
179
414
180
export function BannerTitle < As extends HeadingElement > ( props : BannerTitleProps < As > ) {
415
181
const { as : Heading = 'h2' , className, children, ...rest } = props
416
- const enabled = useFeatureFlag ( CSS_MODULES_FEATURE_FLAG )
417
182
return (
418
- < Heading
419
- { ...rest }
420
- className = { clsx ( className , {
421
- [ classes . BannerTitle ] : enabled ,
422
- BannerTitle : ! enabled ,
423
- } ) }
424
- data-banner-title = ""
425
- >
183
+ < Heading { ...rest } className = { clsx ( className , classes . BannerTitle ) } data-banner-title = "" >
426
184
{ children }
427
185
</ Heading >
428
186
)
@@ -444,31 +202,13 @@ export type BannerActionsProps = {
444
202
}
445
203
446
204
export function BannerActions ( { primaryAction, secondaryAction} : BannerActionsProps ) {
447
- const enabled = useFeatureFlag ( CSS_MODULES_FEATURE_FLAG )
448
205
return (
449
- < div
450
- className = { clsx ( {
451
- [ classes . BannerActions ] : enabled ,
452
- BannerActions : ! enabled ,
453
- } ) }
454
- >
455
- < div
456
- className = { clsx ( {
457
- [ classes . BannerActionsContainer ] : enabled ,
458
- BannerActionsContainer : ! enabled ,
459
- } ) }
460
- data-primary-action = "trailing"
461
- >
206
+ < div className = { classes . BannerActions } >
207
+ < div className = { classes . BannerActionsContainer } data-primary-action = "trailing" >
462
208
{ secondaryAction ?? null }
463
209
{ primaryAction ?? null }
464
210
</ div >
465
- < div
466
- className = { clsx ( {
467
- [ classes . BannerActionsContainer ] : enabled ,
468
- BannerActionsContainer : ! enabled ,
469
- } ) }
470
- data-primary-action = "leading"
471
- >
211
+ < div className = { classes . BannerActionsContainer } data-primary-action = "leading" >
472
212
{ primaryAction ?? null }
473
213
{ secondaryAction ?? null }
474
214
</ div >
0 commit comments