@talend/react-components
Version:
Set of react components.
303 lines (301 loc) • 10.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = require("react");
var _reactTransitionGroup = require("react-transition-group");
var _classnames = _interopRequireDefault(require("classnames"));
var _reactI18next = require("react-i18next");
var _Actions = require("../Actions");
var _NotificationModule = _interopRequireDefault(require("./Notification.module.scss"));
var _constants = _interopRequireDefault(require("../constants"));
var _translate = _interopRequireDefault(require("../translate"));
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/* eslint-disable jsx-a11y/no-static-element-interactions */
const TYPES = {
INFO: 'info',
WARNING: 'warning',
ERROR: 'error'
};
function CloseButtonComponent(props) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Actions.Action, {
onClick: () => props.leaveFn(props.notification),
"data-feature": props['data-feature'],
label: "",
icon: "talend-cross",
bsClass: (0, _classnames.default)(_NotificationModule.default['tc-notification-action'], 'tc-notification-action', _NotificationModule.default['tc-notification-close'], '.tc-notification-close'),
"aria-label": props.t('NOTIFICATION_CLOSE', {
defaultValue: 'Close notifications'
})
});
}
CloseButtonComponent.propTypes = {
notification: _propTypes.default.object,
leaveFn: _propTypes.default.func,
t: _propTypes.default.func,
'data-feature': _propTypes.default.string
};
CloseButtonComponent.defaultProps = {
t: (0, _translate.default)()
};
const CloseButton = (0, _reactI18next.withTranslation)(_constants.default)(CloseButtonComponent);
function MessageAction({
action
}) {
return !!action && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Actions.Action, {
...action,
bsClass: (0, _classnames.default)(_NotificationModule.default['tc-notification-action'], 'tc-notification-action', _NotificationModule.default['tc-notification-message-action'], 'tc-notification-message-action')
});
}
function Message({
notification
}) {
const {
title,
message,
action
} = notification;
const messages = Array.isArray(message) ? message : [message];
const titleClass = (0, _classnames.default)(_NotificationModule.default['tc-notification-title'], 'tc-notification-title');
const messageClass = (0, _classnames.default)(_NotificationModule.default['tc-notification-message'], 'tc-notification-message');
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("article", {
className: _NotificationModule.default.article,
children: [title && /*#__PURE__*/(0, _jsxRuntime.jsx)("h3", {
className: titleClass,
children: title
}), messages.map((paragraph, index) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
className: messageClass,
children: [paragraph, index === messages.length - 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(MessageAction, {
action: action
})]
}, index))]
});
}
function TimerBar({
type,
autoLeaveError
}) {
if (type === TYPES.ERROR && !autoLeaveError) {
return null;
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: (0, _classnames.default)(_NotificationModule.default['tc-notification-timer-bar'], 'tc-notification-timer-bar'),
"data-testid": "timer"
});
}
function Notification({
notification,
leaveFn,
...props
}) {
const isInfo = !notification.type || notification.type === TYPES.INFO;
const isWarning = notification.type === TYPES.WARNING;
const isError = notification.type === TYPES.ERROR;
const classes = (0, _classnames.default)(_NotificationModule.default['tc-notification'], 'tc-notification', {
[_NotificationModule.default['tc-notification-info']]: isInfo,
'tc-notification-info': isInfo,
[_NotificationModule.default['tc-notification-warning']]: isWarning,
'tc-notification-warning': isWarning,
[_NotificationModule.default['tc-notification-error']]: isError,
'tc-notification-error': isError
});
const enterAction = event => props.onMouseEnter(event, notification);
const leaveAction = event => props.onMouseOut(event, notification);
return (
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
(0, _jsxRuntime.jsxs)("div", {
role: isError ? 'alert' : 'status',
className: classes,
onClick: event => props.onClick(event, notification),
onFocus: enterAction,
onMouseEnter: enterAction,
onMouseLeave: leaveAction
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
,
tabIndex: 0,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(CloseButton, {
notification: notification,
leaveFn: leaveFn,
"data-feature": `close-notification-${notification.type}`
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(Message, {
notification: notification
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(TimerBar, {
type: notification.type,
autoLeaveError: props.autoLeaveError
})]
})
);
}
class Timer {
constructor(callback, delay) {
this.timerId = null;
this.start = null;
this.callbackFn = callback;
this.remaining = delay;
this.resume();
}
pause() {
clearTimeout(this.timerId);
this.remaining -= Date.now() - this.start;
}
resume() {
this.start = Date.now();
clearTimeout(this.timerId);
this.timerId = setTimeout(this.callbackFn, this.remaining);
}
cancel() {
clearTimeout(this.timerId);
}
}
class Registry {
constructor() {
this.timerRegistry = {};
}
isRegistered(notification) {
return !!this.timerRegistry[notification.id];
}
register(notification, timer) {
this.timerRegistry[notification.id] = timer;
}
pause(notification) {
if (this.isRegistered(notification)) {
this.timerRegistry[notification.id].pause();
}
}
resume(notification) {
if (this.isRegistered(notification)) {
this.timerRegistry[notification.id].resume();
}
}
cancel(notification) {
if (this.isRegistered(notification)) {
this.timerRegistry[notification.id].cancel();
// Clean registry to avoid memory leak
delete this.timerRegistry[notification.id];
}
}
}
function NotificationsContainer({
autoLeaveError,
autoLeaveTimeout,
enterTimeout,
leaveFn,
leaveTimeout,
notifications
}) {
const registryRef = (0, _react.useRef)(new Registry());
const registry = registryRef.current;
(0, _react.useEffect)(() => {
if (!registry) {
return;
}
notifications.filter(notification => !registry.isRegistered(notification)).filter(notification => notification.type !== TYPES.ERROR || autoLeaveError).forEach(notification => {
registry.register(notification, new Timer(() => {
leaveFn(notification);
registry.cancel(notification);
}, autoLeaveTimeout));
});
}, [autoLeaveError, autoLeaveTimeout, leaveFn, notifications, registry]);
const onClick = (event, notification) => {
if (notification.type !== TYPES.ERROR || autoLeaveError) {
if (event.currentTarget.getAttribute('pin') !== 'true') {
event.currentTarget.setAttribute('pin', 'true');
} else {
event.currentTarget.setAttribute('pin', 'false');
leaveFn(notification);
}
}
};
const onClose = (event, notification) => {
event.stopPropagation();
registry.cancel(notification);
leaveFn(notification);
};
const onMouseEnter = (event, notification) => {
if (notification.type !== TYPES.ERROR || autoLeaveError) {
registry.pause(notification);
}
};
const onMouseOut = (event, notification) => {
if ((notification.type !== TYPES.ERROR || autoLeaveError) && event.currentTarget.getAttribute('pin') !== 'true') {
registry.resume(notification);
}
};
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: (0, _classnames.default)(_NotificationModule.default['tc-notification-container'], 'tc-notification-container'),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactTransitionGroup.TransitionGroup, {
children: notifications.map(notification => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactTransitionGroup.CSSTransition, {
classNames: "tc-notification",
timeout: {
enter: enterTimeout,
exit: leaveTimeout
},
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Notification, {
notification: notification,
leaveFn: leaveFn,
autoLeaveTimeout: autoLeaveTimeout,
autoLeaveError: autoLeaveError,
onMouseEnter: onMouseEnter,
onMouseOut: onMouseOut,
onClose: onClose,
onClick: onClick
})
}, notification.id))
})
});
}
const notificationShape = {
id: _propTypes.default.any.isRequired,
type: _propTypes.default.oneOf(Object.values(TYPES)),
title: _propTypes.default.string,
message: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]).isRequired,
action: _propTypes.default.shape(_Actions.Action.propTypes)
};
CloseButton.propTypes = {
notification: _propTypes.default.shape(notificationShape).isRequired,
leaveFn: _propTypes.default.func.isRequired
};
MessageAction.propTypes = {
action: _propTypes.default.shape(_Actions.Action.propTypes)
};
Message.propTypes = {
notification: _propTypes.default.shape(notificationShape).isRequired
};
TimerBar.propTypes = {
type: _propTypes.default.oneOf(Object.values(TYPES)),
autoLeaveError: _propTypes.default.bool
};
Notification.displayName = 'Notification';
Notification.propTypes = {
notification: _propTypes.default.shape(notificationShape).isRequired,
leaveFn: _propTypes.default.func.isRequired,
autoLeaveTimeout: _propTypes.default.number,
autoLeaveError: _propTypes.default.bool,
onMouseEnter: _propTypes.default.func,
onMouseOut: _propTypes.default.func,
onClick: _propTypes.default.func
};
NotificationsContainer.displayName = 'NotificationsContainer';
NotificationsContainer.propTypes = {
enterTimeout: _propTypes.default.number,
leaveTimeout: _propTypes.default.number,
autoLeaveTimeout: _propTypes.default.number,
notifications: _propTypes.default.arrayOf(_propTypes.default.shape(notificationShape)).isRequired,
leaveFn: _propTypes.default.func.isRequired,
autoLeaveError: _propTypes.default.bool
};
NotificationsContainer.defaultProps = {
enterTimeout: 300,
leaveTimeout: 300,
autoLeaveTimeout: 4000,
autoLeaveError: false
};
NotificationsContainer.TYPES = TYPES;
var _default = exports.default = NotificationsContainer;
//# sourceMappingURL=Notification.component.js.map