Skip to content

Instantly share code, notes, and snippets.

@iErik
Created June 6, 2018 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iErik/cc76783a1a0dfbfd9d52b8025868efa0 to your computer and use it in GitHub Desktop.
Save iErik/cc76783a1a0dfbfd9d52b8025868efa0 to your computer and use it in GitHub Desktop.
<template>
<c-input-container v-bind="$attrs" :class="classes" :validation="isOpened ? '' : validation">
<div class="input" @click="toggle" v-click-outside="outside">
<span class="selected">{{ selected ? selected[displayBy] : placeholder || value }}</span>
<c-icon size="15" class="icon" icon="chevron-down" />
</div>
<div v-if="isOpened" class="items">
<div
class="item"
v-for="(item, index) in items"
:key="index"
@click="select(index)"
>
<span class="text">{{ item[displayBy] }}</span>
</div>
</div>
</c-input-container>
</template>
<script>
import CInputContainer from '@/components/CComponents/CInputContainer'
import CIcon from '@/components/CComponents/CIcon'
export default {
components: { CInputContainer, CIcon },
data() {
return {
isOpened: false,
selected: null
}
},
props: {
items: {
type: Array,
required: true
},
value: [String, Number],
trackBy: String,
displayBy: {
type: String,
default: 'name'
},
placeholder: String,
clearOnSelect: Boolean,
validation: String,
success: Boolean
},
computed: {
classes () {
const classes = [ 'c-select', {
'-is-opened': this.isOpened,
'-has-validation': this.validation || this.success,
'-success': this.success
}]
return classes
}
},
methods: {
outside (e) {
this.isOpened = false
},
clear () {
this.clearOnSelect ? this.itemSelected = '' : this.itemSelected
},
toggle () {
this.isOpened = !this.isOpened
},
select (index) {
this.selected = this.items[index]
const tracked = this.trackBy ? this.selected[this.trackBy] : this.selected
this.$emit('input', tracked)
}
},
directives: {
'click-outside': {
bind: function(el, binding, vNode) {
const handler = (e) => {
if (!el.contains(e.target) && el !== e.target) {
binding.value(e)
}
}
el.__vueClickOutside__ = handler
document.addEventListener('click', handler)
},
unbind: function(el, binding) {
document.removeEventListener('click', el.__vueClickOutside__)
el.__vueClickOutside__ = null
}
}
}
}
</script>
<style lang="scss">
@import '~@/styles/reference';
.c-select {
position: relative;
& > .input {
position: relative;
border: 1px solid $border-color;
display: flex;
align-items: center;
min-height: 40px;
background-color: white;
border-radius: 3px;
font-size: 16px;
transition: border-color .3s ease, box-shadow .3s ease;
cursor: pointer;
& > .selected {
padding: {
left: 10px;
right: 35px;
}
}
& > .icon {
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
transition: transform 500ms ease;
}
&:hover,
&:active,
&:focus {
border-color: $secondary-color-placeholder;
border-color: var(--color-secondary);
box-shadow: 0 0 0 2px $secondary-color-placeholder;
box-shadow: 0 0 0 2px var(--color-secondary);
}
}
.items {
z-index: 1;
width: 100%;
box-sizing: border-box;
background-color: #fff;
position: absolute;
left: 0;
top: 100%;
& > .item {
cursor: pointer;
border: 1px solid $border-color;
border-top: none;
min-height: 40px;
display: flex;
align-items: center;
& > .text {
transition: color .3s ease;
padding: 10px;
}
&:hover > .text {
color: $primary-color-placeholder;
color: var(--color-primary);
}
}
}
&.-is-opened { @extend %c-select-opened; }
}
%c-select-opened {
& > .input {
border-radius: 3px 3px 0 0;
& > .entry > .icon { transform: translateY(-50%) rotate(-180deg); }
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment