/* @oracle/oraclejet-preact: undefined */
import { useRef, useCallback } from 'preact/hooks';
import { b as addKeys, d as removeKeys, c as containsKey, a as addKey, r as removeKey } from './keys-49c92dbb.js';
import { g as getIsSelectionPending } from './textSelectionUtils-a6554a42.js';

/**
 * @license
 * Copyright (c) %FIRST_YEAR% %CURRENT_YEAR%, Oracle and/or its affiliates.
 * The Universal Permissive License (UPL), Version 1.0
 * as shown at https://oss.oracle.com/licenses/upl/
 * @ignore
 */
/**
 * The hook for handling selection for collection ListView that is used as itemRenderer inside SelectSingle/SelectMultiple.
 *
 * @param keyExtractor function to extract the key based on provided element
 * @param selectedKeys the currently selected keys
 * @param selectionMode the selection mode
 * @param isSelectionRequired true if empty selected key is not allowed, false otherwise
 * @param getIndexByKey function to get the index based on the given key
 * @param getKeysByRange function to get the keys based on the given startIndex and endIndex
 * @param getPrevNextKey function to get the previous/next key in the vertical direction based on the current key
 * @param currentKey the current key
 * @param onChange callback function that is invoked when selection has changed.
 * @param onRangeChange callback function that is invoked when the selection range has changed.
 * @param scrollToKey function to scroll the item with the key to be visible
 */
function useDropDownSelection(keyExtractor, selectedKeys, selectionMode, isSelectionRequired, getIndexByKey, getKeysByRange, getPrevNextKey, currentKey, onChange, onRangeChange, scrollToKey) {
    // the start key of the range selection
    const anchorKey = useRef();
    // the previous end key of the range selection, i.e. the last key during shift+click/arrow keys
    const cursorKey = useRef();
    const onClick = useCallback((event) => {
        if (getIsSelectionPending()) {
            return;
        }
        const itemKey = keyExtractor(event.target);
        if (itemKey == null) {
            return;
        }
        if (selectionMode === 'single') {
            toggleSelection(event, selectedKeys, selectionMode, isSelectionRequired, itemKey, onChange);
        }
        else if (selectionMode === 'multiple') {
            // when anchorKey is undefined, i.e. shift+click is the first interaction, we should do toggle selection instead
            if (!event.shiftKey || anchorKey.current === undefined) {
                // reset anchorKey and cursorKey, a new range could happen after the click
                anchorKey.current = itemKey;
                cursorKey.current = undefined;
                toggleSelection(event, selectedKeys, selectionMode, isSelectionRequired, itemKey, onChange);
            }
            else {
                const newCursorKey = rangeSelection(event, selectedKeys, isSelectionRequired, anchorKey.current, cursorKey.current, itemKey, getIndexByKey, getKeysByRange, onChange, onRangeChange);
                if (newCursorKey !== undefined) {
                    cursorKey.current = itemKey;
                }
            }
        }
    }, [
        keyExtractor,
        selectedKeys,
        selectionMode,
        isSelectionRequired,
        getIndexByKey,
        getKeysByRange,
        onChange,
        onRangeChange
    ]);
    const onKeyDown = useCallback((event) => {
        // prevent default (propagation) for keyDown to space bar causing container to scroll
        if (event.key === ' ') {
            event.preventDefault();
            return;
        }
        if (selectionMode === 'multiple') {
            if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
                return;
            }
            const itemKey = getPrevNextKey(currentKey, event.key === 'ArrowUp')();
            if (itemKey == null) {
                return;
            }
            // keep visible
            scrollToKey?.(itemKey);
            if (!event.shiftKey) {
                // reset anchorKey and cursorKey, a new range could happen after the arrow keys
                anchorKey.current = itemKey;
                cursorKey.current = undefined;
            }
            else {
                // Avoid increasing range of selection text selection with arrow keys
                event.preventDefault();
                // when anchorKey is undefined, i.e. shift+arrow was the first interaction
                if (anchorKey.current === undefined) {
                    anchorKey.current = currentKey;
                }
                const newCursorKey = rangeSelection(event, selectedKeys, isSelectionRequired, anchorKey.current, cursorKey.current, itemKey, getIndexByKey, getKeysByRange, onChange, onRangeChange);
                if (newCursorKey !== undefined) {
                    cursorKey.current = newCursorKey;
                }
            }
        }
    }, [
        getPrevNextKey,
        currentKey,
        selectedKeys,
        selectionMode,
        isSelectionRequired,
        getIndexByKey,
        getKeysByRange,
        onChange,
        onRangeChange,
        scrollToKey
    ]);
    const onKeyUp = useCallback((event) => {
        if (event.key === ' ' || event.key === 'Enter') {
            const itemKey = keyExtractor(event.target);
            if (itemKey == null) {
                return;
            }
            toggleSelection(event, selectedKeys, selectionMode, isSelectionRequired, itemKey, onChange);
        }
    }, [keyExtractor, selectedKeys, selectionMode, isSelectionRequired, onChange]);
    const onPointerDown = useCallback((event) => {
        if (anchorKey.current !== undefined && event.shiftKey && selectionMode === 'multiple') {
            // Avoid text selection during shift+click, unless when anchorKey is undefined, i.e. shift+click
            // is the first interaction, which should do toggle selection and update currentKey during initial focus
            event.preventDefault();
        }
    }, [selectionMode]);
    const dropDownSelectionProps = selectionMode === 'none' || onChange == null
        ? {}
        : { onClick, onKeyDown, onKeyUp, onPointerDown };
    return { dropDownSelectionProps };
}
/**
 * The helper function for range selection
 */
