<text-expander>

back edit

This demo implements a custom expander for emoticons, triggered by !.

<text-expander keys="!" class="position-relative">
  <textarea class="form-control width-full" autofocus></textarea>
  <ul class="js-emoticons suggestions suggester position-absolute" style="z-index: 1;" hidden>
    <li role="option" data-value="/ᐠ。ꞈ。ᐟ\___ ∫">Cat <small class="ml-2">/ᐠ。ꞈ。ᐟ\___ ∫</small></li>
    <li role="option" data-value="U・ᴥ・U">Dog <small class="ml-2">U・ᴥ・U</small></li>
    <li role="option" data-value="¯\_(ツ)_/¯">Shrug <small class="ml-2">¯\_(ツ)_/¯</small></li>
    <li role="option" data-value="(╯°□°)╯︵ ┻━┻">Table flip <small class="ml-2">(╯°□°)╯︵ ┻━┻</small></li>
  </ul>
</text-expander>

When the key is matched, provide filtered suggestions:

const expander = document.querySelector('text-expander')

expander.addEventListener('text-expander-change', function(event) {
  const {key, provide, text} = event.detail
  if (key !== '!') return

  const suggestions = document.querySelector('.js-emoticons').cloneNode(true)
  suggestions.hidden = false
  const unmatched = Array.from(suggestions.children).filter(suggestion => {
    return !suggestion.textContent.toLowerCase().includes(text.toLowerCase())
  })
  for (const suggestion of unmatched) {
    suggestion.remove()
  }
  provide(Promise.resolve({matched: suggestions.childElementCount > 0, fragment: suggestions}))
})

When a suggestion is selected, provide the snippet to expand with:

expander.addEventListener('text-expander-value', function(event) {
  const {key, item}  = event.detail
  if (key === '!') {
    event.detail.value = item.getAttribute('data-value')
  }
})