/* @oracle/oraclejet-preact: undefined */
'use strict';

var jsxRuntime = require('preact/jsx-runtime');
var hooks = require('preact/hooks');
var mergeProps = require('./mergeProps-e3da7237.js');
var classNames = require('./classNames-c14c6ef3.js');
var clientUtils = require('./clientUtils-ef5e20ce.js');
var useId = require('./useId-6c0eeb27.js');
var UNSAFE_NavigationList_themes_NavigationListStyles_css = require('./UNSAFE_NavigationList/themes/NavigationListStyles.css.js');
var collectionUtils = require('./collectionUtils-f1d3183f.js');
var useCollectionFocusRing = require('./useCollectionFocusRing-bed0aa16.js');
var useCurrentKey = require('./useCurrentKey-1b9e3382.js');
var useContextMenuGesture = require('./useContextMenuGesture-530ef8dd.js');
var useTranslationBundle = require('./useTranslationBundle-12dd087d.js');
var TabBarContextMenu = require('./TabBarContextMenu-d9bf65c2.js');
var compat = require('preact/compat');
var useTestId = require('./useTestId-4f53d561.js');
var HiddenAccessible = require('./HiddenAccessible-087eb49a.js');
var LiveRegion = require('./LiveRegion-62ce9ac7.js');
require('./UNSAFE_Text/themes/TextStyles.css.js');
var useNavigationListItem = require('./useNavigationListItem-b97e76d5.js');
require('./Flex-3a257bc3.js');
require('./logger-2b636482.js');


require('./UNSAFE_Badge/themes/redwood/BadgeVariants.css.js');
require('preact');
require('./LayerHost-3cd73603.js');


require('./hooks/UNSAFE_useTooltip/themes/redwood/TooltipContentVariants.css.js');
require('./tooltipUtils-2bc15136.js');

require('./UNSAFE_NavigationList/themes/NavigationListItemStyles.css.js');

require('./UNSAFE_NavigationList/themes/redwood/NavigationListItemVariants.css.js');
require('./BaseButton-d8f96bfa.js');
require('./ButtonLabelLayout-c876923f.js');

