var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import React from 'react';
import { useEventListener } from '../../effects/EventListener';
import { useI18nContext } from '../../state/I18n';
import { useListNavigation } from '../../state/ListNavigation';
import { addSubcomponents } from '../../utils/addSubcomponents';
import { usingHookOrDefault } from '../../utils/usingHookOrDefault';
import { useOverlayTriggerContext } from '../OverlayTrigger';
import { Search as SearchBase } from '../Search';
import { useSearch } from '../Search/Search.hooks';
import { StyledFooter, StyledGroup, StyledHeader, StyledItem, StyledMenu, StyledOptions, StyledSearch, StyledWrapper, } from '../MenuImperative/MenuImperative.styles';
var onScrollBottomThreshold = 8;
export var isItem = function (element) { return element.type === Item; };
function scrollIntoView(index, element) {
    if (!element.parentElement) {
        return;
    }
    if (index === 0) {
        element.parentElement.scrollTop = 0;
        return;
    }
    var offsetTop = element.offsetTop, clientHeight = element.clientHeight;
    var _a = element.parentElement, scrollTop = _a.scrollTop, parentHeight = _a.clientHeight;
    if (offsetTop < scrollTop) {
        element.parentElement.scrollTop = offsetTop;
    }
    else if (offsetTop + clientHeight > scrollTop + parentHeight) {
        element.parentElement.scrollTop = offsetTop - parentHeight + clientHeight;
    }
}
function checkBottomScrollPosition(callback) {
    return function onScroll(e) {
        if (callback &&
            e.currentTarget instanceof HTMLElement &&
            e.currentTarget.scrollTop >=
                e.currentTarget.scrollHeight -
                    e.currentTarget.clientHeight -
                    onScrollBottomThreshold) {
            callback(e);
        }
    };
}
function noop() { }
export function useMenu(_a) {
    var _b = _a.isSelectable, isSelectable = _b === void 0 ? isItem : _b, externalKeyHandlerRef = _a.keyHandlerRef, _c = _a.multiple, multiple = _c === void 0 ? false : _c, onScrollBottom = _a.onScrollBottom, _d = _a.onSearch, onSearch = _d === void 0 ? noop : _d, _e = _a.onSelect, onSelect = _e === void 0 ? noop : _e, _f = _a.scrollable, scrollable = _f === void 0 ? true : _f;
    var listNavigation = useListNavigation({
        circular: !onScrollBottom,
        initialIndex: 0,
        size: 0,
    });
    var search = useSearch({
        onChange: function (e) {
            listNavigation.set(0);
            onSearch(e);
        },
        typeahead: true,
    });
    var highlighted = React.useRef(null);
    var keyHandlerRef = externalKeyHandlerRef || React.createRef();
    var selectItem = React.useCallback(function (selection) {
        onSelect(selection);
    }, [onSelect]);
    var onKeyDown = React.useCallback(function (e) {
        var key = e.key;
        if (key === 'ArrowDown' || key === 'Down') {
            listNavigation.increment();
            e.preventDefault();
        }
        else if (key === 'ArrowUp' || key === 'Up') {
            listNavigation.decrement();
            e.preventDefault();
        }
        else if (key === 'Enter') {
            if (highlighted.current) {
                highlighted.current.click();
            }
        }
    }, [listNavigation]);
    // TODO - deprecate keyhandlerRef, this is just for backwards compatibility since we already exposed it
    React.useEffect(function () {
        var el;
        if (keyHandlerRef.current) {
            keyHandlerRef.current.addEventListener('keydown', onKeyDown);
            el = keyHandlerRef.current;
        }
        return function () {
            if (el) {
                el.removeEventListener('keydown', onKeyDown);
            }
        };
    }, [keyHandlerRef, onKeyDown]);
    return {
        domHandlers: {
            onKeyDown: function (e) {
                return onKeyDown(e.nativeEvent);
            },
        },
        highlighted: highlighted,
        isSelectable: isSelectable,
        listNavigation: listNavigation,
        multiple: multiple,
        onScrollBottom: onScrollBottom,
        scrollable: scrollable,
        selectItem: selectItem,
        search: search,
    };
}
export var MenuHookContext = React.createContext(null);
export function useMenuHookContext() {
    var context = React.useContext(MenuHookContext);
    if (context === null) {
        throw new Error('Cannot find `MenuHook` context, please wrap your component in `<MenuHookContext.Provider>`');
    }
    return context;
}
/**

 Menus are used in conjunction with components that contain dropdowns.
 For example, multi select, single select, and dropdown.

 @since 10.19.0

 @see [Storybook](https://procore.github.io/core/latest/?path=/story/menu--basic-props)

 @see [Design Guidelines](https://design.procore.com/menu)

 */
