@ -1,9 +1,8 @@
import * as React from 'react' ;
import * as PropTypes from 'prop-types' ;
import classNames from 'classnames' ;
import omit from 'omit.js' ;
import Spin , { SpinProps } from '../spin' ;
import { ConfigConsumer , ConfigConsumerProps , RenderEmptyHandler } from '../config-provider' ;
import { RenderEmptyHandler , ConfigContext } from '../config-provider' ;
import Pagination , { PaginationConfig } from '../pagination' ;
import { Row } from '../grid' ;
@ -58,73 +57,49 @@ export interface ListLocale {
emptyText : React.ReactNode | ( ( ) = > React . ReactNode ) ;
}
interface ListState {
paginationCurrent : number ;
paginationSize : number ;
export interface ListConsumerProps {
grid? : any ;
itemLayout? : string ;
}
export default class List < T > extends React . Component < ListProps < T > , ListState > {
static Item : typeof Item = Item ;
export const ListContext = React . createContext < ListConsumerProps > ( { } ) ;
static childContextTypes = {
grid : PropTypes.any ,
itemLayout : PropTypes.string ,
} ;
export const ListConsumer = ListContext . Consumer ;
static defaultProps = {
dataSource : [ ] ,
bordered : false ,
split : true ,
loading : false ,
pagination : false as ListProps < any > [ 'pagination' ] ,
} ;
function List < T > ( { pagination , . . . props } : ListProps < T > ) {
const paginationObj = pagination && typeof pagination === 'object' ? pagination : { } ;
const [ paginationCurrent , setPaginationCurrent ] = React . useState (
paginationObj . defaultCurrent || 1 ,
) ;
const [ paginationSize , setPaginationSize ] = React . useState ( paginationObj . defaultPageSize || 10 ) ;
defaultPaginationProps = {
const { getPrefixCls , renderEmpty , direction } = React . useContext ( ConfigContext ) ;
const defaultPaginationProps = {
current : 1 ,
total : 0 ,
} ;
private keys : { [ key : string ] : string } = { } ;
private onPaginationChange = this . triggerPaginationEvent ( 'onChange' ) ;
private onPaginationShowSizeChange = this . triggerPaginationEvent ( 'onShowSizeChange' ) ;
constructor ( props : ListProps < T > ) {
super ( props ) ;
const { pagination } = props ;
const paginationObj = pagination && typeof pagination === 'object' ? pagination : { } ;
this . state = {
paginationCurrent : paginationObj.defaultCurrent || 1 ,
paginationSize : paginationObj.defaultPageSize || 10 ,
} ;
}
getChildContext() {
return {
grid : this.props.grid ,
itemLayout : this.props.itemLayout ,
} ;
}
const keys : { [ key : string ] : string } = { } ;
triggerPaginationEvent ( eventName : string ) {
const triggerPaginationEvent = ( eventName : string ) = > {
return ( page : number , pageSize : number ) = > {
const { pagination } = this . props ;
this . setState ( {
paginationCurrent : page ,
paginationSize : pageSize ,
} ) ;
setPaginationCurrent ( page ) ;
setPaginationSize ( pageSize ) ;
if ( pagination && ( pagination as any ) [ eventName ] ) {
( pagination as any ) [ eventName ] ( page , pageSize ) ;
}
} ;
}
} ;
const onPaginationChange = triggerPaginationEvent ( 'onChange' ) ;
const onPaginationShowSizeChange = triggerPaginationEvent ( 'onShowSizeChange' ) ;
renderItem = ( item : any , index : number ) = > {
const { renderItem , rowKey } = this . props ;
if ( ! renderItem ) return null ;
const renderItem = ( item : any , index : number ) = > {
const { rowKey } = props ;
if ( ! props . renderItem ) return null ;
let key ;
@ -140,138 +115,136 @@ export default class List<T> extends React.Component<ListProps<T>, ListState> {
key = ` list-item- ${ index } ` ;
}
this . keys [ index ] = key ;
keys [ index ] = key ;
return renderItem ( item , index ) ;
return props . renderItem ( item , index ) ;
} ;
isSomethingAfterLastItem() {
const { loadMore , pagination , footer } = this . props ;
const isSomethingAfterLastItem = ( ) = > {
const { loadMore , footer } = props ;
return ! ! ( loadMore || pagination || footer ) ;
}
} ;
renderEmpty = ( prefixCls : string , renderEmpty : RenderEmptyHandler ) = > {
const { locale } = this . props ;
const renderEmptyFunc = ( prefixCls : string , renderEmptyHandler : RenderEmptyHandler ) = > {
const { locale } = props ;
return (
< div className = { ` ${ prefixCls } -empty-text ` } >
{ ( locale && locale . emptyText ) || renderEmpty ( 'List' ) }
{ ( locale && locale . emptyText ) || renderEmptyHandler ( 'List' ) }
< / div >
) ;
} ;
renderList = ( { getPrefixCls , renderEmpty , direction } : ConfigConsumerProps ) = > {
const { paginationCurrent , paginationSize } = this . state ;
const {
prefixCls : customizePrefixCls ,
bordered ,
split ,
className ,
children ,
itemLayout ,
loadMore ,
pagination ,
grid ,
dataSource = [ ] ,
size ,
header ,
footer ,
loading ,
. . . rest
} = this . props ;
const prefixCls = getPrefixCls ( 'list' , customizePrefixCls ) ;
let loadingProp = loading ;
if ( typeof loadingProp === 'boolean' ) {
loadingProp = {
spinning : loadingProp ,
} ;
}
const isLoading = loadingProp && loadingProp . spinning ;
// large => lg
// small => sm
let sizeCls = '' ;
switch ( size ) {
case 'large' :
sizeCls = 'lg' ;
break ;
case 'small' :
sizeCls = 'sm' ;
break ;
default :
break ;
}
const classString = classNames ( prefixCls , className , {
[ ` ${ prefixCls } -vertical ` ] : itemLayout === 'vertical' ,
[ ` ${ prefixCls } - ${ sizeCls } ` ] : sizeCls ,
[ ` ${ prefixCls } -split ` ] : split ,
[ ` ${ prefixCls } -bordered ` ] : bordered ,
[ ` ${ prefixCls } -loading ` ] : isLoading ,
[ ` ${ prefixCls } -grid ` ] : grid ,
[ ` ${ prefixCls } -something-after-last-item ` ] : this . isSomethingAfterLastItem ( ) ,
[ ` ${ prefixCls } -rtl ` ] : direction === 'rtl' ,
} ) ;
const paginationProps = {
. . . this . defaultPaginationProps ,
total : dataSource.length ,
current : paginationCurrent ,
pageSize : paginationSize ,
. . . ( pagination || { } ) ,
const {
prefixCls : customizePrefixCls ,
bordered ,
split ,
className ,
children ,
itemLayout ,
loadMore ,
grid ,
dataSource = [ ] ,
size ,
header ,
footer ,
loading ,
. . . rest
} = props ;
const prefixCls = getPrefixCls ( 'list' , customizePrefixCls ) ;
let loadingProp = loading ;
if ( typeof loadingProp === 'boolean' ) {
loadingProp = {
spinning : loadingProp ,
} ;
}
const isLoading = loadingProp && loadingProp . spinning ;
// large => lg
// small => sm
let sizeCls = '' ;
switch ( size ) {
case 'large' :
sizeCls = 'lg' ;
break ;
case 'small' :
sizeCls = 'sm' ;
break ;
default :
break ;
}
const largestPage = Math . ceil ( paginationProps . total / paginationProps . pageSize ) ;
if ( paginationProps . current > largestPage ) {
paginationProps . current = largestPage ;
}
const paginationContent = pagination ? (
< div className = { ` ${ prefixCls } -pagination ` } >
< Pagination
{ . . . paginationProps }
onChange = { this . onPaginationChange }
onShowSizeChange = { this . onPaginationShowSizeChange }
/ >
< / div >
) : null ;
let splitDataSource = [ . . . dataSource ] ;
if ( pagination ) {
if ( dataSource . length > ( paginationProps . current - 1 ) * paginationProps . pageSize ) {
splitDataSource = [ . . . dataSource ] . splice (
( paginationProps . current - 1 ) * paginationProps . pageSize ,
paginationProps . pageSize ,
) ;
}
}
const classString = classNames ( prefixCls , className , {
[ ` ${ prefixCls } -vertical ` ] : itemLayout === 'vertical' ,
[ ` ${ prefixCls } - ${ sizeCls } ` ] : sizeCls ,
[ ` ${ prefixCls } -split ` ] : split ,
[ ` ${ prefixCls } -bordered ` ] : bordered ,
[ ` ${ prefixCls } -loading ` ] : isLoading ,
[ ` ${ prefixCls } -grid ` ] : grid ,
[ ` ${ prefixCls } -something-after-last-item ` ] : isSomethingAfterLastItem ( ) ,
[ ` ${ prefixCls } -rtl ` ] : direction === 'rtl' ,
} ) ;
const paginationProps = {
. . . defaultPaginationProps ,
total : dataSource.length ,
current : paginationCurrent ,
pageSize : paginationSize ,
. . . ( pagination || { } ) ,
} ;
let childrenContent ;
childrenContent = isLoading && < div style = { { minHeight : 53 } } / > ;
if ( splitDataSource . length > 0 ) {
const items = splitDataSource . map ( ( item : any , index : number ) = > this . renderItem ( item , index ) ) ;
const childrenList : Array < React.ReactNode > = [ ] ;
React . Children . forEach ( items , ( child : any , index ) = > {
childrenList . push (
React . cloneElement ( child , {
key : this.keys [ index ] ,
} ) ,
) ;
} ) ;
childrenContent = grid ? (
< Row gutter = { grid . gutter } > { childrenList } < / Row >
) : (
< ul className = { ` ${ prefixCls } -items ` } > { childrenList } < / ul >
const largestPage = Math . ceil ( paginationProps . total / paginationProps . pageSize ) ;
if ( paginationProps . current > largestPage ) {
paginationProps . current = largestPage ;
}
const paginationContent = pagination ? (
< div className = { ` ${ prefixCls } -pagination ` } >
< Pagination
{ . . . paginationProps }
onChange = { onPaginationChange }
onShowSizeChange = { onPaginationShowSizeChange }
/ >
< / div >
) : null ;
let splitDataSource = [ . . . dataSource ] ;
if ( pagination ) {
if ( dataSource . length > ( paginationProps . current - 1 ) * paginationProps . pageSize ) {
splitDataSource = [ . . . dataSource ] . splice (
( paginationProps . current - 1 ) * paginationProps . pageSize ,
paginationProps . pageSize ,
) ;
} else if ( ! children && ! isLoading ) {
childrenContent = this . renderEmpty ( prefixCls , renderEmpty ) ;
}
}
let childrenContent ;
childrenContent = isLoading && < div style = { { minHeight : 53 } } / > ;
if ( splitDataSource . length > 0 ) {
const items = splitDataSource . map ( ( item : any , index : number ) = > renderItem ( item , index ) ) ;
const childrenList : Array < React.ReactNode > = [ ] ;
React . Children . forEach ( items , ( child : any , index ) = > {
childrenList . push (
React . cloneElement ( child , {
key : keys [ index ] ,
} ) ,
) ;
} ) ;
childrenContent = grid ? (
< Row gutter = { grid . gutter } > { childrenList } < / Row >
) : (
< ul className = { ` ${ prefixCls } -items ` } > { childrenList } < / ul >
) ;
} else if ( ! children && ! isLoading ) {
childrenContent = renderEmptyFunc ( prefixCls , renderEmpty ) ;
}
const paginationPosition = paginationProps . position || 'bottom' ;
const paginationPosition = paginationProps . position || 'bottom' ;
return (
return (
< ListContext.Provider value = { { grid : props.grid , itemLayout : props.itemLayout } } >
< div className = { classString } { ...omit ( rest , [ ' rowKey ' , ' renderItem ' , ' locale ' ] ) } >
{ ( paginationPosition === 'top' || paginationPosition === 'both' ) && paginationContent }
{ header && < div className = { ` ${ prefixCls } -header ` } > { header } < / div > }
@ -283,10 +256,18 @@ export default class List<T> extends React.Component<ListProps<T>, ListState> {
{ loadMore ||
( ( paginationPosition === 'bottom' || paginationPosition === 'both' ) && paginationContent ) }
< / div >
) ;
} ;
render() {
return < ConfigConsumer > { this . renderList } < / ConfigConsumer > ;
}
< / ListContext.Provider >
) ;
}
List . defaultProps = {
dataSource : [ ] ,
bordered : false ,
split : true ,
loading : false ,
pagination : false as ListProps < any > [ 'pagination' ] ,
} ;
List . Item = Item ;
export default List ;