import React, { ReactElement } from 'react'; import css from '../../utils/css'; import Icon, { IconName } from '../Icon'; import Button from '../Button'; import { StyledBanner, StyledInner, StyledTitle, StyledContent, StyledIconWrapper, StyledCloseButton, } from './StyledBanner'; 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'; export interface BannerProps extends CommonProps { /** * Banner content. */ content: string | ReactElement; /** * Icon name or a react element as custom icon. * - undefined: use default icon according to Banner intent. * - null: no icon at all. * - string: an icon string from hero-design icon list. * - ReactElement: Custom icon by your own. */ icon?: null | IconName | ReactElement; /** * Visual intent color to apply to banner. */ intent?: 'success' | 'info' | 'warning' | 'danger' | 'error'; /** * Closing callback. When onClose is available, an `x` button will be rendered on the right side of Banner. The callback will be called when user clicks on `x` button. */ onClose?: () => void; /** * Banner title. */ title?: string; } type BannerSize = 'default' | 'compact'; const ICON_MAP = { success: 'circle-ok', info: 'circle-info', warning: 'circle-warning', danger: 'circle-cancel', error: 'circle-cancel', } as const; const ICON_SIZE_MAP = { default: 'xlarge', compact: 'small', } as const; export const getBannerIcon = ( 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 Banner = ({ intent = 'info', title, content, icon, onClose, id, className, style, sx = {}, 'data-test-id': dataTestId, }: BannerProps): ReactElement => { const size: BannerSize = title !== undefined ? 'default' : 'compact'; const defaultIcon = ICON_MAP[intent]; const maybeIcon = getBannerIcon(defaultIcon, icon); const iconSize = ICON_SIZE_MAP[size]; 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 Banner;