mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-02 03:58:05 +08:00
feat: select support fieldNames
This commit is contained in:
parent
3ce5046dd5
commit
80f9b9e8ac
@ -13,9 +13,12 @@ import type {
|
|||||||
OptionData,
|
OptionData,
|
||||||
RenderNode,
|
RenderNode,
|
||||||
OnActiveValue,
|
OnActiveValue,
|
||||||
|
FieldNames,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
import type { RawValueType, FlattenOptionsType } from './interface/generator';
|
import type { RawValueType, FlattenOptionsType } from './interface/generator';
|
||||||
|
import { fillFieldNames } from './utils/valueUtil';
|
||||||
import useMemo from '../_util/hooks/useMemo';
|
import useMemo from '../_util/hooks/useMemo';
|
||||||
|
import { isPlatformMac } from './utils/platformUtil';
|
||||||
|
|
||||||
export interface RefOptionListProps {
|
export interface RefOptionListProps {
|
||||||
onKeydown: (e?: KeyboardEvent) => void;
|
onKeydown: (e?: KeyboardEvent) => void;
|
||||||
@ -24,10 +27,12 @@ export interface RefOptionListProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import type { EventHandler } from '../_util/EventInterface';
|
import type { EventHandler } from '../_util/EventInterface';
|
||||||
|
import omit from '../_util/omit';
|
||||||
export interface OptionListProps<OptionType extends object> {
|
export interface OptionListProps<OptionType extends object> {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
id: string;
|
id: string;
|
||||||
options: OptionType[];
|
options: OptionType[];
|
||||||
|
fieldNames?: FieldNames;
|
||||||
flattenOptions: FlattenOptionsType<OptionType>;
|
flattenOptions: FlattenOptionsType<OptionType>;
|
||||||
height: number;
|
height: number;
|
||||||
itemHeight: number;
|
itemHeight: number;
|
||||||
@ -40,6 +45,7 @@ export interface OptionListProps<OptionType extends object> {
|
|||||||
childrenAsData: boolean;
|
childrenAsData: boolean;
|
||||||
searchValue: string;
|
searchValue: string;
|
||||||
virtual: boolean;
|
virtual: boolean;
|
||||||
|
direction?: 'ltr' | 'rtl';
|
||||||
|
|
||||||
onSelect: (value: RawValueType, option: { selected: boolean }) => void;
|
onSelect: (value: RawValueType, option: { selected: boolean }) => void;
|
||||||
onToggleOpen: (open?: boolean) => void;
|
onToggleOpen: (open?: boolean) => void;
|
||||||
@ -55,6 +61,7 @@ const OptionListProps = {
|
|||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
options: PropTypes.array,
|
options: PropTypes.array,
|
||||||
|
fieldNames: PropTypes.object,
|
||||||
flattenOptions: PropTypes.array,
|
flattenOptions: PropTypes.array,
|
||||||
height: PropTypes.number,
|
height: PropTypes.number,
|
||||||
itemHeight: PropTypes.number,
|
itemHeight: PropTypes.number,
|
||||||
@ -67,6 +74,7 @@ const OptionListProps = {
|
|||||||
childrenAsData: PropTypes.looseBool,
|
childrenAsData: PropTypes.looseBool,
|
||||||
searchValue: PropTypes.string,
|
searchValue: PropTypes.string,
|
||||||
virtual: PropTypes.looseBool,
|
virtual: PropTypes.looseBool,
|
||||||
|
direction: PropTypes.string,
|
||||||
|
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
onToggleOpen: { type: Function as PropType<(open?: boolean) => void> },
|
onToggleOpen: { type: Function as PropType<(open?: boolean) => void> },
|
||||||
@ -153,15 +161,17 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
// Auto scroll to item position in single mode
|
// Auto scroll to item position in single mode
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.open,
|
[() => props.open, () => props.searchValue],
|
||||||
() => {
|
() => {
|
||||||
if (!props.multiple && props.open && props.values.size === 1) {
|
if (!props.multiple && props.open && props.values.size === 1) {
|
||||||
const value = Array.from(props.values)[0];
|
const value = Array.from(props.values)[0];
|
||||||
const index = memoFlattenOptions.value.findIndex(({ data }) => data.value === value);
|
const index = memoFlattenOptions.value.findIndex(({ data }) => data.value === value);
|
||||||
setActive(index);
|
if (index !== -1) {
|
||||||
nextTick(() => {
|
setActive(index);
|
||||||
scrollIntoView(index);
|
nextTick(() => {
|
||||||
});
|
scrollIntoView(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Force trigger scrollbar visible when open
|
// Force trigger scrollbar visible when open
|
||||||
if (props.open) {
|
if (props.open) {
|
||||||
@ -216,9 +226,11 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
setActive,
|
setActive,
|
||||||
onSelectValue,
|
onSelectValue,
|
||||||
onKeydown: (event: KeyboardEvent) => {
|
onKeydown: (event: KeyboardEvent) => {
|
||||||
const { which } = event;
|
const { which, ctrlKey } = event;
|
||||||
switch (which) {
|
switch (which) {
|
||||||
// >>> Arrow keys
|
// >>> Arrow keys & ctrl + n/p on Mac
|
||||||
|
case KeyCode.N:
|
||||||
|
case KeyCode.P:
|
||||||
case KeyCode.UP:
|
case KeyCode.UP:
|
||||||
case KeyCode.DOWN: {
|
case KeyCode.DOWN: {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
@ -226,6 +238,12 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
offset = -1;
|
offset = -1;
|
||||||
} else if (which === KeyCode.DOWN) {
|
} else if (which === KeyCode.DOWN) {
|
||||||
offset = 1;
|
offset = 1;
|
||||||
|
} else if (isPlatformMac() && ctrlKey) {
|
||||||
|
if (which === KeyCode.N) {
|
||||||
|
offset = 1;
|
||||||
|
} else if (which === KeyCode.P) {
|
||||||
|
offset = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset !== 0) {
|
if (offset !== 0) {
|
||||||
@ -290,11 +308,13 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
menuItemSelectedIcon,
|
menuItemSelectedIcon,
|
||||||
notFoundContent,
|
notFoundContent,
|
||||||
virtual,
|
virtual,
|
||||||
|
fieldNames,
|
||||||
onScroll,
|
onScroll,
|
||||||
onMouseenter,
|
onMouseenter,
|
||||||
} = this.$props;
|
} = this.$props;
|
||||||
const renderOption = $slots.option;
|
const renderOption = $slots.option;
|
||||||
const { activeIndex } = this.state;
|
const { activeIndex } = this.state;
|
||||||
|
const omitFieldNameList = Object.values(fillFieldNames(fieldNames));
|
||||||
// ========================== Render ==========================
|
// ========================== Render ==========================
|
||||||
if (memoFlattenOptions.length === 0) {
|
if (memoFlattenOptions.length === 0) {
|
||||||
return (
|
return (
|
||||||
@ -326,8 +346,8 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
onMouseenter={onMouseenter}
|
onMouseenter={onMouseenter}
|
||||||
children={({ group, groupOption, data }, itemIndex) => {
|
children={({ group, groupOption, data, label, value }, itemIndex) => {
|
||||||
const { label, key } = data;
|
const { key } = data;
|
||||||
// Group
|
// Group
|
||||||
if (group) {
|
if (group) {
|
||||||
return (
|
return (
|
||||||
@ -337,17 +357,8 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { disabled, title, children, style, class: cls, className, ...otherProps } = data;
|
||||||
disabled,
|
const passedProps = omit(otherProps, omitFieldNameList);
|
||||||
value,
|
|
||||||
title,
|
|
||||||
children,
|
|
||||||
style,
|
|
||||||
class: cls,
|
|
||||||
className,
|
|
||||||
...otherProps
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
// Option
|
// Option
|
||||||
const selected = values.has(value);
|
const selected = values.has(value);
|
||||||
|
|
||||||
@ -376,7 +387,7 @@ const OptionList = defineComponent<OptionListProps<SelectOptionsType[number]>, {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...otherProps}
|
{...passedProps}
|
||||||
aria-selected={selected}
|
aria-selected={selected}
|
||||||
class={optionClassName}
|
class={optionClassName}
|
||||||
title={optionTitle}
|
title={optionTitle}
|
||||||
|
@ -7,6 +7,7 @@ import type { CSSProperties, VNodeChild } from 'vue';
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import type { RenderDOMFunc } from './interface';
|
import type { RenderDOMFunc } from './interface';
|
||||||
import type { DropdownRender } from './interface/generator';
|
import type { DropdownRender } from './interface/generator';
|
||||||
|
import type { Placement } from './generate';
|
||||||
|
|
||||||
const getBuiltInPlacements = (dropdownMatchSelectWidth: number | boolean) => {
|
const getBuiltInPlacements = (dropdownMatchSelectWidth: number | boolean) => {
|
||||||
// Enable horizontal overflow auto-adjustment when a custom dropdown width is provided
|
// Enable horizontal overflow auto-adjustment when a custom dropdown width is provided
|
||||||
@ -55,6 +56,7 @@ export interface SelectTriggerProps {
|
|||||||
animation?: string;
|
animation?: string;
|
||||||
transitionName?: string;
|
transitionName?: string;
|
||||||
containerWidth: number;
|
containerWidth: number;
|
||||||
|
placement?: Placement;
|
||||||
dropdownStyle: CSSProperties;
|
dropdownStyle: CSSProperties;
|
||||||
dropdownClassName: string;
|
dropdownClassName: string;
|
||||||
direction: string;
|
direction: string;
|
||||||
@ -88,12 +90,13 @@ const SelectTrigger = defineComponent<SelectTriggerProps, { popupRef: any }>({
|
|||||||
popupElement,
|
popupElement,
|
||||||
dropdownClassName,
|
dropdownClassName,
|
||||||
dropdownStyle,
|
dropdownStyle,
|
||||||
|
direction = 'ltr',
|
||||||
|
placement,
|
||||||
dropdownMatchSelectWidth,
|
dropdownMatchSelectWidth,
|
||||||
containerWidth,
|
containerWidth,
|
||||||
dropdownRender,
|
dropdownRender,
|
||||||
animation,
|
animation,
|
||||||
transitionName,
|
transitionName,
|
||||||
direction,
|
|
||||||
getPopupContainer,
|
getPopupContainer,
|
||||||
getTriggerDOMNode,
|
getTriggerDOMNode,
|
||||||
} = props as SelectTriggerProps;
|
} = props as SelectTriggerProps;
|
||||||
@ -120,7 +123,7 @@ const SelectTrigger = defineComponent<SelectTriggerProps, { popupRef: any }>({
|
|||||||
{...props}
|
{...props}
|
||||||
showAction={[]}
|
showAction={[]}
|
||||||
hideAction={[]}
|
hideAction={[]}
|
||||||
popupPlacement={direction === 'rtl' ? 'bottomRight' : 'bottomLeft'}
|
popupPlacement={placement || (direction === 'rtl' ? 'bottomRight' : 'bottomLeft')}
|
||||||
builtinPlacements={builtInPlacements}
|
builtinPlacements={builtInPlacements}
|
||||||
prefixCls={dropdownPrefixCls}
|
prefixCls={dropdownPrefixCls}
|
||||||
popupTransitionName={mergedTransitionName}
|
popupTransitionName={mergedTransitionName}
|
||||||
@ -146,6 +149,7 @@ SelectTrigger.props = {
|
|||||||
disabled: PropTypes.looseBool,
|
disabled: PropTypes.looseBool,
|
||||||
dropdownClassName: PropTypes.string,
|
dropdownClassName: PropTypes.string,
|
||||||
dropdownStyle: PropTypes.object,
|
dropdownStyle: PropTypes.object,
|
||||||
|
placement: PropTypes.string,
|
||||||
empty: PropTypes.looseBool,
|
empty: PropTypes.looseBool,
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
popupClassName: PropTypes.string,
|
popupClassName: PropTypes.string,
|
||||||
|
@ -121,6 +121,11 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||||||
class={classNames(`${selectionPrefixCls.value}-item`, {
|
class={classNames(`${selectionPrefixCls.value}-item`, {
|
||||||
[`${selectionPrefixCls.value}-item-disabled`]: itemDisabled,
|
[`${selectionPrefixCls.value}-item-disabled`]: itemDisabled,
|
||||||
})}
|
})}
|
||||||
|
title={
|
||||||
|
typeof content === 'string' || typeof content === 'number'
|
||||||
|
? content.toString()
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span class={`${selectionPrefixCls.value}-item-content`}>{content}</span>
|
<span class={`${selectionPrefixCls.value}-item-content`}>{content}</span>
|
||||||
{closable && (
|
{closable && (
|
||||||
|
@ -11,7 +11,7 @@ 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 { Mode, RenderDOMFunc, OnActiveValue } from './interface';
|
import type { Mode, RenderDOMFunc, OnActiveValue, FieldNames } from './interface';
|
||||||
import type {
|
import type {
|
||||||
GetLabeledValue,
|
GetLabeledValue,
|
||||||
FilterOptions,
|
FilterOptions,
|
||||||
@ -67,6 +67,8 @@ const DEFAULT_OMIT_PROPS = [
|
|||||||
'tabindex',
|
'tabindex',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export type Placement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';
|
||||||
|
|
||||||
export function selectBaseProps<OptionType, ValueType>() {
|
export function selectBaseProps<OptionType, ValueType>() {
|
||||||
return {
|
return {
|
||||||
prefixCls: String,
|
prefixCls: String,
|
||||||
@ -87,6 +89,7 @@ export function selectBaseProps<OptionType, ValueType>() {
|
|||||||
},
|
},
|
||||||
labelInValue: { type: Boolean, default: undefined },
|
labelInValue: { type: Boolean, default: undefined },
|
||||||
|
|
||||||
|
fieldNames: { type: Object as PropType<FieldNames> },
|
||||||
// Search
|
// Search
|
||||||
inputValue: String,
|
inputValue: String,
|
||||||
searchValue: String,
|
searchValue: String,
|
||||||
@ -127,13 +130,16 @@ export function selectBaseProps<OptionType, ValueType>() {
|
|||||||
type: [Boolean, Number] as PropType<boolean | number>,
|
type: [Boolean, Number] as PropType<boolean | number>,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
|
placement: {
|
||||||
|
type: String as PropType<Placement>,
|
||||||
|
},
|
||||||
virtual: { type: Boolean, default: undefined },
|
virtual: { type: Boolean, default: undefined },
|
||||||
dropdownRender: { type: Function as PropType<(menu: VNode) => any> },
|
dropdownRender: { type: Function as PropType<(menu: VNode) => any> },
|
||||||
dropdownAlign: PropTypes.any,
|
dropdownAlign: PropTypes.any,
|
||||||
animation: String,
|
animation: String,
|
||||||
transitionName: String,
|
transitionName: String,
|
||||||
getPopupContainer: { type: Function as PropType<RenderDOMFunc> },
|
getPopupContainer: { type: Function as PropType<RenderDOMFunc> },
|
||||||
direction: String,
|
direction: { type: String as PropType<'ltr' | 'rtl'> },
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
disabled: { type: Boolean, default: undefined },
|
disabled: { type: Boolean, default: undefined },
|
||||||
@ -237,7 +243,7 @@ export interface GenerateConfig<OptionType extends object> {
|
|||||||
| ((
|
| ((
|
||||||
values: RawValueType[],
|
values: RawValueType[],
|
||||||
options: FlattenOptionsType<OptionType>,
|
options: FlattenOptionsType<OptionType>,
|
||||||
info?: { prevValueOptions?: OptionType[][] },
|
info?: { prevValueOptions?: OptionType[][]; props?: any },
|
||||||
) => OptionType[]);
|
) => OptionType[]);
|
||||||
/** Check if a value is disabled */
|
/** Check if a value is disabled */
|
||||||
isValueDisabled: (value: RawValueType, options: FlattenOptionsType<OptionType>) => boolean;
|
isValueDisabled: (value: RawValueType, options: FlattenOptionsType<OptionType>) => boolean;
|
||||||
@ -487,7 +493,7 @@ export default function generateSelector<
|
|||||||
|
|
||||||
const triggerSelect = (newValue: RawValueType, isSelect: boolean, source: SelectSource) => {
|
const triggerSelect = (newValue: RawValueType, isSelect: boolean, source: SelectSource) => {
|
||||||
const newValueOption = getValueOption([newValue]);
|
const newValueOption = getValueOption([newValue]);
|
||||||
const outOption = findValueOption([newValue], newValueOption)[0];
|
const outOption = findValueOption([newValue], newValueOption, { props })[0];
|
||||||
const { internalProps = {} } = props;
|
const { internalProps = {} } = props;
|
||||||
if (!internalProps.skipTriggerSelect) {
|
if (!internalProps.skipTriggerSelect) {
|
||||||
// Skip trigger `onSelect` or `onDeselect` if configured
|
// Skip trigger `onSelect` or `onDeselect` if configured
|
||||||
@ -549,6 +555,7 @@ export default function generateSelector<
|
|||||||
) {
|
) {
|
||||||
const outOptions = findValueOption(newRawValues, newRawValuesOptions, {
|
const outOptions = findValueOption(newRawValues, newRawValuesOptions, {
|
||||||
prevValueOptions: prevValueOptions.value,
|
prevValueOptions: prevValueOptions.value,
|
||||||
|
props,
|
||||||
});
|
});
|
||||||
|
|
||||||
// We will cache option in case it removed by ajax
|
// We will cache option in case it removed by ajax
|
||||||
@ -1008,6 +1015,7 @@ export default function generateSelector<
|
|||||||
backfill,
|
backfill,
|
||||||
getInputElement,
|
getInputElement,
|
||||||
getPopupContainer,
|
getPopupContainer,
|
||||||
|
placement,
|
||||||
|
|
||||||
// Dropdown
|
// Dropdown
|
||||||
listHeight = 200,
|
listHeight = 200,
|
||||||
@ -1022,6 +1030,7 @@ export default function generateSelector<
|
|||||||
dropdownAlign,
|
dropdownAlign,
|
||||||
showAction,
|
showAction,
|
||||||
direction,
|
direction,
|
||||||
|
fieldNames,
|
||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
tokenSeparators,
|
tokenSeparators,
|
||||||
@ -1062,6 +1071,7 @@ export default function generateSelector<
|
|||||||
open={mergedOpen.value}
|
open={mergedOpen.value}
|
||||||
childrenAsData={!options}
|
childrenAsData={!options}
|
||||||
options={displayOptions.value}
|
options={displayOptions.value}
|
||||||
|
fieldNames={fieldNames}
|
||||||
flattenOptions={displayFlattenOptions.value}
|
flattenOptions={displayFlattenOptions.value}
|
||||||
multiple={isMultiple.value}
|
multiple={isMultiple.value}
|
||||||
values={rawValues.value}
|
values={rawValues.value}
|
||||||
@ -1077,6 +1087,7 @@ export default function generateSelector<
|
|||||||
menuItemSelectedIcon={menuItemSelectedIcon}
|
menuItemSelectedIcon={menuItemSelectedIcon}
|
||||||
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
virtual={virtual !== false && dropdownMatchSelectWidth !== false}
|
||||||
onMouseenter={onPopupMouseEnter}
|
onMouseenter={onPopupMouseEnter}
|
||||||
|
direction={direction}
|
||||||
v-slots={slots}
|
v-slots={slots}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -1193,6 +1204,7 @@ export default function generateSelector<
|
|||||||
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
|
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
|
||||||
dropdownRender={dropdownRender as any}
|
dropdownRender={dropdownRender as any}
|
||||||
dropdownAlign={dropdownAlign}
|
dropdownAlign={dropdownAlign}
|
||||||
|
placement={placement}
|
||||||
getPopupContainer={getPopupContainer}
|
getPopupContainer={getPopupContainer}
|
||||||
empty={!mergedOptions.value.length}
|
empty={!mergedOptions.value.length}
|
||||||
getTriggerDOMNode={() => selectorDomRef.current}
|
getTriggerDOMNode={() => selectorDomRef.current}
|
||||||
|
@ -12,17 +12,15 @@ export default function useCacheOptions<
|
|||||||
>(options: Ref) {
|
>(options: Ref) {
|
||||||
const optionMap = computed(() => {
|
const optionMap = computed(() => {
|
||||||
const map: Map<RawValueType, FlattenOptionsType<OptionType>[number]> = new Map();
|
const map: Map<RawValueType, FlattenOptionsType<OptionType>[number]> = new Map();
|
||||||
options.value.forEach((item: any) => {
|
options.value.forEach(item => {
|
||||||
const {
|
const { value } = item;
|
||||||
data: { value },
|
|
||||||
} = item;
|
|
||||||
map.set(value, item);
|
map.set(value, item);
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getValueOption = (vals: RawValueType[]) =>
|
const getValueOption = (valueList: RawValueType[]) =>
|
||||||
vals.map(value => optionMap.value.get(value)).filter(Boolean);
|
valueList.map(value => optionMap.value.get(value)).filter(Boolean);
|
||||||
|
|
||||||
return getValueOption;
|
return getValueOption;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,13 @@ export type RenderNode = VNodeChild | ((props: any) => VNodeChild);
|
|||||||
export type Mode = 'multiple' | 'tags' | 'combobox';
|
export type Mode = 'multiple' | 'tags' | 'combobox';
|
||||||
|
|
||||||
// ======================== Option ========================
|
// ======================== Option ========================
|
||||||
|
|
||||||
|
export interface FieldNames {
|
||||||
|
value?: string;
|
||||||
|
label?: string;
|
||||||
|
options?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type OnActiveValue = (
|
export type OnActiveValue = (
|
||||||
active: RawValueType,
|
active: RawValueType,
|
||||||
index: number,
|
index: number,
|
||||||
@ -49,4 +56,6 @@ export interface FlattenOptionData {
|
|||||||
groupOption?: boolean;
|
groupOption?: boolean;
|
||||||
key: string | number;
|
key: string | number;
|
||||||
data: OptionData | OptionGroupData;
|
data: OptionData | OptionGroupData;
|
||||||
|
label?: any;
|
||||||
|
value?: RawValueType;
|
||||||
}
|
}
|
||||||
|
4
components/vc-select/utils/platformUtil.ts
Normal file
4
components/vc-select/utils/platformUtil.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
export function isPlatformMac(): boolean {
|
||||||
|
return /(mac\sos|macintosh)/i.test(navigator.appVersion);
|
||||||
|
}
|
@ -6,6 +6,7 @@ import type {
|
|||||||
OptionData,
|
OptionData,
|
||||||
OptionGroupData,
|
OptionGroupData,
|
||||||
FlattenOptionData,
|
FlattenOptionData,
|
||||||
|
FieldNames,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
import type {
|
import type {
|
||||||
LabelValueType,
|
LabelValueType,
|
||||||
@ -34,22 +35,45 @@ function getKey(data: OptionData | OptionGroupData, index: number) {
|
|||||||
return `rc-index-key-${index}`;
|
return `rc-index-key-${index}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fillFieldNames(fieldNames?: FieldNames) {
|
||||||
|
const { label, value, options } = fieldNames || {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: label || 'label',
|
||||||
|
value: value || 'value',
|
||||||
|
options: options || 'options',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flat options into flatten list.
|
* Flat options into flatten list.
|
||||||
* We use `optionOnly` here is aim to avoid user use nested option group.
|
* We use `optionOnly` here is aim to avoid user use nested option group.
|
||||||
* Here is simply set `key` to the index if not provided.
|
* Here is simply set `key` to the index if not provided.
|
||||||
*/
|
*/
|
||||||
export function flattenOptions(options: SelectOptionsType): FlattenOptionData[] {
|
export function flattenOptions(
|
||||||
|
options: SelectOptionsType,
|
||||||
|
{ fieldNames }: { fieldNames?: FieldNames } = {},
|
||||||
|
): FlattenOptionData[] {
|
||||||
const flattenList: FlattenOptionData[] = [];
|
const flattenList: FlattenOptionData[] = [];
|
||||||
|
|
||||||
|
const {
|
||||||
|
label: fieldLabel,
|
||||||
|
value: fieldValue,
|
||||||
|
options: fieldOptions,
|
||||||
|
} = fillFieldNames(fieldNames);
|
||||||
|
|
||||||
function dig(list: SelectOptionsType, isGroupOption: boolean) {
|
function dig(list: SelectOptionsType, isGroupOption: boolean) {
|
||||||
list.forEach(data => {
|
list.forEach(data => {
|
||||||
if (isGroupOption || !('options' in data)) {
|
const label = data[fieldLabel];
|
||||||
|
|
||||||
|
if (isGroupOption || !(fieldOptions in data)) {
|
||||||
// Option
|
// Option
|
||||||
flattenList.push({
|
flattenList.push({
|
||||||
key: getKey(data, flattenList.length),
|
key: getKey(data, flattenList.length),
|
||||||
groupOption: isGroupOption,
|
groupOption: isGroupOption,
|
||||||
data,
|
data,
|
||||||
|
label,
|
||||||
|
value: data[fieldValue],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Option Group
|
// Option Group
|
||||||
@ -57,9 +81,10 @@ export function flattenOptions(options: SelectOptionsType): FlattenOptionData[]
|
|||||||
key: getKey(data, flattenList.length),
|
key: getKey(data, flattenList.length),
|
||||||
group: true,
|
group: true,
|
||||||
data,
|
data,
|
||||||
|
label,
|
||||||
});
|
});
|
||||||
|
|
||||||
dig(data.options, true);
|
dig(data[fieldOptions], true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -96,11 +121,10 @@ export function findValueOption(
|
|||||||
): OptionData[] {
|
): OptionData[] {
|
||||||
const optionMap: Map<RawValueType, OptionData> = new Map();
|
const optionMap: Map<RawValueType, OptionData> = new Map();
|
||||||
|
|
||||||
options.forEach(flattenItem => {
|
options.forEach(({ data, group, value }) => {
|
||||||
if (!flattenItem.group) {
|
if (!group) {
|
||||||
const data = flattenItem.data as OptionData;
|
|
||||||
// Check if match
|
// Check if match
|
||||||
optionMap.set(data.value, data);
|
optionMap.set(value, data as OptionData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user