Make DropdownSelect component
This commit is contained in:
parent
1a41fe4f10
commit
c35b5cce70
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {reactive} from 'vue'
|
|
||||||
import {Menu, MenuButton, MenuItems, MenuItem} from '@headlessui/vue'
|
import {Menu, MenuButton, MenuItems, MenuItem} from '@headlessui/vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { watch, onMounted, reactive, defineEmits, computed } from 'vue'
|
||||||
|
import {Listbox, ListboxButton, ListboxOption, ListboxOptions} from '@headlessui/vue';
|
||||||
|
|
||||||
|
export interface DropdownSelectable {
|
||||||
|
id: number|string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/64775876/vue-3-pass-reactive-object-to-component-with-two-way-binding
|
||||||
|
export interface Props {
|
||||||
|
modelValue: {
|
||||||
|
id: string|number
|
||||||
|
name: string
|
||||||
|
},
|
||||||
|
items: DropdownSelectable[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', data: object): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
modelValue: {
|
||||||
|
id: -1,
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const dropdownSelected = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Listbox as="div" v-model="dropdownSelected">
|
||||||
|
<div class="mt-1 relative w-128">
|
||||||
|
<ListboxButton
|
||||||
|
class="bg-white relative w-full border border-gray-500 pl-5 pr-10 py-3 text-left cursor-default font-bold">
|
||||||
|
<span class="block truncate">{{ dropdownSelected.name }}</span>
|
||||||
|
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||||
|
<it-icon-arrow-down class="h-5 w-5" aria-hidden="true"/>
|
||||||
|
</span>
|
||||||
|
</ListboxButton>
|
||||||
|
|
||||||
|
<transition leave-active-class="transition ease-in duration-100" leave-from-class="opacity-100"
|
||||||
|
leave-to-class="opacity-0">
|
||||||
|
<ListboxOptions
|
||||||
|
class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
|
||||||
|
<ListboxOption
|
||||||
|
as="template"
|
||||||
|
v-for="item in items"
|
||||||
|
:key="item.id"
|
||||||
|
:value="item"
|
||||||
|
v-slot="{ active, selected }">
|
||||||
|
<li
|
||||||
|
:class="[active ? 'text-white bg-blue-900' : 'text-black', 'cursor-default select-none relative py-2 pl-3 pr-9']">
|
||||||
|
<span :class="[dropdownSelected ? 'font-semibold' : 'font-normal', 'block truncate']">
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="dropdownSelected"
|
||||||
|
class="text-blue-900 absolute inset-y-0 right-0 flex items-center pr-4">
|
||||||
|
<it-icon-check
|
||||||
|
v-if="selected"
|
||||||
|
class="h-5 w-5"
|
||||||
|
aria-hidden="true"/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ListboxOption>
|
||||||
|
</ListboxOptions>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</Listbox>
|
||||||
|
</template>
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LinkCard from "@/components/mediacenter/LinkCard.vue";
|
|
||||||
import HandlungsfeldLayout from "@/views/HandlungsfeldLayout.vue";
|
import HandlungsfeldLayout from "@/views/HandlungsfeldLayout.vue";
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {reactive} from 'vue'
|
import {reactive} from 'vue'
|
||||||
import {Listbox, ListboxButton, ListboxOption, ListboxOptions} from '@headlessui/vue'
|
|
||||||
import ItCheckbox from '@/components/ui/ItCheckbox.vue';
|
import ItCheckbox from '@/components/ui/ItCheckbox.vue';
|
||||||
import ItDropdown from "@/components/ui/ItDropdown.vue";
|
import ItDropdown from "@/components/ui/ItDropdown.vue";
|
||||||
import IconLogout from "@/components/icons/IconLogout.vue"
|
import IconLogout from "@/components/icons/IconLogout.vue"
|
||||||
import IconSettings from "@/components/icons/IconSettings.vue"
|
import IconSettings from "@/components/icons/IconSettings.vue"
|
||||||
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
|
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
|
@ -22,7 +22,10 @@ const state = reactive({
|
||||||
{id: 9, name: 'Claudie Smitham'},
|
{id: 9, name: 'Claudie Smitham'},
|
||||||
{id: 10, name: 'Emil Schaefer'},
|
{id: 10, name: 'Emil Schaefer'},
|
||||||
],
|
],
|
||||||
dropdownSelected: {id: 8},
|
dropdownSelected: {
|
||||||
|
id: -1,
|
||||||
|
name: 'Select a name'
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const dropdownData = [
|
const dropdownData = [
|
||||||
|
|
@ -294,38 +297,11 @@ function log(data: any) {
|
||||||
|
|
||||||
<h2 class="mt-8 mb-8">Dropdown (Work-in-progress)</h2>
|
<h2 class="mt-8 mb-8">Dropdown (Work-in-progress)</h2>
|
||||||
|
|
||||||
<Listbox as="div" v-model="state.dropdownSelected">
|
<ItDropdownSelect
|
||||||
<div class="mt-1 relative w-128">
|
v-model="state.dropdownSelected"
|
||||||
<ListboxButton
|
:items="state.dropdownValues">
|
||||||
class="bg-white relative w-full border border-gray-500 pl-5 pr-10 py-3 text-left cursor-default font-bold">
|
</ItDropdownSelect>
|
||||||
<span class="block truncate">{{ state.dropdownSelected.name }}</span>
|
{{state.dropdownSelected}}
|
||||||
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
|
||||||
<it-icon-arrow-down class="h-5 w-5" aria-hidden="true"/>
|
|
||||||
</span>
|
|
||||||
</ListboxButton>
|
|
||||||
|
|
||||||
<transition leave-active-class="transition ease-in duration-100" leave-from-class="opacity-100"
|
|
||||||
leave-to-class="opacity-0">
|
|
||||||
<ListboxOptions
|
|
||||||
class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
|
|
||||||
<ListboxOption as="template" v-for="person in state.dropdownValues" :key="person.id" :value="person"
|
|
||||||
v-slot="{ active, selected }">
|
|
||||||
<li
|
|
||||||
:class="[active ? 'text-white bg-blue-900' : 'text-black', 'cursor-default select-none relative py-2 pl-3 pr-9']">
|
|
||||||
<span :class="[state.dropdownSelected ? 'font-semibold' : 'font-normal', 'block truncate']">
|
|
||||||
{{ person.name }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-if="state.dropdownSelected"
|
|
||||||
:class="[active ? 'text-white' : 'text-blue-900', 'absolute inset-y-0 right-0 flex items-center pr-4']">
|
|
||||||
<it-icon-check class="h-5 w-5" aria-hidden="true"/>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ListboxOption>
|
|
||||||
</ListboxOptions>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</Listbox>
|
|
||||||
|
|
||||||
<h2 class="mt-8 mb-8">Checkbox</h2>
|
<h2 class="mt-8 mb-8">Checkbox</h2>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue