Compare commits

..

34 Commits

Author SHA1 Message Date
HugoRCD
ef5d3d7231 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-07-08 10:26:10 +02:00
HugoRCD
9009b51f78 up 2025-07-08 10:26:07 +02:00
Benjamin Canac
ec569e427b feat(Toast): progress bar with Progress component 2025-07-07 17:10:05 +02:00
Benjamin Canac
1d052ec565 fix(Toast): only show progress when open
Resolves #4464
2025-07-07 16:40:59 +02:00
J-Michalek
1ba8a55bcb fix(Carousel): add aria-current attribute to active dot (#4447)
Co-authored-by: Jakub <jakub.michalek@freelo.io>
2025-07-07 12:09:57 +02:00
Hugo Richard
63730d684b feat(CommandPalette): add footer slot (#4457)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-07-07 12:01:26 +02:00
HugoRCD
b6dc5b98f2 Merge branch 'v3' into feat/init-blog 2025-07-03 16:41:18 +02:00
HugoRCD
d2624313ae Merge branch 'v3' into feat/init-blog 2025-07-02 10:14:42 +02:00
HugoRCD
c98265ee32 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-07-01 10:34:52 +02:00
HugoRCD
2835ea669b up 2025-06-23 17:38:02 +02:00
HugoRCD
7f20093993 up 2025-06-23 16:00:38 +02:00
HugoRCD
ac884bc2db up 2025-06-23 15:19:41 +02:00
Hugo Richard
42d7ddde48 Merge branch 'v3' into feat/init-blog 2025-06-23 12:27:47 +02:00
Hugo Richard
842760d777 Merge branch 'v3' into feat/init-blog 2025-06-17 15:16:34 +02:00
HugoRCD
917849f638 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-26 17:15:37 +02:00
HugoRCD
1368b49de3 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-26 11:41:27 +02:00
HugoRCD
7ea84e3e47 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-23 19:03:53 +02:00
HugoRCD
8045ec7c03 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-19 10:14:49 +02:00
HugoRCD
fb021c4f70 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-15 16:32:48 +02:00
HugoRCD
58b8681a53 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-15 15:44:56 +02:00
HugoRCD
5ed63fa147 Merge branch 'v3' into feat/init-blog 2025-05-14 18:52:54 +02:00
HugoRCD
30b9d11098 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-13 13:52:19 +02:00
HugoRCD
3228f402e8 Merge branch 'v3' into feat/init-blog 2025-05-12 15:39:51 +02:00
HugoRCD
e9b80da977 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-11 19:20:16 +02:00
HugoRCD
c097b6fae2 up 2025-05-07 10:31:33 +02:00
HugoRCD
7050a0cecf Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-06 17:27:44 +02:00
HugoRCD
391feb62df up 2025-05-06 17:27:37 +02:00
HugoRCD
23adf96db7 Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-06 15:44:55 +02:00
HugoRCD
63d92d074f up 2025-05-06 15:44:52 +02:00
HugoRCD
85cf840fde up 2025-05-06 14:38:44 +02:00
HugoRCD
64d574ba6e up 2025-05-06 14:09:34 +02:00
HugoRCD
9589a7ffcf Merge remote-tracking branch 'origin/v3' into feat/init-blog 2025-05-06 13:06:21 +02:00
HugoRCD
4f6cb68b97 up 2025-05-06 13:06:16 +02:00
HugoRCD
7901e5733a feat: init blog 2025-05-06 10:32:24 +02:00
24 changed files with 1440 additions and 279 deletions

View File

@@ -0,0 +1,78 @@
<script setup lang="ts">
const groups = [
{
id: 'actions',
items: [
{
label: 'Add new file',
suffix: 'Create a new file in the current directory',
icon: 'i-lucide-file-plus',
kbds: ['meta', 'N']
},
{
label: 'Add new folder',
suffix: 'Create a new folder in the current directory',
icon: 'i-lucide-folder-plus',
kbds: ['meta', 'F']
},
{
label: 'Search files',
suffix: 'Search across all files in the project',
icon: 'i-lucide-search',
kbds: ['meta', 'P']
},
{
label: 'Settings',
suffix: 'Open application settings',
icon: 'i-lucide-settings',
kbds: ['meta', ',']
}
]
},
{
id: 'recent',
label: 'Recent',
items: [
{
label: 'project.vue',
suffix: 'components/',
icon: 'i-vscode-icons-file-type-vue'
},
{
label: 'readme.md',
suffix: 'docs/',
icon: 'i-vscode-icons-file-type-markdown'
},
{
label: 'package.json',
suffix: 'root/',
icon: 'i-vscode-icons-file-type-node'
}
]
}
]
</script>
<template>
<UCommandPalette :groups="groups" class="flex-1 h-80">
<template #footer>
<div class="flex items-center justify-between gap-2">
<UIcon name="i-simple-icons-nuxtdotjs" class="size-5 text-dimmed ml-1" />
<div class="flex items-center gap-1">
<UButton color="neutral" variant="ghost" label="Open Command" class="text-dimmed" size="xs">
<template #trailing>
<UKbd value="enter" />
</template>
</UButton>
<USeparator orientation="vertical" class="h-4" />
<UButton color="neutral" variant="ghost" label="Actions" class="text-dimmed" size="xs">
<template #trailing>
<UKbd value="meta" />
<UKbd value="k" />
</template>
</UButton>
</div>
</div>
</template>
</UCommandPalette>
</template>

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
const toast = useToast()
function showToast() {
toast.add({
title: 'Uh oh! Something went wrong.',
description: 'There was a problem with your request.',
icon: 'i-lucide-wifi',
progress: false
})
}
</script>
<template>
<UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

View File

@@ -107,6 +107,10 @@ export function useLinks() {
to: 'https://github.com/Justineo/tempad-dev-plugin-nuxt-ui',
target: '_blank'
}]
}, {
label: 'Blog',
icon: 'i-lucide-file-text',
to: '/blog'
}, {
label: 'Releases',
icon: 'i-lucide-rocket',

View File

@@ -57,6 +57,10 @@ export function useSearchLinks() {
description: 'Meet the team behind Nuxt UI.',
icon: 'i-lucide-users',
to: '/team'
}, {
label: 'Blog',
icon: 'i-lucide-file-text',
to: '/blog'
}, {
label: 'Releases',
icon: 'i-lucide-rocket',

View File

@@ -0,0 +1,7 @@
seo:
title: Nuxt UI Blog
description: Read the latest news, tutorials, and updates about Nuxt UI.
title: Nuxt [UI]{.text-primary} Blog
navigation.title: Blog
description: Read the latest news, tutorials, and updates about Nuxt UI.
navigation.icon: i-lucide-newspaper

View File

@@ -0,0 +1,183 @@
<script setup lang="ts">
import { kebabCase } from 'scule'
const route = useRoute()
const [{ data: page }, { data: surround }] = await Promise.all([
useAsyncData(kebabCase(route.path), () => queryCollection('blog').path(route.path).first()),
useAsyncData(`${kebabCase(route.path)}-surround`, () => {
return queryCollectionItemSurroundings('blog', route.path, {
fields: ['description']
}).order('date', 'DESC')
})
])
if (!page.value) {
throw createError({ statusCode: 404, statusMessage: 'Article not found', fatal: true })
}
const title = page.value.seo?.title || page.value.title
const description = page.value.seo?.description || page.value.description
useSeoMeta({
title,
description,
ogDescription: description,
ogTitle: title
})
if (page.value.image) {
defineOgImage({ url: page.value.image })
} else {
defineOgImageComponent('Docs', {
headline: 'Blog',
title,
description
})
}
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
}).toUpperCase()
}
const getCategoryVariant = (category: string) => {
switch (category?.toLowerCase()) {
case 'release': return 'solid'
case 'tutorial': return 'soft'
case 'improvement': return 'soft'
default: return 'soft'
}
}
const getCategoryIcon = (category: string) => {
switch (category?.toLowerCase()) {
case 'release': return 'i-lucide-rocket'
case 'tutorial': return 'i-lucide-book-open'
case 'improvement': return 'i-lucide-trending-up'
default: return 'i-lucide-file-text'
}
}
</script>
<template>
<div v-if="page" class="min-h-screen">
<div class="border-b border-default">
<UContainer class="py-4">
<ULink to="/blog" class="flex items-center gap-2 text-sm">
<UIcon name="i-lucide-chevron-left" class="size-4" />
Back to Blog
</ULink>
</UContainer>
</div>
<div class="py-16 sm:pt-20 pb-10">
<UContainer class="max-w-4xl">
<div class="text-center space-y-6">
<div class="flex items-center justify-center gap-4 text-sm">
<UBadge
v-if="page.category"
:variant="getCategoryVariant(page.category)"
size="sm"
class="font-mono text-xs gap-2"
>
<UIcon :name="getCategoryIcon(page.category)" class="size-3" />
{{ page.category?.toUpperCase() }}
</UBadge>
<span class="text-muted font-mono text-xs">
{{ formatDate(page.date) }}
</span>
<span v-if="page.minRead" class="text-muted font-mono text-xs">
{{ page.minRead }} MIN READ
</span>
</div>
<Motion
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ duration: 0.6 }"
>
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-highlighted leading-tight">
{{ page.title }}
</h1>
</Motion>
<Motion
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: 0.1, duration: 0.6 }"
>
<p class="text-lg text-muted max-w-2xl mx-auto leading-relaxed">
{{ page.description }}
</p>
</Motion>
<Motion
v-if="page.authors?.length"
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: 0.2, duration: 0.6 }"
class="flex justify-center"
>
<UAvatarGroup>
<ULink
v-for="(author, index) in page.authors"
:key="index"
:to="author.to"
raw
>
<UAvatar v-bind="author.avatar" />
</ULink>
</UAvatarGroup>
</Motion>
</div>
</UContainer>
</div>
<div v-if="page.image" class="py-4">
<UContainer class="max-w-6xl">
<Motion
:initial="{ opacity: 0, y: 30 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: 0.3, duration: 0.8 }"
>
<NuxtImg
:src="page.image"
:alt="page.title"
class="w-full max-h-[400px] object-cover object-center max-w-5xl mx-auto"
/>
</Motion>
</UContainer>
</div>
<div class="py-12 sm:py-16">
<UContainer class="max-w-3xl">
<Motion
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: 0.4, duration: 0.6 }"
>
<ContentRenderer
v-if="page.body"
:value="page"
/>
</Motion>
<div v-if="surround?.length" class="mt-16 pt-8 border-t border-default">
<Motion
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: 0.6, duration: 0.6 }"
>
<UContentSurround :surround="surround" />
</Motion>
</div>
</UContainer>
</div>
</div>
</template>

