This commit is contained in:
Khairul Haaziq 2023-06-23 09:09:11 +08:00
parent ac762b050d
commit 2b92a14cf9
30 changed files with 537 additions and 107 deletions

View File

@ -9,6 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@headlessui-float/vue": "^0.11.2",
"@headlessui/vue": "^1.7.14",
"vue": "^3.2.47"
},

View File

@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
'@headlessui-float/vue':
specifier: ^0.11.2
version: 0.11.2(vue@3.3.4)
'@headlessui/vue':
specifier: ^1.7.14
version: 1.7.14(vue@3.3.4)
@ -263,6 +266,43 @@ packages:
dev: true
optional: true
/@floating-ui/core@1.3.1:
resolution: {integrity: sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==}
dev: false
/@floating-ui/dom@1.4.2:
resolution: {integrity: sha512-VKmvHVatWnewmGGy+7Mdy4cTJX71Pli6v/Wjb5RQBuq5wjUYx+Ef+kRThi8qggZqDgD8CogCpqhRoVp3+yQk+g==}
dependencies:
'@floating-ui/core': 1.3.1
dev: false
/@floating-ui/vue@0.2.1(vue@3.3.4):
resolution: {integrity: sha512-HE+EIeakID7wI6vUwF0yMpaW48bNaPj8QtnQaRMkaQFhQReVBA4bY6fmJ3J7X+dqVgDbMhyfCG0fBJfdQMdWxQ==}
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^2.0.0 || >=3.0.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
'@floating-ui/dom': 1.4.2
vue: 3.3.4
vue-demi: 0.13.11(vue@3.3.4)
dev: false
/@headlessui-float/vue@0.11.2(vue@3.3.4):
resolution: {integrity: sha512-9yWN6LHeaXZKyU9y/rj6SmujCzkRxxf4bhg7nRs2RSwfSRI9E+JPvM/Tl7AA2lFQAJegWTRcElt3dSJ0Nkth0Q==}
peerDependencies:
vue: ^3.0.0
dependencies:
'@floating-ui/core': 1.3.1
'@floating-ui/dom': 1.4.2
'@floating-ui/vue': 0.2.1(vue@3.3.4)
vue: 3.3.4
transitivePeerDependencies:
- '@vue/composition-api'
dev: false
/@headlessui/vue@1.7.14(vue@3.3.4):
resolution: {integrity: sha512-aL9U9Sa7wdOzlrfjx6EjMIYNRCma5mngWcWzQBcHFwznpRZ8g/QZ/AYFtRDrZZUw22Ttttja4D7ZRXFwhONewA==}
engines: {node: '>=10'}
@ -1131,6 +1171,21 @@ packages:
fsevents: 2.3.2
dev: true
/vue-demi@0.13.11(vue@3.3.4):
resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
vue: 3.3.4
dev: false
/vue-template-compiler@2.7.14:
resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
dependencies:

View File

