import React, { useState, useRef, ReactElement, useEffect } from 'react'; import { Button, Row, Col } from 'antd'; import { Input as AntdInput, InputNumber as AntdInputNumber } from 'antd'; import classNames from 'classnames'; import { InputProps } from 'antd/lib/input'; import { InputState } from 'antd/lib/input/Input'; import { InputNumberProps } from 'antd/lib/input-number'; export type FilterType = { title?: string, label?: string, elem?: React.ReactElement, render?: React.ReactElement, [propName: string]: any, spanMultiple?: number, // 暂不支持,间距没有适配 } const Filter:React.FunctionComponent<{label:string}> = (props) => { return ( <> {props.label ? { props.label } : null} {props.children ? { props.children } : null} ) } const Arrow:React.FunctionComponent<{onClick?:() => void, isDown:boolean, style?:React.CSSProperties}> = ({onClick, isDown, style}) => { return ( { onClick && onClick(); }} > ) } const FoldButton:React.FunctionComponent<{isFold: boolean, onClick:Function, style?:any}> = ({isFold, onClick, style}) => { return ( ) } /* PageFilterContext: 用于存储 PageFilter 下的 onSearch */ const PageFilterContext = React.createContext(null); class Input extends React.Component { static contextType = PageFilterContext; static Group = AntdInput.Group; render() { const onSearch = (this.context && typeof this.context === 'function') ? this.context : null; return ( <> (onSearch && onSearch())} {...this.props}> ); } } class InputNumber extends React.Component { static contextType = PageFilterContext; static Group = AntdInput.Group; render() { const onSearch = (this.context && typeof this.context === 'function') ? this.context : null; return ( <> (onSearch && onSearch())} {...this.props}> ); } } type PageFiltersProps = { filters: (FilterType|React.ReactElement)[], onResetFilters?: () => void, onSearch?: () => void | Promise, className?: string, loading?:boolean, [propName: string]: any, } const ANTD_GRID = 24; const EVERY_WIDTH = 310+24; // width + paddingRight interface StaticComponents { Input: typeof Input, InputNumber: typeof InputNumber, } const PageFilter:React.FunctionComponent & StaticComponents = ({ filters, onResetFilters, onSearch, className, loading: propsLoading, ...rest }) => { const [ isFold, setIsFold ] = useState(true); const [ loading, setLoading ] = useState(propsLoading || false); const [ colCnt, setColCnt ] = useState(3); const showLoading = typeof propsLoading == 'boolean' ? propsLoading : loading; const averageCol = ANTD_GRID / colCnt; const isLastCol = (index) => (index % colCnt === colCnt - 1); const container = useRef(null); useEffect(() => { function handleResize() { const colCnt = Math.floor(container.current.offsetWidth / EVERY_WIDTH); setColCnt(Math.min(4, colCnt)); } handleResize(); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); const needFoldButton = filters.length + 1 > colCnt; const filtersShow = isFold ? filters.slice(0, colCnt-1) : filters; // 1 is left for search button const filtersLength = filtersShow.length; return (
{ (filtersShow) .map((filter, index) => { const { title, label, elem, render } = filter as FilterType; const renderFilter = title == null && label == null && elem == null && render == null ? (filter as ReactElement) : null; // 如果 filter 直接传入为 ReactElement const getSelectStyle:any = (index) => ({ paddingRight: isLastCol(index) ? '0' : '24px', }); return (
{ renderFilter ? renderFilter : ( <> {(title || label) ? { title || label } : null} {elem || render ? { elem || render } : null} ) }
) }) } { (onResetFilters || onSearch) && { onResetFilters && ( ) } { onSearch && ( ) } } { needFoldButton && ( { setIsFold(!isFold); }} isFold={isFold}> ) }
) } PageFilter.Input = Input PageFilter.InputNumber = InputNumber export { PageFilter, Filter, Arrow, }