const rangeSelection = (event, selectedKeys, isSelectionRequired, anchorKey, cursorKey, itemKey, getIndexByKey, getKeysByRange, onChange, onRangeChange) => {
    if (anchorKey !== undefined) {
        if (cursorKey !== undefined && cursorKey !== itemKey) {
            let keySet = selectedKeys;
            const startIndex = getIndexByKey(anchorKey);
            const endIndex = getIndexByKey(itemKey);
            const previousEndIndex = getIndexByKey(cursorKey);
            if (startIndex === -1 || endIndex === -1 || previousEndIndex === -1) {
                return undefined;
            }
            const minIndex = Math.min(startIndex, endIndex);
            const maxIndex = Math.max(startIndex, endIndex);
            // add keys that are within the range
            const keys = getKeysByRange(minIndex, maxIndex + 1);
            keySet = addKeys(keySet, keys);
            // only remove keys when previousEndIndex is out of range
            if (previousEndIndex < minIndex || previousEndIndex > maxIndex) {
                const keys = previousEndIndex < minIndex
                    ? getKeysByRange(previousEndIndex, minIndex)
                    : getKeysByRange(maxIndex + 1, previousEndIndex + 1);
                keySet = removeKeys(keySet, keys, isSelectionRequired);
            }
            if (selectedKeys != keySet && onChange) {
                onChange({ value: keySet, target: event.target });
                if (event.type === 'click') {
                    event.stopPropagation();
                }
            }
        }
        else {
            // if no cursorKey was set, meaning the previous interaction was not shift+click/arrow,
            // we can do range selection directly
            onRangeChange?.({
                value: { start: anchorKey, end: itemKey },
                eventType: event.type === 'click' ? 'shiftClick' : 'shiftArrowKeys'
            });
        }
        return itemKey;
    }
    return undefined;
};
const toggleSelection = (event, selectedKeys, selectionMode, isSelectionRequired, itemKey, onChange) => {
    let keySet = selectedKeys;
    const selected = containsKey(keySet, itemKey);
    if (!selected) {
        if (selectionMode === 'single') {
            keySet = { all: false, keys: new Set([itemKey]) };
        }
        else {
            keySet = addKey(keySet, itemKey);
        }
    }
    else {
        keySet = removeKey(keySet, itemKey, isSelectionRequired);
    }
    if (selectedKeys != keySet && onChange) {
        onChange({ value: keySet, target: event.target });
        if (event.type === 'click') {
            event.stopPropagation();
        }
    }
};

export { useDropDownSelection as u };
//# sourceMappingURL=useDropDownSelection-28285b15.js.map
