import type { App, Plugin } from 'vue'; import { defineComponent, inject } from 'vue'; import VcTreeSelect, { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from '../vc-tree-select'; import classNames from '../_util/classNames'; import { TreeSelectProps } from './interface'; import warning from '../_util/warning'; import { getOptionProps, getComponent, getSlot } from '../_util/props-util'; import initDefaultProps from '../_util/props-util/initDefaultProps'; import { defaultConfigProvider } from '../config-provider'; export { TreeData, TreeSelectProps } from './interface'; import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'; import CaretDownOutlined from '@ant-design/icons-vue/CaretDownOutlined'; import DownOutlined from '@ant-design/icons-vue/DownOutlined'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled'; import omit from 'omit.js'; import { convertChildrenToData } from './utils'; const TreeSelect = defineComponent({ TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD, name: 'ATreeSelect', inheritAttrs: false, props: initDefaultProps(TreeSelectProps(), { transitionName: 'slide-up', choiceTransitionName: '', }), setup() { return { vcTreeSelect: null, configProvider: inject('configProvider', defaultConfigProvider), }; }, created() { warning( this.multiple !== false || !this.treeCheckable, 'TreeSelect', '`multiple` will alway be `true` when `treeCheckable` is true', ); }, methods: { saveTreeSelect(node: any) { this.vcTreeSelect = node; }, focus() { this.vcTreeSelect.focus(); }, blur() { this.vcTreeSelect.blur(); }, renderSwitcherIcon(prefixCls: string, { isLeaf, loading }) { if (loading) { return ; } if (isLeaf) { return null; } return ; }, handleChange(...args: any[]) { this.$emit('update:value', args[0]); this.$emit('change', ...args); }, handleTreeExpand(...args: any[]) { this.$emit('update:treeExpandedKeys', args[0]); this.$emit('treeExpand', ...args); }, handleSearch(...args: any[]) { this.$emit('update:searchValue', args[0]); this.$emit('search', ...args); }, updateTreeData(treeData: any[]) { const { $slots } = this; const defaultFields = { children: 'children', title: 'title', key: 'key', label: 'label', value: 'value', }; const replaceFields = { ...defaultFields, ...this.$props.replaceFields }; return treeData.map(item => { const { slots = {} } = item; const label = item[replaceFields.label]; const title = item[replaceFields.title]; const value = item[replaceFields.value]; const key = item[replaceFields.key]; const children = item[replaceFields.children]; let newLabel = typeof label === 'function' ? label() : label; let newTitle = typeof title === 'function' ? title() : title; if (!newLabel && slots.label && $slots[slots.label]) { newLabel = <>{$slots[slots.label](item)}; } if (!newTitle && slots.title && $slots[slots.title]) { newTitle = <>{$slots[slots.title](item)}; } const treeNodeProps = { ...item, title: newTitle || newLabel, value, dataRef: item, key, }; if (children) { return { ...treeNodeProps, children: this.updateTreeData(children) }; } return treeNodeProps; }); }, }, render() { const props: any = getOptionProps(this); const { prefixCls: customizePrefixCls, size, dropdownStyle, dropdownClassName, getPopupContainer, ...restProps } = props; const { class: className } = this.$attrs; const { renderEmpty, getPrefixCls } = this.configProvider; const prefixCls = getPrefixCls('select', customizePrefixCls); const notFoundContent = getComponent(this, 'notFoundContent'); const removeIcon = getComponent(this, 'removeIcon'); const clearIcon = getComponent(this, 'clearIcon'); const { getPopupContainer: getContextPopupContainer } = this.configProvider; const rest = omit(restProps, [ 'inputIcon', 'removeIcon', 'clearIcon', 'switcherIcon', 'suffixIcon', ]); let suffixIcon = getComponent(this, 'suffixIcon'); suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon; let treeData = props.treeData; if (treeData) { treeData = this.updateTreeData(treeData); } const cls = { [`${prefixCls}-lg`]: size === 'large', [`${prefixCls}-sm`]: size === 'small', [className as string]: className, }; // showSearch: single - false, multiple - true let { showSearch } = restProps; if (!('showSearch' in restProps)) { showSearch = !!(restProps.multiple || restProps.treeCheckable); } let checkable = getComponent(this, 'treeCheckable'); if (checkable) { checkable = ; } const inputIcon = suffixIcon || ; const finalRemoveIcon = removeIcon || ; const finalClearIcon = clearIcon || ; const VcTreeSelectProps = { ...this.$attrs, switcherIcon: nodeProps => this.renderSwitcherIcon(prefixCls, nodeProps), inputIcon, removeIcon: finalRemoveIcon, clearIcon: finalClearIcon, ...rest, showSearch, getPopupContainer: getPopupContainer || getContextPopupContainer, dropdownClassName: classNames(dropdownClassName, `${prefixCls}-tree-dropdown`), prefixCls, dropdownStyle: { maxHeight: '100vh', overflow: 'auto', ...dropdownStyle }, treeCheckable: checkable, notFoundContent: notFoundContent || renderEmpty('Select'), class: cls, onChange: this.handleChange, onSearch: this.handleSearch, onTreeExpand: this.handleTreeExpand, ref: this.saveTreeSelect, treeData: treeData ? treeData : convertChildrenToData(getSlot(this)), }; return ( ); }, }); /* istanbul ignore next */ TreeSelect.install = function (app: App) { app.component(TreeSelect.name, TreeSelect); app.component(TreeSelect.TreeNode.displayName, TreeSelect.TreeNode); return app; }; export const TreeSelectNode = TreeSelect.TreeNode; export default TreeSelect as typeof TreeSelect & Plugin & { readonly TreeNode: typeof TreeNode; readonly SHOW_ALL: typeof SHOW_ALL; readonly SHOW_PARENT: typeof SHOW_PARENT; readonly SHOW_CHILD: typeof SHOW_CHILD; };