refactor: tree-select
parent
956ed09885
commit
fdf7c5d4ce
|
@ -29,14 +29,17 @@ import { SelectContext } from './Context';
|
||||||
import useTreeData from './hooks/useTreeData';
|
import useTreeData from './hooks/useTreeData';
|
||||||
import useKeyValueMap from './hooks/useKeyValueMap';
|
import useKeyValueMap from './hooks/useKeyValueMap';
|
||||||
import useKeyValueMapping from './hooks/useKeyValueMapping';
|
import useKeyValueMapping from './hooks/useKeyValueMapping';
|
||||||
import type { CheckedStrategy } from './utils/strategyUtil';
|
|
||||||
import { formatStrategyKeys, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './utils/strategyUtil';
|
import { formatStrategyKeys, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './utils/strategyUtil';
|
||||||
import { fillAdditionalInfo } from './utils/legacyUtil';
|
import { fillAdditionalInfo } from './utils/legacyUtil';
|
||||||
import useSelectValues from './hooks/useSelectValues';
|
import useSelectValues from './hooks/useSelectValues';
|
||||||
import { treeSelectProps, TreeSelectProps } from './props';
|
import { treeSelectProps, TreeSelectProps } from './props';
|
||||||
import { getLabeledValue } from '../vc-select/utils/valueUtil';
|
import { getLabeledValue } from '../vc-select/utils/valueUtil';
|
||||||
import omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
import { defineComponent } from 'vue';
|
import { computed, defineComponent, ref, toRef, watch, watchEffect } from 'vue';
|
||||||
|
import { convertDataToEntities } from '../vc-tree/utils/treeUtil';
|
||||||
|
import { conductCheck } from '../vc-tree/utils/conductUtil';
|
||||||
|
import { warning } from '../vc-util/warning';
|
||||||
|
import { INTERNAL_PROPS_MARK } from '../vc-select/interface/generator';
|
||||||
|
|
||||||
const OMIT_PROPS: (keyof TreeSelectProps)[] = [
|
const OMIT_PROPS: (keyof TreeSelectProps)[] = [
|
||||||
'expandedKeys' as any,
|
'expandedKeys' as any,
|
||||||
|
@ -91,9 +94,413 @@ export default function generate(config: {
|
||||||
props: treeSelectProps(),
|
props: treeSelectProps(),
|
||||||
slots: [],
|
slots: [],
|
||||||
name: 'TreeSelect',
|
name: 'TreeSelect',
|
||||||
setup(props) {
|
TreeNode: TreeNode,
|
||||||
return () => {
|
SHOW_ALL: SHOW_ALL,
|
||||||
|
SHOW_PARENT: SHOW_PARENT,
|
||||||
|
SHOW_CHILD: SHOW_CHILD,
|
||||||
|
setup(props, { expose, slots, attrs }) {
|
||||||
|
const mergedCheckable = computed(() => props.treeCheckable || props.treeCheckStrictly);
|
||||||
|
const mergedMultiple = computed(() => props.multiple || mergedCheckable.value);
|
||||||
|
const treeConduction = computed(() => props.treeCheckable && !props.treeCheckStrictly);
|
||||||
|
const mergedLabelInValue = computed(() => props.treeCheckStrictly || props.labelInValue);
|
||||||
|
|
||||||
|
// ======================= Tree Data =======================
|
||||||
|
// FieldNames
|
||||||
|
const mergedFieldNames = computed(() => fillFieldNames(props.fieldNames, true));
|
||||||
|
|
||||||
|
// Legacy both support `label` or `title` if not set.
|
||||||
|
// We have to fallback to function to handle this
|
||||||
|
const getTreeNodeTitle = (node: DataNode) => {
|
||||||
|
if (!props.treeData) {
|
||||||
|
return node.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergedFieldNames.value?.label) {
|
||||||
|
return node[mergedFieldNames.value.label];
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.label || node.title;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTreeNodeLabelProp = (entity: FlattenDataNode) => {
|
||||||
|
const { labelRender, treeNodeLabelProp } = props;
|
||||||
|
const { node } = entity.data;
|
||||||
|
|
||||||
|
if (labelRender) {
|
||||||
|
return labelRender(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (treeNodeLabelProp) {
|
||||||
|
return node[treeNodeLabelProp];
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTreeNodeTitle(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergedTreeData = useTreeData(toRef(props, 'treeData'), toRef(props, 'children'), {
|
||||||
|
getLabelProp: getTreeNodeTitle,
|
||||||
|
simpleMode: toRef(props, 'treeDataSimpleMode'),
|
||||||
|
fieldNames: mergedFieldNames,
|
||||||
|
});
|
||||||
|
|
||||||
|
const flattedOptions = computed(() => flattenOptions(mergedTreeData.value));
|
||||||
|
const [cacheKeyMap, cacheValueMap] = useKeyValueMap(flattedOptions);
|
||||||
|
const [getEntityByKey, getEntityByValue] = useKeyValueMapping(cacheKeyMap, cacheValueMap);
|
||||||
|
|
||||||
|
// Only generate keyEntities for check conduction when is `treeCheckable`
|
||||||
|
const conductKeyEntities = computed(() => {
|
||||||
|
if (treeConduction.value) {
|
||||||
|
return convertDataToEntities(mergedTreeData.value).keyEntities;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================== Ref ==========================
|
||||||
|
const selectRef = ref(null);
|
||||||
|
|
||||||
|
expose({
|
||||||
|
scrollTo: selectRef.value.scrollTo,
|
||||||
|
focus: selectRef.value.focus,
|
||||||
|
blur: selectRef.value.blur,
|
||||||
|
|
||||||
|
/** @private Internal usage. It's save to remove if `rc-cascader` not use it any longer */
|
||||||
|
getEntityByValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
const valueRef = ref<DefaultValueType>(props.defaultValue);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
() => {
|
||||||
|
if (props.value !== undefined) {
|
||||||
|
valueRef.value = props.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Get `missingRawValues` which not exist in the tree yet */
|
||||||
|
const splitRawValues = (newRawValues: RawValueType[]) => {
|
||||||
|
const missingRawValues = [];
|
||||||
|
const existRawValues = [];
|
||||||
|
|
||||||
|
// Keep missing value in the cache
|
||||||
|
newRawValues.forEach(val => {
|
||||||
|
if (getEntityByValue(val)) {
|
||||||
|
existRawValues.push(val);
|
||||||
|
} else {
|
||||||
|
missingRawValues.push(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { missingRawValues, existRawValues };
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawValues = ref<RawValueType[]>([]);
|
||||||
|
const rawHalfCheckedKeys = ref<RawValueType[]>([]);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const valueHalfCheckedKeys: RawValueType[] = [];
|
||||||
|
const newRawValues: RawValueType[] = [];
|
||||||
|
|
||||||
|
toArray(valueRef.value).forEach(item => {
|
||||||
|
if (item && typeof item === 'object' && 'value' in item) {
|
||||||
|
if (item.halfChecked && props.treeCheckStrictly) {
|
||||||
|
const entity = getEntityByValue(item.value);
|
||||||
|
valueHalfCheckedKeys.push(entity ? entity.key : item.value);
|
||||||
|
} else {
|
||||||
|
newRawValues.push(item.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRawValues.push(item as RawValueType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// We need do conduction of values
|
||||||
|
if (treeConduction.value) {
|
||||||
|
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
|
||||||
|
const keyList = existRawValues.map(val => getEntityByValue(val).key);
|
||||||
|
|
||||||
|
const { checkedKeys, halfCheckedKeys } = conductCheck(
|
||||||
|
keyList,
|
||||||
|
true,
|
||||||
|
conductKeyEntities.value,
|
||||||
|
);
|
||||||
|
rawValues.value = [
|
||||||
|
...missingRawValues,
|
||||||
|
...checkedKeys.map(key => getEntityByKey(key).data.value),
|
||||||
|
];
|
||||||
|
rawHalfCheckedKeys.value = halfCheckedKeys;
|
||||||
|
}
|
||||||
|
[rawValues.value, rawHalfCheckedKeys.value] = [newRawValues, valueHalfCheckedKeys];
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectValues = useSelectValues(rawValues, {
|
||||||
|
treeConduction,
|
||||||
|
value: valueRef,
|
||||||
|
showCheckedStrategy: toRef(props, 'showCheckedStrategy'),
|
||||||
|
conductKeyEntities,
|
||||||
|
getEntityByValue,
|
||||||
|
getEntityByKey,
|
||||||
|
getLabelProp: getTreeNodeLabelProp,
|
||||||
|
});
|
||||||
|
|
||||||
|
const triggerChange = (
|
||||||
|
newRawValues: RawValueType[],
|
||||||
|
extra: { triggerValue: RawValueType; selected: boolean },
|
||||||
|
source: SelectSource,
|
||||||
|
) => {
|
||||||
|
const { onChange, showCheckedStrategy, treeCheckStrictly } = props;
|
||||||
|
const preValue = valueRef.value;
|
||||||
|
valueRef.value = mergedMultiple.value ? newRawValues : newRawValues[0];
|
||||||
|
if (onChange) {
|
||||||
|
let eventValues: RawValueType[] = newRawValues;
|
||||||
|
if (treeConduction.value && showCheckedStrategy !== 'SHOW_ALL') {
|
||||||
|
const keyList = newRawValues.map(val => {
|
||||||
|
const entity = getEntityByValue(val);
|
||||||
|
return entity ? entity.key : val;
|
||||||
|
});
|
||||||
|
const formattedKeyList = formatStrategyKeys(
|
||||||
|
keyList,
|
||||||
|
showCheckedStrategy,
|
||||||
|
conductKeyEntities.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
eventValues = formattedKeyList.map(key => {
|
||||||
|
const entity = getEntityByKey(key);
|
||||||
|
return entity ? entity.data.value : key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { triggerValue, selected } = extra || {
|
||||||
|
triggerValue: undefined,
|
||||||
|
selected: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
let returnValues = mergedLabelInValue.value
|
||||||
|
? getRawValueLabeled(eventValues, preValue, getEntityByValue, getTreeNodeLabelProp)
|
||||||
|
: eventValues;
|
||||||
|
|
||||||
|
// We need fill half check back
|
||||||
|
if (treeCheckStrictly) {
|
||||||
|
const halfValues = rawHalfCheckedKeys.value
|
||||||
|
.map(key => {
|
||||||
|
const entity = getEntityByKey(key);
|
||||||
|
return entity ? entity.data.value : key;
|
||||||
|
})
|
||||||
|
.filter(val => !eventValues.includes(val));
|
||||||
|
|
||||||
|
returnValues = [
|
||||||
|
...(returnValues as LabelValueType[]),
|
||||||
|
...getRawValueLabeled(halfValues, preValue, getEntityByValue, getTreeNodeLabelProp),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const additionalInfo = {
|
||||||
|
// [Legacy] Always return as array contains label & value
|
||||||
|
preValue: selectValues.value,
|
||||||
|
triggerValue,
|
||||||
|
} as ChangeEventExtra;
|
||||||
|
|
||||||
|
// [Legacy] Fill legacy data if user query.
|
||||||
|
// This is expansive that we only fill when user query
|
||||||
|
// https://github.com/react-component/tree-select/blob/fe33eb7c27830c9ac70cd1fdb1ebbe7bc679c16a/src/Select.jsx
|
||||||
|
let showPosition = true;
|
||||||
|
if (treeCheckStrictly || (source === 'selection' && !selected)) {
|
||||||
|
showPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillAdditionalInfo(
|
||||||
|
additionalInfo,
|
||||||
|
triggerValue,
|
||||||
|
newRawValues,
|
||||||
|
mergedTreeData.value,
|
||||||
|
showPosition,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mergedCheckable.value) {
|
||||||
|
additionalInfo.checked = selected;
|
||||||
|
} else {
|
||||||
|
additionalInfo.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(
|
||||||
|
mergedMultiple.value ? returnValues : returnValues[0],
|
||||||
|
mergedLabelInValue.value
|
||||||
|
? null
|
||||||
|
: eventValues.map(val => {
|
||||||
|
const entity = getEntityByValue(val);
|
||||||
|
return entity ? entity.data.title : null;
|
||||||
|
}),
|
||||||
|
additionalInfo,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalSelect = (
|
||||||
|
selectValue: RawValueType,
|
||||||
|
option: DataNode,
|
||||||
|
source: SelectSource,
|
||||||
|
) => {
|
||||||
|
const eventValue = mergedLabelInValue.value ? selectValue : selectValue;
|
||||||
|
|
||||||
|
if (!mergedMultiple.value) {
|
||||||
|
// Single mode always set value
|
||||||
|
triggerChange([selectValue], { selected: true, triggerValue: selectValue }, source);
|
||||||
|
} else {
|
||||||
|
let newRawValues = addValue(rawValues.value, selectValue);
|
||||||
|
|
||||||
|
// Add keys if tree conduction
|
||||||
|
if (treeConduction.value) {
|
||||||
|
// Should keep missing values
|
||||||
|
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
|
||||||
|
const keyList = existRawValues.map(val => getEntityByValue(val).key);
|
||||||
|
const { checkedKeys } = conductCheck(keyList, true, conductKeyEntities.value);
|
||||||
|
newRawValues = [
|
||||||
|
...missingRawValues,
|
||||||
|
...checkedKeys.map(key => getEntityByKey(key).data.value),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerChange(newRawValues, { selected: true, triggerValue: selectValue }, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
props.onSelect?.(eventValue, option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalDeselect = (
|
||||||
|
selectValue: RawValueType,
|
||||||
|
option: DataNode,
|
||||||
|
source: SelectSource,
|
||||||
|
) => {
|
||||||
|
const eventValue = mergedLabelInValue.value ? selectValue : selectValue;
|
||||||
|
|
||||||
|
let newRawValues = removeValue(rawValues.value, selectValue);
|
||||||
|
|
||||||
|
// Remove keys if tree conduction
|
||||||
|
if (treeConduction.value) {
|
||||||
|
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
|
||||||
|
const keyList = existRawValues.map(val => getEntityByValue(val).key);
|
||||||
|
const { checkedKeys } = conductCheck(
|
||||||
|
keyList,
|
||||||
|
{ checked: false, halfCheckedKeys: rawHalfCheckedKeys.value },
|
||||||
|
conductKeyEntities.value,
|
||||||
|
);
|
||||||
|
newRawValues = [
|
||||||
|
...missingRawValues,
|
||||||
|
...checkedKeys.map(key => getEntityByKey(key).data.value),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerChange(newRawValues, { selected: false, triggerValue: selectValue }, source);
|
||||||
|
|
||||||
|
props.onDeselect?.(eventValue, option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalClear = () => {
|
||||||
|
triggerChange([], null, 'clear');
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================= Open ==========================
|
||||||
|
const onInternalDropdownVisibleChange = (open: boolean) => {
|
||||||
|
if (props.onDropdownVisibleChange) {
|
||||||
|
const legacyParam = {};
|
||||||
|
|
||||||
|
Object.defineProperty(legacyParam, 'documentClickClose', {
|
||||||
|
get() {
|
||||||
|
warning(false, 'Second param of `onDropdownVisibleChange` has been removed.');
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
(props.onDropdownVisibleChange as any)(open, legacyParam);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ======================== Warning ========================
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
warningProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
treeNodeFilterProp,
|
||||||
|
dropdownPopupAlign,
|
||||||
|
filterTreeNode,
|
||||||
|
treeDefaultExpandAll,
|
||||||
|
treeExpandedKeys,
|
||||||
|
treeDefaultExpandedKeys,
|
||||||
|
onTreeExpand,
|
||||||
|
treeIcon,
|
||||||
|
treeMotion,
|
||||||
|
showTreeIcon,
|
||||||
|
switcherIcon,
|
||||||
|
treeLine,
|
||||||
|
loadData,
|
||||||
|
treeLoadedKeys,
|
||||||
|
onTreeLoad,
|
||||||
|
} = props;
|
||||||
|
// ======================== Render =========================
|
||||||
|
// We pass some props into select props style
|
||||||
|
const selectProps = {
|
||||||
|
optionLabelProp: null,
|
||||||
|
optionFilterProp: treeNodeFilterProp,
|
||||||
|
dropdownAlign: dropdownPopupAlign,
|
||||||
|
internalProps: {
|
||||||
|
mark: INTERNAL_PROPS_MARK,
|
||||||
|
onClear: onInternalClear,
|
||||||
|
skipTriggerChange: true,
|
||||||
|
skipTriggerSelect: true,
|
||||||
|
onRawSelect: onInternalSelect,
|
||||||
|
onRawDeselect: onInternalDeselect,
|
||||||
|
},
|
||||||
|
filterOption: filterTreeNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (props.filterTreeNode === undefined) {
|
||||||
|
delete selectProps.filterOption;
|
||||||
|
}
|
||||||
|
const selectContext = {
|
||||||
|
checkable: mergedCheckable.value,
|
||||||
|
loadData,
|
||||||
|
treeLoadedKeys,
|
||||||
|
onTreeLoad,
|
||||||
|
checkedKeys: rawValues.value,
|
||||||
|
halfCheckedKeys: rawHalfCheckedKeys.value,
|
||||||
|
treeDefaultExpandAll,
|
||||||
|
treeExpandedKeys,
|
||||||
|
treeDefaultExpandedKeys,
|
||||||
|
onTreeExpand,
|
||||||
|
treeIcon,
|
||||||
|
treeMotion,
|
||||||
|
showTreeIcon,
|
||||||
|
switcherIcon,
|
||||||
|
treeLine,
|
||||||
|
treeNodeFilterProp,
|
||||||
|
getEntityByKey,
|
||||||
|
getEntityByValue,
|
||||||
|
customCheckable: slots.checkable,
|
||||||
|
slots,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<SelectContext value={selectContext}>
|
||||||
|
<RefSelect
|
||||||
|
{...attrs}
|
||||||
|
ref={selectRef}
|
||||||
|
mode={mergedMultiple.value ? 'multiple' : null}
|
||||||
|
{...props}
|
||||||
|
{...selectProps}
|
||||||
|
value={selectValues}
|
||||||
|
// We will handle this ourself since we need calculate conduction
|
||||||
|
labelInValue
|
||||||
|
options={mergedTreeData.value}
|
||||||
|
onChange={null}
|
||||||
|
onSelect={null}
|
||||||
|
onDeselect={null}
|
||||||
|
onDropdownVisibleChange={onInternalDropdownVisibleChange}
|
||||||
|
/>
|
||||||
|
</SelectContext>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { ExtractPropTypes, PropType } from 'vue';
|
import type { ExtractPropTypes, PropType } from 'vue';
|
||||||
import type { DataNode } from '../tree';
|
import type { DataNode } from './interface';
|
||||||
import { selectBaseProps } from '../vc-select';
|
import { selectBaseProps } from '../vc-select';
|
||||||
import type { FilterFunc } from '../vc-select/interface/generator';
|
import type { FilterFunc } from '../vc-select/interface/generator';
|
||||||
import omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
|
@ -87,9 +87,9 @@ export function treeSelectProps<ValueType = DefaultValueType>() {
|
||||||
type: [Boolean, Object] as PropType<boolean | SimpleModeConfig>,
|
type: [Boolean, Object] as PropType<boolean | SimpleModeConfig>,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
treeExpandedKeys: { type: [String, Number] as PropType<Key> },
|
treeExpandedKeys: { type: Array as PropType<Key[]> },
|
||||||
treeDefaultExpandedKeys: { type: [String, Number] as PropType<Key> },
|
treeDefaultExpandedKeys: { type: Array as PropType<Key[]> },
|
||||||
treeLoadedKeys: { type: [String, Number] as PropType<Key> },
|
treeLoadedKeys: { type: Array as PropType<Key[]> },
|
||||||
treeCheckable: { type: Boolean, default: undefined },
|
treeCheckable: { type: Boolean, default: undefined },
|
||||||
treeCheckStrictly: { type: Boolean, default: undefined },
|
treeCheckStrictly: { type: Boolean, default: undefined },
|
||||||
showCheckedStrategy: { type: String as PropType<CheckedStrategy> },
|
showCheckedStrategy: { type: String as PropType<CheckedStrategy> },
|
||||||
|
|
|
@ -21,19 +21,19 @@ export interface DataNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventDataNode extends DataNode {
|
export interface EventDataNode extends DataNode {
|
||||||
expanded: boolean;
|
expanded?: boolean;
|
||||||
selected: boolean;
|
selected?: boolean;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
loaded: boolean;
|
loaded?: boolean;
|
||||||
loading: boolean;
|
loading?: boolean;
|
||||||
halfChecked: boolean;
|
halfChecked?: boolean;
|
||||||
dragOver: boolean;
|
dragOver?: boolean;
|
||||||
dragOverGapTop: boolean;
|
dragOverGapTop?: boolean;
|
||||||
dragOverGapBottom: boolean;
|
dragOverGapBottom?: boolean;
|
||||||
pos: string;
|
pos?: string;
|
||||||
active: boolean;
|
active?: boolean;
|
||||||
dataRef: DataNode;
|
dataRef?: DataNode;
|
||||||
eventKey: Key; // 兼容 v2, 推荐直接用 key
|
eventKey?: Key; // 兼容 v2, 推荐直接用 key
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IconType = any;
|
export type IconType = any;
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const treeNodeProps = {
|
||||||
pos: String,
|
pos: String,
|
||||||
|
|
||||||
/** New added in Tree for easy data access */
|
/** New added in Tree for easy data access */
|
||||||
data: { type: Object as PropType<DataNode> },
|
data: { type: Object as PropType<DataNode>, default: undefined as DataNode },
|
||||||
isStart: { type: Array as PropType<boolean[]> },
|
isStart: { type: Array as PropType<boolean[]> },
|
||||||
isEnd: { type: Array as PropType<boolean[]> },
|
isEnd: { type: Array as PropType<boolean[]> },
|
||||||
active: { type: Boolean, default: undefined },
|
active: { type: Boolean, default: undefined },
|
||||||
|
|
Loading…
Reference in New Issue