/**
 * @license MIT
 * author: Cube Dev Team
 * @cube-dev/ui-kit v0.0.0-canary-2800b6c
 * Released under the MIT license.
 */

import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { Children, forwardRef, isValidElement, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from 'react';
import { useTab, useTabList, useTabPanel, useTextField, } from 'react-aria';
import { Item as CollectionItem, useTabListState, } from 'react-stately';
import { useEvent } from '../../../_internal/hooks/index.js';
import { CloseIcon } from '../../../icons/index.js';
import { tasty } from '../../../tasty/index.js';
import { chainRaf } from '../../../utils/raf.js';
import { ItemAction } from '../../actions/ItemAction/index.js';
import { Item } from '../../content/Item/index.js';
import { useTinyScrollbar } from '../../content/Layout/hooks/useTinyScrollbar.js';
// =============================================================================
// Styled Components
// =============================================================================
const TabsElement = tasty({
    styles: {
        display: 'flex',
        flow: 'row',
        placeItems: {
            '': 'end stretch',
            'type=radio | type=panel': 'stretch',
        },
        overflow: 'visible',
        border: {
            '': 0,
            'type=default': 'bottom',
        },
        width: {
            '': '100%',
            'type=radio': 'max-content',
        },
        padding: {
            '': 0,
            'type=radio': '.5x',
        },
        radius: {
            '': 0,
            'type=radio': '1cr',
        },
        fill: {
            '': '#clear',
            'type=radio': '#dark.06',
        },
        flexShrink: 0,
        flexGrow: 0,
        $transition: '$tab-transition',
        Prefix: {
            display: 'flex',
            placeItems: 'center',
            placeContent: 'center',
            flexShrink: 0,
            placeSelf: 'center',
        },
        Suffix: {
            display: 'flex',
            placeItems: 'center',
            placeContent: 'center',
            flexShrink: 0,
            placeSelf: 'center',
        },
        // Wrapper for scroll area and scrollbar (scrollbar is positioned relative to this)
        ScrollWrapper: {
            position: 'relative',
            display: 'flex',
            flexGrow: 1,
            flexShrink: 1,
            width: 'min 0',
        },
        Scroll: {
            position: 'relative',
            display: 'block',
            overflow: {
                '': 'auto hidden',
                'type=radio': 'visible',
            },
            scrollbar: 'none',
            flexGrow: 1,
            width: '100%',
            // Use multi-group fade with color tokens for smooth transitions
            fade: '2x left #tabs-fade-left #black, 2x right #tabs-fade-right #black',
            // ##name outputs --name-color (literal CSS property name)
            transition: '##tabs-fade-left $tab-transition ease-in, ##tabs-fade-right $tab-transition ease-in',
            // Transition transparent color: opaque (no fade) -> transparent (fade visible)
            '#tabs-fade-left': {
                '': 'rgb(0 0 0 / 1)',
                'fade-left': 'rgb(0 0 0 / 0)',
            },
            '#tabs-fade-right': {
                '': 'rgb(0 0 0 / 1)',
                'fade-right': 'rgb(0 0 0 / 0)',
            },
        },
        Container: {
            position: 'relative',
            display: 'grid',
            gridAutoFlow: 'column',
            gap: {
                '': 0,
                'type=radio': '.5x',
            },
            placeContent: 'start',
            overflow: 'visible',
            width: 'max-content',
        },
        // Custom horizontal scrollbar (tiny) - positioned relative to ScrollWrapper
        ScrollbarH: {
            position: 'absolute',
            bottom: '1px',
            left: '$scrollbar-h-left',
            height: '1ow',
            width: '$scrollbar-h-width',
            radius: 'round',
            fill: '#dark.35',
            opacity: {
                '': 0,
                'focused | scrolling': 1,
            },
            transition: 'opacity 0.15s',
            pointerEvents: 'none',
        },
    },
});
const TabElement = tasty(Item, {
    as: 'button',
    type: 'clear',
    styles: {
        preset: {
            '': 't3m',
            'size=small | size=xsmall': 't4',
            'size=large | size=xlarge': 't2m',
        },
        shadow: {
            '': 'none',
            editing: 'inset 0 0 0 1bw #purple-text',
        },
    },
});
const CardTabElement = tasty(Item, {
    as: 'button',
    type: 'clear',
    styles: {
        radius: 'top',
        color: {
            '': '#dark-03',
            selected: '#purple-text',
        },
        fill: '#clear',
        preset: 'h6',
        shadow: {
            '': 'none',
            editing: 'inset 0 0 0 1bw #purple-text',
        },
    },
});
const RadioTabElement = tasty(Item, {
    as: 'button',
    type: 'neutral',
    styles: {
        fill: {
            '': '#clear',
            selected: '#white',
        },
        shadow: {
            '': 'none',
            selected: '$item-shadow',
        },
        Label: {
            placeSelf: {
                '': 'center start',
                '!has-prefix & !has-suffix & !has-icon & !has-right-icon': 'center',
            },
        },
    },
});
const TabContainer = tasty({
    styles: {
        position: 'relative',
        display: 'grid',
    },
});
// =============================================================================
// EditableTitle Component (inline title editing)
// =============================================================================
const EditableTitleInputElement = tasty({
    as: 'input',
    styles: {
        border: 0,
        padding: 0,
        margin: 0,
        fill: 'transparent',
        outline: 0,
        preset: 'inherit',
        color: 'inherit',
        width: 'initial $input-width 100%',
    },
});
const HiddenMeasure = tasty({
    styles: {
        position: 'absolute',
        visibility: 'hidden',
        whiteSpace: 'pre',
        font: 'inherit',
        pointerEvents: 'none',
        height: 0,
        overflow: 'hidden',
    },
});
function EditableTitle({ title, isEditing, editValue, onEditValueChange, onStartEditing, onSubmit, onCancel, }) {
    const inputRef = useRef(null);
    const measureRef = useRef(null);
    const [inputWidth, setInputWidth] = useState(null);
    const justEnteredEditModeRef = useRef(false);
    // React Aria text field hook
    const { inputProps } = useTextField({
        'aria-label': 'Edit tab title',
        value: editValue,
        onChange: onEditValueChange,
    }, inputRef);
    // Focus and select input when entering edit mode
    useLayoutEffect(() => {
        if (isEditing && inputRef.current) {
            const input = inputRef.current;
            // Set flag to ignore immediate blur events
            justEnteredEditModeRef.current = true;
            input.focus();
            // Use requestAnimationFrame to ensure selection happens after focus
            requestAnimationFrame(() => {
                input.select();
                // Clear the flag after focus is established (allow 2 frames for menu to fully close)
                requestAnimationFrame(() => {
                    requestAnimationFrame(() => {
                        justEnteredEditModeRef.current = false;
                    });
                });
            });
        }
        else {
            justEnteredEditModeRef.current = false;
        }
    }, [isEditing]);
    // Measure text width and update input width
    useLayoutEffect(() => {
        if (isEditing && measureRef.current) {
            const width = measureRef.current.scrollWidth;
            setInputWidth(width);
        }
    }, [isEditing, editValue]);
    const handleKeyDown = useEvent((e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            onSubmit();
        }
        else if (e.key === 'Escape') {
            e.preventDefault();
            onCancel();
        }
        else if (e.key === 'ArrowLeft' ||
            e.key === 'ArrowRight' ||
            e.key === ' ') {
            // Stop propagation to prevent tab navigation while editing
            e.stopPropagation();
        }
    });
    const handleBlur = useEvent(() => {
        // Ignore blur events immediately after entering edit mode (menu closing causes focus loss)
        if (justEnteredEditModeRef.current) {
            // Re-focus the input since something else stole focus
            requestAnimationFrame(() => {
                inputRef.current?.focus();
                inputRef.current?.select();
            });
            return;
        }
        // Submit on blur (per user preference)
        onSubmit();
    });
    const handleDoubleClick = useEvent((e) => {
        e.preventDefault();
        e.stopPropagation();
        onStartEditing();
    });
    if (isEditing) {
        // Merge our handlers with React Aria's inputProps
        const mergedProps = {
            ...inputProps,
            onKeyDown: (e) => {
                handleKeyDown(e);
                inputProps.onKeyDown?.(e);
            },
            onBlur: (e) => {
                handleBlur();
                inputProps.onBlur?.(e);
            },
        };
        return (_jsxs(_Fragment, { children: [_jsx(HiddenMeasure, { ref: measureRef, "aria-hidden": "true", children: editValue || ' ' }), _jsx(EditableTitleInputElement, { ...mergedProps, ref: inputRef, tokens: { '$input-width': inputWidth ? `${inputWidth}px` : 'auto' } })] }));
    }
    return _jsx("span", { onDoubleClick: handleDoubleClick, children: title });
}
const TabPanelElement = tasty({
    as: 'section',
    styles: {
        display: 'contents',
    },
});
const TabIndicatorElement = tasty({
    styles: {
        position: 'absolute',
        bottom: '0',
        left: 0,
        height: '1ow',
        fill: '#purple',
        transition: 'left, width',
        transitionDuration: '.2s',
        transitionTimingFunction: 'ease-out',
        pointerEvents: 'none',
    },
});
/**
 * Hook to track and animate tab indicator position.
 * Returns null if disabled (e.g., for non-default types).
 */
