diff --git a/examples/index.html b/examples/index.html index 8ed58e8..8fe579f 100644 --- a/examples/index.html +++ b/examples/index.html @@ -43,6 +43,7 @@ + @@ -56,52 +57,7 @@ - -
- - - - - - -
    - -
    -
    - -
    - - -
    - - - -
      -
      -
      - -
      - - -
      - - - -
        -
        -
        - -
        - - - - + + diff --git a/src/auto-complete-element.ts b/src/auto-complete-element.ts index 0e36f37..1b2d380 100644 --- a/src/auto-complete-element.ts +++ b/src/auto-complete-element.ts @@ -12,10 +12,14 @@ export default class AutocompleteElement extends HTMLElement { // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback const input = this.querySelector('input') + // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback + const tokenizedInput = this.querySelector('[data-tokenized-input]') + // eslint-disable-next-line no-console + console.log(tokenizedInput) const results = document.getElementById(listId) if (!(input instanceof HTMLInputElement) || !results) return const autoselectEnabled = this.getAttribute('data-autoselect') === 'true' - state.set(this, new Autocomplete(this, input, results, autoselectEnabled)) + state.set(this, new Autocomplete(this, input, tokenizedInput as HTMLElement, results, autoselectEnabled)) results.setAttribute('role', 'listbox') } @@ -74,6 +78,28 @@ export default class AutocompleteElement extends HTMLElement { case 'value': if (newValue !== null) { autocomplete.input.value = newValue + + // TODO: Deduplicate this from `autocomplete.ts` + autocomplete.tokenizedInput.textContent = '' + + const tokens = newValue.split(' ') + + for (const token of tokens) { + const tokenItem = document.createElement('span') + const tokenItemSpace = document.createElement('span') + tokenItemSpace.textContent = ' ' + + if (token.includes(':')) { + tokenItem.setAttribute('data-input-type', 'token') + tokenItem.style.border = '1px solid hotpink' + } else { + tokenItem.setAttribute('data-input-type', 'text') + } + + tokenItem.textContent = `${token}` + autocomplete.tokenizedInput?.appendChild(tokenItem) + autocomplete.tokenizedInput?.appendChild(tokenItemSpace) + } } this.dispatchEvent( new AutocompleteEvent('auto-complete-change', { diff --git a/src/autocomplete.ts b/src/autocomplete.ts index 6d5a99b..b897e39 100644 --- a/src/autocomplete.ts +++ b/src/autocomplete.ts @@ -1,6 +1,6 @@ import type AutocompleteElement from './auto-complete-element' import Combobox from '@github/combobox-nav' -import debounce from './debounce.js' +// import debounce from './debounce.js' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -9,6 +9,7 @@ const SCREEN_READER_DELAY = window.testScreenReaderDelay || 100 export default class Autocomplete { container: AutocompleteElement input: HTMLInputElement + tokenizedInput: HTMLElement results: HTMLElement combobox: Combobox feedback: HTMLElement | null @@ -21,11 +22,13 @@ export default class Autocomplete { constructor( container: AutocompleteElement, input: HTMLInputElement, + tokenizedInput: HTMLElement, results: HTMLElement, autoselectEnabled = false ) { this.container = container this.input = input + this.tokenizedInput = tokenizedInput this.results = results this.combobox = new Combobox(input, results) this.feedback = document.getElementById(`${this.results.id}-feedback`) @@ -61,7 +64,9 @@ export default class Autocomplete { this.interactingWithList = false - this.onInputChange = debounce(this.onInputChange.bind(this), 300) + // Change this so the results are more instant - remove debounce? + // this.onInputChange = debounce(this.onInputChange.bind(this), 300) + this.onInputChange = this.onInputChange.bind(this) this.onResultsMouseDown = this.onResultsMouseDown.bind(this) this.onInputBlur = this.onInputBlur.bind(this) this.onInputFocus = this.onInputFocus.bind(this) @@ -96,6 +101,10 @@ export default class Autocomplete { this.updateFeedbackForScreenReaders('Results hidden.') } + if (this.tokenizedInput) { + this.tokenizedInput.textContent = '' + } + this.input.value = '' this.container.value = '' this.input.focus() @@ -162,7 +171,32 @@ export default class Autocomplete { this.interactingWithList = true } - onInputChange(): void { + onInputChange(event: Event): void { + if (this.tokenizedInput) { + this.tokenizedInput.textContent = '' + } + + const inputValue = (event.target as any).value + const tokens = inputValue.split(' ') + + for (const token of tokens) { + const tokenItem = document.createElement('span') + const tokenItemSpace = document.createElement('span') + tokenItemSpace.textContent = ' ' + + if (token.includes(':')) { + tokenItem.setAttribute('data-input-type', 'token') + tokenItem.style.border = '1px solid hotpink' + } else { + tokenItem.setAttribute('data-input-type', 'text') + } + + // TODO: If a selection is made from the list, replace the visual div with the contents + tokenItem.textContent = `${token}` + this.tokenizedInput?.appendChild(tokenItem) + this.tokenizedInput?.appendChild(tokenItemSpace) + } + if (this.feedback && this.feedback.textContent) { this.feedback.textContent = '' }