/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-b859c78 | Cube Dev Team */
import { extractStyles } from "../../../tasty/utils/styles.js";
import { OUTER_STYLES } from "../../../tasty/styles/list.js";
import { mergeStyles } from "../../../tasty/utils/merge-styles.js";
import { mergeProps as mergeProps$1 } from "../../../utils/react/mergeProps.js";
import { useEvent } from "../../../_internal/hooks/use-event.js";
import { useMergeStyles } from "../../../utils/react/useMergeStyles.js";
import { useWarn } from "../../../_internal/hooks/use-warn.js";
import { DirectionIcon } from "../../../icons/DirectionIcon.js";
import { useTinyScrollbar } from "../../content/Layout/hooks/useTinyScrollbar.js";
import { DraggableTabList } from "./DraggableTabList.js";
import { TabIndicatorElement, TabsElement } from "./styled.js";
import { TabsProvider } from "./TabsContext.js";
import { TabButton } from "./TabButton.js";
import { CachedPanelRenderer, TabPanelRenderer } from "./TabPanel.js";
import { TabPicker } from "./TabPicker.js";
import { TabsAction } from "./TabsAction.js";
import { useTabEditing } from "./use-tab-editing.js";
import { useTabIndicator } from "./use-tab-indicator.js";
import { Children, forwardRef, isValidElement, useEffect, useMemo, useRef } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
import { useTabList } from "react-aria";
import { Item, useTabListState } from "react-stately";