function useTabIndicator(containerRef, selectedKey, enabled) {
    const [style, setStyle] = useState(null);
    const cancelRef = useRef(null);
    const updateIndicator = useCallback(() => {
        if (!enabled || !containerRef.current || selectedKey == null) {
            setStyle(null);
            return;
        }
        // Find the selected tab button within the container
        const selectedTab = containerRef.current.querySelector('[aria-selected="true"]');
        if (!selectedTab) {
            setStyle(null);
            return;
        }
        const containerRect = containerRef.current.getBoundingClientRect();
        const tabRect = selectedTab.getBoundingClientRect();
        // Only update if dimensions are valid (element has been painted)
        if (tabRect.width > 0) {
            setStyle({
                left: tabRect.left - containerRect.left + containerRef.current.scrollLeft,
                width: tabRect.width,
            });
        }
    }, [containerRef, selectedKey, enabled]);
    // Update on selectedKey change - use chainRaf to ensure DOM is fully painted
    useLayoutEffect(() => {
        // Cancel any pending RAF chain
        if (cancelRef.current) {
            cancelRef.current();
        }
        // Schedule update after 2 frames to ensure layout is complete
        cancelRef.current = chainRaf(() => {
            updateIndicator();
        }, 2);
        return () => {
            if (cancelRef.current) {
                cancelRef.current();
            }
        };
    }, [updateIndicator]);
    // Update on window resize
    useEffect(() => {
        if (!enabled)
            return;
        const handleResize = () => updateIndicator();
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
    }, [enabled, updateIndicator]);
    return enabled ? style : null;
}
// =============================================================================
// Helper Functions
// =============================================================================
/**
 * Checks if a child is a Tab component.
 */
