feat: tree-select add status & placement
parent
bf1226d3bb
commit
03f559a0dc
|
@ -11,6 +11,8 @@
|
|||
<virtualScrollVue />
|
||||
<customTagRenderVue />
|
||||
<replaceFieldsVue />
|
||||
<placementVue />
|
||||
<statusVue />
|
||||
</demo-sort>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@ -25,6 +27,8 @@ import treeLineVue from './tree-line.vue';
|
|||
import virtualScrollVue from './virtual-scroll.vue';
|
||||
import customTagRenderVue from './custom-tag-render.vue';
|
||||
import replaceFieldsVue from './replaceFields.vue';
|
||||
import placementVue from './placement.vue';
|
||||
import statusVue from './status.vue';
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
import { defineComponent } from 'vue';
|
||||
|
@ -33,6 +37,8 @@ export default defineComponent({
|
|||
CN,
|
||||
US,
|
||||
components: {
|
||||
placementVue,
|
||||
statusVue,
|
||||
Basic,
|
||||
Multiple,
|
||||
// TreeData,
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<docs>
|
||||
---
|
||||
order: 28
|
||||
title:
|
||||
zh-CN: 弹出位置
|
||||
en-US: Popup Placement
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
可以通过 `placement` 手动指定弹出的位置。
|
||||
|
||||
## en-US
|
||||
|
||||
You can manually specify the position of the popup via `placement`.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-radio-group v-model:value="placement">
|
||||
<a-radio-button value="topLeft">topLeft</a-radio-button>
|
||||
<a-radio-button value="topRight">topRight</a-radio-button>
|
||||
<a-radio-button value="bottomLeft">bottomLeft</a-radio-button>
|
||||
<a-radio-button value="bottomRight">bottomRight</a-radio-button>
|
||||
</a-radio-group>
|
||||
<br />
|
||||
<br />
|
||||
<a-tree-select
|
||||
v-model:value="value"
|
||||
show-search
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '300px' }"
|
||||
placeholder="Please select"
|
||||
allow-clear
|
||||
tree-default-expand-all
|
||||
:tree-data="treeData"
|
||||
:placement="placement"
|
||||
:dropdown-match-select-width="false"
|
||||
>
|
||||
<template #title="{ value: val, title }">
|
||||
<b v-if="val === 'parent 1-1'" style="color: #08c">sss</b>
|
||||
<template v-else>{{ title }}</template>
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import type { TreeSelectProps } from 'ant-design-vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const placement = ref('topLeft' as const);
|
||||
const value = ref<string>();
|
||||
const treeData = ref<TreeSelectProps['treeData']>([
|
||||
{
|
||||
title: 'parent 1',
|
||||
value: 'parent 1',
|
||||
children: [
|
||||
{
|
||||
title: 'parent 1-0',
|
||||
value: 'parent 1-0',
|
||||
children: [
|
||||
{
|
||||
title: 'my leaf',
|
||||
value: 'leaf1',
|
||||
},
|
||||
{
|
||||
title: 'your leaf',
|
||||
value: 'leaf2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'parent 1-1',
|
||||
value: 'parent 1-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
return {
|
||||
placement,
|
||||
value,
|
||||
treeData,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
<docs>
|
||||
---
|
||||
order: 19
|
||||
version: 3.3.0
|
||||
title:
|
||||
zh-CN: 自定义状态
|
||||
en-US: Status
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
使用 `status` 为 DatePicker 添加状态,可选 `error` 或者 `warning`。
|
||||
|
||||
## en-US
|
||||
|
||||
Add status to DatePicker with `status`, which could be `error` or `warning`.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-tree-select status="error" style="width: 100%" placeholder="Error" />
|
||||
<a-tree-select status="warning" style="width: 100%" multiple placeholder="Warning multiple" />
|
||||
</a-space>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -34,12 +34,14 @@ Tree selection control.
|
|||
| multiple | Support multiple or not, will be `true` when enable `treeCheckable`. | boolean | false | | |
|
||||
| notFoundContent | Specify content to show when no result matches | slot | `Not Found` | | |
|
||||
| placeholder | Placeholder of the select input | string\|slot | - | | |
|
||||
| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
||||
| replaceFields | Replace the title,value, key and children fields in treeNode with the corresponding fields in treeData | object | { children:'children', label:'title', value: 'value' } | | 1.6.1 (3.0.0 deprecated) |
|
||||
| searchPlaceholder | Placeholder of the search input | string\|slot | - | | |
|
||||
| searchValue(v-model) | work with `search` event to make search value controlled. | string | - | | |
|
||||
| showCheckedStrategy | The way show selected item in box. **Default:** just show child nodes. **`TreeSelect.SHOW_ALL`:** show all checked treeNodes (include parent treeNode). **`TreeSelect.SHOW_PARENT`:** show checked treeNodes (just show parent treeNode). | enum { TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD | | |
|
||||
| showSearch | Whether to display a search input in the dropdown menu(valid only in the single mode) | boolean | false | | |
|
||||
| size | To set the size of the select input, options: `large` `small` | string | 'default' | | |
|
||||
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
||||
| suffixIcon | The custom suffix icon | VNode \| slot | - | | |
|
||||
| tagRender | Customize tag render when `multiple` | (props) => slot | - | 3.0 | |
|
||||
| title | custom title | slot | | 3.0.0 | |
|
||||
|
@ -51,6 +53,7 @@ Tree selection control.
|
|||
| treeDefaultExpandedKeys | Default expanded treeNodes | string\[] \| number\[] | - | | |
|
||||
| treeExpandedKeys(v-model) | Set expanded keys | string\[] \| number\[] | - | | |
|
||||
| treeIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false | | |
|
||||
| treeLoadedKeys | (Controlled) Set loaded tree nodes, work with `loadData` only | string[] | [] | 3.3.0 |
|
||||
| treeLine | Show the line. Ref [Tree - showLine](/components/tree/#components-tree-demo-line) | boolean \| object | false | 3.0 | |
|
||||
| treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | 'value' | | |
|
||||
| treeNodeLabelProp | Will render as content of select | string | 'title' | | |
|
||||
|
|
|
@ -20,10 +20,14 @@ import type { SwitcherIconProps } from '../tree/utils/iconUtil';
|
|||
import renderSwitcherIcon from '../tree/utils/iconUtil';
|
||||
import { warning } from '../vc-util/warning';
|
||||
import { flattenChildren } from '../_util/props-util';
|
||||
import { useInjectFormItemContext } from '../form/FormItemContext';
|
||||
import { FormItemInputContext, useInjectFormItemContext } from '../form/FormItemContext';
|
||||
import type { BaseSelectRef } from '../vc-select';
|
||||
import type { BaseOptionType, DefaultOptionType } from '../vc-tree-select/TreeSelect';
|
||||
import type { TreeProps } from '../tree';
|
||||
import type { SelectCommonPlacement } from '../_util/transition';
|
||||
import { getTransitionDirection } from '../_util/transition';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
|
||||
|
||||
const getTransitionName = (rootPrefixCls: string, motion: string, transitionName?: string) => {
|
||||
if (transitionName !== undefined) {
|
||||
|
@ -62,6 +66,8 @@ export function treeSelectProps<
|
|||
bordered: { type: Boolean, default: undefined },
|
||||
treeLine: { type: [Boolean, Object] as PropType<TreeProps['showLine']>, default: undefined },
|
||||
replaceFields: { type: Object as PropType<FieldNames> },
|
||||
placement: String as PropType<SelectCommonPlacement>,
|
||||
status: String as PropType<InputStatus>,
|
||||
'onUpdate:value': { type: Function as PropType<(value: any) => void> },
|
||||
'onUpdate:treeExpandedKeys': { type: Function as PropType<(keys: Key[]) => void> },
|
||||
'onUpdate:searchValue': { type: Function as PropType<(value: string) => void> },
|
||||
|
@ -107,6 +113,8 @@ const TreeSelect = defineComponent({
|
|||
});
|
||||
|
||||
const formItemContext = useInjectFormItemContext();
|
||||
const formItemInputContext = FormItemInputContext.useInject();
|
||||
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
||||
const {
|
||||
prefixCls,
|
||||
renderEmpty,
|
||||
|
@ -118,8 +126,21 @@ const TreeSelect = defineComponent({
|
|||
getPrefixCls,
|
||||
} = useConfigInject('select', props);
|
||||
const rootPrefixCls = computed(() => getPrefixCls());
|
||||
// ===================== Placement =====================
|
||||
const placement = computed(() => {
|
||||
if (props.placement !== undefined) {
|
||||
return props.placement;
|
||||
}
|
||||
return direction.value === 'rtl'
|
||||
? ('bottomRight' as SelectCommonPlacement)
|
||||
: ('bottomLeft' as SelectCommonPlacement);
|
||||
});
|
||||
const transitionName = computed(() =>
|
||||
getTransitionName(rootPrefixCls.value, 'slide-up', props.transitionName),
|
||||
getTransitionName(
|
||||
rootPrefixCls.value,
|
||||
getTransitionDirection(placement.value),
|
||||
props.transitionName,
|
||||
),
|
||||
);
|
||||
const choiceTransitionName = computed(() =>
|
||||
getTransitionName(rootPrefixCls.value, '', props.choiceTransitionName),
|
||||
|
@ -134,6 +155,9 @@ const TreeSelect = defineComponent({
|
|||
);
|
||||
|
||||
const isMultiple = computed(() => !!(props.treeCheckable || props.multiple));
|
||||
const mergedShowArrow = computed(() =>
|
||||
props.showArrow !== undefined ? props.showArrow : props.loading || !isMultiple.value,
|
||||
);
|
||||
|
||||
const treeSelectRef = ref();
|
||||
expose({
|
||||
|
@ -173,15 +197,20 @@ const TreeSelect = defineComponent({
|
|||
multiple,
|
||||
treeIcon,
|
||||
treeLine,
|
||||
showArrow,
|
||||
switcherIcon = slots.switcherIcon?.(),
|
||||
fieldNames = props.replaceFields,
|
||||
id = formItemContext.id.value,
|
||||
} = props;
|
||||
const { isFormItemInput, hasFeedback, feedbackIcon } = formItemInputContext;
|
||||
// ===================== Icons =====================
|
||||
const { suffixIcon, removeIcon, clearIcon } = getIcons(
|
||||
{
|
||||
...props,
|
||||
multiple: isMultiple.value,
|
||||
showArrow: mergedShowArrow.value,
|
||||
hasFeedback,
|
||||
feedbackIcon,
|
||||
prefixCls: prefixCls.value,
|
||||
},
|
||||
slots,
|
||||
|
@ -202,6 +231,7 @@ const TreeSelect = defineComponent({
|
|||
'clearIcon',
|
||||
'switcherIcon',
|
||||
'bordered',
|
||||
'status',
|
||||
'onUpdate:value',
|
||||
'onUpdate:treeExpandedKeys',
|
||||
'onUpdate:searchValue',
|
||||
|
@ -214,7 +244,9 @@ const TreeSelect = defineComponent({
|
|||
[`${prefixCls.value}-sm`]: size.value === 'small',
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
[`${prefixCls.value}-borderless`]: !bordered,
|
||||
[`${prefixCls.value}-in-form-item`]: isFormItemInput,
|
||||
},
|
||||
getStatusClassNames(prefixCls.value, mergedStatus.value, hasFeedback),
|
||||
attrs.class,
|
||||
);
|
||||
const otherProps: any = {};
|
||||
|
@ -263,6 +295,8 @@ const TreeSelect = defineComponent({
|
|||
treeCheckable: () => <span class={`${prefixCls.value}-tree-checkbox-inner`} />,
|
||||
}}
|
||||
maxTagPlaceholder={props.maxTagPlaceholder || slots.maxTagPlaceholder}
|
||||
placement={placement.value}
|
||||
showArrow={hasFeedback || showArrow}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -35,12 +35,14 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg
|
|||
| multiple | 支持多选(当设置 treeCheckable 时自动变为 true) | boolean | false | | |
|
||||
| notFoundContent | 当下拉列表为空时显示的内容 | slot | `Not Found` | | |
|
||||
| placeholder | 选择框默认文字 | string\|slot | - | | |
|
||||
| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
||||
| replaceFields | 替换 treeNode 中 title,value,key,children 字段为 treeData 中对应的字段 | object | {children:'children', label:'title', key:'key', value: 'value' } | | 1.6.1 (3.0.0 废弃) |
|
||||
| searchPlaceholder | 搜索框默认文字 | string\|slot | - | | |
|
||||
| searchValue(v-model) | 搜索框的值,可以通过 `search` 事件获取用户输入 | string | - | | |
|
||||
| showCheckedStrategy | 定义选中项回填的方式。`TreeSelect.SHOW_ALL`: 显示所有选中节点(包括父节点). `TreeSelect.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时). 默认只显示子节点. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD | | |
|
||||
| showSearch | 在下拉中显示搜索框(仅在单选模式下生效) | boolean | false | | |
|
||||
| size | 选择框大小,可选 `large` `small` | string | 'default' | | |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||
| suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - | | |
|
||||
| tagRender | 自定义 tag 内容,多选时生效 | slot | - | 3.0 | |
|
||||
| title | 自定义标题 | slot | | 3.0.0 | |
|
||||
|
@ -53,6 +55,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg
|
|||
| treeExpandedKeys(v-model) | 设置展开的树节点 | string\[] \| number\[] | - | | |
|
||||
| treeIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | | |
|
||||
| treeLine | 是否展示线条样式,请参考 [Tree - showLine](/components/tree/#components-tree-demo-line) | boolean \| object | false | 3.0 | |
|
||||
| treeLoadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string[] | [] | 3.3.0 |
|
||||
| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | 'value' | | |
|
||||
| treeNodeLabelProp | 作为显示的 prop 设置 | string | 'title' | | |
|
||||
| value(v-model) | 指定当前选中的条目 | string/string\[] | - | | |
|
||||
|
|
|
@ -2,6 +2,6 @@ import '../../style/index.less';
|
|||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: tree
|
||||
// deps-lint-skip: tree, form
|
||||
import '../../select/style';
|
||||
import '../../empty/style';
|
||||
|
|
|
@ -181,7 +181,8 @@ export default defineComponent({
|
|||
open,
|
||||
notFoundContent = slots.notFoundContent?.(),
|
||||
} = baseProps;
|
||||
const { listHeight, listItemHeight, virtual } = context;
|
||||
const { listHeight, listItemHeight, virtual, dropdownMatchSelectWidth, treeExpandAction } =
|
||||
context;
|
||||
const {
|
||||
checkable,
|
||||
treeDefaultExpandAll,
|
||||
|
@ -228,7 +229,7 @@ export default defineComponent({
|
|||
treeData={memoTreeData.value as TreeDataNode[]}
|
||||
height={listHeight}
|
||||
itemHeight={listItemHeight}
|
||||
virtual={virtual}
|
||||
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
||||
multiple={multiple}
|
||||
icon={treeIcon}
|
||||
showIcon={showTreeIcon}
|
||||
|
@ -251,6 +252,7 @@ export default defineComponent({
|
|||
onExpand={onInternalExpand}
|
||||
onLoad={onTreeLoad}
|
||||
filterTreeNode={filterTreeNode}
|
||||
expandAction={treeExpandAction}
|
||||
v-slots={{ ...slots, checkable: legacyContext.customSlots.treeCheckable }}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,7 @@ import { conductCheck } from '../vc-tree/utils/conductUtil';
|
|||
import { warning } from '../vc-util/warning';
|
||||
import { toReactive } from '../_util/toReactive';
|
||||
import useMaxLevel from '../vc-tree/useMaxLevel';
|
||||
import type { ExpandAction } from '../tree/DirectoryTree';
|
||||
|
||||
export type OnInternalSelect = (value: RawValueType, info: { selected: boolean }) => void;
|
||||
|
||||
|
@ -180,6 +181,7 @@ export function treeSelectProps<
|
|||
switcherIcon: PropTypes.any,
|
||||
treeMotion: PropTypes.any,
|
||||
children: Array as PropType<VueNode[]>,
|
||||
treeExpandAction: String as PropType<ExpandAction>,
|
||||
|
||||
showArrow: { type: Boolean, default: undefined },
|
||||
showSearch: { type: Boolean, default: undefined },
|
||||
|
@ -621,8 +623,10 @@ export default defineComponent({
|
|||
switcherIcon,
|
||||
treeMotion,
|
||||
customSlots,
|
||||
|
||||
dropdownMatchSelectWidth,
|
||||
treeExpandAction,
|
||||
} = toRefs(props);
|
||||
toRaw;
|
||||
useProvideLegacySelectContext(
|
||||
toReactive({
|
||||
checkable: mergedCheckable,
|
||||
|
@ -654,6 +658,8 @@ export default defineComponent({
|
|||
treeData: filteredTreeData,
|
||||
fieldNames: mergedFieldNames,
|
||||
onSelect: onOptionSelect,
|
||||
dropdownMatchSelectWidth,
|
||||
treeExpandAction,
|
||||
} as unknown as TreeSelectContextProps),
|
||||
);
|
||||
const selectRef = ref<BaseSelectRef>();
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import type { InjectionKey } from 'vue';
|
||||
import { provide, inject } from 'vue';
|
||||
import type { ExpandAction } from '../tree/DirectoryTree';
|
||||
import type { DefaultOptionType, InternalFieldName, OnInternalSelect } from './TreeSelect';
|
||||
|
||||
export interface TreeSelectContextProps {
|
||||
virtual?: boolean;
|
||||
dropdownMatchSelectWidth?: boolean | number;
|
||||
listHeight: number;
|
||||
listItemHeight: number;
|
||||
treeData: DefaultOptionType[];
|
||||
fieldNames: InternalFieldName;
|
||||
onSelect: OnInternalSelect;
|
||||
treeExpandAction?: ExpandAction;
|
||||
}
|
||||
|
||||
const TreeSelectContextPropsKey: InjectionKey<TreeSelectContextProps> = Symbol(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// base rc-tree-select@5.1.4
|
||||
// base rc-tree-select@5.4.0
|
||||
import type { TreeSelectProps } from './TreeSelect';
|
||||
import TreeSelect, { treeSelectProps } from './TreeSelect';
|
||||
import TreeNode from './TreeNode';
|
||||
|
|
Loading…
Reference in New Issue