UNPKG

@wix/design-system

Version:

@wix/design-system

68 lines 2.87 kB
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