function isTabElement(child) {
    return (isValidElement(child) &&
        typeof child.type === 'function' &&
        child.type.displayName === 'CubeTab');
}
/**
 * Checks if a child is a TabPanel component.
 */
function isTabPanelElement(child) {
    return (isValidElement(child) &&
        typeof child.type === 'function' &&
        child.type.displayName === 'CubeTabPanel');
}
/**
 * Checks if a child is a TabList component.
 */
function isTabListElement(child) {
    return (isValidElement(child) &&
        typeof child.type === 'function' &&
        child.type.displayName === 'CubeTabList');
}
/**
 * Extracts the raw key from a React child (strips the ".$" prefix added by Children.map).
 *
 * Note: All keys are converted to strings for React Aria compatibility.
 * This means numeric keys like `key={1}` become `"1"`.
 *
 * @returns The key as a string, or null if no key is present
 */
function getRawKey(child) {
    if (child.key == null)
        return null;
    const keyStr = String(child.key);
    // React prefixes keys with ".$" in Children.map
    if (keyStr.startsWith('.$')) {
        return keyStr.slice(2);
    }
    return keyStr;
}
// =============================================================================
// Tab Component (for building items)
// =============================================================================
function Tab(_props) {
    // This component is never rendered directly - it's used for configuration
    // The actual rendering happens in TabButton
    return null;
}
Tab.displayName = 'CubeTab';
function TabButton({ item, state, tabData, type, size, onDelete, showActionsOnHover: parentShowActionsOnHover, isEditing = false, editValue = '', onEditValueChange, onStartEditing, onSubmitEditing, onCancelEditing, }) {
    const ref = useRef(null);
    const { tabProps } = useTab({ key: item.key }, state, ref);
    const isActive = state.selectedKey === item.key;
    const isDisabled = state.disabledKeys.has(item.key);
    const isDeletable = !!onDelete;
    const isEditable = tabData.isEditable ?? false;
    const effectiveType = tabData.type ?? type ?? 'default';
    const handleDelete = useEvent(() => {
        onDelete?.(item.key);
    });
    const handleStartEditing = useEvent(() => {
        if (!isEditable || isDisabled)
            return;
        const titleText = typeof tabData.title === 'string' ? tabData.title : String(item.key);
        onStartEditing?.(item.key, titleText);
    });
    const handleSubmitEditing = useEvent(() => {
        onSubmitEditing?.(item.key, editValue, tabData.onTitleChange);
    });
    const handleCancelEditing = useEvent(() => {
        onCancelEditing?.();
    });
    const handleEditValueChange = useEvent((value) => {
        onEditValueChange?.(value);
    });
    const mods = useMemo(() => ({
        default: effectiveType === 'default',
        panel: effectiveType === 'panel',
        radio: effectiveType === 'radio',
        active: isActive,
        deletable: isDeletable,
        disabled: isDisabled,
        editing: isEditing,
    }), [effectiveType, isActive, isDeletable, isDisabled, isEditing]);
    // Scroll active tab into view
    useEffect(() => {
        if (ref.current && isActive) {
            ref.current.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });
        }
    }, [isActive]);
    // Build actions for the tab (custom actions + delete button)
    const deleteAction = isDeletable ? (_jsx(ItemAction, { icon: _jsx(CloseIcon, {}), tooltip: "Delete tab", onPress: handleDelete })) : null;
    // Combine tab's custom actions with delete action
    const actions = tabData.actions || deleteAction ? (_jsxs(_Fragment, { children: [tabData.actions, deleteAction] })) : undefined;
    // Determine effective size - map 'medium'/'large' to Item size values
    const isRadioType = effectiveType === 'radio';
    const isPanelType = effectiveType === 'panel';
    const isDefaultType = effectiveType === 'default';
    const effectiveSize = tabData.size ?? size ?? 'medium';
    // For radio type, use smaller sizes like RadioGroup tabs mode
    let itemSize;
    if (isRadioType) {
        // Map sizes similar to RadioGroup tabs mode
        if (effectiveSize === 'medium') {
            itemSize = 'xsmall';
        }
        else {
            // large -> medium
            itemSize = 'medium';
        }
    }
    else {
        itemSize = effectiveSize === 'large' ? 'large' : 'medium';
    }
    // Determine which element to use based on type
    let Element;
    if (isRadioType) {
        Element = RadioTabElement;
    }
    else if (isDefaultType) {
        Element = CardTabElement;
    }
    else {
        Element = TabElement;
    }
    // Determine Item type prop
    let itemType = !isRadioType
        ? isActive
            ? 'clear'
            : 'neutral'
        : 'neutral';
    // Determine shape - panel type uses sharp edges
    const itemShape = isPanelType ? 'sharp' : undefined;
    // Determine showActionsOnHover - tab-level overrides parent-level
    const effectiveShowActionsOnHover = tabData.showActionsOnHover ?? parentShowActionsOnHover;
    // Render title with editing support if editable
    const titleContent = isEditable ? (_jsx(EditableTitle, { title: tabData.title, isEditing: isEditing, editValue: editValue, onEditValueChange: handleEditValueChange, onStartEditing: handleStartEditing, onSubmit: handleSubmitEditing, onCancel: handleCancelEditing })) : (tabData.title);
    // Extract tab-specific props and pass through the rest (style props) to the Item
    const { title: _title, content: _content, key: _key, isDisabled: _isDisabled, prerender: _prerender, keepMounted: _keepMounted, size: _size, type: _type, actions: _actions, showActionsOnHover: _showActionsOnHover, isEditable: _isEditable, onTitleChange: _onTitleChange, qa, qaVal, styles, ...itemStyleProps } = tabData;
    return (_jsx(TabContainer, { mods: mods, children: _jsx(Element, { preserveActionsSpace: true, showActionsOnHover: effectiveShowActionsOnHover, as: "button", ...tabProps, ...itemStyleProps, ref: ref, qa: qa ?? `Tab-${String(item.key)}`, qaVal: qaVal, styles: styles, mods: mods, isSelected: isActive, isDisabled: isDisabled, size: itemSize, type: itemType, shape: itemShape, actions: actions, children: titleContent }) }));
}
function TabPanelRenderer({ tabKey, state, content, prerender, keepMounted, tabPrerender, tabKeepMounted, visitedKeys, panelStyles, qa, qaVal, }) {
    const ref = useRef(null);
    const { tabPanelProps } = useTabPanel({ key: tabKey }, state, ref);
    const isActive = state.selectedKey === tabKey;
    // Determine effective prerender/keepMounted (tab-level overrides global)
    const effectivePrerender = tabPrerender ?? prerender;
    const effectiveKeepMounted = tabKeepMounted ?? keepMounted;
    // Determine if panel should render using shared utility
    if (!shouldRenderPanel(isActive, visitedKeys.has(tabKey), effectivePrerender, effectiveKeepMounted)) {
        return null;
    }
    return (_jsx(TabPanelElement, { ...tabPanelProps, ref: ref, qa: qa ?? 'TabPanel', qaVal: qaVal ?? String(tabKey), styles: panelStyles, style: {
            display: isActive ? 'contents' : 'none',
        }, children: content }));
}
/**
 * Determines if a panel should be rendered based on prerender/keepMounted settings.
 */
