brunner56's picture
implement app
0bfe2e3
import { cva, VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { cn, ComponentAnatomy, defineStyleAnatomy } from '../core/styling';
/* -------------------------------------------------------------------------------------------------
* Anatomy
* -----------------------------------------------------------------------------------------------*/
export const AlertAnatomy = defineStyleAnatomy({
root: cva(
['UI-Alert__root', 'py-3 px-4 flex justify-between rounded-[--radius]'],
{
variants: {
intent: {
info: 'bg-blue-50 text-blue-500 dark:bg-opacity-10 dark:text-blue-200',
success:
'bg-green-50 text-green-500 dark:bg-opacity-10 dark:text-green-200',
warning:
'bg-orange-50 text-orange-500 dark:bg-opacity-10 dark:text-orange-200',
alert: 'bg-red-50 text-red-500 dark:bg-opacity-10 dark:text-red-200',
'info-basic':
'bg-white text-gray-800 border dark:bg-gray-800 dark:text-gray-200',
'success-basic':
'bg-white text-gray-800 border dark:bg-gray-800 dark:text-gray-200',
'warning-basic':
'bg-white text-gray-800 border dark:bg-gray-800 dark:text-gray-200',
'alert-basic':
'bg-white text-gray-800 border dark:bg-gray-800 dark:text-gray-200',
},
},
defaultVariants: {
intent: 'info',
},
}
),
detailsContainer: cva(['UI-Alert__detailsContainer', 'flex']),
textContainer: cva([
'UI-Alert__textContainer',
'flex flex-col self-center ml-3 gap-.5',
]),
title: cva(['UI-Alert__title', 'font-bold']),
description: cva(['UI-Alert__description']),
icon: cva(['UI-Alert__icon', 'text-2xl content-evenly'], {
variants: {
intent: {
'info-basic': 'text-blue-500',
'success-basic': 'text-green-500',
'warning-basic': 'text-orange-500',
'alert-basic': 'text-red-500',
info: 'text-blue-500',
success: 'text-green-500',
warning: 'text-orange-500',
alert: 'text-red-500',
},
},
defaultVariants: {
intent: 'info-basic',
},
}),
closeButton: cva([
'UI-Alert__closeButton',
'flex-none self-start text-2xl hover:opacity-50 transition ease-in cursor-pointer h-5 w-5',
]),
});
/* -------------------------------------------------------------------------------------------------
* Alert
* -----------------------------------------------------------------------------------------------*/
export type AlertProps = React.ComponentPropsWithRef<'div'> &
VariantProps<typeof AlertAnatomy.root> &
ComponentAnatomy<typeof AlertAnatomy> & {
/**
* The title of the alert
*/
title?: string;
/**
* The description text or content of the alert
*/
description?: React.ReactNode;
/**
* Replace the default icon with a custom icon
*
* - `iconClass` does not apply to custom icons
*/
icon?: React.ReactNode;
/**
* If true, a close button will be rendered
*/
isClosable?: boolean;
/**
* Callback invoked when the close button is clicked
*/
onClose?: () => void;
};
export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
(props, ref) => {
const {
children,
className,
title,
description,
isClosable,
onClose,
intent = 'info-basic',
iconClass,
detailsContainerClass,
textContainerClass,
titleClass,
descriptionClass,
closeButtonClass,
icon,
...rest
} = props;
let Icon: any = null;
if (intent === 'info-basic' || intent === 'info') {
Icon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4"></path>
<path d="M12 8h.01"></path>
</svg>
);
} else if (intent === 'alert-basic' || intent === 'alert') {
Icon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" x2="12" y1="8" y2="12"></line>
<line x1="12" x2="12.01" y1="16" y2="16"></line>
</svg>
);
} else if (intent === 'warning-basic' || intent === 'warning') {
Icon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path>
<line x1="12" x2="12" y1="9" y2="13"></line>
<line x1="12" x2="12.01" y1="17" y2="17"></line>
</svg>
);
} else if (intent === 'success-basic' || intent === 'success') {
Icon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"></path>
<path d="m9 12 2 2 4-4"></path>
</svg>
);
}
return (
<div
className={cn(AlertAnatomy.root({ intent }), className)}
{...rest}
ref={ref}
>
<div
className={cn(AlertAnatomy.detailsContainer(), detailsContainerClass)}
>
{icon ? (
icon
) : (
<div
className={cn(AlertAnatomy.icon({ intent: intent }), iconClass)}
>
{Icon && Icon}
</div>
)}
<div className={cn(AlertAnatomy.textContainer(), textContainerClass)}>
<span className={cn(AlertAnatomy.title(), titleClass)}>
{title}
</span>
{!!(description || children) && (
<div className={cn(AlertAnatomy.description(), descriptionClass)}>
{description || children}
</div>
)}
</div>
</div>
{onClose && (
<button
className={cn(AlertAnatomy.closeButton(), closeButtonClass)}
onClick={onClose}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="18" x2="6" y1="6" y2="18"></line>
<line x1="6" x2="18" y1="6" y2="18"></line>
</svg>
</button>
)}
</div>
);
}
);
Alert.displayName = 'Alert';