UNPKG

@talend/react-components

Version:
303 lines (301 loc) 10.9 kB
"use strict"; 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