72 lines
2.3 KiB
JavaScript
72 lines
2.3 KiB
JavaScript
import * as React from 'react';
|
|
import { AlertCircle, CheckCircle2, Info, TriangleAlert, X } from 'lucide-react';
|
|
import { cva } from 'class-variance-authority';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
const alertVariants = cva('flex items-start gap-3 rounded-xl border p-4 animate-slide-down', {
|
|
variants: {
|
|
tone: {
|
|
info: 'bg-info-muted border-krow-blue/20 text-ink-2',
|
|
success: 'bg-success-muted border-success/20 text-ink-2',
|
|
warning: 'bg-warning-muted border-warning/25 text-ink-2',
|
|
destructive: 'bg-destructive-muted border-destructive/20 text-ink-2',
|
|
neutral: 'bg-surface-subtle border-border text-ink-2',
|
|
},
|
|
},
|
|
defaultVariants: { tone: 'info' },
|
|
});
|
|
|
|
const ICONS = {
|
|
info: Info,
|
|
success: CheckCircle2,
|
|
warning: TriangleAlert,
|
|
destructive: AlertCircle,
|
|
neutral: Info,
|
|
};
|
|
|
|
const ICON_COLORS = {
|
|
info: 'text-krow-blue',
|
|
success: 'text-success',
|
|
warning: 'text-warning',
|
|
destructive: 'text-destructive',
|
|
neutral: 'text-ink-4',
|
|
};
|
|
|
|
/**
|
|
* Alert — an inline, persistent message about the state of the page.
|
|
*
|
|
* For transient confirmation of something the user just did, use `toast`
|
|
* instead: an Alert that appears and disappears is easy to miss, and a toast
|
|
* that persists is noise.
|
|
*/
|
|
export function Alert({ tone = 'info', title, children, icon, onDismiss, action, className, ...props }) {
|
|
const Icon = icon || ICONS[tone];
|
|
|
|
return (
|
|
<div role="alert" className={cn(alertVariants({ tone }), className)} {...props}>
|
|
{Icon && <Icon className={cn('w-4.5 h-4.5 shrink-0 mt-0.5', ICON_COLORS[tone])} aria-hidden="true" />}
|
|
|
|
<div className="flex-1 min-w-0">
|
|
{title && <p className="text-body-sm font-semibold text-ink-1">{title}</p>}
|
|
{children && (
|
|
<div className={cn('text-body-sm text-ink-2 leading-relaxed', title && 'mt-0.5')}>
|
|
{children}
|
|
</div>
|
|
)}
|
|
{action && <div className="mt-3">{action}</div>}
|
|
</div>
|
|
|
|
{onDismiss && (
|
|
<button
|
|
type="button"
|
|
onClick={onDismiss}
|
|
aria-label="Dismiss"
|
|
className="grid place-items-center w-6 h-6 rounded-md text-ink-4 hover:text-ink-1 hover:bg-black/5 transition-colors shrink-0 focus-ring-inset"
|
|
>
|
|
<X className="w-3.5 h-3.5" aria-hidden="true" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|