import * as React from 'react'; import { Platform, StyleSheet, View } from 'react-native'; import { default as base } from '../../_styles/themes/default.basic'; import { picker } from '../../_styles/themes/default.components'; import { innerScaleSize } from '../../_styles/themes/responsive'; import PickerColumn from './picker-column'; import PickerColumnAndroid from './picker-column.android'; interface IMDPickerProps { itemHeight?: number; pickerWidth: number; pickerHeight: number; onPickerSelected?: (columnIndex: number) => void; defaultIndex?: number[]; defaultValue?: string[]; invalidIndex?: number[][]; data: any[][]; cols?: number; isCascade?: boolean; } export interface IMDItemModel { label: string; value: string; children?: IMDItemModel[]; } interface IMDPickerState { columns: any[]; activeIndexs: number[]; } export default class Picker extends React.Component< IMDPickerProps, IMDPickerState > { public static defaultProps = { itemHeight: innerScaleSize(40 * 2), pickerHeight: innerScaleSize((40 + 2 * 80) * 2), }; constructor (props: IMDPickerProps) { super(props); this.state = { columns: props.data, activeIndexs: [], }; } private activeIndexs: number[] = []; private activeValues: any[] = []; private columnValues: any[] = []; public componentWillReceiveProps (nextProps: IMDPickerProps) { this.initActiveIndexsByNextProps(nextProps); this.initColumnValues(); this.setupStateColumns(); } public componentWillMount () { this.initActiveIndexs(); this.initColumnValues(); this.setupStateColumns(); } public componentDidMount () { this.initActiveValues(); } public render () { const maskHeight = (this.props.pickerHeight - this.props.itemHeight!) / 2; return ( {this.renderColumns()} ); } public setColumnValues (index: number, values: any[]) { if (index === undefined || values === undefined) { return; } this.updateActiveIndexs(index, 0); this.columnValues[index] = values; if (this.props.isCascade) { this.cascadePicker(this.columnValues[index], index, this.props.cols!); } this.setupStateColumns(); const selectIndex = this.activeIndexs[index]; this.updateActiveValues(index, values[selectIndex]); } public getActiveValues () { return this.activeValues || []; } public getActiveIndexs () { return this.activeIndexs || []; } private renderColumns () { if (Platform.OS === 'ios') { return this.state.columns.map((column, index) => { return ( ); }); } else { return this.state.columns.map((column, index) => { return ( ); }); } } private cascadePicker ( columValue: any[], curColumnIndex: number, maxCols: number ) { if (!this.props.isCascade) { return; } let valuesChange = false; let colIndex = curColumnIndex; let nextIndex = this.activeIndexs[colIndex]; let nextValue: any = columValue[nextIndex]; while (colIndex < maxCols - 1) { if ( nextValue && nextValue.children !== undefined && nextValue.children.length > 0 ) { this.columnValues[++colIndex] = nextValue.children ? nextValue.children : []; nextIndex = this.activeIndexs[colIndex]; nextValue = this.columnValues[colIndex][nextIndex]; } else { this.columnValues[++colIndex] = []; } valuesChange = true; } if (valuesChange) { this.setupStateColumns(); } } private initColumnValues () { this.columnValues = this.props.data; if (this.columnValues.length > 0 && this.props.isCascade) { this.cascadePicker(this.columnValues[0], 0, this.props.cols!); } } private initActiveIndexsByNextProps (nextProps: IMDPickerProps) { const { defaultIndex, defaultValue } = nextProps; if ( defaultIndex && defaultIndex.length > 0 && JSON.stringify(defaultIndex) !== JSON.stringify(this.props.defaultIndex) ) { this.activeIndexs = defaultIndex; } else if ( defaultValue && defaultValue.length > 0 && JSON.stringify(defaultValue) !== JSON.stringify(this.props.defaultValue) ) { this.activeIndexs = this.getIndexsByDefaultValues(nextProps); } } private initActiveIndexs () { const { defaultIndex, defaultValue } = this.props; if (defaultIndex && defaultIndex.length > 0) { this.activeIndexs = defaultIndex; } else if (defaultValue && defaultValue.length > 0) { this.activeIndexs = this.getIndexsByDefaultValues(this.props); } else { let i = 0; while (i < this.props.cols!) { this.activeIndexs[i] = 0; i++; } } } private getIndexsByDefaultValues (props: IMDPickerProps) { const indexs: number[] = []; const values: any[] = props.defaultValue || []; const cValues: any[] = props.data; if (props.isCascade) { let i = 0; let lastFind: boolean = true; while (i < props.cols!) { const value: string = i < values.length ? values[i] : ''; const cValue: any[] = i < cValues.length ? cValues[i] : []; indexs[i] = 0; if (value.length > 0 && cValue.length > 0 && lastFind) { lastFind = false; cValue.map((item, index) => { if ( item.value === value || item.label === value || item.text === value ) { indexs[i] = index; lastFind = true; if (item.children && item.children.length > 0) { cValues[i + 1] = item.children; } } }); } ++i; } } else { let i = 0; while (i < props.cols!) { const value: string = i < values.length ? values[i] : ''; const cValue: any[] = i < cValues.length ? cValues[i] : []; indexs[i] = 0; if (cValue.length > 0) { cValue.map((item, index) => { if ( item.value === value || item.label === value || item.text === value ) { indexs[i] = index; } }); } ++i; } } return indexs; } private setupStateColumns () { this.setState({ columns: this.columnValues, activeIndexs: this.activeIndexs, }); } private updateActiveIndexs (curColumnIndex: number, itemIndex: number) { this.activeIndexs[curColumnIndex] = itemIndex; if (this.props.isCascade) { while (++curColumnIndex < this.props.cols!) { this.activeIndexs[curColumnIndex] = 0; } } } private initActiveValues () { this.setBehindActiveValues(0); } private setBehindActiveValues (index: number) { let i = index; while (i < this.props.cols!) { const pIndex = this.activeIndexs[i]; if (this.state.columns[i] && pIndex < this.state.columns[i].length) { const item = this.state.columns[i][pIndex]; this.activeValues[i] = item; } else { this.activeValues[i] = null; } ++i; } } private updateActiveValues (curColumnIndex: number, itemValue: any) { this.activeValues[curColumnIndex] = itemValue; if (this.props.isCascade) { this.setBehindActiveValues(++curColumnIndex); } } private onSeleted (itemIndex: number, itemValue: any, columnIndex: number) { if (columnIndex < this.props.cols!) { this.updateActiveIndexs(columnIndex, itemIndex); if (this.props.isCascade) { this.cascadePicker( this.columnValues[columnIndex], columnIndex, this.props.cols! ); } this.updateActiveValues(columnIndex, itemValue); } this.props.onPickerSelected!(columnIndex); } private getInvalidIndexs (index: number) { if (this.props.invalidIndex && this.props.invalidIndex.length > index) { return this.props.invalidIndex[index]; } } } const styles = StyleSheet.create({ container: { display: 'flex', flexDirection: 'column', justifyContent: 'space-between', backgroundColor: base.colors.textBaseInverse, }, maskTop: { position: 'relative', width: '100%', borderColor: picker.borderColor, borderBottomWidth: 1, zIndex: 2, }, maskBottom: { position: 'relative', width: '100%', borderTopWidth: 1, borderColor: picker.borderColor, zIndex: 2, }, columns: { position: 'absolute', width: '100%', height: '100%', display: 'flex', flexDirection: 'row', alignItems: 'stretch', justifyContent: 'space-between', }, });