@ -1,41 +1,92 @@
<script setup lang="ts">
import { ref } from 'vue';
import { Accordion, AccordionTrigger, AccordionItem, AccordionContent } from './components/Accordion'
import { Alert, AlertDescription, AlertTitle } from './components/Alert'
import { Card as InternalCard } from './components/Internal/Docs/Card'
import { TransitionExpand } from '@morev/vue-transitions';
import { ref, computed } from "vue";
import {
Accordion,
AccordionTrigger,
AccordionItem,
AccordionContent,
} from "./components/Accordion";
import { Alert, AlertDescription, AlertTitle } from "./components/Alert";
import { Card as InternalCard } from "./components/Internal/Docs/Card";
import { TransitionExpand } from "@morev/vue-transitions";
import { Icon } from "@iconify/vue";
import { Button } from './components/Button'
import { AlertDialog, AlertDialogTitle, AlertDialogHeader, AlertDialogDescription, AlertDialogFooter } from './components/AlertDialog'
import { Avatar, AvatarFallback, AvatarImage } from './components/Avatar'
import { Badge } from './components/Badge'
import { Checkbox } from './components/Checkbox'
import { Label } from './components/Label'
import { Input } from './components/Input'
import { Textarea } from './components/Textarea'
import { Switch } from './components/Switch'
import { Toggle } from './components/Toggle'
import { Card } from './components/Demos'
import { AspectRatio } from './components/AspectRatio'
import { Button } from "./components/Button";
import {
AlertDialog,
AlertDialogTitle,
AlertDialogHeader,
AlertDialogDescription,
AlertDialogFooter,
} from "./components/AlertDialog";
import { Avatar, AvatarFallback, AvatarImage } from "./components/Avatar";
import { Badge } from "./components/Badge";
import { Checkbox } from "./components/Checkbox";
import { Label } from "./components/Label";
import { Input } from "./components/Input";
import { Textarea } from "./components/Textarea";
import { Switch } from "./components/Switch";
import { Toggle } from "./components/Toggle";
import { Card } from "./components/Demos";
import { AspectRatio, Image } from "./components/AspectRatio";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "./components/Collapsible";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectLabel,
} from "./components/Select";
import { Float } from "@headlessui-float/vue";
import { Popover, PopoverContent, PopoverTrigger } from "./components/Popover";
import { Separator } from "./components/Separator";
const alertDialogIsOpen = ref(false)
const enabled = ref(false)
const checkboxEnabled = ref(false)
const checkboxEnabled2 = ref(false)
const toggleEnabled = ref(false)
const alertDialogIsOpen = ref(false);
const enabled = ref(false);
const checkboxEnabled = ref(false);
const checkboxEnabled2 = ref(false);
const toggleEnabled = ref(false);
const collapsibleIsOpen = ref(false);
const people = [
{ id: 1, name: "Durward Reynolds", unavailable: false },
{ id: 2, name: "Kenton Towne", unavailable: false },
{ id: 3, name: "Therese Wunsch", unavailable: false },
{ id: 4, name: "Benedict Kessler", unavailable: true },
{ id: 5, name: "Katelyn Rohan", unavailable: false },
];
const selectedPerson = ref(people[0]);
const people2 = [
"Durward Reynolds",
"Kenton Towne",
"Therese Wunsch",
"Benedict Kessler",
"Katelyn Rohan",
];
const selectedPerson2 = ref(people[0]);
const query = ref("");
const filteredPeople = computed(() =>
query.value === ""
? people
: people.filter((person) => {
return person.toLowerCase().includes(query.value.toLowerCase());
})
);
</script>
<template>
<div class="flex justify-center px-6">
<div class="grid grid-cols-3 max-w-6xl gap-4 w-full mt-10">
<InternalCard title="Accordion">
<div class="w-full max-w-[400px]">
<Accordion>
<AccordionItem>
<AccordionTrigger>
Is it accessible?
</AccordionTrigger>
<AccordionTrigger> Is it accessible? </AccordionTrigger>
<transition-expand>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design pattern.
@ -43,19 +94,16 @@ const toggleEnabled = ref(false)
</transition-expand>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>
Is it styled?
</AccordionTrigger>
<AccordionTrigger> Is it styled? </AccordionTrigger>
<transition-expand>
<AccordionContent>
Yes. It comes with default styles that matches the other components' aesthetic.
Yes. It comes with default styles that matches the other components'
aesthetic.
</AccordionContent>
</transition-expand>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>
Is it animated?
</AccordionTrigger>
<AccordionTrigger> Is it animated? </AccordionTrigger>
<transition-expand>
<AccordionContent>
Yes. It's animated by default, but you can disable it if you prefer.
@ -68,7 +116,7 @@ const toggleEnabled = ref(false)
<InternalCard title="Alert">
<div class="max-w-[400px]">
<Alert>
<Icon icon="lucide:terminal" className="h-4 w-4" />
<Icon icon="lucide:terminal" class="h-4 w-4" />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components to your app using the cli.
@ -82,8 +130,8 @@ const toggleEnabled = ref(false)
<AlertDialogHeader>
<AlertDialogTitle>Title</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
This action cannot be undone. This will permanently delete your account and
remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter><Button variant="outline"
@ -92,14 +140,11 @@ const toggleEnabled = ref(false)
</AlertDialog>
</InternalCard>
<InternalCard title="Aspect Ratio">
<AspectRatio ratio="16/9" class="bg-muted">
<img
src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
alt="Photo by Drew Beamer"
fill
class="rounded-md object-cover"
/>
</AspectRatio></InternalCard>
<AspectRatio :ratio="16 / 9" class="bg-muted">
<Image src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
alt="Photo by Drew Beamer" fill class="rounded-md object-cover" />
</AspectRatio>
</InternalCard>
<InternalCard title="Avatar">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
@ -117,15 +162,40 @@ const toggleEnabled = ref(false)
<Card />
</InternalCard>
<InternalCard title="Checkbox">
<div className="flex items-center space-x-2">
<Checkbox id="terms" v-model="checkboxEnabled"/>
<div class="flex items-center space-x-2">
<Checkbox id="terms" v-model="checkboxEnabled" />
<label htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Accept terms and conditions
</label>
</div>
</InternalCard>
<InternalCard title="Collapsible"></InternalCard>
<InternalCard title="Collapsible">
<Collapsible class="w-[350px] space-y-2" v-slot="{ open }">
<div class="flex items-center justify-between space-x-4 px-4">
<h4 class="text-sm font-semibold">@peduarte starred 3 repositories</h4>
<CollapsibleTrigger>
<Button variant="outline" class="w-9 p-0 aspect-square">
<span>
<Icon v-show="open" icon="lucide:chevrons-up-down" class="h-4 w-4 text-black" />
<Icon v-show="!open" icon="lucide:x" class="h-4 w-4 text-black" />
</span>
</Button>
</CollapsibleTrigger>
</div>
<div class="rounded-md border px-4 py-3 font-mono text-sm">
@radix-ui/primitives
</div>
<CollapsibleContent class="space-y-2">
<div class="rounded-md border px-4 py-3 font-mono text-sm">
@radix-ui/colors
</div>
<div class="rounded-md border px-4 py-3 font-mono text-sm">
@stitches/react
</div>
</CollapsibleContent>
</Collapsible>
</InternalCard>
<InternalCard title="Combobox"></InternalCard>
<InternalCard title="Command"></InternalCard>
<InternalCard title="Context Menu"></InternalCard>
@ -138,24 +208,84 @@ const toggleEnabled = ref(false)
<Input type="email" placeholder="Email" />
</InternalCard>
<InternalCard title="Label">
<div className="flex items-center space-x-2">
<Checkbox id="terms2" v-model="checkboxEnabled2"/>
<div class="flex items-center space-x-2">
<Checkbox id="terms2" v-model="checkboxEnabled2" />
<Label htmlFor="terms2">Accept terms and conditions</Label>
</div>
</InternalCard>
<InternalCard title="Menubar"></InternalCard>
<InternalCard title="Navigation Menu"></InternalCard>
<InternalCard title="Popover"></InternalCard>
<InternalCard title="Popover">
<Popover>
<PopoverTrigger><Button variant="outline">Open popover</Button></PopoverTrigger>
<PopoverContent class="w-80">
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">Dimensions</h4>
<p class="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
<div class="grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label htmlFor="width">Width</Label>
<Input id="width" defaultValue="100%" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxWidth">Max. width</Label>
<Input id="maxWidth" defaultValue="300px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label htmlFor="height">Height</Label>
<Input id="height" defaultValue="25px" class="col-span-2 h-8" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label htmlFor="maxHeight">Max. height</Label>
<Input id="maxHeight" defaultValue="none" class="col-span-2 h-8" />
</div>
</div>
</div>
</PopoverContent>
</Popover>
</InternalCard>
<InternalCard title="Progress"></InternalCard>
<InternalCard title="Radio Group"></InternalCard>
<InternalCard title="Scroll Area"></InternalCard>
<InternalCard title="Select"></InternalCard>
<InternalCard title="Separator"></InternalCard>
<InternalCard title="Select">
<Select v-model="selectedPerson">
<SelectTrigger class="w-[180px]">
{{ selectedPerson.name }}
</SelectTrigger>
<SelectContent>
<SelectLabel>Fruits</SelectLabel>
<SelectItem v-for="person in people" :key="person.id" :value="person"
:disabled="person.unavailable">{{ person.name }}</SelectItem>
</SelectContent>
</Select>
</InternalCard>
<InternalCard title="Separator">
<div>
<div className="space-y-1">
<h4 className="text-sm font-medium leading-none">Radix Primitives</h4>
<p className="text-sm text-muted-foreground">
An open-source UI component library.
</p>
</div>
<Separator class="my-4" />
<div className="flex h-5 items-center space-x-4 text-sm">
<div>Blog</div>
<Separator orientation="vertical" />
<div>Docs</div>
<Separator orientation="vertical" />
<div>Source</div>
</div>
</div>
</InternalCard>
<InternalCard title="Sheet"></InternalCard>
<InternalCard title="Skeleton"></InternalCard>
<InternalCard title="Slider"></InternalCard>
<InternalCard title="Switch">
<div className="flex items-center space-x-2">
<div class="flex items-center space-x-2">
<Switch id="airplane-mode" v-model="enabled" />
<Label htmlFor="airplane-mode">Airplane Mode</Label>
</div>
@ -166,10 +296,10 @@ const toggleEnabled = ref(false)
<InternalCard title="Toast"></InternalCard>
<InternalCard title="Toggle">
<Toggle aria-label="Toggle italic" v-model="toggleEnabled">
<Icon icon="lucide:bold" className="h-4 w-4" />
<Icon icon="lucide:bold" class="h-4 w-4" />
</Toggle>
</InternalCard>
<InternalCard title="Tooltip"></InternalCard>
</div>
</div>
</template>
</template>

