import React, { Component, createRef, ReactNode, KeyboardEvent } from 'react' import { LevelSelectDataItem, LevelSelectProps } from './types' import { Selection } from '../selection' import { Popover } from '../popover' import { Flex } from '../flex' import { LevelList } from '../level_list' import { getLevel } from '../level_list/utils' import _ from 'lodash' import { judgeFunction } from '../../common/utils' import { ConfigConsumer, ConfigProvider, ConfigProviderProps } from '../config_provider' interface LevelSelectState { willActiveSelected: V[] } class LevelSelect extends Component, LevelSelectState> { static defaultProps = { renderSelected: (item: any) => item.map((v: any) => v.text).join(','), onKeyDown: _.noop, popoverType: 'focus', selected: [], onSelect: _.noop, } readonly state: LevelSelectState = { willActiveSelected: this.props.selected, } private _selectionRef = createRef() private _popoverRef = createRef() public apiDoFocus = (): void => { this._selectionRef.current!.apiDoFocus() } public apiDoSelectWillActive = (): void => { const { onSelect } = this.props const { willActiveSelected } = this.state judgeFunction(onSelect, willActiveSelected) } private _handleSelect = (selected: V[]): void => { const { onSelect } = this.props this._popoverRef.current!.apiDoSetActive(false) judgeFunction(onSelect, selected) } private _handleWillActiveSelect = (willActiveSelected: V[]): void => { this.setState({ willActiveSelected }) } private _renderPopup = (config: ConfigProviderProps): ReactNode => { const { titles, data, selected, right, onlySelectLeaf } = this.props const { willActiveSelected } = this.state return ( isReverse={right} data={data} onWillActiveSelect={this._handleWillActiveSelect} willActiveSelected={willActiveSelected} selected={selected} onSelect={this._handleSelect} titles={titles} onlySelectLeaf={onlySelectLeaf} /> ) } private _handleSelectionSelect = (selected: V[] | null): void => { const { onSelect } = this.props judgeFunction(onSelect, selected === null ? [] : selected) } private _getSelectItemText = (): ReactNode => { const { renderSelected } = this.props const selectedItems = this._getSelectedItem() return renderSelected!(selectedItems) } private _getSelectedItem = (): LevelSelectDataItem[] => { const { data, selected = [] } = this.props const items: LevelSelectDataItem[] = [] selected.forEach((value, index) => { const match = (index === 0 ? data : items[index - 1].children)!.find( (item) => item.value === value ) items.push(match!) }) return items } private _handleKeyDown = (event: KeyboardEvent): void => { const { data = [], onKeyDown } = this.props const { willActiveSelected } = this.state // 不是方向键,不用拦截 if ( event.key !== 'ArrowDown' && event.key !== 'ArrowUp' && event.key !== 'ArrowLeft' && event.key !== 'ArrowRight' ) { onKeyDown!(event) return } // 没有数据,不拦截 if (data.length === 0) { onKeyDown!(event) return } // 避免引用 let newWill = willActiveSelected.slice() const level = getLevel(data, willActiveSelected) // 如果没法左和右了,则不拦截,抛出去 if ( (event.key === 'ArrowLeft' && newWill.length === 0) || (event.key === 'ArrowRight' && newWill.length >= level.length) ) { onKeyDown!(event) return } // 以下要拦截拉 // 阻止默认行为 event.preventDefault() if (event.key === 'ArrowUp' || event.key === 'ArrowDown') { // 如果没有选择,则默认到第一个 if (newWill.length === 0) { newWill = [level[0][0].value] } else { const arr = level[newWill.length - 1] let index = _.findIndex(arr, (v) => v.value === newWill[newWill.length - 1]) if (event.key === 'ArrowDown') { index++ } else { index-- } // fix index if (index > arr.length - 1) { index = 0 } else if (index < 0) { index = arr.length - 1 } newWill[newWill.length - 1] = arr[index].value } } else if (event.key === 'ArrowLeft') { newWill.pop() } else if (event.key === 'ArrowRight') { newWill.push(level[newWill.length][0].value) } this.setState({ willActiveSelected: newWill, }) } private _renderTarget = (): ReactNode => { const { titles = [], data = [], selected = [], disabled, popoverType, right, onlySelectLeaf, ...rest } = this.props // 注意转换 selected onSelect renderSelected return ( this._getSelectItemText()} onKeyDown={this._handleKeyDown} disabled={disabled} /> ) } render() { const { disabled, children, popoverType, right } = this.props return ( {(config) => ( {children ?? this._renderTarget()} )} ) } } export default LevelSelect