Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/giant-bushes-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Update Flash from sx to CSS Modules
59 changes: 59 additions & 0 deletions packages/react/src/Flash/Flash.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.Flash {
position: relative;
color: var(--fgColor-default);
padding: var(--base-size-16);
border-style: solid;
border-width: 1px;
border-radius: var(--borderRadius-medium);
margin-top: 0;

&:where([data-variant='default']) {
background-color: var(--bgColor-accent-muted);
Comment thread
joshblack marked this conversation as resolved.
border-color: var(--borderColor-accent-muted);

& :where(svg) {
color: var(--fgColor-accent);
}
}

&:where([data-variant='success']) {
background-color: var(--bgColor-success-muted);
Comment thread
joshblack marked this conversation as resolved.
border-color: var(--borderColor-success-muted);

& :where(svg) {
color: var(--fgColor-success);
}
}

&:where([data-variant='danger']) {
background-color: var(--bgColor-danger-muted);
Comment thread
joshblack marked this conversation as resolved.
border-color: var(--borderColor-danger-muted);

& :where(svg) {
color: var(--fgColor-danger);
}
}

&:where([data-variant='warning']) {
background-color: var(--bgColor-attention-muted);
Comment thread
joshblack marked this conversation as resolved.
border-color: var(--borderColor-attention-muted);

& :where(svg) {
color: var(--fgColor-attention);
}
}

&:where([data-full]) {
border-width: 1px 0px;
border-radius: 0;
margin-top: -1px;
}

& :where(p:last-child) {
margin-bottom: 0;
}

& :where(svg) {
margin-right: var(--base-size-8);
}
}
87 changes: 18 additions & 69 deletions packages/react/src/Flash/Flash.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,29 @@
import {clsx} from 'clsx'
import React from 'react'
import styled from 'styled-components'
import {variant} from 'styled-system'
import {get} from '../constants'
import type {SxProp} from '../sx'
import sx from '../sx'
import type {ComponentProps} from '../utils/types'
import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic'
import {BoxWithFallback} from '../internal/components/BoxWithFallback'
import classes from './Flash.module.css'

const variants = variant({
variants: {
default: {
color: 'fg.default',
backgroundColor: 'accent.subtle',
borderColor: 'accent.muted',
svg: {
color: 'accent.fg',
},
},
success: {
color: 'fg.default',
backgroundColor: 'success.subtle',
borderColor: 'success.muted',
svg: {
color: 'success.fg',
},
},
danger: {
color: 'fg.default',
backgroundColor: 'danger.subtle',
borderColor: 'danger.muted',
svg: {
color: 'danger.fg',
},
},
warning: {
color: 'fg.default',
backgroundColor: 'attention.subtle',
borderColor: 'attention.muted',
svg: {
color: 'attention.fg',
},
},
},
})

type StyledFlashProps = {
export type FlashProps = React.ComponentPropsWithoutRef<'div'> & {
className?: string
variant?: 'default' | 'warning' | 'success' | 'danger'
full?: boolean
} & SxProp

const StyledFlash = styled.div<StyledFlashProps>`
position: relative;
color: ${get('colors.fg.default')};
padding: ${get('space.3')};
border-style: solid;
border-width: ${props => (props.full ? '1px 0px' : '1px')};
border-radius: ${props => (props.full ? '0' : get('radii.2'))};
margin-top: ${props => (props.full ? '-1px' : '0')};

p:last-child {
margin-bottom: 0;
}

svg {
margin-right: ${get('space.2')};
}

${variants};
${sx};
`

export type FlashProps = ComponentProps<typeof StyledFlash>

const Flash = React.forwardRef(function Flash({as, variant = 'default', ...rest}, ref) {
return <StyledFlash ref={ref} as={as} variant={variant} {...rest} />
}) as PolymorphicForwardRefComponent<'div', StyledFlashProps>
const Flash = React.forwardRef(function Flash({as, className, variant = 'default', full, sx, ...rest}, ref) {
return (
<BoxWithFallback
{...rest}
ref={ref}
as={as}
className={clsx(classes.Flash, className)}
data-full={full ? '' : undefined}
data-variant={variant}
sx={sx}
/>
)
}) as PolymorphicForwardRefComponent<'div', FlashProps>

if (__DEV__) {
Flash.displayName = 'Flash'
Expand Down
62 changes: 30 additions & 32 deletions packages/react/src/Flash/__tests__/Flash.test.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
import React from 'react'
import Flash from '..'
import {render, behavesAsComponent, checkExports} from '../../utils/testing'
import {render as HTMLRender} from '@testing-library/react'
import axe from 'axe-core'
import {render, screen} from '@testing-library/react'

describe('Flash', () => {
behavesAsComponent({Component: Flash})

checkExports('Flash', {
default: Flash,
it('should support the `full` prop', () => {
render(
<>
<Flash data-testid="full" full />
<Flash data-testid="no-full" />
</>,
)
expect(screen.getByTestId('full')).toHaveAttribute('data-full', '')
expect(screen.getByTestId('no-full')).not.toHaveAttribute('data-full')
})

it('should have no axe violations', async () => {
const {container} = HTMLRender(<Flash variant="warning" />)
const results = await axe.run(container)
expect(results).toHaveNoViolations()
it('should support the `variant` prop', () => {
render(
<>
<Flash data-testid="danger" variant="danger" />
<Flash data-testid="success" variant="success" />
<Flash data-testid="warning" variant="warning" />
<Flash data-testid="default" variant="default" />
</>,
)

expect(screen.getByTestId('danger')).toHaveAttribute('data-variant', 'danger')
expect(screen.getByTestId('success')).toHaveAttribute('data-variant', 'success')
expect(screen.getByTestId('warning')).toHaveAttribute('data-variant', 'warning')
expect(screen.getByTestId('default')).toHaveAttribute('data-variant', 'default')
})

it('respects the "full" prop', () => {
expect(render(<Flash full />)).toHaveStyleRule('margin-top', '-1px')
expect(render(<Flash full />)).toHaveStyleRule('border-radius', '0')
expect(render(<Flash full />)).toHaveStyleRule('border-width', '1px 0px')
it('should support `className` on the outermost element', () => {
const {container} = render(<Flash className="test-class" />)
expect(container.firstChild).toHaveClass('test-class')
})

it('respects the "variant" prop', () => {
expect(render(<Flash variant="warning" />)).toHaveStyleRule(
'background-color',
'var(--bgColor-attention-muted,var(--color-attention-subtle,#fff8c5))',
)
expect(render(<Flash variant="danger" />)).toHaveStyleRule(
'background-color',
'var(--bgColor-danger-muted,var(--color-danger-subtle,#ffebe9))',
)
expect(render(<Flash variant="success" />)).toHaveStyleRule(
'background-color',
'var(--bgColor-success-muted,var(--color-success-subtle,#dafbe1))',
)
expect(render(<Flash />)).toHaveStyleRule(
'background-color',
'var(--bgColor-accent-muted,var(--color-accent-subtle,#ddf4ff))',
)
it('should spread props to the outermost element', () => {
const {container} = render(<Flash data-testid="test" />)
expect(container.firstChild).toHaveAttribute('data-testid', 'test')
})
})