const ITEM_SELECTOR = '[role="tab"]';
const REMOVE_ICON_SELECTOR = '[data-oj-navigationlist-item-remove-icon]';
const TOUCH_OFFSET_VALUE = 40;
const menuPropGestureStates = {
    mouse: {
        initialFocus: 'menu',
        placement: 'bottom-start',
        offsetValue: 0
    },
    keyboard: {
        initialFocus: 'firstItem',
        placement: 'bottom-start',
        offsetValue: 0
    },
    touch: {
        initialFocus: 'menu',
        placement: 'end',
        offsetValue: TOUCH_OFFSET_VALUE
    }
};
const initialMenuProps = {
    isOpen: false,
    initialFocus: 'menu',
    placement: 'bottom-start',
    offsetValue: 0,
    anchorRef: { current: null }
};
/*TODO: JET-58534. Create a hook to share some logic between navlist and tabbar. Hook will be used inside this one. */
function useNavigationList({ containerRef, selection, onRemove, onSelectionChange, children, contextMenuConfig }) {
    const translations = useTranslationBundle.useTranslationBundle('@oracle/oraclejet-preact');
    const [currentKey, setCurrentKey] = hooks.useState(selection);
    const onCurrentKeyChange = hooks.useCallback((detail) => {
        setCurrentKey(detail.value);
    }, []);
    const { currentKeyProps } = useCurrentKey.useCurrentKey((element) => onRemove
        ? extractOnlyItemKey(element, ITEM_SELECTOR, REMOVE_ICON_SELECTOR)
        : collectionUtils.keyExtractor(element, ITEM_SELECTOR), false, false, collectionUtils.getPrevNextKeyUsingRef(containerRef, currentKey, true, ITEM_SELECTOR), collectionUtils.getPrevNextKeyUsingRef(containerRef, currentKey, false, ITEM_SELECTOR), undefined, undefined, currentKey, onCurrentKeyChange);
    const [showFocusRing, focusRingProps] = useCollectionFocusRing.useCollectionFocusRing(containerRef, [
        'Home',
        'End',
        'ArrowUp',
        'ArrowDown'
    ]);
    const onFocus = hooks.useCallback(() => {
        if (containerRef.current && currentKey === undefined) {
            const key = collectionUtils.getFirstVisibleKey(containerRef.current, ITEM_SELECTOR);
            if (key) {
                setCurrentKey(key);
            }
        }
    }, [currentKey, containerRef]);
    const onFocusProps = { onFocus };
    const prevNavItems = hooks.useRef();
    hooks.useEffect(() => {
        if (containerRef.current) {
            const navListItemKeys = Array.from(containerRef.current.querySelectorAll(ITEM_SELECTOR), (elem) => collectionUtils.getKey(elem));
            if (currentKey != null && navListItemKeys.indexOf(currentKey) !== -1) {
                const navListItem = collectionUtils.findElementByKey(containerRef.current, currentKey, ITEM_SELECTOR);
                if (navListItem.scrollIntoViewIfNeeded) {
                    // for some browsers, we'll need the non-standard scrollIntoViewIfNeeded
                    navListItem.scrollIntoViewIfNeeded();
                }
                else {
                    navListItem.scrollIntoView({ block: 'nearest' });
                }
            }
            else {
                if (currentKey && navListItemKeys.indexOf(currentKey) === -1) {
                    prevNavItems.current
                        ? setCurrentKey(findNextCurrentKey(currentKey, navListItemKeys, prevNavItems.current))
                        : setCurrentKey(navListItemKeys[0]);
                }
                prevNavItems.current = navListItemKeys;
            }
        }
    }, [children, currentKey, containerRef]);
    const onKeyDown = hooks.useCallback((event) => {
        if ((event.key === 'Home' || event.key === 'End') && containerRef.current && currentKey) {
            const navListItemKey = Array.from(containerRef.current.querySelectorAll(ITEM_SELECTOR), (elem) => collectionUtils.getKey(elem));
            onCurrentKeyChange?.({
                value: navListItemKey[event.key === 'Home' ? 0 : navListItemKey.length - 1]
            });
        }
        if (currentKey && (event.key === 'Enter' || event.key === ' ')) {
            // Prevent default to avoid page scrolling on Space (and native actions on Enter)
            event.preventDefault();
            onSelectionChange?.({
                value: currentKey,
                reason: 'keyboard'
            });
        }
        if (currentKey && event.key === 'Delete') {
            onRemove?.({ value: currentKey });
        }
    }, [currentKey, onSelectionChange, onRemove, onCurrentKeyChange, containerRef]);
    const [contextMenuContext, setContextMenuContext] = hooks.useState();
    const [menuProps, setMenuProps] = hooks.useState(initialMenuProps);
    const [accStatusInfo, setAccStatusInfo] = hooks.useState();
    const { triggerProps } = useContextMenuGesture.useContextMenuGesture(({ gesture, anchor, target }) => {
        let anchorBasedOnGesture = anchor;
        let itemKey = currentKey;
        if (gesture === 'keyboard') {
            //We find the element where the position of the menu is going to be based of
            const elem = collectionUtils.findElementByKey(containerRef.current, currentKey, ITEM_SELECTOR);
            //We set the correct anchor
            anchorBasedOnGesture = elem ? elem : anchor;
        }
        else {
            //We search for the key using the target of the event
            const key = collectionUtils.keyExtractor(target, ITEM_SELECTOR);
            //On touch devices, the keyExtractor returns null because target of touch event is the entire tabbar. Hence we make use of currentkey since the context menu is always launched from selected item and its key is currentKey
            itemKey = key != null ? key : currentKey;
        }
        let isRemovable = false;
        if (containerRef.current) {
            isRemovable = getItemAttribute(itemKey, containerRef.current, REMOVE_ICON_SELECTOR) != null;
        }
        const defaultContext = TabBarContextMenu.getDefaultContextMenu({
            // For default menu items the existence of REMOVE_ICON_SELECTOR is the indicator that it is removable because we render the default menu in touch devices not the application.
            // Furthermore in corepack due to delegations onRemove is always defined as it is a even handler hence not a good check for isRemovable.
            isRemovable: isRemovable,
            handleRemove: onRemove,
            handleReorder: undefined,
            itemKey: itemKey,
            tabKeys: undefined,
            // As direction is only needed for reorder to switch the labels
            direction: undefined,
            itemLabels: {
                labelRemove: isRemovable ? translations.tabbar_labelRemove() : undefined
            },
            handleAccStatus: (detail) => {
                const removeItemLabel = getItemLabel(detail.removedKey, containerRef.current);
                const removeStatus = isRemovable && detail.removedKey ? ` Removed ${removeItemLabel}` : '';
                setAccStatusInfo(removeStatus);
            }
        });
        setContextMenuContext(defaultContext);
        setMenuProps({
            ...menuPropGestureStates[gesture],
            anchorRef: { current: anchorBasedOnGesture },
            // This is set so that when no contextMenuConfig and when items is not removable we need not open it.
            isOpen: contextMenuConfig != null
        });
    }, {
        isDisabled: !contextMenuConfig //If there is no a context menu renderer we disable the hook
    });
    const handleCloseContextMenu = hooks.useCallback((detail) => {
        //Focus has to be set on the current target that was obtained
        //during context menu gesture when menu is dismissed or item is "selected"
        if (detail.reason === 'dismissed' || detail.reason === 'itemAction') {
            setCurrentKey(contextMenuContext?.itemKey);
            containerRef.current?.focus();
        }
        // We close the menu.The only prop that matters here is isOpen
        setMenuProps({ ...initialMenuProps });
    }, [containerRef, contextMenuContext?.itemKey]);
    const contextMenuDescriptionId = 'contextMenu_' + hooks.useId();
    const contextMenuDescription = translations.tabbar_labelContextMenu();
    return {
        showFocusRing,
        currentKey,
        onCurrentKeyChange,
        onKeyDown,
        menuProps: { ...menuProps, onClose: handleCloseContextMenu },
        contextMenuContext,
        contextMenuDescription,
        contextMenuDescriptionId,
        accStatusInfo,
        containerHandlers: mergeProps.mergeProps(focusRingProps, currentKeyProps, onFocusProps, triggerProps)
    };
}
// Utility that returns the value for a attribute related to the role="tab" item.
const getItemAttribute = (itemKey, root, attribute) => {
    const navItem = collectionUtils.findElementByKey(root, itemKey, ITEM_SELECTOR);
    if (navItem) {
        const tabBarItemAttribute = navItem.querySelector(attribute);
        return tabBarItemAttribute;
    }
    return;
};
// Utility that returns the visible inner text inside the role="tab" item.
const getItemLabel = (itemKey, root) => {
    const tabBarItem = collectionUtils.findElementByKey(root, itemKey, ITEM_SELECTOR);
    if (tabBarItem) {
        return tabBarItem.innerText;
    }
    return;
};
const extractOnlyItemKey = (element, itemSelector, itemEliminator) => {
    const navigationListItem = element.closest(itemSelector);
    const removeButton = element.closest(itemEliminator);
    return navigationListItem?.contains(removeButton) ? null : collectionUtils.keyExtractor(element, itemSelector);
};
const findNextCurrentKey = (currentKey, currNavs, prevNavs) => {
    const index = prevNavs.indexOf(currentKey);
    if (index > 0) {
        const nextIndex = index === prevNavs.length - 1 ? index - 1 : index + 1;
        const nextKey = prevNavs[nextIndex];
        if (currNavs.indexOf(nextKey) !== -1) {
            return nextKey;
        }
    }
    // update current key to be the first one if we can't find a suitable next key
    return currNavs[0];
};

