Toast 吐司

用于展示短暂且不打断用户操作的反馈信息,支持自动关闭、手动关闭、堆叠展示、进度条提示、ESC 快捷键关闭、响应式视口适配与显示/隐藏动画。

BrToast 基于 BrConfigProvider 实现全局主题配置(颜色/圆角/阴影/z-index 等 tokens),同时支持组件式与函数式两种调用方式。

组件特性

  • ⏱️ 自动关闭:支持自动关闭和手动关闭两种模式。
  • 📚 堆叠展示:支持多个 Toast 同时堆叠显示。
  • 📊 进度条提示:可选显示关闭进度条,直观了解剩余时间。
  • ⌨️ 快捷键关闭:支持 ESC 快捷键关闭。
  • 📐 8 个弹出位置:支持 top/top-left/top-center/top-right/bottom/bottom-left/bottom-center/bottom-right。
  • 🎨 多种变体:支持 Default、Primary、Success、Error、Warning、Info 等视觉风格。
  • 🎨 主题配置:基于 BrConfigProvider 实现全局主题配置(颜色/圆角/阴影/z-index 等 tokens)。

基础用法

点击按钮后弹出默认样式 Toast(自动关闭 + 可手动关闭)。

<script setup>
import { BrButton, BrToastProvider, useToast } from '@breezeui/vue'

const { toast } = useToast()

function notify() {
  toast({
    group: 'basic',
    title: 'Saved',
    description: 'Your changes have been saved successfully.',
    showProgress: true,
  })
}
</script>

<template>
  <div class="flex items-center gap-3">
    <BrToastProvider group="basic" />
    <BrButton @click="notify">Show Toast</BrButton>
  </div>
</template>

变体

使用 variant 属性控制 Toast 的视觉风格:

  • Default:默认风格
  • Primary:主色风格
  • Success:成功色风格
  • Error:错误色风格
  • Warning:警告色风格
  • Info:信息色风格
<script setup>
import { BrButton, BrToastProvider, useToast } from '@breezeui/vue'

const { toast } = useToast()
</script>

<template>
  <div class="flex flex-wrap items-center gap-3">
    <BrToastProvider group="variants" />

    <BrButton @click="toast({ group: 'variants', title: 'Default', description: 'default variant' })">Default</BrButton>
    <BrButton color="primary" @click="toast({ group: 'variants', title: 'Primary', description: 'primary variant', variant: 'primary' })">Primary</BrButton>
    <BrButton color="success" @click="toast({ group: 'variants', title: 'Success', description: 'success variant', variant: 'success' })">Success</BrButton>
    <BrButton color="danger" @click="toast({ group: 'variants', title: 'Error', description: 'error variant', variant: 'error' })">Error</BrButton>
    <BrButton color="warning" @click="toast({ group: 'variants', title: 'Warning', description: 'warning variant', variant: 'warning' })">Warning</BrButton>
    <BrButton color="info" @click="toast({ group: 'variants', title: 'Info', description: 'info variant', variant: 'info' })">Info</BrButton>
  </div>
</template>

位置与堆叠

支持 8 个弹出位置(top/top-left/top-center/top-right/bottom/bottom-left/bottom-center/bottom-right),并支持堆叠展示与进度条提示。

<script setup>
import { ref } from 'vue'
import { BrButton, BrToastProvider, useToast } from '@breezeui/vue'

const { toast, dismiss } = useToast()

const position = ref('top-left')
const duration = ref(2800)

const positionOptions = [
  { label: 'top', value: 'top' },
  { label: 'top-left', value: 'top-left' },
  { label: 'top-center', value: 'top-center' },
  { label: 'top-right', value: 'top-right' },
  { label: 'bottom', value: 'bottom' },
  { label: 'bottom-left', value: 'bottom-left' },
  { label: 'bottom-center', value: 'bottom-center' },
  { label: 'bottom-right', value: 'bottom-right' },
]

function notify() {
  toast({
    group: 'positions',
    title: 'Custom Position',
    description: `position=${position.value} duration=${duration.value}ms`,
    position: position.value,
    duration: duration.value,
  })
}

function spam() {
  for (let i = 1; i <= 4; i += 1) {
    toast({
      group: 'positions',
      title: `Toast ${i}`,
      description: 'Stacked display',
      position: position.value,
      duration: duration.value + i * 250,
      variant: i % 2 === 0 ? 'primary' : 'default',
    })
  }
}
</script>

<template>
  <div class="space-y-6">
    <BrToastProvider group="positions" :position="position" />

    <!-- Position Selection -->
    <div class="space-y-3">
      <div class="text-sm font-medium text-muted-foreground">Select Position</div>
      <div class="flex flex-wrap gap-2">
        <BrButton
          v-for="opt in positionOptions"
          :key="opt.value"
          :variant="position === opt.value ? 'solid' : 'outline'"
          :color="position === opt.value ? 'primary' : 'default'"
          size="sm"
          @click="position = opt.value"
        >
          {{ opt.label }}
        </BrButton>
      </div>
    </div>

    <!-- Controls -->
    <div class="flex flex-wrap items-end gap-4">
      <div class="space-y-1.5">
        <label class="text-sm font-medium text-muted-foreground">Duration (ms)</label>
        <input
          v-model.number="duration"
          type="number"
          min="500"
          step="100"
          class="flex h-9 w-32 rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
        />
      </div>

      <div class="flex flex-wrap gap-2">
        <BrButton @click="notify">Show Toast</BrButton>
        <BrButton variant="outline" @click="spam">Stack Toasts</BrButton>
        <BrButton variant="outline" @click="dismiss()">Dismiss All</BrButton>
      </div>
    </div>
  </div>