function shouldRenderPanel(isActive, wasVisited, effectivePrerender, effectiveKeepMounted) {
    return (!!effectivePrerender || isActive || (!!effectiveKeepMounted && wasVisited));
}
/**
 * Renders panels with optional content caching.
 * Only the content from renderPanel is cached - the TabPanelRenderer wrapper
 * is always rendered fresh so it can correctly determine the active state.
 *
 * Caching behavior:
 * - By default, panels re-render on every Tabs render (no caching)
 * - When a panel has a non-undefined cache key in `panelCacheKeys`, caching is enabled
 * - Cached content is reused until the cache key changes
 * - Setting a cache key to `undefined` is the same as not having it (no caching)
 */
function CachedPanelRenderer({ parsedTabs, explicitPanels, state, renderPanel, panelCacheKeys, prerender, keepMounted, visitedKeys, }) {
    // Cache for rendered content - stores { content, cacheKey } per panel
    const contentCacheRef = useRef(new Map());
    /**
     * Get the cache key for a panel.
     * Returns undefined if no cache key is defined or if set to undefined (no caching).
     */
    const getCacheKey = (key) => {
        if (!panelCacheKeys)
            return undefined;
        if (Object.prototype.hasOwnProperty.call(panelCacheKeys, key)) {
            const value = panelCacheKeys[key];
            // undefined means no caching
            return value;
        }
        return undefined;
    };
    /**
     * Check if a panel has caching enabled.
     * Only enabled when a non-undefined cache key is defined.
     */
    const hasCacheKey = (key) => {
        if (!panelCacheKeys)
            return false;
        if (!Object.prototype.hasOwnProperty.call(panelCacheKeys, key))
            return false;
        // undefined value means no caching
        return panelCacheKeys[key] !== undefined;
    };
    // Clean up cache entries for removed tabs
    const currentTabKeys = useMemo(() => new Set(parsedTabs.map((t) => t.key)), [parsedTabs]);
    // Use effect to clean up stale cache entries when tabs change
    useEffect(() => {
        for (const key of contentCacheRef.current.keys()) {
            if (!currentTabKeys.has(key)) {
                contentCacheRef.current.delete(key);
            }
        }
    }, [currentTabKeys]);
    return (_jsx(_Fragment, { children: parsedTabs.map((tab) => {
            const explicitPanel = explicitPanels.get(tab.key);
            const tabPrerender = explicitPanel?.prerender ?? tab.prerender;
            const tabKeepMounted = explicitPanel?.keepMounted ?? tab.keepMounted;
            const effectivePrerender = tabPrerender ?? prerender;
            const effectiveKeepMounted = tabKeepMounted ?? keepMounted;
            const isActive = state.selectedKey === tab.key;
            const wasVisited = visitedKeys.has(tab.key);
            if (!shouldRenderPanel(isActive, wasVisited, effectivePrerender, effectiveKeepMounted)) {
                return null;
            }
            // Check if this panel has caching enabled
            const isCachingEnabled = hasCacheKey(tab.key);
            let content;
            if (isCachingEnabled) {
                // Caching is enabled for this panel - check cache
                const currentCacheKey = getCacheKey(tab.key);
                const cached = contentCacheRef.current.get(tab.key);
                // Cache hit if keys match (currentCacheKey is guaranteed non-undefined here)
                if (cached !== undefined && cached.cacheKey === currentCacheKey) {
                    // Cache hit - use cached content
                    content = cached.content;
                }
                else {
                    // Cache miss or key changed - compute fresh and cache
                    content = renderPanel(tab.key);
                    contentCacheRef.current.set(tab.key, {
                        content,
                        cacheKey: currentCacheKey,
                    });
                }
            }
            else {
                // No caching - always compute fresh
                content = renderPanel(tab.key);
                // Clear any stale cache entry
                contentCacheRef.current.delete(tab.key);
            }
            return (_jsx(TabPanelRenderer, { tabKey: tab.key, state: state, content: content, prerender: prerender, keepMounted: keepMounted, tabPrerender: tabPrerender, tabKeepMounted: tabKeepMounted, visitedKeys: visitedKeys, panelStyles: explicitPanel?.styles, qa: explicitPanel?.qa, qaVal: explicitPanel?.qaVal }, tab.key));
        }) }));
}
// =============================================================================
// TabPanel Component (for explicit panel API)
// =============================================================================
function TabPanel(_props) {
    // This component is never rendered directly - it's used for configuration
    return null;
}
TabPanel.displayName = 'CubeTabPanel';
// =============================================================================
// TabList Component (for explicit list API)
// =============================================================================
function TabList(_props) {
    // This component is never rendered directly - it's used for configuration
    return null;
}
TabList.displayName = 'CubeTabList';
// =============================================================================
// Main Tabs Component
// =============================================================================
function TabsComponent(props, ref) {
    const { label = 'Tabs', defaultActiveKey, activeKey, size, type = 'default', onChange, onDelete, onTitleChange, showActionsOnHover, children, styles, prefix, suffix, prerender = false, keepMounted = false, qa = 'Tabs', renderPanel, panelCacheKeys, } = props;
    // DOM element ref (separate from imperative handle ref)
    const elementRef = useRef(null);
    const listRef = useRef(null);
    const scrollRef = useRef(null);
    // Track visited tabs for keepMounted functionality
    const visitedKeysRef = useRef(new Set());
    // =========================================================================
    // Tab Title Editing State
    // =========================================================================
    const [editingKey, setEditingKey] = useState(null);
    const [editValue, setEditValue] = useState('');
    const startEditing = useCallback((key, currentTitle) => {
        // Also select the tab being edited
        onChange?.(key);
        chainRaf(() => {
            setEditingKey(key);
            setEditValue(currentTitle);
        }, 2);
    }, [onChange]);
    const cancelEditing = useCallback(() => {
        setEditingKey(null);
        setEditValue('');
    }, []);
    const submitEditing = useCallback((key, newTitle, tabOnTitleChange) => {
        const trimmed = newTitle.trim();
        if (trimmed) {
            // Tab-level callback takes precedence
            if (tabOnTitleChange) {
                tabOnTitleChange(trimmed);
            }
            else if (onTitleChange) {
                onTitleChange(key, trimmed);
            }
        }
        setEditingKey(null);
        setEditValue('');
    }, [onTitleChange]);
    // Parse children to extract tabs and explicit panels
    const { parsedTabs, explicitPanels, hasAnyContent } = useMemo(() => {
        const childArray = Children.toArray(children);
        const tabs = [];
        const panels = new Map();
        let hasExplicitList = false;
        let tabChildren = [];
        // Check for explicit Tabs.List / Tabs.Panel structure
        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 no explicit list, use direct Tab children
        if (!hasExplicitList) {
            tabChildren = childArray;
        }
        // Parse Tab elements
        let hasContent = panels.size > 0;
        for (const child of tabChildren) {
            if (isTabElement(child)) {
                // Get key from the element's key prop or id prop (convert to string)
                const key = getRawKey(child) ?? child.props.id;
                if (key != null) {
                    const { id: _id, children: tabChildren, ...tabProps } = child.props;
                    tabs.push({
                        ...tabProps,
                        key,
                        content: tabChildren,
                    });
                    if (tabChildren != null) {
                        hasContent = true;
                    }
                }
            }
        }
        return {
            parsedTabs: tabs,
            explicitPanels: panels,
            hasAnyContent: hasContent,
        };
    }, [children]);
    // Clean up visitedKeys when tabs are removed
    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]);
    // Create collection items for React Stately
    const collectionItems = useMemo(() => {
        return parsedTabs.map((tab) => (_jsx(CollectionItem, { textValue: typeof tab.title === 'string' ? tab.title : String(tab.key), children: tab.title }, tab.key)));
    }, [parsedTabs]);
    // Create a lookup map for tab data
    const tabDataMap = useMemo(() => {
        const map = new Map();
        for (const tab of parsedTabs) {
            map.set(tab.key, tab);
        }
        return map;
    }, [parsedTabs]);
    // Expose ref API for programmatic control (separate from DOM ref)
    useImperativeHandle(ref, () => ({
        element: elementRef.current,
        startEditing: (key) => {
            // Convert key to string for internal lookup
            const keyStr = String(key);
            const tabData = tabDataMap.get(keyStr);
            if (tabData?.isEditable) {
                const titleText = typeof tabData.title === 'string'
                    ? tabData.title
                    : String(tabData.key);
                startEditing(keyStr, titleText);
            }
        },
        cancelEditing,
    }), [tabDataMap, startEditing, cancelEditing]);
    // Determine disabled keys
    const disabledKeys = useMemo(() => {
        return new Set(parsedTabs.filter((tab) => tab.isDisabled).map((tab) => tab.key));
    }, [parsedTabs]);
    // Handle selection change
    const handleSelectionChange = useEvent((key) => {
        // Convert to string for internal tracking
        visitedKeysRef.current.add(String(key));
        onChange?.(key);
    });
    // Create aria props for useTabListState
    const ariaProps = useMemo(() => ({
        selectedKey: activeKey,
        defaultSelectedKey: defaultActiveKey,
        onSelectionChange: handleSelectionChange,
        disabledKeys,
        children: collectionItems,
        'aria-label': label,
    }), [
        activeKey,
        defaultActiveKey,
        handleSelectionChange,
        disabledKeys,
        collectionItems,
        label,
    ]);
    // Create state using useTabListState
    const state = useTabListState(ariaProps);
    // Track initial selected key for visited tabs
    useEffect(() => {
        if (state.selectedKey != null) {
            visitedKeysRef.current.add(String(state.selectedKey));
        }
    }, [state.selectedKey]);
    // Get tablist props from react-aria
    const { tabListProps } = useTabList(ariaProps, state, listRef);
    // Tab indicator for default type
    const indicatorStyle = useTabIndicator(listRef, state.selectedKey, type === 'default');
    // Tiny scrollbar for horizontal scrolling (not for radio type)
    const isTinyScrollbar = type !== 'radio';
    const { handleHStyle, hasOverflowX, isScrolling, isAtStartX, isAtEndX } = useTinyScrollbar(scrollRef, isTinyScrollbar);
    const mods = useMemo(() => ({
        type,
        deletable: !!onDelete,
        scrolling: isScrolling,
        'fade-left': !isAtStartX,
        'fade-right': !isAtEndX,
    }), [type, onDelete, isScrolling, isAtStartX, isAtEndX]);
    return (_jsxs(_Fragment, { children: [_jsxs(TabsElement, { ref: elementRef, qa: qa, mods: mods, styles: styles, style: handleHStyle, "data-size": size, children: [prefix ? _jsx("div", { "data-element": "Prefix", children: prefix }) : null, _jsxs("div", { "data-element": "ScrollWrapper", children: [_jsx("div", { ref: scrollRef, "data-element": "Scroll", children: _jsxs("div", { ...tabListProps, ref: listRef, "data-element": "Container", children: [[...state.collection].map((item) => {
                                            // Convert item.key to string for internal lookup
                                            const tabData = tabDataMap.get(String(item.key));
                                            if (!tabData)
                                                return null;
                                            const isItemEditing = editingKey === item.key;
                                            return (_jsx(TabButton, { item: item, state: state, tabData: tabData, type: type, size: size, showActionsOnHover: showActionsOnHover, isEditing: isItemEditing, editValue: isItemEditing ? editValue : '', onDelete: onDelete, onEditValueChange: setEditValue, onStartEditing: startEditing, onSubmitEditing: submitEditing, onCancelEditing: cancelEditing }, item.key));
                                        }), indicatorStyle && (_jsx(TabIndicatorElement, { style: {
                                                left: indicatorStyle.left,
                                                width: indicatorStyle.width,
                                            } }))] }) }), isTinyScrollbar && hasOverflowX && _jsx("div", { "data-element": "ScrollbarH" })] }), suffix ? _jsx("div", { "data-element": "Suffix", children: suffix }) : null] }), renderPanel && (_jsx(CachedPanelRenderer, { parsedTabs: parsedTabs, explicitPanels: explicitPanels, state: state, renderPanel: renderPanel, panelCacheKeys: panelCacheKeys, prerender: prerender, keepMounted: keepMounted, visitedKeys: visitedKeysRef.current })), !renderPanel &&
                hasAnyContent &&
                parsedTabs.map((tab) => {
                    // Use explicit panel if provided, otherwise use tab's content
                    const explicitPanel = explicitPanels.get(tab.key);
                    const content = explicitPanel?.content ?? tab.content;
                    if (content == null)
                        return null;
                    return (_jsx(TabPanelRenderer, { tabKey: tab.key, state: state, content: content, prerender: prerender, keepMounted: 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));
                })] }));
}
// =============================================================================
// Exports
// =============================================================================
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.
 * When using `activeKey`, `onChange`, etc., be aware that numeric keys will be
 * converted to their string equivalents.
 *
 * @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>
 *
 * @example
 * // Optimized lazy rendering with renderPanel
 * <Tabs
 *   defaultActiveKey="tab1"
 *   renderPanel={(key) => {
 *     switch (key) {
 *       case 'tab1': return <ExpensiveComponent />;
 *       case 'tab2': return <AnotherExpensive />;
 *       default: return null;
 *     }
 *   }}
 * >
 *   <Tab key="tab1" title="Tab 1" />
 *   <Tab key="tab2" title="Tab 2" />
 * </Tabs>
 */
export const Tabs = Object.assign(_Tabs, {
    Tab,
    List: TabList,
    Panel: TabPanel,
});
export { Tab, TabList, TabPanel };

        