All files / lib/util dropdown.ts

98.21% Statements 55/56
85.71% Branches 6/7
100% Functions 2/2
98.21% Lines 55/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 571x 1x 1x 1x 1x 1x 27x 27x 27x 27x 27x 27x 27x 27x 27x 27x 27x 27x 27x 27x   27x 27x 27x 27x 27x 27x 27x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 27x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 27x  
import getCaretPosition from 'textarea-caret';
import { AcceptedInputType, DropdownPosition } from '../types';
import { getInputSelectionStart } from './input';
import { DROPDOWN_MARGIN, DROPDOWN_WIDTH } from '../constants';
 
export function getDropdownPosition(
    input: AcceptedInputType,
    dropdownHeight: number
): DropdownPosition {
    const { top, left } = getCaretPosition(
        input,
        getInputSelectionStart(input)
    );
 
    // Calculate base positioning
    const inputRect = input.getBoundingClientRect();
    const baseLeft = left + input.offsetLeft + DROPDOWN_MARGIN;
    
    // Check for horizontal overflow and adjust if necessary
    const adjustedLeft = baseLeft + DROPDOWN_WIDTH > window.innerWidth
        ? window.innerWidth - DROPDOWN_WIDTH - DROPDOWN_MARGIN
        : baseLeft;
 
    // Is there place for the dropdown below the caret?
    if (
        inputRect.top + top + dropdownHeight + 2 * DROPDOWN_MARGIN <=
        window.innerHeight
    ) {
        return {
            toTop: false,
            top: top + input.offsetTop + DROPDOWN_MARGIN,
            left: adjustedLeft,
            width: DROPDOWN_WIDTH,
            height: dropdownHeight,
        };
    }
 
    // If there is place for the dropdown above the caret, show it there
    if (inputRect.top + top - dropdownHeight - DROPDOWN_MARGIN > 0) {
        return {
            toTop: true,
            top: top + input.offsetTop - dropdownHeight - DROPDOWN_MARGIN,
            left: adjustedLeft,
            width: DROPDOWN_WIDTH,
            height: dropdownHeight,
        };
    }
 
    return {
        toTop: true,
        top: input.offsetTop - inputRect.top + DROPDOWN_MARGIN,
        left: adjustedLeft,
        width: DROPDOWN_WIDTH,
        height: window.innerHeight - 2 * DROPDOWN_MARGIN,
    };
}