@wix/design-system
Version:
@wix/design-system
68 lines • 2.87 kB
JavaScript
import React, { createRef, forwardRef, isValidElement, useRef } from 'react';
import { ToastContext } from '../Toast/ToastContext';
import { classes } from './ToastContainer.classes';
import { useStackShift } from './hooks/useStackShift';
import { useExitTransition } from './hooks/useExitTransition';
/* mirrors $duration / $shift-easing in styles/ToastContainer.module.scss */
const SHIFT_DURATION = 300;
const SHIFT_EASING = 'cubic-bezier(0, 0, 0.2, 1)';
let reducedMotionQuery;
const prefersReducedMotion = () => {
if (reducedMotionQuery === undefined) {
reducedMotionQuery =
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
? window.matchMedia('(prefers-reduced-motion: reduce)')
: null;
}
return !!reducedMotionQuery?.matches;
};
const ToastContainer = forwardRef(({ offset, zIndex, dataHook, position, maxToasts = 1, className, children }, ref) => {
const toasts = React.Children.toArray(children)
.filter(isValidElement)
.reverse();
const stacked = maxToasts > 1;
const reducedMotion = prefersReducedMotion();
const itemRefs = useRef(new Map());
const hiddenByKey = useRef(new Map());
const getItemRef = (key) => {
let itemRef = itemRefs.current.get(key);
if (!itemRef) {
itemRef = createRef();
itemRefs.current.set(key, itemRef);
}
return itemRef;
};
const entries = useExitTransition({
elements: toasts,
getNode: key => getItemRef(key).current,
});
const itemKeys = entries.map(entry => entry.key).join('|');
useStackShift({
itemKeys,
itemRefs,
enabled: stacked && !reducedMotion,
duration: SHIFT_DURATION,
easing: SHIFT_EASING,
});
const nextHidden = new Map();
let liveIndex = 0;
const items = entries.map(({ key, element, exiting }) => {
let hidden;
if (exiting) {
hidden = hiddenByKey.current.get(key) ?? false;
}
else {
hidden = liveIndex >= maxToasts;
liveIndex += 1;
}
nextHidden.set(key, hidden);
const containerKey = `toast-container-${key}`;
return (React.createElement("div", { key: containerKey, ref: getItemRef(key), "data-hook": containerKey, "data-hidden": hidden, className: classes.item({ hidden, exiting }) },
React.createElement(ToastContext.Provider, { value: { hidden } }, element)));
});
hiddenByKey.current = nextHidden;
return (React.createElement("div", { ref: ref, className: classes.root({ stacked }, className), "data-hook": dataHook, style: { bottom: offset, zIndex, position: position || 'fixed' } }, items));
});
ToastContainer.displayName = 'ToastContainer';
export { ToastContainer };
//# sourceMappingURL=ToastContainer.js.map