Neovici/cosmoz-autocomplete

View on GitHub
src/autocomplete/use-overflow.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { useLayoutEffect, useState, useMemo } from '@pionjs/pion';
import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
import { raf } from './util';

const overflow = (host: HTMLElement) => {
    const chips = host.shadowRoot!.querySelectorAll<HTMLElement>('.chip');
    const badge = host.shadowRoot!.querySelector<HTMLElement>('.badge')!;
    badge.hidden = true;
    for (const chip of chips) {
        chip.hidden = false;
    }
    const input = host.shadowRoot!.querySelector('cosmoz-input')!;
    const limit = input.shadowRoot
        ?.querySelector('.control')
        ?.getBoundingClientRect();
    let i;
    for (i = 0; i < chips.length; i++) {
        const chip = chips[i];
        const bounds = chip.getBoundingClientRect();
        const isIn = bounds.x + bounds.width <= limit!.x + limit!.width - 24;
        if (!isIn) {
            break;
        }
    }

    const overflown = chips.length - i;
    badge.querySelector('span')!.textContent = '+' + overflown.toString();
    badge.hidden = overflown < 1;

    for (; i < chips.length; i++) {
        chips[i].hidden = true;
    }
};

export const useOverflow = <I>({
    value,
    active,
    wrap,
    limit,
}: {
    value: I[];
    active?: boolean;
    wrap?: boolean;
    limit?: number;
}) => {
    const host = useHost();
    // eslint-disable-next-line eqeqeq
    const enabled = !(wrap || limit == 1);
    const doRaf = useMemo(() => raf(() => overflow(host)), []);
    const [width, setWidth] = useState(0);

    useLayoutEffect(() => {
        if (!enabled) return;
        const input = host.shadowRoot!.querySelector('cosmoz-input')!;
        const observer = new ResizeObserver((e) => {
            setWidth(e[0].contentRect.width);
        });
        observer.observe(input);
        return () => observer.disconnect();
    }, [enabled]);

    useLayoutEffect(
        () => (enabled ? doRaf() : undefined),
        [enabled, width, active, value],
    );
};