"use client";
import {
  getElementPolygon,
  getEventPoint,
  isPointInPolygon
} from "./X7QOZUD3.js";
import {
  HovercardScopedContextProvider,
  useHovercardProviderContext
} from "./PTRWAQFT.js";
import {
  usePopover
} from "./KW7Z5AIL.js";
import {
  createDialogComponent
} from "./Z32PU2LQ.js";
import {
  createElement,
  createHook,
  forwardRef
} from "./GWSL6KNJ.js";
import {
  useBooleanEvent,
  useEvent,
  useIsMouseMoving,
  useLiveRef,
  useMergeRefs,
  usePortalRef,
  useSafeLayoutEffect,
  useWrapElement
} from "./KPHZR4MB.js";

// src/hovercard/hovercard.tsx
import { contains } from "@ariakit/core/utils/dom";
import { addGlobalEventListener } from "@ariakit/core/utils/events";
import { hasFocusWithin } from "@ariakit/core/utils/focus";
import {
  chain,
  invariant,
  isFalsyBooleanCallback
} from "@ariakit/core/utils/misc";
import { sync } from "@ariakit/core/utils/store";
import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useRef,
  useState
} from "react";
import { jsx } from "react/jsx-runtime";
var TagName = "div";
function isMovingOnHovercard(target, card, anchor, nested) {
  if (hasFocusWithin(card)) return true;
  if (!target) return false;
  if (contains(card, target)) return true;
  if (anchor && contains(anchor, target)) return true;
  if (nested == null ? void 0 : nested.some((card2) => isMovingOnHovercard(target, card2, anchor))) {
    return true;
  }
  return false;
}
function useAutoFocusOnHide({
  store,
  ...props
}) {
  const [autoFocusOnHide, setAutoFocusOnHide] = useState(false);
  const mounted = store.useState("mounted");
  useEffect(() => {
    if (!mounted) {
      setAutoFocusOnHide(false);
    }
  }, [mounted]);
  const onFocusProp = props.onFocus;
  const onFocus = useEvent((event) => {
    onFocusProp == null ? void 0 : onFocusProp(event);
    if (event.defaultPrevented) return;
    setAutoFocusOnHide(true);
  });
  const finalFocusRef = useRef(null);
  useEffect(() => {
    return sync(store, ["anchorElement"], (state) => {
      finalFocusRef.current = state.anchorElement;
    });
  }, []);
  props = {
    autoFocusOnHide,
    finalFocus: finalFocusRef,
    ...props,
    onFocus
  };
  return props;
}
var NestedHovercardContext = createContext(null);
var useHovercard = createHook(
  function useHovercard2({
    store,
    modal = false,
    portal = !!modal,
    hideOnEscape = true,
    hideOnHoverOutside = true,
    disablePointerEventsOnApproach = !!hideOnHoverOutside,
    ...props
  }) {
    const context = useHovercardProviderContext();
    store = store || context;
    invariant(
      store,
      process.env.NODE_ENV !== "production" && "Hovercard must receive a `store` prop or be wrapped in a HovercardProvider component."
    );
    const ref = useRef(null);
    const [nestedHovercards, setNestedHovercards] = useState([]);
    const hideTimeoutRef = useRef(0);
    const enterPointRef = useRef(null);
    const { portalRef, domReady } = usePortalRef(portal, props.portalRef);
    const isMouseMoving = useIsMouseMoving();
    const mayHideOnHoverOutside = !!hideOnHoverOutside;
    const hideOnHoverOutsideProp = useBooleanEvent(hideOnHoverOutside);
    const mayDisablePointerEvents = !!disablePointerEventsOnApproach;
    const disablePointerEventsProp = useBooleanEvent(
      disablePointerEventsOnApproach
    );
    const open = store.useState("open");
    const mounted = store.useState("mounted");
    useEffect(() => {
      if (!domReady) return;
      if (!mounted) return;
      if (!mayHideOnHoverOutside && !mayDisablePointerEvents) return;
      const element = ref.current;
      if (!element) return;
      const onMouseMove = (event) => {
        if (!store) return;
        if (!isMouseMoving()) return;
        const { anchorElement, hideTimeout, timeout } = store.getState();
        const enterPoint = enterPointRef.current;
        const [target] = event.composedPath();
        const anchor = anchorElement;
        if (isMovingOnHovercard(target, element, anchor, nestedHovercards)) {
          enterPointRef.current = target && anchor && contains(anchor, target) ? getEventPoint(event) : null;
          window.clearTimeout(hideTimeoutRef.current);
          hideTimeoutRef.current = 0;
          return;
        }
        if (hideTimeoutRef.current) return;
        if (enterPoint) {
          const currentPoint = getEventPoint(event);
          const polygon = getElementPolygon(element, enterPoint);
          if (isPointInPolygon(currentPoint, polygon)) {
            enterPointRef.current = currentPoint;
            if (!disablePointerEventsProp(event)) return;
            event.preventDefault();
            event.stopPropagation();
            return;
          }
        }
        if (!hideOnHoverOutsideProp(event)) return;
        hideTimeoutRef.current = window.setTimeout(() => {
          hideTimeoutRef.current = 0;
          store == null ? void 0 : store.hide();
        }, hideTimeout != null ? hideTimeout : timeout);
      };
      return chain(
        addGlobalEventListener("mousemove", onMouseMove, true),
        () => clearTimeout(hideTimeoutRef.current)
      );
    }, [
      store,
      isMouseMoving,
      domReady,
      mounted,
      mayHideOnHoverOutside,
      mayDisablePointerEvents,
      nestedHovercards,
      disablePointerEventsProp,
      hideOnHoverOutsideProp
    ]);
    useEffect(() => {
      if (!domReady) return;
      if (!mounted) return;
      if (!mayDisablePointerEvents) return;
      const disableEvent = (event) => {
        const element = ref.current;
        if (!element) return;
        const enterPoint = enterPointRef.current;
        if (!enterPoint) return;
        const polygon = getElementPolygon(element, enterPoint);
        if (isPointInPolygon(getEventPoint(event), polygon)) {
          if (!disablePointerEventsProp(event)) return;
          event.preventDefault();
          event.stopPropagation();
        }
      };
      return chain(
        // Note: we may need to add pointer events here in the future.
        addGlobalEventListener("mouseenter", disableEvent, true),
        addGlobalEventListener("mouseover", disableEvent, true),
        addGlobalEventListener("mouseout", disableEvent, true),
        addGlobalEventListener("mouseleave", disableEvent, true)
      );
    }, [domReady, mounted, mayDisablePointerEvents, disablePointerEventsProp]);
    useEffect(() => {
      if (!domReady) return;
      if (open) return;
      store == null ? void 0 : store.setAutoFocusOnShow(false);
    }, [store, domReady, open]);
    const openRef = useLiveRef(open);
    useEffect(() => {
      if (!domReady) return;
      return () => {
        if (!openRef.current) {
          store == null ? void 0 : store.setAutoFocusOnShow(false);
        }
      };
    }, [store, domReady]);
    const registerOnParent = useContext(NestedHovercardContext);
    useSafeLayoutEffect(() => {
      if (modal) return;
      if (!portal) return;
      if (!mounted) return;
      if (!domReady) return;
      const element = ref.current;
      if (!element) return;
      return registerOnParent == null ? void 0 : registerOnParent(element);
    }, [modal, portal, mounted, domReady]);
    const registerNestedHovercard = useCallback(
      (element) => {
        setNestedHovercards((prevElements) => [...prevElements, element]);
        const parentUnregister = registerOnParent == null ? void 0 : registerOnParent(element);
        return () => {
          setNestedHovercards(
            (prevElements) => prevElements.filter((item) => item !== element)
          );
          parentUnregister == null ? void 0 : parentUnregister();
        };
      },
      [registerOnParent]
    );
    props = useWrapElement(
      props,
      (element) => /* @__PURE__ */ jsx(HovercardScopedContextProvider, { value: store, children: /* @__PURE__ */ jsx(NestedHovercardContext.Provider, { value: registerNestedHovercard, children: element }) }),
      [store, registerNestedHovercard]
    );
    props = {
      ...props,
      ref: useMergeRefs(ref, props.ref)
    };
    props = useAutoFocusOnHide({ store, ...props });
    const autoFocusOnShow = store.useState(
      (state) => modal || state.autoFocusOnShow
    );
    props = usePopover({
      store,
      modal,
      portal,
      autoFocusOnShow,
      ...props,
      portalRef,
      hideOnEscape(event) {
        if (isFalsyBooleanCallback(hideOnEscape, event)) return false;
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            store == null ? void 0 : store.hide();
          });
        });
        return true;
      }
    });
    return props;
  }
);
var Hovercard = createDialogComponent(
  forwardRef(function Hovercard2(props) {
    const htmlProps = useHovercard(props);
    return createElement(TagName, htmlProps);
  }),
  useHovercardProviderContext
);

export {
  useHovercard,
  Hovercard
};