//#region src/components/navigation/Tabs/Tabs.tsx
/**
* Generic helper to check if a child is a specific component by displayName.
*/
function isComponentElement(child, displayName) {
	return isValidElement(child) && typeof child.type === "function" && child.type.displayName === displayName;
}
/** Checks if a child is a Tab component. */
const isTabElement = (child) => isComponentElement(child, "CubeTab");
/** Checks if a child is a TabPanel component. */
const isTabPanelElement = (child) => isComponentElement(child, "CubeTabPanel");
/** Checks if a child is a TabList component. */
const isTabListElement = (child) => isComponentElement(child, "CubeTabList");
/**
* Extracts the raw key from a React element, stripping the ".$" prefix
* that React adds via Children.map/toArray.
*/
function getRawKey(element) {
	if (element.key == null) return null;
	const keyStr = String(element.key);
	return keyStr.startsWith(".$") ? keyStr.slice(2) : keyStr;
}
function Tab(_props) {
	return null;
}
Tab.displayName = "CubeTab";
function TabPanel(_props) {
	return null;
}
TabPanel.displayName = "CubeTabPanel";
function TabList(_props) {
	return null;
}
TabList.displayName = "CubeTabList";
function TabsComponent(props, ref) {
	const { label = "Tabs", defaultActiveKey, activeKey, size, type = "default", onChange, onDelete, onTitleChange, autoHideActions, isEditable: parentIsEditable, menu: parentMenu, menuTriggerProps: parentMenuTriggerProps, menuProps: parentMenuProps, contextMenu: parentContextMenu, onAction: parentOnAction, children, prefix, suffix, prerender = false, keepMounted = false, qa = "Tabs", renderPanel, panelCacheKeys, isReorderable = false, keyOrder, onReorder, showTabPicker = false, showScrollArrows = false, tabPickerPosition = "suffix", scrollArrowsPosition = "suffix", tabListPadding, tabListStyles, prefixStyles, suffixStyles, ...otherProps } = props;
	const baseStyles = extractStyles(otherProps, OUTER_STYLES);
	const tabListPaddingStyles = useMemo(() => tabListPadding ? { padding: `0 ${tabListPadding}` } : void 0, [tabListPadding]);
	const combinedStyles = useMergeStyles(baseStyles, {
		TabList: useMemo(() => mergeStyles(tabListPaddingStyles, tabListStyles), [tabListPaddingStyles, tabListStyles]),
		Prefix: prefixStyles,
		Suffix: suffixStyles
	});
	const listRef = useRef(null);
	const scrollRef = useRef(null);
	const visitedKeysRef = useRef(/* @__PURE__ */ new Set());
	const { editingKey, editValue, setEditValue, startEditing, cancelEditing, submitEditing } = useTabEditing({
		onChange,
		onTitleChange
	});
	const { parsedTabs, explicitPanels, hasAnyContent } = useMemo(() => {
		const childArray = Children.toArray(children);
		const tabs = [];
		const panels = /* @__PURE__ */ new Map();
		let hasExplicitList = false;
		let tabChildren = [];
		for (const child of childArray) if (isTabListElement(child)) {
			hasExplicitList = true;
			tabChildren = Children.toArray(child.props.children);
		} else if (isTabPanelElement(child)) {
			const key = getRawKey(child);
			if (key != null) panels.set(key, {
				key,
				content: child.props.children,
				prerender: child.props.prerender,
				keepMounted: child.props.keepMounted,
				styles: child.props.styles,
				qa: child.props.qa,
				qaVal: child.props.qaVal
			});
		}
		if (!hasExplicitList) tabChildren = childArray;
		let hasContent = panels.size > 0;
		for (const child of tabChildren) if (isTabElement(child)) {
			const key = getRawKey(child) ?? child.props.id;
			if (key != null) {
				const { id: _id, children: tabContent, ...tabProps } = child.props;
				tabs.push({
					...tabProps,
					key,
					content: tabContent
				});
				if (tabContent != null) hasContent = true;
			}
		}
		return {
			parsedTabs: tabs,
			explicitPanels: panels,
			hasAnyContent: hasContent
		};
	}, [children]);
	const currentTabKeysSet = useMemo(() => new Set(parsedTabs.map((t) => t.key)), [parsedTabs]);
	useEffect(() => {
		for (const key of visitedKeysRef.current) if (!currentTabKeysSet.has(key)) visitedKeysRef.current.delete(key);
	}, [currentTabKeysSet]);
	const orderedParsedTabs = useMemo(() => {
		if (!keyOrder || keyOrder.length === 0) return parsedTabs;
		const tabMap = /* @__PURE__ */ new Map();
		for (const tab of parsedTabs) tabMap.set(tab.key, tab);
		const ordered = [];
		for (const key of keyOrder) {
			const tab = tabMap.get(String(key));
			if (tab) {
				ordered.push(tab);
				tabMap.delete(String(key));
			}
		}
		for (const tab of parsedTabs) if (tabMap.has(tab.key)) ordered.push(tab);
		return ordered;
	}, [parsedTabs, keyOrder]);
	const collectionItems = useMemo(() => {
		return orderedParsedTabs.map((tab) => /* @__PURE__ */ jsx(Item, {
			textValue: typeof tab.title === "string" ? tab.title : String(tab.key),
			children: tab.title
		}, tab.key));
	}, [orderedParsedTabs]);
	const disabledKeys = useMemo(() => {
		return new Set(parsedTabs.filter((tab) => tab.isDisabled).map((tab) => tab.key));
	}, [parsedTabs]);
	const handleSelectionChange = useEvent((key) => {
		const keyStr = String(key);
		visitedKeysRef.current.add(keyStr);
		onChange?.(keyStr);
	});
	const selectedKey = activeKey != null ? String(activeKey) : void 0;
	const defaultSelectedKey = defaultActiveKey != null ? String(defaultActiveKey) : void 0;
	const ariaProps = useMemo(() => ({
		selectedKey,
		defaultSelectedKey,
		onSelectionChange: handleSelectionChange,
		disabledKeys,
		children: collectionItems,
		"aria-label": label
	}), [
		selectedKey,
		defaultSelectedKey,
		handleSelectionChange,
		disabledKeys,
		collectionItems,
		label
	]);
	const state = useTabListState(ariaProps);
	useEffect(() => {
		if (state.selectedKey != null) visitedKeysRef.current.add(String(state.selectedKey));
	}, [state.selectedKey]);
	const { tabListProps } = useTabList(ariaProps, state, listRef);
	const handleTabPickerSelect = useEvent((key) => {
		state.setSelectedKey(key);
		handleSelectionChange(key);
	});
	const orderToken = useMemo(() => orderedParsedTabs.map((t) => t.key).join(","), [orderedParsedTabs]);
	const indicatorStyle = useTabIndicator(listRef, state.selectedKey, type === "default" || type === "narrow", orderToken);
	const isTinyScrollbar = type !== "radio";
	const { handleHStyle, hasOverflowX, isScrolling, isAtStartX, isAtEndX } = useTinyScrollbar(scrollRef, isTinyScrollbar);
	const hasPanels = hasAnyContent || !!renderPanel;
	useWarn(showTabPicker && type === "radio", {
		key: ["tabs-tabpicker-radio-unsupported"],
		args: ["Tabs:", "`showTabPicker` is not supported when `type=\"radio\"`. The TabPicker will not be rendered."]
	});
	const shouldShowTabPicker = type !== "radio" && (showTabPicker === true || showTabPicker === "auto" && hasOverflowX);
	useWarn(showScrollArrows && type === "radio", {
		key: ["tabs-scrollarrows-radio-unsupported"],
		args: ["Tabs:", "`showScrollArrows` is not supported when `type=\"radio\"`. The scroll arrows will not be rendered."]
	});
	const shouldShowScrollArrows = type !== "radio" && (showScrollArrows === true || showScrollArrows === "auto" && hasOverflowX);
	const handleScrollLeft = useEvent(() => {
		const el = scrollRef.current;
		if (el) el.scrollTo({
			left: el.scrollLeft - el.clientWidth,
			behavior: "smooth"
		});
	});
	const handleScrollRight = useEvent(() => {
		const el = scrollRef.current;
		if (el) el.scrollTo({
			left: el.scrollLeft + el.clientWidth,
			behavior: "smooth"
		});
	});
	const baseContextValue = useMemo(() => ({
		state,
		type,
		size,
		autoHideActions,
		isEditable: parentIsEditable,
		menu: parentMenu,
		menuTriggerProps: parentMenuTriggerProps,
		menuProps: parentMenuProps,
		contextMenu: parentContextMenu,
		onDelete,
		onAction: parentOnAction,
		editingKey,
		editValue,
		setEditValue,
		startEditing,
		submitEditing,
		cancelEditing
	}), [
		state,
		type,
		size,
		autoHideActions,
		parentIsEditable,
		parentMenu,
		parentMenuTriggerProps,
		parentMenuProps,
		parentContextMenu,
		onDelete,
		parentOnAction,
		editingKey,
		editValue,
		setEditValue,
		startEditing,
		submitEditing,
		cancelEditing
	]);
	const createContextValue = (dragState, dropState) => ({
		...baseContextValue,
		dragState,
		dropState
	});
	const renderTabListContent = (contextValue, collectionProps = {}) => /* @__PURE__ */ jsxs("div", {
		...mergeProps$1(tabListProps, collectionProps),
		ref: listRef,
		"data-element": "TabList",
		children: [/* @__PURE__ */ jsx(TabsProvider, {
			value: contextValue,
			children: orderedParsedTabs.map((tab, index) => {
				const item = state.collection.getItem(tab.key);
				if (!item) return null;
				return /* @__PURE__ */ jsx(TabButton, {
					item,
					tabData: tab,
					isLastTab: index === orderedParsedTabs.length - 1
				}, item.key);
			})
		}), indicatorStyle && /* @__PURE__ */ jsx(TabIndicatorElement, { style: {
			left: indicatorStyle.left,
			width: indicatorStyle.width
		} })]
	});
	const mods = useMemo(() => ({
		type,
		size,
		deletable: !!onDelete,
		scrolling: isScrolling,
		"fade-left": !isAtStartX,
		"fade-right": !isAtEndX,
		"has-panels": hasPanels
	}), [
		type,
		size,
		onDelete,
		isScrolling,
		isAtStartX,
		isAtEndX,
		hasPanels
	]);
	const scrollArrowsElement = shouldShowScrollArrows ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(TabsAction, {
		icon: /* @__PURE__ */ jsx(DirectionIcon, { to: "left" }),
		"aria-label": "Scroll tabs left",
		isDisabled: isAtStartX,
		onPress: handleScrollLeft
	}), /* @__PURE__ */ jsx(TabsAction, {
		icon: /* @__PURE__ */ jsx(DirectionIcon, { to: "right" }),
		"aria-label": "Scroll tabs right",
		isDisabled: isAtEndX,
		onPress: handleScrollRight
	})] }) : null;
	const tabPickerElement = shouldShowTabPicker ? /* @__PURE__ */ jsx(TabPicker, {
		tabs: orderedParsedTabs,
		selectedKey: state.selectedKey,
		size,
		type,
		onSelect: handleTabPickerSelect,
		onDelete
	}) : null;
	const prefixHasActions = shouldShowTabPicker && tabPickerPosition === "prefix" || shouldShowScrollArrows && scrollArrowsPosition === "prefix";
	const suffixHasActions = shouldShowTabPicker && tabPickerPosition === "suffix" || shouldShowScrollArrows && scrollArrowsPosition === "suffix";
	return /* @__PURE__ */ jsxs(TabsProvider, {
		value: baseContextValue,
		children: [
			/* @__PURE__ */ jsxs(TabsElement, {
				ref,
				qa,
				mods,
				styles: combinedStyles,
				style: handleHStyle,
				"data-size": size,
				children: [
					prefix || prefixHasActions ? /* @__PURE__ */ jsxs("div", {
						"data-element": "Prefix",
						children: [
							tabPickerPosition === "prefix" && tabPickerElement,
							scrollArrowsPosition === "prefix" && scrollArrowsElement,
							prefix
						]
					}) : null,
					/* @__PURE__ */ jsxs("div", {
						"data-element": "ScrollWrapper",
						children: [/* @__PURE__ */ jsx("div", {
							ref: scrollRef,
							"data-element": "Scroll",
							children: isReorderable ? /* @__PURE__ */ jsx(DraggableTabList, {
								state,
								listRef,
								orderedKeys: orderedParsedTabs.map((t) => t.key),
								onReorder,
								children: (dragState, dropState, collectionProps) => renderTabListContent(createContextValue(dragState, dropState), collectionProps)
							}) : renderTabListContent(createContextValue())
						}), isTinyScrollbar && hasOverflowX && /* @__PURE__ */ jsx("div", { "data-element": "ScrollbarH" })]
					}),
					suffix || suffixHasActions ? /* @__PURE__ */ jsxs("div", {
						"data-element": "Suffix",
						children: [
							scrollArrowsPosition === "suffix" && scrollArrowsElement,
							tabPickerPosition === "suffix" && tabPickerElement,
							suffix
						]
					}) : null
				]
			}),
			renderPanel && /* @__PURE__ */ jsx(CachedPanelRenderer, {
				parsedTabs,
				explicitPanels,
				state,
				renderPanel,
				panelCacheKeys,
				prerender,
				keepMounted,
				visitedKeys: visitedKeysRef.current
			}),
			!renderPanel && hasAnyContent && parsedTabs.map((tab) => {
				const explicitPanel = explicitPanels.get(tab.key);
				const content = explicitPanel?.content ?? tab.content;
				if (content == null) return null;
				return /* @__PURE__ */ jsx(TabPanelRenderer, {
					tabKey: tab.key,
					state,
					content,
					prerender,
					keepMounted,
					tabPrerender: explicitPanel?.prerender ?? tab.prerender,
					tabKeepMounted: explicitPanel?.keepMounted ?? tab.keepMounted,
					visitedKeys: visitedKeysRef.current,
					panelStyles: explicitPanel?.styles,
					qa: explicitPanel?.qa,
					qaVal: explicitPanel?.qaVal
				}, tab.key);
			})
		]
	});
}
const _Tabs = forwardRef(TabsComponent);
/**
* Tabs component for organizing content into multiple panels.
* Built with React Aria for full accessibility support.
*
* **Note:** Tab keys are internally converted to strings for React Aria compatibility.
*
* @example
* // Simple usage
* <Tabs defaultActiveKey="tab1">
*   <Tab key="tab1" title="Tab 1">Content 1</Tab>
*   <Tab key="tab2" title="Tab 2">Content 2</Tab>
* </Tabs>
*
* @example
* // Tabs-only (no panels)
* <Tabs activeKey={activeTab} onChange={setActiveTab}>
*   <Tab key="overview" title="Overview" />
*   <Tab key="settings" title="Settings" />
* </Tabs>
*
* @example
* // Explicit panels
* <Tabs defaultActiveKey="tab1">
*   <Tabs.List>
*     <Tab key="tab1" title="Tab 1" />
*     <Tab key="tab2" title="Tab 2" />
*   </Tabs.List>
*   <Tabs.Panel key="tab1">Content 1</Tabs.Panel>
*   <Tabs.Panel key="tab2">Content 2</Tabs.Panel>
* </Tabs>
*/
const Tabs = Object.assign(_Tabs, {
	Tab,
	List: TabList,
	Panel: TabPanel,
	Action: TabsAction
});

//#endregion
export { Tab, Tabs };
//# sourceMappingURL=Tabs.js.map