refactor: tree-select
parent
8e38ed883c
commit
1581943eb0
|
@ -2,13 +2,12 @@ import type { App, PropType, Plugin, ExtractPropTypes } from 'vue';
|
||||||
import { computed, defineComponent, ref } from 'vue';
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { selectProps as vcSelectProps } from '../vc-select';
|
import { selectProps as vcSelectProps } from '../vc-select';
|
||||||
import RcSelect, { Option, OptGroup, selectBaseProps } from '../vc-select';
|
import RcSelect, { Option, OptGroup } 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';
|
||||||
import PropTypes from '../_util/vue-types';
|
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 omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
|
|
||||||
type RawValue = string | number;
|
type RawValue = string | number;
|
||||||
|
@ -62,7 +61,7 @@ const Select = defineComponent({
|
||||||
'option',
|
'option',
|
||||||
],
|
],
|
||||||
setup(props, { attrs, emit, slots, expose }) {
|
setup(props, { attrs, emit, slots, expose }) {
|
||||||
const selectRef = ref(null);
|
const selectRef = ref();
|
||||||
|
|
||||||
const focus = () => {
|
const focus = () => {
|
||||||
if (selectRef.value) {
|
if (selectRef.value) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ 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';
|
import { warning } from '../vc-util/warning';
|
||||||
|
import { flattenChildren } from '../_util/props-util';
|
||||||
|
|
||||||
const getTransitionName = (rootPrefixCls: string, motion: string, transitionName?: string) => {
|
const getTransitionName = (rootPrefixCls: string, motion: string, transitionName?: string) => {
|
||||||
if (transitionName !== undefined) {
|
if (transitionName !== undefined) {
|
||||||
|
@ -80,7 +81,7 @@ const TreeSelect = defineComponent({
|
||||||
setup(props, { attrs, slots, expose, emit }) {
|
setup(props, { attrs, slots, expose, emit }) {
|
||||||
warning(
|
warning(
|
||||||
!(props.treeData === undefined && slots.default),
|
!(props.treeData === undefined && slots.default),
|
||||||
'`children` of Tree is deprecated. Please use `treeData` instead.',
|
'`children` of TreeSelect is deprecated. Please use `treeData` instead.',
|
||||||
);
|
);
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
devWarning(
|
devWarning(
|
||||||
|
@ -194,6 +195,10 @@ const TreeSelect = defineComponent({
|
||||||
attrs.class,
|
attrs.class,
|
||||||
);
|
);
|
||||||
const rootPrefixCls = configProvider.getPrefixCls();
|
const rootPrefixCls = configProvider.getPrefixCls();
|
||||||
|
const otherProps: any = {};
|
||||||
|
if (props.treeData === undefined && slots.default) {
|
||||||
|
otherProps.children = flattenChildren(slots.default());
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<VcTreeSelect
|
<VcTreeSelect
|
||||||
{...attrs}
|
{...attrs}
|
||||||
|
@ -227,7 +232,7 @@ const TreeSelect = defineComponent({
|
||||||
...slots,
|
...slots,
|
||||||
treeCheckable: () => <span class={`${prefixCls.value}-tree-checkbox-inner`} />,
|
treeCheckable: () => <span class={`${prefixCls.value}-tree-checkbox-inner`} />,
|
||||||
}}
|
}}
|
||||||
children={slots.default?.()}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,8 @@ import {
|
||||||
flattenOptions,
|
flattenOptions,
|
||||||
fillOptionsWithMissingValue,
|
fillOptionsWithMissingValue,
|
||||||
} from './utils/valueUtil';
|
} from './utils/valueUtil';
|
||||||
import { selectBaseProps, SelectProps } from './generate';
|
import type { SelectProps } from './generate';
|
||||||
|
import { selectBaseProps } 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';
|
||||||
|
@ -79,7 +80,7 @@ const Select = defineComponent({
|
||||||
OptGroup,
|
OptGroup,
|
||||||
props: RefSelect.props,
|
props: RefSelect.props,
|
||||||
setup(props, { attrs, expose, slots }) {
|
setup(props, { attrs, expose, slots }) {
|
||||||
const selectRef = ref(null);
|
const selectRef = ref();
|
||||||
expose({
|
expose({
|
||||||
focus: () => {
|
focus: () => {
|
||||||
selectRef.value?.focus();
|
selectRef.value?.focus();
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import pickAttrs from '../../_util/pickAttrs';
|
import pickAttrs from '../../_util/pickAttrs';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import type { InnerSelectorProps } from './interface';
|
import type { InnerSelectorProps } from './interface';
|
||||||
import { Fragment, Suspense, VNodeChild } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
|
import { Fragment } from 'vue';
|
||||||
import { computed, defineComponent, 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';
|
import { useInjectTreeSelectContext } from 'ant-design-vue/es/vc-tree-select/Context';
|
||||||
|
|
|
@ -52,7 +52,7 @@ export interface SelectorProps {
|
||||||
// Motion
|
// Motion
|
||||||
choiceTransitionName?: string;
|
choiceTransitionName?: string;
|
||||||
|
|
||||||
onToggleOpen: (open?: boolean) => void;
|
onToggleOpen: (open?: boolean) => void | any;
|
||||||
/** `onSearch` returns go next step boolean to check if need do toggle open */
|
/** `onSearch` returns go next step boolean to check if need do toggle open */
|
||||||
onSearch: (searchText: string, fromTyping: boolean, isCompositing: boolean) => boolean;
|
onSearch: (searchText: string, fromTyping: boolean, isCompositing: boolean) => boolean;
|
||||||
onSearchSubmit: (searchText: string) => void;
|
onSearchSubmit: (searchText: string) => void;
|
||||||
|
|
|
@ -37,6 +37,7 @@ import useSelectTriggerControl from './hooks/useSelectTriggerControl';
|
||||||
import useCacheDisplayValue from './hooks/useCacheDisplayValue';
|
import useCacheDisplayValue from './hooks/useCacheDisplayValue';
|
||||||
import useCacheOptions from './hooks/useCacheOptions';
|
import useCacheOptions from './hooks/useCacheOptions';
|
||||||
import type { CSSProperties, DefineComponent, PropType, VNode, VNodeChild } from 'vue';
|
import type { CSSProperties, DefineComponent, PropType, VNode, VNodeChild } from 'vue';
|
||||||
|
import { getCurrentInstance } from 'vue';
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
@ -275,7 +276,7 @@ export default function generateSelector<
|
||||||
slots: ['option'],
|
slots: ['option'],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: selectBaseProps<OptionType, DefaultValueType>(),
|
props: selectBaseProps<OptionType, DefaultValueType>(),
|
||||||
setup(props, { expose }) {
|
setup(props, { expose, attrs, slots }) {
|
||||||
const useInternalProps = computed(
|
const useInternalProps = computed(
|
||||||
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
||||||
);
|
);
|
||||||
|
@ -284,10 +285,10 @@ export default function generateSelector<
|
||||||
'Select',
|
'Select',
|
||||||
'optionFilterProp not support children, please use label instead',
|
'optionFilterProp not support children, please use label instead',
|
||||||
);
|
);
|
||||||
const containerRef = ref(null);
|
const containerRef = ref();
|
||||||
const triggerRef = ref(null);
|
const triggerRef = ref();
|
||||||
const selectorRef = ref(null);
|
const selectorRef = ref();
|
||||||
const listRef = ref(null);
|
const listRef = ref();
|
||||||
const tokenWithEnter = computed(() =>
|
const tokenWithEnter = computed(() =>
|
||||||
(props.tokenSeparators || []).some(tokenSeparator =>
|
(props.tokenSeparators || []).some(tokenSeparator =>
|
||||||
['\n', '\r\n'].includes(tokenSeparator),
|
['\n', '\r\n'].includes(tokenSeparator),
|
||||||
|
@ -353,7 +354,7 @@ export default function generateSelector<
|
||||||
|
|
||||||
// ============================= Option =============================
|
// ============================= Option =============================
|
||||||
// Set by option list active, it will merge into search input when mode is `combobox`
|
// Set by option list active, it will merge into search input when mode is `combobox`
|
||||||
const activeValue = ref(null);
|
const activeValue = ref();
|
||||||
const setActiveValue = (val: string) => {
|
const setActiveValue = (val: string) => {
|
||||||
activeValue.value = val;
|
activeValue.value = val;
|
||||||
};
|
};
|
||||||
|
@ -925,7 +926,7 @@ export default function generateSelector<
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================= Popup ==============================
|
// ============================= Popup ==============================
|
||||||
const containerWidth = ref(null);
|
const containerWidth = ref<number>(null);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
watch(
|
watch(
|
||||||
triggerOpen,
|
triggerOpen,
|
||||||
|
@ -952,342 +953,270 @@ export default function generateSelector<
|
||||||
blur,
|
blur,
|
||||||
scrollTo: (...args: any[]) => listRef.value?.scrollTo(...args),
|
scrollTo: (...args: any[]) => listRef.value?.scrollTo(...args),
|
||||||
});
|
});
|
||||||
return {
|
const instance = getCurrentInstance();
|
||||||
tokenWithEnter,
|
const onPopupMouseEnter = () => {
|
||||||
mockFocused,
|
// We need force update here since popup dom is render async
|
||||||
mergedId,
|
instance.update();
|
||||||
containerWidth,
|
|
||||||
onActiveValue,
|
|
||||||
accessibilityIndex,
|
|
||||||
mergedDefaultActiveFirstOption,
|
|
||||||
onInternalMouseDown,
|
|
||||||
onContainerFocus,
|
|
||||||
onContainerBlur,
|
|
||||||
onInternalKeyDown,
|
|
||||||
isMultiple,
|
|
||||||
mergedOpen,
|
|
||||||
displayOptions,
|
|
||||||
displayFlattenOptions,
|
|
||||||
rawValues,
|
|
||||||
onInternalOptionSelect,
|
|
||||||
onToggleOpen,
|
|
||||||
mergedSearchValue,
|
|
||||||
useInternalProps,
|
|
||||||
triggerChange,
|
|
||||||
triggerSearch,
|
|
||||||
mergedRawValue,
|
|
||||||
mergedShowSearch,
|
|
||||||
onInternalKeyUp,
|
|
||||||
triggerOpen,
|
|
||||||
mergedOptions,
|
|
||||||
onInternalSelectionSelect,
|
|
||||||
selectorDomRef,
|
|
||||||
displayValues,
|
|
||||||
activeValue,
|
|
||||||
onSearchSubmit,
|
|
||||||
containerRef,
|
|
||||||
listRef,
|
|
||||||
triggerRef,
|
|
||||||
selectorRef,
|
|
||||||
};
|
};
|
||||||
},
|
return () => {
|
||||||
methods: {
|
const {
|
||||||
// We need force update here since popup dom is render async
|
prefixCls = defaultPrefixCls,
|
||||||
onPopupMouseEnter() {
|
id,
|
||||||
(this as any).$forceUpdate();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
tokenWithEnter,
|
|
||||||
mockFocused,
|
|
||||||
mergedId,
|
|
||||||
containerWidth,
|
|
||||||
onActiveValue,
|
|
||||||
accessibilityIndex,
|
|
||||||
mergedDefaultActiveFirstOption,
|
|
||||||
onInternalMouseDown,
|
|
||||||
onInternalKeyDown,
|
|
||||||
isMultiple,
|
|
||||||
mergedOpen,
|
|
||||||
displayOptions,
|
|
||||||
displayFlattenOptions,
|
|
||||||
rawValues,
|
|
||||||
onInternalOptionSelect,
|
|
||||||
onToggleOpen,
|
|
||||||
mergedSearchValue,
|
|
||||||
onPopupMouseEnter,
|
|
||||||
useInternalProps,
|
|
||||||
triggerChange,
|
|
||||||
triggerSearch,
|
|
||||||
mergedRawValue,
|
|
||||||
mergedShowSearch,
|
|
||||||
onInternalKeyUp,
|
|
||||||
triggerOpen,
|
|
||||||
mergedOptions,
|
|
||||||
onInternalSelectionSelect,
|
|
||||||
selectorDomRef,
|
|
||||||
displayValues,
|
|
||||||
activeValue,
|
|
||||||
onSearchSubmit,
|
|
||||||
$slots: slots,
|
|
||||||
} = this as any;
|
|
||||||
const {
|
|
||||||
prefixCls = defaultPrefixCls,
|
|
||||||
id,
|
|
||||||
|
|
||||||
open,
|
open,
|
||||||
defaultOpen,
|
defaultOpen,
|
||||||
options,
|
options,
|
||||||
children,
|
children,
|
||||||
|
|
||||||
mode,
|
mode,
|
||||||
value,
|
value,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
labelInValue,
|
labelInValue,
|
||||||
|
|
||||||
// Search related
|
// Search related
|
||||||
showSearch,
|
showSearch,
|
||||||
inputValue,
|
inputValue,
|
||||||
searchValue,
|
searchValue,
|
||||||
filterOption,
|
filterOption,
|
||||||
optionFilterProp,
|
optionFilterProp,
|
||||||
autoClearSearchValue,
|
autoClearSearchValue,
|
||||||
onSearch,
|
onSearch,
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
allowClear,
|
allowClear,
|
||||||
clearIcon,
|
clearIcon,
|
||||||
showArrow,
|
showArrow,
|
||||||
inputIcon,
|
inputIcon,
|
||||||
menuItemSelectedIcon,
|
menuItemSelectedIcon,
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
disabled,
|
disabled,
|
||||||
loading,
|
loading,
|
||||||
defaultActiveFirstOption,
|
defaultActiveFirstOption,
|
||||||
notFoundContent = 'Not Found',
|
notFoundContent = 'Not Found',
|
||||||
optionLabelProp,
|
optionLabelProp,
|
||||||
backfill,
|
backfill,
|
||||||
getInputElement,
|
getInputElement,
|
||||||
getPopupContainer,
|
getPopupContainer,
|
||||||
|
|
||||||
// Dropdown
|
// Dropdown
|
||||||
listHeight = 200,
|
listHeight = 200,
|
||||||
listItemHeight = 20,
|
listItemHeight = 20,
|
||||||
animation,
|
animation,
|
||||||
transitionName,
|
transitionName,
|
||||||
virtual,
|
virtual,
|
||||||
dropdownStyle,
|
dropdownStyle,
|
||||||
dropdownClassName,
|
dropdownClassName,
|
||||||
dropdownMatchSelectWidth,
|
dropdownMatchSelectWidth,
|
||||||
dropdownRender,
|
dropdownRender,
|
||||||
dropdownAlign,
|
dropdownAlign,
|
||||||
showAction,
|
showAction,
|
||||||
direction,
|
direction,
|
||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
tokenSeparators,
|
tokenSeparators,
|
||||||
tagRender,
|
tagRender,
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
onPopupScroll,
|
onPopupScroll,
|
||||||
onDropdownVisibleChange,
|
onDropdownVisibleChange,
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
onKeyup,
|
onKeyup,
|
||||||
onKeydown,
|
onKeydown,
|
||||||
onMousedown,
|
onMousedown,
|
||||||
|
|
||||||
onChange,
|
onChange,
|
||||||
onSelect,
|
onSelect,
|
||||||
onDeselect,
|
onDeselect,
|
||||||
onClear,
|
onClear,
|
||||||
|
|
||||||
internalProps = {},
|
internalProps = {},
|
||||||
|
|
||||||
...restProps
|
...restProps
|
||||||
} = this.$props; //as SelectProps<OptionType[], ValueType>;
|
} = props; //as SelectProps<OptionType[], ValueType>;
|
||||||
|
// ============================= Input ==============================
|
||||||
|
// Only works in `combobox`
|
||||||
|
const customizeInputElement: VNodeChild | JSX.Element =
|
||||||
|
(mode === 'combobox' && getInputElement && getInputElement()) || null;
|
||||||
|
|
||||||
// ============================= Input ==============================
|
const domProps = omitDOMProps ? omitDOMProps(restProps) : restProps;
|
||||||
// Only works in `combobox`
|
DEFAULT_OMIT_PROPS.forEach(prop => {
|
||||||
const customizeInputElement: VNodeChild | JSX.Element =
|
delete domProps[prop];
|
||||||
(mode === 'combobox' && getInputElement && getInputElement()) || null;
|
});
|
||||||
|
const popupNode = (
|
||||||
const domProps = omitDOMProps ? omitDOMProps(restProps) : restProps;
|
<OptionList
|
||||||
DEFAULT_OMIT_PROPS.forEach(prop => {
|
ref={listRef}
|
||||||
delete domProps[prop];
|
prefixCls={prefixCls}
|
||||||
});
|
id={mergedId.value}
|
||||||
const popupNode = (
|
open={mergedOpen.value}
|
||||||
<OptionList
|
childrenAsData={!options}
|
||||||
ref="listRef"
|
options={displayOptions.value}
|
||||||
prefixCls={prefixCls}
|
flattenOptions={displayFlattenOptions.value}
|
||||||
id={mergedId}
|
multiple={isMultiple.value}
|
||||||
open={mergedOpen}
|
values={rawValues.value}
|
||||||
childrenAsData={!options}
|
height={listHeight}
|
||||||
options={displayOptions}
|
itemHeight={listItemHeight}
|
||||||
flattenOptions={displayFlattenOptions}
|
onSelect={onInternalOptionSelect}
|
||||||
multiple={isMultiple}
|
onToggleOpen={onToggleOpen}
|
||||||
values={rawValues}
|
onActiveValue={onActiveValue}
|
||||||
height={listHeight}
|
defaultActiveFirstOption={mergedDefaultActiveFirstOption.value}
|
||||||
itemHeight={listItemHeight}
|
notFoundContent={notFoundContent}
|
||||||
onSelect={onInternalOptionSelect}
|
onScroll={onPopupScroll}
|
||||||
onToggleOpen={onToggleOpen}
|
searchValue={mergedSearchValue.value}
|
||||||
onActiveValue={onActiveValue}
|
menuItemSelectedIcon={menuItemSelectedIcon}
|
||||||
defaultActiveFirstOption={mergedDefaultActiveFirstOption}
|
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
||||||
notFoundContent={notFoundContent}
|
onMouseenter={onPopupMouseEnter}
|
||||||
onScroll={onPopupScroll}
|
v-slots={{ ...slots, option: slots.option }}
|
||||||
searchValue={mergedSearchValue}
|
|
||||||
menuItemSelectedIcon={menuItemSelectedIcon}
|
|
||||||
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
|
||||||
onMouseenter={onPopupMouseEnter}
|
|
||||||
v-slots={{ ...slots, option: slots.option }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
// ============================= Clear ==============================
|
|
||||||
let clearNode: VNode | JSX.Element;
|
|
||||||
const onClearMouseDown = () => {
|
|
||||||
// Trigger internal `onClear` event
|
|
||||||
if (useInternalProps && internalProps.onClear) {
|
|
||||||
internalProps.onClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onClear) {
|
|
||||||
onClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerChange([]);
|
|
||||||
triggerSearch('', false, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!disabled && allowClear && (mergedRawValue.length || mergedSearchValue)) {
|
|
||||||
clearNode = (
|
|
||||||
<TransBtn
|
|
||||||
class={`${prefixCls}-clear`}
|
|
||||||
onMousedown={onClearMouseDown}
|
|
||||||
customizeIcon={clearIcon}
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</TransBtn>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================= Arrow ==============================
|
|
||||||
const mergedShowArrow =
|
|
||||||
showArrow !== undefined ? showArrow : loading || (!isMultiple && mode !== 'combobox');
|
|
||||||
let arrowNode: VNode | JSX.Element;
|
|
||||||
|
|
||||||
if (mergedShowArrow) {
|
|
||||||
arrowNode = (
|
|
||||||
<TransBtn
|
|
||||||
class={classNames(`${prefixCls}-arrow`, {
|
|
||||||
[`${prefixCls}-arrow-loading`]: loading,
|
|
||||||
})}
|
|
||||||
customizeIcon={inputIcon}
|
|
||||||
customizeIconProps={{
|
|
||||||
loading,
|
|
||||||
searchValue: mergedSearchValue,
|
|
||||||
open: mergedOpen,
|
|
||||||
focused: mockFocused,
|
|
||||||
showSearch: mergedShowSearch,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// ============================ Warning =============================
|
// ============================= Clear ==============================
|
||||||
if (process.env.NODE_ENV !== 'production' && warningProps) {
|
let clearNode: VNode | JSX.Element;
|
||||||
warningProps(this.$props);
|
const onClearMouseDown = () => {
|
||||||
}
|
// Trigger internal `onClear` event
|
||||||
|
if (useInternalProps.value && internalProps.onClear) {
|
||||||
|
internalProps.onClear();
|
||||||
|
}
|
||||||
|
|
||||||
// ============================= Render =============================
|
if (onClear) {
|
||||||
const mergedClassName = classNames(prefixCls, this.$attrs.class, {
|
onClear();
|
||||||
[`${prefixCls}-focused`]: mockFocused,
|
}
|
||||||
[`${prefixCls}-multiple`]: isMultiple,
|
|
||||||
[`${prefixCls}-single`]: !isMultiple,
|
triggerChange([]);
|
||||||
[`${prefixCls}-allow-clear`]: allowClear,
|
triggerSearch('', false, false);
|
||||||
[`${prefixCls}-show-arrow`]: mergedShowArrow,
|
};
|
||||||
[`${prefixCls}-disabled`]: disabled,
|
|
||||||
[`${prefixCls}-loading`]: loading,
|
if (!disabled && allowClear && (mergedRawValue.value.length || mergedSearchValue.value)) {
|
||||||
[`${prefixCls}-open`]: mergedOpen,
|
clearNode = (
|
||||||
[`${prefixCls}-customize-input`]: customizeInputElement,
|
<TransBtn
|
||||||
[`${prefixCls}-show-search`]: mergedShowSearch,
|
class={`${prefixCls}-clear`}
|
||||||
});
|
onMousedown={onClearMouseDown}
|
||||||
return (
|
customizeIcon={clearIcon}
|
||||||
<div
|
|
||||||
{...this.$attrs}
|
|
||||||
class={mergedClassName}
|
|
||||||
{...domProps}
|
|
||||||
ref="containerRef"
|
|
||||||
onMousedown={onInternalMouseDown}
|
|
||||||
onKeydown={onInternalKeyDown}
|
|
||||||
onKeyup={onInternalKeyUp}
|
|
||||||
// onFocus={onContainerFocus} // trigger by input
|
|
||||||
// onBlur={onContainerBlur} // trigger by input
|
|
||||||
>
|
|
||||||
{mockFocused && !mergedOpen && (
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
display: 'flex',
|
|
||||||
overflow: 'hidden',
|
|
||||||
opacity: 0,
|
|
||||||
}}
|
|
||||||
aria-live="polite"
|
|
||||||
>
|
>
|
||||||
{/* Merge into one string to make screen reader work as expect */}
|
×
|
||||||
{`${mergedRawValue.join(', ')}`}
|
</TransBtn>
|
||||||
</span>
|
);
|
||||||
)}
|
}
|
||||||
<SelectTrigger
|
|
||||||
ref="triggerRef"
|
|
||||||
disabled={disabled}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
visible={triggerOpen}
|
|
||||||
popupElement={popupNode}
|
|
||||||
containerWidth={containerWidth}
|
|
||||||
animation={animation}
|
|
||||||
transitionName={transitionName}
|
|
||||||
dropdownStyle={dropdownStyle}
|
|
||||||
dropdownClassName={dropdownClassName}
|
|
||||||
direction={direction}
|
|
||||||
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
|
|
||||||
dropdownRender={dropdownRender as any}
|
|
||||||
dropdownAlign={dropdownAlign}
|
|
||||||
getPopupContainer={getPopupContainer}
|
|
||||||
empty={!mergedOptions.length}
|
|
||||||
getTriggerDOMNode={() => selectorDomRef.current}
|
|
||||||
>
|
|
||||||
<Selector
|
|
||||||
{...this.$props}
|
|
||||||
domRef={selectorDomRef}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
inputElement={customizeInputElement}
|
|
||||||
ref="selectorRef"
|
|
||||||
id={mergedId}
|
|
||||||
showSearch={mergedShowSearch}
|
|
||||||
mode={mode}
|
|
||||||
accessibilityIndex={accessibilityIndex}
|
|
||||||
multiple={isMultiple}
|
|
||||||
tagRender={tagRender}
|
|
||||||
values={displayValues}
|
|
||||||
open={mergedOpen}
|
|
||||||
onToggleOpen={onToggleOpen}
|
|
||||||
searchValue={mergedSearchValue}
|
|
||||||
activeValue={activeValue}
|
|
||||||
onSearch={triggerSearch}
|
|
||||||
onSearchSubmit={onSearchSubmit}
|
|
||||||
onSelect={onInternalSelectionSelect}
|
|
||||||
tokenWithEnter={tokenWithEnter}
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
|
|
||||||
{arrowNode}
|
// ============================= Arrow ==============================
|
||||||
{clearNode}
|
const mergedShowArrow =
|
||||||
</div>
|
showArrow !== undefined
|
||||||
);
|
? showArrow
|
||||||
|
: loading || (!isMultiple.value && mode !== 'combobox');
|
||||||
|
let arrowNode: VNode | JSX.Element;
|
||||||
|
|
||||||
|
if (mergedShowArrow) {
|
||||||
|
arrowNode = (
|
||||||
|
<TransBtn
|
||||||
|
class={classNames(`${prefixCls}-arrow`, {
|
||||||
|
[`${prefixCls}-arrow-loading`]: loading,
|
||||||
|
})}
|
||||||
|
customizeIcon={inputIcon}
|
||||||
|
customizeIconProps={{
|
||||||
|
loading,
|
||||||
|
searchValue: mergedSearchValue.value,
|
||||||
|
open: mergedOpen.value,
|
||||||
|
focused: mockFocused.value,
|
||||||
|
showSearch: mergedShowSearch.value,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ Warning =============================
|
||||||
|
if (process.env.NODE_ENV !== 'production' && warningProps) {
|
||||||
|
warningProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================= Render =============================
|
||||||
|
const mergedClassName = classNames(prefixCls, attrs.class, {
|
||||||
|
[`${prefixCls}-focused`]: mockFocused.value,
|
||||||
|
[`${prefixCls}-multiple`]: isMultiple.value,
|
||||||
|
[`${prefixCls}-single`]: !isMultiple.value,
|
||||||
|
[`${prefixCls}-allow-clear`]: allowClear,
|
||||||
|
[`${prefixCls}-show-arrow`]: mergedShowArrow,
|
||||||
|
[`${prefixCls}-disabled`]: disabled,
|
||||||
|
[`${prefixCls}-loading`]: loading,
|
||||||
|
[`${prefixCls}-open`]: mergedOpen.value,
|
||||||
|
[`${prefixCls}-customize-input`]: customizeInputElement,
|
||||||
|
[`${prefixCls}-show-search`]: mergedShowSearch.value,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...attrs}
|
||||||
|
class={mergedClassName}
|
||||||
|
{...domProps}
|
||||||
|
ref={containerRef}
|
||||||
|
onMousedown={onInternalMouseDown}
|
||||||
|
onKeydown={onInternalKeyDown}
|
||||||
|
onKeyup={onInternalKeyUp}
|
||||||
|
// onFocus={onContainerFocus} // trigger by input
|
||||||
|
// onBlur={onContainerBlur} // trigger by input
|
||||||
|
>
|
||||||
|
{mockFocused.value && !mergedOpen.value && (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
display: 'flex',
|
||||||
|
overflow: 'hidden',
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
aria-live="polite"
|
||||||
|
>
|
||||||
|
{/* Merge into one string to make screen reader work as expect */}
|
||||||
|
{`${mergedRawValue.value.join(', ')}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<SelectTrigger
|
||||||
|
ref={triggerRef}
|
||||||
|
disabled={disabled}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
visible={triggerOpen.value}
|
||||||
|
popupElement={popupNode}
|
||||||
|
containerWidth={containerWidth.value}
|
||||||
|
animation={animation}
|
||||||
|
transitionName={transitionName}
|
||||||
|
dropdownStyle={dropdownStyle}
|
||||||
|
dropdownClassName={dropdownClassName}
|
||||||
|
direction={direction}
|
||||||
|
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
|
||||||
|
dropdownRender={dropdownRender as any}
|
||||||
|
dropdownAlign={dropdownAlign}
|
||||||
|
getPopupContainer={getPopupContainer}
|
||||||
|
empty={!mergedOptions.value.length}
|
||||||
|
getTriggerDOMNode={() => selectorDomRef.current}
|
||||||
|
>
|
||||||
|
<Selector
|
||||||
|
{...props}
|
||||||
|
domRef={selectorDomRef}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
inputElement={customizeInputElement}
|
||||||
|
ref={selectorRef}
|
||||||
|
id={mergedId.value}
|
||||||
|
showSearch={mergedShowSearch.value}
|
||||||
|
mode={mode}
|
||||||
|
accessibilityIndex={accessibilityIndex.value}
|
||||||
|
multiple={isMultiple.value}
|
||||||
|
tagRender={tagRender}
|
||||||
|
values={displayValues.value}
|
||||||
|
open={mergedOpen.value}
|
||||||
|
onToggleOpen={onToggleOpen}
|
||||||
|
searchValue={mergedSearchValue.value}
|
||||||
|
activeValue={activeValue.value}
|
||||||
|
onSearch={triggerSearch}
|
||||||
|
onSearchSubmit={onSearchSubmit}
|
||||||
|
onSelect={onInternalSelectionSelect}
|
||||||
|
tokenWithEnter={tokenWithEnter.value}
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
|
||||||
|
{arrowNode}
|
||||||
|
{clearNode}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return Select;
|
return Select;
|
||||||
|
|
|
@ -34,7 +34,6 @@ export default defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: optionListProps<DataNode>(),
|
props: optionListProps<DataNode>(),
|
||||||
slots: ['notFoundContent', 'menuItemSelectedIcon'],
|
slots: ['notFoundContent', 'menuItemSelectedIcon'],
|
||||||
expose: ['scrollTo', 'onKeydown', 'onKeyup'],
|
|
||||||
setup(props, { slots, expose }) {
|
setup(props, { slots, expose }) {
|
||||||
const context = useInjectTreeSelectContext();
|
const context = useInjectTreeSelectContext();
|
||||||
|
|
||||||
|
@ -153,7 +152,7 @@ export default defineComponent({
|
||||||
case KeyCode.DOWN:
|
case KeyCode.DOWN:
|
||||||
case KeyCode.LEFT:
|
case KeyCode.LEFT:
|
||||||
case KeyCode.RIGHT:
|
case KeyCode.RIGHT:
|
||||||
treeRef.value?.onKeyDown(event);
|
treeRef.value?.onKeydown(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// >>> Select item
|
// >>> Select item
|
||||||
|
|
|
@ -8,7 +8,8 @@ export interface TreeNodeProps extends Omit<DataNode, 'children'> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is a placeholder, not real render in dom */
|
/** This is a placeholder, not real render in dom */
|
||||||
const TreeNode: FunctionalComponent<TreeNodeProps> = () => null;
|
const TreeNode: FunctionalComponent<TreeNodeProps> & { isTreeSelectNode: boolean } = () => null;
|
||||||
TreeNode.inheritAttrs = false;
|
TreeNode.inheritAttrs = false;
|
||||||
TreeNode.displayName = 'ATreeSelectNode';
|
TreeNode.displayName = 'ATreeSelectNode';
|
||||||
|
TreeNode.isTreeSelectNode = true;
|
||||||
export default TreeNode;
|
export default TreeNode;
|
||||||
|
|
|
@ -161,7 +161,7 @@ export default function generate(config: {
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========================== Ref ==========================
|
// ========================== Ref ==========================
|
||||||
const selectRef = ref(null);
|
const selectRef = ref();
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
scrollTo: (...args: any[]) => selectRef.value.scrollTo?.(...args),
|
scrollTo: (...args: any[]) => selectRef.value.scrollTo?.(...args),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
import type { VNodeChild } from 'vue';
|
||||||
|
import { camelize } from 'vue';
|
||||||
import { warning } from '../../vc-util/warning';
|
import { warning } from '../../vc-util/warning';
|
||||||
import { isValidElement } from '../../_util/props-util';
|
|
||||||
import type {
|
import type {
|
||||||
DataNode,
|
DataNode,
|
||||||
LegacyDataNode,
|
LegacyDataNode,
|
||||||
|
@ -10,32 +11,58 @@ import type {
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
import TreeNode from '../TreeNode';
|
import TreeNode from '../TreeNode';
|
||||||
|
|
||||||
export function convertChildrenToData(nodes): DataNode[] {
|
function isTreeSelectNode(node: any) {
|
||||||
return nodes
|
return node && node.type && (node.type as any).isTreeSelectNode;
|
||||||
.map(node => {
|
}
|
||||||
if (!isValidElement(node) || !node.type) {
|
export function convertChildrenToData(rootNodes: VNodeChild): DataNode[] {
|
||||||
|
function dig(treeNodes: any[] = []): DataNode[] {
|
||||||
|
return treeNodes.map(treeNode => {
|
||||||
|
// Filter invalidate node
|
||||||
|
if (!isTreeSelectNode(treeNode)) {
|
||||||
|
warning(!treeNode, 'TreeSelect/TreeSelectNode can only accept TreeSelectNode as children.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const slots = (treeNode.children as any) || {};
|
||||||
|
const key = treeNode.key as string | number;
|
||||||
|
const props: any = {};
|
||||||
|
for (const [k, v] of Object.entries(treeNode.props)) {
|
||||||
|
props[camelize(k)] = v;
|
||||||
|
}
|
||||||
|
const { isLeaf, checkable, selectable, disabled, disableCheckbox } = props;
|
||||||
|
// 默认值为 undefined
|
||||||
|
const newProps = {
|
||||||
|
isLeaf: isLeaf || isLeaf === '' || undefined,
|
||||||
|
checkable: checkable || checkable === '' || undefined,
|
||||||
|
selectable: selectable || selectable === '' || undefined,
|
||||||
|
disabled: disabled || disabled === '' || undefined,
|
||||||
|
disableCheckbox: disableCheckbox || disableCheckbox === '' || undefined,
|
||||||
|
};
|
||||||
|
const slotsProps = { ...props, ...newProps };
|
||||||
const {
|
const {
|
||||||
|
title = slots.title?.(slotsProps),
|
||||||
|
switcherIcon = slots.switcherIcon?.(slotsProps),
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
const children = slots.default?.();
|
||||||
|
const dataNode: DataNode = {
|
||||||
|
...rest,
|
||||||
|
title,
|
||||||
|
switcherIcon,
|
||||||
key,
|
key,
|
||||||
props: { children, value, ...restProps },
|
isLeaf,
|
||||||
} = node;
|
...newProps,
|
||||||
|
|
||||||
const data = {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
...restProps,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const childData = convertChildrenToData(children);
|
const parsedChildren = dig(children);
|
||||||
if (childData.length) {
|
if (parsedChildren.length) {
|
||||||
data.children = childData;
|
dataNode.children = parsedChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return dataNode;
|
||||||
})
|
});
|
||||||
.filter(data => data);
|
}
|
||||||
|
|
||||||
|
return dig(rootNodes as any[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fillLegacyProps(dataNode: DataNode): LegacyDataNode {
|
export function fillLegacyProps(dataNode: DataNode): LegacyDataNode {
|
||||||
|
|
|
@ -96,8 +96,8 @@ export default defineComponent({
|
||||||
props: nodeListProps,
|
props: nodeListProps,
|
||||||
setup(props, { expose, attrs }) {
|
setup(props, { expose, attrs }) {
|
||||||
// =============================== Ref ================================
|
// =============================== Ref ================================
|
||||||
const listRef = ref(null);
|
const listRef = ref();
|
||||||
const indentMeasurerRef = ref(null);
|
const indentMeasurerRef = ref();
|
||||||
expose({
|
expose({
|
||||||
scrollTo: scroll => {
|
scrollTo: scroll => {
|
||||||
listRef.value.scrollTo(scroll);
|
listRef.value.scrollTo(scroll);
|
||||||
|
|
|
@ -870,8 +870,8 @@ export default defineComponent({
|
||||||
active: true,
|
active: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const onKeyDown = event => {
|
const onKeydown = event => {
|
||||||
const { onKeyDown, checkable, selectable } = props;
|
const { onKeydown, checkable, selectable } = props;
|
||||||
|
|
||||||
// >>>>>>>>>> Direction
|
// >>>>>>>>>> Direction
|
||||||
switch (event.which) {
|
switch (event.which) {
|
||||||
|
@ -943,13 +943,14 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onKeyDown) {
|
if (onKeydown) {
|
||||||
onKeyDown(event);
|
onKeydown(event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
expose({
|
expose({
|
||||||
onNodeExpand,
|
onNodeExpand,
|
||||||
scrollTo,
|
scrollTo,
|
||||||
|
onKeydown,
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('dragend', onWindowDragEnd);
|
window.removeEventListener('dragend', onWindowDragEnd);
|
||||||
|
@ -1068,7 +1069,7 @@ export default defineComponent({
|
||||||
activeItem={activeItem.value}
|
activeItem={activeItem.value}
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
onKeydown={onKeyDown}
|
onKeydown={onKeydown}
|
||||||
onActiveChange={onActiveChange}
|
onActiveChange={onActiveChange}
|
||||||
onListChangeStart={onListChangeStart}
|
onListChangeStart={onListChangeStart}
|
||||||
onListChangeEnd={onListChangeEnd}
|
onListChangeEnd={onListChangeEnd}
|
||||||
|
|
|
@ -146,7 +146,7 @@ export const treeProps = () => ({
|
||||||
},
|
},
|
||||||
onFocus: { type: Function as PropType<(e: FocusEvent) => void> },
|
onFocus: { type: Function as PropType<(e: FocusEvent) => void> },
|
||||||
onBlur: { type: Function as PropType<(e: FocusEvent) => void> },
|
onBlur: { type: Function as PropType<(e: FocusEvent) => void> },
|
||||||
onKeyDown: { type: Function as PropType<EventHandlerNonNull> },
|
onKeydown: { type: Function as PropType<EventHandlerNonNull> },
|
||||||
onContextmenu: { type: Function as PropType<EventHandlerNonNull> },
|
onContextmenu: { type: Function as PropType<EventHandlerNonNull> },
|
||||||
onClick: { type: Function as PropType<NodeMouseEventHandler> },
|
onClick: { type: Function as PropType<NodeMouseEventHandler> },
|
||||||
onDblclick: { type: Function as PropType<NodeMouseEventHandler> },
|
onDblclick: { type: Function as PropType<NodeMouseEventHandler> },
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { getPosition, isTreeNode } from '../util';
|
||||||
import { warning } from '../../vc-util/warning';
|
import { warning } from '../../vc-util/warning';
|
||||||
import Omit from 'omit.js';
|
import Omit from 'omit.js';
|
||||||
import type { VNodeChild } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
|
import { camelize } from 'vue';
|
||||||
import type { TreeNodeProps } from '../props';
|
import type { TreeNodeProps } from '../props';
|
||||||
|
|
||||||
export function getKey(key: Key, pos: string) {
|
export function getKey(key: Key, pos: string) {
|
||||||
|
@ -60,74 +61,58 @@ export function warningWithoutKey(treeData: DataNode[], fieldNames: FieldNames)
|
||||||
dig(treeData);
|
dig(treeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheStringFunction = (fn: (s: string) => string) => {
|
|
||||||
const cache = Object.create(null);
|
|
||||||
return (str: string) => {
|
|
||||||
const hit = cache[str];
|
|
||||||
return hit || (cache[str] = fn(str));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const camelizeRE = /-(\w)/g;
|
|
||||||
|
|
||||||
const camelize = cacheStringFunction((str: string) => {
|
|
||||||
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert `children` of Tree into `treeData` structure.
|
* Convert `children` of Tree into `treeData` structure.
|
||||||
*/
|
*/
|
||||||
export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
|
export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
|
||||||
function dig(node: VNodeChild = []): DataNode[] {
|
function dig(node: VNodeChild = []): DataNode[] {
|
||||||
const treeNodes = node as NodeElement[];
|
const treeNodes = node as NodeElement[];
|
||||||
return treeNodes
|
return treeNodes.map(treeNode => {
|
||||||
.map(treeNode => {
|
// Filter invalidate node
|
||||||
// Filter invalidate node
|
if (!isTreeNode(treeNode)) {
|
||||||
if (!isTreeNode(treeNode)) {
|
warning(!treeNode, 'Tree/TreeNode can only accept TreeNode as children.');
|
||||||
warning(!treeNode, 'Tree/TreeNode can only accept TreeNode as children.');
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
const slots = (treeNode.children as any) || {};
|
||||||
const slots = (treeNode.children as any) || {};
|
const key = treeNode.key as string | number;
|
||||||
const key = treeNode.key as string | number;
|
const props: any = {};
|
||||||
const props: any = {};
|
for (const [k, v] of Object.entries(treeNode.props)) {
|
||||||
for (const [k, v] of Object.entries(treeNode.props)) {
|
props[camelize(k)] = v;
|
||||||
props[camelize(k)] = v;
|
}
|
||||||
}
|
const { isLeaf, checkable, selectable, disabled, disableCheckbox } = props;
|
||||||
const { isLeaf, checkable, selectable, disabled, disableCheckbox } = props;
|
// 默认值为 undefined
|
||||||
// 默认值为 undefined
|
const newProps = {
|
||||||
const newProps = {
|
isLeaf: isLeaf || isLeaf === '' || undefined,
|
||||||
isLeaf: isLeaf || isLeaf === '' || undefined,
|
checkable: checkable || checkable === '' || undefined,
|
||||||
checkable: checkable || checkable === '' || undefined,
|
selectable: selectable || selectable === '' || undefined,
|
||||||
selectable: selectable || selectable === '' || undefined,
|
disabled: disabled || disabled === '' || undefined,
|
||||||
disabled: disabled || disabled === '' || undefined,
|
disableCheckbox: disableCheckbox || disableCheckbox === '' || undefined,
|
||||||
disableCheckbox: disableCheckbox || disableCheckbox === '' || undefined,
|
};
|
||||||
};
|
const slotsProps = { ...props, ...newProps };
|
||||||
const slotsProps = { ...props, ...newProps };
|
const {
|
||||||
const {
|
title = slots.title?.(slotsProps),
|
||||||
title = slots.title?.(slotsProps),
|
icon = slots.icon?.(slotsProps),
|
||||||
icon = slots.icon?.(slotsProps),
|
switcherIcon = slots.switcherIcon?.(slotsProps),
|
||||||
switcherIcon = slots.switcherIcon?.(slotsProps),
|
...rest
|
||||||
...rest
|
} = props;
|
||||||
} = props;
|
const children = slots.default?.();
|
||||||
const children = slots.default?.();
|
const dataNode: DataNode = {
|
||||||
const dataNode: DataNode = {
|
...rest,
|
||||||
...rest,
|
title,
|
||||||
title,
|
icon,
|
||||||
icon,
|
switcherIcon,
|
||||||
switcherIcon,
|
key,
|
||||||
key,
|
isLeaf,
|
||||||
isLeaf,
|
...newProps,
|
||||||
...newProps,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const parsedChildren = dig(children);
|
const parsedChildren = dig(children);
|
||||||
if (parsedChildren.length) {
|
if (parsedChildren.length) {
|
||||||
dataNode.children = parsedChildren;
|
dataNode.children = parsedChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataNode;
|
return dataNode;
|
||||||
})
|
});
|
||||||
.filter((dataNode: DataNode) => dataNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dig(rootNodes);
|
return dig(rootNodes);
|
||||||
|
|
|
@ -1,64 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<a-tree-select
|
<a-tree-select
|
||||||
v-model:value="value"
|
v-model:value="value"
|
||||||
|
show-search
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||||
:tree-data="treeData"
|
|
||||||
placeholder="Please select"
|
placeholder="Please select"
|
||||||
|
allow-clear
|
||||||
|
multiple
|
||||||
tree-default-expand-all
|
tree-default-expand-all
|
||||||
>
|
>
|
||||||
<template #title="{ key, value }">
|
<a-tree-select-node value="parent 1" title="parent 1">
|
||||||
<span v-if="key === '0-0-1'" style="color: #08c">Child Node1 {{ value }}</span>
|
<a-tree-select-node value="parent 1-0" title="parent 1-0">
|
||||||
</template>
|
<a-tree-select-node value="leaf1" title="my leaf" />
|
||||||
|
<a-tree-select-node value="leaf2" title="your leaf" />
|
||||||
|
</a-tree-select-node>
|
||||||
|
<a-tree-select-node value="parent 1-1" title="parent 1-1">
|
||||||
|
<a-tree-select-node value="sss">
|
||||||
|
<template #title><b style="color: #08c">sss</b></template>
|
||||||
|
</a-tree-select-node>
|
||||||
|
</a-tree-select-node>
|
||||||
|
</a-tree-select-node>
|
||||||
</a-tree-select>
|
</a-tree-select>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch } from 'vue';
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
|
|
||||||
interface TreeDataItem {
|
|
||||||
value: string;
|
|
||||||
key: string;
|
|
||||||
title?: string;
|
|
||||||
slots?: Record<string, string>;
|
|
||||||
children?: TreeDataItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const treeData: TreeDataItem[] = [
|
|
||||||
{
|
|
||||||
title: 'Node1',
|
|
||||||
value: '0-0',
|
|
||||||
key: '0-0',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: '0-0-1',
|
|
||||||
key: '0-0-1',
|
|
||||||
slots: {
|
|
||||||
title: 'title1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Child Node2',
|
|
||||||
value: '0-0-2',
|
|
||||||
key: '0-0-2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Node2',
|
|
||||||
value: '0-1',
|
|
||||||
key: '0-1',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const value = ref<string>();
|
const value = ref<string[]>([]);
|
||||||
|
|
||||||
watch(value, () => {
|
watch(value, () => {
|
||||||
console.log(value.value);
|
console.log('select', value.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
treeData,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue