box-ui-elements-mlh
Version:
129 lines (112 loc) • 3.92 kB
Flow
// @flow
import * as React from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import IconAlertCircle from '../../icons/general/IconAlertCircle';
import IconBell from '../../icons/general/IconBell';
import IconClose from '../../icons/general/IconClose';
import IconInfoThin from '../../icons/general/IconInfoThin';
import IconSync from '../../icons/general/IconSync';
import type { NotificationType } from '../../common/types/core';
import './Notification.scss';
// @NOTE: We can't import these constants from ./constant.js because `react-docgen`
// can't handle imported variables appear in propTypes
// see https://github.com/reactjs/react-docgen/issues/33
const DURATION_SHORT = 'short';
const DURATION_LONG = 'long';
const OVERFLOW_WRAP = 'wrap';
const TYPE_DEFAULT = 'default';
const TYPE_INFO = 'info';
const TYPE_WARN = 'warn';
const TYPE_ERROR = 'error';
const DURATION_TIMES = {
[DURATION_SHORT]: 5000,
[DURATION_LONG]: 10000,
};
const ICON_RENDERER: { [string]: Function } = {
[TYPE_DEFAULT]: () => <IconBell />,
[TYPE_ERROR]: () => <IconAlertCircle />,
[TYPE_INFO]: () => <IconSync />,
[TYPE_WARN]: () => <IconInfoThin />,
};
const messages = defineMessages({
clearNotificationButtonText: {
defaultMessage: 'Clear Notification',
description: 'Button to clear notification',
id: 'boxui.notification.clearNotification',
},
});
type Props = {
/**
* The contents of the `Notification`.
* - Notification text must be wrapped in a `<span />` tag.
* - Notification buttons must be the `<Button />` component.
*/
children: React.Node,
/** Function that gets executed when close button is clicked or when duration expires. */
duration?: 'short' | 'long',
/** `duration`: When set, dictates how long the notification will exist before calling `onClose`.
* If unset, the notification will not automatically call `onClose`.
* - `short`: 5s
* - `long`: 10s */
intl: Object,
onClose?: Function,
/**
* Determines notification colors
* - `default`: black
* - `info`: green
* - `warn`: yellow
* - `error`: red
*/
overflow?: 'wrap' | 'ellipsis',
type: NotificationType,
};
class Notification extends React.Component<Props> {
static defaultProps = {
overflow: OVERFLOW_WRAP,
type: TYPE_DEFAULT,
};
componentDidMount() {
const { duration, onClose } = this.props;
this.timeout = duration && onClose ? setTimeout(onClose, DURATION_TIMES[duration]) : null;
}
onClose = event => {
const { onClose } = this.props;
if (this.timeout) {
clearTimeout(this.timeout);
}
if (onClose) {
onClose(event);
}
};
getChildren() {
const { children } = this.props;
return typeof children === 'string' ? <span>{children}</span> : children;
}
timeout: TimeoutID | null;
render() {
const contents = this.getChildren();
const { intl, type, overflow } = this.props;
const { formatMessage } = intl;
const classes = classNames('notification', type, overflow);
return (
<div className={classes}>
{React.cloneElement(ICON_RENDERER[type](), {
color: '#fff',
height: 20,
width: 20,
})}
{contents}
<button
aria-label={formatMessage(messages.clearNotificationButtonText)}
className="close-btn"
onClick={this.onClose}
type="button"
>
<IconClose color="#FFF" height={18} width={18} />
</button>
</div>
);
}
}
export default injectIntl(Notification);