summaryrefslogblamecommitdiffstats
path: root/webapp/src/components/SelectBox.vue
blob: 4fe4593795bce19e704440028d56384ad44e0208 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                   






                                                                                                                              











                                                                         
                                                                                
                   
                                                                                                                                     
              
                                                                                                                                            
            
              








                                         


               












                                              
                       


                  
                       


















                     













                    



                    

















                                                                                















                                                                                                     











                                               












                                                                   
                   


                      




                           

                       
                   



                          



                     


                     


          




                          















                                 


                     

        
<i18n>
{
  "en": {
    "name": "Name",
    "more": "more"
  },
  "de": {
    "name": "Name",
    "more": "mehr"
  }
}
</i18n>

<template>
  <v-input class="v-text-field select-input" :class="inputClasses" :hide-details="hideDetails" :prepend-icon="prependIcon">
    <v-menu v-model="menu" offset-y :close-on-content-click="false" lazy class="select-menu non-selectable" :nudge-bottom="1">
      <div slot="activator" class="select-input-content">
        <label v-if="label !== undefined && (!singleLine || (singleLine && value.length === 0))"
          class="select-label v-label"
          :class="labelClasses"
        >{{ label }}</label>
        <div class="select-input-chips">
          <v-chip
            class="item-chip"
            :style="{ width: 'calc(' + (100 / maxColumns) + '% - 8px)' }"
            v-for="(item, index) in value"
            :key="item[idKey]"
            v-if="index < maxShow"
            small
            label
            close
            @input="removeItem(index)"
          >
            <div class="select-input-chip-text">{{ item.name || item.id }}</div>
          </v-chip>
          <span v-if="value.length > maxShow" class="text--secondary and-more">+ {{ value.length - maxShow }} {{ $t('more') }}</span>
        </div>
        <v-icon class="select-input-arrow" :class="{ 'expand-arrow-flipped': menu }" :color="menu ? 'primary' : ''">arrow_drop_down</v-icon>
      </div>
      <v-card>
        <data-table
          :value="value"
          @input="$emit('input', $event)"
          :headers="headers"
          :items="items"
          slim
          :row-count="6"
          :single-select="singleSelect"
        ></data-table>
      </v-card>
    </v-menu>
  </v-input>
</template>

<script>
import DataTable from '@/components/DataTable'

export default {
  name: 'SelectBox',
  components: {
    DataTable
  },
  props: {
    value: {
      type: Array,
      default: () => []
    },
    items: {
      type: Array,
      default: () => []
    },
    idKey: {
      type: String,
      default: 'id'
    },
    textKey: {
      type: String,
      default: 'name'
    },
    textHeading: {
      type: String
    },
    maxColumns: {
      type: Number,
      default: 2
    },
    maxRows: {
      type: Number,
      default: 3
    },
    label: {
      type: String
    },
    hideDetails: {
      type: Boolean,
      default: false
    },
    singleLine: {
      type: Boolean,
      default: false
    },
    prependIcon: {
      type: String
    },
    singleSelect: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      menu: false
    }
  },
  computed: {
    maxShow () {
      return this.maxColumns * this.maxRows - 1
    },
    computedTextHeading () {
      return this.textHeading === undefined ? this.$t('name') : this.textHeading
    },
    headers () {
      return [
        { key: this.textKey, text: this.computedTextHeading }
      ]
    },
    inputClasses () {
      const classes = {}
      if (this.menu) {
        classes['primary--text'] = true
        classes['v-input--is-label-active'] = true
        classes['v-input--is-focused'] = true
      }
      if (this.singleLine) classes['single-line'] = true
      return classes
    },
    labelClasses () {
      const classes = {}
      if (!this.menu || this.singleLine) classes['text--secondary'] = true
      if (!this.singleLine && (this.menu || this.value.length > 0)) classes['v-label--active'] = true
      return classes
    }
  },
  watch: {
    value () {
      window.dispatchEvent(new Event('resize'))
    }
  },
  methods: {
    removeItem (index) {
      const newValue = this.value.slice(0)
      newValue.splice(index, 1)
      this.$emit('input', newValue)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.select-menu {
  width: 100%;
  overflow: hidden;
}

.select-input {
  margin-bottom: 0;
  padding-bottom: 1px;
}

.select-input.single-line {
  margin-top: 0;
  padding-top: 0;
}

.select-input-content {
  width: 100%;
  min-height: 32px;
  display: flex;
  align-items: flex-start;
}

.select-input-arrow {
  margin-top: 4px
}

.select-input-chips {
  display: flex;
  flex-wrap: wrap;
  flex: 1;
}

.select-input-chip-text {
  overflow: hidden;
  text-overflow: ellipsis;
}

.item-chip >>> .v-chip__content {
  width: 100%;
  cursor: pointer;
}

.expand-arrow-flipped {
  transform: rotate(180deg);
}

.and-more {
  font-size: 13px;
  display: flex;
  align-items: center;
  margin: 4px 17px;
}

.select-label {
  position: absolute;
  left: 0;
}
</style>