import { jsxs, jsx } from 'react/jsx-runtime';
import { useState, useEffect, createContext, useContext, forwardRef, useRef, useMemo } from 'react';
import { I as Icon } from './Icon-BMMbp40n.js';
import { F as Flex } from './Flex-DOUtHiPi.js';
import { S as SvgCheck } from './check-Cf67OWrZ.js';
import { c as cx } from './index-De1g9FRV.js';
import { l as listboxStyles } from './Listbox.module-CfpLm9pS.js';
import { useTrackingId } from './useTrackingId.js';
import { T as Text } from './Text-J5YtSSXY.js';
import { u as useLayoutPropsUtil } from './useLayoutPropsUtil-CB_zHDbW.js';
import { u as useMergeRefs } from './useMergeRefs-Dfmtq9cI.js';

const useTypeAhead = (timeout = 750) => {
  const [typeAhead, setTypeAhead] = useState("");
  useEffect(() => {
    const timer = setTimeout(() => setTypeAhead(""), timeout);
    return () => clearTimeout(timer);
  }, [typeAhead, timeout]);
  const updateTypeAhead = (char) => setTypeAhead((prev) => prev + char);
  return [typeAhead, updateTypeAhead];
};

const ListboxContext = createContext(
  null
);
const useListbox = () => {
  const context = useContext(ListboxContext);
  if (context == null) {
    throw new Error("useListbox must be wrapped in <Listbox />");
  }
  return context;
};

const ListboxOptionGroupContext = createContext({});

const ListboxOption = forwardRef(
  (props, ref) => {
    const {
      className,
      children,
      disabled: disabledProp,
      onClick,
      label: labelProp,
      item,
      value,
      alignItems,
      justifyItems,
      alignContent,
      justifyContent,
      placeItems,
      placeContent,
      ...rest
    } = props;
    const {
      setCurrentFocus,
      currentFocus,
      selected,
      setSelected,
      selectionMode,
      onSelectionChange,
      controlled
    } = useListbox();
    const label = labelProp || item?.label || "";
    const { disabled: groupDisabled } = useContext(ListboxOptionGroupContext);
    const disabled = groupDisabled || disabledProp || item?.disabled || false;
    const isSelected = () => {
      if (selectionMode === "single") {
        if (item) {
          return selected?.label === label;
        }
        return selected === label;
      }
      if (selectionMode === "multiple") {
        const selectedItems = Array.isArray(selected) ? selected : selected ? [selected] : [];
        if (item) {
          return selectedItems.some(
            (selectedItem) => selectedItem.label === label
          );
        }
        return selectedItems.includes(label);
      }
      return false;
    };
    const onClickHandler = (e) => {
      if (disabled) return;
      onClick?.(e);
      setCurrentFocus?.(label);
      if (selectionMode === "single") {
        if (!item && selected === label || item && selected?.label === label) {
          if (!controlled) {
            setSelected?.(void 0);
          }
          onSelectionChange?.(void 0);
          return;
        }
        if (item) {
          if (!controlled) {
            setSelected?.(item);
          }
          onSelectionChange?.(item);
          return;
        }
        if (!item) {
          if (!controlled) {
            setSelected?.(label);
          }
          onSelectionChange?.(label);
          return;
        }
      }
      if (selectionMode === "multiple") {
        const selectedItems = Array.isArray(selected) ? selected : selected ? [selected] : [];
        if (item && selectedItems.some((selectedItem) => selectedItem.label === label)) {
          const selectedItemsWithItemRemoved = selectedItems.filter(
            (selectedItem) => selectedItem.label !== label
          );
          setSelected?.(selectedItemsWithItemRemoved);
          onSelectionChange?.(selectedItemsWithItemRemoved);
          return;
        }
        if (!item && selectedItems.includes(label)) {
          const selectedItemsWithItemRemoved = selectedItems.filter(
            (selectedItem) => selectedItem !== label
          );
          setSelected?.(selectedItemsWithItemRemoved);
          onSelectionChange?.(selectedItemsWithItemRemoved);
          return;
        }
        if (item) {
          const selectedItemsWithItemAdded = [...selectedItems, item];
          setSelected?.(selectedItemsWithItemAdded);
          onSelectionChange?.(selectedItemsWithItemAdded);
          return;
        }
        if (!item) {
          const selectedItemsWithItemAdded = [...selectedItems, label];
          setSelected?.(selectedItemsWithItemAdded);
          onSelectionChange?.(selectedItemsWithItemAdded);
          return;
        }
      }
    };
    const data = {
      value: props.value,
      label: "item" in props ? props.item?.label : props.label
    };
    const trackingId = useTrackingId({
      name: "ListboxOption",
      data,
      hasOverride: !!props["data-tracking-id"]
    });
    const ListboxOptionClassNames = cx(listboxStyles["option"], className, {});
    return /* @__PURE__ */ jsxs(
      "li",
      {
        "data-tracking-id": trackingId,
        className: ListboxOptionClassNames,
        "data-anv": "listbox-option",
        role: "option",
        "aria-disabled": disabled,
        "data-focused": currentFocus === label,
        "aria-selected": isSelected(),
        id: label,
        onClick: onClickHandler,
        ref,
        value: value ?? label,
        ...rest,
        children: [
          /* @__PURE__ */ jsx(
            Flex,
            {
              className: listboxStyles["children"],
              grow: 1,
              shrink: 1,
              alignItems,
              justifyItems,
              alignContent,
              justifyContent,
              placeItems,
              placeContent,
              children
            }
          ),
          /* @__PURE__ */ jsx(
            Icon,
            {
              "aria-hidden": true,
              svg: SvgCheck,
              inherit: true,
              className: listboxStyles["icon"],
              style: { opacity: isSelected() ? 1 : 0 }
            }
          )
        ]
      }
    );
  }
);
ListboxOption.displayName = "ListboxOption";

