Skip to content

Commit 93f590b

Browse files
committed
add new shadcn alert component
1 parent 3bc62ca commit 93f590b

File tree

4 files changed

+185
-2
lines changed

4 files changed

+185
-2
lines changed

src/components/Alert/Alert.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Meta, StoryObj } from "@storybook/react"
55
import Alert from "."
66

77
const meta = {
8-
title: "Molecules / Action Feedback / Alerts",
8+
title: "Molecules / Action Feedback / Old Alerts",
99
component: Alert,
1010
decorators: [
1111
(Story) => (
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as React from "react"
2+
import { MdInfoOutline } from "react-icons/md"
3+
import { Meta, StoryObj } from "@storybook/react"
4+
5+
import {
6+
Alert,
7+
AlertCloseButton,
8+
AlertContent,
9+
AlertDescription,
10+
AlertTitle,
11+
} from "../alert"
12+
import { Center } from "../flex"
13+
14+
const meta = {
15+
title: "Molecules / Action Feedback / Alerts",
16+
component: Alert,
17+
parameters: {
18+
layout: "none",
19+
},
20+
decorators: [
21+
(Story) => (
22+
<Center className="min-h-[100vh]">
23+
<Story />
24+
</Center>
25+
),
26+
],
27+
} satisfies Meta<typeof Alert>
28+
29+
export default meta
30+
31+
type Story = StoryObj<typeof meta>
32+
33+
const DEMO_TITLE = "Alert or callout title"
34+
const DEMO_DESC = "This is an alert to be used for important information."
35+
36+
const VARIANTS = ["info", "error", "success", "warning", "update"] as const
37+
38+
export const Variants: Story = {
39+
render: (args) => (
40+
<div className="flex w-[500px] flex-col gap-4">
41+
{VARIANTS.map((variant) => (
42+
<Alert key={variant} variant={variant} className="w-full" {...args}>
43+
<AlertContent>
44+
<AlertTitle>{DEMO_TITLE}</AlertTitle>
45+
<AlertDescription>
46+
This is a <pre className="inline text-sm">{variant}</pre> alert
47+
</AlertDescription>
48+
</AlertContent>
49+
</Alert>
50+
))}
51+
</div>
52+
),
53+
}
54+
55+
export const WithCloseButton: Story = {
56+
render: (args) => (
57+
<div className="flex flex-col gap-4">
58+
{VARIANTS.map((variant) => (
59+
<Alert key={variant} variant={variant} {...args}>
60+
<AlertContent>
61+
<AlertTitle>{DEMO_TITLE}</AlertTitle>
62+
<AlertDescription>{DEMO_DESC}</AlertDescription>
63+
</AlertContent>
64+
<AlertCloseButton />
65+
</Alert>
66+
))}
67+
</div>
68+
),
69+
}
70+
71+
export const Banner: Story = {
72+
render: (args) => (
73+
<div className="mx-8 flex w-full flex-col gap-4">
74+
{VARIANTS.map((variant) => (
75+
<Alert key={variant} variant={variant} size="full" {...args}>
76+
<MdInfoOutline className="h-6 w-6" />
77+
<AlertContent>
78+
<AlertTitle>Banner use case</AlertTitle>
79+
<AlertDescription>
80+
<p>{DEMO_DESC}</p>
81+
<p>{DEMO_DESC}</p>
82+
</AlertDescription>
83+
</AlertContent>
84+
<AlertCloseButton />
85+
</Alert>
86+
))}
87+
</div>
88+
),
89+
}

src/components/ui/alert.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import * as React from "react"
2+
import { cva, type VariantProps } from "class-variance-authority"
3+
import { MdClose } from "react-icons/md"
4+
5+
import { cn } from "@/lib/utils/cn"
6+
7+
import { Button } from "../../../tailwind/ui/buttons/Button"
8+
9+
const alertVariants = cva(
10+
"flex flex-row gap-4 items-center rounded-lg border p-4",
11+
{
12+
variants: {
13+
variant: {
14+
info: "bg-background-highlight border",
15+
error:
16+
"border-error bg-error-light [&_h6]:text-error [&_svg]:text-error text-gray-800",
17+
success:
18+
"border-success bg-success-light [&_h6]:text-success [&_svg]:text-success text-gray-800",
19+
warning:
20+
"border-attention-outline bg-attention-light [&_h6]:text-attention [&_svg]:text-attention text-gray-800",
21+
update:
22+
"bg-primary-low-contrast border-primary-high-contrast [&_h6]:text-primary-high-contrast [&_svg]:text-primary-high-contrast",
23+
},
24+
size: {
25+
// Useful for banner alerts
26+
full: "rounded-none border-none w-full",
27+
},
28+
},
29+
defaultVariants: {
30+
variant: "info",
31+
},
32+
}
33+
)
34+
35+
const Alert = React.forwardRef<
36+
HTMLDivElement,
37+
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
38+
>(({ className, variant, size, ...props }, ref) => (
39+
<div
40+
ref={ref}
41+
role="alert"
42+
className={cn(alertVariants({ variant, size }), className)}
43+
{...props}
44+
/>
45+
))
46+
Alert.displayName = "Alert"
47+
48+
const AlertContent = React.forwardRef<
49+
HTMLDivElement,
50+
React.HTMLAttributes<HTMLDivElement>
51+
>(({ className, ...props }, ref) => (
52+
<div ref={ref} className={cn("flex flex-1 flex-col", className)} {...props} />
53+
))
54+
AlertContent.displayName = "AlertContent"
55+
56+
const AlertTitle = React.forwardRef<
57+
HTMLParagraphElement,
58+
React.HTMLAttributes<HTMLHeadingElement>
59+
>(({ className, ...props }, ref) => (
60+
<h6 ref={ref} className={cn("tracking-tight", className)} {...props} />
61+
))
62+
AlertTitle.displayName = "AlertTitle"
63+
64+
const AlertDescription = React.forwardRef<
65+
HTMLParagraphElement,
66+
React.HTMLAttributes<HTMLParagraphElement>
67+
>(({ className, ...props }, ref) => (
68+
<div
69+
ref={ref}
70+
className={cn("text-sm [&_p]:leading-relaxed", className)}
71+
{...props}
72+
/>
73+
))
74+
AlertDescription.displayName = "AlertDescription"
75+
76+
const AlertCloseButton = React.forwardRef<
77+
HTMLButtonElement,
78+
React.ButtonHTMLAttributes<HTMLButtonElement>
79+
>(({ className, ...props }, ref) => (
80+
<Button
81+
ref={ref}
82+
variant="ghost"
83+
className={cn("-me-4 rounded-full text-body", className)}
84+
{...props}
85+
>
86+
<MdClose className="h-6 w-6" />
87+
<span className="sr-only">Close</span>
88+
</Button>
89+
))
90+
AlertCloseButton.displayName = "AlertCloseButton"
91+
92+
export { Alert, AlertCloseButton, AlertContent, AlertDescription, AlertTitle }

src/styles/global.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@
148148
/* Complementary Set */
149149
--attention-outline: var(--attention-light);
150150

151-
--error-light: var(--error-light);
151+
--error: var(--red-500);
152+
--error-light: var(--red-100);
153+
--error-outline: var(--error);
152154
/* ! Deprecating error-neutral */
153155
--error-netural: var(--red-900);
154156

0 commit comments

Comments
 (0)