'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef } from 'react';
import { AnimatePresence, motion, useIsPresent } from 'motion/react';
import { defaultEasing, easings, } from '@graphprotocol/gds-css';
import { useCSSState } from "../../hooks/index.js";
import { cn, getReactNodeKey } from "../../utils/index.js";
export function Transition({ ref: passedRef, layout = 'block', mode = 'cross', duration = 300, ease = defaultEasing, animateSize = true, className, children, ...props }) {
    const [statePassedRef, state] = useCSSState({
        transition: 'idle',
    }, { ref: passedRef });
    const Element = layout === 'inline' ? 'span' : 'div';
    const sizeProperty = animateSize ? (layout === 'inline' ? 'width' : 'height') : null;
    const transitionElementsWrapperRef = useRef(null);
    // TODO: Debug the issue that this works around (was working fine in the old GDS)
    const hasMounted = useRef(false);
    useEffect(() => {
        window.setTimeout(() => {
            hasMounted.current = true;
        }, 0);
    }, []);
    if (duration <= 0) {
        return (_jsx(Element, { ref: statePassedRef, "data-layout": layout, className: cn(`gds-transition
          u:state-[transition=idle]
          u:data-[layout=block]:block
          u:data-[layout=flex-col]:flex
          u:data-[layout=flex-col]:flex-col
          u:data-[layout=inline]:inline-block`, className), ...state.polyfillAttributes, ...props, children: children }));
    }
    return (_jsx(Element, { ref: statePassedRef, "data-layout": layout, "data-animate-size": animateSize || undefined, className: cn(`gds-transition
        u:state-[transition=idle]
        u:has-[>*>*>[inert]]:state-[transition=running]
        u:has-[>*>*>[inert]]:data-[animate-size=clip]:overflow-clip
        u:data-[layout=block]:block
        u:data-[layout=flex-col]:flex
        u:data-[layout=flex-col]:flex-col
        u:data-[layout=inline]:inline-block`, className), ...state.polyfillAttributes, ...props, children: _jsx(Element, { ref: transitionElementsWrapperRef, "data-layout": layout, className: `
          gds-transition-elements-wrapper flex [--height:auto] [--shrink:1]
          data-[layout=block]:flex-col
          data-[layout=flex-col]:grow
          data-[layout=flex-col]:flex-col
        `, children: _jsx(AnimatePresence, { initial: false, onExitComplete: () => {
                    window.setTimeout(() => {
                        if (layout === 'flex-col' &&
                            sizeProperty === 'height' &&
                            transitionElementsWrapperRef.current) {
                            Array.from(transitionElementsWrapperRef.current.children).forEach((element) => {
                                if (element instanceof HTMLElement) {
                                    element.style.removeProperty('--height');
                                    element.style.removeProperty('--shrink');
                                }
                            });
                        }
                    }, 0);
                }, children: _jsx(motion.span, { transition: {
                        duration: duration / 1000,
                        ease: typeof ease === 'string' ? easings[ease] : ease,
                    }, ...(sizeProperty
                        ? {
                            initial: { [sizeProperty]: 0 },
                            animate: { [sizeProperty]: 'auto' },
                            exit: { [sizeProperty]: 0 },
                        }
                        : {}), onAnimationStart: (animation) => {
                        if (!hasMounted.current)
                            return;
                        // Only continue if `layout` is `flex-col` and we're animating the height to `auto`
                        if (layout !== 'flex-col' || sizeProperty !== 'height')
                            return;
                        const animateHeightTo = typeof animation === 'object' && 'height' in animation
                            ? animation.height
                            : null;
                        if (animateHeightTo !== 'auto')
                            return;
                        /**
                         * Find all relevant entering and exiting elements, including those in other
                         * transitions happening at the same time as the current transition, as they could
                         * affect it by participating in the same layout.
                         */
                        if (!transitionElementsWrapperRef.current)
                            return;
                        const currentTransitionElements = Array.from(transitionElementsWrapperRef.current.children).filter((child) => child instanceof HTMLElement);
                        const otherTransitionElements = Array.from(document.querySelectorAll('.gds-transition-elements-wrapper:has(>*>[inert])')).flatMap((element) => {
                            if (element === transitionElementsWrapperRef.current)
                                return [];
                            return Array.from(element.children).filter((child) => child instanceof HTMLElement);
                        });
                        const currentEnteringElement = currentTransitionElements.find((element) => element.matches(':not(:has(>[inert]))'));
                        if (!currentEnteringElement)
                            return;
                        const otherEnteringElements = otherTransitionElements.filter((element) => element.matches(':not(:has(>[inert]))'));
                        const allEnteringElements = [currentEnteringElement, ...otherEnteringElements];
                        const currentExitingElements = currentTransitionElements.filter((element) => element.matches(':has(>[inert])'));
                        const otherExitingElements = otherTransitionElements.filter((element) => element.matches(':has(>[inert])'));
                        const allExitingElements = [...currentExitingElements, ...otherExitingElements];
                        /**
                         * Lock the height of the current transition's exiting element(s) to their current
                         * height, temporarily taking all the elements that could mess with it out of the flow
                         * with `position: absolute`.
                         */
                        allEnteringElements.forEach((enteringElement) => {
                            enteringElement.style.position = 'absolute';
                        });
                        currentExitingElements.forEach((currentExitingElement) => {
                            // `--height` may already be set if the previous transition was interrupted
                            if (!currentExitingElement.style.getPropertyValue('--height')) {
                                currentExitingElement.style.setProperty('--height', `${currentExitingElement.offsetHeight}px`);
                                currentExitingElement.style.setProperty('--shrink', '0');
                            }
                        });
                        allEnteringElements.forEach((enteringElement) => {
                            enteringElement.style.position = '';
                            enteringElement.style.setProperty('--previous-height', enteringElement.style.height);
                            enteringElement.style.height = ''; // not sure why this is needed, honestly
                        });
                        /**
                         * Do the same for the current transition's entering element, but go one step further
                         * and lock the exiting elements' dimensions before setting their position to
                         * `absolute`, to prevent changing the current scroll position.
                         */
                        allExitingElements.forEach((exitingElement) => {
                            exitingElement.style.width = `${exitingElement.offsetWidth}px`;
                            exitingElement.style.height = `${exitingElement.offsetHeight}px`;
                            exitingElement.style.position = 'absolute';
                        });
                        if (!currentEnteringElement.style.getPropertyValue('--height')) {
                            currentEnteringElement.style.setProperty('--height', `${currentEnteringElement.offsetHeight}px`);
                            currentEnteringElement.style.setProperty('--shrink', '0');
                        }
                        allExitingElements.forEach((exitingElement) => {
                            exitingElement.style.width = '';
                            exitingElement.style.height = '';
                            exitingElement.style.position = '';
                        });
                        allEnteringElements.forEach((enteringElement) => {
                            enteringElement.style.height =
                                enteringElement.style.getPropertyValue('--previous-height');
                        });
                    }, "data-layout": layout, "data-animate-size": animateSize || undefined, className: `
              static block
              not-has-[>[inert]]:order-first
              data-[layout=flex-col]:flex
              data-[layout=flex-col]:flex-col
              not-has-[>[inert]]:data-[layout=flex-col]:grow
              data-[layout=flex-col]:data-animate-size:grow
              has-[>[inert]]:data-[layout=flex-col]:data-animate-size:shrink-9999
            `, children: _jsx(TransitionContent, { layout: layout, mode: mode, duration: duration, ease: ease, children: children }) }, getReactNodeKey(children)) }) }) }));
}
function TransitionContent({ layout, mode, duration, ease, children, }) {
    const isPresent = useIsPresent();
    return (_jsxs(motion.span, { initial: {
            /**
             * Animating `opacity` directly seems buggy with multiple keyframes (e.g. the enter opacity
             * is not synced with the enter transforms in `exit-enter` mode). TODO: Report bug.
             */
            '--opacity': 'var(--gds-transition-enter-opacity)',
            x: 'var(--gds-transition-enter-translate-x)',
            y: 'var(--gds-transition-enter-translate-y)',
            scale: 'var(--gds-transition-enter-scale)',
        }, animate: {
            '--opacity': 1,
            x: 0,
            y: 0,
            scale: 1,
            transition: {
                duration: duration / 1000,
                ease: typeof ease === 'string' ? easings[ease] : ease,
                times: (() => {
                    switch (mode) {
                        case 'cross':
                            return [0, 1];
                        case 'exit-enter':
                            return [0.5, 1];
                        case 'enter-exit':
                            return [0, 0.5];
                        default:
                            return mode.enter;
                    }
                })(),
            },
        }, exit: {
            '--opacity': 'var(--gds-transition-exit-opacity)',
            x: 'var(--gds-transition-exit-translate-x)',
            y: 'var(--gds-transition-exit-translate-y)',
            scale: 'var(--gds-transition-exit-scale)',
            '--position': 'absolute',
            transition: {
                duration: duration / 1000,
                ease: typeof ease === 'string' ? easings[ease] : ease,
                times: (() => {
                    switch (mode) {
                        case 'cross':
                            return [0, 1];
                        case 'exit-enter':
                            return [0, 0.5];
                        case 'enter-exit':
                            return [0.5, 1];
                        default:
                            return mode.exit;
                    }
                })(),
            },
        }, inert: !isPresent, "data-layout": layout, className: `
        nested/transition-content block opacity-(--opacity) [--position:relative]
        not-inert:z-10
        inert:[position:var(--position)]
        inert:inset-0
        data-[layout=flex-col]:flex
        data-[layout=flex-col]:h-(--height)
        data-[layout=flex-col]:shrink-(--shrink)
        data-[layout=flex-col]:grow
        data-[layout=flex-col]:flex-col
        data-[layout=inline]:w-max
      `, children: [children, !children ||
                (typeof children === 'string' && children.trim() === '') ||
                (Array.isArray(children) && children.length === 0) ? (_jsx("span", { "aria-hidden": true, className: "block size-px [:not([inert])>&]:absolute" })) : null] }));
}
//# sourceMappingURL=Transition.js.map