import React, { ReactElement } from 'react'; import css from '../../utils/css'; import Icon, { IconName } from '../Icon'; import Button from '../Button'; import StyledNotification, { StyledInner, StyledTitle, StyledContent, StyledIconWrapper, StyledCloseButton, } from './StyledNotification'; import { CommonProps } from '../common'; import { Either, left, match, right } from '../../fp/Either'; import { getOrElse, map, none, Option, some } from '../../fp/Option'; import { pipe } from '../../fp/function'; type NotificationIntent = 'success' | 'info' | 'warning' | 'danger' | 'error'; export interface NotificationProps extends CommonProps { /** * Notification content. */ content?: string | ReactElement; /** * Icon name or a react element as custom icon. * - undefined: use default icon according to Notification 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 notification icon. */ intent?: NotificationIntent; /** * Closing callback. When onClose is available, an `x` button will be rendered on the right side of notification. The callback will be called when user clicks on `x` button. */ onClose?: () => void; /** * Notification title. */ title: string | ReactElement; } const getIcon = ( intent: NotificationIntent ): { icon: IconName; intent: NotificationIntent; } => { switch (intent) { case 'success': return { icon: 'circle-ok', intent: 'success' }; case 'info': return { icon: 'circle-info', intent: 'info' }; case 'warning': return { icon: 'circle-warning', intent: 'warning' }; case 'danger': return { icon: 'circle-cancel', intent: 'danger' }; case 'error': return { icon: 'circle-cancel', intent: 'error' }; default: return { icon: 'circle-ok', intent: 'success' }; } }; const getNotificationIcon = ( defaultIcon: IconName, icon: undefined | null | IconName | ReactElement ): Option> => { if (icon === undefined) { return some(left(defaultIcon)); } // FIXME: Logic on type guard is not expected if (typeof icon === 'string') { return some(left(icon)); } if (React.isValidElement(icon)) { return some(right(icon)); } return none; }; const Notification = ({ intent = 'info', title, content, icon, onClose, id, className, style, sx = {}, 'data-test-id': dataTestId, }: NotificationProps): ReactElement => { const { icon: defaultIcon, intent: iconIntent } = getIcon(intent); const maybeIcon = getNotificationIcon(defaultIcon, icon); const renderWithIconWrapper = (iconEle: ReactElement): ReactElement => ( {iconEle} ); return ( {pipe( maybeIcon, map( match( (iconString): ReactElement => renderWithIconWrapper( ), renderWithIconWrapper ) ), getOrElse(() => null) )} {title} {content} {onClose !== undefined && ( )} ); }; export default Notification;