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

Shadcn migration - alert #13617

Merged
merged 4 commits into from
Aug 19, 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
2 changes: 1 addition & 1 deletion src/components/Alert/Alert.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Meta, StoryObj } from "@storybook/react"
import Alert from "."

const meta = {
title: "Molecules / Action Feedback / Alerts",
title: "Molecules / Action Feedback / Old Alerts",
component: Alert,
decorators: [
(Story) => (
Expand Down
87 changes: 87 additions & 0 deletions src/components/ui/__stories__/Alert.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from "react"
import { MdInfoOutline } from "react-icons/md"
import { Meta, StoryObj } from "@storybook/react"

import {
Alert,
AlertCloseButton,
AlertContent,
AlertDescription,
AlertTitle,
} from "../alert"
import { Center } from "../flex"

const meta = {
title: "Molecules / Action Feedback / Alerts",
component: Alert,
parameters: {
layout: "none",
},
decorators: [
(Story) => (
<Center className="min-h-[100vh]">
<Story />
</Center>
),
],
} satisfies Meta<typeof Alert>

export default meta

type Story = StoryObj<typeof meta>

const DEMO_TITLE = "Alert or callout title"
const DEMO_DESC = "This is an alert to be used for important information."

const VARIANTS = ["info", "error", "success", "warning", "update"] as const

export const Variants: Story = {
render: (args) => (
<div className="flex w-[500px] flex-col gap-4">
{VARIANTS.map((variant) => (
<Alert key={variant} variant={variant} className="w-full" {...args}>
<AlertContent>
<AlertTitle>{DEMO_TITLE}</AlertTitle>
<AlertDescription>This is a {variant} alert</AlertDescription>
</AlertContent>
</Alert>
))}
</div>
),
}

export const WithCloseButton: Story = {
render: (args) => (
<div className="flex flex-col gap-4">
{VARIANTS.map((variant) => (
<Alert key={variant} variant={variant} {...args}>
<AlertContent>
<AlertTitle>{DEMO_TITLE}</AlertTitle>
<AlertDescription>{DEMO_DESC}</AlertDescription>
</AlertContent>
<AlertCloseButton />
</Alert>
))}
</div>
),
}

export const Banner: Story = {
render: (args) => (
<div className="mx-8 flex w-full flex-col gap-4">
{VARIANTS.map((variant) => (
<Alert key={variant} variant={variant} size="full" {...args}>
<MdInfoOutline className="h-6 w-6" />
<AlertContent>
<AlertTitle>Banner use case</AlertTitle>
<AlertDescription>
<p>{DEMO_DESC}</p>
<p>{DEMO_DESC}</p>
</AlertDescription>
</AlertContent>
<AlertCloseButton />
</Alert>
))}
</div>
),
}
92 changes: 92 additions & 0 deletions src/components/ui/alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { MdClose } from "react-icons/md"

import { cn } from "@/lib/utils/cn"

import { Button } from "./buttons/Button"

const alertVariants = cva(
"flex flex-row gap-4 items-center rounded-lg border p-4",
{
variants: {
variant: {
info: "bg-background-highlight border",
error:
"border-error bg-error-light [&_h6]:text-error [&_svg]:text-error text-gray-800",
success:
"border-success bg-success-light [&_h6]:text-success [&_svg]:text-success text-gray-800",
warning:
"border-attention-outline bg-attention-light [&_h6]:text-attention [&_svg]:text-attention text-gray-800",
update:
"bg-primary-low-contrast border-primary-high-contrast [&_h6]:text-primary-high-contrast [&_svg]:text-primary-high-contrast",
},
size: {
// Useful for banner alerts
full: "rounded-none border-none w-full",
},
},
defaultVariants: {
variant: "info",
},
}
)

const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, size, ...props }, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant, size }), className)}
{...props}
/>
))
Alert.displayName = "Alert"

const AlertContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-1 flex-col", className)} {...props} />
))
AlertContent.displayName = "AlertContent"

const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h6 ref={ref} className={cn("tracking-tight", className)} {...props} />
))
AlertTitle.displayName = "AlertTitle"

const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"

const AlertCloseButton = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => (
<Button
ref={ref}
variant="ghost"
className={cn("-me-4 rounded-full text-body", className)}
{...props}
>
<MdClose className="h-6 w-6" />
<span className="sr-only">Close</span>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice (ref for anyone else: https://tailwindcss.com/docs/screen-readers)

</Button>
))
AlertCloseButton.displayName = "AlertCloseButton"

export { Alert, AlertCloseButton, AlertContent, AlertDescription, AlertTitle }
4 changes: 3 additions & 1 deletion src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@
/* Complementary Set */
--attention-outline: var(--attention-light);

--error-light: var(--error-light);
--error: var(--red-500);
--error-light: var(--red-100);
--error-outline: var(--error);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious the reason for the -outline token variants?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm good call, we are not using it, right? I guess the idea was to use this color as the border color. I missed that.

/* ! Deprecating error-neutral */
--error-netural: var(--red-900);

Expand Down
Loading