react-snackbar-ui-customizable
Version:
snackbar component for react without style
280 lines (265 loc) • 18 kB
JavaScript
import React, { useRef, useEffect, useState, useMemo, createContext, useReducer, useContext } from 'react';
import { v4 } from 'uuid';
import produce from 'immer';
import ReactDOM from 'react-dom';
import styled, { keyframes, css, createGlobalStyle } from 'styled-components';
import { CheckCircleOutlined, ExclamationCircleOutlined, WarningOutlined, InfoCircleOutlined, CloseOutlined } from '@ant-design/icons';
/*! *****************************************************************************
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.
***************************************************************************** */
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);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __makeTemplateObject(cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
}
var ActionType;
(function (ActionType) {
ActionType[ActionType["ADD"] = 0] = "ADD";
ActionType[ActionType["REMOVE"] = 1] = "REMOVE";
})(ActionType || (ActionType = {}));
var initialState = [];
var snackbarContainerReducer = function (state, action) {
switch (action.type) {
case ActionType.ADD:
return produce(state, function (draft) {
draft.push(action.payload.options);
});
case ActionType.REMOVE:
return produce(state, function (draft) {
return draft.filter(function (snackbar) { return snackbar.id !== action.payload.id; });
});
default:
return state;
}
};
var useInterval = function (callback, delay) {
var savedCallback = useRef(callback);
// Remember the latest callback if it changes.
useEffect(function () {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(function () {
// Don't schedule if no delay is specified.
if (delay === null) {
return;
}
var id = setInterval(function () { return savedCallback.current(); }, delay);
return function () { return clearInterval(id); };
}, [delay]);
};
var StyleMapper = {
SUCCESS: {
color: "#ffffff",
backgroundColor: "#37933c",
},
ERROR: {
color: "#ffffff",
backgroundColor: "#c92323",
},
WARN: {
color: "#ffffff",
backgroundColor: "#e78012",
},
INFO: {
color: "#ffffff",
backgroundColor: "#1495db",
},
};
var Snackbar = function (_a) {
var id = _a.id, _b = _a.type, type = _b === void 0 ? "SUCCESS" : _b, title = _a.title, message = _a.message, onClose = _a.onClose, onClickButton = _a.onClickButton, buttonText = _a.buttonText, _c = _a.duration, duration = _c === void 0 ? 3 : _c, _d = _a.position, position = _d === void 0 ? "top-right" : _d, _e = _a.successIcon, successIcon = _e === void 0 ? React.createElement(CheckCircleOutlined, { style: { fontSize: "24px" } }) : _e, _f = _a.errorIcon, errorIcon = _f === void 0 ? React.createElement(ExclamationCircleOutlined, { style: { fontSize: "24px" } }) : _f, _g = _a.warnIcon, warnIcon = _g === void 0 ? React.createElement(WarningOutlined, { style: { fontSize: "24px" } }) : _g, _h = _a.infoIcon, infoIcon = _h === void 0 ? React.createElement(InfoCircleOutlined, { style: { fontSize: "24px" } }) : _h, _j = _a.closeIcon, closeIcon = _j === void 0 ? React.createElement(CloseOutlined, { style: { fontSize: "18px" } }) : _j;
var isInfinite = !duration;
var _k = useState(duration * 1000), remainSeconds = _k[0], setRemainSeconds = _k[1];
var _l = useState(false), show = _l[0], setShow = _l[1];
var _m = useState(false), pause = _m[0], setPause = _m[1];
var _o = position === null || position === void 0 ? void 0 : position.split("-"), verticalDirection = _o[0], horizontalDirection = _o[1];
var onCloseSnackbar = function () { return onClose === null || onClose === void 0 ? void 0 : onClose(id); };
var interval = useMemo(function () { return (!isInfinite && remainSeconds >= 0 ? 100 : null); }, [isInfinite, remainSeconds]);
useInterval(function () {
setRemainSeconds(pause ? remainSeconds : remainSeconds - 100);
if (remainSeconds === 0) {
onCloseSnackbar();
}
}, interval);
var progressWidth = function () {
if (isInfinite)
return 0;
return (remainSeconds / (duration * 1000)) * 100;
};
var customIconMapper = {
SUCCESS: successIcon,
ERROR: errorIcon,
WARN: warnIcon,
INFO: infoIcon,
};
useEffect(function () {
setShow(true);
}, [show]);
console.log("position", horizontalDirection);
return (React.createElement(StyledContainer, { className: "snackbar-container snackbar-container--".concat(type), onMouseEnter: function () { return setPause(true); }, onMouseLeave: function () { return setPause(false); } },
React.createElement(StyledSnackbarBox, { className: "snackbar-box snackbar-box--".concat(type), verticalDirection: verticalDirection, horizontalDirection: horizontalDirection, type: type, show: show },
React.createElement(StyledProgressbar, { className: "snackbar-progressbar snackbar-progressbar--".concat(type), style: { width: "".concat(progressWidth(), "%") }, show: show }),
React.createElement(StyledIcon, null, customIconMapper[type !== null && type !== void 0 ? type : "SUCCESS"]),
React.createElement(StyledClose, { onClick: onCloseSnackbar }, closeIcon),
React.createElement(StyledContents, null,
title && (React.createElement(StyledTitle, { className: "snackbar-title snackbar-title--".concat(type) }, title)),
React.createElement(StyledDescription, { className: "snackbar-description snackbar-description--".concat(type) }, message)),
React.createElement(StyledButton, { type: type, className: "snackbar-action snackbar-action--".concat(type) }, buttonText && React.createElement("button", { onClick: onClickButton }, buttonText)))));
};
var fadeinRightToLeft = keyframes(templateObject_1$1 || (templateObject_1$1 = __makeTemplateObject(["\n from { transform: translateX(100%); opacity: 0 }\n to { transform: translateX(0); opacity: 1 }\n"], ["\n from { transform: translateX(100%); opacity: 0 }\n to { transform: translateX(0); opacity: 1 }\n"])));
var fadeinLeftToRight = keyframes(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n from { transform: translateX(-100%); opacity: 0 }\n to { transform: translateX(0); opacity: 1 }\n"], ["\n from { transform: translateX(-100%); opacity: 0 }\n to { transform: translateX(0); opacity: 1 }\n"])));
var fadeinTopToBottom = keyframes(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n from { transform: translateY(-100%); opacity: 0 }\n to { transform: translateY(0); opacity: 1 }\n"], ["\n from { transform: translateY(-100%); opacity: 0 }\n to { transform: translateY(0); opacity: 1 }\n"])));
var fadeinBottomToTop = keyframes(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n from { transform: translateY(100%); opacity: 0 }\n to { transform: translateY(0); opacity: 1 }\n"], ["\n from { transform: translateY(100%); opacity: 0 }\n to { transform: translateY(0); opacity: 1 }\n"])));
var StyledContainer = styled.div(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n position: relative;\n right: 0;\n margin-bottom: 20px;\n overflow: hidden;\n border-radius: 8px;\n"], ["\n position: relative;\n right: 0;\n margin-bottom: 20px;\n overflow: hidden;\n border-radius: 8px;\n"])));
var StyledProgressbar = styled.span(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n width: 100%;\n height: 8px;\n position: absolute;\n display: block;\n opacity: 0.16;\n background-color: #000000;\n z-index: 1;\n top: 0;\n left: 0;\n transition: width 0.1s linear;\n"], ["\n width: 100%;\n height: 8px;\n position: absolute;\n display: block;\n opacity: 0.16;\n background-color: #000000;\n z-index: 1;\n top: 0;\n left: 0;\n transition: width 0.1s linear;\n"])));
var StyledSnackbarBox = styled.div(templateObject_9 || (templateObject_9 = __makeTemplateObject(["\n position: relative;\n overflow: hidden;\n\n width: 330px;\n padding: 20px 48px 16px 56px;\n background-color: ", ";\n color: ", ";\n border-radius: 8px;\n\n\n ", "}\n"], ["\n position: relative;\n overflow: hidden;\n\n width: 330px;\n padding: 20px 48px 16px 56px;\n background-color: ", ";\n color: ", ";\n border-radius: 8px;\n\n\n ", "}\n"])), function (_a) {
var type = _a.type;
return StyleMapper[type].backgroundColor;
}, function (_a) {
var type = _a.type;
return StyleMapper[type].color;
}, function (_a) {
var show = _a.show, verticalDirection = _a.verticalDirection, horizontalDirection = _a.horizontalDirection;
if (show) {
return css(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n visibility: visible;\n animation: ", " 0.3s;\n "], ["\n visibility: visible;\n animation: ", " 0.3s;\n "])), getAnimation(verticalDirection, horizontalDirection));
}
return css(templateObject_8 || (templateObject_8 = __makeTemplateObject(["\n visibility: hidden;\n "], ["\n visibility: hidden;\n "])));
});
var StyledIcon = styled.span(templateObject_10 || (templateObject_10 = __makeTemplateObject(["\n position: absolute;\n left: 20px;\n top: 16px;\n"], ["\n position: absolute;\n left: 20px;\n top: 16px;\n"])));
var StyledClose = styled.span(templateObject_11 || (templateObject_11 = __makeTemplateObject(["\n position: absolute;\n top: 10px;\n right: 10px;\n cursor: pointer;\n"], ["\n position: absolute;\n top: 10px;\n right: 10px;\n cursor: pointer;\n"])));
var StyledTitle = styled.div(templateObject_12 || (templateObject_12 = __makeTemplateObject(["\n font-weight: bold;\n margin-bottom: 8px;\n font-size: 16px;\n"], ["\n font-weight: bold;\n margin-bottom: 8px;\n font-size: 16px;\n"])));
var StyledDescription = styled.div(templateObject_13 || (templateObject_13 = __makeTemplateObject(["\n line-height: 20px;\n margin-bottom: 4px;\n font-size: 14px;\n word-wrap: break-word;\n"], ["\n line-height: 20px;\n margin-bottom: 4px;\n font-size: 14px;\n word-wrap: break-word;\n"])));
var StyledContents = styled.div(templateObject_14 || (templateObject_14 = __makeTemplateObject([""], [""])));
var StyledButton = styled.div(templateObject_15 || (templateObject_15 = __makeTemplateObject(["\n text-align: right;\n button {\n cursor: pointer;\n margin-right: -30px;\n margin-bottom: -10px;\n padding: 12px 18px;\n color: ", ";\n border: 0;\n background: transparent;\n font-size: 16px;\n font-weight: bold;\n }\n"], ["\n text-align: right;\n button {\n cursor: pointer;\n margin-right: -30px;\n margin-bottom: -10px;\n padding: 12px 18px;\n color: ", ";\n border: 0;\n background: transparent;\n font-size: 16px;\n font-weight: bold;\n }\n"])), function (_a) {
var type = _a.type;
return StyleMapper[type].color;
});
var getAnimation = function (verticalDirecation, horizontalDirection) {
if (horizontalDirection === "center") {
return verticalDirecation === "top" ? fadeinTopToBottom : fadeinBottomToTop;
}
return horizontalDirection === "right"
? fadeinRightToLeft
: fadeinLeftToRight;
};
var templateObject_1$1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15;
var GlobalStyle = createGlobalStyle(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n /* Hide scrollbar for Chrome, Safari and Opera */\n #snackbar-portal::-webkit-scrollbar {\n display: none;\n }\n\n /* Hide scrollbar for IE, Edge and Firefox */\n #snackbar-portal {\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n }\n"], ["\n /* Hide scrollbar for Chrome, Safari and Opera */\n #snackbar-portal::-webkit-scrollbar {\n display: none;\n }\n\n /* Hide scrollbar for IE, Edge and Firefox */\n #snackbar-portal {\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n }\n"])));
var templateObject_1;
var SnackbarPortal = function (_a) {
var id = _a.id, off = _a.off, zIndex = _a.zIndex, position = _a.position, _b = _a.snackbars, snackbars = _b === void 0 ? [] : _b, snackbarGlobalOptions = __rest(_a, ["id", "off", "zIndex", "position", "snackbars"]);
var _position = position !== null && position !== void 0 ? position : "top-right";
var _c = useState(false), loaded = _c[0], setLoaded = _c[1];
var portalId = id ? id.toString() : "snackbar-portal";
var _d = _position.split("-"), verticalPosition = _d[0], horizontalPosition = _d[1];
useEffect(function () {
if (typeof window === "undefined")
return;
// const wrapper = document.createElement("div");
var div = document.createElement("div");
div.setAttribute("role", "log");
div.style.zIndex = zIndex ? zIndex.toString() : "100";
div.id = portalId;
div.style.position = "fixed";
div.style[verticalPosition] = "10px";
// div.style.overflowY = "scroll";
div.style.overflowX = "hidden";
if (verticalPosition === "top") {
div.style.top = "10px";
}
if (verticalPosition === "bottom") {
div.style.bottom = "10px";
div.style.display = "flex";
div.style.justifyContent = "flex-end";
div.style.flexDirection = "column";
}
if (horizontalPosition === "right") {
div.style.right = "10px";
}
if (horizontalPosition === "left") {
div.style.left = "10px";
}
if (horizontalPosition === "center") {
div.style.right = "50%";
div.style.transform = "translate(50%, 0)";
}
// wrapper.appendChild(div);
document.getElementsByTagName("body")[0].prepend(div);
setLoaded(true);
return function () {
document.getElementsByTagName("body")[0].removeChild(div);
};
}, [horizontalPosition, zIndex, portalId, verticalPosition]);
if (!(loaded && snackbars && (snackbars === null || snackbars === void 0 ? void 0 : snackbars.length) > 0)) {
return null;
}
var orderByCreatedAt = snackbars.slice().reverse();
return ReactDOM.createPortal(React.createElement("div", null,
React.createElement(GlobalStyle, null),
orderByCreatedAt.map(function (snackbarLocalOption) { return (React.createElement(Snackbar, __assign({ position: _position, key: snackbarLocalOption.id, onClose: off }, snackbarGlobalOptions, snackbarLocalOption))); })), document.getElementById(portalId));
};
var SnackbarContext = createContext(null);
var SnackbarContextProvider = function (_a) {
var id = _a.id, option = _a.option, children = _a.children;
var _b = useReducer(snackbarContainerReducer, initialState), snackbars = _b[0], dispatch = _b[1];
var off = function (id) {
return dispatch({
type: ActionType.REMOVE,
payload: { id: id },
});
};
return (React.createElement(SnackbarContext.Provider, { value: { id: id, snackbars: snackbars, dispatch: dispatch } },
children,
React.createElement(SnackbarPortal, __assign({}, option, { id: id, snackbars: snackbars, off: off }))));
};
var useSnackbar = function () {
var context = useContext(SnackbarContext);
if (!context)
return null;
return {
on: function (options) {
context.dispatch({
type: ActionType.ADD,
payload: { options: __assign(__assign({}, options), { id: v4() }) },
});
},
off: function (id) {
context.dispatch({
type: ActionType.REMOVE,
payload: { id: id },
});
},
length: context.snackbars.length,
list: context.snackbars,
};
};
export { SnackbarContextProvider, useSnackbar };
//# sourceMappingURL=index.esm.js.map