/*! ratio-ui · design system for knowledge sharing · https://github.com/losol/ratio-ui · (c) 2026 Losol AS · MPL-2.0 */
"use client";
import { cn } from "../../utils/cn.js";
import { ChevronRight } from "../../icons/index.js";
import { useCallback, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/core/NavTree/NavTree.tsx
var ROW = "flex items-center gap-2.5 rounded-lg px-3 py-2 transition-colors outline-none focus-visible:ring-2 focus-visible:ring-(--focus-ring)";
var ROW_ACTIVE = "bg-primary-100 dark:bg-primary-900 text-(--text) font-medium";
var ROW_IDLE = "text-(--text-muted) hover:text-(--text) hover:bg-card-hover";
var GROUP_LABEL = "px-3 pb-1.5 text-[11px] font-semibold uppercase tracking-[0.09em] text-(--text-subtle)";
/**
* NavTree — hierarchical navigation for sidebars and docs. Optionally grouped
* under uppercase eyebrow labels (the admin-console form), with per-item
* icons, collapsible branches, and active-path highlighting with auto-expanded
* ancestors.
*
* Pass a `LinkComponent` for SPA routers (e.g. Next.js `Link`). When no
* `currentPath` is provided, no item is highlighted. A branch with an `href`
* renders a split row: the label navigates, the chevron toggles.
*
* Successor to `TreeView` (kept as a deprecated alias).
*/
function NavTree({ groups, items, currentPath, iconOnly = false, LinkComponent, "aria-label": ariaLabel = "Navigation", className }) {
	const resolvedGroups = groups ?? (items ? [{ items }] : []);
	return /* @__PURE__ */ jsx("nav", {
		"aria-label": ariaLabel,
		className: cn("text-[14.5px]", className),
		children: resolvedGroups.map((group, index) => /* @__PURE__ */ jsxs("div", {
			className: index > 0 ? "mt-6" : void 0,
			children: [group.label && (iconOnly ? index > 0 && /* @__PURE__ */ jsx("div", {
				"aria-hidden": true,
				className: "mx-2 mb-2 h-px bg-border-1"
			}) : /* @__PURE__ */ jsx("div", {
				className: GROUP_LABEL,
				children: group.label
			})), /* @__PURE__ */ jsx("ul", {
				className: "space-y-0.5",
				children: group.items.map((node, i) => /* @__PURE__ */ jsx(NavTreeRow, {
					node,
					currentPath,
					iconOnly,
					LinkComponent,
					depth: 0
				}, nodeKey(node, i)))
			})]
		}, `${group.label ?? "group"}-${index}`))
	});
}
/** Stable list key: explicit `id`, else `href`, else a string title, else index. */
function nodeKey(node, index) {
	return node.id ?? node.href ?? (typeof node.title === "string" ? node.title : `item-${index}`);
}
function isActive(href, currentPath) {
	if (!href || !currentPath) return false;
	return (href.replace(/\/$/, "") || "/") === (currentPath.replace(/\/$/, "") || "/");
}
function hasActiveChild(node, currentPath) {
	if (!currentPath) return false;
	if (isActive(node.href, currentPath)) return true;
	return node.children?.some((child) => hasActiveChild(child, currentPath)) ?? false;
}
function NavTreeRow({ node, currentPath, iconOnly, LinkComponent, depth }) {
	const hasChildren = !!node.children?.length;
	const active = isActive(node.href, currentPath);
	const containsActive = hasActiveChild(node, currentPath);
	const [manualOpen, setManualOpen] = useState(null);
	const [prevPath, setPrevPath] = useState(currentPath);
	if (prevPath !== currentPath) {
		setPrevPath(currentPath);
		setManualOpen(null);
	}
	const isOpen = manualOpen ?? (active || containsActive);
	const toggle = useCallback(() => setManualOpen((prev) => !(prev ?? (active || containsActive))), [active, containsActive]);
	const LinkTag = LinkComponent ?? "a";
	const paddingLeft = `${.75 + depth * .75}rem`;
	const titleText = typeof node.title === "string" ? node.title : node.id;
	const iconNode = node.icon && /* @__PURE__ */ jsx("span", {
		"aria-hidden": true,
		className: "shrink-0",
		children: node.icon
	});
	const trailingNode = node.trailing && /* @__PURE__ */ jsx("span", {
		className: "ml-auto shrink-0",
		children: node.trailing
	});
	const chevron = /* @__PURE__ */ jsx(ChevronRight, {
		"aria-hidden": "true",
		className: cn("h-4 w-4 shrink-0 transition-transform", isOpen && "rotate-90")
	});
	if (iconOnly) {
		const railActive = active || containsActive;
		const railLabel = titleText ?? node.href;
		const rowClass = cn(ROW, "justify-center px-2", railActive ? ROW_ACTIVE : ROW_IDLE);
		const inner = node.icon ? /* @__PURE__ */ jsx("span", {
			"aria-hidden": true,
			className: "shrink-0",
			children: node.icon
		}) : /* @__PURE__ */ jsx("span", {
			"aria-hidden": true,
			className: "text-sm font-semibold",
			children: (railLabel ?? "·").charAt(0)
		});
		return /* @__PURE__ */ jsx("li", { children: node.href ? /* @__PURE__ */ jsx(LinkTag, {
			href: node.href,
			"aria-label": railLabel,
			title: railLabel,
			"aria-current": active ? "page" : void 0,
			className: rowClass,
			children: inner
		}) : /* @__PURE__ */ jsx("span", {
			"aria-label": railLabel,
			title: railLabel,
			className: cn(rowClass, "cursor-default"),
			children: inner
		}) });
	}
	if (!hasChildren) return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(LinkTag, {
		href: node.href ?? "#",
		"aria-current": active ? "page" : void 0,
		className: cn(ROW, active ? ROW_ACTIVE : ROW_IDLE),
		style: { paddingLeft },
		children: [
			iconNode,
			/* @__PURE__ */ jsx("span", {
				className: "min-w-0 flex-1 truncate",
				children: node.title
			}),
			trailingNode
		]
	}) });
	return /* @__PURE__ */ jsxs("li", { children: [node.href ? /* @__PURE__ */ jsxs("div", {
		className: cn(ROW, "py-0 pr-1", active ? ROW_ACTIVE : containsActive ? "text-(--text) font-medium" : ROW_IDLE),
		style: { paddingLeft },
		children: [
			/* @__PURE__ */ jsxs(LinkTag, {
				href: node.href,
				"aria-current": active ? "page" : void 0,
				className: "flex min-w-0 flex-1 items-center gap-2.5 py-2 outline-none focus-visible:ring-2 focus-visible:ring-(--focus-ring) rounded-md",
				children: [iconNode, /* @__PURE__ */ jsx("span", {
					className: "min-w-0 flex-1 truncate",
					children: node.title
				})]
			}),
			trailingNode,
			/* @__PURE__ */ jsx("button", {
				type: "button",
				onClick: toggle,
				"aria-expanded": isOpen,
				"aria-label": isOpen ? titleText ? `Collapse ${titleText}` : "Collapse" : titleText ? `Expand ${titleText}` : "Expand",
				className: "rounded-md p-1.5 outline-none transition-colors hover:bg-card-hover focus-visible:ring-2 focus-visible:ring-(--focus-ring)",
				children: chevron
			})
		]
	}) : /* @__PURE__ */ jsxs("button", {
		type: "button",
		onClick: toggle,
		"aria-expanded": isOpen,
		className: cn(ROW, "w-full text-left", containsActive ? "text-(--text) font-medium" : ROW_IDLE),
		style: { paddingLeft },
		children: [
			/* @__PURE__ */ jsxs("span", {
				className: "flex min-w-0 flex-1 items-center gap-2.5",
				children: [iconNode, /* @__PURE__ */ jsx("span", {
					className: "truncate",
					children: node.title
				})]
			}),
			trailingNode,
			chevron
		]
	}), isOpen && /* @__PURE__ */ jsx("ul", {
		className: "mt-0.5 space-y-0.5",
		children: node.children.map((child, i) => /* @__PURE__ */ jsx(NavTreeRow, {
			node: child,
			currentPath,
			iconOnly,
			LinkComponent,
			depth: depth + 1
		}, nodeKey(child, i)))
	})] });
}
//#endregion
export { NavTree };

//# sourceMappingURL=NavTree.js.map