tailwindlabs / tailwindui-vue

Deprecated, please use the Headless UI repo instead.
https://github.com/tailwindlabs/headlessui/
647 stars 29 forks source link

Feat/multi select listbox #11

Closed visualjerk closed 3 years ago

visualjerk commented 4 years ago

Hi @adamwathan

First of all, thanks for the great work you are doing with tailwind and the idea of putting out a renderless component library.

I have been dreaming about this for a while and hope it will become reality. It would really solve a lot of headaches developers have when trying to implement component libraries for design systems. No more overwriting styles or starting from scratch over and over again 😄

If you like, I would be happy to contribute to this project.

This PR implements the minimal requirement for multiple listboxes according to W3C.

It can be used like so:

<template>
  <div>
    <Listbox v-model="selectedWrestlerIds" v-slot="{ isOpen }" multiple>
      <ListboxLabel class="sr-only">Select a wrestler:</ListboxLabel>
      <ListboxButton class="rounded p-3 border flex space-x-2">
        <span v-if="!selectedWrestlers.length">Select a wrestler ...</span>
        <span v-for="wrestler in selectedWrestlers" :key="wrestler.id">
          <span class="flex items-center">
            <img :src="wrestler.image" class="rounded-full h-6 mr-2" />
            {{ wrestler.name }}
          </span>
        </span>
      </ListboxButton>
      <ListboxList v-show="isOpen" class="max-w-sm">
        <ListboxOption
          v-for="wrestler in wrestlers"
          :key="wrestler.id"
          :value="wrestler.id"
          v-slot="{ isActive, isSelected }"
        >
          <div
            class="p-3 pl-2 flex items-center"
            :class="
              isActive ? 'bg-blue-600 text-white' : 'bg-white text-gray-900'
            "
          >
            <span class="w-4 mr-1">
              <svg
                v-show="isSelected"
                class="h-4"
                fill="none"
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                <path d="M5 13l4 4L19 7" />
              </svg>
            </span>
            <span class="flex items-center">
              <img :src="wrestler.image" class="rounded-full h-6 mr-2" />
              {{ wrestler.name }}
            </span>
          </div>
        </ListboxOption>
      </ListboxList>
    </Listbox>
  </div>
</template>

<script>
import {
  Listbox,
  ListboxLabel,
  ListboxButton,
  ListboxList,
  ListboxOption,
} from '@tailwindui/vue'

export default {
  components: {
    Listbox,
    ListboxLabel,
    ListboxButton,
    ListboxList,
    ListboxOption,
  },
  computed: {
    selectedWrestlers() {
      return this.wrestlers.filter(({ id }) =>
        this.selectedWrestlerIds.includes(id)
      )
    },
  },
  data() {
    return {
      selectedWrestlerIds: ['d6107793-33dc-484e-8678-f118fea0e6c5'],
      wrestlers: [
        {
          id: 'd6107793-33dc-484e-8678-f118fea0e6c5',
          name: 'The Ultimate Warrior',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/johncafazza/128.jpg',
        },
        {
          id: '05c72ddd-3fa2-4956-805a-66b9a9277c7c',
          name: 'Randy Savage',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/elliotlewis/128.jpg',
        },
        {
          id: '7c67a6cb-7a35-408b-8c61-89c922801598',
          name: 'Hulk Hogan',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/mfacchinello/128.jpg',
        },
        {
          id: '6ba6378a-dd0f-4df5-a763-6ed86ef9bbf4',
          name: 'Bret Hart',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/ilya_pestov/128.jpg',
        },
        {
          id: '9dd3c940-89da-4fb0-a1da-5e817981224a',
          name: 'The Undertaker',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/alessandroribe/128.jpg',
        },
        {
          id: 'a3cf02cb-d0f0-41a6-a8b8-ec69496e4d80',
          name: 'Mr. Perfect',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/geshan/128.jpg',
        },
        {
          id: '4c7e5ff4-5798-4e95-a3d9-9e4e5d95ce78',
          name: 'Ted DiBiase',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/johnriordan/128.jpg',
        },
        {
          id: 'a0a5d758-806f-4ca8-8e06-322b3ec9c7f9',
          name: 'Bam Bam Bigelow',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/lhausermann/128.jpg',
        },
        {
          id: '769d693c-e4b5-4620-bf40-0170866f1693',
          name: 'Yokozuna',
          image:
            'https://s3.amazonaws.com/uifaces/faces/twitter/marcobarbosa/128.jpg',
        },
      ],
    }
  },
}
</script>
visualjerk commented 4 years ago

@adamwathan quick update:

I added a test suite to ensure the existing behavior is not affected and fixed some minor bugs in the process.

There is still a lot of untested behavior, but I will work on that in the next days.

If you think this is too much, we can also get rid of the last commit and just have the changes for multi listbox in the PR.

mitchbne commented 4 years ago

@adamwathan are you able to have a look over this one and merge it in, please?

RobinMalfait commented 3 years ago

Hey! I'm deprecating this repository in favor of the Headless UI repo. If this PR is still applicable, please re-open the PR in the new repository. Thank you!