View File

@ -1,17 +1,18 @@
<template>
<div class="relative w-full pb-[50%] overflow-clip">
<div class="absolute inset-0">
<slot />
</div>
</div></template>
<div :class="`relative w-full`" :style="`padding-bottom: ${aspect}%`">
<div class="absolute inset-0">
<slot />
</div>
</div>
</template>
<script setup>
import {computed} from 'vue'
import { computed } from "vue";
const props = defineProps({
ratio: String
})
ratio: Number,
});
const aspect = computed(()=>{
return
})
</script>
const aspect = computed(() => {
return 1/props.ratio*100;
});
</script>

View File

@ -0,0 +1,3 @@
<template>
<img style="position: absolute; height: 100%; width: 100%; inset: 0px; color: transparent;" />
</template>

View File

@ -1 +1,2 @@
export { default as AspectRatio } from "./AspectRatio.vue";
export { default as Image } from "./Image.vue";

View File

@ -0,0 +1,9 @@
<template>
<Disclosure as="div" v-slot="{ open }">
<slot :open="open"></slot>
</Disclosure>
</template>
<script setup>
import { Disclosure } from "@headlessui/vue"
</script>

View File

@ -0,0 +1,11 @@
<template>
<DisclosurePanel class="overflow-hidden text-sm">
<slot />
</DisclosurePanel>
</template>
<script setup>
import {
DisclosurePanel,
} from '@headlessui/vue'
</script>

