refactor: tree-select
parent
b0678d79ee
commit
956ed09885
|
@ -0,0 +1,15 @@
|
||||||
|
function omit<T extends object, K extends [...(keyof T)[]]>(
|
||||||
|
obj: T,
|
||||||
|
fields: K,
|
||||||
|
): {
|
||||||
|
[K2 in Exclude<keyof T, K[number]>]: T[K2];
|
||||||
|
} {
|
||||||
|
// eslint-disable-next-line prefer-object-spread
|
||||||
|
const shallowCopy = Object.assign({}, obj);
|
||||||
|
for (let i = 0; i < fields.length; i += 1) {
|
||||||
|
const key = fields[i];
|
||||||
|
delete shallowCopy[key];
|
||||||
|
}
|
||||||
|
return shallowCopy;
|
||||||
|
}
|
||||||
|
export default omit;
|
|
@ -1,9 +1,9 @@
|
||||||
import type { VNodeChild, App, PropType, Plugin } from 'vue';
|
import type { App, PropType, Plugin, ExtractPropTypes } from 'vue';
|
||||||
import { computed, defineComponent, ref } from 'vue';
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
import omit from 'omit.js';
|
import omit from 'omit.js';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import type { SelectProps as RcSelectProps } from '../vc-select';
|
import type { SelectProps as RcSelectProps } from '../vc-select';
|
||||||
import RcSelect, { Option, OptGroup, BaseProps } from '../vc-select';
|
import RcSelect, { Option, OptGroup, selectBaseProps } from '../vc-select';
|
||||||
import type { OptionProps as OptionPropsType } from '../vc-select/Option';
|
import type { OptionProps as OptionPropsType } from '../vc-select/Option';
|
||||||
import getIcons from './utils/iconUtil';
|
import getIcons from './utils/iconUtil';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
|
@ -20,36 +20,26 @@ export type OptionType = typeof Option;
|
||||||
export interface LabeledValue {
|
export interface LabeledValue {
|
||||||
key?: string;
|
key?: string;
|
||||||
value: RawValue;
|
value: RawValue;
|
||||||
label: VNodeChild;
|
label: any;
|
||||||
}
|
}
|
||||||
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
|
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
|
||||||
|
|
||||||
export interface InternalSelectProps<VT> extends Omit<RcSelectProps<VT>, 'mode'> {
|
interface InternalSelectProps<VT> extends Omit<RcSelectProps<VT>, 'mode'> {
|
||||||
suffixIcon?: VNodeChild;
|
suffixIcon?: any;
|
||||||
itemIcon?: VNodeChild;
|
itemIcon?: any;
|
||||||
size?: SizeType;
|
size?: SizeType;
|
||||||
mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
|
mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
|
||||||
bordered?: boolean;
|
bordered?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectPropsTypes<VT>
|
interface SelectPropsTypes<VT>
|
||||||
extends Omit<
|
extends Omit<InternalSelectProps<VT>, 'inputIcon' | 'mode' | 'getInputElement' | 'backfill'> {
|
||||||
InternalSelectProps<VT>,
|
|
||||||
'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
|
|
||||||
> {
|
|
||||||
mode?: 'multiple' | 'tags';
|
mode?: 'multiple' | 'tags';
|
||||||
}
|
}
|
||||||
export type SelectTypes = SelectPropsTypes<SelectValue>;
|
export type SelectProps = Partial<ExtractPropTypes<SelectPropsTypes<SelectValue>>>;
|
||||||
export const SelectProps = () => ({
|
export const selectProps = () => ({
|
||||||
...(omit(BaseProps(), [
|
...(omit(selectBaseProps(), ['inputIcon', 'mode', 'getInputElement', 'backfill']) as Omit<
|
||||||
'inputIcon',
|
SelectPropsTypes<SelectValue>,
|
||||||
'mode',
|
|
||||||
'getInputElement',
|
|
||||||
'backfill',
|
|
||||||
'class',
|
|
||||||
'style',
|
|
||||||
]) as Omit<
|
|
||||||
ReturnType<typeof BaseProps>,
|
|
||||||
'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
|
'inputIcon' | 'mode' | 'getInputElement' | 'backfill' | 'class' | 'style'
|
||||||
>),
|
>),
|
||||||
value: {
|
value: {
|
||||||
|
@ -58,9 +48,9 @@ export const SelectProps = () => ({
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
type: [Array, Object, String, Number] as PropType<SelectValue>,
|
type: [Array, Object, String, Number] as PropType<SelectValue>,
|
||||||
},
|
},
|
||||||
notFoundContent: PropTypes.VNodeChild,
|
notFoundContent: PropTypes.any,
|
||||||
suffixIcon: PropTypes.VNodeChild,
|
suffixIcon: PropTypes.any,
|
||||||
itemIcon: PropTypes.VNodeChild,
|
itemIcon: PropTypes.any,
|
||||||
size: PropTypes.oneOf(tuple('small', 'middle', 'large', 'default')),
|
size: PropTypes.oneOf(tuple('small', 'middle', 'large', 'default')),
|
||||||
mode: PropTypes.oneOf(tuple('multiple', 'tags', 'SECRET_COMBOBOX_MODE_DO_NOT_USE')),
|
mode: PropTypes.oneOf(tuple('multiple', 'tags', 'SECRET_COMBOBOX_MODE_DO_NOT_USE')),
|
||||||
bordered: PropTypes.looseBool.def(true),
|
bordered: PropTypes.looseBool.def(true),
|
||||||
|
@ -73,7 +63,7 @@ const Select = defineComponent({
|
||||||
Option,
|
Option,
|
||||||
OptGroup,
|
OptGroup,
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: SelectProps(),
|
props: selectProps(),
|
||||||
SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE',
|
SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE',
|
||||||
emits: ['change', 'update:value'],
|
emits: ['change', 'update:value'],
|
||||||
slots: [
|
slots: [
|
||||||
|
@ -146,7 +136,7 @@ const Select = defineComponent({
|
||||||
const isMultiple = mode.value === 'multiple' || mode.value === 'tags';
|
const isMultiple = mode.value === 'multiple' || mode.value === 'tags';
|
||||||
|
|
||||||
// ===================== Empty =====================
|
// ===================== Empty =====================
|
||||||
let mergedNotFound: VNodeChild;
|
let mergedNotFound: any;
|
||||||
if (notFoundContent !== undefined) {
|
if (notFoundContent !== undefined) {
|
||||||
mergedNotFound = notFoundContent;
|
mergedNotFound = notFoundContent;
|
||||||
} else if (slots.notFoundContent) {
|
} else if (slots.notFoundContent) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import classNames from '../_util/classNames';
|
||||||
import pickAttrs from '../_util/pickAttrs';
|
import pickAttrs from '../_util/pickAttrs';
|
||||||
import { isValidElement } from '../_util/props-util';
|
import { isValidElement } from '../_util/props-util';
|
||||||
import createRef from '../_util/createRef';
|
import createRef from '../_util/createRef';
|
||||||
import type { PropType, VNodeChild } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { computed, defineComponent, nextTick, reactive, watch } from 'vue';
|
import { computed, defineComponent, nextTick, reactive, watch } from 'vue';
|
||||||
import List from '../vc-virtual-list/List';
|
import List from '../vc-virtual-list/List';
|
||||||
import type {
|
import type {
|
||||||
|
@ -22,18 +22,18 @@ export interface RefOptionListProps {
|
||||||
onKeyup: (e?: KeyboardEvent) => void;
|
onKeyup: (e?: KeyboardEvent) => void;
|
||||||
scrollTo?: (index: number) => void;
|
scrollTo?: (index: number) => void;
|
||||||
}
|
}
|
||||||
export interface OptionListProps {
|
export interface OptionListProps<OptionType extends object> {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
id: string;
|
id: string;
|
||||||
options: SelectOptionsType;
|
options: OptionType[];
|
||||||
flattenOptions: FlattenOptionsType<SelectOptionsType>;
|
flattenOptions: FlattenOptionsType<OptionType>;
|
||||||
height: number;
|
height: number;
|
||||||
itemHeight: number;
|
itemHeight: number;
|
||||||
values: Set<RawValueType>;
|
values: Set<RawValueType>;
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
defaultActiveFirstOption?: boolean;
|
defaultActiveFirstOption?: boolean;
|
||||||
notFoundContent?: VNodeChild;
|
notFoundContent?: any;
|
||||||
menuItemSelectedIcon?: RenderNode;
|
menuItemSelectedIcon?: RenderNode;
|
||||||
childrenAsData: boolean;
|
childrenAsData: boolean;
|
||||||
searchValue: string;
|
searchValue: string;
|
||||||
|
@ -80,7 +80,7 @@ const OptionListProps = {
|
||||||
* Using virtual list of option display.
|
* Using virtual list of option display.
|
||||||
* Will fallback to dom if use customize render.
|
* Will fallback to dom if use customize render.
|
||||||
*/
|
*/
|
||||||
const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, { state?: any }>({
|
||||||
name: 'OptionList',
|
name: 'OptionList',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
slots: ['option'],
|
slots: ['option'],
|
||||||
|
@ -290,7 +290,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
virtual,
|
virtual,
|
||||||
onScroll,
|
onScroll,
|
||||||
onMouseenter,
|
onMouseenter,
|
||||||
} = this.$props as OptionListProps;
|
} = this.$props;
|
||||||
const renderOption = $slots.option;
|
const renderOption = $slots.option;
|
||||||
const { activeIndex } = this.state;
|
const { activeIndex } = this.state;
|
||||||
// ========================== Render ==========================
|
// ========================== Render ==========================
|
||||||
|
|
|
@ -47,9 +47,8 @@ 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';
|
||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import omit from 'lodash-es/omit';
|
|
||||||
|
|
||||||
const RefSelect = generateSelector<SelectOptionsType>({
|
const RefSelect = generateSelector<SelectOptionsType[number]>({
|
||||||
prefixCls: 'rc-select',
|
prefixCls: 'rc-select',
|
||||||
components: {
|
components: {
|
||||||
optionList: SelectOptionList as any,
|
optionList: SelectOptionList as any,
|
||||||
|
@ -64,10 +63,17 @@ const RefSelect = generateSelector<SelectOptionsType>({
|
||||||
fillOptionsWithMissingValue,
|
fillOptionsWithMissingValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ExportedSelectProps<ValueType extends DefaultValueType = DefaultValueType> =
|
export type ExportedSelectProps<T extends DefaultValueType = DefaultValueType> = SelectProps<
|
||||||
SelectProps<SelectOptionsType, ValueType>;
|
SelectOptionsType[number],
|
||||||
|
T
|
||||||
|
>;
|
||||||
|
|
||||||
const Select = defineComponent<Omit<ExportedSelectProps, 'children'>>({
|
const Select = defineComponent({
|
||||||
|
name: 'Select',
|
||||||
|
inheritAttrs: false,
|
||||||
|
Option: Option,
|
||||||
|
OptGroup: OptGroup,
|
||||||
|
props: RefSelect.props,
|
||||||
setup(props, { attrs, expose, slots }) {
|
setup(props, { attrs, expose, slots }) {
|
||||||
const selectRef = ref(null);
|
const selectRef = ref(null);
|
||||||
expose({
|
expose({
|
||||||
|
@ -91,8 +97,4 @@ const Select = defineComponent<Omit<ExportedSelectProps, 'children'>>({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Select.inheritAttrs = false;
|
|
||||||
Select.props = omit(RefSelect.props, ['children']);
|
|
||||||
Select.Option = Option;
|
|
||||||
Select.OptGroup = OptGroup;
|
|
||||||
export default Select;
|
export default Select;
|
||||||
|
|
|
@ -57,7 +57,7 @@ export interface SelectorProps {
|
||||||
onSearch: (searchText: string, fromTyping: boolean, isCompositing: boolean) => boolean;
|
onSearch: (searchText: string, fromTyping: boolean, isCompositing: boolean) => boolean;
|
||||||
onSearchSubmit: (searchText: string) => void;
|
onSearchSubmit: (searchText: string) => void;
|
||||||
onSelect: (value: RawValueType, option: { selected: boolean }) => void;
|
onSelect: (value: RawValueType, option: { selected: boolean }) => void;
|
||||||
onInputKeyDown?: EventHandlerNonNull;
|
onInputKeyDown?: (e: KeyboardEvent) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private get real dom for trigger align.
|
* @private get real dom for trigger align.
|
||||||
|
|
|
@ -11,14 +11,13 @@ import KeyCode from '../_util/KeyCode';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import Selector from './Selector';
|
import Selector from './Selector';
|
||||||
import SelectTrigger from './SelectTrigger';
|
import SelectTrigger from './SelectTrigger';
|
||||||
import type { RenderNode, Mode, RenderDOMFunc, OnActiveValue } from './interface';
|
import type { Mode, RenderDOMFunc, OnActiveValue } from './interface';
|
||||||
import type {
|
import type {
|
||||||
GetLabeledValue,
|
GetLabeledValue,
|
||||||
FilterOptions,
|
FilterOptions,
|
||||||
FilterFunc,
|
FilterFunc,
|
||||||
DefaultValueType,
|
DefaultValueType,
|
||||||
RawValueType,
|
RawValueType,
|
||||||
LabelValueType,
|
|
||||||
Key,
|
Key,
|
||||||
DisplayLabelValueType,
|
DisplayLabelValueType,
|
||||||
FlattenOptionsType,
|
FlattenOptionsType,
|
||||||
|
@ -26,7 +25,6 @@ import type {
|
||||||
OnClear,
|
OnClear,
|
||||||
SelectSource,
|
SelectSource,
|
||||||
CustomTagProps,
|
CustomTagProps,
|
||||||
DropdownRender,
|
|
||||||
} from './interface/generator';
|
} from './interface/generator';
|
||||||
import { INTERNAL_PROPS_MARK } from './interface/generator';
|
import { INTERNAL_PROPS_MARK } from './interface/generator';
|
||||||
import type { OptionListProps } from './OptionList';
|
import type { OptionListProps } from './OptionList';
|
||||||
|
@ -38,7 +36,7 @@ import { getSeparatedContent } from './utils/valueUtil';
|
||||||
import useSelectTriggerControl from './hooks/useSelectTriggerControl';
|
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, VNode, VNodeChild } from 'vue';
|
import type { CSSProperties, DefineComponent, PropType, VNode, VNodeChild } from 'vue';
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
@ -50,8 +48,7 @@ import {
|
||||||
watchEffect,
|
watchEffect,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import createRef from '../_util/createRef';
|
import createRef from '../_util/createRef';
|
||||||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
|
||||||
import warning from '../_util/warning';
|
import warning from '../_util/warning';
|
||||||
import isMobile from '../vc-util/isMobile';
|
import isMobile from '../vc-util/isMobile';
|
||||||
|
|
||||||
|
@ -68,248 +65,177 @@ const DEFAULT_OMIT_PROPS = [
|
||||||
'tabindex',
|
'tabindex',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const BaseProps = () => ({
|
export function selectBaseProps<OptionType, ValueType>() {
|
||||||
prefixCls: PropTypes.string,
|
return {
|
||||||
id: PropTypes.string,
|
prefixCls: String,
|
||||||
class: PropTypes.string,
|
id: String,
|
||||||
style: PropTypes.any,
|
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
options: PropTypes.array,
|
options: { type: Array as PropType<OptionType[]> },
|
||||||
mode: PropTypes.string,
|
mode: { type: String as PropType<Mode> },
|
||||||
|
|
||||||
// Value
|
// Value
|
||||||
value: PropTypes.any,
|
value: { type: [String, Number, Object, Array] as PropType<ValueType> },
|
||||||
defaultValue: PropTypes.any,
|
defaultValue: { type: [String, Number, Object, Array] as PropType<ValueType> },
|
||||||
labelInValue: PropTypes.looseBool,
|
labelInValue: { type: Boolean, default: undefined },
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
inputValue: PropTypes.string,
|
inputValue: String,
|
||||||
searchValue: PropTypes.string,
|
searchValue: String,
|
||||||
optionFilterProp: PropTypes.string,
|
optionFilterProp: String,
|
||||||
/**
|
/**
|
||||||
* In Select, `false` means do nothing.
|
* In Select, `false` means do nothing.
|
||||||
* In TreeSelect, `false` will highlight match item.
|
* In TreeSelect, `false` will highlight match item.
|
||||||
* It's by design.
|
* It's by design.
|
||||||
*/
|
*/
|
||||||
filterOption: PropTypes.any,
|
filterOption: {
|
||||||
filterSort: PropTypes.func,
|
type: [Boolean, Function] as PropType<boolean | FilterFunc<OptionType>>,
|
||||||
showSearch: PropTypes.looseBool,
|
default: undefined,
|
||||||
autoClearSearchValue: PropTypes.looseBool,
|
},
|
||||||
onSearch: PropTypes.func,
|
filterSort: {
|
||||||
onClear: PropTypes.func,
|
type: Function as PropType<(optionA: OptionType, optionB: OptionType) => number>,
|
||||||
|
},
|
||||||
|
showSearch: { type: Boolean, default: undefined },
|
||||||
|
autoClearSearchValue: { type: Boolean, default: undefined },
|
||||||
|
onSearch: { type: Function as PropType<(value: string) => void> },
|
||||||
|
onClear: { type: Function as PropType<OnClear> },
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
allowClear: PropTypes.looseBool,
|
allowClear: { type: Boolean, default: undefined },
|
||||||
clearIcon: PropTypes.VNodeChild,
|
clearIcon: PropTypes.any,
|
||||||
showArrow: PropTypes.looseBool,
|
showArrow: { type: Boolean, default: undefined },
|
||||||
inputIcon: PropTypes.VNodeChild,
|
inputIcon: PropTypes.VNodeChild,
|
||||||
removeIcon: PropTypes.VNodeChild,
|
removeIcon: PropTypes.VNodeChild,
|
||||||
menuItemSelectedIcon: PropTypes.VNodeChild,
|
menuItemSelectedIcon: PropTypes.VNodeChild,
|
||||||
|
|
||||||
// Dropdown
|
// Dropdown
|
||||||
open: PropTypes.looseBool,
|
open: { type: Boolean, default: undefined },
|
||||||
defaultOpen: PropTypes.looseBool,
|
defaultOpen: { type: Boolean, default: undefined },
|
||||||
listHeight: PropTypes.number,
|
listHeight: Number,
|
||||||
listItemHeight: PropTypes.number,
|
listItemHeight: Number,
|
||||||
dropdownStyle: PropTypes.object,
|
dropdownStyle: { type: Function as PropType<CSSProperties> },
|
||||||
dropdownClassName: PropTypes.string,
|
dropdownClassName: String,
|
||||||
dropdownMatchSelectWidth: withUndefined(PropTypes.oneOfType([Boolean, Number])),
|
dropdownMatchSelectWidth: {
|
||||||
virtual: PropTypes.looseBool,
|
type: [Boolean, Number] as PropType<boolean | number>,
|
||||||
dropdownRender: PropTypes.func,
|
default: undefined,
|
||||||
|
},
|
||||||
|
virtual: { type: Boolean, default: undefined },
|
||||||
|
dropdownRender: { type: Function as PropType<(menu: VNode) => any> },
|
||||||
dropdownAlign: PropTypes.any,
|
dropdownAlign: PropTypes.any,
|
||||||
animation: PropTypes.string,
|
animation: String,
|
||||||
transitionName: PropTypes.string,
|
transitionName: String,
|
||||||
getPopupContainer: PropTypes.func,
|
getPopupContainer: { type: Function as PropType<RenderDOMFunc> },
|
||||||
direction: PropTypes.string,
|
direction: String,
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
disabled: PropTypes.looseBool,
|
disabled: { type: Boolean, default: undefined },
|
||||||
loading: PropTypes.looseBool,
|
loading: { type: Boolean, default: undefined },
|
||||||
autofocus: PropTypes.looseBool,
|
autofocus: { type: Boolean, default: undefined },
|
||||||
defaultActiveFirstOption: PropTypes.looseBool,
|
defaultActiveFirstOption: { type: Boolean, default: undefined },
|
||||||
notFoundContent: PropTypes.VNodeChild,
|
notFoundContent: PropTypes.any,
|
||||||
placeholder: PropTypes.VNodeChild,
|
placeholder: PropTypes.any,
|
||||||
backfill: PropTypes.looseBool,
|
backfill: { type: Boolean, default: undefined },
|
||||||
getInputElement: PropTypes.func,
|
/** @private Internal usage. Do not use in your production. */
|
||||||
optionLabelProp: PropTypes.string,
|
getInputElement: { type: Function as PropType<() => any> },
|
||||||
maxTagTextLength: PropTypes.number,
|
optionLabelProp: String,
|
||||||
maxTagCount: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
maxTagTextLength: Number,
|
||||||
|
maxTagCount: { type: [String, Number] as PropType<number | 'responsive'> },
|
||||||
maxTagPlaceholder: PropTypes.any,
|
maxTagPlaceholder: PropTypes.any,
|
||||||
tokenSeparators: PropTypes.array,
|
tokenSeparators: { type: Array as PropType<string[]> },
|
||||||
tagRender: PropTypes.func,
|
tagRender: { type: Function as PropType<(props: CustomTagProps) => any> },
|
||||||
showAction: PropTypes.array,
|
showAction: { type: Array as PropType<('focus' | 'click')[]> },
|
||||||
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
tabindex: { type: [Number, String] },
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
onKeyup: PropTypes.func,
|
onKeyup: { type: Function as PropType<(e: KeyboardEvent) => void> },
|
||||||
onKeydown: PropTypes.func,
|
onKeydown: { type: Function as PropType<(e: KeyboardEvent) => void> },
|
||||||
onPopupScroll: PropTypes.func,
|
onPopupScroll: { type: Function as PropType<(e: UIEvent) => void> },
|
||||||
onDropdownVisibleChange: PropTypes.func,
|
onDropdownVisibleChange: { type: Function as PropType<(open: boolean) => void> },
|
||||||
onSelect: PropTypes.func,
|
onSelect: {
|
||||||
onDeselect: PropTypes.func,
|
type: Function as PropType<(value: SingleType<ValueType>, option: OptionType) => void>,
|
||||||
onInputKeyDown: PropTypes.func,
|
},
|
||||||
onClick: PropTypes.func,
|
onDeselect: {
|
||||||
onChange: PropTypes.func,
|
type: Function as PropType<(value: SingleType<ValueType>, option: OptionType) => void>,
|
||||||
onBlur: PropTypes.func,
|
},
|
||||||
onFocus: PropTypes.func,
|
onInputKeyDown: { type: Function as PropType<(e: KeyboardEvent) => void> },
|
||||||
onMousedown: PropTypes.func,
|
onClick: { type: Function as PropType<(e: MouseEvent) => void> },
|
||||||
onMouseenter: PropTypes.func,
|
onChange: {
|
||||||
onMouseleave: PropTypes.func,
|
type: Function as PropType<(value: ValueType, option: OptionType | OptionType[]) => void>,
|
||||||
|
},
|
||||||
|
onBlur: { type: Function as PropType<(e: FocusEvent) => void> },
|
||||||
|
onFocus: { type: Function as PropType<(e: FocusEvent) => void> },
|
||||||
|
onMousedown: { type: Function as PropType<(e: MouseEvent) => void> },
|
||||||
|
onMouseenter: { type: Function as PropType<(e: MouseEvent) => void> },
|
||||||
|
onMouseleave: { type: Function as PropType<(e: MouseEvent) => void> },
|
||||||
|
|
||||||
// Motion
|
// Motion
|
||||||
choiceTransitionName: PropTypes.string,
|
choiceTransitionName: String,
|
||||||
|
|
||||||
// Internal props
|
// Internal props
|
||||||
/**
|
/**
|
||||||
* Only used in current version for internal event process.
|
* Only used in current version for internal event process.
|
||||||
* Do not use in production environment.
|
* Do not use in production environment.
|
||||||
*/
|
*/
|
||||||
internalProps: PropTypes.object,
|
internalProps: {
|
||||||
children: PropTypes.array,
|
type: Object as PropType<{
|
||||||
});
|
|
||||||
|
|
||||||
export interface SelectProps<OptionsType extends object[], ValueType> {
|
|
||||||
prefixCls?: string;
|
|
||||||
id?: string;
|
|
||||||
class?: string;
|
|
||||||
style?: CSSProperties;
|
|
||||||
|
|
||||||
// Options
|
|
||||||
options?: OptionsType;
|
|
||||||
children?: any[];
|
|
||||||
mode?: Mode;
|
|
||||||
|
|
||||||
// Value
|
|
||||||
value?: ValueType;
|
|
||||||
defaultValue?: ValueType;
|
|
||||||
labelInValue?: boolean;
|
|
||||||
|
|
||||||
// Search
|
|
||||||
inputValue?: string;
|
|
||||||
searchValue?: string;
|
|
||||||
optionFilterProp?: string;
|
|
||||||
/**
|
|
||||||
* In Select, `false` means do nothing.
|
|
||||||
* In TreeSelect, `false` will highlight match item.
|
|
||||||
* It's by design.
|
|
||||||
*/
|
|
||||||
filterOption?: boolean | FilterFunc<OptionsType[number]>;
|
|
||||||
filterSort?: (optionA: OptionsType[number], optionB: OptionsType[number]) => number;
|
|
||||||
showSearch?: boolean;
|
|
||||||
autoClearSearchValue?: boolean;
|
|
||||||
onSearch?: (value: string) => void;
|
|
||||||
onClear?: OnClear;
|
|
||||||
|
|
||||||
// Icons
|
|
||||||
allowClear?: boolean;
|
|
||||||
clearIcon?: VNodeChild;
|
|
||||||
showArrow?: boolean;
|
|
||||||
inputIcon?: RenderNode;
|
|
||||||
removeIcon?: VNodeChild;
|
|
||||||
menuItemSelectedIcon?: RenderNode;
|
|
||||||
|
|
||||||
// Dropdown
|
|
||||||
open?: boolean;
|
|
||||||
defaultOpen?: boolean;
|
|
||||||
listHeight?: number;
|
|
||||||
listItemHeight?: number;
|
|
||||||
dropdownStyle?: CSSProperties;
|
|
||||||
dropdownClassName?: string;
|
|
||||||
dropdownMatchSelectWidth?: boolean | number;
|
|
||||||
virtual?: boolean;
|
|
||||||
dropdownRender?: DropdownRender;
|
|
||||||
dropdownAlign?: any;
|
|
||||||
animation?: string;
|
|
||||||
transitionName?: string;
|
|
||||||
getPopupContainer?: RenderDOMFunc;
|
|
||||||
direction?: string;
|
|
||||||
|
|
||||||
// Others
|
|
||||||
disabled?: boolean;
|
|
||||||
loading?: boolean;
|
|
||||||
autofocus?: boolean;
|
|
||||||
defaultActiveFirstOption?: boolean;
|
|
||||||
notFoundContent?: VNodeChild;
|
|
||||||
placeholder?: VNodeChild;
|
|
||||||
backfill?: boolean;
|
|
||||||
getInputElement?: () => VNodeChild | JSX.Element;
|
|
||||||
optionLabelProp?: string;
|
|
||||||
maxTagTextLength?: number;
|
|
||||||
maxTagCount?: number | 'responsive';
|
|
||||||
maxTagPlaceholder?: VNodeChild | ((omittedValues: LabelValueType[]) => VNodeChild);
|
|
||||||
tokenSeparators?: string[];
|
|
||||||
tagRender?: (props: CustomTagProps) => VNodeChild;
|
|
||||||
showAction?: ('focus' | 'click')[];
|
|
||||||
tabindex?: number | string;
|
|
||||||
|
|
||||||
// Events
|
|
||||||
onKeyup?: EventHandlerNonNull;
|
|
||||||
onKeydown?: EventHandlerNonNull;
|
|
||||||
onPopupScroll?: EventHandlerNonNull;
|
|
||||||
onDropdownVisibleChange?: (open: boolean) => void;
|
|
||||||
onSelect?: (value: SingleType<ValueType>, option: OptionsType[number]) => void;
|
|
||||||
onDeselect?: (value: SingleType<ValueType>, option: OptionsType[number]) => void;
|
|
||||||
onInputKeyDown?: EventHandlerNonNull;
|
|
||||||
onClick?: EventHandlerNonNull;
|
|
||||||
onChange?: (value: ValueType, option: OptionsType[number] | OptionsType) => void;
|
|
||||||
onBlur?: EventHandlerNonNull;
|
|
||||||
onFocus?: EventHandlerNonNull;
|
|
||||||
onMousedown?: EventHandlerNonNull;
|
|
||||||
onMouseenter?: EventHandlerNonNull;
|
|
||||||
onMouseleave?: EventHandlerNonNull;
|
|
||||||
|
|
||||||
// Motion
|
|
||||||
choiceTransitionName?: string;
|
|
||||||
|
|
||||||
// Internal props
|
|
||||||
/**
|
|
||||||
* Only used in current version for internal event process.
|
|
||||||
* Do not use in production environment.
|
|
||||||
*/
|
|
||||||
internalProps?: {
|
|
||||||
mark?: string;
|
mark?: string;
|
||||||
onClear?: OnClear;
|
onClear?: OnClear;
|
||||||
skipTriggerChange?: boolean;
|
skipTriggerChange?: boolean;
|
||||||
skipTriggerSelect?: boolean;
|
skipTriggerSelect?: boolean;
|
||||||
onRawSelect?: (value: RawValueType, option: OptionsType[number], source: SelectSource) => void;
|
onRawSelect?: (value: RawValueType, option: OptionType, source: SelectSource) => void;
|
||||||
onRawDeselect?: (
|
onRawDeselect?: (value: RawValueType, option: OptionType, source: SelectSource) => void;
|
||||||
value: RawValueType,
|
}>,
|
||||||
option: OptionsType[number],
|
default: undefined as {
|
||||||
source: SelectSource,
|
mark?: string;
|
||||||
) => void;
|
onClear?: OnClear;
|
||||||
|
skipTriggerChange?: boolean;
|
||||||
|
skipTriggerSelect?: boolean;
|
||||||
|
onRawSelect?: (value: RawValueType, option: OptionType, source: SelectSource) => void;
|
||||||
|
onRawDeselect?: (value: RawValueType, option: OptionType, source: SelectSource) => void;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: Array,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenerateConfig<OptionsType extends object[]> {
|
class Helper<T1, T2> {
|
||||||
|
SelectBaseProps = selectBaseProps<T1, T2>();
|
||||||
|
}
|
||||||
|
type FuncReturnType<T1, T2> = Helper<T1, T2>['SelectBaseProps'];
|
||||||
|
|
||||||
|
export type SelectProps<T1, T2> = FuncReturnType<T1, T2>;
|
||||||
|
|
||||||
|
export interface GenerateConfig<OptionType extends object> {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
components: {
|
components: {
|
||||||
optionList: DefineComponent<Omit<OptionListProps, 'options'> & { options?: OptionsType }>;
|
optionList: DefineComponent<
|
||||||
|
Omit<OptionListProps<OptionType>, 'options'> & { options?: OptionType[] }
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
/** Convert jsx tree into `OptionsType` */
|
/** Convert jsx tree into `OptionType[]` */
|
||||||
convertChildrenToData: (children: VNodeChild | JSX.Element) => OptionsType;
|
convertChildrenToData: (children: VNodeChild | JSX.Element) => OptionType[];
|
||||||
/** Flatten nest options into raw option list */
|
/** Flatten nest options into raw option list */
|
||||||
flattenOptions: (options: OptionsType, props: any) => FlattenOptionsType<OptionsType>;
|
flattenOptions: (options: OptionType[], props: any) => FlattenOptionsType<OptionType>;
|
||||||
/** Convert single raw value into { label, value } format. Will be called by each value */
|
/** Convert single raw value into { label, value } format. Will be called by each value */
|
||||||
getLabeledValue: GetLabeledValue<FlattenOptionsType<OptionsType>>;
|
getLabeledValue: GetLabeledValue<FlattenOptionsType<OptionType>>;
|
||||||
filterOptions: FilterOptions<OptionsType>;
|
filterOptions: FilterOptions<OptionType[]>;
|
||||||
findValueOption: // Need still support legacy ts api
|
findValueOption: // Need still support legacy ts api
|
||||||
| ((values: RawValueType[], options: FlattenOptionsType<OptionsType>) => OptionsType)
|
| ((values: RawValueType[], options: FlattenOptionsType<OptionType>) => OptionType[])
|
||||||
// New API add prevValueOptions support
|
// New API add prevValueOptions support
|
||||||
| ((
|
| ((
|
||||||
values: RawValueType[],
|
values: RawValueType[],
|
||||||
options: FlattenOptionsType<OptionsType>,
|
options: FlattenOptionsType<OptionType>,
|
||||||
info?: { prevValueOptions?: OptionsType[] },
|
info?: { prevValueOptions?: OptionType[][] },
|
||||||
) => OptionsType);
|
) => OptionType[]);
|
||||||
/** Check if a value is disabled */
|
/** Check if a value is disabled */
|
||||||
isValueDisabled: (value: RawValueType, options: FlattenOptionsType<OptionsType>) => boolean;
|
isValueDisabled: (value: RawValueType, options: FlattenOptionsType<OptionType>) => boolean;
|
||||||
warningProps?: (props: any) => void;
|
warningProps?: (props: any) => void;
|
||||||
fillOptionsWithMissingValue?: (
|
fillOptionsWithMissingValue?: (
|
||||||
options: OptionsType,
|
options: OptionType[],
|
||||||
value: DefaultValueType,
|
value: DefaultValueType,
|
||||||
optionLabelProp: string,
|
optionLabelProp: string,
|
||||||
labelInValue: boolean,
|
labelInValue: boolean,
|
||||||
) => OptionsType;
|
) => OptionType[];
|
||||||
omitDOMProps?: (props: object) => object;
|
omitDOMProps?: (props: object) => object;
|
||||||
}
|
}
|
||||||
type ValueType = DefaultValueType;
|
type ValueType = DefaultValueType;
|
||||||
|
@ -318,13 +244,13 @@ type ValueType = DefaultValueType;
|
||||||
* Do not use it in your prod env since we may refactor this.
|
* Do not use it in your prod env since we may refactor this.
|
||||||
*/
|
*/
|
||||||
export default function generateSelector<
|
export default function generateSelector<
|
||||||
OptionsType extends {
|
OptionType extends {
|
||||||
value?: RawValueType;
|
value?: RawValueType;
|
||||||
label?: VNodeChild;
|
label?: any;
|
||||||
key?: Key;
|
key?: Key;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}[],
|
},
|
||||||
>(config: GenerateConfig<OptionsType>) {
|
>(config: GenerateConfig<OptionType>) {
|
||||||
const {
|
const {
|
||||||
prefixCls: defaultPrefixCls,
|
prefixCls: defaultPrefixCls,
|
||||||
components: { optionList: OptionList },
|
components: { optionList: OptionList },
|
||||||
|
@ -338,10 +264,12 @@ export default function generateSelector<
|
||||||
fillOptionsWithMissingValue,
|
fillOptionsWithMissingValue,
|
||||||
omitDOMProps,
|
omitDOMProps,
|
||||||
} = config as any;
|
} = config as any;
|
||||||
const Select = defineComponent<SelectProps<OptionsType, ValueType>>({
|
const Select = defineComponent({
|
||||||
name: 'Select',
|
name: 'Select',
|
||||||
slots: ['option'],
|
slots: ['option'],
|
||||||
setup(props: SelectProps<OptionsType, ValueType>) {
|
inheritAttrs: false,
|
||||||
|
props: selectBaseProps<OptionType, DefaultValueType>(),
|
||||||
|
setup(props) {
|
||||||
const useInternalProps = computed(
|
const useInternalProps = computed(
|
||||||
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
() => props.internalProps && props.internalProps.mark === INTERNAL_PROPS_MARK,
|
||||||
);
|
);
|
||||||
|
@ -440,7 +368,7 @@ export default function generateSelector<
|
||||||
return mergedSearchValue;
|
return mergedSearchValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
const mergedOptions = computed((): OptionsType => {
|
const mergedOptions = computed((): OptionType[] => {
|
||||||
let newOptions = props.options;
|
let newOptions = props.options;
|
||||||
if (newOptions === undefined) {
|
if (newOptions === undefined) {
|
||||||
newOptions = convertChildrenToData(props.children);
|
newOptions = convertChildrenToData(props.children);
|
||||||
|
@ -459,7 +387,7 @@ export default function generateSelector<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newOptions || ([] as OptionsType);
|
return newOptions || ([] as OptionType[]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const mergedFlattenOptions = computed(() => flattenOptions(mergedOptions.value, props));
|
const mergedFlattenOptions = computed(() => flattenOptions(mergedOptions.value, props));
|
||||||
|
@ -467,12 +395,12 @@ export default function generateSelector<
|
||||||
const getValueOption = useCacheOptions(mergedFlattenOptions);
|
const getValueOption = useCacheOptions(mergedFlattenOptions);
|
||||||
|
|
||||||
// Display options for OptionList
|
// Display options for OptionList
|
||||||
const displayOptions = computed<OptionsType>(() => {
|
const displayOptions = computed<OptionType[]>(() => {
|
||||||
if (!mergedSearchValue.value || !mergedShowSearch.value) {
|
if (!mergedSearchValue.value || !mergedShowSearch.value) {
|
||||||
return [...mergedOptions.value] as OptionsType;
|
return [...mergedOptions.value] as OptionType[];
|
||||||
}
|
}
|
||||||
const { optionFilterProp = 'value', mode, filterOption } = props;
|
const { optionFilterProp = 'value', mode, filterOption } = props;
|
||||||
const filteredOptions: OptionsType = filterOptions(
|
const filteredOptions: OptionType[] = filterOptions(
|
||||||
mergedSearchValue.value,
|
mergedSearchValue.value,
|
||||||
mergedOptions.value,
|
mergedOptions.value,
|
||||||
{
|
{
|
||||||
|
@ -489,10 +417,10 @@ export default function generateSelector<
|
||||||
value: mergedSearchValue.value,
|
value: mergedSearchValue.value,
|
||||||
label: mergedSearchValue.value,
|
label: mergedSearchValue.value,
|
||||||
key: '__RC_SELECT_TAG_PLACEHOLDER__',
|
key: '__RC_SELECT_TAG_PLACEHOLDER__',
|
||||||
});
|
} as OptionType);
|
||||||
}
|
}
|
||||||
if (props.filterSort && Array.isArray(filteredOptions)) {
|
if (props.filterSort && Array.isArray(filteredOptions)) {
|
||||||
return ([...filteredOptions] as OptionsType).sort(props.filterSort);
|
return ([...filteredOptions] as OptionType[]).sort(props.filterSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredOptions;
|
return filteredOptions;
|
||||||
|
@ -591,9 +519,9 @@ export default function generateSelector<
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newRawValuesOptions = getValueOption(newRawValues);
|
const newRawValuesOptions = getValueOption(newRawValues);
|
||||||
const outValues = toOuterValues<FlattenOptionsType<OptionsType>>(Array.from(newRawValues), {
|
const outValues = toOuterValues<FlattenOptionsType<OptionType>>(Array.from(newRawValues), {
|
||||||
labelInValue: mergedLabelInValue.value,
|
labelInValue: mergedLabelInValue.value,
|
||||||
options: newRawValuesOptions,
|
options: newRawValuesOptions as any,
|
||||||
getLabeledValue,
|
getLabeledValue,
|
||||||
prevValueMap: mergedValueMap.value,
|
prevValueMap: mergedValueMap.value,
|
||||||
optionLabelProp: mergedOptionLabelProp.value,
|
optionLabelProp: mergedOptionLabelProp.value,
|
||||||
|
@ -872,7 +800,7 @@ export default function generateSelector<
|
||||||
};
|
};
|
||||||
|
|
||||||
// KeyUp
|
// KeyUp
|
||||||
const onInternalKeyUp = (event: Event) => {
|
const onInternalKeyUp = (event: KeyboardEvent) => {
|
||||||
if (mergedOpen.value && listRef.value) {
|
if (mergedOpen.value && listRef.value) {
|
||||||
listRef.value.onKeyup(event);
|
listRef.value.onKeyup(event);
|
||||||
}
|
}
|
||||||
|
@ -1098,7 +1026,6 @@ export default function generateSelector<
|
||||||
} = this as any;
|
} = this as any;
|
||||||
const {
|
const {
|
||||||
prefixCls = defaultPrefixCls,
|
prefixCls = defaultPrefixCls,
|
||||||
class: className,
|
|
||||||
id,
|
id,
|
||||||
|
|
||||||
open,
|
open,
|
||||||
|
@ -1172,7 +1099,7 @@ export default function generateSelector<
|
||||||
internalProps = {},
|
internalProps = {},
|
||||||
|
|
||||||
...restProps
|
...restProps
|
||||||
} = this.$props as SelectProps<OptionsType, ValueType>;
|
} = this.$props; //as SelectProps<OptionType[], ValueType>;
|
||||||
|
|
||||||
// ============================= Input ==============================
|
// ============================= Input ==============================
|
||||||
// Only works in `combobox`
|
// Only works in `combobox`
|
||||||
|
@ -1267,7 +1194,7 @@ export default function generateSelector<
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Render =============================
|
// ============================= Render =============================
|
||||||
const mergedClassName = classNames(prefixCls, className, {
|
const mergedClassName = classNames(prefixCls, this.$attrs.class, {
|
||||||
[`${prefixCls}-focused`]: mockFocused,
|
[`${prefixCls}-focused`]: mockFocused,
|
||||||
[`${prefixCls}-multiple`]: isMultiple,
|
[`${prefixCls}-multiple`]: isMultiple,
|
||||||
[`${prefixCls}-single`]: !isMultiple,
|
[`${prefixCls}-single`]: !isMultiple,
|
||||||
|
@ -1282,6 +1209,7 @@ export default function generateSelector<
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
{...this.$attrs}
|
||||||
class={mergedClassName}
|
class={mergedClassName}
|
||||||
{...domProps}
|
{...domProps}
|
||||||
ref="containerRef"
|
ref="containerRef"
|
||||||
|
@ -1355,6 +1283,5 @@ export default function generateSelector<
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Select.props = initDefaultProps(BaseProps(), {});
|
|
||||||
return Select;
|
return Select;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import type { Ref, VNodeChild } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import type { RawValueType, FlattenOptionsType, Key } from '../interface/generator';
|
import type { RawValueType, FlattenOptionsType, Key } from '../interface/generator';
|
||||||
|
|
||||||
export default function useCacheOptions<
|
export default function useCacheOptions<
|
||||||
OptionsType extends {
|
OptionType extends {
|
||||||
value?: RawValueType;
|
value?: RawValueType;
|
||||||
label?: VNodeChild;
|
label?: any;
|
||||||
key?: Key;
|
key?: Key;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}[],
|
},
|
||||||
>(options: Ref) {
|
>(options: Ref) {
|
||||||
const optionMap = computed(() => {
|
const optionMap = computed(() => {
|
||||||
const map: Map<RawValueType, FlattenOptionsType<OptionsType>[number]> = new Map();
|
const map: Map<RawValueType, FlattenOptionsType<OptionType>[number]> = new Map();
|
||||||
options.value.forEach((item: any) => {
|
options.value.forEach((item: any) => {
|
||||||
const {
|
const {
|
||||||
data: { value },
|
data: { value },
|
||||||
|
@ -21,7 +21,7 @@ export default function useCacheOptions<
|
||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getValueOption = (vals: RawValueType[]): FlattenOptionsType<OptionsType> =>
|
const getValueOption = (vals: RawValueType[]) =>
|
||||||
vals.map(value => optionMap.value.get(value)).filter(Boolean);
|
vals.map(value => optionMap.value.get(value)).filter(Boolean);
|
||||||
|
|
||||||
return getValueOption;
|
return getValueOption;
|
||||||
|
|
|
@ -2,9 +2,9 @@ import type { ExportedSelectProps } from './Select';
|
||||||
import Select from './Select';
|
import Select from './Select';
|
||||||
import Option from './Option';
|
import Option from './Option';
|
||||||
import OptGroup from './OptGroup';
|
import OptGroup from './OptGroup';
|
||||||
import { BaseProps } from './generate';
|
import { selectBaseProps } from './generate';
|
||||||
|
|
||||||
export type SelectProps<T = any> = ExportedSelectProps<T>;
|
export type SelectProps<T = any> = ExportedSelectProps<T>;
|
||||||
export { Option, OptGroup, BaseProps };
|
export { Option, OptGroup, selectBaseProps };
|
||||||
|
|
||||||
export default Select;
|
export default Select;
|
||||||
|
|
|
@ -56,9 +56,11 @@ export type FilterOptions<OptionsType extends object[]> = (
|
||||||
|
|
||||||
export type FilterFunc<OptionType> = (inputValue: string, option?: OptionType) => boolean;
|
export type FilterFunc<OptionType> = (inputValue: string, option?: OptionType) => boolean;
|
||||||
|
|
||||||
export type FlattenOptionsType<OptionsType extends object[] = object[]> = {
|
export type FlattenOptionsType<OptionType = object> = {
|
||||||
key: Key;
|
key: Key;
|
||||||
data: OptionsType[number];
|
data: OptionType;
|
||||||
|
label?: any;
|
||||||
|
value?: RawValueType;
|
||||||
/** Used for customize data */
|
/** Used for customize data */
|
||||||
[name: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
[name: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
}[];
|
}[];
|
||||||
|
|
|
@ -1,6 +1,100 @@
|
||||||
import { GenerateConfig } from '../vc-select/generate';
|
import generateSelector, { GenerateConfig } from '../vc-select/generate';
|
||||||
|
import TreeNode from './TreeNode';
|
||||||
|
import type {
|
||||||
|
Key,
|
||||||
|
DefaultValueType,
|
||||||
|
DataNode,
|
||||||
|
LabelValueType,
|
||||||
|
SimpleModeConfig,
|
||||||
|
RawValueType,
|
||||||
|
ChangeEventExtra,
|
||||||
|
LegacyDataNode,
|
||||||
|
SelectSource,
|
||||||
|
FlattenDataNode,
|
||||||
|
FieldNames,
|
||||||
|
} from './interface';
|
||||||
|
import {
|
||||||
|
flattenOptions,
|
||||||
|
filterOptions,
|
||||||
|
isValueDisabled,
|
||||||
|
findValueOption,
|
||||||
|
addValue,
|
||||||
|
removeValue,
|
||||||
|
getRawValueLabeled,
|
||||||
|
toArray,
|
||||||
|
fillFieldNames,
|
||||||
|
} from './utils/valueUtil';
|
||||||
|
import warningProps from './utils/warningPropsUtil';
|
||||||
|
import { SelectContext } from './Context';
|
||||||
|
import useTreeData from './hooks/useTreeData';
|
||||||
|
import useKeyValueMap from './hooks/useKeyValueMap';
|
||||||
|
import useKeyValueMapping from './hooks/useKeyValueMapping';
|
||||||
|
import type { CheckedStrategy } from './utils/strategyUtil';
|
||||||
|
import { formatStrategyKeys, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './utils/strategyUtil';
|
||||||
|
import { fillAdditionalInfo } from './utils/legacyUtil';
|
||||||
|
import useSelectValues from './hooks/useSelectValues';
|
||||||
|
import { treeSelectProps, TreeSelectProps } from './props';
|
||||||
|
import { getLabeledValue } from '../vc-select/utils/valueUtil';
|
||||||
|
import omit from '../_util/omit';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
const OMIT_PROPS: (keyof TreeSelectProps)[] = [
|
||||||
|
'expandedKeys' as any,
|
||||||
|
'treeData',
|
||||||
|
'treeCheckable',
|
||||||
|
'showCheckedStrategy',
|
||||||
|
'searchPlaceholder',
|
||||||
|
'treeLine',
|
||||||
|
'treeIcon',
|
||||||
|
'showTreeIcon',
|
||||||
|
'switcherIcon',
|
||||||
|
'treeNodeFilterProp',
|
||||||
|
'filterTreeNode',
|
||||||
|
'dropdownPopupAlign',
|
||||||
|
'treeDefaultExpandAll',
|
||||||
|
'treeCheckStrictly',
|
||||||
|
'treeExpandedKeys',
|
||||||
|
'treeLoadedKeys',
|
||||||
|
'treeMotion',
|
||||||
|
'onTreeExpand',
|
||||||
|
'onTreeLoad',
|
||||||
|
'labelRender',
|
||||||
|
'loadData',
|
||||||
|
'treeDataSimpleMode',
|
||||||
|
'treeNodeLabelProp',
|
||||||
|
'treeDefaultExpandedKeys',
|
||||||
|
];
|
||||||
|
|
||||||
export default function generate(config: {
|
export default function generate(config: {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
optionList: GenerateConfig<any>['components']['optionList'];
|
optionList: GenerateConfig<DataNode>['components']['optionList'];
|
||||||
}) {}
|
}) {
|
||||||
|
const { prefixCls, optionList } = config;
|
||||||
|
|
||||||
|
const RefSelect = generateSelector<DataNode>({
|
||||||
|
prefixCls,
|
||||||
|
components: {
|
||||||
|
optionList,
|
||||||
|
},
|
||||||
|
// Not use generate since we will handle ourself
|
||||||
|
convertChildrenToData: () => null,
|
||||||
|
flattenOptions,
|
||||||
|
// Handle `optionLabelProp` in TreeSelect component
|
||||||
|
getLabeledValue: getLabeledValue as any,
|
||||||
|
filterOptions,
|
||||||
|
isValueDisabled,
|
||||||
|
findValueOption,
|
||||||
|
omitDOMProps: (props: TreeSelectProps<any>) => omit(props, OMIT_PROPS),
|
||||||
|
});
|
||||||
|
|
||||||
|
return defineComponent({
|
||||||
|
props: treeSelectProps(),
|
||||||
|
slots: [],
|
||||||
|
name: 'TreeSelect',
|
||||||
|
setup(props) {
|
||||||
|
return () => {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
import type { ExtractPropTypes, PropType } from 'vue';
|
import type { ExtractPropTypes, PropType } from 'vue';
|
||||||
import type { DataNode } from '../tree';
|
import type { DataNode } from '../tree';
|
||||||
|
import { selectBaseProps } from '../vc-select';
|
||||||
|
import type { FilterFunc } from '../vc-select/interface/generator';
|
||||||
|
import omit from '../_util/omit';
|
||||||
|
import type { Key } from '../_util/type';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import type { FlattenDataNode, RawValueType } from './interface';
|
import type {
|
||||||
|
ChangeEventExtra,
|
||||||
|
DefaultValueType,
|
||||||
|
FieldNames,
|
||||||
|
FlattenDataNode,
|
||||||
|
LabelValueType,
|
||||||
|
LegacyDataNode,
|
||||||
|
RawValueType,
|
||||||
|
SimpleModeConfig,
|
||||||
|
} from './interface';
|
||||||
|
import type { CheckedStrategy } from './utils/strategyUtil';
|
||||||
|
|
||||||
export function optionListProps<OptionsType>() {
|
export function optionListProps<OptionsType>() {
|
||||||
return {
|
return {
|
||||||
|
@ -33,6 +47,94 @@ export function optionListProps<OptionsType>() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OptionListProps = Partial<
|
export function treeSelectProps<ValueType = DefaultValueType>() {
|
||||||
Omit<ExtractPropTypes<ReturnType<typeof optionListProps>>, 'options'> & { options: DataNode[] }
|
const selectProps = omit(selectBaseProps<DataNode, ValueType>(), [
|
||||||
|
'onChange',
|
||||||
|
'mode',
|
||||||
|
'menuItemSelectedIcon',
|
||||||
|
'dropdownAlign',
|
||||||
|
'backfill',
|
||||||
|
'getInputElement',
|
||||||
|
'optionLabelProp',
|
||||||
|
'tokenSeparators',
|
||||||
|
'filterOption',
|
||||||
|
]);
|
||||||
|
return {
|
||||||
|
...selectProps,
|
||||||
|
|
||||||
|
multiple: { type: Boolean, default: undefined },
|
||||||
|
showArrow: { type: Boolean, default: undefined },
|
||||||
|
showSearch: { type: Boolean, default: undefined },
|
||||||
|
open: { type: Boolean, default: undefined },
|
||||||
|
defaultOpen: { type: Boolean, default: undefined },
|
||||||
|
value: { type: [String, Number, Object, Array] as PropType<ValueType> },
|
||||||
|
defaultValue: { type: [String, Number, Object, Array] as PropType<ValueType> },
|
||||||
|
disabled: { type: Boolean, default: undefined },
|
||||||
|
|
||||||
|
placeholder: PropTypes.any,
|
||||||
|
/** @deprecated Use `searchValue` instead */
|
||||||
|
inputValue: String,
|
||||||
|
searchValue: String,
|
||||||
|
autoClearSearchValue: { type: Boolean, default: undefined },
|
||||||
|
|
||||||
|
maxTagPlaceholder: { type: Function as PropType<(omittedValues: LabelValueType[]) => any> },
|
||||||
|
|
||||||
|
fieldNames: { type: Object as PropType<FieldNames> },
|
||||||
|
loadData: { type: Function as PropType<(dataNode: LegacyDataNode) => Promise<unknown>> },
|
||||||
|
treeNodeFilterProp: String,
|
||||||
|
treeNodeLabelProp: String,
|
||||||
|
treeDataSimpleMode: {
|
||||||
|
type: [Boolean, Object] as PropType<boolean | SimpleModeConfig>,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
treeExpandedKeys: { type: [String, Number] as PropType<Key> },
|
||||||
|
treeDefaultExpandedKeys: { type: [String, Number] as PropType<Key> },
|
||||||
|
treeLoadedKeys: { type: [String, Number] as PropType<Key> },
|
||||||
|
treeCheckable: { type: Boolean, default: undefined },
|
||||||
|
treeCheckStrictly: { type: Boolean, default: undefined },
|
||||||
|
showCheckedStrategy: { type: String as PropType<CheckedStrategy> },
|
||||||
|
treeDefaultExpandAll: { type: Boolean, default: undefined },
|
||||||
|
treeData: { type: Array as PropType<DataNode[]> },
|
||||||
|
treeLine: { type: Boolean, default: undefined },
|
||||||
|
treeIcon: PropTypes.any,
|
||||||
|
showTreeIcon: { type: Boolean, default: undefined },
|
||||||
|
switcherIcon: PropTypes.any,
|
||||||
|
treeMotion: PropTypes.any,
|
||||||
|
children: PropTypes.any,
|
||||||
|
|
||||||
|
filterTreeNode: {
|
||||||
|
type: [Boolean, Function] as PropType<boolean | FilterFunc<LegacyDataNode>>,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
dropdownPopupAlign: PropTypes.any,
|
||||||
|
|
||||||
|
// Event
|
||||||
|
onSearch: { type: Function as PropType<(value: string) => void> },
|
||||||
|
onChange: {
|
||||||
|
type: Function as PropType<
|
||||||
|
(value: ValueType, labelList: any[], extra: ChangeEventExtra) => void
|
||||||
|
>,
|
||||||
|
},
|
||||||
|
onTreeExpand: { type: Function as PropType<(expandedKeys: Key[]) => void> },
|
||||||
|
onTreeLoad: { type: Function as PropType<(loadedKeys: Key[]) => void> },
|
||||||
|
onDropdownVisibleChange: { type: Function as PropType<(open: boolean) => void> },
|
||||||
|
|
||||||
|
// Legacy
|
||||||
|
/** `searchPlaceholder` has been removed since search box has been merged into input box */
|
||||||
|
searchPlaceholder: PropTypes.any,
|
||||||
|
|
||||||
|
/** @private This is not standard API since we only used in `rc-cascader`. Do not use in your production */
|
||||||
|
labelRender: { type: Function as PropType<(entity: FlattenDataNode) => any> },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Helper<T> {
|
||||||
|
ReturnOptionListProps = optionListProps<T>();
|
||||||
|
ReturnTreeSelectProps = treeSelectProps<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OptionListProps = Partial<ExtractPropTypes<Helper<DataNode>['ReturnOptionListProps']>>;
|
||||||
|
|
||||||
|
export type TreeSelectProps<T = DefaultValueType> = Partial<
|
||||||
|
ExtractPropTypes<Helper<T>['ReturnTreeSelectProps']>
|
||||||
>;
|
>;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
"ant-design-vue/es/*": ["components/*"]
|
"ant-design-vue/es/*": ["components/*"]
|
||||||
},
|
},
|
||||||
"strictNullChecks": false,
|
"strictNullChecks": false,
|
||||||
"strict": true,
|
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
|
Loading…
Reference in New Issue