diff --git a/examples/index.html b/examples/index.html index 4702cf9..2b90b7d 100644 --- a/examples/index.html +++ b/examples/index.html @@ -46,10 +46,10 @@ - +
@@ -64,10 +64,10 @@ - +
@@ -79,7 +79,7 @@ - +
@@ -96,7 +96,7 @@ data-autoselect="true" > - +
@@ -113,7 +113,7 @@ - +
diff --git a/src/autocomplete.ts b/src/autocomplete.ts index 7008de3..13126dc 100644 --- a/src/autocomplete.ts +++ b/src/autocomplete.ts @@ -112,42 +112,40 @@ export default class Autocomplete { this.container.value = '' this.input.focus() this.input.dispatchEvent(new Event('change')) - this.container.open = false + this.close() } onKeydown(event: KeyboardEvent): void { if (event.key === 'Escape' && this.container.open) { - this.container.open = false + this.close() event.stopPropagation() event.preventDefault() } else if (event.altKey && event.key === 'ArrowUp' && this.container.open) { - this.container.open = false + this.close() event.stopPropagation() event.preventDefault() } else if (event.altKey && event.key === 'ArrowDown' && !this.container.open) { if (!this.input.value.trim()) return - this.container.open = true + this.open() event.stopPropagation() event.preventDefault() } } onInputFocus(): void { + if (this.interactingWithList) return this.fetchResults() } onInputBlur(): void { - if (this.interactingWithList) { - this.interactingWithList = false - return - } - this.container.open = false + if (this.interactingWithList) return + this.close() } onCommit({target}: Pick): void { const selected = target if (!(selected instanceof HTMLElement)) return - this.container.open = false + this.close() if (selected instanceof HTMLAnchorElement) return const value = selected.getAttribute('data-autocomplete-value') || selected.textContent! this.updateFeedbackForScreenReaders(`${selected.textContent || ''} selected.`) @@ -189,7 +187,7 @@ export default class Autocomplete { fetchResults(): void { const query = this.input.value.trim() if (!query && !this.container.fetchOnEmpty) { - this.container.open = false + this.close() return } @@ -225,7 +223,7 @@ export default class Autocomplete { this.updateFeedbackForScreenReaders(`${numOptions || 'No'} results.`) } - this.container.open = hasResults + hasResults ? this.open() : this.close() this.container.dispatchEvent(new CustomEvent('load')) this.container.dispatchEvent(new CustomEvent('loadend')) }) @@ -246,6 +244,8 @@ export default class Autocomplete { this.results.hidden = false } } + this.container.open = true + this.interactingWithList = true } close(): void { @@ -258,5 +258,7 @@ export default class Autocomplete { this.results.hidden = true } } + this.container.open = false + this.interactingWithList = false } } diff --git a/test/auto-complete-element.js b/test/auto-complete-element.js index 74cd5bf..7d1827f 100644 --- a/test/auto-complete-element.js +++ b/test/auto-complete-element.js @@ -18,19 +18,8 @@ describe('auto-complete element', function () { }) }) - describe('requesting server results', function () { - beforeEach(function () { - document.body.innerHTML = ` -
- - - - - -
- ` - }) - + // eslint-disable-next-line func-style + const serverResponseExamples = function () { it('requests html fragment', async function () { const container = document.querySelector('auto-complete') const input = container.querySelector('input') @@ -147,25 +136,6 @@ describe('auto-complete element', function () { assert.isFalse(container.open) }) - it('does not close on blur after mousedown', async function () { - const container = document.querySelector('auto-complete') - const input = container.querySelector('input') - - triggerInput(input, 'hub') - await once(container, 'loadend') - - const link = container.querySelector('a[role=option]') - - assert.equal('', container.value) - link.dispatchEvent(new MouseEvent('mousedown', {bubbles: true})) - input.dispatchEvent(new Event('blur')) - assert(container.open) - - await sleep(100) - input.dispatchEvent(new Event('blur')) - assert.isFalse(container.open) - }) - it('closes on Escape', async function () { const container = document.querySelector('auto-complete') const input = container.querySelector('input') @@ -175,10 +145,10 @@ describe('auto-complete element', function () { await once(container, 'loadend') assert.isTrue(container.open) - assert.isFalse(popup.hidden) + if (!popup.popover) assert.isFalse(popup.hidden) assert.isFalse(keydown(input, 'Escape')) assert.isFalse(container.open) - assert.isTrue(popup.hidden) + if (!popup.popover) assert.isTrue(popup.hidden) }) it('opens and closes on alt + ArrowDown and alt + ArrowUp', async function () { @@ -190,15 +160,15 @@ describe('auto-complete element', function () { await once(container, 'loadend') assert.isTrue(container.open) - assert.isFalse(popup.hidden) + if (!popup.popover) assert.isFalse(popup.hidden) assert.isFalse(keydown(input, 'ArrowUp', true)) assert.isFalse(container.open) - assert.isTrue(popup.hidden) + if (!popup.popover) assert.isTrue(popup.hidden) assert.isFalse(keydown(input, 'ArrowDown', true)) assert.isTrue(container.open) - assert.isFalse(popup.hidden) + if (!popup.popover) assert.isFalse(popup.hidden) }) it('allows providing a custom fetch method', async () => { @@ -216,6 +186,38 @@ describe('auto-complete element', function () { assert.equal(2, popup.children.length) assert.equal(popup.querySelector('li').textContent, 'Mock Custom Fetch Result 1') }) + } + + describe('requesting server results (non-popover)', function () { + beforeEach(function () { + document.body.innerHTML = ` +
+ + + + + +
+ ` + }) + + serverResponseExamples() + }) + + describe('requesting server results (popover)', function () { + beforeEach(function () { + document.body.innerHTML = ` +
+ + + + + +
+ ` + }) + + serverResponseExamples() }) describe('clear button provided', () => {