View File

@ -0,0 +1,9 @@
<template>
<DisclosureButton as="template">
<slot />
</DisclosureButton>
</template>
<script setup lang="ts">
import { DisclosureButton } from "@headlessui/vue";
</script>

View File

@ -0,0 +1,3 @@
export { default as Collapsible } from "./Collapsible.vue";
export { default as CollapsibleContent } from "./CollapsibleContent.vue";
export { default as CollapsibleTrigger } from "./CollapsibleTrigger.vue";

View File

@ -0,0 +1,44 @@
<template>
<Listbox v-model="isOpen" v-slot="{ open }">
<Float
portal
placement="bottom"
flip
strategy="fixed"
adaptive-width
enter="transition duration-200 ease-out"
enter-from="scale-95 opacity-0"
enter-to="scale-100 opacity-100"
leave="transition duration-150 ease-in"
leave-from="scale-100 opacity-100"
leave-to="scale-95 opacity-0"
tailwindcss-origin-class
:offset="4"
as="div"
class="relative mt-1"
>
<slot :open="open"></slot>
</Float>
</Listbox>
</template>
<script setup>
import { ref, computed } from "vue";
import { Listbox } from "@headlessui/vue";
import { Float } from "@headlessui-float/vue";
const props = defineProps({
modelValue: Boolean,
});
const emit = defineEmits(["update:modelValue", "close"]);
const isOpen = computed({
get() {
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});
</script>

View File

@ -0,0 +1,16 @@
<template>
<ListboxButton v-slot="{ open }"
class="flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
<span>
<slot />
</span>
<Icon icon="lucide:chevron-down" :class="`h-4 w-4 opacity-50 transition-all ${open ? 'rotate-180' : ''}`" />
</ListboxButton>
</template>
<script setup>
import {
ListboxButton,
} from '@headlessui/vue'
import { Icon } from "@iconify/vue";
</script>

View File

@ -0,0 +1,24 @@
<template>
<ListboxOption v-slot="{ active, selected, disabled }" as="template">
<li :class="[
active ? 'bg-accent text-accent-foreground' : 'text-gray-900',
disabled ? 'opacity-50 pointer-events-none' : 'text-gray-900',
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
]">
<span v-if="selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<Icon icon="lucide:check" class="h-[14px] w-[14px]" aria-hidden="true" />
</span>
<span>
<slot />
</span>
</li>
</ListboxOption>
</template>
<script setup>
import {
ListboxOption,
} from '@headlessui/vue'
import { Icon } from "@iconify/vue";
</script>

