import { U as createStoreContext, V as PopoverScopedContextProvider, W as PopoverContextProvider, x as createHook, F as invariant, X as usePortalRef, Y as useIsMouseMoving, Z as useBooleanEvent, $ as chain, a0 as addGlobalEventListener, a1 as useLiveRef, K as useSafeLayoutEffect, a2 as useWrapElement, j as jsxRuntimeExports, I as useMergeRefs, a3 as usePopover, a4 as isFalsyBooleanCallback, a5 as contains, a6 as useEvent, a7 as sync, a8 as hasFocusWithin, a9 as createDialogComponent, w as forwardRef2, y as createElement, aa as disabledFromProps, ab as useFocusable, ac as createStore, ad as createPopoverStore, ae as defaultValue, af as useStoreProps, ag as usePopoverStoreProps, ah as useStore } from "./doenetml-cB_aZGJ5.js";
import { useRef, useState, useEffect, useContext, createContext, useCallback } from "react";
var ctx$1 = createStoreContext(
  [PopoverContextProvider],
  [PopoverScopedContextProvider]
);
ctx$1.useContext;
ctx$1.useScopedContext;
var useHovercardProviderContext = ctx$1.useProviderContext;
var HovercardContextProvider = ctx$1.ContextProvider;
var HovercardScopedContextProvider = ctx$1.ScopedContextProvider;
var ctx = createStoreContext(
  [HovercardContextProvider],
  [HovercardScopedContextProvider]
);
var useTooltipProviderContext = ctx.useProviderContext;
var TooltipContextProvider = ctx.ContextProvider;
var TooltipScopedContextProvider = ctx.ScopedContextProvider;
function getEventPoint(event) {
  return [event.clientX, event.clientY];
}
function isPointInPolygon(point, polygon) {
  const [x, y] = point;
  let inside = false;
  const length = polygon.length;
  for (let l = length, i = 0, j = l - 1; i < l; j = i++) {
    const [xi, yi] = polygon[i];
    const [xj, yj] = polygon[j];
    const [, vy] = polygon[j === 0 ? l - 1 : j - 1] || [0, 0];
    const where = (yi - yj) * (x - xi) - (xi - xj) * (y - yi);
    if (yj < yi) {
      if (y >= yj && y < yi) {
        if (where === 0) return true;
        if (where > 0) {
          if (y === yj) {
            if (y > vy) {
              inside = !inside;
            }
          } else {
            inside = !inside;
          }
        }
      }
    } else if (yi < yj) {
      if (y > yi && y <= yj) {
        if (where === 0) return true;
        if (where < 0) {
          if (y === yj) {
            if (y < vy) {
              inside = !inside;
            }
          } else {
            inside = !inside;
          }
        }
      }
    } else if (y === yi && (x >= xj && x <= xi || x >= xi && x <= xj)) {
      return true;
    }
  }
  return inside;
}
function getEnterPointPlacement(enterPoint, rect) {
  const { top, right, bottom, left } = rect;
  const [x, y] = enterPoint;
  const placementX = x < left ? "left" : x > right ? "right" : null;
  const placementY = y < top ? "top" : y > bottom ? "bottom" : null;
  return [placementX, placementY];
}
function getElementPolygon(element, enterPoint) {
  const rect = element.getBoundingClientRect();
  const { top, right, bottom, left } = rect;
  const [x, y] = getEnterPointPlacement(enterPoint, rect);
  const polygon = [enterPoint];
  if (x) {
    if (y !== "top") {
      polygon.push([x === "left" ? left : right, top]);
    }
    polygon.push([x === "left" ? right : left, top]);
    polygon.push([x === "left" ? right : left, bottom]);
    if (y !== "bottom") {
      polygon.push([x === "left" ? left : right, bottom]);
    }
  } else if (y === "top") {
    polygon.push([left, top]);
    polygon.push([left, bottom]);
    polygon.push([right, bottom]);
    polygon.push([right, top]);
  } else {
    polygon.push([left, bottom]);
    polygon.push([left, top]);
    polygon.push([right, top]);
    polygon.push([right, bottom]);
  }
  return polygon;
}
var TagName$3 = "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__ */ jsxRuntimeExports.jsx(HovercardScopedContextProvider, { value: store, children: /* @__PURE__ */ jsxRuntimeExports.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;
  }
);
createDialogComponent(
  forwardRef2(function Hovercard2(props) {
    const htmlProps = useHovercard(props);
    return createElement(TagName$3, htmlProps);
  }),
  useHovercardProviderContext
);
var TagName$2 = "div";
var useTooltip = createHook(
  function useTooltip2({
    store,
    portal = true,
    gutter = 8,
    preserveTabOrder = false,
    hideOnHoverOutside = true,
    hideOnInteractOutside = true,
    ...props
  }) {
    const context = useTooltipProviderContext();
    store = store || context;
    invariant(
      store,
      process.env.NODE_ENV !== "production" && "Tooltip must receive a `store` prop or be wrapped in a TooltipProvider component."
    );
    props = useWrapElement(
      props,
      (element) => /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipScopedContextProvider, { value: store, children: element }),
      [store]
    );
    const role = store.useState(
      (state) => state.type === "description" ? "tooltip" : "none"
    );
    props = { role, ...props };
    props = useHovercard({
      ...props,
      store,
      portal,
      gutter,
      preserveTabOrder,
      hideOnHoverOutside(event) {
        if (isFalsyBooleanCallback(hideOnHoverOutside, event)) return false;
        const anchorElement = store == null ? void 0 : store.getState().anchorElement;
        if (!anchorElement) return true;
        if ("focusVisible" in anchorElement.dataset) return false;
        return true;
      },
      hideOnInteractOutside: (event) => {
        if (isFalsyBooleanCallback(hideOnInteractOutside, event)) return false;
        const anchorElement = store == null ? void 0 : store.getState().anchorElement;
        if (!anchorElement) return true;
        if (contains(anchorElement, event.target)) return false;
        return true;
      }
    });
    return props;
  }
);
var Tooltip = createDialogComponent(
  forwardRef2(function Tooltip2(props) {
    const htmlProps = useTooltip(props);
    return createElement(TagName$2, htmlProps);
  }),
  useTooltipProviderContext
);
var TagName$1 = "a";
var useHovercardAnchor = createHook(
  function useHovercardAnchor2({ store, showOnHover = true, ...props }) {
    const context = useHovercardProviderContext();
    store = store || context;
    invariant(
      store,
      process.env.NODE_ENV !== "production" && "HovercardAnchor must receive a `store` prop or be wrapped in a HovercardProvider component."
    );
    const disabled = disabledFromProps(props);
    const showTimeoutRef = useRef(0);
    useEffect(() => () => window.clearTimeout(showTimeoutRef.current), []);
    useEffect(() => {
      const onMouseLeave = (event) => {
        if (!store) return;
        const { anchorElement } = store.getState();
        if (!anchorElement) return;
        if (event.target !== anchorElement) return;
        window.clearTimeout(showTimeoutRef.current);
        showTimeoutRef.current = 0;
      };
      return addGlobalEventListener("mouseleave", onMouseLeave, true);
    }, [store]);
    const onMouseMoveProp = props.onMouseMove;
    const showOnHoverProp = useBooleanEvent(showOnHover);
    const isMouseMoving = useIsMouseMoving();
    const onMouseMove = useEvent((event) => {
      onMouseMoveProp == null ? void 0 : onMouseMoveProp(event);
      if (disabled) return;
      if (!store) return;
      if (event.defaultPrevented) return;
      if (showTimeoutRef.current) return;
      if (!isMouseMoving()) return;
      if (!showOnHoverProp(event)) return;
      const element = event.currentTarget;
      store.setAnchorElement(element);
      store.setDisclosureElement(element);
      const { showTimeout, timeout } = store.getState();
      const showHovercard = () => {
        showTimeoutRef.current = 0;
        if (!isMouseMoving()) return;
        store == null ? void 0 : store.setAnchorElement(element);
        store == null ? void 0 : store.show();
        queueMicrotask(() => {
          store == null ? void 0 : store.setDisclosureElement(element);
        });
      };
      const timeoutMs = showTimeout != null ? showTimeout : timeout;
      if (timeoutMs === 0) {
        showHovercard();
      } else {
        showTimeoutRef.current = window.setTimeout(showHovercard, timeoutMs);
      }
    });
    const onClickProp = props.onClick;
    const onClick = useEvent((event) => {
      onClickProp == null ? void 0 : onClickProp(event);
      if (!store) return;
      window.clearTimeout(showTimeoutRef.current);
      showTimeoutRef.current = 0;
    });
    const ref = useCallback(
      (element) => {
        if (!store) return;
        const { anchorElement } = store.getState();
        if (anchorElement == null ? void 0 : anchorElement.isConnected) return;
        store.setAnchorElement(element);
      },
      [store]
    );
    props = {
      ...props,
      ref: useMergeRefs(ref, props.ref),
      onMouseMove,
      onClick
    };
    props = useFocusable(props);
    return props;
  }
);
forwardRef2(function HovercardAnchor2(props) {
  const htmlProps = useHovercardAnchor(props);
  return createElement(TagName$1, htmlProps);
});
var TagName = "div";
var globalStore = createStore({
  activeStore: null
});
function createRemoveStoreCallback(store) {
  return () => {
    const { activeStore } = globalStore.getState();
    if (activeStore !== store) return;
    globalStore.setState("activeStore", null);
  };
}
var useTooltipAnchor = createHook(
  function useTooltipAnchor2({ store, showOnHover = true, ...props }) {
    const context = useTooltipProviderContext();
    store = store || context;
    invariant(
      store,
      process.env.NODE_ENV !== "production" && "TooltipAnchor must receive a `store` prop or be wrapped in a TooltipProvider component."
    );
    const canShowOnHoverRef = useRef(false);
    useEffect(() => {
      return sync(store, ["mounted"], (state) => {
        if (state.mounted) return;
        canShowOnHoverRef.current = false;
      });
    }, [store]);
    useEffect(() => {
      if (!store) return;
      return chain(
        // Immediately remove the current store from the global store when
        // the component unmounts. This is useful, for example, to avoid
        // showing tooltips immediately on serial tests.
        createRemoveStoreCallback(store),
        sync(store, ["mounted", "skipTimeout"], (state) => {
          if (!store) return;
          if (state.mounted) {
            const { activeStore } = globalStore.getState();
            if (activeStore !== store) {
              activeStore == null ? void 0 : activeStore.hide();
            }
            return globalStore.setState("activeStore", store);
          }
          const id = setTimeout(
            createRemoveStoreCallback(store),
            state.skipTimeout
          );
          return () => clearTimeout(id);
        })
      );
    }, [store]);
    const onMouseEnterProp = props.onMouseEnter;
    const onMouseEnter = useEvent((event) => {
      onMouseEnterProp == null ? void 0 : onMouseEnterProp(event);
      canShowOnHoverRef.current = true;
    });
    const onFocusVisibleProp = props.onFocusVisible;
    const onFocusVisible = useEvent((event) => {
      onFocusVisibleProp == null ? void 0 : onFocusVisibleProp(event);
      if (event.defaultPrevented) return;
      store == null ? void 0 : store.setAnchorElement(event.currentTarget);
      store == null ? void 0 : store.show();
    });
    const onBlurProp = props.onBlur;
    const onBlur = useEvent((event) => {
      onBlurProp == null ? void 0 : onBlurProp(event);
      if (event.defaultPrevented) return;
      const { activeStore } = globalStore.getState();
      canShowOnHoverRef.current = false;
      if (activeStore === store) {
        globalStore.setState("activeStore", null);
      }
    });
    const type = store.useState("type");
    const contentId = store.useState((state) => {
      var _a;
      return (_a = state.contentElement) == null ? void 0 : _a.id;
    });
    props = {
      "aria-labelledby": type === "label" ? contentId : void 0,
      ...props,
      onMouseEnter,
      onFocusVisible,
      onBlur
    };
    props = useHovercardAnchor({
      store,
      showOnHover(event) {
        if (!canShowOnHoverRef.current) return false;
        if (isFalsyBooleanCallback(showOnHover, event)) return false;
        const { activeStore } = globalStore.getState();
        if (!activeStore) return true;
        store == null ? void 0 : store.show();
        return false;
      },
      ...props
    });
    return props;
  }
);
var TooltipAnchor = forwardRef2(function TooltipAnchor2(props) {
  const htmlProps = useTooltipAnchor(props);
  return createElement(TagName, htmlProps);
});
function createHovercardStore(props = {}) {
  var _a;
  const syncState = (_a = props.store) == null ? void 0 : _a.getState();
  const popover = createPopoverStore({
    ...props,
    placement: defaultValue(
      props.placement,
      syncState == null ? void 0 : syncState.placement,
      "bottom"
    )
  });
  const timeout = defaultValue(props.timeout, syncState == null ? void 0 : syncState.timeout, 500);
  const initialState = {
    ...popover.getState(),
    timeout,
    showTimeout: defaultValue(props.showTimeout, syncState == null ? void 0 : syncState.showTimeout),
    hideTimeout: defaultValue(props.hideTimeout, syncState == null ? void 0 : syncState.hideTimeout),
    autoFocusOnShow: defaultValue(syncState == null ? void 0 : syncState.autoFocusOnShow, false)
  };
  const hovercard = createStore(initialState, popover, props.store);
  return {
    ...popover,
    ...hovercard,
    setAutoFocusOnShow: (value) => hovercard.setState("autoFocusOnShow", value)
  };
}
function useHovercardStoreProps(store, update, props) {
  useStoreProps(store, props, "timeout");
  useStoreProps(store, props, "showTimeout");
  useStoreProps(store, props, "hideTimeout");
  return usePopoverStoreProps(store, update, props);
}
function createTooltipStore(props = {}) {
  var _a;
  if (process.env.NODE_ENV !== "production") {
    if (props.type === "label") {
      console.warn(
        "The `type` option on the tooltip store is deprecated.",
        "Render a visually hidden label or use the `aria-label` or `aria-labelledby` attributes on the anchor element instead.",
        "See https://ariakit.org/components/tooltip#tooltip-anchors-must-have-accessible-names"
      );
    }
  }
  const syncState = (_a = props.store) == null ? void 0 : _a.getState();
  const hovercard = createHovercardStore({
    ...props,
    placement: defaultValue(
      props.placement,
      syncState == null ? void 0 : syncState.placement,
      "top"
    ),
    hideTimeout: defaultValue(props.hideTimeout, syncState == null ? void 0 : syncState.hideTimeout, 0)
  });
  const initialState = {
    ...hovercard.getState(),
    type: defaultValue(props.type, syncState == null ? void 0 : syncState.type, "description"),
    skipTimeout: defaultValue(props.skipTimeout, syncState == null ? void 0 : syncState.skipTimeout, 300)
  };
  const tooltip = createStore(initialState, hovercard, props.store);
  return {
    ...hovercard,
    ...tooltip
  };
}
function useTooltipStoreProps(store, update, props) {
  useStoreProps(store, props, "type");
  useStoreProps(store, props, "skipTimeout");
  return useHovercardStoreProps(store, update, props);
}
function useTooltipStore(props = {}) {
  const [store, update] = useStore(createTooltipStore, props);
  return useTooltipStoreProps(store, update, props);
}
function TooltipProvider(props = {}) {
  const store = useTooltipStore(props);
  return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContextProvider, { value: store, children: props.children });
}
export {
  TooltipProvider as T,
  TooltipAnchor as a,
  Tooltip as b
};
