uui/components/filters/FilterPickerBody.tsx (105 lines of code) (raw):
import * as React from 'react';
import { DataRowProps, DataSourceListProps, DataSourceState, DropdownBodyProps, isMobile, PickerFilterConfig, usePrevious } from '@epam/uui-core';
import { PickerBodyBaseProps, PickerInputBaseProps, usePickerInput } from '@epam/uui-components';
import {
DataPickerRow,
PickerItem,
DataPickerBody,
DataPickerFooter,
PickerInputProps,
PickerItemProps,
DataPickerRowProps,
DataPickerFooterProps,
DataPickerBodyProps,
} from '../pickers';
import { settings } from '../../settings';
const pickerHeight = 300;
type FilterPickerBodyProps<TItem, TId> = DropdownBodyProps & PickerInputBaseProps<TItem, TId> & PickerFilterConfig<any> & {
showSearch?: boolean;
};
export function FilterPickerBody<TItem, TId>({
highlightSearchMatches = true,
...restProps
}: FilterPickerBodyProps<TItem, TId>) {
const props = { ...restProps, highlightSearchMatches };
const shouldShowBody = () => props.isOpen;
const {
view,
getName,
isSingleSelect,
getRows,
dataSourceState,
getFooterProps,
getPickerBodyProps,
getListProps,
handleDataSourceValueChange,
} = usePickerInput<TItem, TId, PickerInputProps<TItem, TId>>({ ...props, shouldShowBody });
const prevValue = usePrevious(props.value);
const prevOpened = usePrevious(props.isOpen);
React.useLayoutEffect(() => {
if (prevOpened === props.isOpen && props.isOpen
&& prevValue !== props.value && props.value !== props.emptyValue
&& props.selectionMode === 'single'
) {
props.onClose();
}
}, [props.value]);
const getSubtitle = ({ path }: DataRowProps<TItem, TId>, { search }: DataSourceState) => {
if (!search) return;
return path
.map(({ value }) => getName(value))
.filter(Boolean)
.join(' / ');
};
const renderItem = (item: TItem, rowProps: DataRowProps<TItem, TId>, dsState?: DataSourceState) => {
const { flattenSearchResults } = view.getConfig();
return (
<PickerItem
title={ getName(item) }
highlightSearchMatches={ highlightSearchMatches }
{ ...(flattenSearchResults ? { subtitle: getSubtitle(rowProps, dsState) } : {}) }
dataSourceState={ dsState }
size={ settings.sizes.filtersPanel.pickerInput.body.default as PickerItemProps<any, any>['size'] }
{ ...rowProps }
/>
);
};
const onSelect = (row: DataRowProps<TItem, TId>) => {
handleDataSourceValueChange((currentDataSourceState) => ({ ...currentDataSourceState, search: '', selectedId: row.id }));
};
const renderRow = (rowProps: DataRowProps<TItem, TId>, dsState: DataSourceState) => {
if (rowProps.isSelectable && isSingleSelect() && props.editMode !== 'modal') {
rowProps.onSelect = onSelect;
}
return props.renderRow ? (
props.renderRow(rowProps, dataSourceState)
) : (
<DataPickerRow
{ ...rowProps }
key={ rowProps.rowKey }
size={ settings.sizes.filtersPanel.pickerInput.body.default as DataPickerRowProps<any, any>['size'] }
padding="12"
renderItem={ (item, itemProps) => renderItem(item, itemProps, dsState) }
/>
);
};
const renderFooter = () => {
return <DataPickerFooter { ...getFooterProps() } size={ settings.sizes.filtersPanel.pickerInput.body.default as DataPickerFooterProps<any, any>['size'] } />;
};
const renderBody = (bodyProps: DataSourceListProps & Omit<PickerBodyBaseProps, 'rows'>, rows: DataRowProps<TItem, TId>[]) => {
const renderedDataRows = rows.map((props) => renderRow(props, dataSourceState));
const maxHeight = isMobile() ? document.documentElement.clientHeight : props.maxBodyHeight || pickerHeight;
const maxWidth = isMobile() ? undefined : 360;
return (
<>
<DataPickerBody
{ ...bodyProps }
selectionMode={ props.selectionMode }
rows={ renderedDataRows }
maxHeight={ maxHeight }
maxWidth={ maxWidth }
searchSize={ settings.sizes.filtersPanel.pickerInput.body.default as DataPickerBodyProps['searchSize'] }
editMode="dropdown"
/>
{renderFooter()}
</>
);
};
const rows = getRows();
return renderBody({ ...getPickerBodyProps(rows), ...getListProps(), showSearch: props.showSearch ?? true }, rows);
}