import { flip, offset, shift } from "@floating-ui/dom";
import { dynamic } from "@solidjs/web";
import { createEffect, createMemo, createSignal, omit, Show } from "solid-js";
import { composeRefs, userRef } from "../../internals/compose-refs.jsx";
import { FloatingPortal } from "../../internals/floating-ui/components/floating-portal.jsx";
import { useFloating } from "../../internals/floating-ui/hooks/use-floating.jsx";
import { arrow } from "../../internals/floating-ui/middleware/arrow.jsx";
import { mergeRootProps } from "../../internals/merge-root-props.jsx";
import { resolveClassStyle } from "../../internals/resolve-class-style.jsx";
import { TooltipPositionerContext } from "../tooltip-positioner-context.jsx";
import { useTooltipRootContext } from "../tooltip-root-context.jsx";
function parsePlacement(placement) {
  const [rawSide, rawAlign = "center"] = placement.split("-");
  const side = rawSide ?? "top";
  const align = rawAlign === "start" || rawAlign === "end" ? rawAlign : "center";
  return {
    side,
    align
  };
}

/**
 * Positions the tooltip against the trigger. Renders a `<div>` element inside
 * a `FloatingPortal` (mounted at `document.body` by default).
 *
 * Solid 2.0-native rewire (§1 wave 2): replaces `renderElement` with
 * `dynamic(() => props.as ?? "div")` and inlines state-attr
 * getters via `mergeRootProps`.
 */
export function TooltipPositioner(props) {
  const rootContext = useTooltipRootContext();
  const side = () => props.side ?? "top";
  const align = () => props.align ?? "center";
  const sideOffset = () => props.sideOffset ?? 0;
  void props.alignOffset;
  const collisionPadding = () => props.collisionPadding ?? 5;
  const keepMounted = () => props.keepMounted ?? false;
  const arrowRef = {
    current: null
  };
  const [, setPositionerElement] = createSignal(null, {
    ownedWrite: true
  });
  const physicalSide = () => {
    const s = side();
    if (s === "inline-start") return "left";
    if (s === "inline-end") return "right";
    return s;
  };
  const placement = createMemo(() => {
    const s = physicalSide();
    const a = align();
    if (a === "center") return s;
    return `${s}-${a}`;
  });
  const floating = useFloating({
    rootContext: rootContext.floatingRootContext,
    get placement() {
      return placement();
    },
    strategy: "absolute",
    get middleware() {
      return [offset(sideOffset()), flip(), shift({
        padding: collisionPadding()
      }), arrow({
        element: arrowRef.current,
        offsetParent: "real"
      })];
    }
  });
  const parsed = createMemo(() => parsePlacement(floating.placement));
  const resolvedSide = () => parsed().side;
  const resolvedAlign = () => parsed().align;
  const arrowUncentered = createMemo(() => {
    const arrowData = floating.middlewareData.arrow;
    return Boolean(arrowData?.centerOffset);
  });
  const arrowStyles = createMemo(() => {
    const arrowData = floating.middlewareData.arrow;
    const resolved = resolvedSide();
    const opposite = {
      top: "bottom",
      bottom: "top",
      left: "right",
      right: "left",
      "inline-end": "inline-start",
      "inline-start": "inline-end"
    };
    const styles = {
      position: "absolute"
    };
    if (arrowData?.x !== undefined) {
      styles.left = `${arrowData.x}px`;
    }
    if (arrowData?.y !== undefined) {
      styles.top = `${arrowData.y}px`;
    }
    const oppositeSide = opposite[resolved] ?? "bottom";
    styles[oppositeSide] = "100%";
    return styles;
  });
  const anchorHidden = createMemo(() => {
    const hideData = floating.middlewareData.hide;
    return Boolean(hideData?.referenceHidden);
  });
  const state = createMemo(() => ({
    open: rootContext.open(),
    side: resolvedSide(),
    align: resolvedAlign(),
    anchorHidden: anchorHidden()
  }));
  const positionerContextValue = {
    side: resolvedSide,
    align: resolvedAlign,
    arrowRef,
    arrowUncentered,
    arrowStyles,
    anchorHidden
  };
  const shouldRender = () => rootContext.mounted() || keepMounted();
  let positionerNode = null;
  const positionerRef = el => {
    positionerNode = el;
    // opacity:0 before first paint (ref runs during DOM construction); the
    // reveal effect can run after the first paint in Solid 2. See
    // popover-positioner. `transition: none` suppresses consumer position
    // transitions during mount — computePosition's getBoundingClientRect
    // forces a layout at `transform: none`, so the first transform write
    // would otherwise animate in from the document origin (also see
    // popover-positioner).
    if (el) {
      el.style.opacity = "0";
      el.style.transition = "none";
    }
    setPositionerElement(el);
    floating.refs.setFloating(el);
  };

  // Transform + reveal in ONE imperative write so the tooltip is never visible
  // at the stale (0,0) transform (the teleport). `opacity:0` until
  // `isPositioned`, matching Base UI's `useAnchorPositioning`. See
  // popover-positioner for the full rationale.
  createEffect(() => {
    if (!rootContext.mounted() && !keepMounted()) return null;
    return {
      transform: `translate(${Math.round(floating.x)}px, ${Math.round(floating.y)}px)`,
      positioned: rootContext.mounted() && (floating.isPositioned || !rootContext.open()),
      starting: rootContext.transitionStatus() === "starting"
    };
  }, data => {
    if (!data || !positionerNode) return;
    positionerNode.style.transform = data.transform;
    positionerNode.style.opacity = data.positioned ? "" : "0";
    // Suppress consumer position transitions until the mount settles
    // (see the ref above); re-enable after "starting" so anchor tracking
    // still animates.
    positionerNode.style.transition = data.starting ? "none" : "";
  });
  const positionerStyle = () => ({
    position: "absolute",
    top: 0,
    left: 0,
    "min-width": "max-content"
  });
  const internal = {
    get style() {
      return positionerStyle();
    },
    get "data-open"() {
      return state().open ? "" : undefined;
    },
    get "data-closed"() {
      return state().open ? undefined : "";
    },
    get "data-side"() {
      return state().side;
    },
    get "data-align"() {
      return state().align;
    },
    get "data-anchor-hidden"() {
      return state().anchorHidden ? "" : undefined;
    }
  };
  const userClassStyle = resolveClassStyle(props, () => state());
  const userProps = omit(props, "as", "class", "style", "attrs", "side", "align", "sideOffset", "alignOffset", "collisionPadding", "keepMounted");
  let merged = mergeRootProps(internal, userClassStyle);
  merged = mergeRootProps(merged, userProps);
  const Tag = dynamic(() => props.as ?? "div");
  return <Show when={shouldRender()}>
			<FloatingPortal>
				<TooltipPositionerContext value={positionerContextValue}>
					<Tag {...merged} ref={composeRefs(positionerRef, userRef(props))} />
				</TooltipPositionerContext>
			</FloatingPortal>
		</Show>;
}
//# sourceMappingURL=tooltip-positioner.jsx.map
