mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
chore: [select] remove @ts-nocheck directive (#19098)
* chore: [select] remove @ts-nocheck directive * Update packages/components/select/src/option.vue Co-authored-by: qiang <qw13131wang@gmail.com> * chore: delete useless type * Update packages/components/select/src/useSelect.ts Co-authored-by: qiang <qw13131wang@gmail.com> * fix: type error * fix: type error * chore: use buildProps * chore: add type * Update packages/components/select/src/useSelect.ts Co-authored-by: btea <2356281422@qq.com> * chore: fix type * chore: fix type * chore: fix types --------- Co-authored-by: warmthsea <2586244885@qq.com> Co-authored-by: sea <45450994+warmthsea@users.noreply.github.com> Co-authored-by: qiang <qw13131wang@gmail.com> Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { withInstall, withNoopInstall } from '@element-plus/utils'
|
||||
|
||||
import Select from './src/select.vue'
|
||||
import Option from './src/option.vue'
|
||||
import OptionGroup from './src/option-group.vue'
|
||||
|
||||
import type { SFCWithInstall } from '@element-plus/utils'
|
||||
|
||||
export const ElSelect: SFCWithInstall<typeof Select> & {
|
||||
@@ -18,3 +18,10 @@ export const ElOptionGroup: SFCWithInstall<typeof OptionGroup> =
|
||||
withNoopInstall(OptionGroup)
|
||||
|
||||
export * from './src/token'
|
||||
export * from './src/select'
|
||||
|
||||
export type {
|
||||
SelectContext,
|
||||
OptionPublicInstance as SelectOptionProxy,
|
||||
OptionBasic,
|
||||
} from './src/type'
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
getCurrentInstance,
|
||||
isVNode,
|
||||
onMounted,
|
||||
provide,
|
||||
reactive,
|
||||
@@ -22,10 +22,13 @@ import {
|
||||
toRefs,
|
||||
} from 'vue'
|
||||
import { useMutationObserver } from '@vueuse/core'
|
||||
import { ensureArray } from '@element-plus/utils'
|
||||
import { ensureArray, isArray } from '@element-plus/utils'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { selectGroupKey } from './token'
|
||||
|
||||
import type { Component, VNode, VNodeArrayChildren } from 'vue'
|
||||
import type { OptionInternalInstance, OptionPublicInstance } from './type'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElOptionGroup',
|
||||
componentName: 'ElOptionGroup',
|
||||
@@ -42,9 +45,9 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const ns = useNamespace('select')
|
||||
const groupRef = ref(null)
|
||||
const instance = getCurrentInstance()
|
||||
const children = ref([])
|
||||
const groupRef = ref<HTMLElement>()
|
||||
const instance = getCurrentInstance()!
|
||||
const children = ref<OptionPublicInstance[]>([])
|
||||
|
||||
provide(
|
||||
selectGroupKey,
|
||||
@@ -57,18 +60,22 @@ export default defineComponent({
|
||||
children.value.some((option) => option.visible === true)
|
||||
)
|
||||
|
||||
const isOption = (node) =>
|
||||
node.type?.name === 'ElOption' && !!node.component?.proxy
|
||||
const isOption = (
|
||||
node: VNode
|
||||
): node is VNode & { component: OptionInternalInstance } =>
|
||||
(node.type as Component).name === 'ElOption' && !!node.component?.proxy
|
||||
|
||||
// get all instances of options
|
||||
const flattedChildren = (node) => {
|
||||
const Nodes = ensureArray(node)
|
||||
const children = []
|
||||
const flattedChildren = (node: VNode | VNodeArrayChildren) => {
|
||||
const nodes = ensureArray(node) as VNode[] | VNodeArrayChildren
|
||||
const children: OptionPublicInstance[] = []
|
||||
|
||||
nodes.forEach((child) => {
|
||||
if (!isVNode(child)) return
|
||||
|
||||
Nodes.forEach((child) => {
|
||||
if (isOption(child)) {
|
||||
children.push(child.component.proxy)
|
||||
} else if (child.children?.length) {
|
||||
} else if (isArray(child.children) && child.children.length) {
|
||||
children.push(...flattedChildren(child.children))
|
||||
} else if (child.component?.subTree) {
|
||||
children.push(...flattedChildren(child.component.subTree))
|
||||
|
||||
23
packages/components/select/src/option.ts
Normal file
23
packages/components/select/src/option.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
|
||||
export const COMPONENT_NAME = 'ElOption'
|
||||
export const optionProps = buildProps({
|
||||
/**
|
||||
* @description value of option
|
||||
*/
|
||||
value: {
|
||||
type: [String, Number, Boolean, Object],
|
||||
required: true as const,
|
||||
},
|
||||
/**
|
||||
* @description label of option, same as `value` if omitted
|
||||
*/
|
||||
label: {
|
||||
type: [String, Number],
|
||||
},
|
||||
created: Boolean,
|
||||
/**
|
||||
* @description whether option is disabled
|
||||
*/
|
||||
disabled: Boolean,
|
||||
})
|
||||
@@ -16,7 +16,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
@@ -29,30 +28,15 @@ import {
|
||||
} from 'vue'
|
||||
import { useId, useNamespace } from '@element-plus/hooks'
|
||||
import { useOption } from './useOption'
|
||||
import type { SelectOptionProxy } from './token'
|
||||
import { COMPONENT_NAME, optionProps } from './option'
|
||||
|
||||
import type { OptionExposed, OptionInternalInstance, OptionStates } from './type'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElOption',
|
||||
componentName: 'ElOption',
|
||||
name: COMPONENT_NAME,
|
||||
componentName: COMPONENT_NAME,
|
||||
|
||||
props: {
|
||||
/**
|
||||
* @description value of option
|
||||
*/
|
||||
value: {
|
||||
required: true,
|
||||
type: [String, Number, Boolean, Object],
|
||||
},
|
||||
/**
|
||||
* @description label of option, same as `value` if omitted
|
||||
*/
|
||||
label: [String, Number],
|
||||
created: Boolean,
|
||||
/**
|
||||
* @description whether option is disabled
|
||||
*/
|
||||
disabled: Boolean,
|
||||
},
|
||||
props: optionProps,
|
||||
|
||||
setup(props) {
|
||||
const ns = useNamespace('select')
|
||||
@@ -65,7 +49,7 @@ export default defineComponent({
|
||||
ns.is('hovering', unref(hover)),
|
||||
])
|
||||
|
||||
const states = reactive({
|
||||
const states = reactive<OptionStates>({
|
||||
index: -1,
|
||||
groupDisabled: false,
|
||||
visible: true,
|
||||
@@ -83,7 +67,7 @@ export default defineComponent({
|
||||
|
||||
const { visible, hover } = toRefs(states)
|
||||
|
||||
const vm = getCurrentInstance().proxy as unknown as SelectOptionProxy
|
||||
const vm = (getCurrentInstance()! as OptionInternalInstance).proxy
|
||||
|
||||
select.onOptionCreate(vm)
|
||||
|
||||
@@ -116,13 +100,14 @@ export default defineComponent({
|
||||
itemSelected,
|
||||
isDisabled,
|
||||
select,
|
||||
hoverItem,
|
||||
updateOption,
|
||||
visible,
|
||||
hover,
|
||||
selectOptionClick,
|
||||
states,
|
||||
}
|
||||
|
||||
hoverItem,
|
||||
updateOption,
|
||||
selectOptionClick,
|
||||
} satisfies OptionExposed
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -2,17 +2,19 @@ import { defineComponent, inject } from 'vue'
|
||||
import { isEqual } from 'lodash-unified'
|
||||
import { isArray, isFunction, isString } from '@element-plus/utils'
|
||||
import { selectKey } from './token'
|
||||
|
||||
import type { Component, VNode, VNodeNormalizedChildren } from 'vue'
|
||||
import type { OptionValue } from './type'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElOptions',
|
||||
setup(_, { slots }) {
|
||||
const select = inject(selectKey)
|
||||
let cachedValueList: any[] = []
|
||||
let cachedValueList: OptionValue[] = []
|
||||
|
||||
return () => {
|
||||
const children = slots.default?.()!
|
||||
const valueList: any[] = []
|
||||
const valueList: OptionValue[] = []
|
||||
|
||||
function filterOptions(children?: VNodeNormalizedChildren) {
|
||||
if (!isArray(children)) return
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
import { placements } from '@popperjs/core'
|
||||
import { scrollbarEmits } from 'element-plus'
|
||||
import {
|
||||
useAriaProps,
|
||||
useEmptyValuesProps,
|
||||
useSizeProp,
|
||||
} from '@element-plus/hooks'
|
||||
import { buildProps, definePropType, iconPropType } from '@element-plus/utils'
|
||||
import {
|
||||
EmitFn,
|
||||
buildProps,
|
||||
definePropType,
|
||||
iconPropType,
|
||||
} from '@element-plus/utils'
|
||||
import { useTooltipContentProps } from '@element-plus/components/tooltip'
|
||||
import { ArrowDown, CircleClose } from '@element-plus/icons-vue'
|
||||
import { tagProps } from '@element-plus/components/tag'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import type Select from './select.vue'
|
||||
import type {
|
||||
Options,
|
||||
Placement,
|
||||
PopperEffect,
|
||||
} from '@element-plus/components/popper'
|
||||
import type { OptionValue } from './type'
|
||||
|
||||
export const SelectProps = buildProps({
|
||||
/**
|
||||
@@ -27,7 +38,13 @@ export const SelectProps = buildProps({
|
||||
* @description binding value
|
||||
*/
|
||||
modelValue: {
|
||||
type: [Array, String, Number, Boolean, Object],
|
||||
type: definePropType<OptionValue | OptionValue[]>([
|
||||
Array,
|
||||
String,
|
||||
Number,
|
||||
Boolean,
|
||||
Object,
|
||||
]),
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
@@ -252,3 +269,19 @@ export const SelectProps = buildProps({
|
||||
...useEmptyValuesProps,
|
||||
...useAriaProps(['ariaLabel']),
|
||||
})
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
export const selectEmits = {
|
||||
[UPDATE_MODEL_EVENT]: (val: ISelectProps['modelValue']) => true,
|
||||
[CHANGE_EVENT]: (val: ISelectProps['modelValue']) => true,
|
||||
'popup-scroll': scrollbarEmits.scroll,
|
||||
'remove-tag': (val: unknown) => true,
|
||||
'visible-change': (visible: boolean) => true,
|
||||
focus: (evt: FocusEvent) => evt instanceof FocusEvent,
|
||||
blur: (evt: FocusEvent) => evt instanceof FocusEvent,
|
||||
clear: () => true,
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
|
||||
export type ISelectProps = ExtractPropTypes<typeof SelectProps>
|
||||
export type SelectEmits = EmitFn<typeof selectEmits>
|
||||
export type SelectInstance = InstanceType<typeof Select> & unknown
|
||||
|
||||
@@ -314,9 +314,9 @@ import ElSelectMenu from './select-dropdown.vue'
|
||||
import { useSelect } from './useSelect'
|
||||
import { selectKey } from './token'
|
||||
import ElOptions from './options'
|
||||
|
||||
import { SelectProps } from './select'
|
||||
import type { SelectContext } from './token'
|
||||
|
||||
import type { SelectContext } from './type'
|
||||
|
||||
const COMPONENT_NAME = 'ElSelect'
|
||||
export default defineComponent({
|
||||
@@ -370,13 +370,13 @@ export default defineComponent({
|
||||
reactive({
|
||||
props: _props,
|
||||
states: API.states,
|
||||
selectRef: API.selectRef,
|
||||
optionsArray: API.optionsArray,
|
||||
setSelected: API.setSelected,
|
||||
handleOptionSelect: API.handleOptionSelect,
|
||||
onOptionCreate: API.onOptionCreate,
|
||||
onOptionDestroy: API.onOptionDestroy,
|
||||
selectRef: API.selectRef,
|
||||
setSelected: API.setSelected,
|
||||
}) as unknown as SelectContext
|
||||
}) satisfies SelectContext
|
||||
)
|
||||
|
||||
const selectedLabel = computed(() => {
|
||||
|
||||
@@ -1,45 +1,8 @@
|
||||
import type { ExtractPropTypes, InjectionKey } from 'vue'
|
||||
import type { SelectProps } from './select'
|
||||
|
||||
interface SelectGroupContext {
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export interface SelectContext {
|
||||
props: ExtractPropTypes<typeof SelectProps>
|
||||
states: any
|
||||
expanded: boolean
|
||||
selectRef: HTMLElement
|
||||
optionsArray: any[]
|
||||
setSelected(): void
|
||||
onOptionCreate(vm: SelectOptionProxy): void
|
||||
onOptionDestroy(
|
||||
key: number | string | Record<string, string>,
|
||||
vm: SelectOptionProxy
|
||||
): void
|
||||
handleOptionSelect(vm: SelectOptionProxy): void
|
||||
}
|
||||
import type { InjectionKey } from 'vue'
|
||||
import type { SelectContext, SelectGroupContext } from './type'
|
||||
|
||||
// For individual build sharing injection key, we had to make `Symbol` to string
|
||||
export const selectGroupKey: InjectionKey<SelectGroupContext> =
|
||||
Symbol('ElSelectGroup')
|
||||
|
||||
export const selectKey: InjectionKey<SelectContext> = Symbol('ElSelect')
|
||||
|
||||
export interface SelectOptionProxy {
|
||||
value: string | number | Record<string, string>
|
||||
label: string | number
|
||||
created: boolean
|
||||
disabled: boolean
|
||||
currentLabel: string
|
||||
itemSelected: boolean
|
||||
isDisabled: boolean
|
||||
select: SelectContext
|
||||
hoverItem: () => void
|
||||
updateOption: (query: string) => void
|
||||
visible: boolean
|
||||
hover: boolean
|
||||
selectOptionClick: () => void
|
||||
}
|
||||
|
||||
export type ISelectProps = ExtractPropTypes<typeof SelectProps>
|
||||
|
||||
72
packages/components/select/src/type.ts
Normal file
72
packages/components/select/src/type.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type {
|
||||
ComponentInternalInstance,
|
||||
ComponentPublicInstance,
|
||||
ComputedRef,
|
||||
ExtractPropTypes,
|
||||
Ref,
|
||||
} from 'vue'
|
||||
import type { ISelectProps } from './select'
|
||||
import type { optionProps } from './option'
|
||||
export interface SelectGroupContext {
|
||||
disabled: boolean
|
||||
}
|
||||
export interface SelectContext {
|
||||
props: ISelectProps
|
||||
states: SelectStates
|
||||
selectRef: HTMLElement | undefined
|
||||
optionsArray: OptionPublicInstance[]
|
||||
setSelected(): void
|
||||
onOptionCreate(vm: OptionPublicInstance): void
|
||||
onOptionDestroy(key: OptionValue, vm: OptionPublicInstance): void
|
||||
handleOptionSelect(vm: OptionPublicInstance): void
|
||||
}
|
||||
export type SelectStates = {
|
||||
inputValue: string
|
||||
options: Map<OptionValue, OptionPublicInstance>
|
||||
cachedOptions: Map<OptionValue, OptionPublicInstance>
|
||||
optionValues: OptionValue[]
|
||||
selected: OptionBasic[]
|
||||
hoveringIndex: number
|
||||
inputHovering: boolean
|
||||
selectionWidth: number
|
||||
collapseItemWidth: number
|
||||
previousQuery: string | null
|
||||
selectedLabel: string
|
||||
menuVisibleOnFocus: boolean
|
||||
isBeforeHide: boolean
|
||||
}
|
||||
export type OptionProps = ExtractPropTypes<typeof optionProps>
|
||||
export interface OptionStates {
|
||||
index: number
|
||||
groupDisabled: boolean
|
||||
visible: boolean
|
||||
hover: boolean
|
||||
}
|
||||
export interface OptionExposed {
|
||||
ns: unknown
|
||||
id: unknown
|
||||
containerKls: unknown
|
||||
currentLabel: ComputedRef<string | number | boolean>
|
||||
itemSelected: ComputedRef<boolean>
|
||||
isDisabled: ComputedRef<boolean>
|
||||
visible: Ref<boolean>
|
||||
hover: Ref<boolean>
|
||||
states: OptionStates
|
||||
select: SelectContext
|
||||
hoverItem: () => void
|
||||
updateOption: (query: string) => void
|
||||
selectOptionClick: () => void
|
||||
}
|
||||
export type OptionPublicInstance = ComponentPublicInstance<
|
||||
OptionProps,
|
||||
OptionExposed
|
||||
>
|
||||
export type OptionInternalInstance = ComponentInternalInstance & {
|
||||
proxy: OptionPublicInstance
|
||||
}
|
||||
export type OptionValue = OptionProps['value']
|
||||
export type OptionBasic = {
|
||||
value: OptionValue
|
||||
currentLabel: OptionPublicInstance['currentLabel']
|
||||
isDisabled?: OptionPublicInstance['isDisabled']
|
||||
}
|
||||
@@ -1,12 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import { computed, getCurrentInstance, inject, toRaw, watch } from 'vue'
|
||||
import { get, isEqual } from 'lodash-unified'
|
||||
import { ensureArray, escapeStringRegexp, isObject } from '@element-plus/utils'
|
||||
import {
|
||||
ensureArray,
|
||||
escapeStringRegexp,
|
||||
isObject,
|
||||
throwError,
|
||||
} from '@element-plus/utils'
|
||||
import { selectGroupKey, selectKey } from './token'
|
||||
import { COMPONENT_NAME } from './option'
|
||||
|
||||
export function useOption(props, states) {
|
||||
import type { OptionInternalInstance, OptionProps, OptionStates } from './type'
|
||||
|
||||
export function useOption(props: OptionProps, states: OptionStates) {
|
||||
// inject
|
||||
const select = inject(selectKey)
|
||||
if (!select) {
|
||||
throwError(COMPONENT_NAME, 'usage: <el-select><el-option /></el-select/>')
|
||||
}
|
||||
const selectGroup = inject(selectGroupKey, { disabled: false })
|
||||
|
||||
// computed
|
||||
@@ -39,9 +49,8 @@ export function useOption(props, states) {
|
||||
return props.disabled || states.groupDisabled || limitReached.value
|
||||
})
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
const contains = (arr = [], target) => {
|
||||
const instance = getCurrentInstance()! as OptionInternalInstance
|
||||
const contains = <T>(arr: T[] = [], target: T) => {
|
||||
if (!isObject(props.value)) {
|
||||
return arr && arr.includes(target)
|
||||
} else {
|
||||
@@ -63,7 +72,7 @@ export function useOption(props, states) {
|
||||
|
||||
const updateOption = (query: string) => {
|
||||
const regexp = new RegExp(escapeStringRegexp(query), 'i')
|
||||
states.visible = regexp.test(currentLabel.value) || props.created
|
||||
states.visible = regexp.test(String(currentLabel.value)) || props.created
|
||||
}
|
||||
|
||||
watch(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
Component,
|
||||
computed,
|
||||
nextTick,
|
||||
onMounted,
|
||||
@@ -49,20 +49,22 @@ import {
|
||||
} from '@element-plus/components/form'
|
||||
|
||||
import type { TooltipInstance } from '@element-plus/components/tooltip'
|
||||
import type { ISelectProps, SelectOptionProxy } from './token'
|
||||
import type { ScrollbarInstance } from '@element-plus/components/scrollbar'
|
||||
import type { ISelectProps, SelectEmits } from './select'
|
||||
import type { OptionPublicInstance, OptionValue, SelectStates } from './type'
|
||||
|
||||
export const useSelect = (props: ISelectProps, emit) => {
|
||||
export const useSelect = (props: ISelectProps, emit: SelectEmits) => {
|
||||
const { t } = useLocale()
|
||||
const contentId = useId()
|
||||
const nsSelect = useNamespace('select')
|
||||
const nsInput = useNamespace('input')
|
||||
|
||||
const states = reactive({
|
||||
const states = reactive<SelectStates>({
|
||||
inputValue: '',
|
||||
options: new Map(),
|
||||
cachedOptions: new Map(),
|
||||
optionValues: [] as any[], // sorted value of options
|
||||
selected: [] as any[],
|
||||
optionValues: [], // sorted value of options
|
||||
selected: [],
|
||||
selectionWidth: 0,
|
||||
collapseItemWidth: 0,
|
||||
selectedLabel: '',
|
||||
@@ -74,19 +76,17 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
})
|
||||
|
||||
// template refs
|
||||
const selectRef = ref<HTMLElement>(null)
|
||||
const selectionRef = ref<HTMLElement>(null)
|
||||
const tooltipRef = ref<TooltipInstance | null>(null)
|
||||
const tagTooltipRef = ref<TooltipInstance | null>(null)
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
const prefixRef = ref<HTMLElement>(null)
|
||||
const suffixRef = ref<HTMLElement>(null)
|
||||
const menuRef = ref<HTMLElement>(null)
|
||||
const tagMenuRef = ref<HTMLElement>(null)
|
||||
const collapseItemRef = ref<HTMLElement>(null)
|
||||
const scrollbarRef = ref<{
|
||||
handleScroll: () => void
|
||||
} | null>(null)
|
||||
const selectRef = ref<HTMLElement>()
|
||||
const selectionRef = ref<HTMLElement>()
|
||||
const tooltipRef = ref<TooltipInstance>()
|
||||
const tagTooltipRef = ref<TooltipInstance>()
|
||||
const inputRef = ref<HTMLInputElement>()
|
||||
const prefixRef = ref<HTMLElement>()
|
||||
const suffixRef = ref<HTMLElement>()
|
||||
const menuRef = ref<HTMLElement>()
|
||||
const tagMenuRef = ref<HTMLElement>()
|
||||
const collapseItemRef = ref<HTMLElement>()
|
||||
const scrollbarRef = ref<ScrollbarInstance>()
|
||||
|
||||
const {
|
||||
isComposing,
|
||||
@@ -153,12 +153,14 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
: props.suffixIcon
|
||||
)
|
||||
const iconReverse = computed(() =>
|
||||
nsSelect.is('reverse', iconComponent.value && expanded.value)
|
||||
nsSelect.is('reverse', !!(iconComponent.value && expanded.value))
|
||||
)
|
||||
|
||||
const validateState = computed(() => formItem?.validateState || '')
|
||||
const validateIcon = computed(
|
||||
() => ValidateComponentsMap[validateState.value]
|
||||
() =>
|
||||
validateState.value &&
|
||||
(ValidateComponentsMap[validateState.value] as Component)
|
||||
)
|
||||
|
||||
const debounce = computed(() => (props.remote ? 300 : 0))
|
||||
@@ -192,7 +194,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
|
||||
const optionsArray = computed(() => {
|
||||
const list = Array.from(states.options.values())
|
||||
const newList = []
|
||||
const newList: OptionPublicInstance[] = []
|
||||
states.optionValues.forEach((item) => {
|
||||
const index = list.findIndex((i) => i.value === item)
|
||||
if (index > -1) {
|
||||
@@ -402,7 +404,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
} else {
|
||||
states.selectedLabel = ''
|
||||
}
|
||||
const result: any[] = []
|
||||
const result: SelectStates['selected'] = []
|
||||
if (!isUndefined(props.modelValue)) {
|
||||
ensureArray(props.modelValue).forEach((value) => {
|
||||
result.push(getOption(value))
|
||||
@@ -411,7 +413,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
states.selected = result
|
||||
}
|
||||
|
||||
const getOption = (value) => {
|
||||
const getOption = (value: OptionValue) => {
|
||||
let option
|
||||
const isObjectValue = isPlainObject(value)
|
||||
|
||||
@@ -449,12 +451,12 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
}
|
||||
|
||||
const resetSelectionWidth = () => {
|
||||
states.selectionWidth = selectionRef.value.getBoundingClientRect().width
|
||||
states.selectionWidth = selectionRef.value!.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const resetCollapseItemWidth = () => {
|
||||
states.collapseItemWidth =
|
||||
collapseItemRef.value.getBoundingClientRect().width
|
||||
collapseItemRef.value!.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const updateTooltip = () => {
|
||||
@@ -472,8 +474,8 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
handleQueryChange(states.inputValue)
|
||||
}
|
||||
|
||||
const onInput = (event) => {
|
||||
states.inputValue = event.target.value
|
||||
const onInput = (event: Event) => {
|
||||
states.inputValue = (event.target as HTMLInputElement).value
|
||||
if (props.remote) {
|
||||
debouncedOnInputChange()
|
||||
} else {
|
||||
@@ -485,22 +487,22 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
onInputChange()
|
||||
}, debounce.value)
|
||||
|
||||
const emitChange = (val) => {
|
||||
const emitChange = (val: OptionValue | OptionValue[]) => {
|
||||
if (!isEqual(props.modelValue, val)) {
|
||||
emit(CHANGE_EVENT, val)
|
||||
}
|
||||
}
|
||||
|
||||
const getLastNotDisabledIndex = (value) =>
|
||||
const getLastNotDisabledIndex = (value: OptionValue[]) =>
|
||||
findLastIndex(value, (it) => {
|
||||
const option = states.cachedOptions.get(it)
|
||||
return option && !option.disabled && !option.states.groupDisabled
|
||||
})
|
||||
|
||||
const deletePrevTag = (e) => {
|
||||
const deletePrevTag = (e: KeyboardEvent) => {
|
||||
if (!props.multiple) return
|
||||
if (e.code === EVENT_CODE.delete) return
|
||||
if (e.target.value.length <= 0) {
|
||||
if ((e.target as HTMLInputElement).value.length <= 0) {
|
||||
const value = ensureArray(props.modelValue).slice()
|
||||
const lastNotDisabledIndex = getLastNotDisabledIndex(value)
|
||||
if (lastNotDisabledIndex < 0) return
|
||||
@@ -512,7 +514,10 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
}
|
||||
}
|
||||
|
||||
const deleteTag = (event, tag) => {
|
||||
const deleteTag = (
|
||||
event: MouseEvent,
|
||||
tag: OptionPublicInstance | SelectStates['selected'][0]
|
||||
) => {
|
||||
const index = states.selected.indexOf(tag)
|
||||
if (index > -1 && !selectDisabled.value) {
|
||||
const value = ensureArray(props.modelValue).slice()
|
||||
@@ -525,9 +530,9 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
focus()
|
||||
}
|
||||
|
||||
const deleteSelected = (event) => {
|
||||
const deleteSelected = (event: Event) => {
|
||||
event.stopPropagation()
|
||||
const value: string | any[] = props.multiple ? [] : valueOnClear.value
|
||||
const value = props.multiple ? [] : valueOnClear.value
|
||||
if (props.multiple) {
|
||||
for (const item of states.selected) {
|
||||
if (item.isDisabled) value.push(item.value)
|
||||
@@ -541,7 +546,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
focus()
|
||||
}
|
||||
|
||||
const handleOptionSelect = (option) => {
|
||||
const handleOptionSelect = (option: OptionPublicInstance) => {
|
||||
if (props.multiple) {
|
||||
const value = ensureArray(props.modelValue ?? []).slice()
|
||||
const optionIndex = getValueIndex(value, option)
|
||||
@@ -573,7 +578,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getValueIndex = (arr: any[] = [], option) => {
|
||||
const getValueIndex = (arr: OptionValue[], option: OptionPublicInstance) => {
|
||||
if (isUndefined(option)) return -1
|
||||
if (!isObject(option.value)) return arr.indexOf(option.value)
|
||||
|
||||
@@ -582,7 +587,12 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
})
|
||||
}
|
||||
|
||||
const scrollToOption = (option) => {
|
||||
const scrollToOption = (
|
||||
option:
|
||||
| OptionPublicInstance
|
||||
| OptionPublicInstance[]
|
||||
| SelectStates['selected']
|
||||
) => {
|
||||
const targetOption = isArray(option) ? option[0] : option
|
||||
let target = null
|
||||
|
||||
@@ -606,12 +616,12 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
scrollbarRef.value?.handleScroll()
|
||||
}
|
||||
|
||||
const onOptionCreate = (vm: SelectOptionProxy) => {
|
||||
const onOptionCreate = (vm: OptionPublicInstance) => {
|
||||
states.options.set(vm.value, vm)
|
||||
states.cachedOptions.set(vm.value, vm)
|
||||
}
|
||||
|
||||
const onOptionDestroy = (key, vm: SelectOptionProxy) => {
|
||||
const onOptionDestroy = (key: OptionValue, vm: OptionPublicInstance) => {
|
||||
if (states.options.get(key) === vm) {
|
||||
states.options.delete(key)
|
||||
}
|
||||
@@ -689,7 +699,9 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getValueKey = (item) => {
|
||||
const getValueKey = (
|
||||
item: OptionPublicInstance | SelectStates['selected'][0]
|
||||
) => {
|
||||
return isObject(item.value) ? get(item.value, props.valueKey) : item.value
|
||||
}
|
||||
|
||||
@@ -717,7 +729,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
: []
|
||||
})
|
||||
|
||||
const navigateOptions = (direction) => {
|
||||
const navigateOptions = (direction: 'prev' | 'next') => {
|
||||
if (!expanded.value) {
|
||||
expanded.value = true
|
||||
return
|
||||
|
||||
@@ -27,6 +27,9 @@ export default defineComponent({
|
||||
() => {
|
||||
props.data.forEach((item) => {
|
||||
if (!select.states.cachedOptions.has(item.value)) {
|
||||
// TODO: the type of 'item' is not compatible with the type of 'cachedOptions',
|
||||
// which may indicate potential runtime issues.
|
||||
// @ts-expect-error
|
||||
select.states.cachedOptions.set(item.value, item)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user