Files
element-plus/packages/components/select-v2/src/defaults.ts
lostElk 2b1ab441e3 feat(components): [select/select-v2] add tag-tooltip config object prop (#23556)
* feat(components): [select] add collapseTagsTooltipAppendTo & test

Add collapseTagsTooltipAppendTo prop to control where the collapse-tags tooltip is appended. Wire it
to the tag tooltip with fallback to appendTo. Add unit test to verify prop is passed correctly.

* docs(docs): add collapseTagsTooltipAppendTo doc

* refactor(components): [select]rename collapseTagsTooltipAppendTo prop

Rename collapseTagsTooltipAppendTo to tooltipAppendTo
Simplify the prop name by removing redundant context
Behavior remains unchanged

* docs(components): [select] add version tag for tooltipAppendTo prop

* Update packages/components/select/__tests__/select.test.ts

Co-authored-by: rzzf <cszhjh@gmail.com>

* feat(components): [select] add tagTooltip config object

Add TagTooltip to support appendTo, placement, fallbackPlacements, effect, popperClass, popperStyle,
teleported, popperOptions, showAfter, and offsetWire all tagTooltip properties to the collapse-tags
tooltip with fallback to existing select propsProvides more granular control over tooltip behavior
while maintaining backward compatibility

* docs(components): [select] add tag-tooltip config object doc

* docs(components): [select] add default value for fallback-placements

* docs(components): [select]  update tag-tooltip default value to {}

* docs(components): [select]remove string type from TagTooltipProps effect

* docs(components): [select] add fallback mechanism tip for tag-tooltip

* feat(components): [select] extend TagTooltipProps

Add transition, hideAfter, and autoClose properties to TagTooltipProps

Update popperStyle type to accept both string and CSSProperties

* docs(components): [select] enhance tag-tooltip documentation

Add transition, hide-after, and auto-close properties to TagTooltip API table

Clarify fallback mechanism with priority order explanation

Add custom container positioning tip for append-to usage

* docs(components): [select] refine tag-tooltip priority description

Co-authored-by: keeplearning66 <1256734885@qq.com>

* docs(components): [select] refine effect prop type in tag-tooltip

Co-authored-by: keeplearning66 <1256734885@qq.com>

* chore: format

* docs: apply rabbit comment

* feat(components): [select-v2] add TagTooltipProps interface

Add TagTooltipProps interface with popper configuration options

* feat(components): [select-v2] implement tagTooltip prop

* test(components): [select-v2] add tag-tooltip prop test case

Add test case to verify tagTooltip prop functionality with appendTo option

* docs(components): [select-v2] add tag-tooltip API documentation

Add tag-tooltip configuration object to Select V2 API table

Add comprehensive tag-tooltip properties section with fallback mechanism explanation and custom
container positioning tip

* docs(components): [select-v2] add version tag to tag-tooltip prop

* fix(components): [select-v2] Optional chain tagTooltip access

* fix(components): [select] optional chain tagTooltip access

* feat(components): [select-v2] Fix tooltip teleport timing

* docs(components): [select-v] add version tag for tag-tooltip

Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>

* docs(components): [select] add version tag for tag-tooltip

Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>

---------

Co-authored-by: rzzf <cszhjh@gmail.com>
Co-authored-by: keeplearning66 <1256734885@qq.com>
Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>
2026-02-14 00:00:16 +01:00

398 lines
10 KiB
TypeScript

import { placements } from '@popperjs/core'
import {
useAriaProps,
useEmptyValuesProps,
useSizeProp,
} from '@element-plus/hooks'
import {
buildProps,
definePropType,
iconPropType,
isBoolean,
isNumber,
} from '@element-plus/utils'
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
import { useTooltipContentProps } from '@element-plus/components/tooltip'
import { ArrowDown, CircleClose } from '@element-plus/icons-vue'
import { tagProps } from '../../tag'
import { defaultProps } from './useProps'
import type SelectV2 from './select.vue'
import type { Option, OptionType } from './select.types'
import type { Props } from './useProps'
import type { EmitFn } from '@element-plus/utils/vue/typescript'
import type {
CSSProperties,
ExtractPropTypes,
ExtractPublicPropTypes,
} from 'vue'
import type {
Options,
Placement,
PopperEffect,
} from '@element-plus/components/popper'
/**
* @description Tag tooltip configuration interface
*/
export interface TagTooltipProps {
appendTo?: string | HTMLElement
placement?: Placement
fallbackPlacements?: Placement[]
effect?: PopperEffect
popperClass?: string
popperStyle?: string | CSSProperties
transition?: string
teleported?: boolean
popperOptions?: Partial<Options>
showAfter?: number
hideAfter?: number
autoClose?: number
offset?: number
}
export const selectV2Props = buildProps({
/**
* @description whether creating new items is allowed. To use this, `filterable` must be true
*/
allowCreate: Boolean,
/**
* @description autocomplete of select input
*/
autocomplete: {
type: definePropType<'none' | 'both' | 'list' | 'inline'>(String),
default: 'none',
},
/**
* @description for non-filterable Select, this prop decides if the option menu pops up when the input is focused
*/
automaticDropdown: Boolean,
/**
* @description whether select can be cleared
*/
clearable: Boolean,
/**
* @description custom clear icon
*/
clearIcon: {
type: iconPropType,
default: CircleClose,
},
/**
* @description tooltip theme, built-in theme: `dark` / `light`
*/
effect: {
type: definePropType<PopperEffect>(String),
default: 'light',
},
/**
* @description whether to collapse tags to a text when multiple selecting
*/
collapseTags: Boolean,
/**
* @description whether show all selected tags when mouse hover text of collapse-tags. To use this, `collapse-tags` must be true
*/
collapseTagsTooltip: Boolean,
/**
* @description configuration object for the collapse-tags tooltip. To use this, `collapse-tags` and `collapse-tags-tooltip` must be true
*/
tagTooltip: {
type: definePropType<TagTooltipProps>(Object),
default: () => ({}),
},
/**
* @description The max tags number to be shown. To use this, `collapse-tags` must be true
*/
maxCollapseTags: {
type: Number,
default: 1,
},
/**
* @description
*/
defaultFirstOption: Boolean,
/**
* @description is disabled
*/
disabled: {
type: Boolean,
default: undefined,
},
/**
* @description
*/
estimatedOptionHeight: {
type: Number,
default: undefined,
},
/**
* @description whether Select is filterable
*/
filterable: Boolean,
/**
* @description custom filter method, the first parameter is the current input value. To use this, `filterable` must be true
*/
filterMethod: {
type: definePropType<(query: string) => void>(Function),
},
/**
* @description The height of the dropdown panel, 34px for each item
*/
height: {
type: Number,
default: 274, // same as select dropdown menu
},
/**
* @description The height of the dropdown item
*/
itemHeight: {
type: Number,
default: 34,
},
/**
* @description native input id
*/
id: String,
/**
* @description whether Select is loading data from server
*/
loading: Boolean,
/**
* @description displayed text while loading data from server, default is 'Loading'
*/
loadingText: String,
/**
* @description biding value
*/
modelValue: {
type: definePropType<
any[] | string | number | boolean | Record<string, any> | any
>([Array, String, Number, Boolean, Object]),
default: undefined,
},
/**
* @description is multiple
*/
multiple: Boolean,
/**
* @description maximum number of options user can select when multiple is true. No limit when set to 0
*/
multipleLimit: {
type: Number,
default: 0,
},
/**
* @description the name attribute of select input
*/
name: String,
/**
* @description displayed text when there is no options, you can also use slot empty, the default is 'No Data'
*/
noDataText: String,
/**
* @description displayed text when no data matches the filtering query, you can also use slot `empty`, default is 'No matching data'
*/
noMatchText: String,
/**
* @description function that gets called when the input value changes. Its parameter is the current input value. To use this, `filterable` must be true
*/
remoteMethod: {
type: definePropType<(query: string) => void>(Function),
},
/**
* @description whether reserve the keyword after select filtered option.
*/
reserveKeyword: {
type: Boolean,
default: true,
},
/**
* @description data of the options, the key of `value` and `label` can be customize by `props`
*/
options: {
type: definePropType<OptionType[]>(Array),
required: true,
},
/**
* @description placeholder, the default is 'Please select'
*/
placeholder: {
type: String,
},
/**
* @description whether select dropdown is teleported, if `true` it will be teleported to where `append-to` sets
*/
teleported: useTooltipContentProps.teleported,
/**
* @description when select dropdown is inactive and `persistent` is `false`, select dropdown will be destroyed
*/
persistent: {
type: Boolean,
default: true,
},
/**
* @description custom class name for Select's dropdown
*/
popperClass: useTooltipContentProps.popperClass,
/**
* @description custom style for Select's dropdown
*/
popperStyle: useTooltipContentProps.popperStyle,
/**
* @description [popper.js](https://popper.js.org/docs/v2/) parameters
*/
popperOptions: {
type: definePropType<Partial<Options>>(Object),
default: () => ({}) as Partial<Options>,
},
/**
* @description whether search data from server
*/
remote: Boolean,
/**
* @description debounce delay during remote search, in milliseconds
*/
debounce: {
type: Number,
default: 300,
},
/**
* @description size of component
*/
size: useSizeProp,
/**
* @description configuration options, see the following table
*/
props: {
type: definePropType<Props>(Object),
default: () => defaultProps,
},
/**
* @description unique identity key name for value, required when value is an object
*/
valueKey: {
type: String,
default: 'value',
},
/**
* @description Controls whether the scrollbar is always displayed
*/
scrollbarAlwaysOn: Boolean,
/**
* @description whether to trigger form validation
*/
validateEvent: {
type: Boolean,
default: true,
},
/**
* @description offset of the dropdown
*/
offset: {
type: Number,
default: 12,
},
/**
* @description in remote search method show suffix icon
*/
remoteShowSuffix: Boolean,
/**
* @description Determines whether the arrow is displayed
*/
showArrow: {
type: Boolean,
default: true,
},
/**
* @description position of dropdown
*/
placement: {
type: definePropType<Placement>(String),
values: placements,
default: 'bottom-start',
},
/**
* @description list of possible positions for dropdown
*/
fallbackPlacements: {
type: definePropType<Placement[]>(Array),
default: ['bottom-start', 'top-start', 'right', 'left'],
},
/**
* @description tag type
*/
tagType: { ...tagProps.type, default: 'info' },
/**
* @description tag effect
*/
tagEffect: { ...tagProps.effect, default: 'light' },
/**
* @description tabindex for input
*/
tabindex: {
type: [String, Number],
default: 0,
},
/**
* @description which element the select dropdown appends to
*/
appendTo: useTooltipContentProps.appendTo,
/**
* @description if it is `true`, the width of the dropdown panel is the same as the input box.
* if it is `false`, the width is automatically calculated based on the value of `label`,
* or it can be set to a number to make it a fixed width
*/
fitInputWidth: {
type: [Boolean, Number],
default: true,
validator(val) {
return isBoolean(val) || isNumber(val)
},
},
suffixIcon: {
type: iconPropType,
default: ArrowDown,
},
...useEmptyValuesProps,
...useAriaProps(['ariaLabel']),
} as const)
export const optionV2Props = buildProps({
data: Array,
disabled: Boolean,
hovering: Boolean,
item: {
type: definePropType<Option>(Object),
required: true,
},
index: Number,
style: Object,
selected: Boolean,
created: Boolean,
} as const)
/* eslint-disable @typescript-eslint/no-unused-vars */
export const selectV2Emits = {
[UPDATE_MODEL_EVENT]: (val: SelectV2Props['modelValue']) => true,
[CHANGE_EVENT]: (val: SelectV2Props['modelValue']) => true,
'remove-tag': (val: unknown) => true,
'visible-change': (visible: boolean) => true,
focus: (evt: FocusEvent) => evt instanceof FocusEvent,
blur: (evt: FocusEvent) => evt instanceof FocusEvent,
clear: () => true,
}
export const optionV2Emits = {
hover: (index?: number) => isNumber(index),
select: (val: Option, index?: number) => true,
}
/* eslint-enable @typescript-eslint/no-unused-vars */
export type SelectV2Props = ExtractPropTypes<typeof selectV2Props>
export type SelectV2PropsPublic = ExtractPublicPropTypes<typeof selectV2Props>
export type OptionV2Props = ExtractPropTypes<typeof optionV2Props>
export type OptionV2PropsPublic = ExtractPublicPropTypes<typeof optionV2Props>
export type SelectV2EmitFn = EmitFn<typeof selectV2Emits>
export type OptionV2EmitFn = EmitFn<typeof optionV2Emits>
export type SelectV2Instance = InstanceType<typeof SelectV2> & unknown