import warning from 'warning' import PropTypes from '../../../_util/vue-types' import { Tree } from '../../../vc-tree' import BaseMixin from '../../../_util/BaseMixin' // export const popupContextTypes = { // onPopupKeyDown: PropTypes.func.isRequired, // onTreeNodeSelect: PropTypes.func.isRequired, // onTreeNodeCheck: PropTypes.func.isRequired, // } function getDerivedStateFromProps (nextProps, prevState) { const { _prevProps: prevProps = {}, _loadedKeys: loadedKeys, _expandedKeyList: expandedKeyList, _cachedExpandedKeyList: cachedExpandedKeyList, } = prevState || {} const { valueList, valueEntities, keyEntities, treeExpandedKeys, filteredTreeNodes, searchValue, } = nextProps const newState = { _prevProps: { ...nextProps }, } // Check value update if (valueList !== prevProps.valueList) { newState._keyList = valueList .map(({ value }) => valueEntities[value]) .filter(entity => entity) .map(({ key }) => key) } // Show all when tree is in filter mode if ( !treeExpandedKeys && filteredTreeNodes && filteredTreeNodes.length && filteredTreeNodes !== prevProps.filteredTreeNodes ) { newState._expandedKeyList = Object.keys(keyEntities) } // Cache `expandedKeyList` when filter set if (searchValue && !prevProps.searchValue) { newState._cachedExpandedKeyList = expandedKeyList } else if (!searchValue && prevProps.searchValue && !treeExpandedKeys) { newState._expandedKeyList = cachedExpandedKeyList || [] newState._cachedExpandedKeyList = [] } // Use expandedKeys if provided if (prevProps.treeExpandedKeys !== treeExpandedKeys) { newState._expandedKeyList = treeExpandedKeys } // Clean loadedKeys if key not exist in keyEntities anymore if (nextProps.loadData) { newState._loadedKeys = loadedKeys.filter(key => key in keyEntities) } return newState } const BasePopup = { mixins: [BaseMixin], name: 'BasePopup', props: { prefixCls: PropTypes.string, upperSearchValue: PropTypes.string, valueList: PropTypes.array, searchHalfCheckedKeys: PropTypes.array, valueEntities: PropTypes.object, keyEntities: PropTypes.object, treeIcon: PropTypes.bool, treeLine: PropTypes.bool, treeNodeFilterProp: PropTypes.string, treeCheckable: PropTypes.any, treeCheckStrictly: PropTypes.bool, treeDefaultExpandAll: PropTypes.bool, treeDefaultExpandedKeys: PropTypes.array, treeExpandedKeys: PropTypes.array, loadData: PropTypes.func, multiple: PropTypes.bool, // onTreeExpand: PropTypes.func, searchValue: PropTypes.string, treeNodes: PropTypes.any, filteredTreeNodes: PropTypes.any, notFoundContent: PropTypes.string, ariaId: PropTypes.string, switcherIcon: PropTypes.any, // HOC renderSearch: PropTypes.func, // onTreeExpanded: PropTypes.func, __propsSymbol__: PropTypes.any, }, inject: { vcTreeSelect: { default: {}}, }, watch: { __propsSymbol__ () { const state = getDerivedStateFromProps(this.$props, this.$data) this.setState(state) }, }, data () { warning(this.$props.__propsSymbol__, 'must pass __propsSymbol__') const { treeDefaultExpandAll, treeDefaultExpandedKeys, keyEntities, } = this.$props // TODO: make `expandedKeyList` control let expandedKeyList = treeDefaultExpandedKeys if (treeDefaultExpandAll) { expandedKeyList = Object.keys(keyEntities) } const state = { _keyList: [], _expandedKeyList: expandedKeyList, // Cache `expandedKeyList` when tree is in filter. This is used in `getDerivedStateFromProps` _cachedExpandedKeyList: [], // eslint-disable-line react/no-unused-state _loadedKeys: [], _prevProps: {}, } return { ...state, ...getDerivedStateFromProps(this.$props, state), } }, methods: { onTreeExpand (expandedKeyList) { const { treeExpandedKeys } = this.$props // Set uncontrolled state if (!treeExpandedKeys) { this.setState({ _expandedKeyList: expandedKeyList }, () => { this.__emit('treeExpanded') }) } this.__emit('treeExpand', expandedKeyList) }, onLoad (loadedKeys) { this.setState({ _loadedKeys: loadedKeys }) }, /** * Not pass `loadData` when searching. To avoid loop ajax call makes browser crash. */ getLoadData () { const { loadData, searchValue } = this.$props if (searchValue) return null return loadData }, /** * This method pass to Tree component which is used for add filtered class * in TreeNode > li */ filterTreeNode (treeNode) { const { upperSearchValue, treeNodeFilterProp } = this.$props const filterVal = treeNode[treeNodeFilterProp] if (typeof filterVal === 'string') { return upperSearchValue && (filterVal).toUpperCase().indexOf(upperSearchValue) !== -1 } return false }, renderNotFound () { const { prefixCls, notFoundContent } = this.$props return ( {notFoundContent} ) }, }, render () { const { _keyList: keyList, _expandedKeyList: expandedKeyList, _loadedKeys: loadedKeys } = this.$data const { prefixCls, treeNodes, filteredTreeNodes, treeIcon, treeLine, treeCheckable, treeCheckStrictly, multiple, ariaId, renderSearch, switcherIcon, searchHalfCheckedKeys, } = this.$props const { vcTreeSelect: { onPopupKeyDown, onTreeNodeSelect, onTreeNodeCheck, }} = this const loadData = this.getLoadData() const treeProps = {} if (treeCheckable) { treeProps.checkedKeys = keyList } else { treeProps.selectedKeys = keyList } let $notFound let $treeNodes if (filteredTreeNodes) { if (filteredTreeNodes.length) { treeProps.checkStrictly = true $treeNodes = filteredTreeNodes // Fill halfCheckedKeys if (treeCheckable && !treeCheckStrictly) { treeProps.checkedKeys = { checked: keyList, halfChecked: searchHalfCheckedKeys, } } } else { $notFound = this.renderNotFound() } } else if (!treeNodes.length) { $notFound = this.renderNotFound() } else { $treeNodes = treeNodes } let $tree if ($notFound) { $tree = $notFound } else { const treeAllProps = { props: { prefixCls: `${prefixCls}-tree`, showIcon: treeIcon, showLine: treeLine, selectable: !treeCheckable, checkable: treeCheckable, checkStrictly: treeCheckStrictly, multiple: multiple, loadData: loadData, loadedKeys: loadedKeys, expandedKeys: expandedKeyList, filterTreeNode: this.filterTreeNode, switcherIcon: switcherIcon, ...treeProps, __propsSymbol__: Symbol(), children: $treeNodes, }, on: { select: onTreeNodeSelect, check: onTreeNodeCheck, expand: this.onTreeExpand, load: this.onLoad, }, } $tree = ( ) } return (
{renderSearch ? renderSearch() : null} {$tree}
) }, } export default BasePopup