refactor: tree-select
parent
81c16aba93
commit
8bf14f40ac
|
@ -1,6 +1,6 @@
|
||||||
import type { App, Plugin, VNode, ExtractPropTypes } from 'vue';
|
import type { App, Plugin, VNode, ExtractPropTypes } from 'vue';
|
||||||
import { defineComponent, inject, provide } from 'vue';
|
import { defineComponent, inject, provide } from 'vue';
|
||||||
import Select, { SelectProps } from '../select';
|
import Select, { selectProps } from '../select';
|
||||||
import Input from '../input';
|
import Input from '../input';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
import { defaultConfigProvider } from '../config-provider';
|
||||||
|
@ -15,7 +15,7 @@ function isSelectOptionOrSelectOptGroup(child: any): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoCompleteProps = {
|
const autoCompleteProps = {
|
||||||
...SelectProps(),
|
...selectProps(),
|
||||||
dataSource: PropTypes.array,
|
dataSource: PropTypes.array,
|
||||||
dropdownMenuStyle: PropTypes.style,
|
dropdownMenuStyle: PropTypes.style,
|
||||||
optionLabelProp: PropTypes.string,
|
optionLabelProp: PropTypes.string,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import VcSelect, { SelectProps } from '../select';
|
import VcSelect, { selectProps } from '../select';
|
||||||
import { getOptionProps, getSlot } from '../_util/props-util';
|
import { getOptionProps, getSlot } from '../_util/props-util';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: SelectProps(),
|
props: selectProps(),
|
||||||
Option: VcSelect.Option,
|
Option: VcSelect.Option,
|
||||||
render() {
|
render() {
|
||||||
const selectOptionsProps = getOptionProps(this);
|
const selectOptionsProps = getOptionProps(this);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import type { App, PropType, Plugin, ExtractPropTypes } from 'vue';
|
import type { App, PropType, Plugin, ExtractPropTypes } from 'vue';
|
||||||
import { computed, defineComponent, ref } from 'vue';
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
import omit from 'omit.js';
|
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import type { SelectProps as RcSelectProps } from '../vc-select';
|
import { selectProps as vcSelectProps } from '../vc-select';
|
||||||
import RcSelect, { Option, OptGroup, selectBaseProps } from '../vc-select';
|
import RcSelect, { Option, OptGroup, selectBaseProps } from '../vc-select';
|
||||||
import type { OptionProps as OptionPropsType } from '../vc-select/Option';
|
import type { OptionProps as OptionPropsType } from '../vc-select/Option';
|
||||||
import getIcons from './utils/iconUtil';
|
import getIcons from './utils/iconUtil';
|
||||||
|
@ -10,6 +9,7 @@ import PropTypes from '../_util/vue-types';
|
||||||
import { tuple } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import type { SizeType } from '../config-provider';
|
import type { SizeType } from '../config-provider';
|
||||||
|
import omit from '../_util/omit';
|
||||||
|
|
||||||
type RawValue = string | number;
|
type RawValue = string | number;
|
||||||
|
|
||||||
|
@ -24,24 +24,8 @@ export interface LabeledValue {
|
||||||
}
|
}
|
||||||
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
|
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
|
||||||
|
|
||||||
interface InternalSelectProps<VT> extends Omit<RcSelectProps<VT>, 'mode'> {
|
|
||||||
suffixIcon?: any;
|
|
||||||
itemIcon?: any;
|
|
||||||
size?: SizeType;
|
|
||||||
mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
|
|
||||||
bordered?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SelectPropsTypes<VT>
|
|
||||||
extends Omit<InternalSelectProps<VT>, 'inputIcon' | 'mode' | 'getInputElement' | 'backfill'> {
|
|
||||||
mode?: 'multiple' | 'tags';
|
|
||||||
}
|
|
||||||
export type SelectProps = Partial<ExtractPropTypes<SelectPropsTypes<SelectValue>>>;
|
|
||||||
export const selectProps = () => ({
|
export const selectProps = () => ({
|
||||||
...(omit(selectBaseProps(), ['inputIcon', 'mode', 'getInputElement', 'backfill']) as Omit<
|
...omit(vcSelectProps<SelectValue>(), ['inputIcon', 'mode', 'getInputElement', 'backfill']),
|
||||||
SelectPropsTypes<SelectValue>,
|
|
||||||
'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
|
|
||||||
>),
|
|
||||||
value: {
|
value: {
|
||||||
type: [Array, Object, String, Number] as PropType<SelectValue>,
|
type: [Array, Object, String, Number] as PropType<SelectValue>,
|
||||||
},
|
},
|
||||||
|
@ -58,6 +42,8 @@ export const selectProps = () => ({
|
||||||
choiceTransitionName: PropTypes.string.def(''),
|
choiceTransitionName: PropTypes.string.def(''),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type SelectProps = Partial<ExtractPropTypes<ReturnType<typeof selectProps>>>;
|
||||||
|
|
||||||
const Select = defineComponent({
|
const Select = defineComponent({
|
||||||
name: 'ASelect',
|
name: 'ASelect',
|
||||||
Option,
|
Option,
|
||||||
|
|
|
@ -11,8 +11,6 @@ import VcTreeSelect, {
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||||
import type { SizeType } from '../config-provider';
|
import type { SizeType } from '../config-provider';
|
||||||
|
|
||||||
export { TreeData, TreeSelectProps } from './interface';
|
|
||||||
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
||||||
import CaretDownOutlined from '@ant-design/icons-vue/CaretDownOutlined';
|
import CaretDownOutlined from '@ant-design/icons-vue/CaretDownOutlined';
|
||||||
import type { DefaultValueType, FieldNames } from '../vc-tree-select/interface';
|
import type { DefaultValueType, FieldNames } from '../vc-tree-select/interface';
|
||||||
|
@ -23,6 +21,7 @@ import devWarning from '../vc-util/devWarning';
|
||||||
import getIcons from '../select/utils/iconUtil';
|
import getIcons from '../select/utils/iconUtil';
|
||||||
import renderSwitcherIcon from '../tree/utils/iconUtil';
|
import renderSwitcherIcon from '../tree/utils/iconUtil';
|
||||||
import type { AntTreeNodeProps } from '../tree/Tree';
|
import type { AntTreeNodeProps } from '../tree/Tree';
|
||||||
|
import { warning } from '../vc-util/warning';
|
||||||
|
|
||||||
const getTransitionName = (rootPrefixCls: string, motion: string, transitionName?: string) => {
|
const getTransitionName = (rootPrefixCls: string, motion: string, transitionName?: string) => {
|
||||||
if (transitionName !== undefined) {
|
if (transitionName !== undefined) {
|
||||||
|
@ -53,6 +52,7 @@ export const treeSelectProps = {
|
||||||
replaceFields: { type: Object as PropType<FieldNames> },
|
replaceFields: { type: Object as PropType<FieldNames> },
|
||||||
};
|
};
|
||||||
export type TreeSelectProps = Partial<ExtractPropTypes<typeof treeSelectProps>>;
|
export type TreeSelectProps = Partial<ExtractPropTypes<typeof treeSelectProps>>;
|
||||||
|
|
||||||
const TreeSelect = defineComponent({
|
const TreeSelect = defineComponent({
|
||||||
TreeNode,
|
TreeNode,
|
||||||
SHOW_ALL,
|
SHOW_ALL,
|
||||||
|
@ -68,8 +68,19 @@ const TreeSelect = defineComponent({
|
||||||
listItemHeight: 26,
|
listItemHeight: 26,
|
||||||
bordered: true,
|
bordered: true,
|
||||||
}),
|
}),
|
||||||
slots: ['placeholder', 'maxTagPlaceholder', 'treeIcon', 'switcherIcon', 'notFoundContent'],
|
slots: [
|
||||||
|
'title',
|
||||||
|
'placeholder',
|
||||||
|
'maxTagPlaceholder',
|
||||||
|
'treeIcon',
|
||||||
|
'switcherIcon',
|
||||||
|
'notFoundContent',
|
||||||
|
],
|
||||||
setup(props, { attrs, slots, expose, emit }) {
|
setup(props, { attrs, slots, expose, emit }) {
|
||||||
|
warning(
|
||||||
|
!(props.treeData === undefined && slots.default),
|
||||||
|
'`children` of Tree is deprecated. Please use `treeData` instead.',
|
||||||
|
);
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
devWarning(
|
devWarning(
|
||||||
props.multiple !== false || !props.treeCheckable,
|
props.multiple !== false || !props.treeCheckable,
|
||||||
|
@ -212,6 +223,7 @@ const TreeSelect = defineComponent({
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
onTreeExpand={handleTreeExpand}
|
onTreeExpand={handleTreeExpand}
|
||||||
v-slots={{
|
v-slots={{
|
||||||
|
...slots,
|
||||||
treeCheckable: () => <span class={`${prefixCls.value}-tree-checkbox-inner`} />,
|
treeCheckable: () => <span class={`${prefixCls.value}-tree-checkbox-inner`} />,
|
||||||
}}
|
}}
|
||||||
children={slots.default?.()}
|
children={slots.default?.()}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
|
||||||
import { SelectProps } from '../select';
|
|
||||||
import { tuple } from '../_util/type';
|
|
||||||
|
|
||||||
export const TreeData = PropTypes.shape({
|
|
||||||
key: PropTypes.string,
|
|
||||||
value: PropTypes.string,
|
|
||||||
label: PropTypes.VNodeChild,
|
|
||||||
slots: PropTypes.object,
|
|
||||||
children: PropTypes.array,
|
|
||||||
}).loose;
|
|
||||||
|
|
||||||
export const TreeSelectProps = () => ({
|
|
||||||
...SelectProps(),
|
|
||||||
autofocus: PropTypes.looseBool,
|
|
||||||
dropdownStyle: PropTypes.object,
|
|
||||||
filterTreeNode: withUndefined(PropTypes.oneOfType([Function, Boolean])),
|
|
||||||
getPopupContainer: PropTypes.func,
|
|
||||||
labelInValue: PropTypes.looseBool,
|
|
||||||
loadData: PropTypes.func,
|
|
||||||
maxTagCount: PropTypes.number,
|
|
||||||
maxTagPlaceholder: PropTypes.VNodeChild,
|
|
||||||
value: PropTypes.oneOfType([
|
|
||||||
PropTypes.string,
|
|
||||||
PropTypes.object,
|
|
||||||
PropTypes.array,
|
|
||||||
PropTypes.number,
|
|
||||||
]),
|
|
||||||
defaultValue: PropTypes.oneOfType([
|
|
||||||
PropTypes.string,
|
|
||||||
PropTypes.object,
|
|
||||||
PropTypes.array,
|
|
||||||
PropTypes.number,
|
|
||||||
]),
|
|
||||||
multiple: PropTypes.looseBool,
|
|
||||||
notFoundContent: PropTypes.VNodeChild,
|
|
||||||
searchPlaceholder: PropTypes.string,
|
|
||||||
searchValue: PropTypes.string,
|
|
||||||
showCheckedStrategy: PropTypes.oneOf(tuple('SHOW_ALL', 'SHOW_PARENT', 'SHOW_CHILD')),
|
|
||||||
suffixIcon: PropTypes.VNodeChild,
|
|
||||||
treeCheckable: PropTypes.looseBool,
|
|
||||||
treeCheckStrictly: PropTypes.looseBool,
|
|
||||||
treeData: PropTypes.arrayOf(Object),
|
|
||||||
treeDataSimpleMode: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, Object])),
|
|
||||||
|
|
||||||
dropdownClassName: PropTypes.string,
|
|
||||||
dropdownMatchSelectWidth: PropTypes.looseBool,
|
|
||||||
treeDefaultExpandAll: PropTypes.looseBool,
|
|
||||||
treeExpandedKeys: PropTypes.array,
|
|
||||||
treeIcon: PropTypes.looseBool,
|
|
||||||
treeDefaultExpandedKeys: PropTypes.array,
|
|
||||||
treeNodeFilterProp: PropTypes.string,
|
|
||||||
treeNodeLabelProp: PropTypes.string,
|
|
||||||
replaceFields: PropTypes.object.def({}),
|
|
||||||
clearIcon: PropTypes.VNodeChild,
|
|
||||||
removeIcon: PropTypes.VNodeChild,
|
|
||||||
|
|
||||||
onSelect: PropTypes.func,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
onSearch: PropTypes.func,
|
|
||||||
onTreeExpand: PropTypes.func,
|
|
||||||
'onUpdate:treeExpandedKeys': PropTypes.func,
|
|
||||||
'onUpdate:searchValue': PropTypes.func,
|
|
||||||
'onUpdate:value': PropTypes.func,
|
|
||||||
});
|
|
|
@ -13,6 +13,7 @@ import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import renderSwitcherIcon from './utils/iconUtil';
|
import renderSwitcherIcon from './utils/iconUtil';
|
||||||
import dropIndicatorRender from './utils/dropIndicator';
|
import dropIndicatorRender from './utils/dropIndicator';
|
||||||
import devWarning from '../vc-util/devWarning';
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
import { warning } from '../vc-util/warning';
|
||||||
|
|
||||||
export interface AntdTreeNodeAttribute {
|
export interface AntdTreeNodeAttribute {
|
||||||
eventKey: string;
|
eventKey: string;
|
||||||
|
@ -153,6 +154,10 @@ export default defineComponent({
|
||||||
],
|
],
|
||||||
TreeNode,
|
TreeNode,
|
||||||
setup(props, { attrs, expose, emit, slots }) {
|
setup(props, { attrs, expose, emit, slots }) {
|
||||||
|
warning(
|
||||||
|
!(props.treeData === undefined && slots.default),
|
||||||
|
'`children` of Tree is deprecated. Please use `treeData` instead.',
|
||||||
|
);
|
||||||
const { prefixCls, direction, virtual } = useConfigInject('tree', props);
|
const { prefixCls, direction, virtual } = useConfigInject('tree', props);
|
||||||
const treeRef = ref();
|
const treeRef = ref();
|
||||||
expose({
|
expose({
|
||||||
|
|
|
@ -42,7 +42,7 @@ import {
|
||||||
flattenOptions,
|
flattenOptions,
|
||||||
fillOptionsWithMissingValue,
|
fillOptionsWithMissingValue,
|
||||||
} from './utils/valueUtil';
|
} from './utils/valueUtil';
|
||||||
import type { SelectProps } from './generate';
|
import { selectBaseProps, SelectProps } from './generate';
|
||||||
import generateSelector from './generate';
|
import generateSelector from './generate';
|
||||||
import type { DefaultValueType } from './interface/generator';
|
import type { DefaultValueType } from './interface/generator';
|
||||||
import warningProps from './utils/warningPropsUtil';
|
import warningProps from './utils/warningPropsUtil';
|
||||||
|
@ -68,6 +68,10 @@ export type ExportedSelectProps<T extends DefaultValueType = DefaultValueType> =
|
||||||
T
|
T
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export function selectProps<T>() {
|
||||||
|
return selectBaseProps<SelectOptionsType[number], T>();
|
||||||
|
}
|
||||||
|
|
||||||
const Select = defineComponent({
|
const Select = defineComponent({
|
||||||
name: 'Select',
|
name: 'Select',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
|
|
@ -2,8 +2,9 @@ import pickAttrs from '../../_util/pickAttrs';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import type { InnerSelectorProps } from './interface';
|
import type { InnerSelectorProps } from './interface';
|
||||||
import type { VNodeChild } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
import { computed, defineComponent, Fragment, ref, watch } from 'vue';
|
import { computed, defineComponent, ref, watch } from 'vue';
|
||||||
import PropTypes from '../../_util/vue-types';
|
import PropTypes from '../../_util/vue-types';
|
||||||
|
import { useInjectTreeSelectContext } from 'ant-design-vue/es/vc-tree-select/Context';
|
||||||
|
|
||||||
interface SelectorProps extends InnerSelectorProps {
|
interface SelectorProps extends InnerSelectorProps {
|
||||||
inputElement: VNodeChild;
|
inputElement: VNodeChild;
|
||||||
|
@ -50,6 +51,7 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
}
|
}
|
||||||
return inputValue;
|
return inputValue;
|
||||||
});
|
});
|
||||||
|
const treeSelectContext = useInjectTreeSelectContext();
|
||||||
watch(
|
watch(
|
||||||
[combobox, () => props.activeValue],
|
[combobox, () => props.activeValue],
|
||||||
() => {
|
() => {
|
||||||
|
@ -94,6 +96,12 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
onInputCompositionEnd,
|
onInputCompositionEnd,
|
||||||
} = props;
|
} = props;
|
||||||
const item = values[0];
|
const item = values[0];
|
||||||
|
let slotTitle = null;
|
||||||
|
if (treeSelectContext.value.slots) {
|
||||||
|
slotTitle =
|
||||||
|
treeSelectContext.value.slots[item?.option?.data?.slots?.title] ||
|
||||||
|
treeSelectContext.value.slots.title;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span class={`${prefixCls}-selection-search`}>
|
<span class={`${prefixCls}-selection-search`}>
|
||||||
|
@ -126,7 +134,8 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
{/* Display value */}
|
{/* Display value */}
|
||||||
{!combobox.value && item && !hasTextInput.value && (
|
{!combobox.value && item && !hasTextInput.value && (
|
||||||
<span class={`${prefixCls}-selection-item`} title={title.value}>
|
<span class={`${prefixCls}-selection-item`} title={title.value}>
|
||||||
<Fragment key={item.key || item.value}>{item.label}</Fragment>
|
{/* <Fragment key={item.key || item.value}>{item.label}</Fragment> */}
|
||||||
|
{slotTitle?.(item.option?.data) || item.label}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ export function selectBaseProps<OptionType, ValueType>() {
|
||||||
defaultOpen: { type: Boolean, default: undefined },
|
defaultOpen: { type: Boolean, default: undefined },
|
||||||
listHeight: Number,
|
listHeight: Number,
|
||||||
listItemHeight: Number,
|
listItemHeight: Number,
|
||||||
dropdownStyle: { type: Function as PropType<CSSProperties> },
|
dropdownStyle: { type: Object as PropType<CSSProperties> },
|
||||||
dropdownClassName: String,
|
dropdownClassName: String,
|
||||||
dropdownMatchSelectWidth: {
|
dropdownMatchSelectWidth: {
|
||||||
type: [Boolean, Number] as PropType<boolean | number>,
|
type: [Boolean, Number] as PropType<boolean | number>,
|
||||||
|
@ -275,7 +275,7 @@ export default function generateSelector<
|
||||||
slots: ['option'],
|
slots: ['option'],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: selectBaseProps<OptionType, DefaultValueType>(),
|
props: selectBaseProps<OptionType, DefaultValueType>(),
|
||||||
setup(props) {
|
setup(props, { expose }) {
|
||||||
const useInternalProps = computed(
|
const useInternalProps = computed(
|
||||||
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
||||||
);
|
);
|
||||||
|
@ -455,10 +455,10 @@ export default function generateSelector<
|
||||||
labelInValue: mergedLabelInValue.value,
|
labelInValue: mergedLabelInValue.value,
|
||||||
optionLabelProp: mergedOptionLabelProp.value,
|
optionLabelProp: mergedOptionLabelProp.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...displayValue,
|
...displayValue,
|
||||||
disabled: isValueDisabled(val, valueOptions),
|
disabled: isValueDisabled(val, valueOptions),
|
||||||
|
option: valueOptions[0],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -947,10 +947,12 @@ export default function generateSelector<
|
||||||
const blur = () => {
|
const blur = () => {
|
||||||
selectorRef.value.blur();
|
selectorRef.value.blur();
|
||||||
};
|
};
|
||||||
return {
|
expose({
|
||||||
focus,
|
focus,
|
||||||
blur,
|
blur,
|
||||||
scrollTo: listRef.value?.scrollTo,
|
scrollTo: (...args: any[]) => listRef.value?.scrollTo(...args),
|
||||||
|
});
|
||||||
|
return {
|
||||||
tokenWithEnter,
|
tokenWithEnter,
|
||||||
mockFocused,
|
mockFocused,
|
||||||
mergedId,
|
mergedId,
|
||||||
|
@ -1139,7 +1141,7 @@ export default function generateSelector<
|
||||||
menuItemSelectedIcon={menuItemSelectedIcon}
|
menuItemSelectedIcon={menuItemSelectedIcon}
|
||||||
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
||||||
onMouseenter={onPopupMouseEnter}
|
onMouseenter={onPopupMouseEnter}
|
||||||
v-slots={{ option: slots.option }}
|
v-slots={{ ...slots, option: slots.option }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1212,7 +1214,6 @@ export default function generateSelector<
|
||||||
[`${prefixCls}-customize-input`]: customizeInputElement,
|
[`${prefixCls}-customize-input`]: customizeInputElement,
|
||||||
[`${prefixCls}-show-search`]: mergedShowSearch,
|
[`${prefixCls}-show-search`]: mergedShowSearch,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...this.$attrs}
|
{...this.$attrs}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import type { ExportedSelectProps } from './Select';
|
import type { ExportedSelectProps } from './Select';
|
||||||
import Select from './Select';
|
import Select, { selectProps } from './Select';
|
||||||
import Option from './Option';
|
import Option from './Option';
|
||||||
import OptGroup from './OptGroup';
|
import OptGroup from './OptGroup';
|
||||||
import { selectBaseProps } from './generate';
|
import { selectBaseProps } from './generate';
|
||||||
import type { ExtractPropTypes } from 'vue';
|
import type { ExtractPropTypes } from 'vue';
|
||||||
|
|
||||||
export type SelectProps<T = any> = Partial<ExtractPropTypes<ExportedSelectProps<T>>>;
|
export type SelectProps<T = any> = Partial<ExtractPropTypes<ExportedSelectProps<T>>>;
|
||||||
export { Option, OptGroup, selectBaseProps };
|
export { Option, OptGroup, selectBaseProps, selectProps };
|
||||||
|
|
||||||
export default Select;
|
export default Select;
|
||||||
|
|
|
@ -50,7 +50,7 @@ export const SelectContext = defineComponent({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useInjectSelectContext = () => {
|
export const useInjectTreeSelectContext = () => {
|
||||||
return inject(
|
return inject(
|
||||||
SelectContextKey,
|
SelectContextKey,
|
||||||
computed(() => ({} as ContextProps)),
|
computed(() => ({} as ContextProps)),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { DataNode, TreeDataNode, Key } from './interface';
|
import type { DataNode, TreeDataNode, Key } from './interface';
|
||||||
import { useInjectSelectContext } from './Context';
|
import { useInjectTreeSelectContext } from './Context';
|
||||||
import type { RefOptionListProps } from '../vc-select/OptionList';
|
import type { RefOptionListProps } from '../vc-select/OptionList';
|
||||||
import type { ScrollTo } from '../vc-virtual-list/List';
|
import type { ScrollTo } from '../vc-virtual-list/List';
|
||||||
import { computed, defineComponent, nextTick, ref, watch } from 'vue';
|
import { computed, defineComponent, nextTick, ref, watch } from 'vue';
|
||||||
|
@ -36,7 +36,7 @@ export default defineComponent({
|
||||||
slots: ['notFoundContent', 'menuItemSelectedIcon'],
|
slots: ['notFoundContent', 'menuItemSelectedIcon'],
|
||||||
expose: ['scrollTo', 'onKeydown', 'onKeyup'],
|
expose: ['scrollTo', 'onKeydown', 'onKeyup'],
|
||||||
setup(props, { slots, expose }) {
|
setup(props, { slots, expose }) {
|
||||||
const context = useInjectSelectContext();
|
const context = useInjectTreeSelectContext();
|
||||||
|
|
||||||
const treeRef = ref();
|
const treeRef = ref();
|
||||||
const memoOptions = useMemo(
|
const memoOptions = useMemo(
|
||||||
|
@ -144,7 +144,7 @@ export default defineComponent({
|
||||||
activeKey.value = key;
|
activeKey.value = key;
|
||||||
};
|
};
|
||||||
expose({
|
expose({
|
||||||
scrollTo: treeRef.value?.scrollTo as ScrollTo,
|
scrollTo: (...args: any[]) => treeRef.value.scrollTo?.(...args),
|
||||||
onKeydown: (event: KeyboardEvent) => {
|
onKeydown: (event: KeyboardEvent) => {
|
||||||
const { which } = event;
|
const { which } = event;
|
||||||
switch (which) {
|
switch (which) {
|
||||||
|
@ -217,7 +217,6 @@ export default defineComponent({
|
||||||
if (mergedExpandedKeys.value) {
|
if (mergedExpandedKeys.value) {
|
||||||
treeProps.expandedKeys = mergedExpandedKeys.value;
|
treeProps.expandedKeys = mergedExpandedKeys.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onMousedown={onListMouseDown} onMouseenter={onMouseenter}>
|
<div onMousedown={onListMouseDown} onMouseenter={onMouseenter}>
|
||||||
{activeEntity.value && open && (
|
{activeEntity.value && open && (
|
||||||
|
@ -255,7 +254,7 @@ export default defineComponent({
|
||||||
onExpand={onInternalExpand}
|
onExpand={onInternalExpand}
|
||||||
onLoad={onTreeLoad}
|
onLoad={onTreeLoad}
|
||||||
filterTreeNode={filterTreeNode}
|
filterTreeNode={filterTreeNode}
|
||||||
v-slots={{ checkable: context.value.customCheckable }}
|
v-slots={{ ...slots, checkable: context.value.customCheckable }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -91,7 +91,15 @@ export default function generate(config: {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name: 'TreeSelect',
|
name: 'TreeSelect',
|
||||||
props: treeSelectProps(),
|
props: treeSelectProps(),
|
||||||
slots: ['placeholder', 'maxTagPlaceholder', 'treeIcon', 'switcherIcon', 'notFoundContent'],
|
slots: [
|
||||||
|
'title',
|
||||||
|
'placeholder',
|
||||||
|
'maxTagPlaceholder',
|
||||||
|
'treeIcon',
|
||||||
|
'switcherIcon',
|
||||||
|
'notFoundContent',
|
||||||
|
'treeCheckable',
|
||||||
|
],
|
||||||
TreeNode,
|
TreeNode,
|
||||||
SHOW_ALL,
|
SHOW_ALL,
|
||||||
SHOW_PARENT,
|
SHOW_PARENT,
|
||||||
|
@ -105,7 +113,6 @@ export default function generate(config: {
|
||||||
// ======================= Tree Data =======================
|
// ======================= Tree Data =======================
|
||||||
// FieldNames
|
// FieldNames
|
||||||
const mergedFieldNames = computed(() => fillFieldNames(props.fieldNames, true));
|
const mergedFieldNames = computed(() => fillFieldNames(props.fieldNames, true));
|
||||||
|
|
||||||
// Legacy both support `label` or `title` if not set.
|
// Legacy both support `label` or `title` if not set.
|
||||||
// We have to fallback to function to handle this
|
// We have to fallback to function to handle this
|
||||||
const getTreeNodeTitle = (node: DataNode) => {
|
const getTreeNodeTitle = (node: DataNode) => {
|
||||||
|
@ -157,9 +164,9 @@ export default function generate(config: {
|
||||||
const selectRef = ref(null);
|
const selectRef = ref(null);
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
scrollTo: selectRef.value.scrollTo,
|
scrollTo: (...args: any[]) => selectRef.value.scrollTo?.(...args),
|
||||||
focus: selectRef.value.focus,
|
focus: () => selectRef.value.focus?.(),
|
||||||
blur: selectRef.value.blur,
|
blur: () => selectRef.value?.blur(),
|
||||||
|
|
||||||
/** @private Internal usage. It's save to remove if `rc-cascader` not use it any longer */
|
/** @private Internal usage. It's save to remove if `rc-cascader` not use it any longer */
|
||||||
getEntityByValue,
|
getEntityByValue,
|
||||||
|
@ -477,7 +484,7 @@ export default function generate(config: {
|
||||||
treeNodeFilterProp,
|
treeNodeFilterProp,
|
||||||
getEntityByKey,
|
getEntityByKey,
|
||||||
getEntityByValue,
|
getEntityByValue,
|
||||||
customCheckable: slots.checkable,
|
customCheckable: slots.treeCheckable,
|
||||||
slots,
|
slots,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
@ -496,6 +503,7 @@ export default function generate(config: {
|
||||||
onSelect={null}
|
onSelect={null}
|
||||||
onDeselect={null}
|
onDeselect={null}
|
||||||
onDropdownVisibleChange={onInternalDropdownVisibleChange}
|
onDropdownVisibleChange={onInternalDropdownVisibleChange}
|
||||||
|
v-slots={slots}
|
||||||
/>
|
/>
|
||||||
</SelectContext>
|
</SelectContext>
|
||||||
);
|
);
|
||||||
|
|
|
@ -78,6 +78,10 @@ function formatTreeData(
|
||||||
node,
|
node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (node.slots) {
|
||||||
|
dataNode.slots = node.slots;
|
||||||
|
}
|
||||||
|
|
||||||
// Check `key` & `value` and warning user
|
// Check `key` & `value` and warning user
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -38,6 +38,8 @@ export interface InternalDataEntity {
|
||||||
|
|
||||||
/** Origin DataNode */
|
/** Origin DataNode */
|
||||||
node: DataNode;
|
node: DataNode;
|
||||||
|
|
||||||
|
slots?: Record<string, string>; // 兼容 V2
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LegacyDataNode extends DataNode {
|
export interface LegacyDataNode extends DataNode {
|
||||||
|
|
|
@ -84,10 +84,6 @@ export default defineComponent({
|
||||||
// abstract-drag-over-node is the top node
|
// abstract-drag-over-node is the top node
|
||||||
dragOverNodeKey: null,
|
dragOverNodeKey: null,
|
||||||
});
|
});
|
||||||
warning(
|
|
||||||
!(props.treeData === undefined && props.children),
|
|
||||||
'`children` of Tree is deprecated. Please use `treeData` instead.',
|
|
||||||
);
|
|
||||||
const treeData = computed(() => {
|
const treeData = computed(() => {
|
||||||
return props.treeData !== undefined ? props.treeData : convertTreeToData(props.children);
|
return props.treeData !== undefined ? props.treeData : convertTreeToData(props.children);
|
||||||
});
|
});
|
||||||
|
@ -953,6 +949,7 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
expose({
|
expose({
|
||||||
onNodeExpand,
|
onNodeExpand,
|
||||||
|
scrollTo,
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('dragend', onWindowDragEnd);
|
window.removeEventListener('dragend', onWindowDragEnd);
|
||||||
|
|
|
@ -22,7 +22,9 @@ export default defineComponent({
|
||||||
setup(props, { attrs, slots, expose }) {
|
setup(props, { attrs, slots, expose }) {
|
||||||
warning(
|
warning(
|
||||||
!('slots' in props.data),
|
!('slots' in props.data),
|
||||||
'treeData slots is deprecated, please use `v-slot:icon` or `v-slot:title`, `v-slot:switcherIcon` instead',
|
`treeData slots is deprecated, please use ${Object.keys(props.data.slots || {}).map(
|
||||||
|
key => '`v-slot:' + key + '` ',
|
||||||
|
)}instead`,
|
||||||
);
|
);
|
||||||
const dragNodeHighlight = ref(false);
|
const dragNodeHighlight = ref(false);
|
||||||
const context = useInjectTreeContext();
|
const context = useInjectTreeContext();
|
||||||
|
@ -346,7 +348,9 @@ export default defineComponent({
|
||||||
// Icon + Title
|
// Icon + Title
|
||||||
const renderSelector = () => {
|
const renderSelector = () => {
|
||||||
const {
|
const {
|
||||||
title = slots.title || context.value.slots?.[props.data?.slots?.title],
|
title = slots.title ||
|
||||||
|
context.value.slots?.[props.data?.slots?.title] ||
|
||||||
|
context.value.slots?.title,
|
||||||
selected,
|
selected,
|
||||||
icon = slots.icon,
|
icon = slots.icon,
|
||||||
loading,
|
loading,
|
||||||
|
|
|
@ -1,49 +1,63 @@
|
||||||
<template>
|
<template>
|
||||||
<a-directory-tree
|
<a-tree-select
|
||||||
v-model:expandedKeys="expandedKeys"
|
v-model:value="value"
|
||||||
v-model:selectedKeys="selectedKeys"
|
style="width: 100%"
|
||||||
multiple
|
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||||
:tree-data1="treeData"
|
:tree-data="treeData"
|
||||||
|
placeholder="Please select"
|
||||||
|
tree-default-expand-all
|
||||||
>
|
>
|
||||||
<a-tree-node key="0-0" title="ddd" class="test" style="color: red">
|
<template #title1="{ key, value }">
|
||||||
<template #title="{ title }">{{ title }}</template>
|
<span v-if="key === '0-0-1'" style="color: #08c">Child Node1 {{ value }}</span>
|
||||||
<a-tree-node key="0-0-0" title="leaf 0-0" is-leaf />
|
</template>
|
||||||
<a-tree-node key="0-0-1" title="leaf 0-1" is-leaf />
|
</a-tree-select>
|
||||||
</a-tree-node>
|
|
||||||
<a-tree-node key="0-1" title="parent 1">
|
|
||||||
<a-tree-node key="0-1-0" title="leaf 1-0" is-leaf />
|
|
||||||
<a-tree-node key="0-1-1" title="leaf 1-1" is-leaf />
|
|
||||||
</a-tree-node>
|
|
||||||
</a-directory-tree>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch } from 'vue';
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
interface TreeDataItem {
|
||||||
const expandedKeys = ref<string[]>([]);
|
value: string;
|
||||||
const selectedKeys = ref<string[]>([]);
|
key: string;
|
||||||
const treeData = [
|
title?: string;
|
||||||
|
slots?: Record<string, string>;
|
||||||
|
children?: TreeDataItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeData: TreeDataItem[] = [
|
||||||
{
|
{
|
||||||
title: 'parent 0',
|
title: 'Node1',
|
||||||
|
value: '0-0',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
children: [
|
children: [
|
||||||
{ title: 'leaf 0-0', key: '0-0-0', isLeaf: true },
|
{
|
||||||
// { title: 'leaf 0-1', key: '0-0-1', isLeaf: true },
|
value: '0-0-1',
|
||||||
|
key: '0-0-1',
|
||||||
|
slots: {
|
||||||
|
title: 'title1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Child Node2',
|
||||||
|
value: '0-0-2',
|
||||||
|
key: '0-0-2',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'parent 1',
|
title: 'Node2',
|
||||||
|
value: '0-1',
|
||||||
key: '0-1',
|
key: '0-1',
|
||||||
children: [
|
|
||||||
{ title: 'leaf 1-0', key: '0-1-0', isLeaf: true },
|
|
||||||
{ title: 'leaf 1-1', key: '0-1-1', isLeaf: true },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const value = ref<string>();
|
||||||
|
|
||||||
|
watch(value, () => {
|
||||||
|
console.log(value.value);
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
expandedKeys,
|
value,
|
||||||
selectedKeys,
|
|
||||||
onTest: () => {},
|
|
||||||
treeData,
|
treeData,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue