Last active
September 18, 2018 04:25
-
-
Save reed-jones/9cb84f93a0cc87c20c6c1089b6c26006 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// demo | |
// https://codesandbox.io/s/o3my2rxxy | |
<template lang="pug"> | |
.wrapper(v-click-outside='_ => opened = false') | |
input.dropdown( | |
type='text' | |
ref='inputBox' | |
@click='opened = !opened' | |
@keydown.prevent='' | |
@keydown.tab='pressTab' | |
@keydown.up="navigate(highlighted - 1)" | |
@keydown.down="navigate(highlighted + 1)" | |
@keydown.enter="pressEnter" | |
:value='(value.label || value)' | |
) | |
.options(v-if='opened') | |
.option( | |
v-for='(option, idx) in options' | |
@click='selectOption(option)' | |
:class='{ | |
active: (option.value || option) === value, | |
highlighted: idx === highlighted | |
}') | |
| {{ option.label || option }} | |
</template> | |
<script> | |
export default { | |
props: { | |
options: { | |
type: Array, | |
required: true, | |
validator: arr => arr.length | |
}, | |
value: { | |
type: String|Number, | |
default: function() { return this.options[0] } | |
} | |
}, | |
directives: { | |
clickOutside: { | |
bind(el, binding, vnode) { | |
window.addEventListener('click', e => { | |
if (!el.contains(e.target)) { | |
return binding.value(e) | |
} | |
}) | |
} | |
} | |
}, | |
data: _ => ({ | |
opened: false, | |
highlighted: 0 | |
}), | |
created() { | |
let value = this.options.find(o => o.value === (this.value.value || this.value)) || this.value | |
this.$emit('input', value) | |
}, | |
methods: { | |
selectOption(option) { | |
this.$emit('input', option) | |
this.highlighted = this.options.indexOf(option) | |
this.opened = false | |
}, | |
navigate(num) { | |
if (!this.opened) { | |
this.opened = true | |
} else { | |
this.highlighted = (this.options.length + num) % this.options.length | |
} | |
}, | |
pressEnter() { | |
if (!this.opened) { | |
this.opened = true | |
this.highlighted = 0 | |
} else { | |
this.selectOption(this.options[this.highlighted]) | |
} | |
}, | |
pressTab() { | |
if(!this.opened) { | |
this.$refs.inputBox.blur() | |
} else { | |
this.selectOption(this.options[this.highlighted]); | |
} | |
} | |
} | |
} | |
</script> | |
<style lang="stylus"> | |
height = 2rem | |
half = .5rem | |
back = #000 | |
border = 1px solid black | |
.wrapper | |
display flex | |
align-items flex-start | |
justify-content flex-start | |
position relative | |
width 150px | |
&:after | |
content '' | |
transition .15s | |
position absolute | |
right half | |
top .75rem | |
bottom 0 | |
width half | |
height half | |
opacity 0 | |
pointer-events none | |
border-left border | |
border-bottom border | |
transform rotate(-45deg) | |
&:focus-within:after, | |
&:hover:after | |
opacity 1 | |
.dropdown | |
padding 0 half | |
border border | |
position relative | |
width 100% | |
height height | |
color transparent | |
text-shadow 0 0 0 black | |
cursor pointer | |
user-select none | |
&::selection | |
background transparent | |
.options | |
border border | |
width 100% | |
position absolute | |
top height | |
margin 0 auto | |
.option | |
padding half | |
border border | |
cursor pointer | |
color transparent | |
text-shadow 0 0 0 black | |
user-select none | |
&::selection | |
background transparent | |
&.active | |
background #eee | |
&.highlighted, | |
&:hover | |
background #888 | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment