feat: Add the new select menu component (#10445)
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import SelectMenu from './SelectMenu.vue';
|
||||
|
||||
const sampleOptions = [
|
||||
{ label: 'Option 1', value: 'option1' },
|
||||
{ label: 'Option 2', value: 'option2' },
|
||||
{ label: 'Option 3', value: 'option3' },
|
||||
{ label: 'Option 4', value: 'option4' },
|
||||
];
|
||||
|
||||
const selectedValue = ref('option1');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/SelectMenu"
|
||||
:layout="{ type: 'grid', width: '400px' }"
|
||||
>
|
||||
<Variant title="Default">
|
||||
<div class="flex flex-col gap-4 p-4 h-[400px]">
|
||||
<SelectMenu
|
||||
v-model="selectedValue"
|
||||
:options="sampleOptions"
|
||||
:label="sampleOptions.find(opt => opt.value === selectedValue)?.label"
|
||||
/>
|
||||
<div class="text-sm">Selected value: {{ selectedValue }}</div>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="With Many Options">
|
||||
<div class="flex flex-col gap-4 p-4 h-[400px]">
|
||||
<SelectMenu
|
||||
v-model="selectedValue"
|
||||
:options="
|
||||
Array.from({ length: 10 }, (_, i) => ({
|
||||
label: `Option ${i + 1}`,
|
||||
value: `value${i + 1}`,
|
||||
}))
|
||||
"
|
||||
label="Select from many"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
@@ -0,0 +1,71 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const isOpen = ref(false);
|
||||
|
||||
const labelValue = computed(() => props.label);
|
||||
|
||||
const toggleMenu = () => {
|
||||
isOpen.value = !isOpen.value;
|
||||
};
|
||||
|
||||
const handleSelect = value => {
|
||||
emit('update:modelValue', value);
|
||||
isOpen.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-on-clickaway="() => (isOpen = false)"
|
||||
class="relative flex flex-col gap-1 w-fit"
|
||||
>
|
||||
<Button
|
||||
icon="i-lucide-chevron-down"
|
||||
size="sm"
|
||||
trailing-icon
|
||||
color="slate"
|
||||
variant="faded"
|
||||
class="!w-fit"
|
||||
:class="{ 'dark:!bg-n-alpha-2 !bg-n-slate-9/20': isOpen }"
|
||||
:label="labelValue"
|
||||
@click="toggleMenu"
|
||||
/>
|
||||
<div
|
||||
v-if="isOpen"
|
||||
class="absolute ltr:left-full rtl:right-full select-none max-w-48 ltr:ml-1 rtl:mr-1 flex flex-col gap-1 bg-n-alpha-3 backdrop-blur-[100px] p-1 top-0 shadow-lg rounded-lg border border-n-weak"
|
||||
>
|
||||
<Button
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:icon="option.value === modelValue ? 'i-lucide-check' : ''"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
color="slate"
|
||||
trailing-icon
|
||||
class="!justify-end !px-2.5 !h-7"
|
||||
:class="{ '!bg-n-alpha-2': option.value === modelValue }"
|
||||
@click="handleSelect(option.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user