export var Menu_ = React.forwardRef(function Menu(_a, ref) {
    var children = _a.children, _b = _a.UNSAFE_closesOnSelect, UNSAFE_closesOnSelect = _b === void 0 ? true : _b, _c = _a.isSelectable, isSelectable = _c === void 0 ? isItem : _c, keyHandlerRef = _a.keyHandlerRef, onScrollBottom = _a.onScrollBottom, _d = _a.onSelect, onSelect = _d === void 0 ? noop : _d, _e = _a.scrollable, scrollable = _e === void 0 ? true : _e, usingHook = _a.usingHook, props = __rest(_a, ["children", "UNSAFE_closesOnSelect", "isSelectable", "keyHandlerRef", "onScrollBottom", "onSelect", "scrollable", "usingHook"]);
    // Don't be tempted to put this in useMenu. In order for hooks to be portable
    // across the dom tree, they should not contain context consumers.
    var overlayTriggerContext = useOverlayTriggerContext();
    var menu = usingHookOrDefault(usingHook, useMenu)({
        isSelectable: isSelectable,
        keyHandlerRef: keyHandlerRef,
        onScrollBottom: onScrollBottom,
        onSelect: onSelect,
        scrollable: scrollable,
    });
    React.useEffect(function () {
        // When unmounting, reset the listNavigation index and set
        // the current highlighted item to null. we only want to run this once,
        // so don't pass any dependencies
        return function () {
            menu.search.clear();
            menu.listNavigation.reset();
            menu.highlighted.current = null;
        };
    }, 
    /* eslint-disable */ [] /* eslint-enable */);
    function selectItem(selection) {
        menu.selectItem(selection);
        if (UNSAFE_closesOnSelect) {
            overlayTriggerContext.hide(selection.event);
        }
    }
    return (React.createElement(MenuHookContext.Provider, { value: __assign(__assign({}, menu), { selectItem: selectItem }) },
        React.createElement(StyledWrapper, __assign({}, menu.domHandlers, { ref: ref, tabIndex: 0 }),
            React.createElement(StyledMenu, __assign({}, props), children))));
});
export var Group = React.forwardRef(function Group(_a, ref) {
    var children = _a.children, _b = _a.clickable, clickable = _b === void 0 ? false : _b, item = _a.item, props = __rest(_a, ["children", "clickable", "item"]);
    return (React.createElement(StyledGroup, __assign({}, props, { ref: ref, onClick: function (event) {
            // TODO: implement selecting groups?
        }, "$clickable": clickable }), children));
});
export var Item = React.forwardRef(function Item(_a, ref) {
    var children = _a.children, _b = _a.index, index = _b === void 0 ? 0 : _b, item = _a.item, _c = _a.onClick, onClick = _c === void 0 ? noop : _c, _d = _a.selected, selected = _d === void 0 ? false : _d, _e = _a.suggested, suggested = _e === void 0 ? false : _e, onMouseMove = _a.onMouseMove, props = __rest(_a, ["children", "index", "item", "onClick", "selected", "suggested", "onMouseMove"]);
    var _f = useMenuHookContext(), highlighted = _f.highlighted, listNavigation = _f.listNavigation, multiple = _f.multiple, selectItem = _f.selectItem;
    var itemRef = ref || React.useRef();
    var isHighlighted = index === listNavigation.index;
    React.useEffect(function () {
        // When mounting, check if this item is selected or suggested, and if
        // it is, then set it as the current index and scroll to it.
        // We only want to run this once, so don't pass any dependencies
        if (multiple) {
            // don't do this behavior in multiple mode
            return;
        }
        if (itemRef.current && (selected || suggested)) {
            highlighted.current = itemRef.current;
            listNavigation.set(index);
        }
    }, 
    /* eslint-disable */ [] /* eslint-enable */);
    React.useEffect(function () {
        // If this item has become highlighted, scroll to it
        if (itemRef.current && isHighlighted) {
            highlighted.current = itemRef.current;
            scrollIntoView(index, itemRef.current);
        }
    }, [highlighted, index, isHighlighted, itemRef]);
    return (React.createElement(StyledItem, __assign({}, props, { onClick: function (event) {
            listNavigation.set(index);
            selectItem({ event: event.nativeEvent, item: item, group: false });
            onClick(event);
        }, onMouseMove: function (event) {
            if (onMouseMove) {
                onMouseMove(event);
            }
            if (listNavigation.index !== index) {
                listNavigation.set(index);
            }
        }, ref: itemRef, "$highlighted": isHighlighted, "$selected": selected }), children));
});
export var Options = React.forwardRef(function Options(_a, ref) {
    var children = _a.children, className = _a.className, _b = _a.scrollable, scrollable = _b === void 0 ? true : _b;
    var _c = useMenuHookContext(), listNavigation = _c.listNavigation, isSelectable = _c.isSelectable, onScrollBottom = _c.onScrollBottom, menuScrollable = _c.scrollable;
    var optionsRef = ref || React.createRef();
    var size = React.Children.toArray(children).filter(isSelectable).length;
    React.useEffect(function () {
        listNavigation.setSize(size);
    }, [listNavigation, size]);
    useEventListener({
        event: 'scroll',
        handler: checkBottomScrollPosition(onScrollBottom),
        scope: optionsRef,
    });
    var index = 0;
    return (React.createElement(StyledOptions, { className: className, ref: optionsRef, "$scrollable": menuScrollable || scrollable }, React.Children.map(children, function (child) {
        if (React.isValidElement(child) && isSelectable(child)) {
            var selectableIndex = index;
            index = index + 1;
            return React.cloneElement(child, {
                index: selectableIndex,
            });
        }
        return child;
    })));
});
export function Search(_a) {
    var className = _a.className, _b = _a.i18nScope, i18nScope = _b === void 0 ? 'core.menu' : _b, placeholder = _a.placeholder, props = __rest(_a, ["className", "i18nScope", "placeholder"]);
    var menu = useMenuHookContext();
    var I18n = useI18nContext();
    return (React.createElement(StyledSearch, { className: className },
        React.createElement(SearchBase, __assign({}, props, { autoFocus: true, placeholder: placeholder || I18n.t('search', { scope: i18nScope }), typeahead: true, usingHook: menu.search }))));
}
export var Header = React.forwardRef(function Header(_a, ref) {
    var props = __rest(_a, []);
    return React.createElement(StyledHeader, __assign({ ref: ref }, props));
});
export var Footer = React.forwardRef(function Footer(_a, ref) {
    var _b = _a.padding, padding = _b === void 0 ? 'md lg' : _b, props = __rest(_a, ["padding"]);
    return React.createElement(StyledFooter, __assign({ ref: ref, padding: padding }, props));
});
Menu_.displayName = 'Menu';
Footer.displayName = 'Menu.Footer';
Group.displayName = 'Menu.Group';
Header.displayName = 'Menu.Header';
Item.displayName = 'Menu.Item';
Options.displayName = 'Menu.Options';
Search.displayName = 'Menu.Search';
export var Menu = addSubcomponents({
    Footer: Footer,
    Group: Group,
    Header: Header,
    Item: Item,
    Options: Options,
    Search: Search,
}, Menu_);
export default Menu;
//# sourceMappingURL=Menu.js.map