diff --git a/src/components/__snapshots__/alert.spec.tsx.snap b/src/components/__snapshots__/alert.spec.tsx.snap new file mode 100644 index 0000000..3b3cf69 --- /dev/null +++ b/src/components/__snapshots__/alert.spec.tsx.snap @@ -0,0 +1,185 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Button component > renders correctly for variant default 1`] = ` +
+ +
+`; + +exports[`Button component > renders correctly for variant destructive 1`] = ` +
+ +
+`; + +exports[`Button component > renders correctly for variant error 1`] = ` +
+ +
+`; + +exports[`Button component > renders correctly for variant warning 1`] = ` +
+ +
+`; diff --git a/src/components/alert.spec.tsx b/src/components/alert.spec.tsx new file mode 100644 index 0000000..f52d104 --- /dev/null +++ b/src/components/alert.spec.tsx @@ -0,0 +1,23 @@ +import { render } from "@testing-library/react"; +import { InfoIcon } from "lucide-react"; +import { describe, expect, it } from "vitest"; +import { Alert, AlertDescription, AlertProps, AlertTitle } from "./alert"; + +type Variant = NonNullable; + +const variants: Variant[] = ["default", "destructive", "error", "warning"]; + +describe("Button component", () => { + it.each(variants)("renders correctly for variant %s", (variant) => { + const { container } = render( + + + {variant} Alert + + Description of altert of variant {variant} + + + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/alert.stories.tsx b/src/components/alert.stories.tsx new file mode 100644 index 0000000..906a8fb --- /dev/null +++ b/src/components/alert.stories.tsx @@ -0,0 +1,87 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { fn } from "@storybook/test"; + +import { + AlertCircle, + AlertCircleIcon, + AlertTriangleIcon, + InfoIcon, +} from "lucide-react"; +import { Alert, AlertDescription, AlertTitle } from "./alert"; + +const meta = { + title: "Alert", + component: Alert, + parameters: { + layout: "centered", + }, + argTypes: { + variant: { + options: ["default", "destructive", "error", "warning"], + control: "select", + }, + }, + args: { onClick: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Example: Story = { + render(props) { + return ( + + + Heads up! + + Message explaining why the heads up. + + + ); + }, +}; + +export const Destructive: Story = { + args: { + variant: "destructive", + }, + render(props) { + return ( + + + Error + Message explaining the error. + + ); + }, +}; + +export const Error: Story = { + args: { + variant: "error", + }, + render(props) { + return ( + + + Error + Message explaining the error. + + ); + }, +}; + +export const Warning: Story = { + args: { + variant: "warning", + }, + render(props) { + return ( + + + Warning + Message explaining the warning. + + ); + }, +}; diff --git a/src/components/alert.tsx b/src/components/alert.tsx new file mode 100644 index 0000000..49e583b --- /dev/null +++ b/src/components/alert.tsx @@ -0,0 +1,63 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +export type AlertProps = React.HTMLAttributes & + VariantProps; + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + error: "border-red-500 bg-red-100 [&>svg]:text-red-500", + warning: "border-yellow-500 bg-yellow-100 [&>svg]:text-yellow-500", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +const Alert = React.forwardRef( + ({ className, variant, ...props }, ref) => ( +
+ ) +); +Alert.displayName = "Alert"; + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertTitle.displayName = "AlertTitle"; + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertDescription.displayName = "AlertDescription"; + +export { Alert, AlertTitle, AlertDescription }; diff --git a/src/index.ts b/src/index.ts index 77b5083..5fcffcc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,4 +4,5 @@ export * from "@/components/form"; export * from "@/components/input"; export * from "@/components/label"; export * from "@/components/skeleton"; +export * from "@/components/alert"; export { cn } from "@/lib/utils";