Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@
<input name="robot" type="text" aria-labelledby="robots-label" autofocus />
<!-- if a clear button is passed in, recommended to be *before* UL elements to avoid conflicting with their blur logic -->
<button id="robot-clear">x</button>
<ul popover id="items-popup"></ul>
<ul id="items-popup"></ul>
<!-- For built-in screen-reader announcements:
- Note the ID is the same as the <ul> with "feedback" appended
- Also note that aria attributes will be added programmatically if they aren't set correctly
- Also note that aria attributes will be added programmatically if they aren't set correctly
-->
<div id="items-popup-feedback" class="sr-only"></div>
</auto-complete>
Expand All @@ -64,10 +64,10 @@
<input id="robot-a" name="robot-a" type="text" aria-labelledby="robots-a-label" autofocus />
<!-- if a clear button is passed in, recommended to be *before* UL elements to avoid conflicting with their blur logic -->
<button id="robot-a-clear">x</button>
<ul popover id="items-a-popup"></ul>
<ul id="items-a-popup"></ul>
<!-- For built-in screen-reader announcements:
- Note the ID is the same as the <ul> with "feedback" appended
- Also note that aria attributes will be added programmatically if they aren't set correctly
- Also note that aria attributes will be added programmatically if they aren't set correctly
-->
<div id="items-a-popup-feedback" class="sr-only"></div>
</auto-complete>
Expand All @@ -79,7 +79,7 @@
<label id="robots-2-label" for="robot-2">Robots (without autoselect on enter)</label>
<auto-complete src="/demo" for="items-2-popup" aria-labelledby="robots-2-label">
<input name="robot-2" type="text" aria-labelledby="robots-2-label" autofocus />
<ul popover id="items-2-popup"></ul>
<ul id="items-2-popup"></ul>
<div id="items-2-popup-feedback" class="sr-only"></div>
</auto-complete>
<button type="submit">Save</button>
Expand All @@ -96,7 +96,7 @@
data-autoselect="true"
>
<input name="custom-fetching-robot" type="text" aria-labelledby="custom-fetching-robots-label" autofocus />
<ul popover id="custom-fetching-items-popup"></ul>
<ul id="custom-fetching-items-popup"></ul>
<div id="custom-fetching-items-popup-feedback" class="sr-only"></div>
</auto-complete>
<button type="submit">Save</button>
Expand All @@ -113,7 +113,7 @@
<auto-complete src="/demo" for="fetch-on-empty-items-popup" aria-labelledby="fetch-on-empty-robots-label" fetch-on-empty>
<input name="fetch-on-empty-robot" type="text" aria-labelledby="fetch-on-empty-robots-label" autofocus />
<button id="fetch-on-empty-robot-clear">x</button>
<ul popover id="fetch-on-empty-items-popup"></ul>
<ul id="fetch-on-empty-items-popup"></ul>
<div id="fetch-on-empty-items-popup-feedback" class="sr-only"></div>
</auto-complete>
<button type="submit">Save</button>
Expand Down
26 changes: 14 additions & 12 deletions src/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event, 'target'>): 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.`)
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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'))
})
Expand All @@ -246,6 +244,8 @@ export default class Autocomplete {
this.results.hidden = false
}
}
this.container.open = true
this.interactingWithList = true
}

close(): void {
Expand All @@ -258,5 +258,7 @@ export default class Autocomplete {
this.results.hidden = true
}
}
this.container.open = false
this.interactingWithList = false
}
}
76 changes: 39 additions & 37 deletions test/auto-complete-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,8 @@ describe('auto-complete element', function () {
})
})

describe('requesting server results', function () {
beforeEach(function () {
document.body.innerHTML = `
<div id="mocha-fixture">
<auto-complete src="/search" for="popup">
<input type="text">
<ul id="popup"></ul>
<div id="popup-feedback"></div>
</auto-complete>
</div>
`
})

// 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')
Expand Down Expand Up @@ -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')
Expand All @@ -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 () {
Expand All @@ -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 () => {
Expand All @@ -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 = `
<div id="mocha-fixture">
<auto-complete src="/search" for="popup">
<input type="text">
<ul id="popup"></ul>
<div id="popup-feedback"></div>
</auto-complete>
</div>
`
})

serverResponseExamples()
})

describe('requesting server results (popover)', function () {
beforeEach(function () {
document.body.innerHTML = `
<div id="mocha-fixture">
<auto-complete src="/search" for="popup">
<input type="text">
<ul popover id="popup"></ul>
<div id="popup-feedback"></div>
</auto-complete>
</div>
`
})

serverResponseExamples()
})

describe('clear button provided', () => {
Expand Down