diff --git a/components/auto-complete/index.tsx b/components/auto-complete/index.tsx
index b3e0fba76..08c2063b2 100644
--- a/components/auto-complete/index.tsx
+++ b/components/auto-complete/index.tsx
@@ -1,6 +1,6 @@
import { App, defineComponent, inject, provide } from 'vue';
import { Option, OptGroup } from '../vc-select';
-import Select, { AbstractSelectProps, SelectValue } from '../select';
+import Select, { SelectProps } from '../select';
import Input from '../input';
import InputElement from './InputElement';
import PropTypes from '../_util/vue-types';
@@ -12,9 +12,7 @@ function isSelectOptionOrSelectOptGroup(child: any): Boolean {
}
const AutoCompleteProps = {
- ...AbstractSelectProps(),
- value: SelectValue,
- defaultValue: SelectValue,
+ ...SelectProps,
dataSource: PropTypes.array,
dropdownMenuStyle: PropTypes.style,
optionLabelProp: PropTypes.string,
diff --git a/components/config-provider/renderEmpty.tsx b/components/config-provider/renderEmpty.tsx
index 0dbc8ec95..9692ce0eb 100644
--- a/components/config-provider/renderEmpty.tsx
+++ b/components/config-provider/renderEmpty.tsx
@@ -1,4 +1,4 @@
-import { inject } from 'vue';
+import { inject, VNodeChild } from 'vue';
import Empty from '../empty';
import { defaultConfigProvider } from '.';
@@ -30,7 +30,7 @@ const RenderEmpty = (props: RenderEmptyProps) => {
return renderHtml(props.componentName);
};
-function renderEmpty(componentName?: string) {
+function renderEmpty(componentName?: string): VNodeChild | JSX.Element{
return ;
}
diff --git a/components/select/index.tsx b/components/select/index.tsx
index b7388283b..84592ea11 100644
--- a/components/select/index.tsx
+++ b/components/select/index.tsx
@@ -1,268 +1,204 @@
-import { provide, inject, defineComponent, App } from 'vue';
-import warning from '../_util/warning';
import omit from 'omit.js';
-import PropTypes, { withUndefined } from '../_util/vue-types';
-import { Select as VcSelect, Option, OptGroup } from '../vc-select';
+import classNames from '../_util/classNames';
+import RcSelect, { Option, OptGroup, SelectProps as RcSelectProps, props } from '../vc-select2';
+import { OptionProps } from '../vc-select2/Option';
import { defaultConfigProvider } from '../config-provider';
-import { getComponent, getOptionProps, isValidElement, getSlot } from '../_util/props-util';
-import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
-import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
-import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
-import DownOutlined from '@ant-design/icons-vue/DownOutlined';
-import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
-import { cloneElement } from '../_util/vnode';
+import getIcons from './utils/iconUtil';
+import { computed, defineComponent, inject, ref, VNodeChild, App, PropType } from 'vue';
+import PropTypes from '../_util/vue-types';
+import { tuple } from '../_util/type';
-const AbstractSelectProps = () => ({
- prefixCls: PropTypes.string,
- size: PropTypes.oneOf(['small', 'large', 'default']),
- showAction: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(String)]),
- notFoundContent: PropTypes.VNodeChild,
- transitionName: PropTypes.string,
- choiceTransitionName: PropTypes.string,
- showSearch: PropTypes.looseBool,
- allowClear: PropTypes.looseBool,
- disabled: PropTypes.looseBool,
- tabindex: PropTypes.number,
- placeholder: PropTypes.VNodeChild,
- defaultActiveFirstOption: PropTypes.looseBool,
- dropdownClassName: PropTypes.string,
- dropdownStyle: PropTypes.style,
- dropdownMenuStyle: PropTypes.style,
- dropdownMatchSelectWidth: PropTypes.looseBool,
- // onSearch: (value: string) => any,
- filterOption: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
- autofocus: PropTypes.looseBool,
- backfill: PropTypes.looseBool,
- showArrow: PropTypes.looseBool,
- getPopupContainer: PropTypes.func,
- open: PropTypes.looseBool,
- defaultOpen: PropTypes.looseBool,
- autoClearSearchValue: PropTypes.looseBool,
- dropdownRender: PropTypes.func,
- onChange: PropTypes.func,
- loading: PropTypes.looseBool,
-});
-const Value = PropTypes.shape({
- key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-}).loose;
+type RawValue = string | number;
-const SelectValue = PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.number,
- PropTypes.arrayOf(PropTypes.oneOfType([Value, PropTypes.string, PropTypes.number])),
- Value,
-]);
+export { OptionProps };
-const SelectProps = {
- ...AbstractSelectProps(),
- value: SelectValue,
- defaultValue: SelectValue,
- // mode: PropTypes.oneOf(['default', 'multiple', 'tags', 'combobox']),
- mode: PropTypes.string,
- optionLabelProp: PropTypes.string,
- firstActiveValue: PropTypes.oneOfType([String, PropTypes.arrayOf(String)]),
- maxTagCount: PropTypes.number,
- maxTagPlaceholder: PropTypes.any,
- maxTagTextLength: PropTypes.number,
- dropdownMatchSelectWidth: PropTypes.looseBool,
- optionFilterProp: PropTypes.string,
- labelInValue: PropTypes.looseBool,
- getPopupContainer: PropTypes.func,
- tokenSeparators: PropTypes.arrayOf(PropTypes.string),
- getInputElement: PropTypes.func,
- options: PropTypes.array,
- suffixIcon: PropTypes.any,
- removeIcon: PropTypes.any,
- clearIcon: PropTypes.any,
- menuItemSelectedIcon: PropTypes.any,
-};
+export type OptionType = typeof Option;
-const SelectPropTypes = {
- prefixCls: PropTypes.string,
- size: PropTypes.oneOf(['default', 'large', 'small']),
- // combobox: PropTypes.looseBool,
- notFoundContent: PropTypes.any,
- showSearch: PropTypes.looseBool,
- optionLabelProp: PropTypes.string,
- transitionName: PropTypes.string,
- choiceTransitionName: PropTypes.string,
-};
+export interface LabeledValue {
+ key?: string;
+ value: RawValue;
+ label: VNodeChild;
+}
+export type SizeType = 'small' | 'middle' | 'large' | undefined;
+export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[];
+
+export interface InternalSelectProps extends Omit, 'mode'> {
+ suffixIcon?: VNodeChild;
+ itemIcon?: VNodeChild;
+ size?: SizeType;
+ mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
+ bordered?: boolean;
+}
+
+export interface SelectPropsTypes
+ extends Omit, 'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'> {
+ mode?: 'multiple' | 'tags';
+}
+export type SelectTypes = SelectPropsTypes
+export const SelectProps = {
+ ...omit(props, ['inputIcon' ,'mode' ,'getInputElement' ,'backfill' ,'class' ,'style']),
+ value: {
+ type: [Array, Object, String, Number] as PropType
+ },
+ defaultValue: {
+ type: [Array, Object, String, Number] as PropType
+ },
+ suffixIcon: PropTypes.VNodeChild,
+ itemIcon: PropTypes.VNodeChild,
+ size: PropTypes.oneOf(tuple('small', 'middle', 'large', undefined, 'default')),
+ mode: PropTypes.oneOf(tuple('multiple', 'tags')),
+ bordered: PropTypes.looseBool.def(true),
+ transitionName: PropTypes.string.def('slide-up'),
+ choiceTransitionName: PropTypes.string.def(''),
+}
-export { AbstractSelectProps, SelectValue, SelectProps };
-const SECRET_COMBOBOX_MODE_DO_NOT_USE = 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
const Select = defineComponent({
- SECRET_COMBOBOX_MODE_DO_NOT_USE,
- Option: { ...Option, name: 'ASelectOption' },
- OptGroup: { ...OptGroup, name: 'ASelectOptGroup' },
name: 'ASelect',
- props: {
- ...SelectProps,
- showSearch: PropTypes.looseBool.def(false),
- transitionName: PropTypes.string.def('slide-up'),
- choiceTransitionName: PropTypes.string.def('zoom'),
- },
- propTypes: SelectPropTypes,
- setup() {
- return {
- configProvider: inject('configProvider', defaultConfigProvider),
- popupRef: null,
+ Option,
+ OptGroup,
+ inheritAttrs: false,
+ props: SelectProps,
+ SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE',
+ emits: ['change', 'update:value'],
+ setup(props: any, {attrs, emit}) {
+ const selectRef = ref(null);
+
+ const configProvider = inject('configProvider', defaultConfigProvider);
+
+ const focus = () => {
+ if (selectRef.value) {
+ selectRef.value.focus();
+ }
};
- },
- created() {
- provide('savePopupRef', this.savePopupRef);
- warning(
- this.$props.mode !== 'combobox',
- 'Select',
- 'The combobox mode of Select is deprecated,' +
- 'it will be removed in next major version,' +
- 'please use AutoComplete instead',
- );
- },
- methods: {
- getNotFoundContent(renderEmpty: any) {
- const notFoundContent = getComponent(this, 'notFoundContent');
- if (notFoundContent !== undefined) {
- return notFoundContent;
- }
- if (this.isCombobox()) {
- return null;
- }
- return renderEmpty('Select');
- },
- savePopupRef(ref) {
- this.popupRef = ref;
- },
- focus() {
- (this.$refs.vcSelect as any).focus();
- },
- blur() {
- (this.$refs.vcSelect as any).blur();
- },
- isCombobox() {
- const { mode } = this;
- return mode === 'combobox' || mode === SECRET_COMBOBOX_MODE_DO_NOT_USE;
- },
+ const blur = () => {
+ if (selectRef.value) {
+ selectRef.value.blur();
+ }
+ };
- renderSuffixIcon(prefixCls) {
- const { loading } = this.$props;
- let suffixIcon = getComponent(this, 'suffixIcon');
- suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
- if (suffixIcon) {
- return isValidElement(suffixIcon)
- ? cloneElement(suffixIcon, { class: `${prefixCls}-arrow-icon` })
- : suffixIcon;
+ const mode = computed(()=>{
+ const { mode } = props
+
+ if ((mode as any) === 'combobox') {
+ return undefined;
}
- if (loading) {
- return ;
+
+ if (mode === Select.SECRET_COMBOBOX_MODE_DO_NOT_USE) {
+ return 'combobox';
}
- return ;
- },
+
+ return mode;
+ });
+
+ const mergedClassName = computed(()=> classNames(
+ {
+ [`${props.prefixCls}-lg`]: props.size === 'large',
+ [`${props.prefixCls}-sm`]: props.size === 'small',
+ [`${props.prefixCls}-rtl`]: props.direction === 'rtl',
+ [`${props.prefixCls}-borderless`]: !props.bordered,
+ },
+ attrs.class,
+ ));
+ const triggerChange=(...args: any[])=>{
+ console.log(args)
+ emit('update:value', ...args)
+ emit('change', ...args)
+ }
+ return {
+ mergedClassName,
+ mode,
+ focus,
+ blur,
+ configProvider,
+ triggerChange
+ }
},
render() {
+ const {configProvider, mode, mergedClassName,triggerChange, $slots: slots, $props} = this as any;
+ const props: SelectTypes = $props
const {
prefixCls: customizePrefixCls,
- size,
- mode,
- options,
+ notFoundContent,
+ listHeight = 256,
+ listItemHeight = 24,
getPopupContainer,
- showArrow,
- ...restProps
- } = getOptionProps(this);
- const { class: className } = this.$attrs as any;
+ dropdownClassName,
+ direction,
+ virtual,
+ dropdownMatchSelectWidth
+ } = props;
- const getPrefixCls = this.configProvider.getPrefixCls;
- const renderEmpty = this.configProvider.renderEmpty;
+ const { getPrefixCls, renderEmpty, getPopupContainer: getContextPopupContainer } = configProvider
const prefixCls = getPrefixCls('select', customizePrefixCls);
- const { getPopupContainer: getContextPopupContainer } = this.configProvider;
- let removeIcon = getComponent(this, 'removeIcon');
- removeIcon = Array.isArray(removeIcon) ? removeIcon[0] : removeIcon;
- let clearIcon = getComponent(this, 'clearIcon');
- clearIcon = Array.isArray(clearIcon) ? clearIcon[0] : clearIcon;
- let menuItemSelectedIcon = getComponent(this, 'menuItemSelectedIcon');
- menuItemSelectedIcon = Array.isArray(menuItemSelectedIcon)
- ? menuItemSelectedIcon[0]
- : menuItemSelectedIcon;
- const rest = omit(restProps as any, [
- 'inputIcon',
- 'removeIcon',
- 'clearIcon',
- 'suffixIcon',
- 'menuItemSelectedIcon',
- ]);
+ const isMultiple = mode === 'multiple' || mode === 'tags';
- const cls = {
- [className]: className,
- [`${prefixCls}-lg`]: size === 'large',
- [`${prefixCls}-sm`]: size === 'small',
- [`${prefixCls}-show-arrow`]: showArrow,
- };
-
- let { optionLabelProp } = this.$props;
- if (this.isCombobox()) {
- // children 带 dom 结构时,无法填入输入框
- optionLabelProp = optionLabelProp || 'value';
+ // ===================== Empty =====================
+ let mergedNotFound: VNodeChild;
+ if (notFoundContent !== undefined) {
+ mergedNotFound = notFoundContent;
+ } else if(slots.notFoundContent){
+ mergedNotFound = slots.notFoundContent()
+ } else if (mode === 'combobox') {
+ mergedNotFound = null;
+ } else {
+ mergedNotFound = renderEmpty('Select') as any;
}
- const modeConfig = {
- multiple: mode === 'multiple',
- tags: mode === 'tags',
- combobox: this.isCombobox(),
- };
- const finalRemoveIcon = (removeIcon &&
- (isValidElement(removeIcon)
- ? cloneElement(removeIcon, { class: `${prefixCls}-remove-icon` })
- : removeIcon)) || ;
-
- const finalClearIcon = (clearIcon &&
- (isValidElement(clearIcon)
- ? cloneElement(clearIcon, { class: `${prefixCls}-clear-icon` })
- : clearIcon)) || ;
-
- const finalMenuItemSelectedIcon = (menuItemSelectedIcon &&
- (isValidElement(menuItemSelectedIcon)
- ? cloneElement(menuItemSelectedIcon, { class: `${prefixCls}-selected-icon` })
- : menuItemSelectedIcon)) || ;
-
- const selectProps = {
- inputIcon: this.renderSuffixIcon(prefixCls),
- removeIcon: finalRemoveIcon,
- clearIcon: finalClearIcon,
- menuItemSelectedIcon: finalMenuItemSelectedIcon,
- showArrow,
- ...rest,
- ...modeConfig,
+ // ===================== Icons =====================
+ const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons({
+ ...this.$props,
+ multiple: isMultiple,
prefixCls,
- optionLabelProp: optionLabelProp || 'children',
- notFoundContent: this.getNotFoundContent(renderEmpty),
- maxTagPlaceholder: getComponent(this, 'maxTagPlaceholder'),
- placeholder: getComponent(this, 'placeholder'),
- children: options
- ? options.map(option => {
- const { key, label = option.title, class: cls, style, ...restOption } = option;
- return (
-
- );
- })
- : getSlot(this),
- dropdownRender: getComponent(this, 'dropdownRender', {}, false),
- getPopupContainer: getPopupContainer || getContextPopupContainer,
- ...this.$attrs,
- class: cls,
- ref: 'vcSelect',
- };
- return ;
- },
-});
+ }, slots);
+ const selectProps = omit(props, [
+ 'prefixCls',
+ 'suffixIcon',
+ 'itemIcon',
+ 'removeIcon',
+ 'clearIcon',
+ 'size',
+ 'bordered',
+ ]) as any;
+
+ const rcSelectRtlDropDownClassName = classNames(dropdownClassName, {
+ [`${prefixCls}-dropdown-${direction}`]: direction === 'rtl',
+ });
+
+ {slots?.default()}
+
+ }
+})
/* istanbul ignore next */
Select.install = function(app: App) {
app.component(Select.name, Select);
- app.component(Select.Option.name, Select.Option);
- app.component(Select.OptGroup.name, Select.OptGroup);
+ app.component('ASelectOption', Select.Option);
+ app.component('ASelectOptGroup', Select.OptGroup);
return app;
};
-export default Select;
+export default Select as typeof Select & {
+ readonly Option: typeof Option;
+ readonly OptGroup: typeof OptGroup;
+ SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
+};
diff --git a/components/select/index1.tsx b/components/select/index1.tsx
new file mode 100644
index 000000000..b7388283b
--- /dev/null
+++ b/components/select/index1.tsx
@@ -0,0 +1,268 @@
+import { provide, inject, defineComponent, App } from 'vue';
+import warning from '../_util/warning';
+import omit from 'omit.js';
+import PropTypes, { withUndefined } from '../_util/vue-types';
+import { Select as VcSelect, Option, OptGroup } from '../vc-select';
+import { defaultConfigProvider } from '../config-provider';
+import { getComponent, getOptionProps, isValidElement, getSlot } from '../_util/props-util';
+import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
+import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
+import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
+import DownOutlined from '@ant-design/icons-vue/DownOutlined';
+import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
+import { cloneElement } from '../_util/vnode';
+
+const AbstractSelectProps = () => ({
+ prefixCls: PropTypes.string,
+ size: PropTypes.oneOf(['small', 'large', 'default']),
+ showAction: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(String)]),
+ notFoundContent: PropTypes.VNodeChild,
+ transitionName: PropTypes.string,
+ choiceTransitionName: PropTypes.string,
+ showSearch: PropTypes.looseBool,
+ allowClear: PropTypes.looseBool,
+ disabled: PropTypes.looseBool,
+ tabindex: PropTypes.number,
+ placeholder: PropTypes.VNodeChild,
+ defaultActiveFirstOption: PropTypes.looseBool,
+ dropdownClassName: PropTypes.string,
+ dropdownStyle: PropTypes.style,
+ dropdownMenuStyle: PropTypes.style,
+ dropdownMatchSelectWidth: PropTypes.looseBool,
+ // onSearch: (value: string) => any,
+ filterOption: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
+ autofocus: PropTypes.looseBool,
+ backfill: PropTypes.looseBool,
+ showArrow: PropTypes.looseBool,
+ getPopupContainer: PropTypes.func,
+ open: PropTypes.looseBool,
+ defaultOpen: PropTypes.looseBool,
+ autoClearSearchValue: PropTypes.looseBool,
+ dropdownRender: PropTypes.func,
+ onChange: PropTypes.func,
+ loading: PropTypes.looseBool,
+});
+const Value = PropTypes.shape({
+ key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+}).loose;
+
+const SelectValue = PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.arrayOf(PropTypes.oneOfType([Value, PropTypes.string, PropTypes.number])),
+ Value,
+]);
+
+const SelectProps = {
+ ...AbstractSelectProps(),
+ value: SelectValue,
+ defaultValue: SelectValue,
+ // mode: PropTypes.oneOf(['default', 'multiple', 'tags', 'combobox']),
+ mode: PropTypes.string,
+ optionLabelProp: PropTypes.string,
+ firstActiveValue: PropTypes.oneOfType([String, PropTypes.arrayOf(String)]),
+ maxTagCount: PropTypes.number,
+ maxTagPlaceholder: PropTypes.any,
+ maxTagTextLength: PropTypes.number,
+ dropdownMatchSelectWidth: PropTypes.looseBool,
+ optionFilterProp: PropTypes.string,
+ labelInValue: PropTypes.looseBool,
+ getPopupContainer: PropTypes.func,
+ tokenSeparators: PropTypes.arrayOf(PropTypes.string),
+ getInputElement: PropTypes.func,
+ options: PropTypes.array,
+ suffixIcon: PropTypes.any,
+ removeIcon: PropTypes.any,
+ clearIcon: PropTypes.any,
+ menuItemSelectedIcon: PropTypes.any,
+};
+
+const SelectPropTypes = {
+ prefixCls: PropTypes.string,
+ size: PropTypes.oneOf(['default', 'large', 'small']),
+ // combobox: PropTypes.looseBool,
+ notFoundContent: PropTypes.any,
+ showSearch: PropTypes.looseBool,
+ optionLabelProp: PropTypes.string,
+ transitionName: PropTypes.string,
+ choiceTransitionName: PropTypes.string,
+};
+
+export { AbstractSelectProps, SelectValue, SelectProps };
+const SECRET_COMBOBOX_MODE_DO_NOT_USE = 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
+const Select = defineComponent({
+ SECRET_COMBOBOX_MODE_DO_NOT_USE,
+ Option: { ...Option, name: 'ASelectOption' },
+ OptGroup: { ...OptGroup, name: 'ASelectOptGroup' },
+ name: 'ASelect',
+ props: {
+ ...SelectProps,
+ showSearch: PropTypes.looseBool.def(false),
+ transitionName: PropTypes.string.def('slide-up'),
+ choiceTransitionName: PropTypes.string.def('zoom'),
+ },
+ propTypes: SelectPropTypes,
+ setup() {
+ return {
+ configProvider: inject('configProvider', defaultConfigProvider),
+ popupRef: null,
+ };
+ },
+ created() {
+ provide('savePopupRef', this.savePopupRef);
+ warning(
+ this.$props.mode !== 'combobox',
+ 'Select',
+ 'The combobox mode of Select is deprecated,' +
+ 'it will be removed in next major version,' +
+ 'please use AutoComplete instead',
+ );
+ },
+ methods: {
+ getNotFoundContent(renderEmpty: any) {
+ const notFoundContent = getComponent(this, 'notFoundContent');
+ if (notFoundContent !== undefined) {
+ return notFoundContent;
+ }
+ if (this.isCombobox()) {
+ return null;
+ }
+ return renderEmpty('Select');
+ },
+ savePopupRef(ref) {
+ this.popupRef = ref;
+ },
+ focus() {
+ (this.$refs.vcSelect as any).focus();
+ },
+ blur() {
+ (this.$refs.vcSelect as any).blur();
+ },
+
+ isCombobox() {
+ const { mode } = this;
+ return mode === 'combobox' || mode === SECRET_COMBOBOX_MODE_DO_NOT_USE;
+ },
+
+ renderSuffixIcon(prefixCls) {
+ const { loading } = this.$props;
+ let suffixIcon = getComponent(this, 'suffixIcon');
+ suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
+ if (suffixIcon) {
+ return isValidElement(suffixIcon)
+ ? cloneElement(suffixIcon, { class: `${prefixCls}-arrow-icon` })
+ : suffixIcon;
+ }
+ if (loading) {
+ return ;
+ }
+ return ;
+ },
+ },
+ render() {
+ const {
+ prefixCls: customizePrefixCls,
+ size,
+ mode,
+ options,
+ getPopupContainer,
+ showArrow,
+ ...restProps
+ } = getOptionProps(this);
+ const { class: className } = this.$attrs as any;
+
+ const getPrefixCls = this.configProvider.getPrefixCls;
+ const renderEmpty = this.configProvider.renderEmpty;
+ const prefixCls = getPrefixCls('select', customizePrefixCls);
+
+ const { getPopupContainer: getContextPopupContainer } = this.configProvider;
+ let removeIcon = getComponent(this, 'removeIcon');
+ removeIcon = Array.isArray(removeIcon) ? removeIcon[0] : removeIcon;
+ let clearIcon = getComponent(this, 'clearIcon');
+ clearIcon = Array.isArray(clearIcon) ? clearIcon[0] : clearIcon;
+ let menuItemSelectedIcon = getComponent(this, 'menuItemSelectedIcon');
+ menuItemSelectedIcon = Array.isArray(menuItemSelectedIcon)
+ ? menuItemSelectedIcon[0]
+ : menuItemSelectedIcon;
+ const rest = omit(restProps as any, [
+ 'inputIcon',
+ 'removeIcon',
+ 'clearIcon',
+ 'suffixIcon',
+ 'menuItemSelectedIcon',
+ ]);
+
+ const cls = {
+ [className]: className,
+ [`${prefixCls}-lg`]: size === 'large',
+ [`${prefixCls}-sm`]: size === 'small',
+ [`${prefixCls}-show-arrow`]: showArrow,
+ };
+
+ let { optionLabelProp } = this.$props;
+ if (this.isCombobox()) {
+ // children 带 dom 结构时,无法填入输入框
+ optionLabelProp = optionLabelProp || 'value';
+ }
+
+ const modeConfig = {
+ multiple: mode === 'multiple',
+ tags: mode === 'tags',
+ combobox: this.isCombobox(),
+ };
+ const finalRemoveIcon = (removeIcon &&
+ (isValidElement(removeIcon)
+ ? cloneElement(removeIcon, { class: `${prefixCls}-remove-icon` })
+ : removeIcon)) || ;
+
+ const finalClearIcon = (clearIcon &&
+ (isValidElement(clearIcon)
+ ? cloneElement(clearIcon, { class: `${prefixCls}-clear-icon` })
+ : clearIcon)) || ;
+
+ const finalMenuItemSelectedIcon = (menuItemSelectedIcon &&
+ (isValidElement(menuItemSelectedIcon)
+ ? cloneElement(menuItemSelectedIcon, { class: `${prefixCls}-selected-icon` })
+ : menuItemSelectedIcon)) || ;
+
+ const selectProps = {
+ inputIcon: this.renderSuffixIcon(prefixCls),
+ removeIcon: finalRemoveIcon,
+ clearIcon: finalClearIcon,
+ menuItemSelectedIcon: finalMenuItemSelectedIcon,
+ showArrow,
+ ...rest,
+ ...modeConfig,
+ prefixCls,
+ optionLabelProp: optionLabelProp || 'children',
+ notFoundContent: this.getNotFoundContent(renderEmpty),
+ maxTagPlaceholder: getComponent(this, 'maxTagPlaceholder'),
+ placeholder: getComponent(this, 'placeholder'),
+ children: options
+ ? options.map(option => {
+ const { key, label = option.title, class: cls, style, ...restOption } = option;
+ return (
+
+ );
+ })
+ : getSlot(this),
+ dropdownRender: getComponent(this, 'dropdownRender', {}, false),
+ getPopupContainer: getPopupContainer || getContextPopupContainer,
+ ...this.$attrs,
+ class: cls,
+ ref: 'vcSelect',
+ };
+ return ;
+ },
+});
+
+/* istanbul ignore next */
+Select.install = function(app: App) {
+ app.component(Select.name, Select);
+ app.component(Select.Option.name, Select.Option);
+ app.component(Select.OptGroup.name, Select.OptGroup);
+ return app;
+};
+export default Select;
diff --git a/components/select/utils/iconUtil.tsx b/components/select/utils/iconUtil.tsx
new file mode 100644
index 000000000..ce55393c9
--- /dev/null
+++ b/components/select/utils/iconUtil.tsx
@@ -0,0 +1,64 @@
+
+import DownOutlined from '@ant-design/icons-vue/DownOutlined';
+import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
+import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
+import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
+import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
+import SearchOutlined from '@ant-design/icons-vue/SearchOutlined';
+
+export default function getIcons(props: any, slots: any = {}) {
+ const {
+ loading,
+ multiple,
+ prefixCls,
+ } = props;
+ const suffixIcon = props.suffixIcon || slots.suffixIcon && slots.suffixIcon();
+ const clearIcon = props.clearIcon || slots.clearIcon && slots.clearIcon();
+ const menuItemSelectedIcon = props.menuItemSelectedIcon || slots.menuItemSelectedIcon && slots.menuItemSelectedIcon();
+ const removeIcon = props.removeIcon || slots.removeIcon && slots.removeIcon();
+ // Clear Icon
+ let mergedClearIcon = clearIcon;
+ if (!clearIcon) {
+ mergedClearIcon = ;
+ }
+
+ // Arrow item icon
+ let mergedSuffixIcon = null;
+ if (suffixIcon !== undefined) {
+ mergedSuffixIcon = suffixIcon;
+ } else if (loading) {
+ mergedSuffixIcon = ;
+ } else {
+ const iconCls = `${prefixCls}-suffix`;
+ mergedSuffixIcon = ({ open, showSearch }: { open: boolean; showSearch: boolean }) => {
+ if (open && showSearch) {
+ return ;
+ }
+ return ;
+ };
+ }
+
+ // Checked item icon
+ let mergedItemIcon = null;
+ if (menuItemSelectedIcon !== undefined) {
+ mergedItemIcon = menuItemSelectedIcon;
+ } else if (multiple) {
+ mergedItemIcon = ;
+ } else {
+ mergedItemIcon = null;
+ }
+
+ let mergedRemoveIcon = null;
+ if (removeIcon !== undefined) {
+ mergedRemoveIcon = removeIcon;
+ } else {
+ mergedRemoveIcon = ;
+ }
+
+ return {
+ clearIcon: mergedClearIcon,
+ suffixIcon: mergedSuffixIcon,
+ itemIcon: mergedItemIcon,
+ removeIcon: mergedRemoveIcon,
+ };
+}
diff --git a/components/tree-select/interface.jsx b/components/tree-select/interface.jsx
index e2d988c5c..2524ae37b 100644
--- a/components/tree-select/interface.jsx
+++ b/components/tree-select/interface.jsx
@@ -1,5 +1,5 @@
import PropTypes, { withUndefined } from '../_util/vue-types';
-import { AbstractSelectProps } from '../select';
+import { SelectProps } from '../select';
export const TreeData = PropTypes.shape({
key: PropTypes.string,
@@ -10,7 +10,7 @@ export const TreeData = PropTypes.shape({
}).loose;
export const TreeSelectProps = () => ({
- ...AbstractSelectProps(),
+ ...SelectProps,
autofocus: PropTypes.looseBool,
dropdownStyle: PropTypes.object,
filterTreeNode: withUndefined(PropTypes.oneOfType([Function, Boolean])),
diff --git a/components/vc-select2/generate.tsx b/components/vc-select2/generate.tsx
index 3d0ae48db..230ec974a 100644
--- a/components/vc-select2/generate.tsx
+++ b/components/vc-select2/generate.tsx
@@ -65,6 +65,106 @@ const DEFAULT_OMIT_PROPS = [
'onInputKeyDown',
];
+export const props = {
+ prefixCls: PropTypes.string,
+ id: PropTypes.string,
+ class: PropTypes.string,
+ style: PropTypes.any,
+
+ // Options
+ options: PropTypes.array,
+ children: PropTypes.array.def([]),
+ mode: PropTypes.string,
+
+ // Value
+ value: PropTypes.any,
+ defaultValue: PropTypes.any,
+ labelInValue: PropTypes.looseBool,
+
+ // Search
+ inputValue: PropTypes.string,
+ searchValue: PropTypes.string,
+ optionFilterProp: PropTypes.string.def('value'),
+ /**
+ * In Select, `false` means do nothing.
+ * In TreeSelect, `false` will highlight match item.
+ * It's by design.
+ */
+ filterOption: PropTypes.any,
+ showSearch: PropTypes.looseBool,
+ autoClearSearchValue: PropTypes.looseBool,
+ onSearch: PropTypes.func,
+ onClear: PropTypes.func,
+
+ // Icons
+ allowClear: PropTypes.looseBool,
+ clearIcon: PropTypes.any,
+ showArrow: PropTypes.looseBool,
+ inputIcon: PropTypes.any,
+ removeIcon: PropTypes.any,
+ menuItemSelectedIcon: PropTypes.func,
+
+ // Dropdown
+ open: PropTypes.looseBool,
+ defaultOpen: PropTypes.looseBool,
+ listHeight: PropTypes.number.def(200),
+ listItemHeight: PropTypes.number.def(20),
+ dropdownStyle: PropTypes.object,
+ dropdownClassName: PropTypes.string,
+ dropdownMatchSelectWidth: PropTypes.oneOfType([Boolean, Number]).def(true),
+ virtual: PropTypes.looseBool,
+ dropdownRender: PropTypes.func,
+ dropdownAlign: PropTypes.any,
+ animation: PropTypes.string,
+ transitionName: PropTypes.string,
+ getPopupContainer: PropTypes.func,
+ direction: PropTypes.string,
+
+ // Others
+ disabled: PropTypes.looseBool,
+ loading: PropTypes.looseBool,
+ autofocus: PropTypes.looseBool,
+ defaultActiveFirstOption: PropTypes.looseBool,
+ notFoundContent: PropTypes.any.def('Not Found'),
+ placeholder: PropTypes.any,
+ backfill: PropTypes.looseBool,
+ getInputElement: PropTypes.func,
+ optionLabelProp: PropTypes.string,
+ maxTagTextLength: PropTypes.number,
+ maxTagCount: PropTypes.number,
+ maxTagPlaceholder: PropTypes.any,
+ tokenSeparators: PropTypes.array,
+ tagRender: PropTypes.func,
+ showAction: PropTypes.array.def([]),
+ tabindex: PropTypes.number,
+
+ // Events
+ onKeyup: PropTypes.func,
+ onKeydown: PropTypes.func,
+ onPopupScroll: PropTypes.func,
+ onDropdownVisibleChange: PropTypes.func,
+ onSelect: PropTypes.func,
+ onDeselect: PropTypes.func,
+ onInputKeyDown: PropTypes.func,
+ onClick: PropTypes.func,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ onFocus: PropTypes.func,
+ onMousedown: PropTypes.func,
+ onMouseenter: PropTypes.func,
+ onMouseleave: PropTypes.func,
+
+ // Motion
+ choiceTransitionName: PropTypes.string,
+
+ // Internal props
+ /**
+ * Only used in current version for internal event process.
+ * Do not use in production environment.
+ */
+ internalProps: PropTypes.object.def({}),
+}
+
export interface SelectProps {
prefixCls?: string;
id?: string;
@@ -1221,104 +1321,6 @@ export default function generateSelector<
},
});
Select.inheritAttrs = false;
- Select.props = {
- prefixCls: PropTypes.string,
- id: PropTypes.string,
- class: PropTypes.string,
- style: PropTypes.any,
-
- // Options
- options: PropTypes.array,
- children: PropTypes.array.def([]),
- mode: PropTypes.string,
-
- // Value
- value: PropTypes.any,
- defaultValue: PropTypes.any,
- labelInValue: PropTypes.looseBool,
-
- // Search
- inputValue: PropTypes.string,
- searchValue: PropTypes.string,
- optionFilterProp: PropTypes.string.def('value'),
- /**
- * In Select, `false` means do nothing.
- * In TreeSelect, `false` will highlight match item.
- * It's by design.
- */
- filterOption: PropTypes.any,
- showSearch: PropTypes.looseBool,
- autoClearSearchValue: PropTypes.looseBool,
- onSearch: PropTypes.func,
- onClear: PropTypes.func,
-
- // Icons
- allowClear: PropTypes.looseBool,
- clearIcon: PropTypes.any,
- showArrow: PropTypes.looseBool,
- inputIcon: PropTypes.any,
- removeIcon: PropTypes.any,
- menuItemSelectedIcon: PropTypes.func,
-
- // Dropdown
- open: PropTypes.looseBool,
- defaultOpen: PropTypes.looseBool,
- listHeight: PropTypes.number.def(200),
- listItemHeight: PropTypes.number.def(20),
- dropdownStyle: PropTypes.object,
- dropdownClassName: PropTypes.string,
- dropdownMatchSelectWidth: PropTypes.oneOfType([Boolean, Number]).def(true),
- virtual: PropTypes.looseBool,
- dropdownRender: PropTypes.func,
- dropdownAlign: PropTypes.any,
- animation: PropTypes.string,
- transitionName: PropTypes.string,
- getPopupContainer: PropTypes.func,
- direction: PropTypes.string,
-
- // Others
- disabled: PropTypes.looseBool,
- loading: PropTypes.looseBool,
- autofocus: PropTypes.looseBool,
- defaultActiveFirstOption: PropTypes.looseBool,
- notFoundContent: PropTypes.any.def('Not Found'),
- placeholder: PropTypes.any,
- backfill: PropTypes.looseBool,
- getInputElement: PropTypes.func,
- optionLabelProp: PropTypes.string,
- maxTagTextLength: PropTypes.number,
- maxTagCount: PropTypes.number,
- maxTagPlaceholder: PropTypes.any,
- tokenSeparators: PropTypes.array,
- tagRender: PropTypes.func,
- showAction: PropTypes.array.def([]),
- tabindex: PropTypes.number,
-
- // Events
- onKeyup: PropTypes.func,
- onKeydown: PropTypes.func,
- onPopupScroll: PropTypes.func,
- onDropdownVisibleChange: PropTypes.func,
- onSelect: PropTypes.func,
- onDeselect: PropTypes.func,
- onInputKeyDown: PropTypes.func,
- onClick: PropTypes.func,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- onFocus: PropTypes.func,
- onMousedown: PropTypes.func,
- onMouseenter: PropTypes.func,
- onMouseleave: PropTypes.func,
-
- // Motion
- choiceTransitionName: PropTypes.string,
-
- // Internal props
- /**
- * Only used in current version for internal event process.
- * Do not use in production environment.
- */
- internalProps: PropTypes.object.def({}),
- };
+ Select.props = props;
return Select;
}
diff --git a/components/vc-select2/index.ts b/components/vc-select2/index.ts
index f1a12a1a3..9652b88e2 100644
--- a/components/vc-select2/index.ts
+++ b/components/vc-select2/index.ts
@@ -1,7 +1,7 @@
-import Select, { ExportedSelectProps } from './Select';
+import Select, { ExportedSelectProps as SelectProps } from './Select';
import Option from './Option';
import OptGroup from './OptGroup';
-type SelectProps = ExportedSelectProps;
-export { Option, OptGroup, SelectProps };
+import { props } from './generate';
+export { Option, OptGroup, SelectProps, props };
export default Select;
diff --git a/components/vc-select2/interface/generator.ts b/components/vc-select2/interface/generator.ts
index 259f34812..62e4548f5 100644
--- a/components/vc-select2/interface/generator.ts
+++ b/components/vc-select2/interface/generator.ts
@@ -1,4 +1,4 @@
-import * as Vue from 'vue';
+import { VNodeChild } from 'vue';
export type SelectSource = 'option' | 'selection' | 'input';
@@ -12,7 +12,7 @@ export type RawValueType = string | number | null;
export interface LabelValueType extends Record {
key?: Key;
value?: RawValueType;
- label?: Vue.VNodeChild;
+ label?: VNodeChild;
}
export type DefaultValueType = RawValueType | RawValueType[] | LabelValueType | LabelValueType[];