/* eslint-disable no-nested-ternary */
/* eslint-disable eqeqeq */
import React, { isValidElement } from 'react';
import cls from 'classnames';
import { noop } from 'lodash';
import { IconFilter } from '@douyinfe/semi-icons';
import { cssClasses } from '@douyinfe/semi-foundation/table/constants';
import Dropdown, { DropdownProps } from '../dropdown';
import { Trigger, Position } from '../tooltip';
import { Radio } from '../radio';
import { Checkbox } from '../checkbox';
import {
FilterIcon,
Filter,
OnFilterDropdownVisibleChange,
RenderFilterDropdownItem
} from './interface';
function renderDropdown(props: RenderDropdownProps = {}, nestedElem: React.ReactNode = null, level = 0) {
const {
filterMultiple = true,
filters = [],
filteredValue = [],
filterDropdownVisible,
onSelect = noop,
onFilterDropdownVisibleChange = noop,
trigger = 'click',
position = 'bottom',
renderFilterDropdownItem,
} = props;
const dropdownProps: DropdownProps = {
...props,
onVisibleChange: (visible: boolean) => onFilterDropdownVisibleChange(visible),
trigger,
position,
render: (
{Array.isArray(filters) &&
filters.map((filter, index) => {
const changeFn = (e: React.MouseEvent) => {
const domEvent = e && e.nativeEvent;
if (domEvent) {
// Block this event to prevent the pop-up layer from closing
domEvent.stopImmediatePropagation();
// Prevent bubbling and default events to prevent label click events from triggering twice
domEvent.stopPropagation();
domEvent.preventDefault();
}
let values = [...filteredValue];
const included = values.includes(filter.value);
const idx = values.indexOf(filter.value);
if (idx > -1) {
values.splice(idx, 1);
} else if (filterMultiple) {
values.push(filter.value);
} else {
values = [filter.value];
}
return onSelect({
value: filter.value,
filteredValue: values,
included: !included,
domEvent,
});
};
const checked = filteredValue.includes(filter.value);
const { text } = filter;
const { value } = filter;
const key = `${level}_${index}`;
const dropdownItem =
typeof renderFilterDropdownItem === 'function' ?
renderFilterDropdownItem({
onChange: changeFn,
filterMultiple,
value,
text,
checked,
filteredValue,
level,
}) :
null;
let item =
dropdownItem && React.isValidElement(dropdownItem) ? (
React.cloneElement(dropdownItem, { key })
) : (
{filterMultiple ? (
{text}
) : (
{text}
)}
);
if (Array.isArray(filter.children) && filter.children.length) {
const childrenDropdownProps = {
...props,
filters: filter.children,
trigger: 'hover' as const,
position: 'right' as const,
};
delete childrenDropdownProps.filterDropdownVisible;
item = renderDropdown(childrenDropdownProps, item, level + 1);
}
return item;
})}
),
};
if (filterDropdownVisible != null) {
dropdownProps.visible = filterDropdownVisible;
}
return (
{nestedElem}
);
}
export interface ColumnFilterProps {
prefixCls?: string;
filteredValue?: any[];
filterIcon?: FilterIcon;
filterDropdown?: React.ReactElement;
renderFilterDropdown?: (props: RenderDropdownProps, options: { iconElem: React.ReactNode }) => React.ReactElement;
filterDropdownProps?: DropdownProps;
onFilterDropdownVisibleChange?: OnFilterDropdownVisibleChange;
onSelect?: (data: OnSelectData) => void;
}
export default function ColumnFilter(props: ColumnFilterProps = {}): React.ReactElement {
const {
prefixCls = cssClasses.PREFIX,
filteredValue,
filterIcon = 'filter',
renderFilterDropdown,
filterDropdownProps,
} = props;
let { filterDropdown = null } = props;
const finalCls = cls(`${prefixCls}-column-filter`, {
on: Array.isArray(filteredValue) && filteredValue.length,
});
let iconElem;
if (typeof filterIcon === 'function') {
iconElem = filterIcon(Array.isArray(filteredValue) && filteredValue.length > 0);
} else if (isValidElement(filterIcon)) {
iconElem = filterIcon;
} else {
iconElem = (
{'\u200b'/* ZWSP(zero-width space) */}
);
}
const renderProps = {
...props,
...filterDropdownProps,
};
filterDropdown = React.isValidElement(filterDropdown) ?
filterDropdown :
typeof renderFilterDropdown === 'function' ?
renderFilterDropdown(renderProps, { iconElem }) :
renderDropdown(renderProps, iconElem);
return filterDropdown;
}
export interface OnSelectData {
value: any;
filteredValue: any;
included: boolean;
domEvent: React.MouseEvent;
}
export interface RenderDropdownProps {
filterMultiple?: boolean;
filters?: Filter[];
filteredValue?: any[];
filterDropdownVisible?: boolean;
onSelect?: (data: OnSelectData) => void;
onFilterDropdownVisibleChange?: OnFilterDropdownVisibleChange;
trigger?: Trigger;
position?: Position;
renderFilterDropdownItem?: RenderFilterDropdownItem;
}