src/components/controls/InputSelect/PopupItems.jsx
import React from 'react';
import PropTypes from 'prop-types';
import { Badge, DropdownItem } from 'reactstrap';
import scrollIntoView from 'scroll-into-view-if-needed';
import Icon from '../../snippets/Icon/Icon';
import CheckboxN2O from '../Checkbox/CheckboxN2O';
import propsResolver from '../../../utils/propsResolver';
import { find } from 'lodash';
import cx from 'classnames';
import { findDOMNode } from 'react-dom';
import { groupData, inArray, isDisabled } from './utils';
/**
* Компонент попапа для {@link InputSelect}
* @reactProps {array} options - массив данных
* @reactProps {string} activeLabel - активный лейбел
* @reactProps {function} setActiveLabel - смена активного лейбла
* @reactProps {string} valueFieldId - значение ключа value в данных
* @reactProps {string} labelFieldId - значение ключа label в данных
* @reactProps {string} iconFieldId - поле для иконки
* @reactProps {string} imageFieldId - поле для картинки
* @reactProps {string} groupFieldId - поле для группировки
* @reactProps {string} badgeFieldId - поле для баджей
* @reactProps {string} badgeColorFieldId - поле для цвета баджа
* @reactProps {array} disabledValues - неактивные данные
* @reactProps {function} onSelect - callback при выборе элемента
* @reactProps {string} format - формат
* @reactProps {boolean} hasCheckboxes - флаг наличия чекбоксов
* @reactProps {array} selected - выбранные элементы
* @reactProps {function} onRemoveItem - callback при удаление элемента
* @reactProps {function} setActiveValueId
* @reactProps {string} activeValueId
*/
function PopupItems({
options,
activeLabel,
setActiveLabel,
labelFieldId,
iconFieldId,
valueFieldId,
imageFieldId,
disabledValues,
selected,
groupFieldId,
hasCheckboxes,
format,
badgeFieldId,
badgeColorFieldId,
onRemoveItem,
onSelect,
setActiveValueId,
activeValueId,
}) {
const handleRef = item => {
if (item) {
const el = findDOMNode(item);
if (el.classList.contains('active')) {
scrollIntoView(el, { scrollMode: 'if-needed', block: 'nearest' });
}
}
};
const handleItemClick = ({ target }, item) => {
if (target.nodeName === 'LABEL') return false;
inArray(selected, item) ? onRemoveItem(item) : onSelect(item);
};
const displayTitle = item => {
if (format) return propsResolver({ format }, item).format;
return item[labelFieldId];
};
const renderSingleItem = item => {
return (
<DropdownItem
className={cx('n2o-eclipse-content', {
active: activeValueId === item[valueFieldId],
})}
onMouseOver={() =>
setActiveValueId && setActiveValueId(item[valueFieldId])
}
disabled={!hasCheckboxes && isDisabled(item, selected, disabledValues)}
ref={handleRef}
key={item.id}
onClick={e => handleItemClick(e, item)}
title={displayTitle(item)}
toggle={false}
>
{iconFieldId && renderIcon(item, iconFieldId)}
{imageFieldId && renderImage(item, imageFieldId)}
{hasCheckboxes ? renderCheckbox(item, selected) : renderLabel(item)}
{badgeFieldId && renderBadge(item, badgeFieldId, badgeColorFieldId)}
</DropdownItem>
);
};
const renderIcon = (item, iconFieldId) =>
item[iconFieldId] && <Icon name={item[iconFieldId]} />;
const renderImage = (item, imageFieldId) =>
item[imageFieldId] && <img src={item[imageFieldId]} />;
const renderBadge = (item, badgeFieldId, badgeColorFieldId) => (
<Badge color={item[badgeColorFieldId]}>{item[badgeFieldId]}</Badge>
);
const renderCheckbox = (item, selected) => (
<CheckboxN2O
value={inArray(selected, item)}
label={displayTitle(item)}
inline
/>
);
const renderLabel = item => (
<span className="text-cropped">{displayTitle(item)}</span>
);
const renderSingleItems = options =>
options.map((item, i) => renderSingleItem(item, i));
const renderGroupedItems = (options, groupFieldId) => {
const groupedData = groupData(options, groupFieldId);
return Object.keys(groupedData).map(key =>
renderGroup(key, groupedData[key])
);
};
const renderGroup = (key, value) => (
<React.Fragment key={key}>
<DropdownItem key={key} header>
{key}
</DropdownItem>
{renderSingleItems(value)}
<DropdownItem divider />
</React.Fragment>
);
const renderMenuItems = options =>
groupFieldId
? renderGroupedItems(options, groupFieldId)
: renderSingleItems(options);
const renderMenu = options => {
if (options && options[0] !== null && options.length) {
return renderMenuItems(options);
}
return <DropdownItem header>Ничего не найдено</DropdownItem>;
};
return <React.Fragment>{renderMenu(options)}</React.Fragment>;
}
PopupItems.propTypes = {
options: PropTypes.array.isRequired,
activeLabel: PropTypes.string,
setActiveLabel: PropTypes.func,
valueFieldId: PropTypes.string.isRequired,
labelFieldId: PropTypes.string.isRequired,
iconFieldId: PropTypes.string,
imageFieldId: PropTypes.string,
groupFieldId: PropTypes.string,
badgeFieldId: PropTypes.string,
badgeColorFieldId: PropTypes.string,
disabledValues: PropTypes.array,
onSelect: PropTypes.func,
onScrollEnd: PropTypes.func,
selected: PropTypes.array,
hasCheckboxes: PropTypes.bool,
onRemoveItem: PropTypes.func,
format: PropTypes.string,
setActiveValueId: PropTypes.func,
activeValueId: PropTypes.string,
};
export default PopupItems;