Vue

by khamer

HTML

<div id="app">
  <button>before</button>
  <nav>
    <a href="#link1" v-kbindex:a="">Link 1</a>
    <a href="#link2" v-kbindex:a="">Link 2</a>
    <a href="#link3" v-kbindex:a="">Link 3</a>
    <a href="#link4" v-kbindex:a="">Link 4</a>
  </nav>
  <button>after</button>
  <nav>
    <a href="#link1" v-kbindex:b="">Link 1</a>
    <a href="#link2" v-kbindex:b="">Link 2</a>
    <a href="#link3" v-kbindex:b="">Link 3</a>
    <a href="#link4" v-kbindex:b="">Link 4</a>
  </nav>
  <button>blah</button>
</div>

SCSS

html {
        background-color: #111;
      }
      body {
        background-color: #fff;
        margin: 3vmin;
        padding: 3vmin;
      }

Vue

Vue.directive('kbindex', (() => {
  let indices = {}

  const createIndex = (index, el) => {
    indices[index] = {
      elements: [ el ],
      add(el) {
        this.elements.push(el)
        el.setAttribute('tabindex', -1)
      },
      focus({ target }) {
        this.elements.forEach(el => {
          if (el === target) {
          	el.setAttribute('tabindex', 0)
          } else {
            el.setAttribute('tabindex', -1)
          }
        })
      },
      handler({ key, target }) {
        const l = this.elements.length;
        let i = this.elements.indexOf(target);

        if (key == 'ArrowLeft') {
          i -= 1
        } else if (key == 'ArrowRight') {
          i += 1
        } else {
          return
        }

        let el = this.elements[(i + l) % l]

        el.setAttribute('tabindex', 0)
        target.setAttribute('tabindex', -1)
        el.focus()
      }
    }
  }

  return {
    bind(el, { arg: index }) {
      if (index in indices) {
        indices[index].add(el)
      } else {
        createIndex(index, el)
      }

      console.log(index)

      el.addEventListener('keyup', evt => indices[index].handler(evt))
      el.addEventListener('focus', evt => indices[index].focus(evt))
    }
  }
})())

new Vue({
  el: "#app",
})