Skip to content

Commit

Permalink
chore(Header): Remove CSS modules feature flag from Header (#5460)
Browse files Browse the repository at this point in the history
* Remove CSS modules feature flag from Header

* Adjust Header for as prop

* Create shaggy-comics-whisper.md
  • Loading branch information
jonrohan authored Dec 19, 2024
1 parent 9bd2f79 commit 6d70d1b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 105 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-comics-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Remove CSS modules feature flag from Header
150 changes: 46 additions & 104 deletions packages/react/src/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,139 +1,81 @@
import type {Location, Pathname} from 'history'
import styled, {css} from 'styled-components'
import {get} from '../constants'
import type {SxProp} from '../sx'
import sx from '../sx'
import type {ComponentProps} from '../utils/types'
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
import {useFeatureFlag} from '../FeatureFlags'
import React from 'react'
import {clsx} from 'clsx'
import classes from './Header.module.css'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'
import {defaultSxProp} from '../utils/defaultSxProp'
import Box from '../Box'

type StyledHeaderProps = React.ComponentProps<'header'> & SxProp
type StyledHeaderItemProps = React.ComponentProps<'div'> & SxProp & {full?: boolean}
type StyledHeaderLinkProps = React.ComponentProps<'a'> & SxProp & {to?: Location | Pathname}
export type HeaderProps = React.ComponentProps<'header'> & SxProp & {as?: React.ElementType}
export type HeaderItemProps = React.ComponentProps<'div'> & SxProp & {full?: boolean}
export type HeaderLinkProps = React.ComponentProps<'a'> & SxProp & {to?: Location | Pathname; as?: React.ElementType}

const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga'

const StyledHeader = toggleStyledComponent(
CSS_MODULES_FEATURE_FLAG,
'header',
styled.header<StyledHeaderProps>`
z-index: 32;
display: flex;
padding: ${get('space.3')};
font-size: ${get('fontSizes.1')};
line-height: ${get('lineHeights.default')};
color: ${get('colors.header.text')};
background-color: ${get('colors.header.bg')};
align-items: center;
flex-wrap: nowrap;
overflow: auto;
${sx};
`,
)

const Header = React.forwardRef<HTMLElement, StyledHeaderProps>(function Header(
{children, className, ...rest},
const Header = React.forwardRef<HTMLElement, HeaderProps>(function Header(
{children, className, sx: sxProp = defaultSxProp, as = 'header', ...rest},
forwardRef,
) {
const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
if (sxProp !== defaultSxProp || as !== 'header') {
return (
<Box as={as} sx={sxProp} ref={forwardRef} className={clsx(className, classes.Header)} {...rest}>
{children}
</Box>
)
}
return (
<StyledHeader ref={forwardRef} className={clsx(className, {[classes.Header]: enabled})} {...rest}>
<header ref={forwardRef} className={clsx(className, classes.Header)} {...rest}>
{children}
</StyledHeader>
</header>
)
}) as PolymorphicForwardRefComponent<'header', StyledHeaderProps>
}) as PolymorphicForwardRefComponent<'header', HeaderProps>

Header.displayName = 'Header'

const StyledHeaderItem = toggleStyledComponent(
CSS_MODULES_FEATURE_FLAG,
'div',
styled.div<StyledHeaderItemProps>`
display: flex;
margin-right: ${get('space.3')};
align-self: stretch;
align-items: center;
flex-wrap: nowrap;
${({full}) =>
full &&
css`
flex: auto;
`};
${sx};
`,
)

const HeaderItem = React.forwardRef<HTMLElement, StyledHeaderItemProps>(function HeaderItem(
{children, className, ...rest},
const HeaderItem = React.forwardRef<HTMLDivElement, HeaderItemProps>(function HeaderItem(
{children, className, sx: sxProp = defaultSxProp, full, ...rest},
forwardRef,
) {
const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
if (sxProp !== defaultSxProp) {
return (
<Box
as={'div'}
sx={sxProp}
ref={forwardRef}
className={clsx(className, classes.HeaderItem)}
data-full={full}
{...rest}
>
{children}
</Box>
)
}
return (
<StyledHeaderItem
ref={forwardRef}
className={clsx(className, enabled && classes.HeaderItem)}
data-full={rest.full}
{...rest}
>
<div ref={forwardRef} className={clsx(className, classes.HeaderItem)} data-full={full} {...rest}>
{children}
</StyledHeaderItem>
</div>
)
})

HeaderItem.displayName = 'Header.Item'

const StyledHeaderLink = toggleStyledComponent(
CSS_MODULES_FEATURE_FLAG,
'a',
styled.a.attrs<StyledHeaderLinkProps>(({to}) => {
const isReactRouter = typeof to === 'string'
if (isReactRouter) {
// according to their docs, NavLink supports aria-current:
// https://reacttraining.com/react-router/web/api/NavLink/aria-current-string
return {'aria-current': 'page'}
} else {
return {}
}
})<StyledHeaderLinkProps>`
font-weight: ${get('fontWeights.bold')};
color: ${get('colors.header.logo')};
white-space: nowrap;
cursor: pointer;
text-decoration: none;
display: flex;
align-items: center;
&:hover,
&:focus {
color: ${get('colors.header.text')};
}
${sx};
`,
)

const HeaderLink = React.forwardRef<HTMLElement, StyledHeaderLinkProps>(function HeaderLink(
{children, className, ...rest},
const HeaderLink = React.forwardRef<HTMLAnchorElement, HeaderLinkProps>(function HeaderLink(
{children, className, sx: sxProp = defaultSxProp, as = 'a', ...rest},
forwardRef,
) {
const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
if (sxProp !== defaultSxProp || as !== 'a') {
return (
<Box as={as} sx={sxProp} ref={forwardRef} className={clsx(className, classes.HeaderLink)} {...rest}>
{children}
</Box>
)
}
return (
<StyledHeaderLink ref={forwardRef} className={clsx(className, enabled && classes.HeaderLink)} {...rest}>
<a ref={forwardRef} className={clsx(className, classes.HeaderLink)} {...rest}>
{children}
</StyledHeaderLink>
</a>
)
})

HeaderLink.displayName = 'Header.Link'

export type HeaderProps = ComponentProps<typeof Header>
export type HeaderLinkProps = ComponentProps<typeof HeaderLink>
export type HeaderItemProps = ComponentProps<typeof HeaderItem>
export default Object.assign(Header, {Link: HeaderLink, Item: HeaderItem})
2 changes: 1 addition & 1 deletion packages/react/src/__tests__/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Header', () => {
})

describe('Header.Item', () => {
behavesAsComponent({Component: Header.Item})
behavesAsComponent({Component: Header.Item, options: {skipAs: true}})

it('accepts and applies className', () => {
expect(render(<Header.Item className="primer" />).props.className).toContain('primer')
Expand Down

0 comments on commit 6d70d1b

Please sign in to comment.