View File

@@ -0,0 +1,255 @@
<script setup lang="ts">
// @ts-expect-error - yaml import not typed
import page from '.blog.yml'
const { data: posts } = await useAsyncData('blogs', () =>
queryCollection('blog').order('date', 'DESC').all()
)
const title = page.seo?.title || page.title
const description = page.seo?.description || page.description
useSeoMeta({
title,
description,
ogTitle: title,
ogDescription: description
})
const selectedFilter = ref('all')
const searchQuery = ref('')
const availableFilters = computed(() => {
if (!posts.value?.length) return [{ key: 'all', label: 'ALL', count: 0 }]
const postsData = posts.value
const categories = new Set(postsData.map(post => post.category?.toLowerCase()).filter(Boolean))
const filters = [
{ key: 'all', label: 'ALL', count: postsData.length }
]
categories.forEach((category) => {
const count = postsData.filter(p => p.category?.toLowerCase() === category).length
const label = category.replace(/\b\w/g, l => l.toUpperCase()).replace(/([a-z])([A-Z])/g, '$1 $2')
filters.push({
key: category,
label: label,
count
})
})
return filters.sort((a, b) => {
if (a.key === 'all') return -1
if (b.key === 'all') return 1
return b.count - a.count
})
})
const filteredPosts = computed(() => {
if (!posts.value) return []
let filtered = posts.value
if (selectedFilter.value !== 'all') {
filtered = filtered.filter(post => post.category?.toLowerCase() === selectedFilter.value)
}
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
filtered = filtered.filter(post =>
post.title?.toLowerCase().includes(query)
|| post.description?.toLowerCase().includes(query)
)
}
return filtered
})
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {
month: 'short',
day: '2-digit'
}).toUpperCase()
}
const getCategoryVariant = (category: string) => {
switch (category?.toLowerCase()) {
case 'release': return 'solid'
case 'tutorial': return 'soft'
case 'improvement': return 'soft'
default: return 'soft'
}
}
const getCategoryIcon = (category: string) => {
switch (category?.toLowerCase()) {
case 'release': return 'i-lucide-rocket'
case 'tutorial': return 'i-lucide-book-open'
case 'improvement': return 'i-lucide-trending-up'
default: return 'i-lucide-file-text'
}
}
</script>
<template>
<div v-if="page" class="relative grid grid-rows-[auto_auto_1fr] min-h-[calc(100vh-150px)]">
<UPageHero :links="page.links" :ui="{ container: 'relative py-10 sm:py-16 lg:py-24' }">
<LazyStarsBg />
<div aria-hidden="true" class="absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<template #title>
<MDC :value="page.title" unwrap="p" cache-key="pro-templates-hero-title" />
</template>
<template #description>
<MDC :value="page.description" unwrap="p" cache-key="pro-templates-hero-description" />
</template>
</UPageHero>
<UPageBody class="!my-0 !py-0 border-y border-default">
<UContainer>
<div class="border-x border-default px-4 sm:px-6 py-6 sm:py-8">
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-6 lg:gap-8 sm:mb-6">
<div class="flex flex-wrap items-center gap-2 sm:gap-3">
<Motion
v-for="(filter, index) in availableFilters"
:key="filter.key"
:initial="{ opacity: 0, y: 10 }"
:animate="{ opacity: 1, y: 0 }"
:transition="{ delay: index * 0.1 }"
>
<UButton
:variant="selectedFilter === filter.key ? 'solid' : 'ghost'"
:color="selectedFilter === filter.key ? 'primary' : 'neutral'"
size="sm"
class="font-medium transition-all duration-200 hover:scale-105 focus:scale-100 rounded-none text-xs sm:text-sm"
:leading-icon="selectedFilter === filter.key ? 'i-lucide-check' : 'i-lucide-circle'"
:label="filter.label"
@click="selectedFilter = filter.key"
>
<template #trailing>
<UBadge
:variant="selectedFilter === filter.key ? 'solid' : 'soft'"
size="xs"
>
{{ filter.count }}
</UBadge>
</template>
</UButton>
</Motion>
</div>
<div class="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 sm:gap-3">
<div class="relative">
<UInput
v-model="searchQuery"
placeholder="Search posts..."
icon="i-lucide-search"
class="w-full sm:w-64"
:ui="{
base: 'rounded-none'
}"
/>
</div>
<UButton
variant="ghost"
class="rounded-none whitespace-nowrap"
icon="i-lucide-external-link"
label="Follow @nuxt_js on X"
to="https://x.com/nuxt_js"
target="_blank"
/>
</div>
</div>
</div>
<div class="border-x border-t border-default !gap-0">
<Motion
v-for="(post, index) in filteredPosts"
:key="post.path"
:initial="{ opacity: 0, x: -20 }"
:animate="{ opacity: 1, x: 0 }"
:transition="{ delay: index * 0.05, type: 'spring', stiffness: 300, damping: 30 }"
class="group border-b border-default last:border-b-0"
>
<ULink
:to="post.path"
class="flex flex-col sm:flex-row sm:items-center justify-between p-4 sm:p-6 hover:bg-muted/30 transition-all duration-200 gap-4 sm:gap-6"
>
<div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-6 flex-1 min-w-0">
<div class="text-xs text-muted font-mono shrink-0 sm:min-w-[60px]">
{{ formatDate(post.date) }}
</div>
<UBadge
:variant="getCategoryVariant(post.category)"
size="sm"
class="font-mono text-xs justify-center gap-2 shrink-0 self-start sm:self-center"
>
<UIcon :name="getCategoryIcon(post.category)" class="size-3" />
{{ post.category?.toUpperCase() || 'POST' }}
</UBadge>
<div class="flex-1 min-w-0">
<h3 class="font-medium text-highlighted group-hover:text-primary transition-colors duration-200 truncate sm:text-base">
{{ post.title }}
</h3>
<p class="text-sm text-muted mt-1 line-clamp-2 sm:line-clamp-1">
{{ post.description }}
</p>
</div>
</div>
<div class="flex items-center justify-between sm:justify-end gap-3 sm:gap-2 shrink-0">
<UAvatarGroup v-if="post.authors?.length" size="sm" class="sm:size-sm">
<UAvatar
v-for="author in post.authors.slice(0, 3)"
:key="author.name"
:src="author.avatar?.src"
:alt="author.name"
size="sm"
/>
</UAvatarGroup>
<UIcon
name="i-lucide-chevron-right"
class="size-4 text-muted group-hover:text-highlighted transition-colors duration-200 shrink-0"
/>
</div>
</ULink>
</Motion>
<Motion
v-if="filteredPosts.length === 0"
:initial="{ opacity: 0, y: 20 }"
:animate="{ opacity: 1, y: 0 }"
class="text-center py-12 sm:py-16 px-4 sm:px-6"
>
<UIcon name="i-lucide-search-x" class="size-10 sm:size-12 text-muted mx-auto mb-4" />
<h3 class="text-lg font-medium mb-2">
No posts found
</h3>
<p class="text-muted mb-4 text-sm sm:text-base">
{{ searchQuery ? `No posts match "${searchQuery}"` : 'No posts in this category yet' }}
</p>
<UButton
v-if="selectedFilter !== 'all' || searchQuery"
variant="outline"
label="Clear filters"
class="rounded-none"
@click="selectedFilter = 'all'; searchQuery = ''"
/>
</Motion>
</div>
</UContainer>
</UPageBody>
<UContainer class="relative min-h-24">
<div aria-hidden="true" class="absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
</UContainer>
</div>
</template>

