Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update alert component #2591

Merged
merged 4 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
58 changes: 50 additions & 8 deletions packages/Alert/docs/examples/cta.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
import * as React from 'react'
import { Alert } from '@welcome-ui/alert'
import { Stack } from '@welcome-ui/stack'

const Example = () => {
return (
<Alert cta={<Alert.Button>Button</Alert.Button>}>
<Alert.Title>Welcome to the jungle</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
<Stack>
<Alert cta={<Alert.Button>Button</Alert.Button>}>
<Alert.Title>Welcome to the jungle</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
<Alert
cta={
<>
<Alert.Button>Button</Alert.Button>
<Alert.SecondaryButton>Button</Alert.SecondaryButton>
</>
}
>
<Alert.Title>Welcome to the jungle</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
<Alert cta={<Alert.Button>Button</Alert.Button>} ctaPosition="bottom">
<Alert.Title>Welcome to the jungle</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
<Alert
cta={
<>
<Alert.Button>Button</Alert.Button>
<Alert.SecondaryButton>Button</Alert.SecondaryButton>
</>
}
ctaPosition="bottom"
>
<Alert.Title>Welcome to the jungle</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
</Stack>
)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/Alert/docs/examples/is-full-width.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Alert } from '@welcome-ui/alert'

const Example = () => {
return (
<Alert cta={<Alert.Button variant="secondary">Button</Alert.Button>} isFullWidth>
<Alert cta={<Alert.Button>Button</Alert.Button>} isFullWidth>
<Alert.Title>Welcome to the jungle</Alert.Title>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a ornare.
Expand Down
4 changes: 2 additions & 2 deletions packages/Alert/docs/examples/sizes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { Stack } from '@welcome-ui/stack'
const Example = () => {
return (
<Stack>
<Alert>
<Alert cta={<Alert.Button>Button</Alert.Button>}>
<Alert.Title>Default size</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
ultrices. Phasellus iaculis nisi sed dui ornare commodo. Nullam dapibus varius nibh a
ornare.
</span>
</Alert>
<Alert size="md">
<Alert cta={<Alert.Button>Button</Alert.Button>} size="md">
<Alert.Title>Medium size</Alert.Title>
<span>
Nunc laoreet egestas nulla, et dapibus sem malesuada in. Suspendisse eleifend accumsan
Expand Down
2 changes: 1 addition & 1 deletion packages/Alert/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ By default the size is `sm`.

### Call to action

When the `cta` prop is used, it will be displayed in a column on the right.
When the `cta` prop is used, by default it will be displayed in a column on the right.

<div data-playground="cta.tsx" data-component="Alert"></div>

Expand Down
58 changes: 58 additions & 0 deletions packages/Alert/docs/properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,36 @@
"name": "Element"
}
},
"ctaPosition": {
"defaultValue": {
"value": "right"
},
"description": "",
"name": "ctaPosition",
"parent": {
"fileName": "Alert/src/index.tsx",
"name": "AlertOptions"
},
"declarations": [
{
"fileName": "Alert/src/index.tsx",
"name": "AlertOptions"
}
],
"required": false,
"type": {
"name": "enum",
"raw": "\"right\" | \"bottom\"",
"value": [
{
"value": "\"right\""
},
{
"value": "\"bottom\""
}
]
}
},
"handleClose": {
"defaultValue": null,
"description": "@description add a close button with an onclick handleClose function",
Expand Down Expand Up @@ -219,6 +249,34 @@
"name": "Element"
}
},
"ctaPosition": {
"defaultValue": null,
"description": "",
"name": "ctaPosition",
"parent": {
"fileName": "Alert/src/index.tsx",
"name": "AlertOptions"
},
"declarations": [
{
"fileName": "Alert/src/index.tsx",
"name": "AlertOptions"
}
],
"required": false,
"type": {
"name": "enum",
"raw": "\"right\" | \"bottom\"",
"value": [
{
"value": "\"right\""
},
{
"value": "\"bottom\""
}
]
}
},
"handleClose": {
"defaultValue": null,
"description": "@description add a close button with an onclick handleClose function",
Expand Down
2 changes: 1 addition & 1 deletion packages/Alert/src/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type AlertTitleProps = CreateWuiProps<'h5', AlertOptions>
*/
export const Title: React.FC<AlertTitleProps> = ({ children, dataTestId, variant, ...rest }) => {
return (
<S.Title data-testid={dataTestId} variant={variant} {...rest}>
<S.Title data-testid={dataTestId} {...rest} variant={variant}>
{children}
</S.Title>
)
Expand Down
86 changes: 61 additions & 25 deletions packages/Alert/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Children, cloneElement } from 'react'
import { Box } from '@welcome-ui/box'
import { Box, BoxProps } from '@welcome-ui/box'
import { CloseButton } from '@welcome-ui/close-button'
import { Button, ButtonProps } from '@welcome-ui/button'
import { CreateWuiProps, forwardRef } from '@welcome-ui/system'
Expand All @@ -13,6 +13,7 @@ export type Variant = 'danger' | 'success' | 'warning' | 'info' | 'default' | 'b
export interface AlertOptions {
closeButtonDataTestId?: string
cta?: JSX.Element
ctaPosition?: 'bottom' | 'right'
/**
* @description add a close button with an onclick handleClose function
*/
Expand All @@ -25,11 +26,28 @@ export interface AlertOptions {

export type AlertProps = CreateWuiProps<'div', AlertOptions>

type CloneActionsReturns = React.ReactElement<
AlertProps,
string | React.JSXElementConstructor<AlertProps>
>

const LAYOUT: { bottom: BoxProps; right: BoxProps } = {
bottom: {
alignItems: 'flex-start',
flexDirection: 'column',
},
right: {
alignItems: { _: 'flex-start', md: 'center' },
flexDirection: { _: 'column', md: 'row' },
},
}

const AlertComponent = forwardRef<'div', AlertProps>(
(
{
children,
cta,
ctaPosition = 'right',
dataTestId,
handleClose,
icon,
Expand All @@ -44,13 +62,30 @@ const AlertComponent = forwardRef<'div', AlertProps>(
const defaultVariantIcon = variant === 'beige' ? 'default' : variant

const content = Children.toArray(children).map((child: React.ReactElement) => {
// Add variant to Title to show the correct icon
if (child.type === Title) {
return cloneElement(child, { variant })
}
if (child.type === Title) return cloneElement(child, { variant: size })

return child
})

// Handle clone actions recursively in case of multiple buttons
const cloneActions = (child: React.ReactElement<AlertProps>): CloneActionsReturns => {
if (child.type === AlertButton) return cloneElement(child, { size })
if (child.type === AlertSecondaryButton) return cloneElement(child, { size })

if (child.props?.children) {
return cloneElement(child, {
...child.props,
children: Children.map(child.props.children, (nestedChild: React.ReactElement) =>
cloneActions(nestedChild)
),
})
}

return child
}

const actions = React.isValidElement(cta) ? cloneActions(cta) : cta

return (
<S.Alert
data-testid={dataTestId}
Expand All @@ -74,34 +109,35 @@ const AlertComponent = forwardRef<'div', AlertProps>(
alignSelf="flex-start"
icon={icon}
pr="md"
pt={1}
size="sm"
size={size}
variant={defaultVariantIcon}
/>
<Box flex="1">
{cta ? (
<Box
alignItems={{ md: 'center' }}
display="flex"
flexDirection={{ _: 'column', md: 'row' }}
gap="md"
justifyContent="space-between"
>
<div>{content}</div>
{cta}
</Box>
) : (
content
)}
<Box flex={1}>
<Box display="flex" gap="md" justifyContent="space-between" {...LAYOUT[ctaPosition]}>
<Box flex={1}>{content}</Box>
{!!actions && (
<Box alignItems="center" display="flex" gap="sm">
{actions}
</Box>
)}
</Box>
</Box>
</S.Alert>
)
}
)

// We need this component to check its existence in <Alert> and to allow users to add Button in <Alert> content
const AlertButton = forwardRef<'button', ButtonProps>((props, ref) => (
<Button flexShrink={0} ref={ref} size="sm" variant="secondary" w="fit-content" {...props} />
const AlertButton = forwardRef<'button', Omit<ButtonProps, 'size' | 'variant'>>((props, ref) => (
<Button flexShrink={0} ref={ref} w="fit-content" {...props} variant="secondary" />
))

export const Alert = Object.assign(AlertComponent, { Title, Button: AlertButton })
const AlertSecondaryButton = forwardRef<'button', Omit<ButtonProps, 'size' | 'variant'>>(
(props, ref) => <Button flexShrink={0} ref={ref} w="fit-content" {...props} variant="tertiary" />
)

export const Alert = Object.assign(AlertComponent, {
Title,
Button: AlertButton,
SecondaryButton: AlertSecondaryButton,
})
8 changes: 3 additions & 5 deletions packages/Alert/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ export const Alert = styled(Box)<AlertOptions>(
`
)

export const Title = styled(Text).attrs(() => ({
variant: 'sm',
}))(
() => css`
export const Title = styled(Text)<AlertOptions>(
({ variant }) => css`
margin: 0;
margin-bottom: sm;
font-weight: medium;
${th(`alerts.title.${variant}`)};
${system};

&:only-child {
Expand Down
2 changes: 1 addition & 1 deletion packages/Alert/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('<Alert>', () => {
const alertTitle = getByTestId('alert-title')

expect(container).toHaveTextContent(content)
expect(alertTitle).toHaveStyleRule('margin-bottom', '0.5rem')
expect(alertTitle).toHaveStyleRule('margin-bottom', '0.25rem')
})

it('should render correctly with only an Alert.Title', () => {
Expand Down
12 changes: 11 additions & 1 deletion packages/Core/src/theme/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type AttributesState = CSSObject
export type ThemeAlerts = {
default: CSSObject
sizes: Record<Sizes, CSSObject>
title: Record<Sizes, CSSObject>
} & Record<State, AttributesState>

export const getAlerts = (theme: WuiTheme): ThemeAlerts => {
Expand All @@ -29,7 +30,6 @@ export const getAlerts = (theme: WuiTheme): ThemeAlerts => {
borderStyle: 'solid',
borderWidth: borderWidths.sm,
color: colors['neutral-90'],
fontSize: fontSizes.sm,
},
danger: getState('red'),
warning: getState('orange'),
Expand All @@ -38,11 +38,21 @@ export const getAlerts = (theme: WuiTheme): ThemeAlerts => {
beige: { backgroundColor: colors['beige-20'], borderColor: colors['beige-20'] },
sizes: {
sm: {
fontSize: fontSizes.sm,
padding: space.lg,
},
md: {
fontSize: fontSizes.md,
padding: space.xl,
},
},
title: {
sm: {
marginBottom: space.xs,
},
md: {
marginBottom: space.sm,
},
},
}
}
Loading