"use client";
import * as React from 'react';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { jsx, jsxs } from 'react/jsx-runtime';

function cn(...inputs) {
  return twMerge(clsx(inputs));
}
function flattenVisible(nodes, expanded) {
  const out = [];
  function walk(items, depth, parentId) {
    for (const node of items) {
      out.push({ node, depth, parentId });
      if (node.children && expanded.has(node.id)) {
        walk(node.children, depth + 1, node.id);
      }
    }
  }
  walk(nodes, 0, null);
  return out;
}
function Tree({
  data,
  defaultExpanded,
  expanded: expandedProp,
  onExpandedChange,
  selected: selectedProp,
  onSelect,
  "aria-label": ariaLabel,
  className,
  ref
}) {
  const [internalExpanded, setInternalExpanded] = React.useState(
    () => new Set(defaultExpanded ?? [])
  );
  const expanded = React.useMemo(
    () => expandedProp ? new Set(expandedProp) : internalExpanded,
    [expandedProp, internalExpanded]
  );
  const [internalSelected, setInternalSelected] = React.useState(null);
  const selected = selectedProp ?? internalSelected;
  const visible = React.useMemo(() => flattenVisible(data, expanded), [data, expanded]);
  const [focusedId, setFocusedId] = React.useState(
    () => visible[0]?.node.id ?? null
  );
  React.useEffect(() => {
    if (focusedId && !visible.some((row) => row.node.id === focusedId)) {
      setFocusedId(visible[0]?.node.id ?? null);
    }
  }, [visible, focusedId]);
  const setExpandedSet = React.useCallback(
    (next) => {
      if (expandedProp) {
        onExpandedChange?.([...next]);
      } else {
        setInternalExpanded(next);
        onExpandedChange?.([...next]);
      }
    },
    [expandedProp, onExpandedChange]
  );
  const toggleExpand = React.useCallback(
    (id) => {
      const next = new Set(expanded);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      setExpandedSet(next);
    },
    [expanded, setExpandedSet]
  );
  const activate = React.useCallback(
    (id) => {
      if (selectedProp === void 0) setInternalSelected(id);
      onSelect?.(id);
    },
    [selectedProp, onSelect]
  );
  const handleKeyDown = React.useCallback(
    (e) => {
      if (!focusedId) return;
      const idx = visible.findIndex((row2) => row2.node.id === focusedId);
      if (idx < 0) return;
      const row = visible[idx];
      if (!row) return;
      const node = row.node;
      const isParent = !!node.children;
      const isExpanded = expanded.has(node.id);
      switch (e.key) {
        case "ArrowDown": {
          e.preventDefault();
          const next = visible[idx + 1];
          if (next) setFocusedId(next.node.id);
          break;
        }
        case "ArrowUp": {
          e.preventDefault();
          const prev = visible[idx - 1];
          if (prev) setFocusedId(prev.node.id);
          break;
        }
        case "ArrowRight": {
          e.preventDefault();
          if (isParent && !isExpanded) toggleExpand(node.id);
          else if (isParent && isExpanded) {
            const next = visible[idx + 1];
            if (next) setFocusedId(next.node.id);
          }
          break;
        }
        case "ArrowLeft": {
          e.preventDefault();
          if (isParent && isExpanded) toggleExpand(node.id);
          else if (row.parentId) {
            setFocusedId(row.parentId);
          }
          break;
        }
        case "Home": {
          e.preventDefault();
          if (visible[0]) setFocusedId(visible[0].node.id);
          break;
        }
        case "End": {
          e.preventDefault();
          const last = visible[visible.length - 1];
          if (last) setFocusedId(last.node.id);
          break;
        }
        case "Enter":
        case " ": {
          e.preventDefault();
          if (node.disabled) return;
          if (isParent) toggleExpand(node.id);
          activate(node.id);
          break;
        }
        default:
          return;
      }
    },
    [focusedId, visible, expanded, toggleExpand, activate]
  );
  const isSelectable = onSelect !== void 0 || selectedProp !== void 0;
  return /* @__PURE__ */ jsx(
    "ul",
    {
      ref,
      role: "tree",
      "aria-label": ariaLabel,
      className: cn("flex flex-col text-sm text-foreground", className),
      onKeyDown: handleKeyDown,
      children: data.map((node) => /* @__PURE__ */ jsx(
        TreeItem,
        {
          node,
          depth: 0,
          expanded,
          selected,
          isSelectable,
          focusedId,
          onFocus: setFocusedId,
          onToggleExpand: toggleExpand,
          onActivate: activate
        },
        node.id
      ))
    }
  );
}
function TreeItem({
  node,
  depth,
  expanded,
  selected,
  isSelectable,
  focusedId,
  onFocus,
  onToggleExpand,
  onActivate
}) {
  const children = node.children;
  const isParent = children !== void 0;
  const isExpanded = expanded.has(node.id);
  const isSelected = selected === node.id;
  const isFocused = focusedId === node.id;
  const handleClick = () => {
    if (node.disabled) return;
    onFocus(node.id);
    if (isParent) onToggleExpand(node.id);
    onActivate(node.id);
  };
  const labelId = React.useId();
  return /* @__PURE__ */ jsxs(
    "li",
    {
      role: "treeitem",
      "aria-labelledby": labelId,
      "aria-level": depth + 1,
      "aria-expanded": isParent ? isExpanded : void 0,
      "aria-selected": isSelectable ? isSelected : void 0,
      "aria-disabled": node.disabled || void 0,
      tabIndex: isFocused ? 0 : -1,
      onClick: (e) => {
        e.stopPropagation();
        handleClick();
      },
      onFocus: (e) => {
        e.stopPropagation();
        if (!node.disabled) onFocus(node.id);
      },
      className: cn(
        "outline-none rounded-sm",
        // H1: focus-visible-driven ring (NOT state-driven) — the ring
        // only shows on keyboard focus, not on mouse clicks.
        "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
      ),
      children: [
        /* @__PURE__ */ jsxs(
          "div",
          {
            className: cn(
              "flex cursor-pointer select-none items-center gap-[var(--gap-xs,0.25rem)] rounded-sm px-[var(--space-2,0.5rem)] py-[var(--space-1,0.25rem)]",
              "transition-all duration-[var(--duration-normal,200ms)] ease-out",
              "hover:bg-accent hover:text-accent-foreground",
              isSelected && "bg-accent text-accent-foreground font-medium",
              node.disabled && "cursor-not-allowed opacity-50"
            ),
            style: { paddingLeft: `calc(${depth} * var(--space-4, 1rem) + var(--space-2, 0.5rem))` },
            children: [
              isParent ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex h-4 w-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx(
                "svg",
                {
                  xmlns: "http://www.w3.org/2000/svg",
                  viewBox: "0 0 24 24",
                  fill: "none",
                  stroke: "currentColor",
                  strokeWidth: "2",
                  strokeLinecap: "round",
                  strokeLinejoin: "round",
                  className: cn(
                    "h-3 w-3 transition-transform duration-[var(--duration-normal,200ms)] ease-out",
                    isExpanded ? "rotate-90" : "rotate-0"
                  ),
                  children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
                }
              ) }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-block h-4 w-4 shrink-0" }),
              node.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex h-4 w-4 shrink-0 items-center justify-center [&_svg]:size-4", children: node.icon }) : null,
              /* @__PURE__ */ jsx("span", { id: labelId, className: "truncate", children: node.label })
            ]
          }
        ),
        isParent && isExpanded && children ? /* @__PURE__ */ jsx("ul", { role: "group", "aria-labelledby": labelId, className: "flex flex-col", children: children.map((child) => /* @__PURE__ */ jsx(
          TreeItem,
          {
            node: child,
            depth: depth + 1,
            expanded,
            selected,
            isSelectable,
            focusedId,
            onFocus,
            onToggleExpand,
            onActivate
          },
          child.id
        )) }) : null
      ]
    }
  );
}

export { Tree };
//# sourceMappingURL=tree.js.map
//# sourceMappingURL=tree.js.map