@spaced-out/ui-design-system
Version:
Sense UI components library
209 lines (194 loc) • 5.47 kB
Flow
// @flow strict
import * as React from 'react';
import type {AlertSemanticType} from '../../types/common';
import {ALERT_SEMANTIC} from '../../types/common';
import {TEXT_COLORS} from '../../types/typography';
import {classify} from '../../utils/classify';
import type {IconType} from '../Icon';
import {ClickableIcon, Icon} from '../Icon';
import {Link} from '../Link';
import {SubTitleExtraSmall} from '../Text';
import {Truncate} from '../Truncate';
import css from './InContextAlert.module.css';
type ClassNames = $ReadOnly<{
wrapper?: string,
alertText?: string,
actionContainer?: string,
icon?: string,
}>;
type InContextAlertBaseProps = {
classNames?: ClassNames,
...
| {
dismissable: true,
onCloseClick?: ?(SyntheticEvent<HTMLElement>) => mixed,
selfDismiss?: boolean,
}
| {dismissable?: false},
children?: string,
actionText?: string,
onAction?: ?(SyntheticEvent<HTMLElement>) => mixed,
};
export type InContextAlertProps = {
...InContextAlertBaseProps,
semantic?: AlertSemanticType,
leftIconName?: string,
leftIconType?: IconType,
};
const AlertIcon = ({
semantic,
leftIconName,
leftIconType,
iconClassName,
}: {
semantic: AlertSemanticType,
leftIconName: string,
leftIconType?: IconType,
iconClassName?: string,
}) => {
switch (semantic) {
case ALERT_SEMANTIC.neutral:
return (
<Icon
color={TEXT_COLORS.neutral}
name={leftIconName ? leftIconName : 'face-smile'}
size="small"
type={leftIconType}
className={iconClassName}
/>
);
case ALERT_SEMANTIC.success:
return (
<Icon
name={leftIconName ? leftIconName : 'circle-check'}
size="small"
color={TEXT_COLORS.success}
type={leftIconType}
className={iconClassName}
/>
);
case ALERT_SEMANTIC.information:
return (
<Icon
name={leftIconName ? leftIconName : 'circle-info'}
size="small"
color={TEXT_COLORS.information}
type={leftIconType}
className={iconClassName}
/>
);
case ALERT_SEMANTIC.warning:
return (
<Icon
name={leftIconName ? leftIconName : 'circle-exclamation'}
size="small"
color={TEXT_COLORS.warning}
type={leftIconType}
className={iconClassName}
/>
);
case ALERT_SEMANTIC.danger:
return (
<Icon
name={leftIconName ? leftIconName : 'shield-exclamation'}
size="small"
color={TEXT_COLORS.danger}
type={leftIconType}
className={iconClassName}
/>
);
default:
return (
<Icon
color={TEXT_COLORS.neutral}
name={leftIconName ? leftIconName : 'face-smile'}
size="small"
type={leftIconType}
className={iconClassName}
/>
);
}
};
export const InContextAlert: React$AbstractComponent<
InContextAlertProps,
HTMLDivElement,
> = React.forwardRef<InContextAlertProps, HTMLDivElement>(
(props: InContextAlertProps, ref): React.Node => {
const {
classNames,
semantic = ALERT_SEMANTIC.neutral,
dismissable,
children,
selfDismiss = false,
leftIconName = '',
onCloseClick,
actionText = '',
onAction,
leftIconType,
} = props;
const [dismissed, setDismissed] = React.useState(false);
const closeClickHandler = (e) => {
onCloseClick && onCloseClick(e);
selfDismiss && setDismissed(true);
};
return (
<>
{!dismissed && (
<div
className={classify(
css.alertContainer,
{
[css.neutral]: semantic === ALERT_SEMANTIC.neutral,
[css.success]: semantic === ALERT_SEMANTIC.success,
[css.information]: semantic === ALERT_SEMANTIC.information,
[css.warning]: semantic === ALERT_SEMANTIC.warning,
[css.danger]: semantic === ALERT_SEMANTIC.danger,
},
classNames?.wrapper,
)}
ref={ref}
>
<AlertIcon
semantic={semantic}
leftIconName={leftIconName}
leftIconType={leftIconType}
iconClassName={classNames?.icon}
/>
{React.Children.count(children) > 0 && (
<SubTitleExtraSmall className={classify(classNames?.alertText)}>
<Truncate line={2} wordBreak="initial">
{children}
</Truncate>
</SubTitleExtraSmall>
)}
{!!(actionText || dismissable) && (
<div
className={classify(
css.actionContainer,
classNames?.actionContainer,
)}
>
{!!actionText && (
<Link onClick={onAction} color="primary">
{actionText}
</Link>
)}
{!!dismissable && (
<ClickableIcon
color={TEXT_COLORS.primary}
ariaLabel="close"
name="close"
size="small"
type="regular"
onClick={closeClickHandler}
className={css.closeIcon}
/>
)}
</div>
)}
</div>
)}
</>
);
},
);