const scrollToOption = (node) => {
  node?.scrollIntoView({
    block: "nearest",
    inline: "center"
  });
};
const onListboxKeyDown = (e, context) => {
  const {
    options,
    currentFocus,
    selectionMode,
    onSelectionChange,
    selected,
    setSelected,
    items,
    controlled
  } = context;
  if (!options) return;
  const currentNode = Array.from(options).find(
    (node) => node.id === currentFocus
  );
  const currentIndex = Array.from(options).indexOf(currentNode);
  switch (e.code) {
    case "ArrowDown":
      e.preventDefault();
      if (currentIndex === options.length - 1) {
        goTo(options[0], 0, context);
      } else {
        goTo(options[currentIndex + 1], currentIndex + 1, context);
      }
      break;
    case "ArrowUp":
      e.preventDefault();
      if (currentIndex === 0) {
        goTo(options[options.length - 1], options.length - 1, context);
      } else {
        goTo(options[currentIndex - 1], currentIndex - 1, context);
      }
      break;
    case "Home":
      e.preventDefault();
      goTo(options[0], 0, context);
      break;
    case "End":
      e.preventDefault();
      goTo(options[options.length - 1], options.length - 1, context);
      break;
    case "Enter":
    case "Space":
      e.preventDefault();
      if (!currentFocus) return;
      if (controlled) return;
      if (selectionMode === "single") {
        if (typeof selected === "object" ? selected.label === currentFocus : selected === currentFocus) {
          setSelected?.(void 0);
          onSelectionChange?.(void 0);
          return;
        }
        if (items) {
          const enabledItems = items.filter(
            (item) => !item?.disabled
          );
          setSelected?.(enabledItems[currentIndex]);
          onSelectionChange?.(enabledItems[currentIndex]);
          return;
        }
        if (!items) {
          setSelected?.(currentFocus);
          onSelectionChange?.(currentFocus);
          return;
        }
      }
      if (selectionMode === "multiple") {
        const selectedItems = Array.isArray(selected) ? selected : [selected];
        if (items) {
          const focusedItem = items.find(
            (item) => item.label === currentFocus
          );
          if (selectedItems.includes(focusedItem)) {
            const selectedItemsWithItemRemoved = selectedItems.filter(
              (selectedItem) => selectedItem !== focusedItem
            );
            setSelected?.(selectedItemsWithItemRemoved);
            onSelectionChange?.(selectedItemsWithItemRemoved);
            return;
          } else {
            const selectedItemsWithItemAdded = [...selectedItems, focusedItem];
            setSelected?.(selectedItemsWithItemAdded);
            onSelectionChange?.(selectedItemsWithItemAdded);
            return;
          }
        }
        if (!items) {
          if (selectedItems.includes(currentFocus)) {
            setSelected?.(
              selectedItems.filter((item) => item !== currentFocus)
            );
            onSelectionChange?.(
              selectedItems.filter((item) => item !== currentFocus)
            );
            return;
          }
          setSelected?.([...selectedItems, currentFocus]);
          onSelectionChange?.([...selectedItems, currentFocus]);
        }
      }
      break;
  }
};
const goTo = (option, index, context) => {
  const {
    setCurrentFocus,
    setSelected,
    selectionMode,
    disableAutoSelectOnFocus,
    onSelectionChange,
    items,
    controlled
  } = context;
  scrollToOption(option);
  if (disableAutoSelectOnFocus || selectionMode === "multiple") {
    setCurrentFocus(option?.id);
    return;
  }
  setCurrentFocus(option?.id);
  if (controlled) return;
  if (items) {
    const enabledItems = items.filter(
      (item) => !item?.disabled
    );
    setSelected(enabledItems[index]);
    onSelectionChange?.(enabledItems[index]);
  } else {
    setSelected(option?.id);
    onSelectionChange?.(option?.id);
  }
};

