diff --git a/packages/select/__tests__/select.spec.ts b/packages/select/__tests__/select.spec.ts index 9744d69b3d..0a1b8bfc51 100644 --- a/packages/select/__tests__/select.spec.ts +++ b/packages/select/__tests__/select.spec.ts @@ -20,6 +20,7 @@ interface SelectProps { automaticDropdown?: boolean multipleLimit?: number popperClass?: string + defaultFirstOption?: boolean } const _mount = (template: string, data: any = () => ({}), otherObj?) => mount({ @@ -42,7 +43,7 @@ function getOptions(): HTMLElement[] { } 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.multipleLimit = configs.multipleLimit || 0 @@ -78,6 +79,7 @@ const getSelectVm = (configs: SelectProps = {}, options?) => { :multiple-limit="multipleLimit" :popper-class="popperClass" :clearable="clearable" + :default-first-option="defaultFirstOption" :filterable="filterable" :collapse-tags="collapseTags" :allow-create="allowCreate" @@ -99,6 +101,7 @@ const getSelectVm = (configs: SelectProps = {}, options?) => { multiple: configs.multiple, multipleLimit: configs.multipleLimit, clearable: configs.clearable, + defaultFirstOption: configs.defaultFirstOption, filterable: configs.filterable, collapseTags: configs.collapseTags, allowCreate: configs.allowCreate, @@ -449,6 +452,51 @@ describe('Select', () => { 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 () => { const wrapper = getSelectVm({ filterable: true, allowCreate: true }) const select = wrapper.findComponent({ name: 'ElSelect' }) diff --git a/packages/select/src/useOption.ts b/packages/select/src/useOption.ts index 11ce6e5565..a2377bf3ad 100644 --- a/packages/select/src/useOption.ts +++ b/packages/select/src/useOption.ts @@ -81,10 +81,16 @@ export function useOption(props, states) { } const queryChange = (query: string) => { - const regexp = new RegExp(escapeRegexpString(query), 'i') - states.visible = regexp.test(currentLabel.value) || props.created - if (!states.visible) { - select.filteredOptionsCount-- + // not in filtering, just show original options only + if (!query) { + states.visible = !props.created + } 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-- + } } } diff --git a/packages/select/src/useSelect.ts b/packages/select/src/useSelect.ts index 238fa0ed96..ee00d11cbf 100644 --- a/packages/select/src/useSelect.ts +++ b/packages/select/src/useSelect.ts @@ -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 = () => { - states.hoverIndex = -1 - // highlight the created option - let hasCreated = false - for (let i = states.options.size - 1; i >= 0; i--) { - 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 optionsInDropdown = optionsArray.value.filter(n => n.visible && !n.disabled && !n.groupDisabled) + const userCreatedOption = optionsInDropdown.filter(n => n.created)[0] + const firstOriginOption = optionsInDropdown[0] + states.hoverIndex = getValueIndex(optionsArray.value, userCreatedOption || firstOriginOption) } const setSelected = () => {