UNPKG

react-simple-toasts

Version:

Instant, lightweight toast notifications for React. No providers or containers needed.

591 lines (570 loc) 19.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var ReactDOM = require('react-dom'); var ReactDOMClient = require('react-dom/client'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM); var ReactDOMClient__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOMClient); function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var createElement = function (id) { var element = document.createElement('div'); element.setAttribute('id', id); return element; }; var addRootElement = function (rootElem) { document.body.appendChild(rootElem); return rootElem; }; // Let compiler not to search module usage var fullClone = __assign(__assign({}, ReactDOM__namespace), ReactDOMClient__namespace); var version = fullClone.version, reactRender = fullClone.render; fullClone.unmountComponentAtNode; var createRoot; try { var mainVersion = Number((version || '').split('.')[0]); if (mainVersion >= 18 && fullClone.createRoot) { createRoot = fullClone.createRoot; } } catch (e) { // Do nothing; } function toggleWarning(skip) { var __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = fullClone.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; if (__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED && typeof __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED === 'object') { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.usingClientEntryPoint = skip; } } var MARK = '__rc_react_root__'; function modernRender(node, container) { toggleWarning(true); var root = container[MARK] || createRoot(container); toggleWarning(false); /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ root.render(node); container[MARK] = root; } function legacyRender(node, container) { reactRender === null || reactRender === void 0 ? void 0 : reactRender(node, container); } function render(node, container) { if (createRoot != null) { modernRender(node, container); return; } legacyRender(node, container); } var createId = function () { return Date.now() + Math.floor(Math.random() * 10000000000000000); }; var isBrowser = function () { return typeof window !== 'undefined'; }; var reverse = function (arr) { var result = []; for (var i = arr.length - 1; i >= 0; i--) { result.push(arr[i]); } return result; }; var rgbToRgba = function (rgb, alpha) { var _a = rgb.replace(/[rgb(]|[)]/g, '').split(',').map(function (v) { return v.trim(); }), r = _a[0], g = _a[1], b = _a[2]; return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alpha, ")"); }; var classes = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return args.filter(Boolean).join(' '); }; var SET_TIMEOUT_MAX = 2147483647; var ToastPosition = { BOTTOM_LEFT: 'bottom-left', BOTTOM_CENTER: 'bottom-center', BOTTOM_RIGHT: 'bottom-right', TOP_LEFT: 'top-left', TOP_CENTER: 'top-center', TOP_RIGHT: 'top-right', CENTER: 'center' }; var Themes = { DARK: 'dark', DARK_EDGE: 'dark-edge', LIGHT: 'light', LIGHT_EDGE: 'light-edge', PINK_DAWN: 'pink-dawn', CHROMA: 'chroma', BLUE_DUSK: 'blue-dusk', OCEAN_WAVE: 'ocean-wave', SUNSET: 'sunset', MOONLIGHT: 'moonlight', FROSTED_GLASS: 'frosted-glass', SUCCESS: 'success', INFO: 'info', WARNING: 'warning', FAILURE: 'failure', PLAIN: 'plain' }; var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect; function Loading(_a) { var color = _a.color, children = _a.children; var translucentColor = color && rgbToRgba(color, 0.3); return /*#__PURE__*/React.createElement("span", { className: 'toast__spinner-wrap' }, /*#__PURE__*/React.createElement("span", { className: 'toast__spinner', style: { border: "2px solid ".concat(translucentColor), borderTopColor: color } }, children)); } var TransitionClassNames = { enter: 'toast__message--enter-active', exit: 'toast__message--exit-active' }; function ToastMessage(_a) { var id = _a.id, message = _a.message, className = _a.className, clickableProp = _a.clickable, clickClosable = _a.clickClosable, position = _a.position, isExit = _a.isExit, render = _a.render, theme = _a.theme, offsetX = _a.offsetX, offsetY = _a.offsetY, deltaOffsetX = _a.deltaOffsetX, deltaOffsetY = _a.deltaOffsetY, zIndex = _a.zIndex, loading = _a.loading, loadingText = _a.loadingText, onClick = _a.onClick, onClose = _a.onClose, onCloseStart = _a.onCloseStart, _onEnter = _a._onEnter; var clickable = clickableProp || clickClosable; var messageDOM = React.useRef(null); var hasTopPosition = position === null || position === void 0 ? void 0 : position.includes('top'); var hasBottomPosition = position === null || position === void 0 ? void 0 : position.includes('bottom'); var hasRightPosition = position === null || position === void 0 ? void 0 : position.includes('right'); var hasLeftPosition = position === null || position === void 0 ? void 0 : position.includes('left'); var hasCenterPosition = position === null || position === void 0 ? void 0 : position.includes('-center'); var isCenterPosition = position === ToastPosition.CENTER; var _b = React.useState(false), isEnter = _b[0], setIsEnter = _b[1]; var _c = React.useState({ transform: "translate(".concat(deltaOffsetX, ", ").concat(isCenterPosition ? 'calc(50% - 20px)' : "".concat(parseInt(deltaOffsetY || '0') + 20 * (hasTopPosition ? -1 : 1), "px"), ")") }), messageStyle = _c[0], setMessageStyle = _c[1]; var _d = React.useState(!!loading), localLoading = _d[0], setLocalLoading = _d[1]; var _e = React.useState(), loadingColor = _e[0], setLoadingColor = _e[1]; var top = isCenterPosition ? '50%' : hasTopPosition ? offsetY : undefined; var bottom = hasBottomPosition ? offsetY : undefined; var right = hasRightPosition ? offsetX : undefined; var left = hasCenterPosition || isCenterPosition ? '50%' : hasLeftPosition ? offsetX : undefined; useIsomorphicLayoutEffect(function () { var transform = "translate(".concat(deltaOffsetX, ", ").concat(deltaOffsetY, ")"); setMessageStyle({ top: top, right: right, bottom: bottom, left: left, zIndex: zIndex, transform: transform, WebkitTransform: transform }); }, [deltaOffsetX, deltaOffsetY, zIndex, top, right, bottom, left]); useIsomorphicLayoutEffect(function () { var _a; if (((_a = messageDOM.current) === null || _a === void 0 ? void 0 : _a.clientHeight) == null || isEnter) return; var width = messageDOM.current.clientWidth; var height = messageDOM.current.clientHeight; if (messageDOM.current) { _onEnter === null || _onEnter === void 0 ? void 0 : _onEnter({ target: messageDOM.current, width: width, height: height }); } setIsEnter(true); }, [isEnter, _onEnter]); useIsomorphicLayoutEffect(function () { if (!messageDOM.current) return; var messageText = messageDOM.current.querySelector('span'); var textColor = messageText && window.getComputedStyle(messageText).color; if (!textColor) return; setLoadingColor(textColor); }, []); useIsomorphicLayoutEffect(function () { if (loading instanceof Promise) { setLocalLoading(true); loading.then(function () { setLocalLoading(false); }); return; } setLocalLoading(!!loading); }, [loading]); useIsomorphicLayoutEffect(function () { if (isExit) { onCloseStart(); } }, [isExit]); var messageClassNames = classes('toast__message', "toast__message--".concat(position || 'bottom-center'), "toast__".concat(theme, "-wrapper"), isEnter ? TransitionClassNames.enter : '', isExit ? TransitionClassNames.exit : '', localLoading ? 'toast__message--loading' : ''); var contentClassNames = classes('toast__content', clickable ? 'toast__content--clickable' : '', !render && theme ? "toast__".concat(theme) : '', !render && theme ? 'toast__theme-content' : '', theme || '', className); var clickableProps = { onClick: onClick, tabIndex: 0, role: 'button' }; return /*#__PURE__*/React.createElement("div", { ref: messageDOM, id: id.toString(), className: messageClassNames, style: messageStyle, onTransitionEnd: function () { if (messageClassNames.includes(TransitionClassNames.exit)) { onClose(); } } }, /*#__PURE__*/React.createElement("div", _extends({ className: contentClassNames }, clickable && clickableProps), localLoading && /*#__PURE__*/React.createElement(Loading, { color: loadingColor }, loadingText), render ? render(message) : message)); } /** * Check if the updateOptions is a ToastUpdateOptions * @param updateOptions */ var isToastUpdateOptions = function (updateOptions) { if (updateOptions && typeof updateOptions === 'object') { return 'message' in updateOptions || 'duration' in updateOptions || 'loading' in updateOptions; } return false; }; function ToastContainer(props) { var toastComponentList = props.toastComponentList, onToastEnter = props.onToastEnter; var handleToastEnter = function (t, e) { toastComponentList.forEach(function (toast) { if (toast.id !== t.id) return; toast.startCloseTimer(); toast.height = e.height; }); onToastEnter(); }; return /*#__PURE__*/React.createElement(React.Fragment, null, toastComponentList.map(function (t) { var toastComponents = t.position.includes('top') ? reverse(toastComponentList) : toastComponentList; var currentIndex = toastComponents.findIndex(function (toast) { return toast.id === t.id; }); var bottomToasts = toastComponents.slice(currentIndex + 1).filter(function (toast) { return toast.position === t.position && !toast.isExit; }); var bottomToastsHeight = bottomToasts.reduce(function (acc, toast) { var _a; return acc + ((_a = toast.height) !== null && _a !== void 0 ? _a : 0) + t.gap; }, 0); var deltaOffsetX = t.position.includes('left') || t.position.includes('right') ? '0%' : '-50%'; var offsetYAlpha = t.position.includes('top') ? 1 : -1; var baseOffsetY = bottomToastsHeight * offsetYAlpha; var deltaOffsetY = t.position === 'center' ? "calc(-50% - ".concat(baseOffsetY * -1, "px)") : "".concat(baseOffsetY, "px"); return /*#__PURE__*/React.createElement(React.Fragment, { key: t.id }, /*#__PURE__*/React.cloneElement(t.component, { isExit: t.isExit, deltaOffsetX: deltaOffsetX, deltaOffsetY: deltaOffsetY, _onEnter: function (event) { return handleToastEnter(t, event); } })); })); } var toastComponentList = []; var init = function () { var toastContainer = isBrowser() && document.getElementById('#toast__container'); if (isBrowser() && !toastContainer) { addRootElement(createElement('#toast__container')); } if (!toastComponentList || !Array.isArray(toastComponentList)) { toastComponentList = []; } }; // eslint-disable-next-line @typescript-eslint/no-empty-function var noop = function () {}; var defaultOptions = { duration: 3000, className: '', position: 'bottom-center', offsetX: 30, offsetY: 30, gap: 10, clickClosable: false, render: null, maxVisibleToasts: null, isReversedOrder: false, theme: null, loadingText: 'loading', zIndex: 1000, clickable: false, onClick: noop, onClose: noop, onCloseStart: noop, loading: false }; var isValidPosition = function (position) { var positionList = Object.values(ToastPosition); if (!positionList.includes(position)) { throw new Error("Invalid position value. Expected one of ".concat(positionList.join(', '), " but got ").concat(position)); } return true; }; var validateOptions = function (options) { options.position && isValidPosition(options.position); }; var toastConfig = function (options) { if (!isBrowser()) return; validateOptions(options); Object.assign(defaultOptions, options); }; var renderDOM = function () { if (!isBrowser()) return; var toastContainer = document.getElementById('#toast__container'); if (!toastContainer) return; render( /*#__PURE__*/React.createElement(ToastContainer, { toastComponentList: toastComponentList, onToastEnter: renderDOM }), toastContainer); }; var clearToasts = function () { toastComponentList.forEach(function (toast) { return toast.isExit = true; }); renderDOM(); }; function closeToast(id) { var index = toastComponentList.findIndex(function (t) { return t.id === id; }); if (toastComponentList[index]) { toastComponentList[index].isExit = true; } renderDOM(); } function renderToast(message, _options) { var dummyReturn = { close: function () { return null; }, updateDuration: function () { return null; }, update: function () { return null; } }; if (!isBrowser()) return dummyReturn; var closeTimer; var id = createId(); var options = __assign(__assign({}, defaultOptions), _options); var _a = options || {}, loading = _a.loading, loadingText = _a.loadingText, onClose = _a.onClose, onCloseStart = _a.onCloseStart, clickClosable = _a.clickClosable, position = _a.position, onClick = _a.onClick, gap = _a.gap, theme = _a.theme, duration = _a.duration, isReversedOrder = _a.isReversedOrder, maxVisibleToasts = _a.maxVisibleToasts; var durationTime = duration === undefined ? defaultOptions.duration : duration; if (!isValidPosition(position)) ; init(); var handleClick = function (e) { if (clickClosable) { if (closeTimer) { clearTimeout(closeTimer); } closeToast(id); } onClick === null || onClick === void 0 ? void 0 : onClick(e); }; var handleClose = function () { toastComponentList = toastComponentList.filter(function (t) { return t.id !== id; }); renderDOM(); onClose === null || onClose === void 0 ? void 0 : onClose(); }; var startCloseTimer = function (duration) { if (duration === void 0) { duration = options.duration; } if (duration === null || duration === 0 || duration > SET_TIMEOUT_MAX) return; if (closeTimer) { clearTimeout(closeTimer); } closeTimer = window.setTimeout(function () { closeToast(id); }, duration); }; var newToastComponent = { id: id, message: message, position: position, startCloseTimer: startCloseTimer, gap: gap, component: /*#__PURE__*/React.createElement(ToastMessage, _extends({}, options, { id: id, message: message, onClick: handleClick, onClose: handleClose, onCloseStart: onCloseStart })) }; if (isReversedOrder) toastComponentList.unshift(newToastComponent);else toastComponentList.push(newToastComponent); if (maxVisibleToasts) { var toastsToRemove = toastComponentList.length - maxVisibleToasts; for (var i = 0; i < toastsToRemove; i++) { closeToast(toastComponentList[i].id); } } renderDOM(); return { close: function () { return closeToast(id); }, updateDuration: function (newDuration) { if (newDuration === void 0) { newDuration = durationTime; } startCloseTimer(newDuration); }, update: function (messageOrOptions, updateDuration) { var _a, _b; var toast = toastComponentList.find(function (t) { return t.id === id && !t.isExit; }); if (toast) { var newDuration = isToastUpdateOptions(messageOrOptions) ? messageOrOptions.duration : updateDuration; var finalMessage = (_a = isToastUpdateOptions(messageOrOptions) ? messageOrOptions.message : messageOrOptions) !== null && _a !== void 0 ? _a : message; var finalLoading = isToastUpdateOptions(messageOrOptions) ? (_b = messageOrOptions.loading) !== null && _b !== void 0 ? _b : loading : false; var finalTheme = isToastUpdateOptions(messageOrOptions) ? messageOrOptions.theme || theme : theme; toast.message = finalMessage; toast.component = /*#__PURE__*/React.createElement(ToastMessage, _extends({}, options, { id: id, message: finalMessage, theme: finalTheme, loading: finalLoading, loadingText: loadingText, onClick: handleClick, onClose: handleClose, onCloseStart: onCloseStart })); renderDOM(); if (newDuration !== undefined) { startCloseTimer(newDuration); } } } }; } function toast(message, durationOrOptions) { var options = typeof durationOrOptions === 'number' || durationOrOptions === null ? { duration: durationOrOptions } : durationOrOptions; return renderToast(message, options); } var createToast = function (options) { return function (message, durationOrOptions) { if (typeof durationOrOptions === 'number') { return renderToast(message, { duration: durationOrOptions || options.duration }); } if (durationOrOptions === undefined || typeof durationOrOptions === 'object') { var mergedOptions = __assign(__assign({}, options), durationOrOptions); return renderToast(message, mergedOptions); } throw new Error('Invalid durationOrOptions type'); }; }; exports.Themes = Themes; exports.clearToasts = clearToasts; exports.createToast = createToast; exports.default = toast; exports.toast = toast; exports.toastConfig = toastConfig; //# sourceMappingURL=index.js.map