const NavigationList = compat.forwardRef(({ children, selection, edge = 'start', onSelectionChange, onRemove, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelLedBy, testId, display = 'standard' }, ref) => {
    const containerRef = hooks.useRef(null);
    const isMobileDevice = clientUtils.isMobile();
    const defaultContextMenuConfig = hooks.useMemo(() => {
        return isMobileDevice
            ? {
                itemsRenderer: (context) => {
                    //Only if context is available, it is a mobile device and it is removable item, we will return remove context menu item
                    if (context) {
                        const isRemovableItem = getItemAttribute(context.itemKey, containerRef.current, REMOVE_ICON_SELECTOR) !=
                            null;
                        if (isRemovableItem) {
                            const defaultItems = context.defaultMenuItems;
                            return jsxRuntime.jsx(jsxRuntime.Fragment, { children: defaultItems });
                        }
                    }
                    return null;
                }
            }
            : undefined;
    }, [isMobileDevice]);
    const { showFocusRing, currentKey, onCurrentKeyChange, containerHandlers, onKeyDown, contextMenuContext, menuProps, contextMenuDescription, contextMenuDescriptionId, accStatusInfo } = useNavigationList({
        containerRef: containerRef,
        selection,
        onRemove,
        onSelectionChange,
        children,
        contextMenuConfig: defaultContextMenuConfig
    });
    const eventProps = { onKeyDown };
    const navigationListClass = classNames.classNames([UNSAFE_NavigationList_themes_NavigationListStyles_css.navigationListStyles.uListStyle]);
    const navigationListItemPrefix = useId.useId() + '_';
    const testIdProps = useTestId.useTestId(testId);
    //Allows to call focus on rootRef without having to expose it
    compat.useImperativeHandle(ref, () => ({
        focus: () => {
            if (containerRef.current) {
                containerRef.current.focus();
            }
        },
        blur: () => {
            if (containerRef.current) {
                containerRef.current.focus();
            }
        }
    }));
    return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { "aria-label": ariaLabel, "aria-labelledby": ariaLabelLedBy, role: "tablist", ref: containerRef, "aria-orientation": 'vertical', tabIndex: 0, "aria-activedescendant": currentKey ? navigationListItemPrefix + currentKey : '', ...mergeProps.mergeProps(eventProps, containerHandlers), ...testIdProps, class: navigationListClass, children: jsxRuntime.jsx(useNavigationListItem.NavigationListContext.Provider, { value: {
                        selection,
                        display,
                        onSelectionChange,
                        onCurrentKeyChange,
                        currentKey,
                        showFocusRing,
                        navigationListItemPrefix,
                        onRemove,
                        edge
                    }, children: children }) }), defaultContextMenuConfig && contextMenuDescriptionId && contextMenuDescription && (jsxRuntime.jsx("span", { id: contextMenuDescriptionId, children: jsxRuntime.jsx(HiddenAccessible.HiddenAccessible, { children: contextMenuDescription }) })), defaultContextMenuConfig && accStatusInfo && jsxRuntime.jsx(LiveRegion.LiveRegion, { children: accStatusInfo }), defaultContextMenuConfig && (jsxRuntime.jsx(TabBarContextMenu.TabBarContextMenu, { ...menuProps, contextMenuConfig: defaultContextMenuConfig, contextMenuContext: contextMenuContext }))] }));
});

exports.NavigationList = NavigationList;
//# sourceMappingURL=NavigationList-d0d74565.js.map
