import * as React from 'react' ; import * as classNames from 'classnames' ; import Portal from '../Portal' ; import Button from '../Button' ; import PickerItem from './PickerItem' ; import { equals , getOtherProperties } from '../common/Utils' ; import { FadeInUp , Fade } from '../Transitions' ; import { PickerProps , PickerState } from './PropsType' ; export default class Picker extends React . PureComponent < PickerProps , PickerState > { static defaultProps : PickerProps = { data : [ ] , format : '/' , } ; state : PickerState = { data : [ ] , inputValue : '' , value : [ ] , visible : false , } ; visible : boolean = false ; lastInputValue : any ; bodyOverflow : any = '' ; componentDidMount ( ) { this . bodyOverflow = document . body . style . overflow ; const { data , defaultValue } = this . props ; if ( 'data' in this . props && Array . isArray ( this . props . data ! ) && data . length > 0 ) { const value = defaultValue ? this . getCurrentIndex ( data ! , this . getDefaultValue ( data ! , defaultValue ! ) ) : [ ] ; this . setState ( { data , value , inputValue : defaultValue && this . fetchValue ( data , defaultValue , 'label' ) , } ) ; this . lastInputValue = value ; } } componentWillReceiveProps ( nextProps ) { const { data , visible , value : valueProps } = this . props ; if ( ( 'visible' in nextProps && visible !== nextProps . visible ) || ( 'data' in nextProps && data !== nextProps . data ) || ( 'value' in nextProps && valueProps !== nextProps . value ) ) { const dValue = nextProps . value ; let value = nextProps . value ? this . getCurrentIndex ( nextProps . data ! , this . getDefaultValue ( nextProps . data ! , dValue ) ) : this . state . value ! ; if ( ! nextProps . visible || ! this . state . visible ) { value = this . lastInputValue ; } this . setState ( { visible : nextProps . visible ! , value , data : nextProps . data ! , } , ( ) => { this . stopBodyScroll ( this . state . visible ) ; } ) ; } } getDefaultValue ( data , defaultValue ) { let value = [ ] ; if ( Array . isArray ( defaultValue ) ) { value = defaultValue ; } else if ( typeof defaultValue === 'string' ) { value = ( defaultValue as any ) . split ( this . props . format ! ) . map ( ( v ) => ( { value : v , } ) ) ; } else { let child = [ ... data ] ; while ( child && child . length > 0 ) { value . push ( { label : child [ 0 ] . label , value : child [ 0 ] . value , } ) ; child = child [ 0 ] && child [ 0 ] . children ; } } return value ; } getCurrentIndex = ( data , selectedValue ) => { const value = [ ] ; if ( selectedValue ) { let child = [ ... data ! ] ; selectedValue . map ( ( v ) => { if ( child && child . length > 0 ) { for ( let i = 0 ; i < child . length ; i ++ ) { if ( equals ( child [ i ] , v , 'value' ) ) { child = child [ i ] && child [ i ] . children ; value . push ( i ) ; break ; } } } } ) ; } return value ; } ; getItems ( data , value ) { const children = [ ] ; if ( data && data . length > 0 ) { let num = 0 ; let child = [ ... data ! ] ; while ( child && child . length > 0 ) { const index = ( value as any [ ] ) [ num ] || 0 ; children . push ( { num , index , child } ) ; child = child [ index ] && child [ index ] . children ! ; num ++ ; } for ( let i = 0 ; i < children . length ; i ++ ) { const childData = children [ i ] ; children [ i ] = ( < PickerItem key = { childData . num } index = { childData . num } data = { childData . child } style = { { width : 100 / children . length + '%' } } disabled = { this . props . disabled } value = { childData . index } onValueChange = { this . handleValueChange } / > ) ; } } return children ; } fetchValue ( data , value , field , seperator = '/' ) { const selected = [ ] ; if ( Array . isArray ( data ) && value ) { let child = data ; let i = 0 ; while ( child && child . length > 0 ) { child = child [ value [ i ] || 0 ] ; if ( child ) { selected . push ( { label : child . label , value : child . value , } ) ; } i ++ ; child = child && child . children ; } } return selected . map ( ( item ) => { return item [ field ] ; } ) . join ( seperator ) ; } handleClose = ( ) => { this . setState ( { value : this . lastInputValue , visible : false , } ) ; if ( this . props . onClose ) { this . props . onClose ( ) ; } } ; handleValueChange = ( event ) => { const value = [ ... this . state . value ! ] ; value [ event . index ] = event . activeIndex ; this . setState ( { value , } ) ; if ( this . props . onValueChange ) { this . props . onValueChange ( { value : event . value , index : event . index , } ) ; } } ; handleConfirm = ( ) => { const value = [ ... this . state . value ! ] ; const inputValue = this . fetchValue ( this . state . data , value , 'label' ) ; this . setState ( { value , inputValue , visible : false , } ) ; this . lastInputValue = value ; if ( this . props . onClose ) { this . props . onClose ( ) ; } if ( this . props . onChange ) { this . props . onChange ( inputValue ) ; } } ; stopBodyScroll ( visible ) { if ( this . bodyOverflow === 'hidden' ) { return ; } if ( visible ) { document . body . style . overflow = 'hidden' ; } else { document . body . style . overflow = this . bodyOverflow ; } } handleClick = ( ) => { this . setState ( { visible : true , } , ( ) => { this . stopBodyScroll ( this . state . visible ) ; } ) ; if ( this . props . onOpen ) { ( this . props . onOpen as ( ) => void ) ( ) ; } } ; render ( ) { const { className , ... other } = this . props ; const { data , inputValue , value , visible } = this . state ; const styleClass = classNames ( 'Picker-panel' , { 'Picker-open' : visible , } , className ) ; const otherProps = getOtherProperties ( other , [ 'defaultValue' , 'children' , 'data' , 'format' , 'onChange' , 'onOpen' , 'onValueChange' , 'visible' ] ) ; return ( < div className = "Picker" > < div className = "Picker-input" onClick = { this . handleClick } > { inputValue } < /div> < Portal visible = { visible } mountNode = { document . body } > < div className = { styleClass } { ... otherProps } > < Fade in = { visible } > < div className = "Picker-mask" onClick = { this . handleClose } / > < /Fade> < FadeInUp in = { visible } className = "Picker-wrapper" > < div className = "Picker-footer" > < Button onClick = { this . handleClose } > Cancel < /Button> < Button onClick = { this . handleConfirm } > Done < /Button> < /div> < div className = "Picker-body" > < div className = "Picker-top-overlay" / > < div className = "Picker-bottom-overlay" / > < div className = "Picker-line" / > { this . getItems ( data , value ) } < /div> < /FadeInUp> < /div> < /Portal> < /div>); } }