import React, { ReactElement } from 'react'; import css from '../../utils/css'; import Icon, { IconName } from '../Icon'; import Button from '../Button'; import { StyledAlert, StyledInner, StyledTitle, StyledContent, StyledIconWrapper, StyledCloseButton, } from './StyledAlert'; import { ICON_MAP, ICON_SIZE_MAP } from './constants'; import { CommonProps } from '../common'; import { getOrElse, map, none, Option, some } from '../../fp/Option'; import { Either, left, match, right } from '../../fp/Either'; import { pipe } from '../../fp/function'; type AlertSize = 'default' | 'compact'; export interface AlertProps extends CommonProps { /** * Alert content. */ content: string | ReactElement; /** * Icon name or a react element as custom icon. * - undefined: use default icon according to Alert intent. * - null: no icon at all. * - IconName: an icon identifier from hero-design icon list. * - ReactElement: Custom icon by your own. */ icon?: null | IconName | ReactElement; /** * Visual intent color to apply to alert. */ intent?: 'success' | 'info' | 'warning' | 'danger' | 'error'; /** * Closing callback. When onClose is available, an `x` button will be rendered on the right side of alert. The callback will be called when user clicks on `x` button. */ onClose?: () => void; /** * Alert title. */ title?: string | ReactElement; } export const getAlertIcon = ( defaultIcon: IconName, icon: undefined | null | IconName | ReactElement ): Option> => { if (icon === undefined) { return some(left(defaultIcon)); } if (typeof icon === 'string' && Icon.List.includes(icon)) { return some(left(icon)); } if (React.isValidElement(icon)) { return some(right(icon)); } return none; }; const Alert = ({ intent = 'info', title, content, icon, onClose, id, className, style, sx = {}, 'data-test-id': dataTestId, }: AlertProps): ReactElement => { const themeSize: AlertSize = title !== undefined ? 'default' : 'compact'; const defaultIcon = ICON_MAP[intent]; const maybeIcon = getAlertIcon(defaultIcon, icon); const iconIntent = intent; const iconSize = ICON_SIZE_MAP[themeSize]; const renderWithIconWrapper = (iconEle: ReactElement): ReactElement => ( {iconEle} ); return ( {pipe( maybeIcon, map( match( (iconString): ReactElement => renderWithIconWrapper( ), renderWithIconWrapper ) ), getOrElse(() => null) )} {title !== undefined && {title}} {content} {onClose !== undefined && ( )} ); }; export default Alert;