refactor: ⬆️ Upgrade to Tailwind v4

This commit is contained in:
Jesse Wierzbinski 2025-04-10 13:55:56 +02:00
parent 14d283c7a8
commit b6080eff60
No known key found for this signature in database
160 changed files with 1187 additions and 1178 deletions

View file

@ -13,7 +13,7 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<AlertDialogRoot v-bind="forwarded">
<AlertDialogRoot data-slot="alert-dialog" v-bind="forwarded">
<slot />
</AlertDialogRoot>
</template>

View file

@ -27,13 +27,15 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<AlertDialogPortal>
<AlertDialogOverlay
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
data-slot="alert-dialog-overlay"
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80"
/>
<AlertDialogContent
data-slot="alert-dialog-content"
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
'bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
props.class,
)
"

View file

@ -19,8 +19,9 @@ const delegatedProps = computed(() => {
<template>
<AlertDialogDescription
data-slot="alert-dialog-description"
v-bind="delegatedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</AlertDialogDescription>

View file

@ -9,9 +9,10 @@ const props = defineProps<{
<template>
<div
data-slot="alert-dialog-footer"
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
props.class,
)
"

View file

@ -9,7 +9,8 @@ const props = defineProps<{
<template>
<div
:class="cn('flex flex-col gap-y-2 text-center sm:text-left', props.class)"
data-slot="alert-dialog-header"
:class="cn('flex flex-col gap-2 text-center sm:text-left', props.class)"
>
<slot />
</div>

View file

@ -16,6 +16,7 @@ const delegatedProps = computed(() => {
<template>
<AlertDialogTitle
data-slot="alert-dialog-title"
v-bind="delegatedProps"
:class="cn('text-lg font-semibold', props.class)"
>

View file

@ -5,7 +5,7 @@ const props = defineProps<AlertDialogTriggerProps>();
</script>
<template>
<AlertDialogTrigger v-bind="props">
<AlertDialogTrigger data-slot="alert-dialog-trigger" v-bind="props">
<slot />
</AlertDialogTrigger>
</template>

View file

@ -10,7 +10,11 @@ const props = defineProps<{
</script>
<template>
<div :class="cn(alertVariants({ variant }), props.class)" role="alert">
<div
data-slot="alert"
:class="cn(alertVariants({ variant }), props.class)"
role="alert"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('text-sm [&_p]:leading-relaxed', props.class)">
<div
data-slot="alert-description"
:class="cn('text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed', props.class)"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<h5 :class="cn('mb-1 font-medium leading-none tracking-tight', props.class)">
<div
data-slot="alert-title"
:class="cn('col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight', props.class)"
>
<slot />
</h5>
</div>
</template>

View file

@ -5,15 +5,13 @@ export { default as AlertDescription } from "./AlertDescription.vue";
export { default as AlertTitle } from "./AlertTitle.vue";
export const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg]:size-4",
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
{
variants: {
variant: {
default: "bg-background text-foreground",
default: "bg-card text-card-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
warning:
"border-warning/50 text-warning dark:border-warning [&>svg]:text-warning",
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
},
},
defaultVariants: {

View file

@ -2,23 +2,17 @@
import { cn } from "@/lib/utils";
import { AvatarRoot } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { type AvatarVariants, avatarVariant } from ".";
const props = withDefaults(
defineProps<{
class?: HTMLAttributes["class"];
size?: AvatarVariants["size"];
shape?: AvatarVariants["shape"];
}>(),
{
size: "sm",
shape: "circle",
},
);
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>
<template>
<AvatarRoot :class="cn(avatarVariant({ size, shape }), props.class)">
<AvatarRoot
data-slot="avatar"
:class="cn('relative flex size-8 shrink-0 overflow-hidden rounded-full', props.class)"
>
<slot />
</AvatarRoot>
</template>

View file

@ -1,11 +1,25 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { AvatarFallback, type AvatarFallbackProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<AvatarFallbackProps>();
const props = defineProps<
AvatarFallbackProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<AvatarFallback v-bind="props">
<AvatarFallback
data-slot="avatar-fallback"
v-bind="delegatedProps"
:class="cn('bg-muted flex size-full items-center justify-center rounded-full', props.class)"
>
<slot />
</AvatarFallback>
</template>

View file

@ -6,7 +6,11 @@ const props = defineProps<AvatarImageProps>();
</script>
<template>
<AvatarImage v-bind="props" class="h-full w-full object-cover">
<AvatarImage
data-slot="avatar-image"
v-bind="props"
class="aspect-square size-full"
>
<slot />
</AvatarImage>
</template>

View file

@ -1,24 +1,3 @@
import { type VariantProps, cva } from "class-variance-authority";
export { default as Avatar } from "./Avatar.vue";
export { default as AvatarFallback } from "./AvatarFallback.vue";
export { default as AvatarImage } from "./AvatarImage.vue";
export const avatarVariant = cva(
"inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden",
{
variants: {
size: {
sm: "h-10 w-10 text-xs",
base: "h-16 w-16 text-2xl",
lg: "h-32 w-32 text-5xl",
},
shape: {
circle: "rounded-full",
square: "rounded-md",
},
},
},
);
export type AvatarVariants = VariantProps<typeof avatarVariant>;

View file

@ -1,16 +1,30 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
import type { PrimitiveProps } from "reka-ui";
import { Primitive } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { type BadgeVariants, badgeVariants } from ".";
const props = defineProps<{
variant?: BadgeVariants["variant"];
class?: HTMLAttributes["class"];
}>();
const props = defineProps<
PrimitiveProps & {
variant?: BadgeVariants["variant"];
class?: HTMLAttributes["class"];
}
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<div :class="cn(badgeVariants({ variant }), props.class)">
<Primitive
data-slot="badge"
:class="cn(badgeVariants({ variant }), props.class)"
v-bind="delegatedProps"
>
<slot />
</div>
</Primitive>
</template>

View file

@ -3,17 +3,18 @@ import { type VariantProps, cva } from "class-variance-authority";
export { default as Badge } from "./Badge.vue";
export const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},
},
defaultVariants: {
@ -21,5 +22,4 @@ export const badgeVariants = cva(
},
},
);
export type BadgeVariants = VariantProps<typeof badgeVariants>;

View file

@ -17,6 +17,7 @@ const props = withDefaults(defineProps<Props>(), {
<template>
<Primitive
data-slot="button"
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"

View file

@ -1,29 +1,28 @@
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import { type VariantProps, cva } from "class-variance-authority";
export { default as Button } from "./Button.vue";
export const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground hover:bg-primary/90",
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
},
},
defaultVariants: {

View file

@ -8,14 +8,11 @@ const props = defineProps<{
</script>
<template>
<div
:class="
cn(
'rounded-lg border bg-card text-card-foreground shadow-sm flex flex-col gap-6 p-4 items-center justify-center',
props.class
)
"
>
<div data-slot="card" :class="cn(
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
props.class,
)
">
<slot />
</div>
</template>

View file

@ -0,0 +1,17 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>
<template>
<div
data-slot="card-action"
:class="cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', props.class)"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('flex flex-col gap-2', props.class)">
<slot />
</div>
<div
data-slot="card-content"
:class="cn('px-6', props.class)"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<p :class="cn('text-sm text-muted-foreground', props.class)">
<p
data-slot="card-description"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</p>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('flex items-center', props.class)">
<slot />
</div>
<div
data-slot="card-footer"
:class="cn('flex items-center px-6 [.border-t]:pt-6', props.class)"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('flex flex-col gap-y-1.5', props.class)">
<slot />
</div>
<div
data-slot="card-header"
:class="cn('@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6', props.class)"
>
<slot />
</div>
</template>

View file

@ -9,9 +9,8 @@ const props = defineProps<{
<template>
<h3
:class="
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
"
data-slot="card-title"
:class="cn('leading-none font-semibold', props.class)"
>
<slot />
</h3>

View file

@ -1,4 +1,5 @@
export { default as Card } from "./Card.vue";
export { default as CardAction } from "./CardAction.vue";
export { default as CardContent } from "./CardContent.vue";
export { default as CardDescription } from "./CardDescription.vue";
export { default as CardFooter } from "./CardFooter.vue";

View file

@ -21,14 +21,18 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<CheckboxRoot
data-slot="checkbox"
v-bind="forwarded"
:class="
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
cn('peer border-input data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
props.class)"
>
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
<CheckboxIndicator
data-slot="checkbox-indicator"
class="flex items-center justify-center text-current transition-none"
>
<slot>
<Check class="h-4 w-4" />
<Check class="size-3.5" />
</slot>
</CheckboxIndicator>
</CheckboxRoot>

View file

@ -9,7 +9,11 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<CollapsibleRoot v-slot="{ open }" v-bind="forwarded">
<CollapsibleRoot
v-slot="{ open }"
data-slot="collapsible"
v-bind="forwarded"
>
<slot :open="open" />
</CollapsibleRoot>
</template>

View file

@ -5,7 +5,10 @@ const props = defineProps<CollapsibleContentProps>();
</script>
<template>
<CollapsibleContent v-bind="props" class="overflow-hidden transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down">
<CollapsibleContent
data-slot="collapsible-content"
v-bind="props"
>
<slot />
</CollapsibleContent>
</template>

View file

@ -5,7 +5,10 @@ const props = defineProps<CollapsibleTriggerProps>();
</script>
<template>
<CollapsibleTrigger v-bind="props">
<CollapsibleTrigger
data-slot="collapsible-trigger"
v-bind="props"
>
<slot />
</CollapsibleTrigger>
</template>

View file

@ -61,7 +61,7 @@ function filterItems() {
// Check which groups have at least 1 item shown
for (const [groupId, group] of allGroups.value) {
for (const itemId of group) {
if (filterState.filtered.items.get(itemId)) {
if ((filterState.filtered.items.get(itemId) ?? 0) > 0) {
filterState.filtered.groups.add(groupId);
break;
}
@ -90,15 +90,11 @@ provideCommandContext({
</script>
<template>
<ListboxRoot
v-bind="forwarded"
:class="
cn(
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
props.class
)
"
>
<slot />
</ListboxRoot>
<ListboxRoot
data-slot="command"
v-bind="forwarded"
:class="cn('bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md', props.class)"
>
<slot />
</ListboxRoot>
</template>

View file

@ -1,10 +1,27 @@
<script setup lang="ts">
import { Dialog, DialogContent } from "@/components/ui/dialog";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import type { DialogRootEmits, DialogRootProps } from "reka-ui";
import { useForwardPropsEmits } from "reka-ui";
import Command from "./Command.vue";
const props = defineProps<DialogRootProps>();
const props = withDefaults(
defineProps<
DialogRootProps & {
title?: string;
description?: string;
}
>(),
{
title: "Command Palette",
description: "Search for a command to run...",
},
);
const emits = defineEmits<DialogRootEmits>();
const forwarded = useForwardPropsEmits(props, emits);
@ -12,8 +29,12 @@ const forwarded = useForwardPropsEmits(props, emits);
<template>
<Dialog v-bind="forwarded">
<DialogContent class="overflow-hidden p-0 shadow-lg">
<Command class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
<DialogHeader class="sr-only">
<DialogTitle>{{ title }}</DialogTitle>
<DialogDescription>{{ description }}</DialogDescription>
</DialogHeader>
<DialogContent class="overflow-hidden p-0 ">
<Command>
<slot />
</Command>
</DialogContent>

View file

@ -22,7 +22,11 @@ const isRender = computed(
</script>
<template>
<Primitive v-if="isRender" v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
<Primitive
v-if="isRender"
data-slot="command-empty"
v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)"
>
<slot />
</Primitive>
</template>

View file

@ -37,23 +37,16 @@ onUnmounted(() => {
</script>
<template>
<ListboxGroup
v-bind="delegatedProps"
:id="id"
:class="
cn(
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
props.class
)
"
:hidden="isRender ? undefined : true"
>
<ListboxGroupLabel
v-if="heading"
class="px-2 py-1.5 text-xs font-medium text-muted-foreground"
>
{{ heading }}
</ListboxGroupLabel>
<slot />
</ListboxGroup>
<ListboxGroup
v-bind="delegatedProps"
:id="id"
data-slot="command-group"
:class="cn('text-foreground overflow-hidden p-1', props.class)"
:hidden="isRender ? undefined : true"
>
<ListboxGroupLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
{{ heading }}
</ListboxGroupLabel>
<slot />
</ListboxGroup>
</template>

View file

@ -31,13 +31,17 @@ const { filterState } = useCommand();
</script>
<template>
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
<Search class="mr-2 h-4 w-4 shrink-0 opacity-50" />
<div
data-slot="command-input-wrapper"
class="flex h-12 items-center gap-2 border-b px-3"
>
<Search class="size-4 shrink-0 opacity-50" />
<ListboxFilter
v-bind="{ ...forwardedProps, ...$attrs }"
v-model="filterState.search"
data-slot="command-input"
auto-focus
:class="cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
:class="cn('placeholder:text-muted-foreground flex h-12 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50', props.class)"
/>
</div>
</template>

View file

@ -73,23 +73,17 @@ onUnmounted(() => {
</script>
<template>
<ListboxItem
v-if="isRender"
v-bind="forwarded"
:id="id"
ref="itemRef"
:class="
cn(
'relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0',
props.class
)
"
@select="
() => {
filterState.search = '';
}
"
>
<slot />
</ListboxItem>
<ListboxItem
v-if="isRender"
v-bind="forwarded"
:id="id"
ref="itemRef"
data-slot="command-item"
:class="cn(`data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-3 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, props.class)"
@select="() => {
filterState.search = ''
}"
>
<slot />
</ListboxItem>
</template>

View file

@ -18,7 +18,11 @@ const forwarded = useForwardProps(delegatedProps);
</script>
<template>
<ListboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
<ListboxContent
data-slot="command-list"
v-bind="forwarded"
:class="cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', props.class)"
>
<div role="presentation">
<slot />
</div>

View file

@ -17,8 +17,9 @@ const delegatedProps = computed(() => {
<template>
<Separator
data-slot="command-separator"
v-bind="delegatedProps"
:class="cn('-mx-1 h-px bg-border', props.class)"
:class="cn('bg-border -mx-1 h-px', props.class)"
>
<slot />
</Separator>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<span :class="cn('ml-auto text-xs tracking-widest text-muted-foreground', props.class)">
<span
data-slot="command-shortcut"
:class="cn('text-muted-foreground ml-auto text-xs tracking-widest', props.class)"
>
<slot />
</span>
</template>

View file

@ -13,7 +13,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DialogRoot v-bind="forwarded">
<DialogRoot
data-slot="dialog"
v-bind="forwarded"
>
<slot />
</DialogRoot>
</template>

View file

@ -5,7 +5,10 @@ const props = defineProps<DialogCloseProps>();
</script>
<template>
<DialogClose v-bind="props">
<DialogClose
data-slot="dialog-close"
v-bind="props"
>
<slot />
</DialogClose>
</template>

View file

@ -6,17 +6,14 @@ import {
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import DialogOverlay from "./DialogOverlay.vue";
const props = defineProps<
DialogContentProps & {
class?: HTMLAttributes["class"];
hideClose?: boolean;
}
DialogContentProps & { class?: HTMLAttributes["class"] }
>();
const emits = defineEmits<DialogContentEmits>();
@ -30,28 +27,25 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
/>
<DialogContent
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class
)
"
>
<slot />
<DialogPortal>
<DialogOverlay />
<DialogContent
data-slot="dialog-content"
v-bind="forwarded"
:class="
cn(
'bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
props.class,
)"
>
<slot />
<DialogClose
v-if="!hideClose"
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
<DialogClose
class="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<X />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
</template>

View file

@ -22,8 +22,9 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<DialogDescription
data-slot="dialog-description"
v-bind="forwardedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</DialogDescription>

View file

@ -7,12 +7,8 @@ const props = defineProps<{ class?: HTMLAttributes["class"] }>();
<template>
<div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"
data-slot="dialog-footer"
:class="cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', props.class)"
>
<slot />
</div>

View file

@ -9,7 +9,8 @@ const props = defineProps<{
<template>
<div
:class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)"
data-slot="dialog-header"
:class="cn('flex flex-col gap-2 text-center sm:text-left', props.class)"
>
<slot />
</div>

View file

@ -0,0 +1,25 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { DialogOverlay, type DialogOverlayProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
DialogOverlayProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<DialogOverlay
data-slot="dialog-overlay"
v-bind="delegatedProps"
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
>
<slot />
</DialogOverlay>
</template>

View file

@ -29,7 +29,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
>
<DialogContent
:class="
@ -50,7 +50,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<slot />
<DialogClose
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>

View file

@ -18,13 +18,9 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<DialogTitle
data-slot="dialog-title"
v-bind="forwardedProps"
:class="
cn(
'text-lg font-semibold leading-none tracking-tight',
props.class,
)
"
:class="cn('text-lg leading-none font-semibold', props.class)"
>
<slot />
</DialogTitle>

View file

@ -5,7 +5,10 @@ const props = defineProps<DialogTriggerProps>();
</script>
<template>
<DialogTrigger v-bind="props">
<DialogTrigger
data-slot="dialog-trigger"
v-bind="props"
>
<slot />
</DialogTrigger>
</template>

View file

@ -4,6 +4,7 @@ export { default as DialogContent } from "./DialogContent.vue";
export { default as DialogDescription } from "./DialogDescription.vue";
export { default as DialogFooter } from "./DialogFooter.vue";
export { default as DialogHeader } from "./DialogHeader.vue";
export { default as DialogOverlay } from "./DialogOverlay.vue";
export { default as DialogScrollContent } from "./DialogScrollContent.vue";
export { default as DialogTitle } from "./DialogTitle.vue";
export { default as DialogTrigger } from "./DialogTrigger.vue";

View file

@ -13,7 +13,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DrawerRoot v-bind="forwarded">
<DrawerRoot
data-slot="drawer"
v-bind="forwarded"
>
<slot />
</DrawerRoot>
</template>

View file

@ -0,0 +1,15 @@
<script lang="ts" setup>
import type { DrawerCloseProps } from "vaul-vue";
import { DrawerClose } from "vaul-vue";
const props = defineProps<DrawerCloseProps>();
</script>
<template>
<DrawerClose
data-slot="drawer-close"
v-bind="props"
>
<slot />
</DrawerClose>
</template>

View file

@ -18,12 +18,18 @@ const forwarded = useForwardPropsEmits(props, emits);
<DrawerPortal>
<DrawerOverlay />
<DrawerContent
v-bind="forwarded" :class="cn(
'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
data-slot="drawer-content"
v-bind="forwarded"
:class="cn(
`group/drawer-content bg-background fixed z-50 flex h-auto flex-col`,
`data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg`,
`data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg`,
`data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:sm:max-w-sm`,
`data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:sm:max-w-sm`,
props.class,
)"
>
<div class="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
<div class="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
<slot />
</DrawerContent>
</DrawerPortal>

View file

@ -16,7 +16,11 @@ const delegatedProps = computed(() => {
</script>
<template>
<DrawerDescription v-bind="delegatedProps" :class="cn('text-sm text-muted-foreground', props.class)">
<DrawerDescription
data-slot="drawer-description"
v-bind="delegatedProps"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</DrawerDescription>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('mt-auto flex flex-col gap-2 p-4', props.class)">
<div
data-slot="drawer-footer"
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)"
>
<slot />
</div>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('grid gap-1.5 p-4 text-center sm:text-left', props.class)">
<div
data-slot="drawer-header"
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
>
<slot />
</div>
</template>

View file

@ -16,5 +16,9 @@ const delegatedProps = computed(() => {
</script>
<template>
<DrawerOverlay v-bind="delegatedProps" :class="cn('fixed inset-0 z-50 bg-black/80', props.class)" />
<DrawerOverlay
data-slot="drawer-overlay"
v-bind="delegatedProps"
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
/>
</template>

View file

@ -16,7 +16,11 @@ const delegatedProps = computed(() => {
</script>
<template>
<DrawerTitle v-bind="delegatedProps" :class="cn('text-lg font-semibold leading-none tracking-tight', props.class)">
<DrawerTitle
data-slot="drawer-title"
v-bind="delegatedProps"
:class="cn('text-foreground font-semibold', props.class)"
>
<slot />
</DrawerTitle>
</template>

View file

@ -0,0 +1,15 @@
<script lang="ts" setup>
import type { DrawerTriggerProps } from "vaul-vue";
import { DrawerTrigger } from "vaul-vue";
const props = defineProps<DrawerTriggerProps>();
</script>
<template>
<DrawerTrigger
data-slot="drawer-trigger"
v-bind="props"
>
<slot />
</DrawerTrigger>
</template>

View file

@ -1,8 +1,9 @@
export { default as Drawer } from "./Drawer.vue";
export { default as DrawerClose } from "./DrawerClose.vue";
export { default as DrawerContent } from "./DrawerContent.vue";
export { default as DrawerDescription } from "./DrawerDescription.vue";
export { default as DrawerFooter } from "./DrawerFooter.vue";
export { default as DrawerHeader } from "./DrawerHeader.vue";
export { default as DrawerOverlay } from "./DrawerOverlay.vue";
export { default as DrawerTitle } from "./DrawerTitle.vue";
export { DrawerClose, DrawerPortal, DrawerTrigger } from "vaul-vue";
export { default as DrawerTrigger } from "./DrawerTrigger.vue";

View file

@ -13,7 +13,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DropdownMenuRoot v-bind="forwarded">
<DropdownMenuRoot
data-slot="dropdown-menu"
v-bind="forwarded"
>
<slot />
</DropdownMenuRoot>
</template>

View file

@ -26,15 +26,16 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DropdownMenuCheckboxItem
data-slot="dropdown-menu-checkbox-item"
v-bind="forwarded"
:class=" cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Check class="w-4 h-4" />
<Check class="size-4" />
</DropdownMenuItemIndicator>
</span>
<slot />

View file

@ -31,8 +31,9 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DropdownMenuPortal>
<DropdownMenuContent
data-slot="dropdown-menu-content"
v-bind="forwarded"
:class="cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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', props.class)"
:class="cn('bg-popover text-popover-foreground 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 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', props.class)"
>
<slot />
</DropdownMenuContent>

View file

@ -5,7 +5,10 @@ const props = defineProps<DropdownMenuGroupProps>();
</script>
<template>
<DropdownMenuGroup v-bind="props">
<DropdownMenuGroup
data-slot="dropdown-menu-group"
v-bind="props"
>
<slot />
</DropdownMenuGroup>
</template>

View file

@ -1,36 +1,39 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { reactiveOmit } from "@vueuse/core";
import {
DropdownMenuItem,
type DropdownMenuItemProps,
useForwardProps,
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import type { HTMLAttributes } from "vue";
const props = defineProps<
DropdownMenuItemProps & { class?: HTMLAttributes["class"]; inset?: boolean }
>();
const props = withDefaults(
defineProps<
DropdownMenuItemProps & {
class?: HTMLAttributes["class"];
inset?: boolean;
variant?: "default" | "destructive";
}
>(),
{
variant: "default",
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const delegatedProps = reactiveOmit(props, "inset", "variant");
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DropdownMenuItem
v-bind="forwardedProps"
:class="
cn(
'relative flex w-full cursor-default select-none items-center rounded-sm gap-2 px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
inset && 'pl-8',
props.class
)
"
>
<slot />
</DropdownMenuItem>
<DropdownMenuItem
data-slot="dropdown-menu-item"
:data-inset="inset ? '' : undefined"
:data-variant="variant"
v-bind="forwardedProps"
:class="cn(`focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/40 data-[variant=destructive]:focus:text-destructive-foreground data-[variant=destructive]:*:[svg]:!text-destructive-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, props.class)"
>
<slot />
</DropdownMenuItem>
</template>

View file

@ -1,11 +1,12 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { reactiveOmit } from "@vueuse/core";
import {
DropdownMenuLabel,
type DropdownMenuLabelProps,
useForwardProps,
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import type { HTMLAttributes } from "vue";
const props = defineProps<
DropdownMenuLabelProps & {
@ -14,19 +15,16 @@ const props = defineProps<
}
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const delegatedProps = reactiveOmit(props, "class", "inset");
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DropdownMenuLabel
data-slot="dropdown-menu-label"
:data-inset="inset ? '' : undefined"
v-bind="forwardedProps"
:class="cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)"
:class="cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', props.class)"
>
<slot />
</DropdownMenuLabel>

View file

@ -13,7 +13,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DropdownMenuRadioGroup v-bind="forwarded">
<DropdownMenuRadioGroup
data-slot="dropdown-menu-radio-group"
v-bind="forwarded"
>
<slot />
</DropdownMenuRadioGroup>
</template>

View file

@ -27,15 +27,16 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DropdownMenuRadioItem
data-slot="dropdown-menu-radio-item"
v-bind="forwarded"
:class="cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Circle class="h-2 w-2 fill-current" />
<Circle class="size-2 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot />

View file

@ -20,5 +20,9 @@ const delegatedProps = computed(() => {
</script>
<template>
<DropdownMenuSeparator v-bind="delegatedProps" :class="cn('-mx-1 my-1 h-px bg-muted', props.class)" />
<DropdownMenuSeparator
data-slot="dropdown-menu-separator"
v-bind="delegatedProps"
:class="cn('bg-border -mx-1 my-1 h-px', props.class)"
/>
</template>

View file

@ -8,7 +8,10 @@ const props = defineProps<{
</script>
<template>
<span :class="cn('ml-auto text-xs tracking-widest opacity-60', props.class)">
<span
data-slot="dropdown-menu-shortcut"
:class="cn('text-muted-foreground ml-auto text-xs tracking-widest', props.class)"
>
<slot />
</span>
</template>

View file

@ -13,7 +13,7 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DropdownMenuSub v-bind="forwarded">
<DropdownMenuSub data-slot="dropdown-menu-sub" v-bind="forwarded">
<slot />
</DropdownMenuSub>
</template>

View file

@ -24,8 +24,9 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DropdownMenuSubContent
data-slot="dropdown-menu-sub-content"
v-bind="forwarded"
:class="cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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', props.class)"
:class="cn('bg-popover text-popover-foreground 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 z-50 min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg', props.class)"
>
<slot />
</DropdownMenuSubContent>

View file

@ -1,35 +1,35 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { reactiveOmit } from "@vueuse/core";
import { ChevronRight } from "lucide-vue-next";
import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
useForwardProps,
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import type { HTMLAttributes } from "vue";
const props = defineProps<
DropdownMenuSubTriggerProps & { class?: HTMLAttributes["class"] }
DropdownMenuSubTriggerProps & {
class?: HTMLAttributes["class"];
inset?: boolean;
}
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const delegatedProps = reactiveOmit(props, "class", "inset");
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DropdownMenuSubTrigger
data-slot="dropdown-menu-sub-trigger"
v-bind="forwardedProps"
:class="cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
props.class,
)"
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
<ChevronRight class="ml-auto size-4" />
</DropdownMenuSubTrigger>
</template>

View file

@ -11,7 +11,10 @@ const forwardedProps = useForwardProps(props);
</script>
<template>
<DropdownMenuTrigger class="outline-none" v-bind="forwardedProps">
<DropdownMenuTrigger
data-slot="dropdown-menu-trigger"
v-bind="forwardedProps"
>
<slot />
</DropdownMenuTrigger>
</template>

View file

@ -8,6 +8,7 @@ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
<template>
<Slot
:id="formItemId"
data-slot="form-control"
:aria-describedby="!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`"
:aria-invalid="!!error"
>

View file

@ -13,7 +13,8 @@ const { formDescriptionId } = useFormField();
<template>
<p
:id="formDescriptionId"
:class="cn('text-sm text-muted-foreground', props.class)"
data-slot="form-description"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</p>

View file

@ -13,7 +13,10 @@ provide(FORM_ITEM_INJECTION_KEY, id);
</script>
<template>
<div :class="cn('space-y-2', props.class)">
<div
data-slot="form-item"
:class="cn('grid gap-2', props.class)"
>
<slot />
</div>
</template>

View file

@ -12,8 +12,10 @@ const { error, formItemId } = useFormField();
<template>
<Label
data-slot="form-label"
:data-error="!!error"
:class="cn(
error && 'text-destructive',
'data-[error=true]:text-destructive-foreground',
props.class,
)"
:for="formItemId"

View file

@ -1,16 +1,22 @@
<script lang="ts" setup>
import { cn } from "@/lib/utils";
import { ErrorMessage } from "vee-validate";
import { toValue } from "vue";
import { type HTMLAttributes, toValue } from "vue";
import { useFormField } from "./useFormField";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const { name, formMessageId } = useFormField();
</script>
<template>
<ErrorMessage
:id="formMessageId"
data-slot="form-message"
as="p"
:name="toValue(name)"
class="text-sm font-medium text-destructive"
:class="cn('text-destructive-foreground text-sm', props.class)"
/>
</template>

View file

@ -4,4 +4,8 @@ export { default as FormItem } from "./FormItem.vue";
export { default as FormLabel } from "./FormLabel.vue";
export { default as FormMessage } from "./FormMessage.vue";
export { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
export { Form, Field as FormField } from "vee-validate";
export {
Form,
Field as FormField,
FieldArray as FormFieldArray,
} from "vee-validate";

View file

@ -13,7 +13,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<HoverCardRoot v-bind="forwarded">
<HoverCardRoot
data-slot="hover-card"
v-bind="forwarded"
>
<slot />
</HoverCardRoot>
</template>

View file

@ -27,10 +27,11 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<HoverCardPortal>
<HoverCardContent
data-slot="hover-card-content"
v-bind="forwardedProps"
:class="
cn(
'z-50 w-64 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',
'bg-popover text-popover-foreground 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 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden',
props.class,
)
"

View file

@ -5,7 +5,10 @@ const props = defineProps<HoverCardTriggerProps>();
</script>
<template>
<HoverCardTrigger v-bind="props">
<HoverCardTrigger
data-slot="hover-card-trigger"
v-bind="props"
>
<slot />
</HoverCardTrigger>
</template>

View file

@ -19,5 +19,14 @@ const modelValue = useVModel(props, "modelValue", emits, {
</script>
<template>
<input v-model="modelValue" :class="cn('flex h-10 w-full rounded-md border border-input bg-background 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', props.class)">
<input
v-model="modelValue"
data-slot="input"
:class="cn(
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
props.class,
)"
>
</template>

View file

@ -14,10 +14,11 @@ const delegatedProps = computed(() => {
<template>
<Label
data-slot="label"
v-bind="delegatedProps"
:class="
cn(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
props.class,
)
"

View file

@ -9,7 +9,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<PopoverRoot v-bind="forwarded">
<PopoverRoot
data-slot="popover"
v-bind="forwarded"
>
<slot />
</PopoverRoot>
</template>

View file

@ -0,0 +1,15 @@
<script setup lang="ts">
import type { PopoverAnchorProps } from "reka-ui";
import { PopoverAnchor } from "reka-ui";
const props = defineProps<PopoverAnchorProps>();
</script>
<template>
<PopoverAnchor
data-slot="popover-anchor"
v-bind="props"
>
<slot />
</PopoverAnchor>
</template>

View file

@ -34,10 +34,11 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<PopoverPortal>
<PopoverContent
data-slot="popover-content"
v-bind="{ ...forwarded, ...$attrs }"
:class="
cn(
'z-50 w-72 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',
'bg-popover text-popover-foreground 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 z-50 w-72 rounded-md border p-4 shadow-md origin-(--reka-popover-content-transform-origin) outline-hidden',
props.class,
)
"

View file

@ -5,7 +5,10 @@ const props = defineProps<PopoverTriggerProps>();
</script>
<template>
<PopoverTrigger v-bind="props">
<PopoverTrigger
data-slot="popover-trigger"
v-bind="props"
>
<slot />
</PopoverTrigger>
</template>

View file

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

View file

@ -9,7 +9,10 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<SelectRoot v-bind="forwarded">
<slot />
</SelectRoot>
<SelectRoot
data-slot="select"
v-bind="forwarded"
>
<slot />
</SelectRoot>
</template>

View file

@ -35,8 +35,10 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<SelectPortal>
<SelectContent
v-bind="{ ...forwarded, ...$attrs }" :class="cn(
'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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',
data-slot="select-content"
v-bind="{ ...forwarded, ...$attrs }"
:class="cn(
'bg-popover text-popover-foreground 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 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
position === 'popper'
&& 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
props.class,
@ -44,7 +46,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
"
>
<SelectScrollUpButton />
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--reka-select-trigger-height] w-full min-w-[--reka-select-trigger-width]')">
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1')">
<slot />
</SelectViewport>
<SelectScrollDownButton />

View file

@ -1,21 +1,14 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { SelectGroup, type SelectGroupProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
SelectGroupProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const props = defineProps<SelectGroupProps>();
</script>
<template>
<SelectGroup :class="cn('p-1 w-full', props.class)" v-bind="delegatedProps">
<SelectGroup
data-slot="select-group"
v-bind="props"
>
<slot />
</SelectGroup>
</template>

View file

@ -24,25 +24,24 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<SelectItem
v-bind="forwardedProps"
:class="
cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
props.class
)
"
>
<span
class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"
>
<SelectItemIndicator>
<Check class="h-4 w-4" />
</SelectItemIndicator>
</span>
<SelectItem
data-slot="select-item"
v-bind="forwardedProps"
:class="
cn(
`focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,
props.class,
)
"
>
<span class="absolute right-2 flex size-3.5 items-center justify-center">
<SelectItemIndicator>
<Check class="size-4" />
</SelectItemIndicator>
</span>
<SelectItemText class="w-full">
<slot />
</SelectItemText>
</SelectItem>
<SelectItemText>
<slot />
</SelectItemText>
</SelectItem>
</template>

View file

@ -5,7 +5,10 @@ const props = defineProps<SelectItemTextProps>();
</script>
<template>
<SelectItemText v-bind="props">
<SelectItemText
data-slot="select-item-text"
v-bind="props"
>
<slot />
</SelectItemText>
</template>

View file

@ -9,7 +9,10 @@ const props = defineProps<
</script>
<template>
<SelectLabel :class="cn('py-1.5 pl-8 pr-2 text-sm font-semibold', props.class)">
<SelectLabel
data-slot="select-label"
:class="cn('px-2 py-1.5 text-sm font-medium', props.class)"
>
<slot />
</SelectLabel>
</template>

View file

@ -22,9 +22,13 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<SelectScrollDownButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<SelectScrollDownButton
data-slot="select-scroll-down-button"
v-bind="forwardedProps"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
>
<slot>
<ChevronDown class="h-4 w-4" />
<ChevronDown class="size-4" />
</slot>
</SelectScrollDownButton>
</template>

View file

@ -22,9 +22,13 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<SelectScrollUpButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<SelectScrollUpButton
data-slot="select-scroll-up-button"
v-bind="forwardedProps"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
>
<slot>
<ChevronUp class="h-4 w-4" />
<ChevronUp class="size-4" />
</slot>
</SelectScrollUpButton>
</template>

View file

@ -15,5 +15,9 @@ const delegatedProps = computed(() => {
</script>
<template>
<SelectSeparator v-bind="delegatedProps" :class="cn('-mx-1 my-1 h-px bg-muted', props.class)" />
<SelectSeparator
data-slot="select-separator"
v-bind="delegatedProps"
:class="cn('bg-border pointer-events-none -mx-1 my-1 h-px', props.class)"
/>
</template>

Some files were not shown because too many files have changed in this diff Show more