/**
 * `<SelectScrollArrow>` — internal shared implementation for the
 * `<Select.ScrollUpArrow>` / `<Select.ScrollDownArrow>` parts. Mirrors
 * `packages/react/src/select/scroll-arrow/SelectScrollArrow.tsx`.
 *
 * Visibility is driven by `root.scrollUpArrowVisible` /
 * `root.scrollDownArrowVisible` flags — the popup's geometry effect writes
 * them during trigger-aligned placement, and this component gates mount
 * on them plus `openMethod !== 'touch'` (scroll arrows are hover-only).
 *
 * The full scroll-by-item behavior (`onMouseMove` progressing through
 * `listRef` via `getTargetScrollTop`) is ported but only becomes exercisable
 * when real DOM geometry is available (requires browser tests).
 */

import { dynamic } from "@solidjs/web";
import { createMemo, createRenderEffect, omit, onCleanup } from "solid-js";
import { composeRefs, userRef } from "../../internals/compose-refs.jsx";
import { mergeRootProps } from "../../internals/merge-root-props.jsx";
import { resolveClassStyle } from "../../internals/resolve-class-style.jsx";
import { getMaxScrollOffset, normalizeScrollOffset, SCROLL_EDGE_TOLERANCE_PX } from "../../internals/scroll-area-utils/scroll-edges.jsx";
import { Timeout } from "../../internals/use-timeout.jsx";
import { useTransitionStatus } from "../../internals/use-transition-status/use-transition-status.jsx";
import { useSelectPositionerContext } from "../positioner/select-positioner-context.jsx";
import { useSelectRootContext } from "../select-root-context.jsx";
export function SelectScrollArrow(props) {
  const root = useSelectRootContext();
  const positioner = useSelectPositionerContext();
  const isUp = () => props.direction === "up";
  const keepMounted = () => props.keepMounted ?? false;
  const scrollArrowRef = isUp() ? positioner.scrollUpArrowRef : positioner.scrollDownArrowRef;
  const setArrowRef = el => {
    scrollArrowRef.current = el;
  };
  const stateVisible = createMemo(() => isUp() ? root.scrollUpArrowVisible() : root.scrollDownArrowVisible());
  const visible = createMemo(() => stateVisible() && root.openMethod() !== "touch");
  const {
    transitionStatus,
    setMounted
  } = useTransitionStatus(visible);
  root.scrollArrowsMountedCountRef.current += 1;
  onCleanup(() => {
    root.scrollArrowsMountedCountRef.current = Math.max(0, root.scrollArrowsMountedCountRef.current - 1);
  });

  // When visibility drops, unmount after any exit animation — eager here
  // because we don't thread `useOpenChangeComplete` per-arrow.
  createRenderEffect(() => visible(), isVisible => {
    if (!isVisible) setMounted(false);
  });
  const timeout = Timeout.create();
  onCleanup(() => timeout.clear());
  const state = createMemo(() => ({
    direction: props.direction,
    visible: visible(),
    side: positioner.side(),
    transitionStatus: transitionStatus()
  }));
  const internal = {
    "aria-hidden": "true",
    get style() {
      const base = {
        position: "absolute"
      };
      return base;
    },
    children: isUp() ? "\u25B2" : "\u25BC",
    // Default projection: direction \u2192 data-direction=value;
    // visible/transitionStatus mapped explicitly below for clarity.
    get "data-direction"() {
      return state().direction;
    },
    get "data-visible"() {
      return state().visible ? "" : undefined;
    },
    get "data-side"() {
      return state().side;
    },
    get "data-starting-style"() {
      return state().transitionStatus === "starting" ? "" : undefined;
    },
    get "data-ending-style"() {
      return state().transitionStatus === "ending" ? "" : undefined;
    },
    onMouseMove(event) {
      if (event.movementX === 0 && event.movementY === 0 || timeout.isStarted()) {
        return;
      }
      root.setActiveIndex(null);
      const scrollNextItem = () => {
        const popup = root.popupRef.current;
        const scroller = root.listElement() ?? popup;
        if (!scroller) return;
        root.setActiveIndex(null);
        root.handleScrollArrowVisibility();
        const maxScrollTop = getMaxScrollOffset(scroller.scrollHeight, scroller.clientHeight);
        const scrollTop = normalizeScrollOffset(scroller.scrollTop, maxScrollTop);
        const isScrolledToEdge = scrollTop === (isUp() ? 0 : maxScrollTop);
        const items = root.listRef.current;
        if (scrollTop !== scroller.scrollTop) {
          scroller.scrollTop = scrollTop;
        }
        if (items.length === 0) {
          if (isUp()) {
            root.setScrollUpArrowVisible(!isScrolledToEdge);
          } else {
            root.setScrollDownArrowVisible(!isScrolledToEdge);
          }
        }
        if (isScrolledToEdge) {
          timeout.clear();
          return;
        }
        if (items.length > 0) {
          const scrollArrowHeight = scrollArrowRef.current?.offsetHeight ?? 0;
          scroller.scrollTop = getTargetScrollTop(items, isUp(), scrollTop, scroller.clientHeight, scrollArrowHeight, maxScrollTop);
        }
        timeout.start(40, scrollNextItem);
      };
      timeout.start(40, scrollNextItem);
    },
    onMouseLeave() {
      timeout.clear();
    }
  };
  const userClassStyle = resolveClassStyle(props, () => state());
  const userProps = omit(props, "as", "class", "style", "attrs", "direction", "keepMounted");
  let merged = mergeRootProps(internal, userClassStyle);
  merged = mergeRootProps(merged, userProps);
  const Tag = dynamic(() => props.as ?? "div");
  return <>
			{(() => {
      const shouldRender = visible() || keepMounted();
      if (!shouldRender) return null;
      return <Tag {...merged} ref={composeRefs(setArrowRef, userRef(props))} />;
    })()}
		</>;
}
function getTargetScrollTop(items, isUp, scrollTop, clientHeight, scrollArrowHeight, maxScrollTop) {
  if (isUp) {
    let firstVisibleIndex = 0;
    const visibleTop = scrollTop + scrollArrowHeight - SCROLL_EDGE_TOLERANCE_PX;
    for (let i = 0; i < items.length; i += 1) {
      const item = items[i];
      if (item && item.offsetTop >= visibleTop) {
        firstVisibleIndex = i;
        break;
      }
    }
    const targetIndex = Math.max(0, firstVisibleIndex - 1);
    const targetItem = items[targetIndex];
    return targetIndex < firstVisibleIndex && targetItem ? normalizeScrollOffset(targetItem.offsetTop - scrollArrowHeight, maxScrollTop) : 0;
  }
  let lastVisibleIndex = items.length - 1;
  const visibleBottom = scrollTop + clientHeight - scrollArrowHeight + SCROLL_EDGE_TOLERANCE_PX;
  for (let i = 0; i < items.length; i += 1) {
    const item = items[i];
    if (item && item.offsetTop + item.offsetHeight > visibleBottom) {
      lastVisibleIndex = Math.max(0, i - 1);
      break;
    }
  }
  const targetIndex = Math.min(items.length - 1, lastVisibleIndex + 1);
  const targetItem = items[targetIndex];
  return targetIndex > lastVisibleIndex && targetItem ? normalizeScrollOffset(targetItem.offsetTop + targetItem.offsetHeight - clientHeight + scrollArrowHeight, maxScrollTop) : maxScrollTop;
}
//# sourceMappingURL=select-scroll-arrow.jsx.map
