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/package-lock.json b/package-lock.json index f7bf61e..ffdb9c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4846,9 +4846,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "dev": true, "funding": [ { @@ -5423,9 +5423,9 @@ } }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true }, "node_modules/is-array-buffer": { 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', () => {