import { h, Children, concatClassName } from 'lib/h' import * as Button from 'lib/button' export function create( attrs: object, id: string, keys: string[], renderEntry: (entry: string) => Element, onInput: (value: string) => void ): Element { const completion = h('div', {}) const updateCompletion = (target: EventTarget, value: string) => { const entries = search(value, keys) mountOn( completion, renderCompletion( renderEntry, selected => { (target as HTMLInputElement).value = selected completion.remove removeChildren(completion) onInput(selected) }, entries ) ) } const input = h('input', concatClassName( { ...attrs, id, autocomplete: 'off', onfocus: (e: Event) => { if (e.target !== null) { const target = e.target as HTMLInputElement updateCompletion(target, target.value) } }, oninput: (e: Event) => { if (e.target !== null) { const target = e.target as HTMLInputElement updateCompletion(target, target.value) onInput(target.value) } } }, 'g-AutoComplete__Input' ) ) as HTMLInputElement input.addEventListener('blur', (e: MouseEvent) => { if (e.relatedTarget === null) { removeChildren(completion) } }) return h('div', { className: 'g-AutoComplete' }, input, completion, Button.raw( { className: 'g-AutoComplete__Clear', type: 'button', onclick: () => { onInput('') input.value = '' input.focus() } }, 'x' ) ) } function renderCompletion( renderEntry: (entry: string) => Element, onSelect: (entry: string) => void, entries: string[] ): Element { return h('div', { className: 'g-AutoComplete__Completion' }, ...entries.map(c => Button.raw( { className: 'g-AutoComplete__Entry', type: 'button', onclick: (e: Event) => { e.stopPropagation() e.preventDefault() onSelect(c) } }, renderEntry(c) ) ) ) } function search(s: string, xs: string[]): string[] { return xs.filter(x => x.includes(s)) } function mountOn(base: Element, ...children: Element[]) { removeChildren(base) children.forEach(child => base.appendChild(child)) } function removeChildren(base: Element) { const firstChild = base.firstChild if (firstChild !== null) { base.removeChild(firstChild) removeChildren(base) } }