-
Notifications
You must be signed in to change notification settings - Fork 101
feat: add autoFocusPartialMatch to combo boxes #12438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
42f33b2
feat: add autoSelectMode to combo-box and multi-select-combo-box
vursen 6153891
test: focus input in auto-select no-match test to fix WebKit
vursen 53e6eb1
test: assert item highlight only in auto-select-mode suite
vursen 5ddc674
test: assert item highlight only in MSCB auto-select-mode suite
vursen 0cb5164
test: drop Escape and arrow navigation tests from auto-select-mode
vursen 65aee75
test: clarify auto-select-mode test names
vursen 06c82d1
test: cover full-match highlight in auto-select-mode suite
vursen f0c70fe
test: align auto-select-mode test names on matching-item wording
vursen 6454b55
test: name auto-select-mode tests after mode terms
vursen 49e5e85
refactor: rename full-match value of autoSelectMode to exact-match
vursen 99bdcfd
refactor: rename only-match value of autoSelectMode to single-match
vursen 0e884af
refactor: rename autoSelectMode to autoFocusPartialMatch
vursen 9890206
docs: describe exact match focusing outside autoFocusPartialMatch values
vursen 2fe7b56
chore: remove auto-focus-partial-match dev page
vursen 5977686
docs: trim jsdoc on __getItemIndexByFilter to @private only
vursen 06f8a00
test: align MSCB auto-focus-partial-match suite with combo-box
vursen 832f4ca
fix: do not unselect item auto-focused by partial match on Enter
vursen 0d3dd8f
test: cover combo-box auto-focus-partial-match commit triggers
vursen 28da939
test: group auto-focus-partial-match commit tests into a suite
vursen f54a633
test: use mode terminology in auto-focus-partial-match test names
vursen 33d91ed
test: rename match phrases to partial-match terminology
vursen 3daee41
docs: drop blur and outside click from partial match commit examples
vursen fed4471
fix: focus partial match only while the dropdown is open
vursen 88ac2c7
test: simplify auto-focus-partial-match test names
vursen eef5264
refactor: drop redundant comment in __getItemIndexByFilter
vursen 02901a4
refactor: shorten comment in __commitUserInput
vursen 97487ca
test: cover Tab as commit trigger for auto-focused partial match
vursen f32c884
test: add articles to auto-focus-partial-match test names
vursen 7572c9f
test: restructure auto-focus-partial-match commit coverage
vursen 911c507
test: add Tab navigation target to fix Firefox failures
vursen b973c44
Apply suggestion from @vursen
vursen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
220 changes: 220 additions & 0 deletions
220
packages/combo-box/test/auto-focus-partial-match.test.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| import { expect } from '@vaadin/chai-plugins'; | ||
| import { sendKeys } from '@vaadin/test-runner-commands'; | ||
| import { aTimeout, fixtureSync, nextRender, outsideClick } from '@vaadin/testing-helpers'; | ||
| import '../src/vaadin-combo-box.js'; | ||
| import { getFocusedItemIndex } from './helpers.js'; | ||
|
|
||
| describe('auto-focus-partial-match', () => { | ||
| let comboBox, inputElement; | ||
|
|
||
| beforeEach(async () => { | ||
| [comboBox] = fixtureSync( | ||
| `<div> | ||
| <vaadin-combo-box></vaadin-combo-box> | ||
| <input id="last-global-focusable" /> | ||
| </div>`, | ||
| ).children; | ||
| await nextRender(); | ||
| inputElement = comboBox.inputElement; | ||
| inputElement.focus(); | ||
| }); | ||
|
|
||
| describe('none (default)', () => { | ||
| beforeEach(() => { | ||
| comboBox.items = ['apple', 'banana', 'grapefruit', 'grape']; | ||
| }); | ||
|
|
||
| it('should be none by default', () => { | ||
| expect(comboBox.autoFocusPartialMatch).to.equal('none'); | ||
| }); | ||
|
|
||
| it('should highlight the exact match', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(1); | ||
| }); | ||
|
|
||
| it('should not highlight partial matches', async () => { | ||
| await sendKeys({ type: 'gra' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(-1); | ||
| }); | ||
|
|
||
| describe('value commit', () => { | ||
| it('should commit the exact match on Enter', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal('grape'); | ||
| }); | ||
|
|
||
| it('should commit the exact match on Tab', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| await sendKeys({ press: 'Tab' }); | ||
| expect(comboBox.value).to.equal('grape'); | ||
| }); | ||
|
|
||
| it('should commit the exact match on outside click', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| outsideClick(); | ||
| expect(comboBox.value).to.equal('grape'); | ||
| }); | ||
|
|
||
| it('should not commit the partial match on Enter', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal(''); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('first-match', () => { | ||
|
web-padawan marked this conversation as resolved.
|
||
| beforeEach(() => { | ||
| comboBox.autoFocusPartialMatch = 'first-match'; | ||
| comboBox.items = ['apple', 'banana', 'grapefruit', 'grape']; | ||
|
web-padawan marked this conversation as resolved.
|
||
| }); | ||
|
|
||
| it('should highlight the first partial match', async () => { | ||
| await sendKeys({ type: 'gra' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(0); | ||
| }); | ||
|
|
||
| it('should highlight the exact match when there is one', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(1); | ||
| }); | ||
|
|
||
| it('should not highlight the first partial match when custom values are allowed', async () => { | ||
| comboBox.allowCustomValue = true; | ||
| await sendKeys({ type: 'gra' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(-1); | ||
| }); | ||
|
|
||
| it('should not highlight anything when the filter is empty', () => { | ||
| comboBox.open(); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(-1); | ||
| }); | ||
|
|
||
| describe('value commit', () => { | ||
| it('should commit the first partial match on Enter', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal('grapefruit'); | ||
| }); | ||
|
|
||
| it('should not commit on Enter when no items match', async () => { | ||
| await sendKeys({ type: 'xyz' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal(''); | ||
| }); | ||
|
|
||
| it('should commit the first partial match on Tab', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'Tab' }); | ||
| expect(comboBox.value).to.equal('grapefruit'); | ||
| }); | ||
|
|
||
| it('should commit the first partial match on outside click', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| outsideClick(); | ||
| expect(comboBox.value).to.equal('grapefruit'); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('only-match', () => { | ||
| beforeEach(() => { | ||
| comboBox.autoFocusPartialMatch = 'only-match'; | ||
| comboBox.items = ['apple', 'banana', 'grapefruit', 'grape']; | ||
| }); | ||
|
|
||
| it('should highlight the only partial match', async () => { | ||
| await sendKeys({ type: 'ban' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(0); | ||
| }); | ||
|
|
||
| it('should not highlight anything when multiple items match', async () => { | ||
| await sendKeys({ type: 'gra' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(-1); | ||
| }); | ||
|
|
||
| it('should highlight the exact match when there is one', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(1); | ||
| }); | ||
|
|
||
| describe('value commit', () => { | ||
| it('should commit the only partial match on Enter', async () => { | ||
| await sendKeys({ type: 'grapef' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal('grapefruit'); | ||
| }); | ||
|
|
||
| it('should not commit on Enter when multiple items match', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal(''); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('autoOpenDisabled', () => { | ||
| beforeEach(() => { | ||
| comboBox.autoOpenDisabled = true; | ||
| comboBox.autoFocusPartialMatch = 'first-match'; | ||
| comboBox.items = ['apple', 'banana', 'grapefruit', 'grape']; | ||
| }); | ||
|
|
||
| it('should commit the exact match on Enter while closed', async () => { | ||
| await sendKeys({ type: 'grape' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal('grape'); | ||
| }); | ||
|
|
||
| it('should not commit the first partial match on Enter while closed', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal(''); | ||
| }); | ||
|
|
||
| it('should highlight the first partial match when opening the dropdown after typing', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'ArrowDown' }); | ||
| expect(getFocusedItemIndex(comboBox)).to.equal(0); | ||
| }); | ||
|
|
||
| it('should commit the first partial match on Enter after opening the dropdown', async () => { | ||
| await sendKeys({ type: 'grap' }); | ||
| await sendKeys({ press: 'ArrowDown' }); | ||
| await sendKeys({ press: 'Enter' }); | ||
| expect(comboBox.value).to.equal('grapefruit'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('lazy loading', () => { | ||
| beforeEach(() => { | ||
| const allItems = ['apple', 'banana', 'grapefruit', 'grape']; | ||
| comboBox.dataProvider = (params, callback) => { | ||
| setTimeout(() => { | ||
| const filteredItems = allItems.filter((item) => item.includes(params.filter)); | ||
| callback(filteredItems, filteredItems.length); | ||
| }); | ||
| }; | ||
| }); | ||
|
|
||
| it('should highlight the first partial match after the page is loaded', async () => { | ||
| comboBox.autoFocusPartialMatch = 'first-match'; | ||
|
|
||
| await sendKeys({ type: 'gra' }); | ||
| await aTimeout(0); | ||
|
|
||
| expect(getFocusedItemIndex(comboBox)).to.equal(0); | ||
| }); | ||
|
|
||
| it('should highlight the only partial match after the page is loaded', async () => { | ||
| comboBox.autoFocusPartialMatch = 'only-match'; | ||
|
|
||
| await sendKeys({ type: 'ban' }); | ||
| await aTimeout(0); | ||
|
|
||
| expect(getFocusedItemIndex(comboBox)).to.equal(0); | ||
| }); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.