View File

@ -0,0 +1,12 @@
<template>
<ListboxOptions
class="w-full min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md p-1 focus:outline-none">
<slot />
</ListboxOptions>
</template>
<script setup>
import {
ListboxOptions,
} from '@headlessui/vue'
</script>

View File

@ -0,0 +1,4 @@
export { default as Combobox } from "./Combobox.vue";
export { default as ComboboxInput } from "./ComboboxInput.vue";
export { default as ComboboxOptions } from "./ComboboxOptions.vue";
export { default as ComboboxOption } from "./ComboboxOption.vue";

View File

@ -1,12 +1,11 @@
<template>
<input
:class="props.class"
class="flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" />
</template>
<script setup>
const props = defineProps({
class: String,
id: String,
htmlFor: String
})
</script>

View File

@ -0,0 +1,15 @@
<template>
<Popover v-slot="{ open }">
<Float composable placement="bottom" flip strategy="fixed" enter="transition duration-200 ease-out"
enter-from="scale-95 opacity-0" enter-to="scale-100 opacity-100" leave="transition duration-150 ease-in"
leave-from="scale-100 opacity-100" leave-to="scale-95 opacity-0" tailwindcss-origin-class :offset="6" as="div"
class="relative">
<slot :open="open"/>
</Float>
</Popover>
</template>
<script setup>
import { Popover } from "@headlessui/vue";
import { Float } from "@headlessui-float/vue";
</script>

View File

@ -0,0 +1,13 @@
<template>
<FloatContent>
<PopoverPanel
class="z-50 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-80">
<slot />
</PopoverPanel>
</FloatContent>
</template>
<script setup>
import { PopoverPanel } from "@headlessui/vue";
import { FloatContent } from "@headlessui-float/vue";
</script>

View File

@ -0,0 +1,10 @@
<template>
<FloatReference>
<PopoverButton><slot /></PopoverButton>
</FloatReference>
</template>
<script setup>
import { PopoverButton } from "@headlessui/vue";
import { FloatReference } from "@headlessui-float/vue";
</script>

View File

