UNPKG

@ariakit/react-core

Version:

Ariakit React core

195 lines (192 loc) 6.27 kB
"use client"; import { DialogScopedContextProvider } from "./T2AZQXQU.js"; import { useDisclosureProviderContext } from "./ABN76PSX.js"; import { useStoreState } from "./RTNCFSKZ.js"; import { createElement, createHook, forwardRef } from "./VOQWLFSQ.js"; import { useId, useMergeRefs, useSafeLayoutEffect, useWrapElement } from "./5GGHRIN3.js"; import { __objRest, __spreadProps, __spreadValues } from "./3YLGPPWQ.js"; // src/disclosure/disclosure-content.tsx import { invariant, removeUndefinedValues } from "@ariakit/core/utils/misc"; import { useMemo, useRef, useState } from "react"; import { flushSync } from "react-dom"; import { jsx } from "react/jsx-runtime"; var TagName = "div"; function afterTimeout(timeoutMs, cb) { const timeoutId = setTimeout(cb, timeoutMs); return () => clearTimeout(timeoutId); } function afterPaint(cb) { let raf = requestAnimationFrame(() => { raf = requestAnimationFrame(cb); }); return () => cancelAnimationFrame(raf); } function parseCSSTime(...times) { return times.join(", ").split(", ").reduce((longestTime, currentTimeString) => { const multiplier = currentTimeString.endsWith("ms") ? 1 : 1e3; const currentTime = Number.parseFloat(currentTimeString || "0s") * multiplier; if (currentTime > longestTime) return currentTime; return longestTime; }, 0); } function isHidden(mounted, hidden, alwaysVisible) { return !alwaysVisible && hidden !== false && (!mounted || !!hidden); } var useDisclosureContent = createHook(function useDisclosureContent2(_a) { var _b = _a, { store, alwaysVisible } = _b, props = __objRest(_b, ["store", "alwaysVisible"]); const context = useDisclosureProviderContext(); store = store || context; invariant( store, process.env.NODE_ENV !== "production" && "DisclosureContent must receive a `store` prop or be wrapped in a DisclosureProvider component." ); const ref = useRef(null); const id = useId(props.id); const [transition, setTransition] = useState(null); const open = store.useState("open"); const mounted = store.useState("mounted"); const animated = store.useState("animated"); const contentElement = store.useState("contentElement"); const otherElement = useStoreState(store.disclosure, "contentElement"); useSafeLayoutEffect(() => { if (!ref.current) return; store == null ? void 0 : store.setContentElement(ref.current); }, [store]); useSafeLayoutEffect(() => { let previousAnimated; store == null ? void 0 : store.setState("animated", (animated2) => { previousAnimated = animated2; return true; }); return () => { if (previousAnimated === void 0) return; store == null ? void 0 : store.setState("animated", previousAnimated); }; }, [store]); useSafeLayoutEffect(() => { if (!animated) return; if (!(contentElement == null ? void 0 : contentElement.isConnected)) { setTransition(null); return; } return afterPaint(() => { setTransition(open ? "enter" : mounted ? "leave" : null); }); }, [animated, contentElement, open, mounted]); useSafeLayoutEffect(() => { if (!store) return; if (!animated) return; if (!transition) return; if (!contentElement) return; const stopAnimation = () => store == null ? void 0 : store.setState("animating", false); const stopAnimationSync = () => flushSync(stopAnimation); if (transition === "leave" && open) return; if (transition === "enter" && !open) return; if (typeof animated === "number") { const timeout2 = animated; return afterTimeout(timeout2, stopAnimationSync); } const { transitionDuration, animationDuration, transitionDelay, animationDelay } = getComputedStyle(contentElement); const { transitionDuration: transitionDuration2 = "0", animationDuration: animationDuration2 = "0", transitionDelay: transitionDelay2 = "0", animationDelay: animationDelay2 = "0" } = otherElement ? getComputedStyle(otherElement) : {}; const delay = parseCSSTime( transitionDelay, animationDelay, transitionDelay2, animationDelay2 ); const duration = parseCSSTime( transitionDuration, animationDuration, transitionDuration2, animationDuration2 ); const timeout = delay + duration; if (!timeout) { if (transition === "enter") { store.setState("animated", false); } stopAnimation(); return; } const frameRate = 1e3 / 60; const maxTimeout = Math.max(timeout - frameRate, 0); return afterTimeout(maxTimeout, stopAnimationSync); }, [store, animated, contentElement, otherElement, open, transition]); props = useWrapElement( props, (element) => /* @__PURE__ */ jsx(DialogScopedContextProvider, { value: store, children: element }), [store] ); const hidden = isHidden(mounted, props.hidden, alwaysVisible); const styleProp = props.style; const style = useMemo(() => { if (hidden) { return __spreadProps(__spreadValues({}, styleProp), { display: "none" }); } return styleProp; }, [hidden, styleProp]); props = __spreadProps(__spreadValues({ id, "data-open": open || void 0, "data-enter": transition === "enter" || void 0, "data-leave": transition === "leave" || void 0, hidden }, props), { ref: useMergeRefs(id ? store.setContentElement : null, ref, props.ref), style }); return removeUndefinedValues(props); }); var DisclosureContentImpl = forwardRef(function DisclosureContentImpl2(props) { const htmlProps = useDisclosureContent(props); return createElement(TagName, htmlProps); }); var DisclosureContent = forwardRef(function DisclosureContent2(_a) { var _b = _a, { unmountOnHide } = _b, props = __objRest(_b, [ "unmountOnHide" ]); const context = useDisclosureProviderContext(); const store = props.store || context; const mounted = useStoreState( store, (state) => !unmountOnHide || (state == null ? void 0 : state.mounted) ); if (mounted === false) return null; return /* @__PURE__ */ jsx(DisclosureContentImpl, __spreadValues({}, props)); }); export { isHidden, useDisclosureContent, DisclosureContent };