mirror of
https://github.com/idanoo/GoScrobble.git
synced 2024-11-22 16:35:14 +00:00
1291 lines
34 KiB
JavaScript
1291 lines
34 KiB
JavaScript
import React__default, { isValidElement, useRef, useLayoutEffect, useEffect, useReducer, cloneElement, useState, createElement } from 'react';
|
|
import cx from 'clsx';
|
|
import { render } from 'react-dom';
|
|
|
|
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);
|
|
}
|
|
|
|
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
if (source == null) return {};
|
|
var target = {};
|
|
var sourceKeys = Object.keys(source);
|
|
var key, i;
|
|
|
|
for (i = 0; i < sourceKeys.length; i++) {
|
|
key = sourceKeys[i];
|
|
if (excluded.indexOf(key) >= 0) continue;
|
|
target[key] = source[key];
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
function isNum(v) {
|
|
return typeof v === 'number' && !isNaN(v);
|
|
}
|
|
function isBool(v) {
|
|
return typeof v === 'boolean';
|
|
}
|
|
function isStr(v) {
|
|
return typeof v === 'string';
|
|
}
|
|
function isFn(v) {
|
|
return typeof v === 'function';
|
|
}
|
|
function parseClassName(v) {
|
|
return isStr(v) || isFn(v) ? v : null;
|
|
}
|
|
function isToastIdValid(toastId) {
|
|
return toastId === 0 || toastId;
|
|
}
|
|
function getAutoCloseDelay(toastAutoClose, containerAutoClose) {
|
|
return toastAutoClose === false || isNum(toastAutoClose) && toastAutoClose > 0 ? toastAutoClose : containerAutoClose;
|
|
}
|
|
var canUseDom = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
|
function canBeRendered(content) {
|
|
return isValidElement(content) || isStr(content) || isFn(content) || isNum(content);
|
|
}
|
|
|
|
var POSITION = {
|
|
TOP_LEFT: 'top-left',
|
|
TOP_RIGHT: 'top-right',
|
|
TOP_CENTER: 'top-center',
|
|
BOTTOM_LEFT: 'bottom-left',
|
|
BOTTOM_RIGHT: 'bottom-right',
|
|
BOTTOM_CENTER: 'bottom-center'
|
|
};
|
|
var TYPE = {
|
|
INFO: 'info',
|
|
SUCCESS: 'success',
|
|
WARNING: 'warning',
|
|
ERROR: 'error',
|
|
DEFAULT: 'default',
|
|
DARK: 'dark'
|
|
};
|
|
|
|
/**
|
|
* Used to collapse toast after exit animation
|
|
*/
|
|
function collapseToast(node, done, duration
|
|
/* COLLAPSE_DURATION */
|
|
) {
|
|
if (duration === void 0) {
|
|
duration = 300;
|
|
}
|
|
|
|
var height = node.scrollHeight;
|
|
var style = node.style;
|
|
requestAnimationFrame(function () {
|
|
style.minHeight = 'initial';
|
|
style.height = height + 'px';
|
|
style.transition = "all " + duration + "ms";
|
|
requestAnimationFrame(function () {
|
|
style.height = '0';
|
|
style.padding = '0';
|
|
style.margin = '0';
|
|
setTimeout(done, duration);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Css animation that just work.
|
|
* You could use animate.css for instance
|
|
*
|
|
*
|
|
* ```
|
|
* cssTransition({
|
|
* enter: "animate__animated animate__bounceIn",
|
|
* exit: "animate__animated animate__bounceOut"
|
|
* })
|
|
* ```
|
|
*
|
|
*/
|
|
|
|
function cssTransition(_ref) {
|
|
var enter = _ref.enter,
|
|
exit = _ref.exit,
|
|
_ref$appendPosition = _ref.appendPosition,
|
|
appendPosition = _ref$appendPosition === void 0 ? false : _ref$appendPosition,
|
|
_ref$collapse = _ref.collapse,
|
|
collapse = _ref$collapse === void 0 ? true : _ref$collapse,
|
|
_ref$collapseDuration = _ref.collapseDuration,
|
|
collapseDuration = _ref$collapseDuration === void 0 ? 300 : _ref$collapseDuration;
|
|
return function ToastTransition(_ref2) {
|
|
var children = _ref2.children,
|
|
position = _ref2.position,
|
|
preventExitTransition = _ref2.preventExitTransition,
|
|
done = _ref2.done,
|
|
nodeRef = _ref2.nodeRef,
|
|
isIn = _ref2.isIn;
|
|
var enterClassName = appendPosition ? enter + "--" + position : enter;
|
|
var exitClassName = appendPosition ? exit + "--" + position : exit;
|
|
var baseClassName = useRef();
|
|
var animationStep = useRef(0
|
|
/* Enter */
|
|
);
|
|
useLayoutEffect(function () {
|
|
onEnter();
|
|
}, []);
|
|
useEffect(function () {
|
|
if (!isIn) preventExitTransition ? onExited() : onExit();
|
|
}, [isIn]);
|
|
|
|
function onEnter() {
|
|
var node = nodeRef.current;
|
|
baseClassName.current = node.className;
|
|
node.className += " " + enterClassName;
|
|
node.addEventListener('animationend', onEntered);
|
|
}
|
|
|
|
function onEntered() {
|
|
var node = nodeRef.current;
|
|
node.removeEventListener('animationend', onEntered);
|
|
|
|
if (animationStep.current === 0
|
|
/* Enter */
|
|
) {
|
|
node.className = baseClassName.current;
|
|
}
|
|
}
|
|
|
|
function onExit() {
|
|
animationStep.current = 1
|
|
/* Exit */
|
|
;
|
|
var node = nodeRef.current;
|
|
node.className += " " + exitClassName;
|
|
node.addEventListener('animationend', onExited);
|
|
}
|
|
|
|
function onExited() {
|
|
var node = nodeRef.current;
|
|
node.removeEventListener('animationend', onExited);
|
|
collapse ? collapseToast(node, done, collapseDuration) : done();
|
|
}
|
|
|
|
return React__default.createElement(React__default.Fragment, null, children);
|
|
};
|
|
}
|
|
|
|
var eventManager = {
|
|
list: /*#__PURE__*/new Map(),
|
|
emitQueue: /*#__PURE__*/new Map(),
|
|
on: function on(event, callback) {
|
|
this.list.has(event) || this.list.set(event, []);
|
|
this.list.get(event).push(callback);
|
|
return this;
|
|
},
|
|
off: function off(event, callback) {
|
|
if (callback) {
|
|
var cb = this.list.get(event).filter(function (cb) {
|
|
return cb !== callback;
|
|
});
|
|
this.list.set(event, cb);
|
|
return this;
|
|
}
|
|
|
|
this.list["delete"](event);
|
|
return this;
|
|
},
|
|
cancelEmit: function cancelEmit(event) {
|
|
var timers = this.emitQueue.get(event);
|
|
|
|
if (timers) {
|
|
timers.forEach(clearTimeout);
|
|
this.emitQueue["delete"](event);
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Enqueue the event at the end of the call stack
|
|
* Doing so let the user call toast as follow:
|
|
* toast('1')
|
|
* toast('2')
|
|
* toast('3')
|
|
* Without setTimemout the code above will not work
|
|
*/
|
|
emit: function emit(event) {
|
|
var _this = this;
|
|
|
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
this.list.has(event) && this.list.get(event).forEach(function (callback) {
|
|
var timer = setTimeout(function () {
|
|
// @ts-ignore
|
|
callback.apply(void 0, args);
|
|
}, 0);
|
|
_this.emitQueue.has(event) || _this.emitQueue.set(event, []);
|
|
|
|
_this.emitQueue.get(event).push(timer);
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* `useKeeper` is a helper around `useRef`.
|
|
*
|
|
* You don't need to access the `.current`property to get the value
|
|
* If refresh is set to true. The ref will be updated every render
|
|
*/
|
|
|
|
function useKeeper(arg, refresh) {
|
|
if (refresh === void 0) {
|
|
refresh = false;
|
|
}
|
|
|
|
var ref = useRef(arg);
|
|
useEffect(function () {
|
|
if (refresh) ref.current = arg;
|
|
});
|
|
return ref.current;
|
|
}
|
|
|
|
function reducer(state, action) {
|
|
switch (action.type) {
|
|
case 0
|
|
/* ADD */
|
|
:
|
|
return [].concat(state, [action.toastId]).filter(function (id) {
|
|
return id !== action.staleId;
|
|
});
|
|
|
|
case 1
|
|
/* REMOVE */
|
|
:
|
|
return isToastIdValid(action.toastId) ? state.filter(function (id) {
|
|
return id !== action.toastId;
|
|
}) : [];
|
|
}
|
|
}
|
|
|
|
function useToastContainer(props) {
|
|
var _useReducer = useReducer(function (x) {
|
|
return x + 1;
|
|
}, 0),
|
|
forceUpdate = _useReducer[1];
|
|
|
|
var _useReducer2 = useReducer(reducer, []),
|
|
toast = _useReducer2[0],
|
|
dispatch = _useReducer2[1];
|
|
|
|
var containerRef = useRef(null);
|
|
var toastCount = useKeeper(0);
|
|
var queue = useKeeper([]);
|
|
var collection = useKeeper({});
|
|
var instance = useKeeper({
|
|
toastKey: 1,
|
|
displayedToast: 0,
|
|
props: props,
|
|
containerId: null,
|
|
isToastActive: isToastActive,
|
|
getToast: function getToast(id) {
|
|
return collection[id] || null;
|
|
}
|
|
});
|
|
useEffect(function () {
|
|
instance.containerId = props.containerId;
|
|
eventManager.cancelEmit(3
|
|
/* WillUnmount */
|
|
).on(0
|
|
/* Show */
|
|
, buildToast).on(1
|
|
/* Clear */
|
|
, function (toastId) {
|
|
return containerRef.current && removeToast(toastId);
|
|
}).on(5
|
|
/* ClearWaitingQueue */
|
|
, clearWaitingQueue).emit(2
|
|
/* DidMount */
|
|
, instance);
|
|
return function () {
|
|
return eventManager.emit(3
|
|
/* WillUnmount */
|
|
, instance);
|
|
};
|
|
}, []);
|
|
useEffect(function () {
|
|
instance.isToastActive = isToastActive;
|
|
instance.displayedToast = toast.length;
|
|
eventManager.emit(4
|
|
/* Change */
|
|
, toast.length, props.containerId);
|
|
}, [toast]);
|
|
useEffect(function () {
|
|
instance.props = props;
|
|
});
|
|
|
|
function isToastActive(id) {
|
|
return toast.indexOf(id) !== -1;
|
|
}
|
|
|
|
function clearWaitingQueue(_ref) {
|
|
var containerId = _ref.containerId;
|
|
var limit = instance.props.limit;
|
|
|
|
if (limit && (!containerId || instance.containerId === containerId)) {
|
|
toastCount -= queue.length;
|
|
queue = [];
|
|
}
|
|
}
|
|
|
|
function removeToast(toastId) {
|
|
dispatch({
|
|
type: 1
|
|
/* REMOVE */
|
|
,
|
|
toastId: toastId
|
|
});
|
|
}
|
|
|
|
function dequeueToast() {
|
|
var _queue$shift = queue.shift(),
|
|
toastContent = _queue$shift.toastContent,
|
|
toastProps = _queue$shift.toastProps,
|
|
staleId = _queue$shift.staleId;
|
|
|
|
appendToast(toastContent, toastProps, staleId);
|
|
}
|
|
/**
|
|
* check if a container is attached to the dom
|
|
* check for multi-container, build only if associated
|
|
* check for duplicate toastId if no update
|
|
*/
|
|
|
|
|
|
function isNotValid(_ref2) {
|
|
var containerId = _ref2.containerId,
|
|
toastId = _ref2.toastId,
|
|
updateId = _ref2.updateId;
|
|
return !containerRef.current || instance.props.enableMultiContainer && containerId !== instance.props.containerId || collection[toastId] && updateId == null ? true : false;
|
|
} // this function and all the function called inside needs to rely on ref(`useKeeper`)
|
|
|
|
|
|
function buildToast(content, _ref3) {
|
|
var delay = _ref3.delay,
|
|
staleId = _ref3.staleId,
|
|
options = _objectWithoutPropertiesLoose(_ref3, ["delay", "staleId"]);
|
|
|
|
if (!canBeRendered(content) || isNotValid(options)) return;
|
|
var toastId = options.toastId,
|
|
updateId = options.updateId;
|
|
var props = instance.props;
|
|
|
|
var closeToast = function closeToast() {
|
|
return removeToast(toastId);
|
|
};
|
|
|
|
var isNotAnUpdate = options.updateId == null;
|
|
if (isNotAnUpdate) toastCount++;
|
|
var toastProps = {
|
|
toastId: toastId,
|
|
updateId: updateId,
|
|
isIn: false,
|
|
key: options.key || instance.toastKey++,
|
|
type: options.type,
|
|
closeToast: closeToast,
|
|
closeButton: options.closeButton,
|
|
rtl: props.rtl,
|
|
position: options.position || props.position,
|
|
transition: options.transition || props.transition,
|
|
className: parseClassName(options.className || props.toastClassName),
|
|
bodyClassName: parseClassName(options.bodyClassName || props.bodyClassName),
|
|
style: options.style || props.toastStyle,
|
|
bodyStyle: options.bodyStyle || props.bodyStyle,
|
|
onClick: options.onClick || props.onClick,
|
|
pauseOnHover: isBool(options.pauseOnHover) ? options.pauseOnHover : props.pauseOnHover,
|
|
pauseOnFocusLoss: isBool(options.pauseOnFocusLoss) ? options.pauseOnFocusLoss : props.pauseOnFocusLoss,
|
|
draggable: isBool(options.draggable) ? options.draggable : props.draggable,
|
|
draggablePercent: isNum(options.draggablePercent) ? options.draggablePercent : props.draggablePercent,
|
|
draggableDirection: options.draggableDirection || props.draggableDirection,
|
|
closeOnClick: isBool(options.closeOnClick) ? options.closeOnClick : props.closeOnClick,
|
|
progressClassName: parseClassName(options.progressClassName || props.progressClassName),
|
|
progressStyle: options.progressStyle || props.progressStyle,
|
|
autoClose: getAutoCloseDelay(options.autoClose, props.autoClose),
|
|
hideProgressBar: isBool(options.hideProgressBar) ? options.hideProgressBar : props.hideProgressBar,
|
|
progress: options.progress,
|
|
role: isStr(options.role) ? options.role : props.role,
|
|
deleteToast: function deleteToast() {
|
|
removeFromCollection(toastId);
|
|
}
|
|
};
|
|
if (isFn(options.onOpen)) toastProps.onOpen = options.onOpen;
|
|
if (isFn(options.onClose)) toastProps.onClose = options.onClose; // tweak for vertical dragging
|
|
|
|
if (toastProps.draggableDirection === "y"
|
|
/* Y */
|
|
&& toastProps.draggablePercent === 80
|
|
/* DRAGGABLE_PERCENT */
|
|
) {
|
|
toastProps.draggablePercent *= 1.5;
|
|
}
|
|
|
|
var closeButton = props.closeButton;
|
|
|
|
if (options.closeButton === false || canBeRendered(options.closeButton)) {
|
|
closeButton = options.closeButton;
|
|
} else if (options.closeButton === true) {
|
|
closeButton = canBeRendered(props.closeButton) ? props.closeButton : true;
|
|
}
|
|
|
|
toastProps.closeButton = closeButton;
|
|
var toastContent = content;
|
|
|
|
if (isValidElement(content) && !isStr(content.type)) {
|
|
toastContent = cloneElement(content, {
|
|
closeToast: closeToast,
|
|
toastProps: toastProps
|
|
});
|
|
} else if (isFn(content)) {
|
|
toastContent = content({
|
|
closeToast: closeToast,
|
|
toastProps: toastProps
|
|
});
|
|
} // not handling limit + delay by design. Waiting for user feedback first
|
|
|
|
|
|
if (props.limit && props.limit > 0 && toastCount > props.limit && isNotAnUpdate) {
|
|
queue.push({
|
|
toastContent: toastContent,
|
|
toastProps: toastProps,
|
|
staleId: staleId
|
|
});
|
|
} else if (isNum(delay) && delay > 0) {
|
|
setTimeout(function () {
|
|
appendToast(toastContent, toastProps, staleId);
|
|
}, delay);
|
|
} else {
|
|
appendToast(toastContent, toastProps, staleId);
|
|
}
|
|
}
|
|
|
|
function appendToast(content, toastProps, staleId) {
|
|
var toastId = toastProps.toastId;
|
|
if (staleId) delete collection[staleId];
|
|
collection[toastId] = {
|
|
content: content,
|
|
props: toastProps
|
|
};
|
|
dispatch({
|
|
type: 0
|
|
/* ADD */
|
|
,
|
|
toastId: toastId,
|
|
staleId: staleId
|
|
});
|
|
}
|
|
|
|
function removeFromCollection(toastId) {
|
|
delete collection[toastId];
|
|
var queueLen = queue.length;
|
|
toastCount = isToastIdValid(toastId) ? toastCount - 1 : toastCount - instance.displayedToast;
|
|
if (toastCount < 0) toastCount = 0;
|
|
|
|
if (queueLen > 0) {
|
|
var freeSlot = isToastIdValid(toastId) ? 1 : instance.props.limit;
|
|
|
|
if (queueLen === 1 || freeSlot === 1) {
|
|
instance.displayedToast++;
|
|
dequeueToast();
|
|
} else {
|
|
var toDequeue = freeSlot > queueLen ? queueLen : freeSlot;
|
|
instance.displayedToast = toDequeue;
|
|
|
|
for (var i = 0; i < toDequeue; i++) {
|
|
dequeueToast();
|
|
}
|
|
}
|
|
} else {
|
|
forceUpdate();
|
|
}
|
|
}
|
|
|
|
function getToastToRender(cb) {
|
|
var toastToRender = {};
|
|
var toastList = props.newestOnTop ? Object.keys(collection).reverse() : Object.keys(collection);
|
|
|
|
for (var i = 0; i < toastList.length; i++) {
|
|
var _toast = collection[toastList[i]];
|
|
var position = _toast.props.position;
|
|
toastToRender[position] || (toastToRender[position] = []);
|
|
toastToRender[position].push(_toast);
|
|
}
|
|
|
|
return Object.keys(toastToRender).map(function (p) {
|
|
return cb(p, toastToRender[p]);
|
|
});
|
|
}
|
|
|
|
return {
|
|
getToastToRender: getToastToRender,
|
|
collection: collection,
|
|
containerRef: containerRef,
|
|
isToastActive: isToastActive
|
|
};
|
|
}
|
|
|
|
function getX(e) {
|
|
return e.targetTouches && e.targetTouches.length >= 1 ? e.targetTouches[0].clientX : e.clientX;
|
|
}
|
|
|
|
function getY(e) {
|
|
return e.targetTouches && e.targetTouches.length >= 1 ? e.targetTouches[0].clientY : e.clientY;
|
|
}
|
|
|
|
function useToast(props) {
|
|
var _useState = useState(true),
|
|
isRunning = _useState[0],
|
|
setIsRunning = _useState[1];
|
|
|
|
var _useState2 = useState(false),
|
|
preventExitTransition = _useState2[0],
|
|
setPreventExitTransition = _useState2[1];
|
|
|
|
var toastRef = useRef(null);
|
|
var drag = useKeeper({
|
|
start: 0,
|
|
x: 0,
|
|
y: 0,
|
|
delta: 0,
|
|
removalDistance: 0,
|
|
canCloseOnClick: true,
|
|
canDrag: false,
|
|
boundingRect: null
|
|
});
|
|
var syncProps = useKeeper(props, true);
|
|
var autoClose = props.autoClose,
|
|
pauseOnHover = props.pauseOnHover,
|
|
closeToast = props.closeToast,
|
|
onClick = props.onClick,
|
|
closeOnClick = props.closeOnClick;
|
|
useEffect(function () {
|
|
if (isFn(props.onOpen)) props.onOpen(isValidElement(props.children) && props.children.props);
|
|
return function () {
|
|
if (isFn(syncProps.onClose)) syncProps.onClose(isValidElement(syncProps.children) && syncProps.children.props);
|
|
};
|
|
}, []);
|
|
useEffect(function () {
|
|
props.draggable && bindDragEvents();
|
|
return function () {
|
|
props.draggable && unbindDragEvents();
|
|
};
|
|
}, [props.draggable]);
|
|
useEffect(function () {
|
|
props.pauseOnFocusLoss && bindFocusEvents();
|
|
return function () {
|
|
props.pauseOnFocusLoss && unbindFocusEvents();
|
|
};
|
|
}, [props.pauseOnFocusLoss]);
|
|
|
|
function onDragStart(e) {
|
|
if (props.draggable) {
|
|
var toast = toastRef.current;
|
|
drag.canCloseOnClick = true;
|
|
drag.canDrag = true;
|
|
drag.boundingRect = toast.getBoundingClientRect();
|
|
toast.style.transition = '';
|
|
drag.x = getX(e.nativeEvent);
|
|
drag.y = getY(e.nativeEvent);
|
|
|
|
if (props.draggableDirection === "x"
|
|
/* X */
|
|
) {
|
|
drag.start = drag.x;
|
|
drag.removalDistance = toast.offsetWidth * (props.draggablePercent / 100);
|
|
} else {
|
|
drag.start = drag.y;
|
|
drag.removalDistance = toast.offsetHeight * (props.draggablePercent / 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
function onDragTransitionEnd() {
|
|
if (drag.boundingRect) {
|
|
var _drag$boundingRect = drag.boundingRect,
|
|
top = _drag$boundingRect.top,
|
|
bottom = _drag$boundingRect.bottom,
|
|
left = _drag$boundingRect.left,
|
|
right = _drag$boundingRect.right;
|
|
|
|
if (props.pauseOnHover && drag.x >= left && drag.x <= right && drag.y >= top && drag.y <= bottom) {
|
|
pauseToast();
|
|
} else {
|
|
playToast();
|
|
}
|
|
}
|
|
}
|
|
|
|
function playToast() {
|
|
setIsRunning(true);
|
|
}
|
|
|
|
function pauseToast() {
|
|
setIsRunning(false);
|
|
}
|
|
|
|
function bindFocusEvents() {
|
|
if (!document.hasFocus()) pauseToast();
|
|
window.addEventListener('focus', playToast);
|
|
window.addEventListener('blur', pauseToast);
|
|
}
|
|
|
|
function unbindFocusEvents() {
|
|
window.removeEventListener('focus', playToast);
|
|
window.removeEventListener('blur', pauseToast);
|
|
}
|
|
|
|
function bindDragEvents() {
|
|
document.addEventListener('mousemove', onDragMove);
|
|
document.addEventListener('mouseup', onDragEnd);
|
|
document.addEventListener('touchmove', onDragMove);
|
|
document.addEventListener('touchend', onDragEnd);
|
|
}
|
|
|
|
function unbindDragEvents() {
|
|
document.removeEventListener('mousemove', onDragMove);
|
|
document.removeEventListener('mouseup', onDragEnd);
|
|
document.removeEventListener('touchmove', onDragMove);
|
|
document.removeEventListener('touchend', onDragEnd);
|
|
}
|
|
|
|
function onDragMove(e) {
|
|
if (drag.canDrag) {
|
|
e.preventDefault();
|
|
var toast = toastRef.current;
|
|
if (isRunning) pauseToast();
|
|
drag.x = getX(e);
|
|
drag.y = getY(e);
|
|
|
|
if (props.draggableDirection === "x"
|
|
/* X */
|
|
) {
|
|
drag.delta = drag.x - drag.start;
|
|
} else {
|
|
drag.delta = drag.y - drag.start;
|
|
} // prevent false positif during a toast click
|
|
|
|
|
|
if (drag.start !== drag.x) drag.canCloseOnClick = false;
|
|
toast.style.transform = "translate" + props.draggableDirection + "(" + drag.delta + "px)";
|
|
toast.style.opacity = "" + (1 - Math.abs(drag.delta / drag.removalDistance));
|
|
}
|
|
}
|
|
|
|
function onDragEnd() {
|
|
var toast = toastRef.current;
|
|
|
|
if (drag.canDrag) {
|
|
drag.canDrag = false;
|
|
|
|
if (Math.abs(drag.delta) > drag.removalDistance) {
|
|
setPreventExitTransition(true);
|
|
props.closeToast();
|
|
return;
|
|
}
|
|
|
|
toast.style.transition = 'transform 0.2s, opacity 0.2s';
|
|
toast.style.transform = "translate" + props.draggableDirection + "(0)";
|
|
toast.style.opacity = '1';
|
|
}
|
|
}
|
|
|
|
var eventHandlers = {
|
|
onMouseDown: onDragStart,
|
|
onTouchStart: onDragStart,
|
|
onMouseUp: onDragTransitionEnd,
|
|
onTouchEnd: onDragTransitionEnd
|
|
};
|
|
|
|
if (autoClose && pauseOnHover) {
|
|
eventHandlers.onMouseEnter = pauseToast;
|
|
eventHandlers.onMouseLeave = playToast;
|
|
} // prevent toast from closing when user drags the toast
|
|
|
|
|
|
if (closeOnClick) {
|
|
eventHandlers.onClick = function (e) {
|
|
onClick && onClick(e);
|
|
drag.canCloseOnClick && closeToast();
|
|
};
|
|
}
|
|
|
|
return {
|
|
playToast: playToast,
|
|
pauseToast: pauseToast,
|
|
isRunning: isRunning,
|
|
preventExitTransition: preventExitTransition,
|
|
toastRef: toastRef,
|
|
eventHandlers: eventHandlers
|
|
};
|
|
}
|
|
|
|
function CloseButton(_ref) {
|
|
var closeToast = _ref.closeToast,
|
|
type = _ref.type,
|
|
_ref$ariaLabel = _ref.ariaLabel,
|
|
ariaLabel = _ref$ariaLabel === void 0 ? 'close' : _ref$ariaLabel;
|
|
return createElement("button", {
|
|
className: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__close-button " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__close-button--" + type,
|
|
type: "button",
|
|
onClick: function onClick(e) {
|
|
e.stopPropagation();
|
|
closeToast(e);
|
|
},
|
|
"aria-label": ariaLabel
|
|
}, createElement("svg", {
|
|
"aria-hidden": "true",
|
|
viewBox: "0 0 14 16"
|
|
}, createElement("path", {
|
|
fillRule: "evenodd",
|
|
d: "M7.71 8.23l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75L1 11.98l3.75-3.75L1 4.48 2.48 3l3.75 3.75L9.98 3l1.48 1.48-3.75 3.75z"
|
|
})));
|
|
}
|
|
|
|
function ProgressBar(_ref) {
|
|
var _cx, _animationEvent;
|
|
|
|
var delay = _ref.delay,
|
|
isRunning = _ref.isRunning,
|
|
closeToast = _ref.closeToast,
|
|
type = _ref.type,
|
|
hide = _ref.hide,
|
|
className = _ref.className,
|
|
userStyle = _ref.style,
|
|
controlledProgress = _ref.controlledProgress,
|
|
progress = _ref.progress,
|
|
rtl = _ref.rtl,
|
|
isIn = _ref.isIn;
|
|
|
|
var style = _extends({}, userStyle, {
|
|
animationDuration: delay + "ms",
|
|
animationPlayState: isRunning ? 'running' : 'paused',
|
|
opacity: hide ? 0 : 1
|
|
});
|
|
|
|
if (controlledProgress) style.transform = "scaleX(" + progress + ")";
|
|
var defaultClassName = cx("Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__progress-bar", controlledProgress ? "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__progress-bar--controlled" : "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__progress-bar--animated", "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__progress-bar--" + type, (_cx = {}, _cx["Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__progress-bar--rtl"] = rtl, _cx));
|
|
var classNames = isFn(className) ? className({
|
|
rtl: rtl,
|
|
type: type,
|
|
defaultClassName: defaultClassName
|
|
}) : cx(defaultClassName, className); // 🧐 controlledProgress is derived from progress
|
|
// so if controlledProgress is set
|
|
// it means that this is also the case for progress
|
|
|
|
var animationEvent = (_animationEvent = {}, _animationEvent[controlledProgress && progress >= 1 ? 'onTransitionEnd' : 'onAnimationEnd'] = controlledProgress && progress < 1 ? null : function () {
|
|
isIn && closeToast();
|
|
}, _animationEvent); // TODO: add aria-valuenow, aria-valuemax, aria-valuemin
|
|
|
|
return createElement("div", Object.assign({
|
|
role: "progressbar",
|
|
"aria-hidden": hide ? 'true' : 'false',
|
|
"aria-label": "notification timer",
|
|
className: classNames,
|
|
style: style
|
|
}, animationEvent));
|
|
}
|
|
ProgressBar.defaultProps = {
|
|
type: TYPE.DEFAULT,
|
|
hide: false
|
|
};
|
|
|
|
var Toast = function Toast(props) {
|
|
var _cx;
|
|
|
|
var _useToast = useToast(props),
|
|
isRunning = _useToast.isRunning,
|
|
preventExitTransition = _useToast.preventExitTransition,
|
|
toastRef = _useToast.toastRef,
|
|
eventHandlers = _useToast.eventHandlers;
|
|
|
|
var closeButton = props.closeButton,
|
|
children = props.children,
|
|
autoClose = props.autoClose,
|
|
onClick = props.onClick,
|
|
type = props.type,
|
|
hideProgressBar = props.hideProgressBar,
|
|
closeToast = props.closeToast,
|
|
Transition = props.transition,
|
|
position = props.position,
|
|
className = props.className,
|
|
style = props.style,
|
|
bodyClassName = props.bodyClassName,
|
|
bodyStyle = props.bodyStyle,
|
|
progressClassName = props.progressClassName,
|
|
progressStyle = props.progressStyle,
|
|
updateId = props.updateId,
|
|
role = props.role,
|
|
progress = props.progress,
|
|
rtl = props.rtl,
|
|
toastId = props.toastId,
|
|
deleteToast = props.deleteToast,
|
|
isIn = props.isIn;
|
|
var defaultClassName = cx("Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast", "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast--" + type, (_cx = {}, _cx["Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast--rtl"] = rtl, _cx));
|
|
var cssClasses = isFn(className) ? className({
|
|
rtl: rtl,
|
|
position: position,
|
|
type: type,
|
|
defaultClassName: defaultClassName
|
|
}) : cx(defaultClassName, className);
|
|
var isProgressControlled = !!progress;
|
|
|
|
function renderCloseButton(closeButton) {
|
|
if (!closeButton) return;
|
|
var props = {
|
|
closeToast: closeToast,
|
|
type: type
|
|
};
|
|
if (isFn(closeButton)) return closeButton(props);
|
|
if (isValidElement(closeButton)) return cloneElement(closeButton, props);
|
|
}
|
|
|
|
return createElement(Transition, {
|
|
isIn: isIn,
|
|
done: deleteToast,
|
|
position: position,
|
|
preventExitTransition: preventExitTransition,
|
|
nodeRef: toastRef
|
|
}, createElement("div", Object.assign({
|
|
id: toastId,
|
|
onClick: onClick,
|
|
className: cssClasses
|
|
}, eventHandlers, {
|
|
style: style,
|
|
ref: toastRef
|
|
}), createElement("div", Object.assign({}, isIn && {
|
|
role: role
|
|
}, {
|
|
className: isFn(bodyClassName) ? bodyClassName({
|
|
type: type
|
|
}) : cx("Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast-body", bodyClassName),
|
|
style: bodyStyle
|
|
}), children), renderCloseButton(closeButton), (autoClose || isProgressControlled) && createElement(ProgressBar, Object.assign({}, updateId && !isProgressControlled ? {
|
|
key: "pb-" + updateId
|
|
} : {}, {
|
|
rtl: rtl,
|
|
delay: autoClose,
|
|
isRunning: isRunning,
|
|
isIn: isIn,
|
|
closeToast: closeToast,
|
|
hide: hideProgressBar,
|
|
type: type,
|
|
style: progressStyle,
|
|
className: progressClassName,
|
|
controlledProgress: isProgressControlled,
|
|
progress: progress
|
|
}))));
|
|
};
|
|
|
|
var Bounce = /*#__PURE__*/cssTransition({
|
|
enter: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__bounce-enter",
|
|
exit: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__bounce-exit",
|
|
appendPosition: true
|
|
});
|
|
var Slide = /*#__PURE__*/cssTransition({
|
|
enter: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__slide-enter",
|
|
exit: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__slide-exit",
|
|
appendPosition: true
|
|
});
|
|
var Zoom = /*#__PURE__*/cssTransition({
|
|
enter: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__zoom-enter",
|
|
exit: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__zoom-exit"
|
|
});
|
|
var Flip = /*#__PURE__*/cssTransition({
|
|
enter: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__flip-enter",
|
|
exit: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "--animate " + "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__flip-exit"
|
|
});
|
|
|
|
var ToastContainer = function ToastContainer(props) {
|
|
var _useToastContainer = useToastContainer(props),
|
|
getToastToRender = _useToastContainer.getToastToRender,
|
|
containerRef = _useToastContainer.containerRef,
|
|
isToastActive = _useToastContainer.isToastActive;
|
|
|
|
var className = props.className,
|
|
style = props.style,
|
|
rtl = props.rtl,
|
|
containerId = props.containerId;
|
|
|
|
function getClassName(position) {
|
|
var _cx;
|
|
|
|
var defaultClassName = cx("Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast-container", "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast-container--" + position, (_cx = {}, _cx["Toastify"
|
|
/* CSS_NAMESPACE */
|
|
+ "__toast-container--rtl"] = rtl, _cx));
|
|
return isFn(className) ? className({
|
|
position: position,
|
|
rtl: rtl,
|
|
defaultClassName: defaultClassName
|
|
}) : cx(defaultClassName, parseClassName(className));
|
|
}
|
|
|
|
return createElement("div", {
|
|
ref: containerRef,
|
|
className: "Toastify"
|
|
/* CSS_NAMESPACE */
|
|
,
|
|
id: containerId
|
|
}, getToastToRender(function (position, toastList) {
|
|
var containerStyle = toastList.length === 0 ? _extends({}, style, {
|
|
pointerEvents: 'none'
|
|
}) : _extends({}, style);
|
|
return createElement("div", {
|
|
className: getClassName(position),
|
|
style: containerStyle,
|
|
key: "container-" + position
|
|
}, toastList.map(function (_ref) {
|
|
var content = _ref.content,
|
|
toastProps = _ref.props;
|
|
return createElement(Toast, Object.assign({}, toastProps, {
|
|
isIn: isToastActive(toastProps.toastId),
|
|
key: "toast-" + toastProps.key,
|
|
closeButton: toastProps.closeButton === true ? CloseButton : toastProps.closeButton
|
|
}), content);
|
|
}));
|
|
}));
|
|
};
|
|
ToastContainer.defaultProps = {
|
|
position: POSITION.TOP_RIGHT,
|
|
transition: Bounce,
|
|
rtl: false,
|
|
autoClose: 5000,
|
|
hideProgressBar: false,
|
|
closeButton: CloseButton,
|
|
pauseOnHover: true,
|
|
pauseOnFocusLoss: true,
|
|
closeOnClick: true,
|
|
newestOnTop: false,
|
|
draggable: true,
|
|
draggablePercent: 80
|
|
/* DRAGGABLE_PERCENT */
|
|
,
|
|
draggableDirection: "x"
|
|
/* X */
|
|
,
|
|
role: 'alert'
|
|
};
|
|
|
|
var containers = /*#__PURE__*/new Map();
|
|
var latestInstance;
|
|
var containerDomNode;
|
|
var containerConfig;
|
|
var queue = [];
|
|
var lazy = false;
|
|
/**
|
|
* Check whether any container is currently mounted in the DOM
|
|
*/
|
|
|
|
function isAnyContainerMounted() {
|
|
return containers.size > 0;
|
|
}
|
|
/**
|
|
* Get the toast by id, given it's in the DOM, otherwise returns null
|
|
*/
|
|
|
|
|
|
function getToast(toastId, _ref) {
|
|
var containerId = _ref.containerId;
|
|
var container = containers.get(containerId || latestInstance);
|
|
if (!container) return null;
|
|
return container.getToast(toastId);
|
|
}
|
|
/**
|
|
* Generate a random toastId
|
|
*/
|
|
|
|
|
|
function generateToastId() {
|
|
return Math.random().toString(36).substr(2, 9);
|
|
}
|
|
/**
|
|
* Generate a toastId or use the one provided
|
|
*/
|
|
|
|
|
|
function getToastId(options) {
|
|
if (options && (isStr(options.toastId) || isNum(options.toastId))) {
|
|
return options.toastId;
|
|
}
|
|
|
|
return generateToastId();
|
|
}
|
|
/**
|
|
* If the container is not mounted, the toast is enqueued and
|
|
* the container lazy mounted
|
|
*/
|
|
|
|
|
|
function dispatchToast(content, options) {
|
|
if (isAnyContainerMounted()) {
|
|
eventManager.emit(0
|
|
/* Show */
|
|
, content, options);
|
|
} else {
|
|
queue.push({
|
|
content: content,
|
|
options: options
|
|
});
|
|
|
|
if (lazy && canUseDom) {
|
|
lazy = false;
|
|
containerDomNode = document.createElement('div');
|
|
document.body.appendChild(containerDomNode);
|
|
render(createElement(ToastContainer, Object.assign({}, containerConfig)), containerDomNode);
|
|
}
|
|
}
|
|
|
|
return options.toastId;
|
|
}
|
|
/**
|
|
* Merge provided options with the defaults settings and generate the toastId
|
|
*/
|
|
|
|
|
|
function mergeOptions(type, options) {
|
|
return _extends({}, options, {
|
|
type: options && options.type || type,
|
|
toastId: getToastId(options)
|
|
});
|
|
}
|
|
|
|
var createToastByType = function createToastByType(type) {
|
|
return function (content, options) {
|
|
return dispatchToast(content, mergeOptions(type, options));
|
|
};
|
|
};
|
|
|
|
var toast = function toast(content, options) {
|
|
return dispatchToast(content, mergeOptions(TYPE.DEFAULT, options));
|
|
};
|
|
|
|
toast.success = /*#__PURE__*/createToastByType(TYPE.SUCCESS);
|
|
toast.info = /*#__PURE__*/createToastByType(TYPE.INFO);
|
|
toast.error = /*#__PURE__*/createToastByType(TYPE.ERROR);
|
|
toast.warning = /*#__PURE__*/createToastByType(TYPE.WARNING);
|
|
toast.dark = /*#__PURE__*/createToastByType(TYPE.DARK);
|
|
toast.warn = toast.warning;
|
|
/**
|
|
* Remove toast programmaticaly
|
|
*/
|
|
|
|
toast.dismiss = function (id) {
|
|
return eventManager.emit(1
|
|
/* Clear */
|
|
, id);
|
|
};
|
|
/**
|
|
* Clear waiting queue when limit is used
|
|
*/
|
|
|
|
|
|
toast.clearWaitingQueue = function (params) {
|
|
if (params === void 0) {
|
|
params = {};
|
|
}
|
|
|
|
return eventManager.emit(5
|
|
/* ClearWaitingQueue */
|
|
, params);
|
|
};
|
|
/**
|
|
* return true if one container is displaying the toast
|
|
*/
|
|
|
|
|
|
toast.isActive = function (id) {
|
|
var isToastActive = false;
|
|
containers.forEach(function (container) {
|
|
if (container.isToastActive && container.isToastActive(id)) {
|
|
isToastActive = true;
|
|
}
|
|
});
|
|
return isToastActive;
|
|
};
|
|
|
|
toast.update = function (toastId, options) {
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
|
|
// if you call toast and toast.update directly nothing will be displayed
|
|
// this is why I defered the update
|
|
setTimeout(function () {
|
|
var toast = getToast(toastId, options);
|
|
|
|
if (toast) {
|
|
var oldOptions = toast.props,
|
|
oldContent = toast.content;
|
|
|
|
var nextOptions = _extends({}, oldOptions, options, {
|
|
toastId: options.toastId || toastId,
|
|
updateId: generateToastId()
|
|
});
|
|
|
|
if (nextOptions.toastId !== toastId) nextOptions.staleId = toastId;
|
|
var content = nextOptions.render || oldContent;
|
|
delete nextOptions.render;
|
|
dispatchToast(content, nextOptions);
|
|
}
|
|
}, 0);
|
|
};
|
|
/**
|
|
* Used for controlled progress bar.
|
|
*/
|
|
|
|
|
|
toast.done = function (id) {
|
|
toast.update(id, {
|
|
progress: 1
|
|
});
|
|
};
|
|
/**
|
|
* Track changes. The callback get the number of toast displayed
|
|
*
|
|
*/
|
|
|
|
|
|
toast.onChange = function (callback) {
|
|
if (isFn(callback)) {
|
|
eventManager.on(4
|
|
/* Change */
|
|
, callback);
|
|
}
|
|
|
|
return function () {
|
|
isFn(callback) && eventManager.off(4
|
|
/* Change */
|
|
, callback);
|
|
};
|
|
};
|
|
/**
|
|
* Configure the ToastContainer when lazy mounted
|
|
*/
|
|
|
|
|
|
toast.configure = function (config) {
|
|
if (config === void 0) {
|
|
config = {};
|
|
}
|
|
|
|
lazy = true;
|
|
containerConfig = config;
|
|
};
|
|
|
|
toast.POSITION = POSITION;
|
|
toast.TYPE = TYPE;
|
|
/**
|
|
* Wait until the ToastContainer is mounted to dispatch the toast
|
|
* and attach isActive method
|
|
*/
|
|
|
|
eventManager.on(2
|
|
/* DidMount */
|
|
, function (containerInstance) {
|
|
latestInstance = containerInstance.containerId || containerInstance;
|
|
containers.set(latestInstance, containerInstance);
|
|
queue.forEach(function (item) {
|
|
eventManager.emit(0
|
|
/* Show */
|
|
, item.content, item.options);
|
|
});
|
|
queue = [];
|
|
}).on(3
|
|
/* WillUnmount */
|
|
, function (containerInstance) {
|
|
containers["delete"](containerInstance.containerId || containerInstance);
|
|
|
|
if (containers.size === 0) {
|
|
eventManager.off(0
|
|
/* Show */
|
|
).off(1
|
|
/* Clear */
|
|
).off(5
|
|
/* ClearWaitingQueue */
|
|
);
|
|
}
|
|
|
|
if (canUseDom && containerDomNode) {
|
|
document.body.removeChild(containerDomNode);
|
|
}
|
|
});
|
|
|
|
export { Bounce, Flip, Slide, ToastContainer, Zoom, collapseToast, cssTransition, toast, useToast, useToastContainer };
|
|
//# sourceMappingURL=react-toastify.esm.js.map
|