toggle-corp/react-store

View on GitHub
v2/Input/SelectInputBase/Options/index.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React, { useCallback } from 'react';
import { _cs } from '@togglecorp/fujs';

import FloatingContainer from '../../../View/FloatingContainer';
import ListView from '../../../View/ListView';

import { OptionKey } from '../../../types';

import Option from './Option';

import styles from './styles.scss';

interface Props<T, K extends OptionKey> {
    className?: string;
    data: T[];
    focusedKey?: K;
    keySelector: (datum: T) => K;
    labelSelector: (datum: T) => string | number;
    onBlur: () => void;
    onInvalidate: (e: HTMLDivElement) => Record<string, unknown>;
    onOptionClick: (key: K) => void;
    onOptionFocus: (key: K) => void;
    optionLabelSelector?: (datum: T) => React.ReactNode;
    parentRef: React.RefObject<HTMLElement>;
    emptyComponent: React.ComponentType<unknown>;
    emptyWhenFilterComponent: React.ComponentType<unknown>;
    value?: K;
    filtered: boolean;
    pending: boolean;
    children?: React.ReactNode;
}

function Options<T, K extends OptionKey>(props: Props<T, K>) {
    const {
        className: classNameFromProps,
        data,
        focusedKey,
        keySelector,
        labelSelector,
        onBlur,
        onInvalidate,
        onOptionClick,
        onOptionFocus,
        optionLabelSelector,
        parentRef,
        emptyComponent: EmptyComponent,
        emptyWhenFilterComponent: EmptyWhenFilterComponent,
        value,
        filtered,
        pending,
        children,
    } = props;

    const rendererParams = useCallback(
        (key: K, option: T) => {
            const label = optionLabelSelector
                ? optionLabelSelector(option)
                : labelSelector(option);

            const isActive = key === value;
            const isFocused = key === focusedKey;

            return {
                children: label,
                isActive,
                isFocused,
                onClick: onOptionClick,
                onFocus: onOptionFocus,
                optionKey: key,
            };
        },
        [
            focusedKey,
            labelSelector,
            onOptionClick,
            onOptionFocus,
            optionLabelSelector,
            value,
        ],
    );

    const className = _cs(
        classNameFromProps,
        styles.options,
        'options',
    );

    return (
        <FloatingContainer
            onBlur={onBlur}
            onInvalidate={onInvalidate}
            parentRef={parentRef}
            className={className}
        >
            <ListView
                data={data}
                keySelector={keySelector}
                rendererParams={rendererParams}
                renderer={Option}
                emptyComponent={EmptyComponent}
                emptyWhenFilterComponent={EmptyWhenFilterComponent}
                filtered={filtered}
                pending={pending}
                className={styles.list}
            />
            {children}
        </FloatingContainer>
    );
}

Options.defaultProps = {
    data: [],
    filtered: false,
    pending: false,
};

export default Options;