// src/components/layout/FloatingContainer.tsx
import { forwardRef, useImperativeHandle, useRef } from "react";
import { createPortal } from "react-dom";
import { clsx } from "clsx";

// src/hooks/useFloatingElement.ts
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";

// src/utils/math.ts
var clamp = (value, range = [0, 1]) => {
  const [min, max] = range;
  return Math.min(Math.max(value, min), max);
};

// src/hooks/focus/useIsMounted.ts
import { useEffect, useLayoutEffect, useState } from "react";
var isClient = typeof window !== "undefined" && typeof document !== "undefined";
var useIsomorphicEffect = isClient ? useLayoutEffect : useEffect;
var useIsMounted = () => {
  const [isMounted, setIsMounted] = useState(false);
  useIsomorphicEffect(() => {
    setIsMounted(true);
    return () => {
      setIsMounted(false);
    };
  }, []);
  return isMounted;
};

// src/hooks/useFloatingElement.ts
function calculatePosition({
  windowRect,
  containerRect,
  anchorRect,
  options
}) {
  const { verticalAlignment, horizontalAlignment, gap, screenPadding } = options;
  const windowWidth = windowRect.width;
  const windowHeight = windowRect.height;
  const maxWidth = windowWidth - 2 * screenPadding;
  const maxHeight = windowHeight - 2 * screenPadding;
  const width = Math.min(containerRect.width, maxWidth);
  const height = Math.min(containerRect.height, maxHeight);
  const leftSuggestion = {
    beforeStart: anchorRect.left - width - gap,
    afterStart: anchorRect.left,
    center: anchorRect.left + anchorRect.width / 2 - width / 2,
    beforeEnd: anchorRect.right - width,
    afterEnd: anchorRect.right + gap
  }[horizontalAlignment];
  const topSuggestion = {
    beforeStart: anchorRect.top - height - gap,
    afterStart: anchorRect.top,
    center: anchorRect.top + anchorRect.height / 2 - height / 2,
    beforeEnd: anchorRect.bottom - height,
    afterEnd: anchorRect.bottom + gap
  }[verticalAlignment];
  const left = clamp(leftSuggestion, [
    screenPadding,
    windowWidth - screenPadding - width
  ]);
  const top = clamp(topSuggestion, [
    screenPadding,
    windowHeight - screenPadding - height
  ]);
  return {
    left,
    top,
    maxWidth,
    maxHeight
  };
}
function useFloatingElement({
  active = true,
  windowRef,
  anchorRef,
  containerRef,
  isPolling = false,
  pollingInterval = 100,
  verticalAlignment = "afterEnd",
  horizontalAlignment = "afterStart",
  screenPadding = 16,
  gap = 4
}) {
  const [style, setStyle] = useState2();
  const isMounted = useIsMounted();
  const calculate = useCallback(() => {
    const containerRect = containerRef.current.getBoundingClientRect();
    const windowRect = windowRef?.current.getBoundingClientRect() ?? {
      top: 0,
      bottom: window.innerHeight,
      left: 0,
      right: window.innerWidth,
      width: window.innerWidth,
      height: window.innerHeight
    };
    const anchorElement = anchorRef?.current;
    if (anchorRef && !anchorElement) {
      console.warn("FloatingContainer anchor provided, but its value is undefined");
    }
    const anchorRect = anchorElement?.getBoundingClientRect() ?? windowRect;
    const calculateProps = {
      windowRect,
      anchorRect,
      containerRect,
      options: {
        horizontalAlignment,
        verticalAlignment,
        screenPadding,
        gap
      }
    };
    setStyle(calculatePosition(calculateProps));
  }, [anchorRef, containerRef, gap, horizontalAlignment, screenPadding, verticalAlignment, windowRef]);
  const height = containerRef.current?.getBoundingClientRect().height;
  const width = containerRef.current?.getBoundingClientRect().width;
  useEffect2(() => {
    if (active && isMounted) {
      calculate();
    } else {
      setStyle(void 0);
    }
  }, [calculate, active, isMounted, height, width]);
  useEffect2(() => {
    window.addEventListener("resize", calculate);
    let timeout;
    if (isPolling) {
      timeout = setInterval(calculate, pollingInterval);
    }
    return () => {
      window.removeEventListener("resize", calculate);
      if (timeout) {
        clearInterval(timeout);
      }
    };
  }, [calculate, isPolling, pollingInterval]);
  return style;
}

// src/components/layout/FloatingContainer.tsx
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var FloatingContainer = forwardRef(function FloatingContainer2({
  children,
  backgroundOverlay,
  anchor,
  isPolling = false,
  pollingInterval = 100,
  verticalAlignment = "afterEnd",
  horizontalAlignment = "afterStart",
  screenPadding = 16,
  gap = 4,
  ...props
}, forwardRef2) {
  const innerRef = useRef(null);
  useImperativeHandle(forwardRef2, () => innerRef.current);
  const position = useFloatingElement({
    active: !props.hidden,
    containerRef: innerRef,
    anchorRef: anchor,
    isPolling,
    pollingInterval,
    verticalAlignment,
    horizontalAlignment,
    gap,
    screenPadding
  });
  return createPortal(
    /* @__PURE__ */ jsxs(Fragment, { children: [
      backgroundOverlay,
      /* @__PURE__ */ jsx(
        "div",
        {
          ...props,
          ref: innerRef,
          "data-positioned": position && !props.hidden ? "" : void 0,
          style: {
            position: "fixed",
            overflow: "hidden",
            opacity: position ? void 0 : 0,
            // hide when position calculation isn't done yet
            transition: position ? `top ${pollingInterval}ms linear, left ${pollingInterval}ms linear` : void 0,
            ...position,
            ...props.style
          },
          className: clsx("motion-safe:duration-100 motion-reduce:duration-0", props.className),
          children
        }
      )
    ] }),
    document.body
  );
});
export {
  FloatingContainer
};
//# sourceMappingURL=FloatingContainer.js.map