@liveblocks/react-ui
Version:
A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.
85 lines (81 loc) • 2.83 kB
JavaScript
"use client";
import { jsx } from 'react/jsx-runtime';
import { nn } from '@liveblocks/core';
import { useLayoutEffect } from '@liveblocks/react/_private';
import { createContext, useContext, Children, isValidElement, useRef, useState, useCallback } from 'react';
import { flushSync } from 'react-dom';
const PERSIST_NAME = "Persist";
const PersistContext = createContext(null);
function usePersist() {
const persistContext = useContext(PersistContext);
return nn(persistContext, "Persist is missing from the React tree.");
}
function getChild(children) {
const child = Array.isArray(children) ? Children.only(children) : children;
return isValidElement(child) ? child : void 0;
}
function useAnimationPersist(ref) {
const [isPresent, unmount] = usePersist();
const previousAnimationName = useRef(null);
const unmountAnimationName = useRef(null);
useLayoutEffect(() => {
const element = ref.current;
if (!element) {
return;
}
const handleAnimationEnd = (event) => {
if (event.animationName === unmountAnimationName.current) {
unmount();
}
previousAnimationName.current = event.animationName;
};
element.addEventListener("animationcancel", handleAnimationEnd);
element.addEventListener("animationend", handleAnimationEnd);
return () => {
element.removeEventListener("animationcancel", handleAnimationEnd);
element.removeEventListener("animationend", handleAnimationEnd);
};
}, [ref, unmount]);
useLayoutEffect(() => {
const element = ref.current;
let animationFrameId;
if (!element) {
return;
}
if (!isPresent) {
animationFrameId = requestAnimationFrame(() => {
const styles = getComputedStyle(element);
unmountAnimationName.current = styles.animationName;
if (styles.animationName === "none" || styles.animationName === previousAnimationName.current || styles.display === "none") {
unmount();
}
});
}
return () => {
cancelAnimationFrame(animationFrameId);
};
}, [isPresent, ref, unmount]);
}
function Persist({ children }) {
const [isPersisting, setPersisting] = useState(true);
const lastPresentChild = useRef(null);
const child = getChild(children);
const unmount = useCallback(() => {
flushSync(() => setPersisting(false));
}, []);
useLayoutEffect(() => {
if (child) {
setPersisting(true);
lastPresentChild.current = child;
}
}, [child]);
return /* @__PURE__ */ jsx(PersistContext.Provider, {
value: [Boolean(child), unmount],
children: child ?? (isPersisting ? lastPresentChild.current : null)
});
}
if (process.env.NODE_ENV !== "production") {
Persist.displayName = PERSIST_NAME;
}
export { Persist, useAnimationPersist, usePersist };
//# sourceMappingURL=Persist.js.map