Merge remote-tracking branch 'origin/v3' into feat/3880

This commit is contained in:
HugoRCD
2025-07-08 10:24:23 +02:00
20 changed files with 1132 additions and 249 deletions

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

@@ -153,6 +153,7 @@ 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
'actions'(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
@@ -454,5 +455,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

@@ -8,6 +8,7 @@ export default (options: Required<ModuleOptions>) => ({
back: 'p-0',
trailingIcon: 'shrink-0 size-5 text-dimmed',
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: {