@i-novus/ui-core
Version:
Базовые UI компоненты
133 lines (132 loc) • 5.75 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { forwardRef, useCallback, useEffect, useState } from 'react';
import classNames from 'classnames';
import { useConfigProvider } from '../../core';
import { OptionList } from './components';
import { defaultOptions, noOption, noOptions } from './constants';
import { DropdownInput } from './DropdownInput';
import { MultipleSelector } from './MultipleSelector';
// FIXME: Требуется отсмотреть компоненту. Собрать корнер кейсы и провести рефакторинг. Внутри слишком много внутренних состояний.
// eslint-disable-next-line sonarjs/cognitive-complexity
export const InputSelect = forwardRef((props, ref) => {
const { prefix, className, selectedInputValue = '', value, options = defaultOptions, onChange, onSearch, onOpen, onScroll, style, hasSearch = false, visible = true, multiple = false, disabled = false, emptyText, ...restProps } = props;
const [dropdownOptions, setDropdownOptions] = useState(defaultOptions);
const [selectedOptions, setSelectedOptions] = useState(defaultOptions);
const [inputValue, setInputValue] = useState(selectedInputValue);
const { getPrefix } = useConfigProvider();
const prefixCls = getPrefix(prefix);
const onOptionClick = useCallback((newValue, event) => {
setSelectedOptions(newValue);
if (multiple) {
// @ts-ignore
onChange(newValue, event);
}
else {
const [selectedOption] = newValue;
if (selectedOption) {
// @ts-ignore
onChange(selectedOption, event);
setInputValue(selectedOption.label);
}
}
}, [multiple, onChange]);
const onInputValueChange = useCallback((newValue, event) => {
setInputValue(newValue);
if (!newValue && !multiple) {
setSelectedOptions([]);
// @ts-ignore
onChange?.(null, event);
}
if (hasSearch && onSearch) {
// @ts-ignore
onSearch(newValue, event);
return;
}
if (!newValue) {
setDropdownOptions(options);
}
else {
const filteredOptions = options
.filter(option => option.label.toLowerCase().includes(newValue.toLowerCase()));
setDropdownOptions(filteredOptions.length
? filteredOptions
: noOptions);
}
}, [hasSearch, multiple, onChange, onSearch, options]);
const onCloseTag = useCallback((id, evt) => {
setSelectedOptions((prev) => {
const newSelectedOptions = prev.filter(item => item.id !== id);
// @ts-ignore
onChange?.(newSelectedOptions, evt);
return newSelectedOptions;
});
}, [onChange]);
const onCloseDropdown = useCallback(() => {
if (!inputValue) {
return;
}
if ((!multiple && !selectedOptions.length) || multiple) {
setInputValue('');
}
else {
const [selected] = selectedOptions;
setInputValue(selected?.label || '');
}
}, [multiple, inputValue, selectedOptions]);
const handleOpen = useCallback((event) => {
if (onOpen) {
onOpen(event);
}
setDropdownOptions(options);
}, [onOpen, options]);
const handleClearAllSelectedOptions = useCallback((event) => {
event.stopPropagation();
onInputValueChange('');
setSelectedOptions(defaultOptions);
// @ts-ignore
onChange?.(defaultOptions, event);
}, [onInputValueChange, onChange]);
useEffect(() => {
if (Array.isArray(value)) {
setSelectedOptions(value);
}
else if (value && typeof value === 'object' && 'label' in value) {
setSelectedOptions([value]);
setInputValue(value.label);
}
else {
setSelectedOptions([]);
setInputValue('');
}
}, [value]);
useEffect(() => {
setDropdownOptions(options?.length ? options : [{
...noOption,
label: emptyText || noOption.label,
}]);
}, [emptyText, options]);
if (!visible) {
return null;
}
if (multiple) {
return (_jsx("div", { className: classNames(className, `${prefixCls}-multiple-selector`), style: style, children: _jsx(MultipleSelector, { ...restProps, disabled: disabled, ref: ref, prefixCls: prefixCls, value: inputValue, onChange: onInputValueChange, onOpen: handleOpen, dropdownInnerComponent: OptionList, onClose: onCloseDropdown, dropdownInnerComponentProps: {
options: dropdownOptions,
selected: selectedOptions,
onOptionClick,
multiple,
onScroll,
}, tagListProps: {
selectedOptions,
onCloseTag,
handleClearAllSelectedOptions,
} }) }));
}
return (_jsx("div", { className: classNames(className, `${prefixCls}-input-select`), style: style, children: _jsx(DropdownInput, { ...restProps, disabled: disabled, ref: ref, prefixCls: prefixCls, value: inputValue, onChange: onInputValueChange, onOpen: handleOpen, dropdownInnerComponent: OptionList, onClose: onCloseDropdown, dropdownInnerComponentProps: {
options: dropdownOptions,
selected: selectedOptions,
onOptionClick,
multiple,
onScroll,
} }) }));
});
InputSelect.displayName = 'InputSelect';