Remove results element
The combo box composite widget is composed of two elements: an input field and a popup results container.
This commit is contained in:
Родитель
864920e72d
Коммит
0c96ef6424
15
README.md
15
README.md
|
@ -15,14 +15,21 @@ import 'auto-complete-element'
|
|||
```
|
||||
|
||||
```html
|
||||
<auto-complete src="/users/search">
|
||||
<auto-complete src="/users/search" aria-owns="users-popup">
|
||||
<input slot="field" type="text" data-autocomplete-autofocus>
|
||||
<div slot="popup">
|
||||
<ul slot="results"></ul>
|
||||
</div>
|
||||
<ul slot="popup" id="users-popup"></ul>
|
||||
</auto-complete>
|
||||
```
|
||||
|
||||
The server response should include the items that matched the search query.
|
||||
|
||||
```html
|
||||
<li role="option" data-autocomplete-value="@hubot">Hubot</li>
|
||||
<li role="option" data-autocomplete-value="@bender">Bender</li>
|
||||
<li role="option" data-autocomplete-value="@bb-8">BB-8</li>
|
||||
<li role="option" data-autocomplete-value="@r2d2" aria-disabled="true">R2-D2 (powered down)</li>
|
||||
```
|
||||
|
||||
## Browser support
|
||||
|
||||
- Chrome
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
send() {
|
||||
this.status = 200
|
||||
this.responseText = `
|
||||
<li role="option" data-autocomplete-value="one">Hubot</li>
|
||||
<li role="option" data-autocomplete-value="two">Bender</li>
|
||||
<li role="option" data-autocomplete-value="three">BB-8</li>
|
||||
<li role="option" data-autocomplete-value="four" aria-disabled="true">R2-D2 (powered down)</li>
|
||||
<li role="option" data-autocomplete-value="@hubot">Hubot</li>
|
||||
<li role="option" data-autocomplete-value="@bender">Bender</li>
|
||||
<li role="option" data-autocomplete-value="@bb-8">BB-8</li>
|
||||
<li role="option" data-autocomplete-value="@r2d2" aria-disabled="true">R2-D2 (powered down)</li>
|
||||
`
|
||||
setTimeout(this.onload.bind(this), 0)
|
||||
}
|
||||
|
@ -41,10 +41,7 @@
|
|||
<label id="robots-label">Robots</label>
|
||||
<auto-complete src="/demo" aria-owns="items-popup" aria-labelledby="robots-label">
|
||||
<input type="text" slot="field" aria-labelledby="robots-label" autofocus>
|
||||
<div slot="popup" id="items-popup" aria-labelledby="robots-label">
|
||||
<ul slot="results">
|
||||
</ul>
|
||||
</div>
|
||||
<ul slot="popup" id="items-popup" aria-labelledby="robots-label"></ul>
|
||||
</auto-complete>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -12,9 +12,8 @@ export default class AutocompleteElement extends HTMLElement {
|
|||
connectedCallback() {
|
||||
const input = this.querySelector('input[slot="field"]')
|
||||
const results = this.querySelector('[slot="popup"]')
|
||||
const list = this.querySelector('[slot="results"]')
|
||||
if (!(input instanceof HTMLInputElement) || !results || !list) return
|
||||
state.set(this, new Autocomplete(this, input, results, list))
|
||||
if (!(input instanceof HTMLInputElement) || !results) return
|
||||
state.set(this, new Autocomplete(this, input, results))
|
||||
|
||||
this.setAttribute('role', 'combobox')
|
||||
this.setAttribute('aria-haspopup', 'listbox')
|
||||
|
|
|
@ -8,7 +8,6 @@ export default class Autocomplete {
|
|||
container: AutocompleteElement
|
||||
input: HTMLInputElement
|
||||
results: HTMLElement
|
||||
list: HTMLElement
|
||||
|
||||
onInputChange: Function
|
||||
onResultsClick: Function
|
||||
|
@ -19,11 +18,10 @@ export default class Autocomplete {
|
|||
|
||||
mouseDown: boolean
|
||||
|
||||
constructor(container: AutocompleteElement, input: HTMLInputElement, results: HTMLElement, list: HTMLElement) {
|
||||
constructor(container: AutocompleteElement, input: HTMLInputElement, results: HTMLElement) {
|
||||
this.container = container
|
||||
this.input = input
|
||||
this.results = results
|
||||
this.list = list
|
||||
|
||||
this.results.hidden = true
|
||||
this.input.setAttribute('autocomplete', 'off')
|
||||
|
@ -56,8 +54,8 @@ export default class Autocomplete {
|
|||
}
|
||||
|
||||
sibling(next: boolean): Element {
|
||||
const options = Array.from(this.list.querySelectorAll('[role="option"]'))
|
||||
const selected = this.list.querySelector('[aria-selected="true"]')
|
||||
const options = Array.from(this.results.querySelectorAll('[role="option"]'))
|
||||
const selected = this.results.querySelector('[aria-selected="true"]')
|
||||
const index = options.indexOf(selected)
|
||||
const sibling = next ? options[index + 1] : options[index - 1]
|
||||
const def = next ? options[0] : options[options.length - 1]
|
||||
|
@ -65,7 +63,7 @@ export default class Autocomplete {
|
|||
}
|
||||
|
||||
select(target: Element) {
|
||||
for (const el of this.list.querySelectorAll('[aria-selected="true"]')) {
|
||||
for (const el of this.results.querySelectorAll('[aria-selected="true"]')) {
|
||||
el.removeAttribute('aria-selected')
|
||||
}
|
||||
target.setAttribute('aria-selected', 'true')
|
||||
|
@ -99,7 +97,7 @@ export default class Autocomplete {
|
|||
break
|
||||
case 'Enter':
|
||||
{
|
||||
const selected = this.list.querySelector('[aria-selected="true"]')
|
||||
const selected = this.results.querySelector('[aria-selected="true"]')
|
||||
if (selected) {
|
||||
this.commit(selected)
|
||||
event.preventDefault()
|
||||
|
@ -159,7 +157,7 @@ export default class Autocomplete {
|
|||
this.container.dispatchEvent(new CustomEvent('loadstart'))
|
||||
fragment(this.input, url.toString())
|
||||
.then(html => {
|
||||
this.list.innerHTML = html
|
||||
this.results.innerHTML = html
|
||||
const hasResults = !!this.results.querySelector('[data-autocomplete-value]')
|
||||
this.container.open = hasResults
|
||||
this.container.dispatchEvent(new CustomEvent('load'))
|
||||
|
|
|
@ -17,9 +17,7 @@ describe('auto-complete element', function() {
|
|||
container.innerHTML = `
|
||||
<auto-complete src="/search">
|
||||
<input slot="field" type="text">
|
||||
<div slot="popup">
|
||||
<ul slot="results"></ul>
|
||||
</div>
|
||||
<ul slot="popup"></ul>
|
||||
</auto-complete>`
|
||||
document.body.append(container)
|
||||
})
|
||||
|
@ -30,11 +28,11 @@ describe('auto-complete element', function() {
|
|||
|
||||
it('requests html fragment', async function() {
|
||||
const input = document.querySelector('input')
|
||||
const results = document.querySelector('[slot="results"]')
|
||||
const popup = document.querySelector('[slot="popup"]')
|
||||
input.value = 'hub'
|
||||
input.dispatchEvent(new InputEvent('input'))
|
||||
await sleep(500)
|
||||
assert.equal('hubot', results.textContent)
|
||||
assert.equal('hubot', popup.textContent)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче