react-toast
Version:
Minimal toast notifications for React.
393 lines (341 loc) • 11.3 kB
JavaScript
import React, { useReducer, useEffect, useCallback } from 'react';
var Success = function Success() {
return React.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
viewBox: "0 0 16 16"
}, React.createElement("g", {
transform: "translate(.077 .077)"
}, React.createElement("g", null, React.createElement("path", {
fill: "none",
stroke: "#fff",
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: "1.5",
d: "M3.719 7.884L6.235 10.4l3.032-3.032 2.774-2.774"
}))));
};
var Success$1 = /*#__PURE__*/React.memo(Success);
var Close = function Close() {
return React.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
viewBox: "0 0 16 16"
}, React.createElement("g", {
transform: "translate(.077 .077)"
}, React.createElement("g", null, React.createElement("path", {
fill: "#fff",
d: "M10.915 9.98l2.853-2.846a.666.666 0 00-.942-.942L9.979 9.044 7.133 6.191a.666.666 0 00-.942.942L9.044 9.98 6.19 12.826a.666.666 0 10.942.942l2.846-2.853 2.846 2.853a.666.666 0 10.942-.942z",
transform: "translate(-2.017 -2.018)"
}))));
};
var Close$1 = /*#__PURE__*/React.memo(Close);
var Info = function Info() {
return React.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
viewBox: "0 0 16 16"
}, React.createElement("g", {
transform: "translate(-1533 -39)"
}, React.createElement("g", {
fill: "#fff",
transform: "translate(-.358 -1.639)"
}, React.createElement("circle", {
cx: "1.134",
cy: "1.134",
r: "1.134",
transform: "rotate(180 771.246 22.823)"
}), React.createElement("path", {
d: "M1 0a1 1 0 00-1 1v5a1 1 0 002 0V1a1 1 0 00-1-1z",
transform: "rotate(180 771.17 26.882)"
}))));
};
var Info$1 = /*#__PURE__*/React.memo(Info);
var Warning = function Warning() {
return React.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
viewBox: "0 0 16 16"
}, React.createElement("g", {
transform: "rotate(180 774.5 27.5)"
}, React.createElement("g", {
fill: "#fff",
transform: "translate(-.358 -1.639)"
}, React.createElement("circle", {
cx: "1.134",
cy: "1.134",
r: "1.134",
transform: "rotate(180 771.246 22.823)"
}), React.createElement("path", {
d: "M1 0a1 1 0 00-1 1v5a1 1 0 002 0V1a1 1 0 00-1-1z",
transform: "rotate(180 771.17 26.882)"
}))));
};
var Warning$1 = /*#__PURE__*/React.memo(Warning);
var toastIcon = function toastIcon(_ref) {
var type = _ref.type;
switch (type) {
case 'error':
return React.createElement(Close$1, null);
case 'info':
return React.createElement(Info$1, null);
case 'warning':
return React.createElement(Warning$1, null);
default:
return React.createElement(Success$1, null);
}
};
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = ":root {\n --toast-default: #8b1dd0;\n --toast-success: #27d0b2;\n --toast-error: #c52965;\n --toast-info: #004eff;\n --toast-warning: #d0761d;\n --toast-black: #221d26;\n --toast-white: #ffffff;\n}\n\n.toast {\n padding: 15px;\n min-width: 300px;\n max-width: 400px;\n color: var(--toast-white);\n display: flex;\n align-items: flex-start;\n line-height: 1.6;\n font-size: 14px;\n border-radius: 15px;\n}\n\n.toast.default {\n background-color: var(--toast-default);\n}\n\n.toast.success {\n background-color: var(--toast-success);\n}\n\n.toast.error {\n background-color: var(--toast-error);\n}\n\n.toast.info {\n background-color: var(--toast-info);\n}\n\n.toast.warning {\n background-color: var(--toast-warning);\n}\n\n.toast .content {\n flex: 1;\n}\n\n.toast .content p {\n padding: 0;\n margin: 0;\n}\n\n.toast .close {\n margin-left: 10px;\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0);\n transition: all 100ms ease-in-out;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.toast .close:hover {\n background-color: rgba(255, 255, 255, 0.2);\n}\n\n.toast .icon {\n margin-right: 10px;\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n}\n";
styleInject(css_248z);
var Toast = function Toast(_ref) {
var id = _ref.id,
content = _ref.content,
type = _ref.type,
_ref$config = _ref.config;
_ref$config = _ref$config === void 0 ? {} : _ref$config;
var backgroundColor = _ref$config.backgroundColor,
color = _ref$config.color,
onClose = _ref.onClose;
return React.createElement("div", {
className: "toast " + type,
style: {
backgroundColor: backgroundColor
}
}, React.createElement("div", {
className: "icon"
}, toastIcon({
type: type
})), React.createElement("div", {
className: "content"
}, React.createElement("p", {
style: {
color: color
}
}, content)), React.createElement("div", {
className: "close",
onClick: function onClick() {
return onClose(id);
}
}, React.createElement(Close$1, null)));
};
function _extends() {
_extends = Object.assign || 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);
}
var initialState = {
toasts: []
};
var toastReducer = function toastReducer(state, action) {
switch (action.type) {
case 'ADD':
return _extends({}, state, {
toasts: [].concat(state.toasts, [action.toast])
});
case 'REMOVE':
{
return _extends({}, state, {
toasts: [].concat(state.toasts.filter(function (toast) {
return toast.id !== action.id;
}))
});
}
case 'REMOVE_ALL':
return _extends({}, state, {
toasts: []
});
default:
throw new Error();
}
};
var useToast = function useToast() {
var _useReducer = useReducer(toastReducer, initialState),
state = _useReducer[0],
dispatch = _useReducer[1];
return _extends({}, state, {
dispatch: dispatch
});
};
var emitter = /*#__PURE__*/function () {
var events = /*#__PURE__*/new Map();
return {
/**
* Register an event handler for the given event name.
* @param {Events} event Type of event to listen for
* @param {Handler} callback Handler to call in response to given event
*/
on: function on(event, callback) {
if (!events.has(event)) events.set(event, []);
events.get(event).push(callback);
},
/**
* Invoke all handlers for the given event name.
* @param {Events} event The event type to invoke
* @param {Any} args Any value passed to each handler
*/
emit: function emit(event, args) {
if (!events.has(event)) return;
events.get(event).forEach(function (callback) {
return callback(args);
});
},
/** Remove all events. */
off: function off() {
events.clear();
}
};
}();
var toaster = function toaster(_ref) {
var content = _ref.content,
type = _ref.type,
config = _ref.config;
return {
id: Math.random().toString(36).substr(2, 10),
content: content,
type: type,
config: config
};
};
var Events;
(function (Events) {
Events["SHOW"] = "show";
Events["HIDE"] = "hide";
Events["HIDE_ALL"] = "hideAll";
})(Events || (Events = {}));
var toastDispatcher = function toastDispatcher(_ref) {
var dispatch = _ref.dispatch,
delay = _ref.delay;
emitter.on(Events.SHOW, function (toast) {
dispatch({
type: 'ADD',
toast: toast
});
if (delay) setTimeout(function () {
dispatch({
type: 'REMOVE',
id: toast.id
});
}, delay);
});
emitter.on(Events.HIDE, function (id) {
return dispatch({
type: 'REMOVE',
id: id
});
});
emitter.on(Events.HIDE_ALL, function () {
return dispatch({
type: 'REMOVE_ALL'
});
});
};
var css_248z$1 = ".toastContainer {\n overflow: hidden;\n overflow-x: auto;\n display: grid;\n grid-gap: 20px;\n position: fixed;\n user-select: none;\n}\n\n.top-left {\n top: 20px;\n left: 20px;\n}\n\n.top-center {\n top: 20px;\n left: 50%;\n transform: translate(-50%, 0);\n}\n\n.top-right {\n top: 20px;\n right: 20px;\n}\n\n.bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.bottom-center {\n bottom: 20px;\n left: 50%;\n transform: translate(-50%, 0);\n}\n\n.bottom-right {\n bottom: 20px;\n right: 20px;\n}\n";
styleInject(css_248z$1);
var ToastContainer = function ToastContainer(_ref) {
var _ref$position = _ref.position,
position = _ref$position === void 0 ? 'bottom-left' : _ref$position,
delay = _ref.delay;
var _useToast = useToast(),
toasts = _useToast.toasts,
dispatch = _useToast.dispatch;
useEffect(function () {
toastDispatcher({
dispatch: dispatch,
delay: delay
});
return function () {
emitter.off();
};
}, [dispatch, delay]);
var onClose = useCallback(function (id) {
emitter.emit(Events.HIDE, id);
}, []);
return React.createElement("div", {
className: "toastContainer " + position
}, toasts.map(function (toast) {
return React.createElement(Toast, Object.assign({
key: toast.id
}, toast, {
onClose: onClose
}));
}));
};
var applyToast = function applyToast(_ref) {
var toast = _extends({}, _ref);
return emitter.emit(Events.SHOW, toaster(_extends({}, toast)));
};
var toast = function toast(content, config) {
return applyToast({
content: content,
type: 'default',
config: config
});
};
toast.success = function (content, config) {
return applyToast({
content: content,
type: 'success',
config: config
});
};
toast.error = function (content, config) {
return applyToast({
content: content,
type: 'error',
config: config
});
};
toast.info = function (content, config) {
return applyToast({
content: content,
type: 'info',
config: config
});
};
toast.warn = function (content, config) {
return applyToast({
content: content,
type: 'warning',
config: config
});
};
toast.hideAll = function () {
return emitter.emit(Events.HIDE_ALL);
};
export { ToastContainer, toast };
//# sourceMappingURL=react-toast.esm.js.map