View File

@@ -13,6 +13,22 @@ const Button = z.object({
target: z.enum(['_blank', '_self']).optional()
})
const Image = z.object({
src: z.string(),
alt: z.string(),
width: z.number().optional(),
height: z.number().optional()
})
const Author = z.object({
name: z.string(),
description: z.string().optional(),
username: z.string().optional(),
twitter: z.string().optional(),
to: z.string().optional(),
avatar: Image.optional()
})
const schema = z.object({
category: z.enum(['layout', 'form', 'element', 'navigation', 'data', 'overlay']).optional(),
framework: z.string().optional(),
@@ -75,5 +91,18 @@ export const collections = {
})
}))
})
}),
blog: defineCollection({
type: 'page',
source: 'blog/*',
schema: z.object({
image: z.string().editor({ input: 'media' }),
authors: z.array(Author),
date: z.string().date(),
minRead: z.number(),
draft: z.boolean().optional(),
category: z.enum(['Release', 'Tutorial', 'Announcement', 'Article']),
tags: z.array(z.string())
})
})
}

View File

@@ -877,6 +877,20 @@ props:
This can be useful when using the CommandPalette inside a [`Modal`](/components/modal) for example.
::
### With footer slot :badge{label="Soon" class="align-text-top"}
Use the `#footer` slot to add custom content at the bottom of the CommandPalette, such as keyboard shortcuts help or additional actions.
::component-example
---
collapse: true
name: 'command-palette-footer-slot-example'
class: '!p-0'
props:
autofocus: false
---
::
### With custom slot
Use the `slot` property to customize a specific item or group.

View File