</template>

主题定制

通过 BrConfigProvider 全局配置 Toast 默认位置、圆角、阴影、各变体颜色、z-index;也可以通过类名局部覆盖样式。

全局定制(BrConfigProvider)

<script setup>
import { computed } from 'vue'
import { BrButton, BrConfigProvider, BrToastProvider, useToast } from '@breezeui/vue'

const { toast } = useToast()

const theme = computed(() => ({
  radius: 0.75,
  shadow: '0 20px 25px -5px rgb(0 0 0 / 0.15), 0 8px 10px -6px rgb(0 0 0 / 0.15)',
  zToast: 80,
  primary: '#6366f1',
  success: '#22c55e',
  destructive: '#ef4444',
  warning: '#f59e0b',
  info: '#3b82f6',
}))

const toastConfig = computed(() => ({
  position: 'top-right',
  duration: 3800,
  max: 4,
  closeDelay: 220,
}))
</script>

<template>
  <BrConfigProvider :theme="theme" :toast="toastConfig">
    <div class="space-y-4">
      <BrToastProvider group="theme" />

      <div class="flex items-center justify-between gap-4 rounded-lg border bg-card p-4">
        <div class="space-y-1">
          <div class="text-sm font-medium">Theme Preview</div>
          <div class="text-sm text-muted-foreground">Configure Toast tokens and default behavior globally via BrConfigProvider</div>
        </div>
      </div>

      <div class="flex flex-wrap gap-3">
        <BrButton @click="toast({ group: 'theme', title: 'Primary', description: 'Global configuration', variant: 'primary' })">Primary</BrButton>
        <BrButton variant="outline" @click="toast({ group: 'theme', title: 'Success', description: 'success variant', variant: 'success' })">Success</BrButton>
        <BrButton variant="outline" @click="toast({ group: 'theme', title: 'Error', description: 'error variant', variant: 'error' })">Error</BrButton>
      </div>
    </div>
  </BrConfigProvider>
</template>

局部定制(TailwindCSS 类名覆盖)

<script setup>
import { BrButton, BrToastProvider, useToast } from '@breezeui/vue'

const { toast } = useToast()

function customStyle() {
  toast({
    group: 'local',
    title: 'Local Override Style',
    description: "Only via class override current Toast's appearance",
    class: 'rounded-sm shadow-none border-border/60 bg-card text-card-foreground',
    showProgress: true,
  })
}
</script>

<template>
  <div class="flex items-center gap-3">
    <BrToastProvider group="local" />
    <BrButton variant="outline" @click="customStyle">Local override style</BrButton>
  </div>
</template>

API

BrToast

Prop类型默认值说明
openbooleanundefined受控打开状态(配合 @update:open/v-model:open 使用)。
defaultOpenbooleanfalse非受控初始打开状态。
durationnumberundefined当前 Toast 自动关闭时间(ms),优先级高于 Provider 的 duration
variant'default' | 'primary' | 'success' | 'error' | 'warning' | 'info''default'变体样式。
positionBrToastPositionundefined当前 Toast 的弹出位置(优先级高于 Provider/BrConfigProvider)。
dismissiblebooleantrue是否显示关闭按钮、允许手动关闭。
showProgressbooleanfalse是否展示自动关闭进度条(依赖 duration > 0)。
titlestring | Componentundefined标题内容(不传时可用 #title 插槽)。
descriptionstring | Componentundefined描述内容(不传时可用 #description 插槽)。
iconComponentundefined图标内容(不传时可用 #icon 插槽)。
classstring''追加 TailwindCSS 类名,用于局部覆盖样式。

BrToastProvider

Prop类型默认值说明
positionBrToastPositionundefined覆盖 BrConfigProvider 的默认位置。
durationnumberundefined覆盖 BrConfigProvider 的默认自动关闭时间(ms)。
closeDelaynumberundefined关闭后从堆叠列表移除的延迟(ms),用于保留关闭动画。
maxnumberundefined最大堆叠数量,超出会移除更早的 Toast。
closeOnEscapebooleanundefined是否允许按 ESC 关闭最新 Toast。
viewportClassstring''追加到视口(Viewport)的类名,用于局部布局覆盖。

useToast

字段类型默认值说明
toast(options: BrToastOptions) => { id, dismiss, update }-触发 Toast,并返回句柄(可更新/关闭)。
dismiss(id?: string) => void-关闭指定 Toast;不传 id 关闭全部。
update(id: string, patch: BrToastOptions) => void-更新指定 Toast 的配置(标题/描述/变体/时长等)。
toastsRef<BrToastItem[]>-当前 Toast 列表(用于自定义渲染场景)。