import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Select } from '@alifd/next'; import { AddressStore, defaultAddressStoreCNUser } from './AddressStore'; import { SelectionChain, NodeChain, NodeIDStrict, AddressNode } from './Types'; import { nodeChainFromNode, selectionToId, getLabelIntl, lastOr, getNodeLevelInTree, } from './Common'; import AddressIntlCascader from './AddressIntlCascader'; function getDataSource(node: AddressNode | null) { if (!node || node.isLeaf || !node.children || !node.children.length) { return []; } return node.children.map(i => ({ label: getLabelIntl(i), value: i.value })); } function normalizeToId( value: SelectionChain | NodeIDStrict | undefined ): NodeIDStrict | undefined { if (Array.isArray(value)) { return lastOr(value, undefined); } return value; } interface AddressIntlProps { className: string; style: object; value?: SelectionChain | NodeIDStrict; defaultValue?: SelectionChain | NodeIDStrict; onChange?: (value: SelectionChain, nodeChain: NodeChain) => any; size?: 'small' | 'medium' | 'large'; placeholder: string; popupContainer: React.ReactNode | Function; kind: 'cascader' | 'select'; level?: number; addressStore: AddressStore; } interface AddressIntlState { value: SelectionChain; } export default class AddressIntl extends React.Component< AddressIntlProps, AddressIntlState > { static propTypes = { className: PropTypes.string, style: PropTypes.object, value: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string), ]), defaultValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string), ]), onChange: PropTypes.func, size: PropTypes.oneOf(['small', 'medium', 'large']), placeholder: PropTypes.string, popupContainer: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), kind: PropTypes.oneOf(['cascader', 'select']), level: PropTypes.number, addressStore: PropTypes.object, }; static defaultProps = { addressStore: defaultAddressStoreCNUser, }; constructor(props: AddressIntlProps) { super(props); this.state = { value: [], }; this.handleUserSelect = this.handleUserSelect.bind(this); this.getOverlayContainer = this.getOverlayContainer.bind(this); } componentDidMount() { let value = this.props.value || this.props.defaultValue; const valueId = normalizeToId(value) || '0'; this.handleSelect(valueId); } async componentDidUpdate( prevProps: AddressIntlProps, prevState: AddressIntlState ) { const lastValue = normalizeToId(prevProps.value); const thisValue = normalizeToId(this.props.value); if (lastValue != thisValue) { if (typeof thisValue == 'undefined') { this.handleSelect('0'); } else if (typeof thisValue == 'string') { this.handleSelect(thisValue); } else if (Array.isArray(thisValue)) { this.setState({ value: thisValue }); } } const valueNow = selectionToId(this.state.value); if (valueNow != selectionToId(prevState.value)) { this.handleSelect(valueNow); } } setStateAsync(updater: any): Promise { return new Promise((resolve, reject) => this.setState(updater, resolve)); } getOverlayContainer() { const { popupContainer } = this.props; if (this.props.popupContainer) { if (typeof popupContainer == 'function') { return popupContainer(); } return popupContainer; } return this.refs.gatewayWrapper; } async handleSelect(value: NodeIDStrict): Promise { const nodePre = this.props.addressStore.impl.getNodeByIdSync(value); if (!nodePre || (!nodePre.isLeaf && !nodePre.children)) { await this.props.addressStore.impl.getNodeById(value, true); } const node = this.props.addressStore.impl.getNodeByIdSync(value)!; const nodeChain = nodeChainFromNode(node); const idChain = nodeChain.map(i => i.id).slice(1); await this.setStateAsync({ value: idChain }); return nodeChain; } async handleUserSelect(value: NodeIDStrict) { const nodeChain = nodeChainFromNode( this.props.addressStore.impl.getNodeByIdSync(value)! ); const idChain = nodeChain.map(i => i.id).slice(1); typeof this.props.onChange == 'function' && this.props.onChange(idChain, nodeChain); await this.handleSelect(value); } renderSelectBox(value: NodeIDStrict | undefined, parentID: NodeIDStrict) { const SelectComp = Select as any; const parentNode = this.props.addressStore.impl.getNodeByIdSync(parentID); if (!parentNode) { throw new Error(`no such node ${parentID}`); } if ( parentNode.isLeaf || !parentNode.children || !parentNode.children.length ) { return null; } // TODO: complete logic for level in case of SelectBox mode if ( this.props.level && getNodeLevelInTree(parentNode) >= this.props.level ) { return null; } return ( ); } renderSelectBoxes() { const box = (value: NodeIDStrict, index: number) => this.renderSelectBox(value, index ? this.state.value[index - 1] : '0'); return [ this.state.value.map(box), this.renderSelectBox(undefined, selectionToId(this.state.value)), ]; } renderCascader() { return (
); } renderCascaderBox() { const SelectComp = Select as any; const displayValue = this.state.value .map(this.props.addressStore.impl.getNodeByIdSync) .map(i => getLabelIntl(i!)) .join(' / ') || undefined; return ( ); } render() { return ( {/* {this.renderSelectBoxes()} */} {/* {this.renderCascaderBox()} */} {this.props.kind == 'cascader' ? this.renderCascaderBox() : this.renderSelectBoxes()} ); } }