@@ -107,7 +107,7 @@ name: 'toast-color-example'
### Close
Pass a `close` field to customize or hide the close button (with `false` value).
Pass a `close` field to customize or hide the close [Button](/components/button) (with `false` value).
::component-example
---
@@ -143,7 +143,7 @@ You can customize this icon globally in your `vite.config.ts` under `ui.icons.cl
### Actions
Pass an `actions` field to add some [Button](/components/button) actions to the Alert.
Pass an `actions` field to add some [Button](/components/button) actions to the Toast.
::component-example
---
@@ -155,9 +155,23 @@ name: 'toast-actions-example'
---
::
### Progress :badge{label="Soon" class="align-text-top"}
Pass a `progress` field to customize or hide the [Progress](/components/progress) bar (with `false` value).
::tip
The Progress bar inherits the Toast color by default, but you can override it using the `progress.color` field.
::
::component-example
---
name: 'toast-progress-example'
---
::
### Orientation
Use the `orientation` prop to change the orientation of the Toast.
Pass an `orientation` field to the `toast.add` method to change the orientation of the Toast.
::component-example
---

View File

@@ -0,0 +1,198 @@
---
title: Nuxt UI v3
description: Nuxt UI v3 is out! After 1500+ commits, this major redesign brings
improved accessibility, Tailwind CSS v4 support, and full Vue compatibility
navigation: false
image: /assets/blog/nuxt-ui-v3.png
minRead: 7
authors:
- name: Benjamin Canac
avatar:
src: https://github.com/benjamincanac.png
to: https://x.com/benjamincanac
- name: Sébastien Chopin
avatar:
src: https://github.com/atinux.png
to: https://x.com/atinux
- name: Hugo Richard
avatar:
src: https://github.com/hugorcd.png
to: https://x.com/hugorcd__
date: 2025-03-12T10:00:00.000Z
category: Release
---
We are thrilled to announce the release of Nuxt UI v3, a complete redesign of our UI library that brings significant improvements in accessibility, performance, and developer experience. This major update represents over 1500 commits of hard work, collaboration, and innovation from our team and the community.
## 🚀 Reimagined from the Ground Up
Nuxt UI v3 represents a major leap forward in our journey to provide the most comprehensive UI solution for Vue and Nuxt developers. This version has been rebuilt from the ground up with modern technologies and best practices in mind.
### **From HeadlessUI to Reka UI**
With Reka UI at its core, Nuxt UI v3 delivers:
• Proper keyboard navigation across all interactive components
• ARIA attributes automatically handled for you
• Focus management that just works
• Screen reader friendly components out of the box
This means you can build applications that work for everyone without becoming an accessibility expert.
### **Tailwind CSS v4 Integration**
The integration with Tailwind CSS v4 brings huge performance improvements:
**5x faster runtime** with optimized component rendering
**100x faster build times** thanks to the new CSS-first engine
• Smaller bundle sizes with more efficient styling
Your applications will feel snappier, build quicker, and load faster for your users.
## 🎨 A Brand New Design System
```html
<!-- Before: Inconsistent color usage with duplicate dark mode classes -->
<div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg">
<h2 class="text-gray-900 dark:text-white text-xl mb-2">User Profile</h2>
<p class="text-gray-600 dark:text-gray-300">Account settings and preferences</p>
<button class="bg-blue-500 text-white px-3 py-1 rounded mt-2">Edit Profile</button>
</div>
```
```html
<!-- After: Semantic design tokens with automatic dark mode support -->
<div class="bg-muted p-4 rounded-lg">
<h2 class="text-highlighted text-xl mb-2">User Profile</h2>
<p class="text-muted">Account settings and preferences</p>
<UButton color="primary" size="sm" class="mt-2">Edit Profile</UButton>
</div>
```
Our new color system includes 7 semantic color aliases:
| Color | Default | Description |
|-----------------------------------|----------|--------------------------------------------------|
| :code[primary]{.text-primary} | `blue` | Primary color to represent the brand.
| :code[secondary]{.text-secondary} | `blue` | Secondary color to complement the primary color.
| :code[success]{.text-success} | `green` | Used for success states.
| :code[info]{.text-info} | `blue` | Used for informational states.
| :code[warning]{.text-warning} | `yellow` | Used for warning states.
| :code[error]{.text-error} | `red` | Used for form error validation states. |
| `neutral` | `slate` | Neutral color for backgrounds, text, etc. |
This approach makes your codebase more maintainable and your UI more consistent—especially when working in teams. With these semantic tokens, light and dark mode transitions become effortless, as the system automatically handles the appropriate color values for each theme without requiring duplicate class definitions.
## 💚 Complete Vue Compatibility
We're really happy to expand the scope of Nuxt UI beyond the Nuxt framework. With v3, both Nuxt UI and Nuxt UI Pro now work seamlessly in any Vue project, this means you can:
• Use the same components across all your Vue projects
• Benefit from Nuxt UI's theming system in any Vue application
• Enjoy auto-imports and TypeScript support outside of Nuxt
• Leverage both basic components and advanced Pro components in any Vue project
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui()
]
})
```
## 📦 Components for Every Need
With 54 core components, 50 Pro components, and 42 Prose components, Nuxt UI v3 provides solutions for virtually any UI challenge:
• **Data Display**: Tables, charts, and visualizations that adapt to your data
• **Navigation**: Menus, tabs, and breadcrumbs that guide users intuitively
• **Feedback**: Toasts, alerts, and modals that communicate clearly
• **Forms**: Inputs, selectors, and validation that simplify data collection
• **Layout**: Grids, containers, and responsive systems that organize content beautifully
Each component is designed to be both beautiful out of the box and deeply customizable when needed.
## 🔷 Improved TypeScript Integration
We've completely revamped our TypeScript integration, with features that make you more productive:
- Complete type safety with helpful autocompletion
- Generic-based components for flexible APIs
- Type-safe theming through a clear, consistent API
```ts
export default defineAppConfig({
ui: {
button: {
// Your IDE will show all available options
slots: {
base: 'font-bold rounded-lg'
},
defaultVariants: {
size: 'md',
color: 'error'
}
}
}
})
```
## ⬆️ Upgrading to v3
We've prepared a comprehensive [migration](https://ui.nuxt.com/getting-started/migration) guide to help you upgrade from v2 to v3. While there are breaking changes due to our complete overhaul, we've worked hard to make the transition as smooth as possible.
## 🎯 Getting Started
Whether you're starting a new project or upgrading an existing one, getting started with Nuxt UI v3 is easy:
```bash
# Create a new Nuxt project with Nuxt UI
npx nuxi@latest init my-app -t ui
```
::code-group{sync="pm"}
```bash [pnpm]
pnpm add @nuxt/ui@latest
```
```bash [yarn]
yarn add @nuxt/ui@latest
```
```bash [npm]
npm install @nuxt/ui@latest
```
```bash [bun]
bun add @nuxt/ui@latest
```
::
::warning
If you're using **pnpm**, ensure that you either set [`shamefully-hoist=true`](https://pnpm.io/npmrc#shamefully-hoist) in your `.npmrc` file or install `tailwindcss` in your project's root directory.
::
Visit our [documentation](https://ui.nuxt.com/getting-started) to explore all the components and features available in Nuxt UI v3.
## 🙏 Thank You
This release represents thousands of hours of work from our team and the community. We'd like to thank everyone who contributed to making Nuxt UI v3 a reality.
We're excited to see what you'll build with Nuxt UI v3!

View File

@@ -0,0 +1,198 @@
---
title: Nuxt UI
description: Nuxt UI v3 is out! After 1500+ commits, this major redesign brings
improved accessibility, Tailwind CSS v4 support, and full Vue compatibility
navigation: false
image: /assets/blog/nuxt-ui-v3.png
minRead: 7
authors:
- name: Benjamin Canac
avatar:
src: https://github.com/benjamincanac.png
to: https://x.com/benjamincanac
- name: Sébastien Chopin
avatar:
src: https://github.com/atinux.png
to: https://x.com/atinux
- name: Hugo Richard
avatar:
src: https://github.com/hugorcd.png
to: https://x.com/hugorcd__
date: 2025-03-12T09:00:00.000Z
category: improvement
---
We are thrilled to announce the release of Nuxt UI v3, a complete redesign of our UI library that brings significant improvements in accessibility, performance, and developer experience. This major update represents over 1500 commits of hard work, collaboration, and innovation from our team and the community.
## 🚀 Reimagined from the Ground Up
Nuxt UI v3 represents a major leap forward in our journey to provide the most comprehensive UI solution for Vue and Nuxt developers. This version has been rebuilt from the ground up with modern technologies and best practices in mind.
### **From HeadlessUI to Reka UI**
With Reka UI at its core, Nuxt UI v3 delivers:
• Proper keyboard navigation across all interactive components
• ARIA attributes automatically handled for you
• Focus management that just works
• Screen reader friendly components out of the box
This means you can build applications that work for everyone without becoming an accessibility expert.
### **Tailwind CSS v4 Integration**
The integration with Tailwind CSS v4 brings huge performance improvements:
**5x faster runtime** with optimized component rendering
**100x faster build times** thanks to the new CSS-first engine
• Smaller bundle sizes with more efficient styling
Your applications will feel snappier, build quicker, and load faster for your users.
## 🎨 A Brand New Design System
```html
<!-- Before: Inconsistent color usage with duplicate dark mode classes -->
<div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg">
<h2 class="text-gray-900 dark:text-white text-xl mb-2">User Profile</h2>
<p class="text-gray-600 dark:text-gray-300">Account settings and preferences</p>
<button class="bg-blue-500 text-white px-3 py-1 rounded mt-2">Edit Profile</button>
</div>
```
```html
<!-- After: Semantic design tokens with automatic dark mode support -->
<div class="bg-muted p-4 rounded-lg">
<h2 class="text-highlighted text-xl mb-2">User Profile</h2>
<p class="text-muted">Account settings and preferences</p>
<UButton color="primary" size="sm" class="mt-2">Edit Profile</UButton>
</div>
```
Our new color system includes 7 semantic color aliases:
| Color | Default | Description |
|-----------------------------------|----------|--------------------------------------------------|
| :code[primary]{.text-primary} | `blue` | Primary color to represent the brand.
| :code[secondary]{.text-secondary} | `blue` | Secondary color to complement the primary color.
| :code[success]{.text-success} | `green` | Used for success states.
| :code[info]{.text-info} | `blue` | Used for informational states.
| :code[warning]{.text-warning} | `yellow` | Used for warning states.
| :code[error]{.text-error} | `red` | Used for form error validation states. |
| `neutral` | `slate` | Neutral color for backgrounds, text, etc. |
This approach makes your codebase more maintainable and your UI more consistent—especially when working in teams. With these semantic tokens, light and dark mode transitions become effortless, as the system automatically handles the appropriate color values for each theme without requiring duplicate class definitions.
## 💚 Complete Vue Compatibility
We're really happy to expand the scope of Nuxt UI beyond the Nuxt framework. With v3, both Nuxt UI and Nuxt UI Pro now work seamlessly in any Vue project, this means you can:
• Use the same components across all your Vue projects
• Benefit from Nuxt UI's theming system in any Vue application
• Enjoy auto-imports and TypeScript support outside of Nuxt
• Leverage both basic components and advanced Pro components in any Vue project
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui()
]
})
```
## 📦 Components for Every Need
With 54 core components, 50 Pro components, and 42 Prose components, Nuxt UI v3 provides solutions for virtually any UI challenge:
• **Data Display**: Tables, charts, and visualizations that adapt to your data
• **Navigation**: Menus, tabs, and breadcrumbs that guide users intuitively
• **Feedback**: Toasts, alerts, and modals that communicate clearly
• **Forms**: Inputs, selectors, and validation that simplify data collection
• **Layout**: Grids, containers, and responsive systems that organize content beautifully
Each component is designed to be both beautiful out of the box and deeply customizable when needed.
## 🔷 Improved TypeScript Integration
We've completely revamped our TypeScript integration, with features that make you more productive:
- Complete type safety with helpful autocompletion
- Generic-based components for flexible APIs
- Type-safe theming through a clear, consistent API
```ts
export default defineAppConfig({
ui: {
button: {
// Your IDE will show all available options
slots: {
base: 'font-bold rounded-lg'
},
defaultVariants: {
size: 'md',
color: 'error'
}
}
}
})
```
## ⬆️ Upgrading to v3
We've prepared a comprehensive [migration](https://ui.nuxt.com/getting-started/migration) guide to help you upgrade from v2 to v3. While there are breaking changes due to our complete overhaul, we've worked hard to make the transition as smooth as possible.
## 🎯 Getting Started
Whether you're starting a new project or upgrading an existing one, getting started with Nuxt UI v3 is easy:
```bash
# Create a new Nuxt project with Nuxt UI
npx nuxi@latest init my-app -t ui
```
::code-group{sync="pm"}
```bash [pnpm]
pnpm add @nuxt/ui@latest
```
```bash [yarn]
yarn add @nuxt/ui@latest
```
```bash [npm]
npm install @nuxt/ui@latest
```
```bash [bun]
bun add @nuxt/ui@latest
```
::
::warning
If you're using **pnpm**, ensure that you either set [`shamefully-hoist=true`](https://pnpm.io/npmrc#shamefully-hoist) in your `.npmrc` file or install `tailwindcss` in your project's root directory.
::
Visit our [documentation](https://ui.nuxt.com/getting-started) to explore all the components and features available in Nuxt UI v3.
## 🙏 Thank You
This release represents thousands of hours of work from our team and the community. We'd like to thank everyone who contributed to making Nuxt UI v3 a reality.
We're excited to see what you'll build with Nuxt UI v3!

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 KiB

View File

@@ -10,9 +10,8 @@ const open = ref(false)
const searchTerm = ref('')
// const searchTermDebounced = refDebounced(searchTerm, 200)
const selected = ref([])
const commandPalette = useTemplateRef('commandPalette')
const { data: _users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
// params: { q: searchTermDebounced },
transform: (data: User[]) => {
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
@@ -23,6 +22,10 @@ const { data: _users, status } = await useFetch('https://jsonplaceholder.typicod
const loading = ref(false)
const groups = computed(() => [{
id: 'users',
label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
items: users.value || []
}, {
id: 'actions',
items: [{
label: 'Add new file',
@@ -71,12 +74,6 @@ const groups = computed(() => [{
toast.add({ title: 'Label added!' })
},
kbds: ['meta', 'L']
}, {
label: 'Set Wallpaper',
suffix: 'Choose from beautiful wallpaper collection.',
icon: 'i-lucide-image',
view: 'wallpaper',
placeholder: 'Search wallpapers...'
}, {
label: 'More actions',
placeholder: 'Search actions...',
@@ -143,116 +140,6 @@ const labels = [{
}]
const label = ref()
const wallpapers = [
{
id: 1,
name: 'red_distortion_1',
gradient: 'from-red-500 via-orange-500 to-pink-500',
category: 'Abstract',
featured: true
},
{
id: 2,
name: 'blue_distortion_1',
gradient: 'from-blue-600 via-purple-600 to-indigo-600',
category: 'Abstract',
featured: true
},
{
id: 3,
name: 'mono_dark_distortion_1',
gradient: 'from-gray-900 via-gray-700 to-gray-800',
category: 'Monochrome',
featured: false
},
{
id: 4,
name: 'chromatic_dark_1',
gradient: 'from-emerald-600 via-teal-600 to-cyan-600',
category: 'Chromatic',
featured: true
},
{
id: 5,
name: 'red_distortion_2',
gradient: 'from-rose-600 via-red-600 to-orange-600',
category: 'Abstract',
featured: false
},
{
id: 6,
name: 'purple_cosmic_1',
gradient: 'from-violet-700 via-purple-700 to-fuchsia-700',
category: 'Cosmic',
featured: true
},
{
id: 7,
name: 'golden_sunset_1',
gradient: 'from-yellow-500 via-orange-500 to-red-500',
category: 'Nature',
featured: false
},
{
id: 8,
name: 'ocean_deep_1',
gradient: 'from-blue-800 via-blue-900 to-indigo-900',
category: 'Nature',
featured: true
},
{
id: 9,
name: 'mono_light_distortion_1',
gradient: 'from-gray-200 via-gray-300 to-gray-400',
category: 'Monochrome',
featured: false
},
{
id: 10,
name: 'green_matrix_1',
gradient: 'from-green-800 via-emerald-700 to-teal-700',
category: 'Chromatic',
featured: false
},
{
id: 11,
name: 'pink_dreams_1',
gradient: 'from-pink-500 via-rose-500 to-purple-500',
category: 'Abstract',
featured: true
},
{
id: 12,
name: 'midnight_blue_1',
gradient: 'from-slate-900 via-blue-900 to-indigo-900',
category: 'Nature',
featured: false
}
]
const filteredWallpapers = computed(() => {
let filtered = wallpapers
// Filter by search term
if (searchTerm.value.trim()) {
const search = searchTerm.value.toLowerCase()
filtered = filtered.filter(w =>
w.name.toLowerCase().includes(search)
|| w.category.toLowerCase().includes(search)
)
}
return filtered
})
function setWallpaper(wallpaper: any) {
toast.add({
title: `Wallpaper set to ${wallpaper.name}!`,
description: 'Your desktop wallpaper has been updated.',
icon: 'i-lucide-image'
})
}
// function onSelect(item: typeof groups.value[number]['items'][number]) {
function onSelect(item: any) {
console.log('Selected', item)
@@ -260,12 +147,6 @@ function onSelect(item: any) {
defineShortcuts({
meta_k: () => open.value = !open.value,
meta_shift_a: {
usingInput: true,
handler: () => {
commandPalette.value?.openView('askAI')
}
},
...extractShortcuts(groups.value)
})
</script>
@@ -273,7 +154,6 @@ defineShortcuts({
<template>
<DefineTemplate>
<UCommandPalette
ref="commandPalette"
v-model="selected"
v-model:search-term="searchTerm"
:loading="status === 'pending'"
@@ -287,49 +167,25 @@ defineShortcuts({
class="sm:max-h-80"
@update:model-value="onSelect"
>
<template #wallpaper>
<div class="flex-1 overflow-y-auto p-6">
<div class="grid grid-cols-4 gap-4">
<div
v-for="wallpaper in filteredWallpapers"
:key="wallpaper.id"
class="group relative cursor-pointer"
@click="setWallpaper(wallpaper)"
>
<div
class="aspect-video rounded-lg bg-gradient-to-br shadow-lg ring-1 ring-black/5"
:class="wallpaper.gradient"
/>
<div class="mt-2 px-1">
<div class="flex items-center gap-2">
<h3 class="text-sm font-medium text-highlighted truncate">
{{ wallpaper.name }}
</h3>
<UChip
v-if="wallpaper.featured"
label="★"
size="xs"
color="primary"
class="shrink-0"
/>
</div>
<p class="text-xs text-dimmed">
{{ wallpaper.category }}
</p>
</div>
</div>
<template #footer>
<div class="flex items-center justify-between gap-2">
<UIcon name="i-simple-icons-nuxtdotjs" class="size-5 text-dimmed ml-1" />
<div class="flex items-center gap-1">
<UButton color="neutral" variant="ghost" label="Open Command" class="text-dimmed" size="xs">
<template #trailing>
<UKbd value="enter" />
</template>
</UButton>
<USeparator orientation="vertical" class="h-4" />
<UButton color="neutral" variant="ghost" label="Actions" class="text-dimmed" size="xs">
<template #trailing>
<UKbd value="meta" />
<UKbd value="k" />
</template>
</UButton>
</div>
</div>
</template>
<template #askAI>
<div class="flex flex-col items-center justify-center gap-4 p-6">
<UIcon name="i-lucide-sparkles" class="size-8 text-primary" />
<span class="text-lg font-semibold text-highlighted">
Ask me anything...
</span>
</div>
</template>
</UCommandPalette>
</DefineTemplate>

View File

@@ -339,6 +339,7 @@ defineExpose({
:aria-label="t('carousel.goto', { slide: index + 1 })"
:class="ui.dot({ class: props.ui?.dot, active: selectedIndex === index })"
:data-state="selectedIndex === index ? 'active' : undefined"
:aria-current="selectedIndex === index ? true : undefined"
@click="scrollTo(index)"
/>
</template>

View File

@@ -31,11 +31,6 @@ export interface CommandPaletteItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
*/
placeholder?: string
children?: CommandPaletteItem[]
/**
* Custom view to display instead of children items.
* When defined, clicking this item will show the custom view.
*/
view?: string
onSelect?(e?: Event): void
class?: any
ui?: Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemLabel' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>
@@ -152,13 +147,14 @@ type SlotProps<T> = (props: { item: T, index: number }) => any
export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPaletteGroup<any>, T extends CommandPaletteItem = CommandPaletteItem> = {
'empty'(props: { searchTerm?: string }): any
'footer'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
'back'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
'close'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
'item': SlotProps<T>
'item-leading': SlotProps<T>
'item-label': SlotProps<T>
'item-trailing': SlotProps<T>
} & Record<string, SlotProps<G>> & Record<string, SlotProps<T>> & Record<string, (props: { current: any, searchTerm: string, navigateBack: () => void, close: () => void }) => any>
} & Record<string, SlotProps<G>> & Record<string, SlotProps<T>>
</script>
@@ -213,17 +209,12 @@ const fuse = computed(() => defu({}, props.fuse, {
matchAllWhenSearchEmpty: true
}))
const history = ref<(CommandPaletteGroup & { placeholder?: string, view?: string })[]>([])
const history = ref<(CommandPaletteGroup & { placeholder?: string })[]>([])
const placeholder = computed(() => history.value[history.value.length - 1]?.placeholder || props.placeholder || t('commandPalette.placeholder'))
const groups = computed(() => history.value?.length ? [history.value[history.value.length - 1] as G] : props.groups)
const currentView = computed(() => {
const current = history.value[history.value.length - 1]
return current?.view ? current : null
})
const items = computed(() => groups.value?.filter((group) => {
if (!group.id) {
console.warn(`[@nuxt/ui] CommandPalette group is missing an \`id\` property`)
@@ -289,33 +280,8 @@ const filteredGroups = computed(() => {
const listboxRootRef = useTemplateRef('listboxRootRef')
// Exposed methods for programmatic control
function openView(viewName: string) {
history.value.push({
id: `view-${viewName}`,
label: viewName,
view: viewName,
items: []
} as any)
searchTerm.value = ''
listboxRootRef.value?.highlightFirstItem()
}
function closeView() {
if (history.value.length > 0) {
navigateBack()
}
}
defineExpose({
openView,
closeView,
navigateBack
})
function navigate(item: T) {
if (!item.children?.length && !item.view) {
if (!item.children?.length) {
return
}
@@ -324,8 +290,7 @@ function navigate(item: T) {
label: item.label,
slot: item.slot,
placeholder: item.placeholder,
view: item.view,
items: item.children || []
items: item.children
} as any)
searchTerm.value = ''
@@ -352,7 +317,7 @@ function onBackspace() {
}
function onSelect(e: Event, item: T) {
if (item.children?.length || item.view) {
if (item.children?.length) {
e.preventDefault()
navigate(item)
@@ -407,17 +372,7 @@ function onSelect(e: Event, item: T) {
</ListboxFilter>
<ListboxContent :class="ui.content({ class: props.ui?.content })">
<div v-if="currentView" :class="ui.viewport({ class: props.ui?.viewport })">
<slot
:name="currentView.view"
:current="currentView"
:search-term="searchTerm"
:navigate-back="navigateBack"
:close="closeView"
/>
</div>
<div v-else-if="filteredGroups?.length" role="presentation" :class="ui.viewport({ class: props.ui?.viewport })">
<div v-if="filteredGroups?.length" role="presentation" :class="ui.viewport({ class: props.ui?.viewport })">
<ListboxGroup v-for="group in filteredGroups" :key="`group-${group.id}`" :class="ui.group({ class: props.ui?.group })">
<ListboxGroupLabel v-if="get(group, props.labelKey as string)" :class="ui.label({ class: props.ui?.label })">
{{ get(group, props.labelKey as string) }}
@@ -461,7 +416,7 @@ function onSelect(e: Event, item: T) {
<span :class="ui.itemTrailing({ class: [props.ui?.itemTrailing, item.ui?.itemTrailing] })">
<slot :name="((item.slot ? `${item.slot}-trailing` : group.slot ? `${group.slot}-trailing` : `item-trailing`) as keyof CommandPaletteSlots<G, T>)" :item="(item as any)" :index="index">
<UIcon
v-if="(item.children && item.children.length > 0) || item.view"
v-if="item.children && item.children.length > 0"
:name="trailingIcon || appConfig.ui.icons.chevronRight"
:class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, item.ui?.itemTrailingIcon] })"
/>
@@ -490,5 +445,9 @@ function onSelect(e: Event, item: T) {
</slot>
</div>
</ListboxContent>
<div v-if="!!slots.footer" :class="ui.footer({ class: props.ui?.footer })">
<slot name="footer" :ui="ui" />
</div>
</ListboxRoot>
</template>

View File

@@ -2,7 +2,7 @@
import type { ToastRootProps, ToastRootEmits } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/toast'
import type { AvatarProps, ButtonProps } from '../types'
import type { AvatarProps, ButtonProps, ProgressProps } from '../types'
import type { StringOrVNode, ComponentConfig } from '../types/utils'
type Toast = ComponentConfig<typeof theme, AppConfig, 'toast'>
@@ -29,18 +29,6 @@ export interface ToastProps extends Pick<ToastRootProps, 'defaultOpen' | 'open'
* @defaultValue 'vertical'
*/
orientation?: Toast['variants']['orientation']
/**
* Whether to show the progress bar.
* @defaultValue true
*/
progress?: boolean
/**
* Display a list of actions:
* - under the title and description when orientation is `vertical`
* - next to the close button when orientation is `horizontal`
* `{ size: 'xs' }`{lang="ts-type"}
*/
actions?: ButtonProps[]
/**
* Display a close button to dismiss the toast.
* `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"}
@@ -53,6 +41,19 @@ export interface ToastProps extends Pick<ToastRootProps, 'defaultOpen' | 'open'
* @IconifyIcon
*/
closeIcon?: string
/**
* Display a list of actions:
* - under the title and description when orientation is `vertical`
* - next to the close button when orientation is `horizontal`
* `{ size: 'xs' }`{lang="ts-type"}
*/
actions?: ButtonProps[]
/**
* Display a progress bar showing the toast's remaining duration.
* `{ size: 'sm' }`{lang="ts-type"}
* @defaultValue true
*/
progress?: boolean | Pick<ProgressProps, 'color'>
class?: any
ui?: Toast['slots']
}
@@ -78,10 +79,11 @@ import { tv } from '../utils/tv'
import UIcon from './Icon.vue'
import UAvatar from './Avatar.vue'
import UButton from './Button.vue'
import UProgress from './Progress.vue'
const props = withDefaults(defineProps<ToastProps>(), {
close: true,
orientation: 'vertical',
close: true,
progress: true
})
const emits = defineEmits<ToastEmits>()
@@ -119,7 +121,7 @@ defineExpose({
<template>
<ToastRoot
ref="el"
v-slot="{ remaining, duration }"
v-slot="{ remaining, duration, open }"
v-bind="rootProps"
:data-orientation="orientation"
:class="ui.root({ class: [props.ui?.root, props.class] })"
@@ -184,6 +186,13 @@ defineExpose({
</ToastClose>
</div>
<div v-if="progress && remaining > 0 && duration" :class="ui.progress({ class: props.ui?.progress })" :style="{ width: `${remaining / duration * 100}%` }" />
<UProgress
v-if="progress && open && remaining > 0 && duration"
:model-value="remaining / duration * 100"
:color="color"
v-bind="(typeof progress === 'object' ? progress as Partial<ProgressProps> : {})"
size="sm"
:class="ui.progress({ class: props.ui?.progress })"
/>
</ToastRoot>
</template>

View File

@@ -7,6 +7,7 @@ export default (options: Required<ModuleOptions>) => ({
close: '',
back: 'p-0',
content: 'relative overflow-hidden flex flex-col',
footer: 'p-1',
viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1 focus:outline-none',
group: 'p-1 isolate',
empty: 'py-6 text-center text-sm text-muted',

View File

@@ -10,20 +10,18 @@ export default (options: Required<ModuleOptions>) => ({
avatar: 'shrink-0',
avatarSize: '2xl',
actions: 'flex gap-1.5 shrink-0',
progress: 'absolute inset-x-0 bottom-0 h-1 z-[-1]',
progress: 'absolute inset-x-0 bottom-0',
close: 'p-0'
},
variants: {
color: {
...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, {
root: `focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-${color}`,
icon: `text-${color}`,
progress: `bg-${color}`
icon: `text-${color}`
}])),
neutral: {
root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted',
icon: 'text-highlighted',
progress: 'bg-inverted'
icon: 'text-highlighted'
}
},
orientation: {

View File

@@ -89,7 +89,8 @@ describe('CommandPalette', () => {
['with item-label slot', { props, slots: { 'item-label': () => 'Item label slot' } }],
['with item-trailing slot', { props, slots: { 'item-trailing': () => 'Item trailing slot' } }],
['with custom slot', { props, slots: { custom: () => 'Custom slot' } }],
['with close slot', { props: { ...props, close: true }, slots: { close: () => 'Close slot' } }]
['with close slot', { props: { ...props, close: true }, slots: { close: () => 'Close slot' } }],
['with footer slot', { props, slots: { footer: () => 'Footer slot' } }]
])('renders %s correctly', async (nameOrHtml: string, options: { props?: CommandPaletteProps, slots?: Partial<CommandPaletteSlots> }) => {
const html = await ComponentRender(nameOrHtml, options, CommandPalette)
expect(html).toMatchSnapshot()

View File

@@ -32,6 +32,7 @@ exports[`CommandPalette > renders with as correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</section>"
`;
@@ -68,6 +69,7 @@ exports[`CommandPalette > renders with class correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -102,6 +104,7 @@ exports[`CommandPalette > renders with close correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -136,6 +139,7 @@ exports[`CommandPalette > renders with close slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -170,6 +174,7 @@ exports[`CommandPalette > renders with closeIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -204,6 +209,7 @@ exports[`CommandPalette > renders with custom slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -240,6 +246,7 @@ exports[`CommandPalette > renders with defaultValue correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -276,6 +283,7 @@ exports[`CommandPalette > renders with disabled correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -312,6 +320,44 @@ exports[`CommandPalette > renders with empty slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
exports[`CommandPalette > renders with footer slot correctly 1`] = `
"<div dir="ltr" class="flex flex-col min-h-0 min-w-0 divide-y divide-default">
<div class="relative inline-flex items-center [&amp;>input]:h-12"><input type="text" placeholder="Type a command or search..." class="w-full rounded-md border-0 placeholder:text-dimmed focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors px-2.5 py-1.5 text-sm gap-1.5 text-highlighted bg-transparent ps-9" autocomplete="off" aria-disabled="false" value=""><span class="absolute inset-y-0 start-0 flex items-center ps-2.5"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" class="shrink-0 text-dimmed size-5"></svg></span>
<!--v-if-->
</div>
<div class="relative overflow-hidden flex flex-col" role="listbox" aria-orientation="vertical" aria-multiselectable="false" data-orientation="vertical">
<div role="presentation" class="relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1 focus:outline-none">
<div role="group" aria-labelledby="reka-listbox-group-v-0" class="p-1 isolate">
<!--v-if--><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-1" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-highlighted before:bg-elevated"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" class="shrink-0 size-5 text-default"></svg><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add new file</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Create a new file in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">N</kbd></span>
<!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-2" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" class="shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors"></svg><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add new folder</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Create a new folder in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">F</kbd></span>
<!----></span>
</button><button type="button" disabled="" data-reka-collection-item="" id="reka-listbox-item-v-3" role="option" tabindex="-1" aria-selected="false" data-disabled="" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" class="shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors"></svg><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add hashtag</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add a hashtag to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">H</kbd></span>
<!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-4" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" class="shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors"></svg><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add label</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add a label to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">L</kbd></span>
<!----></span>
</button>
</div>
<div role="group" aria-labelledby="reka-listbox-group-v-5" class="p-1 isolate">
<div id="reka-listbox-group-v-5" class="p-1.5 text-xs font-semibold text-highlighted">Labels</div><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-6" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-error h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">bug</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-7" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-success h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">feature</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-8" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-info h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">enhancement</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button>
</div>
<div role="group" aria-labelledby="reka-listbox-group-v-9" class="p-1 isolate">
<div id="reka-listbox-group-v-9" class="p-1.5 text-xs font-semibold text-highlighted">Users</div><a href="https://github.com/benjamincanac" role="option" tabindex="-1" target="_blank" data-reka-collection-item="" id="reka-listbox-item-v-10" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><span class="inline-flex items-center justify-center select-none rounded-full align-middle bg-elevated size-5 text-[10px] shrink-0"><img role="img" src="https://github.com/benjamincanac.png" width="20" height="20" class="h-full w-full rounded-[inherit] object-cover"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">benjamincanac</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span></a>
</div>
</div>
</div>
<div class="p-1">Footer slot</div>
<!---->
</div>"
`;
@@ -348,6 +394,7 @@ exports[`CommandPalette > renders with groups correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -384,6 +431,7 @@ exports[`CommandPalette > renders with icon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -408,6 +456,7 @@ exports[`CommandPalette > renders with item slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -444,6 +493,7 @@ exports[`CommandPalette > renders with item-label slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -474,6 +524,7 @@ exports[`CommandPalette > renders with item-leading slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -504,6 +555,7 @@ exports[`CommandPalette > renders with item-trailing slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -545,6 +597,7 @@ exports[`CommandPalette > renders with labelKey correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -581,6 +634,7 @@ exports[`CommandPalette > renders with loading correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -617,6 +671,7 @@ exports[`CommandPalette > renders with loadingIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -653,6 +708,7 @@ exports[`CommandPalette > renders with modelValue correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -689,6 +745,7 @@ exports[`CommandPalette > renders with placeholder correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -725,6 +782,7 @@ exports[`CommandPalette > renders with selectedIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -761,6 +819,7 @@ exports[`CommandPalette > renders with ui correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -773,6 +832,7 @@ exports[`CommandPalette > renders without data correctly 1`] = `
<div class="relative overflow-hidden flex flex-col" role="listbox" aria-orientation="vertical" aria-multiselectable="false" data-orientation="vertical">
<div class="py-6 text-center text-sm text-muted">No data</div>
</div>
<!--v-if-->
<!---->
</div>"
`;

View File

@@ -32,6 +32,7 @@ exports[`CommandPalette > renders with as correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</section>"
`;
@@ -68,6 +69,7 @@ exports[`CommandPalette > renders with class correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -105,6 +107,7 @@ exports[`CommandPalette > renders with close correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -139,6 +142,7 @@ exports[`CommandPalette > renders with close slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -176,6 +180,7 @@ exports[`CommandPalette > renders with closeIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -210,6 +215,7 @@ exports[`CommandPalette > renders with custom slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -246,6 +252,7 @@ exports[`CommandPalette > renders with defaultValue correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -282,6 +289,7 @@ exports[`CommandPalette > renders with disabled correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -318,6 +326,44 @@ exports[`CommandPalette > renders with empty slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
exports[`CommandPalette > renders with footer slot correctly 1`] = `
"<div dir="ltr" class="flex flex-col min-h-0 min-w-0 divide-y divide-default">
<div class="relative inline-flex items-center [&amp;>input]:h-12"><input type="text" placeholder="Type a command or search..." class="w-full rounded-md border-0 placeholder:text-dimmed focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors px-2.5 py-1.5 text-sm gap-1.5 text-highlighted bg-transparent ps-9" autocomplete="off" aria-disabled="false" value="" aria-activedescendant="reka-listbox-item-v-0-0-1"><span class="absolute inset-y-0 start-0 flex items-center ps-2.5"><span class="iconify i-lucide:search shrink-0 text-dimmed size-5" aria-hidden="true"></span></span>
<!--v-if-->
</div>
<div class="relative overflow-hidden flex flex-col" role="listbox" aria-orientation="vertical" aria-multiselectable="false" data-orientation="vertical">
<div role="presentation" class="relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1 focus:outline-none">
<div role="group" aria-labelledby="reka-listbox-group-v-0-0-0" class="p-1 isolate">
<!--v-if--><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-1" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-highlighted before:bg-elevated" data-highlighted=""><span class="iconify i-lucide:file-plus shrink-0 size-5 text-default" aria-hidden="true"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add new file</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Create a new file in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">N</kbd></span>
<!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-2" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><span class="iconify i-lucide:folder-plus shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors" aria-hidden="true"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add new folder</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Create a new folder in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">F</kbd></span>
<!----></span>
</button><button type="button" disabled="" data-reka-collection-item="" id="reka-listbox-item-v-0-0-3" role="option" tabindex="-1" aria-selected="false" data-disabled="" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><span class="iconify i-lucide:hash shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors" aria-hidden="true"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add hashtag</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add a hashtag to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">H</kbd></span>
<!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-4" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><span class="iconify i-lucide:tag shrink-0 size-5 text-dimmed group-data-highlighted:not-group-data-disabled:text-default transition-colors" aria-hidden="true"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add label</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">Add a label to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">Ctrl</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-sm font-medium font-sans bg-default text-highlighted ring ring-inset ring-accented h-5 min-w-[20px] text-[11px]">L</kbd></span>
<!----></span>
</button>
</div>
<div role="group" aria-labelledby="reka-listbox-group-v-0-0-5" class="p-1 isolate">
<div id="reka-listbox-group-v-0-0-5" class="p-1.5 text-xs font-semibold text-highlighted">Labels</div><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-6" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-error h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">bug</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-7" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-success h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">feature</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button><button type="button" data-reka-collection-item="" id="reka-listbox-item-v-0-0-8" role="option" tabindex="-1" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-bg flex items-center justify-center text-inverted font-medium whitespace-nowrap bg-info h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">enhancement</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</button>
</div>
<div role="group" aria-labelledby="reka-listbox-group-v-0-0-9" class="p-1 isolate">
<div id="reka-listbox-group-v-0-0-9" class="p-1.5 text-xs font-semibold text-highlighted">Users</div><a href="https://github.com/benjamincanac" role="option" tabindex="-1" rel="noopener noreferrer" target="_blank" data-reka-collection-item="" id="reka-listbox-item-v-0-0-10" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50 transition-colors before:transition-colors"><span class="inline-flex items-center justify-center select-none rounded-full align-middle bg-elevated size-5 text-[10px] shrink-0"><img role="img" src="https://github.com/benjamincanac.png" width="20" height="20" class="h-full w-full rounded-[inherit] object-cover"></span><span class="truncate space-x-1 rtl:space-x-reverse text-dimmed"><!--v-if--><span class="text-highlighted [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary">benjamincanac</span><span class="text-dimmed [&amp;>mark]:text-inverted [&amp;>mark]:bg-primary"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span></a>
</div>
</div>
</div>
<div class="p-1">Footer slot</div>
<!---->
</div>"
`;
@@ -354,6 +400,7 @@ exports[`CommandPalette > renders with groups correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -390,6 +437,7 @@ exports[`CommandPalette > renders with icon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -414,6 +462,7 @@ exports[`CommandPalette > renders with item slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -450,6 +499,7 @@ exports[`CommandPalette > renders with item-label slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -480,6 +530,7 @@ exports[`CommandPalette > renders with item-leading slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -510,6 +561,7 @@ exports[`CommandPalette > renders with item-trailing slot correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -551,6 +603,7 @@ exports[`CommandPalette > renders with labelKey correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -587,6 +640,7 @@ exports[`CommandPalette > renders with loading correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -623,6 +677,7 @@ exports[`CommandPalette > renders with loadingIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -659,6 +714,7 @@ exports[`CommandPalette > renders with modelValue correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -695,6 +751,7 @@ exports[`CommandPalette > renders with placeholder correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -731,6 +788,7 @@ exports[`CommandPalette > renders with selectedIcon correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -767,6 +825,7 @@ exports[`CommandPalette > renders with ui correctly 1`] = `
</div>
</div>
</div>
<!--v-if-->
<!---->
</div>"
`;
@@ -779,6 +838,7 @@ exports[`CommandPalette > renders without data correctly 1`] = `
<div class="relative overflow-hidden flex flex-col" role="listbox" aria-orientation="vertical" aria-multiselectable="false" data-orientation="vertical">
<div class="py-6 text-center text-sm text-muted">No data</div>
</div>
<!--v-if-->
<!---->
</div>"
`;

View File

@@ -25,7 +25,13 @@ exports[`Toast > renders with actions correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -56,7 +62,13 @@ exports[`Toast > renders with as correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</section>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -86,7 +98,13 @@ exports[`Toast > renders with avatar correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -117,7 +135,13 @@ exports[`Toast > renders with class correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -145,7 +169,13 @@ exports[`Toast > renders with close slot correctly 1`] = `
<div class="flex gap-1.5 shrink-0 items-center">
<!--v-if-->Close slot
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -176,7 +206,13 @@ exports[`Toast > renders with closeIcon correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -207,7 +243,13 @@ exports[`Toast > renders with color neutral correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-inverted" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-inverted data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -238,7 +280,13 @@ exports[`Toast > renders with description correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -269,7 +317,13 @@ exports[`Toast > renders with description slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -299,7 +353,13 @@ exports[`Toast > renders with icon correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -328,7 +388,13 @@ exports[`Toast > renders with leading slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -359,7 +425,13 @@ exports[`Toast > renders with orientation horizontal correctly 1`] = `
<!--v-if-->
<!--v-if-->
</button></div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -392,7 +464,13 @@ exports[`Toast > renders with orientation vertical correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -423,7 +501,13 @@ exports[`Toast > renders with title correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -454,7 +538,13 @@ exports[`Toast > renders with title slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -485,7 +575,13 @@ exports[`Toast > renders with type correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -516,7 +612,13 @@ exports[`Toast > renders with ui correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -542,7 +644,13 @@ exports[`Toast > renders without close correctly 1`] = `
<!--v-if-->
</div>
<!--v-if-->
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>

View File

@@ -25,7 +25,13 @@ exports[`Toast > renders with actions correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -56,7 +62,13 @@ exports[`Toast > renders with as correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</section>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -86,7 +98,13 @@ exports[`Toast > renders with avatar correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -117,7 +135,13 @@ exports[`Toast > renders with class correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -145,7 +169,13 @@ exports[`Toast > renders with close slot correctly 1`] = `
<div class="flex gap-1.5 shrink-0 items-center">
<!--v-if-->Close slot
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -176,7 +206,13 @@ exports[`Toast > renders with closeIcon correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -207,7 +243,13 @@ exports[`Toast > renders with color neutral correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-inverted" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-inverted data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -238,7 +280,13 @@ exports[`Toast > renders with description correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -269,7 +317,13 @@ exports[`Toast > renders with description slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -299,7 +353,13 @@ exports[`Toast > renders with icon correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -328,7 +388,13 @@ exports[`Toast > renders with leading slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -359,7 +425,13 @@ exports[`Toast > renders with orientation horizontal correctly 1`] = `
<!--v-if-->
<!--v-if-->
</button></div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -392,7 +464,13 @@ exports[`Toast > renders with orientation vertical correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -423,7 +501,13 @@ exports[`Toast > renders with title correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -454,7 +538,13 @@ exports[`Toast > renders with title slot correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -485,7 +575,13 @@ exports[`Toast > renders with type correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -516,7 +612,13 @@ exports[`Toast > renders with ui correctly 1`] = `
<!--v-if-->
</button>
</div>
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>
@@ -542,7 +644,13 @@ exports[`Toast > renders without close correctly 1`] = `
<!--v-if-->
</div>
<!--v-if-->
<div class="absolute inset-x-0 bottom-0 h-1 z-[-1] bg-primary" style="width: 100%;"></div>
<div class="gap-2 w-full flex flex-col absolute inset-x-0 bottom-0">
<!--v-if-->
<div aria-valuemax="100" aria-valuemin="0" aria-valuenow="100" aria-label="100%" role="progressbar" data-state="complete" data-value="100" data-max="100" class="relative overflow-hidden rounded-full bg-accented w-full h-1" style="transform: translateZ(0);">
<div data-state="complete" data-value="100" data-max="100" class="rounded-full size-full transition-transform duration-200 ease-out bg-primary data-[state=indeterminate]:animate-[carousel_2s_ease-in-out_infinite] data-[state=indeterminate]:rtl:animate-[carousel-rtl_2s_ease-in-out_infinite]" style="transform: translateX(-0%);"></div>
</div>
<!--v-if-->
</div>
</li>
</ol><span aria-hidden="true" tabindex="0" style="position: fixed; border: 0px; width: 1px; height: 1px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; word-wrap: normal;"></span>
</div>