@ -0,0 +1,3 @@
export { default as Popover } from "./Popover.vue";
export { default as PopoverContent } from "./PopoverContent.vue";
export { default as PopoverTrigger } from "./PopoverTrigger.vue";

View File

@ -1,9 +1,44 @@
<template>
<div>
<slot />
</div>
<Listbox v-model="isOpen" v-slot="{ open }">
<Float
portal
placement="bottom"
flip
strategy="fixed"
adaptive-width
enter="transition duration-200 ease-out"
enter-from="scale-95 opacity-0"
enter-to="scale-100 opacity-100"
leave="transition duration-150 ease-in"
leave-from="scale-100 opacity-100"
leave-to="scale-95 opacity-0"
tailwindcss-origin-class
:offset="4"
as="div"
class="relative mt-1"
>
<slot :open="open"></slot>
</Float>
</Listbox>
</template>
<script setup>
import { ref, computed } from "vue";
import { Listbox } from "@headlessui/vue";
import { Float } from "@headlessui-float/vue";
</script>
const props = defineProps({
modelValue: Boolean,
});
const emit = defineEmits(["update:modelValue", "close"]);
const isOpen = computed({
get() {
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});
</script>

View File

@ -1,9 +1,12 @@
<template>
<div>
<slot />
</div>
<ListboxOptions
class="w-full min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md p-1 focus:outline-none">
<slot />
</ListboxOptions>
</template>
<script setup>
import {
ListboxOptions,
} from '@headlessui/vue'
</script>

View File

@ -1,9 +0,0 @@
<template>
<div>
<slot />
</div>
</template>
<script setup>
</script>

View File

@ -1,9 +1,24 @@
<template>
<div>
<slot />
</div>
<ListboxOption v-slot="{ active, selected, disabled }" as="template">
<li :class="[
active ? 'bg-accent text-accent-foreground' : 'text-gray-900',
disabled ? 'opacity-50 pointer-events-none' : 'text-gray-900',
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
]">
<span v-if="selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<Icon icon="lucide:check" class="h-[14px] w-[14px]" aria-hidden="true" />
</span>
<span>
<slot />
</span>
</li>
</ListboxOption>
</template>
<script setup>
import {
ListboxOption,
} from '@headlessui/vue'
import { Icon } from "@iconify/vue";
</script>

View File

@ -1,9 +1,15 @@
<template>
<div>
<div class="py-1.5 pl-8 pr-2 text-sm font-semibold">
<ListboxLabel>
<slot />
</div>
</ListboxLabel>
</div>
</template>
<script setup>
import {
ListboxLabel,
} from '@headlessui/vue'
</script>

View File

@ -1,9 +1,16 @@
<template>
<div>
<slot />
</div>
<ListboxButton v-slot="{ open }"
class="flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
<span>
<slot />
</span>
<Icon icon="lucide:chevron-down" :class="`h-4 w-4 opacity-50 transition-all ${open ? 'rotate-180' : ''}`" />
</ListboxButton>
</template>
<script setup>
import {
ListboxButton,
} from '@headlessui/vue'
import { Icon } from "@iconify/vue";
</script>

View File

@ -1,9 +0,0 @@
<template>
<div>
<slot />
</div>
</template>
<script setup>
</script>

View File

@ -0,0 +1,5 @@
export { default as Select } from "./Select.vue";
export { default as SelectContent } from "./SelectContent.vue";
export { default as SelectTrigger } from "./SelectTrigger.vue";
export { default as SelectItem } from "./SelectItem.vue";
export { default as SelectLabel } from "./SelectLabel.vue";

View File

@ -0,0 +1,13 @@
<template>
<div :class="`shrink-0 bg-border ${props.orientation == 'vertical' ? 'w-[1px] h-full' : 'w-full h-[1px]'}`"></div>
</template>
<script setup>
const props = defineProps({
orientation: {
type: String,
required: false,
default: "horizontal"
}
})
</script>

View File

@ -0,0 +1 @@
export {default as Separator} from './Separator.vue'