JSFiddle - React, Tailwind, and code Playground

by Daedalus

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
  <div id="app">
    <div class="row">
      <div class="col">
        Item Selection
        <select class="custom-select" multiple size="5" v-model="selected">
          <option :value="1">1</option>
          <option :value="2">2</option>
          <option :value="3">3</option>
          <option :value="4">4</option>
          <option :value="5">5</option>
        </select>
        <button type="button" class="btn btn-primary" @click="addItem">
          Add item at selected size
        </button>
      </div>
      <div class="col">
        Max selections: <input type="number" v-model.number="max" :max="4" :min="1" /><br />
        Remaining selections: {{remaining}}
        <div>
          Active Item:
        </div>
        <div v-if="item !== null">
          <select class="custom-select" multiple size="5" v-model="item.selected" @mousedown.left="prepareFix" @mouseup.left="fixSelected">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
            <option :value="4">4</option>
            <option :value="5">5</option>
          </select>
        </div>
      </div>
    </div>
  </div>

JavaScript

window.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: "#app",
    data: {
      item: null,
      selected: [],
      max: 4
    },
    methods: {
      addItem() {
        if (this.item === null) {
          let selected = this.selected.slice(0);
          if (this.remaining - selected.length < 0) {
            selected = selected.slice(0, this.remaining);
          }
          this.item = {
            selected
          }
        }
      },
      prepareFix() {
      	this.item.currentlySelected = this.item.selected.length;
      },
      fixSelected() {
      	if (this.remaining - (this.currentlySelected + this.item.selected.length) < 0) {
        	this.item.selected.slice(0, this.remaining);
        }
      }
    },
    computed: {
    	remaining() {
      	if (this.item === null) {
        	return this.max;
        } else {
        	return this.max - this.item.selected.length;
        }
      }
    }
  })
});