chore: ⬆️ Upgrade to the latest Shadcn-Vue version
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 2m30s
Deploy to GitHub Pages / build (push) Failing after 6s
Deploy to GitHub Pages / deploy (push) Has been skipped
Docker / build (push) Failing after 5s
Mirror to Codeberg / Mirror (push) Failing after 0s

This commit is contained in:
Jesse Wierzbinski 2025-03-28 01:16:24 +01:00
parent 7649ecfb80
commit 092bce0f24
No known key found for this signature in database
169 changed files with 1860 additions and 1088 deletions

View file

@ -4,7 +4,7 @@ import {
type AlertDialogProps,
AlertDialogRoot,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<AlertDialogProps>();
const emits = defineEmits<AlertDialogEmits>();

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { AlertDialogAction, type AlertDialogActionProps } from "radix-vue";
import { AlertDialogAction, type AlertDialogActionProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { buttonVariants } from "~/components/ui/button";
const props = defineProps<
AlertDialogActionProps & { class?: HTMLAttributes["class"] }

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { AlertDialogCancel, type AlertDialogCancelProps } from "radix-vue";
import { AlertDialogCancel, type AlertDialogCancelProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { buttonVariants } from "~/components/ui/button";
const props = defineProps<
AlertDialogCancelProps & { class?: HTMLAttributes["class"] }

View file

@ -7,7 +7,7 @@ import {
AlertDialogOverlay,
AlertDialogPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -27,13 +27,13 @@ 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"
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"
/>
<AlertDialogContent
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',
'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,
)
"

View file

@ -3,7 +3,7 @@ import { cn } from "@/lib/utils";
import {
AlertDialogDescription,
type AlertDialogDescriptionProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { AlertDialogTitle, type AlertDialogTitleProps } from "radix-vue";
import { AlertDialogTitle, type AlertDialogTitleProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { AlertDialogTrigger, type AlertDialogTriggerProps } from "radix-vue";
import { AlertDialogTrigger, type AlertDialogTriggerProps } from "reka-ui";
const props = defineProps<AlertDialogTriggerProps>();
</script>

View file

@ -5,7 +5,7 @@ export { default as AlertDescription } from "./AlertDescription.vue";
export { default as AlertTitle } from "./AlertTitle.vue";
export const alertVariants = cva(
"relative w-full rounded border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
"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",
{
variants: {
variant: {

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { AvatarRoot } from "radix-vue";
import { AvatarRoot } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { type AvatarVariants, avatarVariant } from ".";

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { AvatarFallback, type AvatarFallbackProps } from "radix-vue";
import { AvatarFallback, type AvatarFallbackProps } from "reka-ui";
const props = defineProps<AvatarFallbackProps>();
</script>

View file

@ -1,9 +1,12 @@
<script setup lang="ts">
import { AvatarImage, type AvatarImageProps } from "radix-vue";
import type { AvatarImageProps } from "reka-ui";
import { AvatarImage } from "reka-ui";
const props = defineProps<AvatarImageProps>();
</script>
<template>
<AvatarImage v-bind="props" class="h-full w-full object-cover" />
<AvatarImage v-bind="props" class="h-full w-full object-cover">
<slot />
</AvatarImage>
</template>

View file

@ -15,7 +15,7 @@ export const avatarVariant = cva(
},
shape: {
circle: "rounded-full",
square: "rounded",
square: "rounded-md",
},
},
},

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps } from "radix-vue";
import { Primitive, type PrimitiveProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { type ButtonVariants, buttonVariants } from ".";
@ -20,7 +20,6 @@ const props = withDefaults(defineProps<Props>(), {
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
data-component="button"
>
<slot />
</Primitive>

View file

@ -1,4 +1,6 @@
import { type VariantProps, cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
export { default as Button } from "./Button.vue";
export const buttonVariants = cva(
@ -7,21 +9,21 @@ export const buttonVariants = cva(
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
"bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 px-3 text-xs",
lg: "h-10 px-8",
icon: "size-9",
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",
},
},
defaultVariants: {

View file

@ -1,22 +1,21 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps } from "radix-vue";
import type { HTMLAttributes } from "vue";
const props = withDefaults(
defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(),
{
as: "div",
},
);
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>
<template>
<Primitive :as="props.as" :as-child="props.asChild" :class="cn(
'rounded-lg border bg-card/90 backdrop-blur-xl text-card-foreground shadow-sm',
props.class,
)
" data-component="card">
<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
)
"
>
<slot />
</Primitive>
</div>
</template>

View file

@ -8,7 +8,7 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('p-6 pt-0', props.class)">
<slot />
</div>
<div :class="cn('flex flex-col gap-2', props.class)">
<slot />
</div>
</template>

View file

@ -8,7 +8,7 @@ const props = defineProps<{
</script>
<template>
<div :class="cn('flex items-center p-6 pt-0', props.class)">
<slot />
</div>
<div :class="cn('flex items-center', props.class)">
<slot />
</div>
</template>

View file

@ -1,18 +1,14 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps } from "radix-vue";
import type { HTMLAttributes } from "vue";
const props = withDefaults(
defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(),
{
as: "div",
},
);
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>
<template>
<Primitive :as="props.as" :as-child="props.asChild" :class="cn('flex flex-col gap-y-1.5 p-6', props.class)">
<div :class="cn('flex flex-col gap-y-1.5', props.class)">
<slot />
</Primitive>
</div>
</template>

View file

@ -1,12 +1,8 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Check } from "lucide-vue-next";
import type { CheckboxRootEmits, CheckboxRootProps } from "radix-vue";
import {
CheckboxIndicator,
CheckboxRoot,
useForwardPropsEmits,
} from "radix-vue";
import type { CheckboxRootEmits, CheckboxRootProps } from "reka-ui";
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -24,12 +20,16 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<CheckboxRoot v-bind="forwarded" :class="cn('peer size-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',
props.class)">
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
<slot>
<Check class="size-4" />
</slot>
</CheckboxIndicator>
</CheckboxRoot>
<CheckboxRoot
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',
props.class)"
>
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
<slot>
<Check class="h-4 w-4" />
</slot>
</CheckboxIndicator>
</CheckboxRoot>
</template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { CollapsibleRootEmits, CollapsibleRootProps } from "radix-vue";
import { CollapsibleRoot, useForwardPropsEmits } from "radix-vue";
import type { CollapsibleRootEmits, CollapsibleRootProps } from "reka-ui";
import { CollapsibleRoot, useForwardPropsEmits } from "reka-ui";
const props = defineProps<CollapsibleRootProps>();
const emits = defineEmits<CollapsibleRootEmits>();

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { CollapsibleContent, type CollapsibleContentProps } from "radix-vue";
import { CollapsibleContent, type CollapsibleContentProps } from "reka-ui";
const props = defineProps<CollapsibleContentProps>();
</script>

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { CollapsibleTrigger, type CollapsibleTriggerProps } from "radix-vue";
import { CollapsibleTrigger, type CollapsibleTriggerProps } from "reka-ui";
const props = defineProps<CollapsibleTriggerProps>();
</script>

View file

@ -1,18 +1,18 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxRootEmits, ComboboxRootProps } from "radix-vue";
import { ComboboxRoot, useForwardPropsEmits } from "radix-vue";
import { type HTMLAttributes, computed } from "vue";
import type { ListboxRootEmits, ListboxRootProps } from "reka-ui";
import { ListboxRoot, useFilter, useForwardPropsEmits } from "reka-ui";
import { type HTMLAttributes, computed, reactive, ref, watch } from "vue";
import { provideCommandContext } from ".";
const props = withDefaults(
defineProps<ComboboxRootProps & { class?: HTMLAttributes["class"] }>(),
defineProps<ListboxRootProps & { class?: HTMLAttributes["class"] }>(),
{
open: true,
modelValue: "",
},
);
const emits = defineEmits<ComboboxRootEmits>();
const emits = defineEmits<ListboxRootEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@ -21,11 +21,84 @@ const delegatedProps = computed(() => {
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
const allItems = ref<Map<string, string>>(new Map());
const allGroups = ref<Map<string, Set<string>>>(new Map());
const { contains } = useFilter({ sensitivity: "base" });
const filterState = reactive({
search: "",
filtered: {
/** The count of all visible items. */
count: 0,
/** Map from visible item id to its search score. */
items: new Map() as Map<string, number>,
/** Set of groups with at least one visible item. */
groups: new Set() as Set<string>,
},
});
function filterItems() {
if (!filterState.search) {
filterState.filtered.count = allItems.value.size;
// Do nothing, each item will know to show itself because search is empty
return;
}
// Reset the groups
filterState.filtered.groups = new Set();
let itemCount = 0;
// Check which items should be included
for (const [id, value] of allItems.value) {
const score = contains(value, filterState.search);
filterState.filtered.items.set(id, score ? 1 : 0);
if (score) {
itemCount++;
}
}
// 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)) {
filterState.filtered.groups.add(groupId);
break;
}
}
}
filterState.filtered.count = itemCount;
}
function handleSelect() {
filterState.search = "";
}
watch(
() => filterState.search,
() => {
filterItems();
},
);
provideCommandContext({
allItems,
allGroups,
filterState,
});
</script>
<template>
<ComboboxRoot v-bind="forwarded"
:class="cn('flex h-full w-full flex-col overflow-hidden rounded bg-popover text-popover-foreground', props.class)">
<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 />
</ComboboxRoot>
</ListboxRoot>
</template>

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import type { DialogRootEmits, DialogRootProps } from "radix-vue";
import { useForwardPropsEmits } from "radix-vue";
import { Dialog, DialogContent } from "~/components/ui/dialog";
import { Dialog, DialogContent } 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>();

View file

@ -1,11 +1,12 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxEmptyProps } from "radix-vue";
import { ComboboxEmpty } from "radix-vue";
import type { PrimitiveProps } from "reka-ui";
import { Primitive } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { useCommand } from ".";
const props = defineProps<
ComboboxEmptyProps & { class?: HTMLAttributes["class"] }
PrimitiveProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
@ -13,10 +14,15 @@ const delegatedProps = computed(() => {
return delegated;
});
const { filterState } = useCommand();
const isRender = computed(
() => !!filterState.search && filterState.filtered.count === 0,
);
</script>
<template>
<ComboboxEmpty v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
<Primitive v-if="isRender" v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
<slot />
</ComboboxEmpty>
</Primitive>
</template>

View file

@ -1,11 +1,12 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxGroupProps } from "radix-vue";
import { ComboboxGroup, ComboboxLabel } from "radix-vue";
import { type HTMLAttributes, computed } from "vue";
import type { ListboxGroupProps } from "reka-ui";
import { ListboxGroup, ListboxGroupLabel, useId } from "reka-ui";
import { type HTMLAttributes, computed, onMounted, onUnmounted } from "vue";
import { provideCommandGroupContext, useCommand } from ".";
const props = defineProps<
ComboboxGroupProps & {
ListboxGroupProps & {
class?: HTMLAttributes["class"];
heading?: string;
}
@ -16,16 +17,43 @@ const delegatedProps = computed(() => {
return delegated;
});
const { allGroups, filterState } = useCommand();
const id = useId();
const isRender = computed(() =>
filterState.search ? filterState.filtered.groups.has(id) : true,
);
provideCommandGroupContext({ id });
onMounted(() => {
if (!allGroups.value.has(id)) {
allGroups.value.set(id, new Set());
}
});
onUnmounted(() => {
allGroups.value.delete(id);
});
</script>
<template>
<ComboboxGroup
v-bind="delegatedProps"
: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)"
>
<ComboboxLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
{{ heading }}
</ComboboxLabel>
<slot />
</ComboboxGroup>
<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>
</template>

View file

@ -2,18 +2,19 @@
import { cn } from "@/lib/utils";
import { Search } from "lucide-vue-next";
import {
ComboboxInput,
type ComboboxInputProps,
ListboxFilter,
type ListboxFilterProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { useCommand } from ".";
defineOptions({
inheritAttrs: false,
});
const props = defineProps<
ComboboxInputProps & {
ListboxFilterProps & {
class?: HTMLAttributes["class"];
}
>();
@ -25,12 +26,18 @@ const delegatedProps = computed(() => {
});
const forwardedProps = useForwardProps(delegatedProps);
const { filterState } = useCommand();
</script>
<template>
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
<Search class="mr-2 size-4 shrink-0 opacity-50" />
<ComboboxInput v-bind="{ ...forwardedProps, ...$attrs }" auto-focus
:class="cn('flex h-11 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)" />
</div>
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
<Search class="mr-2 h-4 w-4 shrink-0 opacity-50" />
<ListboxFilter
v-bind="{ ...forwardedProps, ...$attrs }"
v-model="filterState.search"
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)"
/>
</div>
</template>

View file

@ -1,13 +1,21 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxItemEmits, ComboboxItemProps } from "radix-vue";
import { ComboboxItem, useForwardPropsEmits } from "radix-vue";
import { type HTMLAttributes, computed } from "vue";
import { useCurrentElement } from "@vueuse/core";
import type { ListboxItemEmits, ListboxItemProps } from "reka-ui";
import { ListboxItem, useForwardPropsEmits, useId } from "reka-ui";
import {
type HTMLAttributes,
computed,
onMounted,
onUnmounted,
ref,
} from "vue";
import { useCommand, useCommandGroup } from ".";
const props = defineProps<
ComboboxItemProps & { class?: HTMLAttributes["class"] }
ListboxItemProps & { class?: HTMLAttributes["class"] }
>();
const emits = defineEmits<ComboboxItemEmits>();
const emits = defineEmits<ListboxItemEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@ -16,13 +24,72 @@ const delegatedProps = computed(() => {
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
const id = useId();
const { filterState, allItems, allGroups } = useCommand();
const groupContext = useCommandGroup();
const isRender = computed(() => {
if (filterState.search) {
const filteredCurrentItem = filterState.filtered.items.get(id);
// If the filtered items is undefined means not in the all times map yet
// Do the first render to add into the map
if (filteredCurrentItem === undefined) {
return true;
}
// Check with filter
return filteredCurrentItem > 0;
}
return true;
});
const itemRef = ref();
const currentElement = useCurrentElement(itemRef);
onMounted(() => {
if (!(currentElement.value instanceof HTMLElement)) {
return;
}
// textValue to perform filter
allItems.value.set(
id,
currentElement.value.textContent ?? props.value?.toString() ?? "",
);
const groupId = groupContext?.id;
if (groupId) {
if (allGroups.value.has(groupId)) {
allGroups.value.get(groupId)?.add(id);
} else {
allGroups.value.set(groupId, new Set([id]));
}
}
});
onUnmounted(() => {
allItems.value.delete(id);
});
</script>
<template>
<ComboboxItem
v-bind="forwarded"
:class="cn('relative flex cursor-default 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', props.class)"
>
<slot />
</ComboboxItem>
<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>
</template>

View file

@ -1,16 +1,12 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxContentEmits, ComboboxContentProps } from "radix-vue";
import { ComboboxContent, useForwardPropsEmits } from "radix-vue";
import type { ListboxContentProps } from "reka-ui";
import { ListboxContent, useForwardProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = withDefaults(
defineProps<ComboboxContentProps & { class?: HTMLAttributes["class"] }>(),
{
dismissable: false,
},
);
const emits = defineEmits<ComboboxContentEmits>();
const props = defineProps<
ListboxContentProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@ -18,13 +14,13 @@ const delegatedProps = computed(() => {
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
const forwarded = useForwardProps(delegatedProps);
</script>
<template>
<ComboboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
<ListboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
<div role="presentation">
<slot />
</div>
</ComboboxContent>
</ListboxContent>
</template>

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { ComboboxSeparatorProps } from "radix-vue";
import { ComboboxSeparator } from "radix-vue";
import type { SeparatorProps } from "reka-ui";
import { Separator } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
ComboboxSeparatorProps & { class?: HTMLAttributes["class"] }
SeparatorProps & { class?: HTMLAttributes["class"] }
>();
const delegatedProps = computed(() => {
@ -16,10 +16,10 @@ const delegatedProps = computed(() => {
</script>
<template>
<ComboboxSeparator
<Separator
v-bind="delegatedProps"
:class="cn('-mx-1 h-px bg-border', props.class)"
>
<slot />
</ComboboxSeparator>
</Separator>
</template>

View file

@ -1,3 +1,6 @@
import { createContext } from "reka-ui";
import type { Ref } from "vue";
export { default as Command } from "./Command.vue";
export { default as CommandDialog } from "./CommandDialog.vue";
export { default as CommandEmpty } from "./CommandEmpty.vue";
@ -7,3 +10,20 @@ export { default as CommandItem } from "./CommandItem.vue";
export { default as CommandList } from "./CommandList.vue";
export { default as CommandSeparator } from "./CommandSeparator.vue";
export { default as CommandShortcut } from "./CommandShortcut.vue";
export const [useCommand, provideCommandContext] = createContext<{
allItems: Ref<Map<string, string>>;
allGroups: Ref<Map<string, Set<string>>>;
filterState: {
search: string;
filtered: {
count: number;
items: Map<string, number>;
groups: Set<string>;
};
};
}>("Command");
export const [useCommandGroup, provideCommandGroupContext] = createContext<{
id?: string;
}>("CommandGroup");

View file

@ -4,7 +4,7 @@ import {
type DialogRootEmits,
type DialogRootProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DialogRootProps>();
const emits = defineEmits<DialogRootEmits>();

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from "radix-vue";
import { DialogClose, type DialogCloseProps } from "reka-ui";
const props = defineProps<DialogCloseProps>();
</script>

View file

@ -9,7 +9,7 @@ import {
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -32,16 +32,24 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 bg-black/80 backdrop-blur 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,
)">
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 />
<DialogClose v-if="!props.hideClose"
class="absolute right-4 top-4 rounded 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="size-4" />
<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>

View file

@ -4,7 +4,7 @@ import {
DialogDescription,
type DialogDescriptionProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -9,7 +9,7 @@ const props = defineProps<{ class?: HTMLAttributes["class"] }>();
<div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2 gap-y-2',
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"

View file

@ -9,7 +9,7 @@ import {
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -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="
@ -52,7 +52,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<DialogClose
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="size-4" />
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { DialogTitle, type DialogTitleProps, useForwardProps } from "radix-vue";
import { DialogTitle, type DialogTitleProps, useForwardProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from "radix-vue";
import { DialogTrigger, type DialogTriggerProps } from "reka-ui";
const props = defineProps<DialogTriggerProps>();
</script>

View file

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { useForwardPropsEmits } from "radix-vue";
import { useForwardPropsEmits } from "reka-ui";
import type { DrawerRootEmits, DrawerRootProps } from "vaul-vue";
import { DrawerRoot } from "vaul-vue";

View file

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { cn } from "@/lib/utils";
import type { DialogContentEmits, DialogContentProps } from "radix-vue";
import { useForwardPropsEmits } from "radix-vue";
import type { DialogContentEmits, DialogContentProps } from "reka-ui";
import { useForwardPropsEmits } from "reka-ui";
import { DrawerContent, DrawerPortal } from "vaul-vue";
import type { HtmlHTMLAttributes } from "vue";
import DrawerOverlay from "./DrawerOverlay.vue";

View file

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { cn } from "@/lib/utils";
import type { DialogOverlayProps } from "radix-vue";
import type { DialogOverlayProps } from "reka-ui";
import { DrawerOverlay } from "vaul-vue";
import { type HtmlHTMLAttributes, computed } from "vue";

View file

@ -4,7 +4,7 @@ import {
type DropdownMenuRootEmits,
type DropdownMenuRootProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DropdownMenuRootProps>();
const emits = defineEmits<DropdownMenuRootEmits>();

View file

@ -7,7 +7,7 @@ import {
type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -25,15 +25,18 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DropdownMenuCheckboxItem 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',
props.class,
)">
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Check class="!mr-0" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
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',
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Check class="w-4 h-4" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuCheckboxItem>
</template>

View file

@ -6,7 +6,7 @@ import {
type DropdownMenuContentProps,
DropdownMenuPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = withDefaults(

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DropdownMenuGroup, type DropdownMenuGroupProps } from "radix-vue";
import { DropdownMenuGroup, type DropdownMenuGroupProps } from "reka-ui";
const props = defineProps<DropdownMenuGroupProps>();
</script>

View file

@ -4,7 +4,7 @@ import {
DropdownMenuItem,
type DropdownMenuItemProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -21,11 +21,16 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DropdownMenuItem v-bind="forwardedProps" :class="cn(
'relative flex 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 [&>svg]:mr-0.5 w-full',
inset && 'pl-8',
props.class,
)">
<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>
</template>

View file

@ -4,7 +4,7 @@ import {
DropdownMenuLabel,
type DropdownMenuLabelProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -24,8 +24,10 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DropdownMenuLabel v-bind="forwardedProps"
:class="cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)">
<slot />
</DropdownMenuLabel>
<DropdownMenuLabel
v-bind="forwardedProps"
:class="cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)"
>
<slot />
</DropdownMenuLabel>
</template>

View file

@ -4,7 +4,7 @@ import {
type DropdownMenuRadioGroupEmits,
type DropdownMenuRadioGroupProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DropdownMenuRadioGroupProps>();
const emits = defineEmits<DropdownMenuRadioGroupEmits>();

View file

@ -7,7 +7,7 @@ import {
type DropdownMenuRadioItemEmits,
type DropdownMenuRadioItemProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -26,15 +26,18 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DropdownMenuRadioItem 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',
props.class,
)">
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Circle class="size-2 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuRadioItem>
<DropdownMenuRadioItem
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',
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Circle class="h-2 w-2 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuRadioItem>
</template>

View file

@ -3,7 +3,7 @@ import { cn } from "@/lib/utils";
import {
DropdownMenuSeparator,
type DropdownMenuSeparatorProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -4,7 +4,7 @@ import {
type DropdownMenuSubEmits,
type DropdownMenuSubProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DropdownMenuSubProps>();
const emits = defineEmits<DropdownMenuSubEmits>();

View file

@ -5,7 +5,7 @@ import {
type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -5,7 +5,7 @@ import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -30,6 +30,6 @@ const forwardedProps = useForwardProps(delegatedProps);
)"
>
<slot />
<ChevronRight class="ml-auto size-4" />
<ChevronRight class="ml-auto h-4 w-4" />
</DropdownMenuSubTrigger>
</template>

View file

@ -3,7 +3,7 @@ import {
DropdownMenuTrigger,
type DropdownMenuTriggerProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DropdownMenuTriggerProps>();

View file

@ -13,4 +13,4 @@ export { default as DropdownMenuSub } from "./DropdownMenuSub.vue";
export { default as DropdownMenuSubContent } from "./DropdownMenuSubContent.vue";
export { default as DropdownMenuSubTrigger } from "./DropdownMenuSubTrigger.vue";
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue";
export { DropdownMenuPortal } from "radix-vue";
export { DropdownMenuPortal } from "reka-ui";

View file

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { Slot } from "radix-vue";
import { Slot } from "reka-ui";
import { useFormField } from "./useFormField";
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();

View file

@ -1,26 +1,19 @@
<script lang="ts" setup>
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps, useId } from "radix-vue";
import { useId } from "reka-ui";
import { type HTMLAttributes, provide } from "vue";
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
const props = withDefaults(
defineProps<
PrimitiveProps & {
class?: HTMLAttributes["class"];
}
>(),
{
as: "div",
},
);
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const id = useId();
provide(FORM_ITEM_INJECTION_KEY, id);
</script>
<template>
<Primitive :as="props.as" :as-child="props.asChild" :class="cn('space-y-2', props.class)">
<slot />
</Primitive>
<div :class="cn('space-y-2', props.class)">
<slot />
</div>
</template>

View file

@ -1,8 +1,8 @@
<script lang="ts" setup>
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import type { LabelProps } from "radix-vue";
import type { LabelProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { Label } from "~/components/ui/label";
import { useFormField } from "./useFormField";
const props = defineProps<LabelProps & { class?: HTMLAttributes["class"] }>();

View file

@ -4,4 +4,4 @@ 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 { Field as FormField, Form } from "vee-validate";
export { Form, Field as FormField } from "vee-validate";

View file

@ -4,7 +4,7 @@ import {
type HoverCardRootEmits,
type HoverCardRootProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<HoverCardRootProps>();
const emits = defineEmits<HoverCardRootEmits>();

View file

@ -5,7 +5,7 @@ import {
type HoverCardContentProps,
HoverCardPortal,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = withDefaults(

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { HoverCardTrigger, type HoverCardTriggerProps } from "radix-vue";
import { HoverCardTrigger, type HoverCardTriggerProps } from "reka-ui";
const props = defineProps<HoverCardTriggerProps>();
</script>

View file

@ -19,6 +19,5 @@ const modelValue = useVModel(props, "modelValue", emits, {
</script>
<template>
<input v-model="modelValue"
:class="cn('flex h-10 w-full rounded 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:ring-0 focus:ring-offset-0 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50', props.class)">
<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)">
</template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Label, type LabelProps } from "radix-vue";
import { Label, type LabelProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<LabelProps & { class?: HTMLAttributes["class"] }>();

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { PopoverRootEmits, PopoverRootProps } from "radix-vue";
import { PopoverRoot, useForwardPropsEmits } from "radix-vue";
import type { PopoverRootEmits, PopoverRootProps } from "reka-ui";
import { PopoverRoot, useForwardPropsEmits } from "reka-ui";
const props = defineProps<PopoverRootProps>();
const emits = defineEmits<PopoverRootEmits>();

View file

@ -6,7 +6,7 @@ import {
type PopoverContentProps,
PopoverPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
defineOptions({

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { PopoverTrigger, type PopoverTriggerProps } from "radix-vue";
import { PopoverTrigger, type PopoverTriggerProps } from "reka-ui";
const props = defineProps<PopoverTriggerProps>();
</script>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { SelectRootEmits, SelectRootProps } from "radix-vue";
import { SelectRoot, useForwardPropsEmits } from "radix-vue";
import type { SelectRootEmits, SelectRootProps } from "reka-ui";
import { SelectRoot, useForwardPropsEmits } from "reka-ui";
const props = defineProps<SelectRootProps>();
const emits = defineEmits<SelectRootEmits>();
@ -9,7 +9,7 @@ const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<SelectRoot v-bind="forwarded">
<slot />
</SelectRoot>
<SelectRoot v-bind="forwarded">
<slot />
</SelectRoot>
</template>

View file

@ -7,7 +7,7 @@ import {
SelectPortal,
SelectViewport,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { SelectScrollDownButton, SelectScrollUpButton } from ".";
@ -44,7 +44,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
"
>
<SelectScrollUpButton />
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--radix-select-trigger-height] w-full min-w-[--radix-select-trigger-width]')">
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--reka-select-trigger-height] w-full min-w-[--reka-select-trigger-width]')">
<slot />
</SelectViewport>
<SelectScrollDownButton />

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { SelectGroup, type SelectGroupProps } from "radix-vue";
import { SelectGroup, type SelectGroupProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -7,7 +7,7 @@ import {
type SelectItemProps,
SelectItemText,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -24,23 +24,25 @@ 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-10 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-3 flex size-3.5 items-center justify-center">
<SelectItemIndicator>
<Check class="size-4" />
</SelectItemIndicator>
</span>
<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>
<SelectItemText class="w-full">
<slot />
</SelectItemText>
</SelectItem>
<SelectItemText class="w-full">
<slot />
</SelectItemText>
</SelectItem>
</template>

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { SelectItemText, type SelectItemTextProps } from "radix-vue";
import { SelectItemText, type SelectItemTextProps } from "reka-ui";
const props = defineProps<SelectItemTextProps>();
</script>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { SelectLabel, type SelectLabelProps } from "radix-vue";
import { SelectLabel, type SelectLabelProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
const props = defineProps<

View file

@ -5,7 +5,7 @@ import {
SelectScrollDownButton,
type SelectScrollDownButtonProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -24,7 +24,7 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<SelectScrollDownButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<slot>
<ChevronDown class="size-4" />
<ChevronDown class="h-4 w-4" />
</slot>
</SelectScrollDownButton>
</template>

View file

@ -5,7 +5,7 @@ import {
SelectScrollUpButton,
type SelectScrollUpButtonProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
@ -24,7 +24,7 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<SelectScrollUpButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<slot>
<ChevronUp class="size-4" />
<ChevronUp class="h-4 w-4" />
</slot>
</SelectScrollUpButton>
</template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { SelectSeparator, type SelectSeparatorProps } from "radix-vue";
import { SelectSeparator, type SelectSeparatorProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -6,11 +6,15 @@ import {
SelectTrigger,
type SelectTriggerProps,
useForwardProps,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<
SelectTriggerProps & { class?: HTMLAttributes["class"] }
SelectTriggerProps & {
class?: HTMLAttributes["class"];
disableDefaultClasses?: boolean;
disableSelectIcon?: boolean;
}
>();
const delegatedProps = computed(() => {
@ -23,16 +27,19 @@ const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<SelectTrigger
v-bind="forwardedProps"
:class="cn(
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[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]:truncate text-start',
props.class,
)"
>
<slot />
<SelectIcon as-child>
<ChevronDown class="size-4 opacity-50 shrink-0" />
</SelectIcon>
</SelectTrigger>
<SelectTrigger
v-bind="forwardedProps"
:class="
cn(
!$props.disableDefaultClasses &&
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[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]:truncate text-start',
props.class
)
"
>
<slot />
<SelectIcon as-child v-if="!$props.disableSelectIcon">
<ChevronDown class="w-4 h-4 opacity-50 shrink-0" />
</SelectIcon>
</SelectTrigger>
</template>

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { SelectValue, type SelectValueProps } from "radix-vue";
import { SelectValue, type SelectValueProps } from "reka-ui";
const props = defineProps<SelectValueProps>();
</script>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Separator, type SeparatorProps } from "radix-vue";
import { Separator, type SeparatorProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -4,7 +4,7 @@ import {
type DialogRootEmits,
type DialogRootProps,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
const props = defineProps<DialogRootProps>();
const emits = defineEmits<DialogRootEmits>();

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from "radix-vue";
import { DialogClose, type DialogCloseProps } from "reka-ui";
const props = defineProps<DialogCloseProps>();
</script>

View file

@ -9,7 +9,7 @@ import {
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from "radix-vue";
} from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
import { type SheetVariants, sheetVariants } from ".";
@ -38,7 +38,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<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"
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
:class="cn(sheetVariants({ side }), props.class)"
@ -49,7 +49,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<DialogClose
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-secondary"
>
<X class="size-4 text-muted-foreground" />
<X class="w-4 h-4 text-muted-foreground" />
</DialogClose>
</DialogContent>
</DialogPortal>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { DialogDescription, type DialogDescriptionProps } from "radix-vue";
import { DialogDescription, type DialogDescriptionProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { DialogTitle, type DialogTitleProps } from "radix-vue";
import { DialogTitle, type DialogTitleProps } from "reka-ui";
import { type HTMLAttributes, computed } from "vue";
const props = defineProps<

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from "radix-vue";
import { DialogTrigger, type DialogTriggerProps } from "reka-ui";
const props = defineProps<DialogTriggerProps>();
</script>

View file

@ -1,30 +1,100 @@
<script setup lang="ts">
import { Sheet, SheetContent } from "@/components/ui/sheet";
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
import type { SidebarProps } from ".";
import { SIDEBAR_WIDTH_MOBILE, useSidebar } from "./utils";
defineOptions({
inheritAttrs: false,
});
const props = withDefaults(
defineProps<{
side?: "left" | "right";
variant?: "sidebar" | "floating" | "inset";
collapsible?: "offcanvas" | "icon" | "none";
class?: HTMLAttributes["class"];
}>(),
{
side: "left",
variant: "sidebar",
collapsible: "offcanvas",
},
);
const props = withDefaults(defineProps<SidebarProps>(), {
side: "left",
variant: "sidebar",
collapsible: "offcanvas",
});
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
</script>
<template>
<aside
:class="cn('flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground p-1', props.class)"
v-bind="$attrs" data-component="sidebar">
<div
v-if="collapsible === 'none'"
:class="
cn(
'flex h-dvh w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground',
props.class
)
"
v-bind="$attrs"
>
<slot />
</aside>
</div>
<Sheet
v-else-if="isMobile"
:open="openMobile"
v-bind="$attrs"
@update:open="setOpenMobile"
>
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
:side="side"
class="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
:style="{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
}"
>
<div class="flex h-full w-full flex-col">
<slot />
</div>
</SheetContent>
</Sheet>
<div
v-else
class="group peer hidden md:block"
:data-state="state"
:data-collapsible="state === 'collapsed' ? collapsible : ''"
:data-variant="variant"
:data-side="side"
>
<!-- This is what handles the sidebar gap on desktop -->
<div
:class="
cn(
'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',
'group-data-[collapsible=offcanvas]:w-0',
'group-data-[side=right]:rotate-180',
variant === 'floating' || variant === 'inset'
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]'
)
"
/>
<div
:class="
cn(
'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',
side === 'left'
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
// Adjust the padding for floating and inset variants.
variant === 'floating' || variant === 'inset'
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
props.class
)
"
v-bind="$attrs"
>
<div
data-sidebar="sidebar"
class="flex h-full w-full flex-col text-sidebar-foreground bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
>
<slot />
</div>
</div>
</div>
</template>

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { PrimitiveProps } from "radix-vue";
import { Primitive } from "radix-vue";
import type { PrimitiveProps } from "reka-ui";
import { Primitive } from "reka-ui";
import type { HTMLAttributes } from "vue";
const props = defineProps<
@ -18,7 +18,6 @@ const props = defineProps<
:as-child="asChild"
:class="cn(
'absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
// Increases the hit area of the button on mobile.
'after:absolute after:-inset-2 after:md:hidden',
'group-data-[collapsible=icon]:hidden',
props.class,

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { PrimitiveProps } from "radix-vue";
import { Primitive } from "radix-vue";
import type { PrimitiveProps } from "reka-ui";
import { Primitive } from "reka-ui";
import type { HTMLAttributes } from "vue";
const props = defineProps<

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
import Input from "~/components/ui/input/Input.vue";
const props = defineProps<{
class?: HTMLAttributes["class"];

View file

@ -1,30 +1,22 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
import { SettingIds } from "~/settings";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const bgSetting = useSetting(SettingIds.BackgroundURL);
const bgImage = computed(() =>
bgSetting.value.value && URL.canParse(bgSetting.value.value as string)
? bgSetting.value.value
: "/images/banner.webp",
);
</script>
<template>
<main :class="cn(
'relative flex min-h-svh max-w-full flex-1 flex-col bg-background',
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:overflow-hidden md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow bg-cover bg-center bg-no-repeat',
props.class,
)" :style="{
backgroundImage: `url('${bgImage}')`,
}">
<!-- Overlay for the background image -->
<div class="absolute -z-10 inset-0 bg-black/20" />
<main
:class="
cn(
'relative flex min-h-svh flex-1 flex-col bg-background',
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
props.class
)
"
>
<slot />
</main>
</template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps } from "radix-vue";
import { Primitive, type PrimitiveProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
const props = withDefaults(
@ -21,7 +21,6 @@ const props = withDefaults(
data-sidebar="menu-action"
:class="cn(
'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',
// Increases the hit area of the button on mobile.
'after:absolute after:-inset-2 after:md:hidden',
'peer-data-[size=sm]/menu-button:top-1',
'peer-data-[size=default]/menu-button:top-1.5',

View file

@ -1,8 +1,10 @@
<script setup lang="ts">
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { type Component, computed } from "vue";
import Tooltip from "~/components/ui/tooltip/Tooltip.vue";
import TooltipContent from "~/components/ui/tooltip/TooltipContent.vue";
import TooltipTrigger from "~/components/ui/tooltip/TooltipTrigger.vue";
import SidebarMenuButtonChild, {
type SidebarMenuButtonProps,
} from "./SidebarMenuButtonChild.vue";

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { Primitive, type PrimitiveProps } from "radix-vue";
import { Primitive, type PrimitiveProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { type SidebarMenuButtonVariants, sidebarMenuButtonVariants } from ".";

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/lib/utils";
import { type HTMLAttributes, computed } from "vue";
import Skeleton from "~/components/ui/skeleton/Skeleton.vue";
const props = defineProps<{
showIcon?: boolean;

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import type { PrimitiveProps } from "radix-vue";
import { Primitive } from "radix-vue";
import type { PrimitiveProps } from "reka-ui";
import { Primitive } from "reka-ui";
import type { HTMLAttributes } from "vue";
const props = withDefaults(

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { cn } from "@/lib/utils";
import { useEventListener, useMediaQuery, useVModel } from "@vueuse/core";
import { TooltipProvider } from "radix-vue";
import { TooltipProvider } from "reka-ui";
import { type HTMLAttributes, type Ref, computed, ref } from "vue";
import {
SIDEBAR_COOKIE_MAX_AGE,
@ -86,7 +86,8 @@ provideSidebarContext({
'--sidebar-width': SIDEBAR_WIDTH,
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
}"
:class="cn('group/sidebar-wrapper flex h-svh overflow-hidden w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar', props.class)"
:class="cn('group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar', props.class)"
v-bind="$attrs"
>
<slot />
</div>

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "vue";
import Separator from "~/components/ui/separator/Separator.vue";
const props = defineProps<{
class?: HTMLAttributes["class"];

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { PanelLeft } from "lucide-vue-next";
import type { HTMLAttributes } from "vue";
import Button from "~/components/ui/button/Button.vue";
import { useSidebar } from "./utils";
const props = defineProps<{
@ -17,7 +17,7 @@ const { toggleSidebar } = useSidebar();
data-sidebar="trigger"
variant="ghost"
size="icon"
:class="cn('size-7', props.class)"
:class="cn('h-7 w-7', props.class)"
@click="toggleSidebar"
>
<PanelLeft />

View file

@ -1,4 +1,12 @@
import { type VariantProps, cva } from "class-variance-authority";
import type { HTMLAttributes } from "vue";
export interface SidebarProps {
side?: "left" | "right";
variant?: "sidebar" | "floating" | "inset";
collapsible?: "offcanvas" | "icon" | "none";
class?: HTMLAttributes["class"];
}
export { default as Sidebar } from "./Sidebar.vue";
export { default as SidebarContent } from "./SidebarContent.vue";
@ -37,9 +45,9 @@ export const sidebarMenuButtonVariants = cva(
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
},
size: {
default: "h-8 text-sm",
sm: "h-7 text-xs",
lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0",
default: "text-sm",
sm: "text-xs",
lg: "text-sm group-data-[collapsible=icon]:!p-0",
},
},
defaultVariants: {

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