mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-12 12:25:22 +08:00
fix(select): should not stop at invisible options by up and down (#2585)
* fix(select): should not stop at invisible options by up and down this also fix another problem (#2562): about unselect user-created tag in ElSelect fix #2563 #2562 * fix(select): checkDefaultFirstOption: exlucde disabled options fix #2562 #2563 * test(select): add test for "default-first-option" (with navigation) check default first option re #2585
This commit is contained in:
parent
5b16f20725
commit
d6fecf9b32
@ -20,6 +20,7 @@ interface SelectProps {
|
|||||||
automaticDropdown?: boolean
|
automaticDropdown?: boolean
|
||||||
multipleLimit?: number
|
multipleLimit?: number
|
||||||
popperClass?: string
|
popperClass?: string
|
||||||
|
defaultFirstOption?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const _mount = (template: string, data: any = () => ({}), otherObj?) => mount({
|
const _mount = (template: string, data: any = () => ({}), otherObj?) => mount({
|
||||||
@ -42,7 +43,7 @@ function getOptions(): HTMLElement[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getSelectVm = (configs: SelectProps = {}, options?) => {
|
const getSelectVm = (configs: SelectProps = {}, options?) => {
|
||||||
['multiple', 'clearable', 'filterable', 'allowCreate', 'remote', 'collapseTags', 'automaticDropdown'].forEach(config => {
|
['multiple', 'clearable', 'defaultFirstOption', 'filterable', 'allowCreate', 'remote', 'collapseTags', 'automaticDropdown'].forEach(config => {
|
||||||
configs[config] = configs[config] || false
|
configs[config] = configs[config] || false
|
||||||
})
|
})
|
||||||
configs.multipleLimit = configs.multipleLimit || 0
|
configs.multipleLimit = configs.multipleLimit || 0
|
||||||
@ -78,6 +79,7 @@ const getSelectVm = (configs: SelectProps = {}, options?) => {
|
|||||||
:multiple-limit="multipleLimit"
|
:multiple-limit="multipleLimit"
|
||||||
:popper-class="popperClass"
|
:popper-class="popperClass"
|
||||||
:clearable="clearable"
|
:clearable="clearable"
|
||||||
|
:default-first-option="defaultFirstOption"
|
||||||
:filterable="filterable"
|
:filterable="filterable"
|
||||||
:collapse-tags="collapseTags"
|
:collapse-tags="collapseTags"
|
||||||
:allow-create="allowCreate"
|
:allow-create="allowCreate"
|
||||||
@ -99,6 +101,7 @@ const getSelectVm = (configs: SelectProps = {}, options?) => {
|
|||||||
multiple: configs.multiple,
|
multiple: configs.multiple,
|
||||||
multipleLimit: configs.multipleLimit,
|
multipleLimit: configs.multipleLimit,
|
||||||
clearable: configs.clearable,
|
clearable: configs.clearable,
|
||||||
|
defaultFirstOption: configs.defaultFirstOption,
|
||||||
filterable: configs.filterable,
|
filterable: configs.filterable,
|
||||||
collapseTags: configs.collapseTags,
|
collapseTags: configs.collapseTags,
|
||||||
allowCreate: configs.allowCreate,
|
allowCreate: configs.allowCreate,
|
||||||
@ -449,6 +452,51 @@ describe('Select', () => {
|
|||||||
expect(vm.value).toBe('')
|
expect(vm.value).toBe('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('check default first option', async () => {
|
||||||
|
const wrapper = getSelectVm({
|
||||||
|
filterable: true,
|
||||||
|
defaultFirstOption: true,
|
||||||
|
})
|
||||||
|
const select = wrapper.findComponent({ name: 'ElSelect' })
|
||||||
|
const selectVm = select.vm as any
|
||||||
|
const input = wrapper.find('input')
|
||||||
|
input.element.focus()
|
||||||
|
|
||||||
|
expect(selectVm.hoverIndex).toBe(0)
|
||||||
|
selectVm.navigateOptions('next')
|
||||||
|
expect(selectVm.hoverIndex).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('check default first option when the very first option is disabled', async () => {
|
||||||
|
const demoOptions = [{
|
||||||
|
value: 'HTML',
|
||||||
|
label: 'HTML',
|
||||||
|
disabled: true,
|
||||||
|
}, {
|
||||||
|
value: 'CSS',
|
||||||
|
label: 'CSS',
|
||||||
|
disabled: false,
|
||||||
|
}, {
|
||||||
|
value: 'JavaScript',
|
||||||
|
label: 'JavaScript',
|
||||||
|
disabled: false,
|
||||||
|
}]
|
||||||
|
const wrapper = getSelectVm({
|
||||||
|
filterable: true,
|
||||||
|
defaultFirstOption: true,
|
||||||
|
}, demoOptions)
|
||||||
|
const select = wrapper.findComponent({ name: 'ElSelect' })
|
||||||
|
const selectVm = select.vm as any
|
||||||
|
const input = wrapper.find('input')
|
||||||
|
input.element.focus()
|
||||||
|
|
||||||
|
expect(selectVm.hoverIndex).toBe(1) // index 0 was skipped
|
||||||
|
selectVm.navigateOptions('next')
|
||||||
|
expect(selectVm.hoverIndex).toBe(2)
|
||||||
|
selectVm.navigateOptions('next')
|
||||||
|
expect(selectVm.hoverIndex).toBe(1) // index 0 was skipped
|
||||||
|
})
|
||||||
|
|
||||||
test('allow create', async () => {
|
test('allow create', async () => {
|
||||||
const wrapper = getSelectVm({ filterable: true, allowCreate: true })
|
const wrapper = getSelectVm({ filterable: true, allowCreate: true })
|
||||||
const select = wrapper.findComponent({ name: 'ElSelect' })
|
const select = wrapper.findComponent({ name: 'ElSelect' })
|
||||||
|
@ -81,10 +81,16 @@ export function useOption(props, states) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const queryChange = (query: string) => {
|
const queryChange = (query: string) => {
|
||||||
const regexp = new RegExp(escapeRegexpString(query), 'i')
|
// not in filtering, just show original options only
|
||||||
states.visible = regexp.test(currentLabel.value) || props.created
|
if (!query) {
|
||||||
if (!states.visible) {
|
states.visible = !props.created
|
||||||
select.filteredOptionsCount--
|
} else {
|
||||||
|
// in filtering, do filter by RegExp
|
||||||
|
const regexp = new RegExp(escapeRegexpString(query), 'i')
|
||||||
|
states.visible = regexp.test(currentLabel.value)
|
||||||
|
if (!states.visible && !props.created) {
|
||||||
|
select.filteredOptionsCount--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,34 +318,21 @@ export const useSelect = (props, states: States, ctx) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find and highlight first option as default selected
|
||||||
|
* @remark
|
||||||
|
* - if the first option in dropdown list is user-created,
|
||||||
|
* it would be at the end of the optionsArray
|
||||||
|
* so find it and set hover.
|
||||||
|
* (NOTE: there must be only one user-created option in dropdown list with query)
|
||||||
|
* - if there's no user-created option in list, just find the first one as usual
|
||||||
|
* (NOTE: exclude options that are disabled or in disabled-group)
|
||||||
|
*/
|
||||||
const checkDefaultFirstOption = () => {
|
const checkDefaultFirstOption = () => {
|
||||||
states.hoverIndex = -1
|
const optionsInDropdown = optionsArray.value.filter(n => n.visible && !n.disabled && !n.groupDisabled)
|
||||||
// highlight the created option
|
const userCreatedOption = optionsInDropdown.filter(n => n.created)[0]
|
||||||
let hasCreated = false
|
const firstOriginOption = optionsInDropdown[0]
|
||||||
for (let i = states.options.size - 1; i >= 0; i--) {
|
states.hoverIndex = getValueIndex(optionsArray.value, userCreatedOption || firstOriginOption)
|
||||||
if (optionsArray.value[i].created) {
|
|
||||||
hasCreated = true
|
|
||||||
states.hoverIndex = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasCreated) return
|
|
||||||
for (let i = 0; i !== states.options.size; ++i) {
|
|
||||||
const option = optionsArray.value[i]
|
|
||||||
if (states.query) {
|
|
||||||
// highlight first options that passes the filter
|
|
||||||
if (!option.disabled && !option.groupDisabled && option.visible) {
|
|
||||||
states.hoverIndex = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// highlight currently selected option
|
|
||||||
if (option.itemSelected) {
|
|
||||||
states.hoverIndex = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSelected = () => {
|
const setSelected = () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user