const ListboxOptionGroup = forwardRef((props, ref) => {
  const { className, children, disabled, label, ...rest } = props;
  const optionGroupCx = cx(listboxStyles["option-group"], className);
  const labelCx = cx(listboxStyles["label"], {
    [listboxStyles["disabled"]]: disabled
  });
  return /* @__PURE__ */ jsx(ListboxOptionGroupContext.Provider, { value: { disabled }, children: /* @__PURE__ */ jsxs(
    "div",
    {
      "data-anv": "listbox-option-group",
      className: optionGroupCx,
      ref,
      ...rest,
      children: [
        /* @__PURE__ */ jsx(Text, { variant: "eyebrow", className: labelCx, children: label }),
        children
      ]
    }
  ) });
});
ListboxOptionGroup.displayName = "ListboxOptionGroup";

function ListboxInner(props, ref) {
  const { layoutStyles, componentProps } = useLayoutPropsUtil(props);
  const {
    className,
    selectionMode = "single",
    items,
    children,
    onKeyDown,
    onFocus,
    onSelectionChange,
    selected: selectedProp,
    defaultSelected,
    disableAutoSelectOnFocus,
    style,
    ...rest
  } = componentProps;
  const listboxRef = useRef(null);
  const [selected, setSelected] = useState(
    selectedProp || defaultSelected
  );
  const [options, setOptions] = useState();
  const [typeAhead, updateTypeAhead] = useTypeAhead();
  const [currentFocus, setCurrentFocus] = useState(
    Array.isArray(selected) ? typeof selected[0] === "object" ? selected[0].label : selected[0] : typeof selected === "object" ? selected?.label : selected
  );
  const ListboxClassNames = cx(listboxStyles["listbox"], className, {});
  const controlled = selectedProp !== void 0;
  useEffect(() => {
    if (listboxRef.current) {
      setOptions(
        listboxRef.current.querySelectorAll(
          "[role=option]:not([aria-disabled='true'])"
        )
      );
    }
  }, [items, listboxRef, selectionMode]);
  useEffect(
    () => {
      if ("selected" in componentProps) {
        setSelected(selectedProp);
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [selectedProp]
  );
  useEffect(() => {
    if (!typeAhead.length) {
      return;
    }
    const lowerTypeAhead = typeAhead.toLowerCase();
    const nodes = options && Array.from(options).filter(
      (node2) => node2.innerText.toLowerCase().startsWith(lowerTypeAhead)
    );
    if (!nodes?.length) {
      return;
    }
    let node = nodes[0];
    if (lowerTypeAhead.length === 1 && nodes.length > 1) {
      const focusIndex = currentFocus ? nodes.map((node2) => node2.id).indexOf(currentFocus) : -1;
      if (focusIndex > -1) {
        let nextFocusIndex = focusIndex + 1;
        if (nextFocusIndex === nodes.length) {
          nextFocusIndex = 0;
        }
        node = nodes[nextFocusIndex];
      }
    }
    setCurrentFocus(node.id);
    scrollToOption(node);
    if (controlled) return;
    if (selectionMode === "single") {
      if (items) {
        if (disableAutoSelectOnFocus) {
          const focusedItem = items.find(
            (item) => item.label === currentFocus
          );
          setSelected?.(focusedItem);
          onSelectionChange?.(focusedItem);
        }
        return;
      }
      if (!items) {
        if (disableAutoSelectOnFocus) {
          setSelected(node.id);
          onSelectionChange?.(node.id);
        }
        return;
      }
    }
  }, [typeAhead]);
  const onKeyDownHandler = (e) => {
    onKeyDown?.(e);
    if (new RegExp(/^[a-zA-Z0-9]$/i).test(e.key)) {
      e.preventDefault();
      e.stopPropagation();
      updateTypeAhead(e.key);
      return;
    }
    onListboxKeyDown(e, {
      setCurrentFocus,
      currentFocus,
      setSelected,
      selected,
      selectionMode,
      options,
      onSelectionChange,
      disableAutoSelectOnFocus: !!disableAutoSelectOnFocus,
      items
    });
  };
  const onFocusHandler = (e) => {
    onFocus?.(e);
    if (!options) return;
    if (selectionMode === "single") {
      const currentFocusExists = Array.from(options).some(
        (item) => item.id === currentFocus
      );
      if (currentFocus && currentFocusExists) return;
      if (!items) {
        if (currentFocusExists) {
          setCurrentFocus(selected);
          return;
        }
        setCurrentFocus(options[0].id);
        return;
      }
      if (currentFocusExists) {
        setCurrentFocus(selected?.label);
        return;
      }
      setCurrentFocus(items?.[0].label);
      return;
    }
    if (selectionMode === "multiple") {
      const selectedArr = Array.isArray(selected) ? selected : [selected];
      const currentFocusExists = Array.from(options).some(
        (item) => item.id === currentFocus
      );
      if (currentFocus && currentFocusExists) return;
      if (!items) {
        console.log({ currentFocus, currentFocusExists });
        if (currentFocusExists) {
          setCurrentFocus(selectedArr[0].label);
          return;
        }
        setCurrentFocus(options[0].id);
        return;
      }
      if (currentFocusExists) {
        setCurrentFocus(selectedArr[0]?.label);
        return;
      }
      setCurrentFocus(items?.[0].label);
      return;
    }
    setCurrentFocus(options[0].id);
  };
  const mergeRef = useMergeRefs([ref, listboxRef]);
  const styleCombined = {
    ...style,
    ...layoutStyles
  };
  const value = useMemo(
    () => ({
      setCurrentFocus,
      currentFocus,
      setSelected,
      selected,
      selectionMode,
      items,
      options,
      onSelectionChange,
      disableAutoSelectOnFocus: !!disableAutoSelectOnFocus,
      controlled
    }),
    [
      currentFocus,
      disableAutoSelectOnFocus,
      onSelectionChange,
      options,
      selected,
      selectionMode,
      items,
      controlled
    ]
  );
  return /* @__PURE__ */ jsx(ListboxContext.Provider, { value, children: /* @__PURE__ */ jsx(
    "ul",
    {
      tabIndex: 0,
      role: "listbox",
      style: styleCombined,
      "aria-multiselectable": selectionMode === "multiple" ? "true" : "false",
      "aria-activedescendant": currentFocus,
      className: ListboxClassNames,
      "data-anv": "listbox",
      onKeyDown: onKeyDownHandler,
      onFocus: onFocusHandler,
      ...rest,
      ref: mergeRef,
      children: items ? children?.({ items }) : children
    }
  ) });
}
ListboxInner.displayName = "Listbox";
const Listbox = Object.assign(
  forwardRef(ListboxInner),
  {
    /**
     * ListboxOption component for individual selectable items within a listbox
     *
     * Features:
     * - Displays selectable options with proper ARIA attributes
     * - Supports disabled state for non-selectable options
     * - Keyboard navigation support
     * - Automatic tracking ID generation for analytics
     * - Accessible with screen reader support
     *
     * @example
     * <Listbox.Option value="option1" label="Option 1" />
     */
    Option: ListboxOption,
    /**
     * ListboxOptionGroup component for grouping related options within a listbox
     *
     * Features:
     * - Groups related options with a descriptive label
     * - Maintains proper ARIA structure for accessibility
     * - Supports keyboard navigation within groups
     * - Visual separation of option categories
     *
     * @example
     * <Listbox.OptionGroup label="Fruits">
     *   <Listbox.Option value="apple">Apple</Listbox.Option>
     *   <Listbox.Option value="banana">Banana</Listbox.Option>
     * </Listbox.OptionGroup>
     */
    OptionGroup: ListboxOptionGroup
  }
);

export { Listbox as L };
//# sourceMappingURL=Listbox-DDlxpVu9.js.map
