UNPKG

@wix/design-system

Version:

@wix/design-system

70 lines 2.52 kB
import { useLayoutEffect, useReducer, useRef } from 'react'; export const useExitTransition = ({ elements, getNode, }) => { const previous = useRef(new Map()); const exiting = useRef(new Map()); const watched = useRef(new Set()); const getNodeRef = useRef(getNode); const [, rerender] = useReducer(count => count + 1, 0); getNodeRef.current = getNode; const current = new Map(); elements.forEach(element => current.set(String(element.key), element)); current.forEach((_, key) => exiting.current.delete(key)); previous.current.forEach((element, key) => { if (!current.has(key) && !exiting.current.has(key)) { exiting.current.set(key, element); } }); const insertions = new Map(); let displaced = []; previous.current.forEach((_, key) => { if (current.has(key)) { if (displaced.length) { insertions.set(key, displaced); displaced = []; } } else if (exiting.current.has(key)) { displaced.push(key); } }); const orderedKeys = []; current.forEach((_, key) => { orderedKeys.push(...(insertions.get(key) ?? []), key); }); orderedKeys.push(...displaced); const entries = orderedKeys.map(key => ({ key, element: (current.get(key) ?? exiting.current.get(key)), exiting: !current.has(key), })); previous.current = new Map(entries.map(entry => [entry.key, entry.element])); const exitingKeys = entries .filter(entry => entry.exiting) .map(entry => entry.key) .join('|'); useLayoutEffect(() => { const finish = (key) => { watched.current.delete(key); previous.current.delete(key); if (exiting.current.delete(key)) { rerender(); } }; exiting.current.forEach((_, key) => { if (watched.current.has(key)) { return; } watched.current.add(key); const node = getNodeRef.current(key); const animations = typeof node?.getAnimations === 'function' ? node.getAnimations() : []; if (!animations.length) { finish(key); return; } Promise.allSettled(animations.map(animation => animation.finished)).then(() => finish(key)); }); }, [exitingKeys]); return entries; }; //# sourceMappingURL=useExitTransition.js.map