跳到正文
册页

反馈

Toast - 轻提示

一次性的确认,在应用根部挂一次。

用法

什么时候用它

某件事成功了、且不需要回应。Toast 是被时间关掉的,而时间不算确认。
TSX
import { Toaster } from '@misoto22/folio'

说明

一闪而过的确认消息,在应用根部附近挂载一次。

Toast 是给“做成了、不需要回应”的事情用的。任何需要读者采取行动的东西都属于页面本身——toast 是被时间关掉的,而时间不是一次确认。

theme 跟随 data-mode。sonner 默认是 light,并且按主题把描述文字的颜色写死——#3f3f3f,只在 [data-sonner-theme=dark] 下才被覆盖——所以一个从不传 theme 的 Toaster,会把深灰文字放到这套系统的 --paper: #0d0d0d 上,于是每一次 toast(title, { description }) 都丢掉了它的后半截。自己传 theme 就以你传的为准;sonner 自己的 system 是唯一不该去碰的值,因为它读的是操作系统,而不是页面实际据以上色的那个属性。

richColors 默认关着:sonner 那套鲜艳配色不是这套系统的状态色阶,打开它等于把彩色重新引进来,而归白只把彩色花在状态上。

结构

Toast anatomy
部件说明
Toaster必填唯一的那次挂载,默认在右下角。它把 sonner 的列表渲染进 body 末尾的一个 portal 里——所以主题是内联样式写的:作用域限定在应用内的样式表根本够不到那里。
令牌样式必填把 sonner 的 --normal-bg、--normal-text、--normal-border 和 --border-radius 分别指向 --paper、--ink、--rule-2 和 --radius,再加上无衬线字体。--success-* 和 --error-* 这两组也一并设了,但 sonner 只在 richColors 下才读它们。
通知区域必填sonner 自己的 section,aria-live="polite",名字是「Notifications altKey+KeyT」。它被移出了 Tab 顺序,只能靠那个快捷键到达;而且对每一种 toast 都是 polite——这里没有 assertive 这条路。
单条提示一条,由 toast() 或它某个带类型的变体推进来,在 sonner 默认的四秒后从 DOM 里移除——这层封装没有改这个默认值。同时最多看得见三条,其余排队。
关闭按钮sonner 出厂是关的,这里默认是开的。没有它,出口就只剩计时器和滑动手势,而键盘没有滑动手势。

实践建议

推荐

  • 有且只挂一个 Toaster。每一次 toast() 调用都会抵达每一个在监听的 Toaster,所以根布局里一个、嵌套布局里再一个,同一条消息就会在两个角上各渲染一遍。
  • 凡是超过一句短话的,都要逐条设 duration。这层封装保留了 sonner 四秒的默认值——念出来大约十个词——剩下的内容还没被读到就已经从页面上移除了。
  • 消息只写发生了什么。同一时刻只看得见三条,其余的排队等位,所以一个逐条 toast 的循环,最后展示的是最后三条,其余的送达时读者早已走开。
  • 在 <html> 上设 data-mode,theme 保持不动。sonner 把描述文字的颜色按主题写死了——#3f3f3f,只有在它自己的 dark 主题下才被覆盖——所以一个由 Toaster 并不跟随的属性刷成深色的页面,会把这抹灰放在 --paper 上,对比度大约 1.85:1,每一条带描述的提示都因此丢掉它的下半句。

避免

  • 任何需要读者动手处理的东西都不该放在这里。四秒是一个从没告诉过他的截止时间,而那个按钮在 body 末尾的 portal 里、键盘最后才够得到——放在 toast 里的「撤销」,是一个大多数人接不住的提议。
  • 任何需要读者看第二遍的东西同样不该放在这里——错误码、单据号、要拿到别处去输的名字。这里没有历史记录:计时一到,那段文字就离开了 DOM,再也找不回来。
  • 不要用 toast.error 报告一次失败,就当作已经报告过了。那个区域对每一种类型都是 polite,所以这条失败会排在读屏软件正在念的内容后面,很可能还没轮到就已经被移除了。
  • 不要传 theme="system"。它读的是 prefers-color-scheme,不是 data-mode,所以一个用浅色页面盖过深色操作系统的读者,会在这个页面上收到一条深色的提示——同一个错配,只是方向反了过来。

示例

default

三种类型,以及它们共同抵达的那一个 Toaster。恰好挂一个,挂在应用根部附近:每一次 toast 调用都会抵达每一个在听的 Toaster,所以嵌套布局里多挂的第二个,会把同一条消息渲染两遍,在两个角落里。这个区域对每一种类型都是 aria-live polite——这里没有 assertive 那条路——所以一个用 toast.error 报出来的失败,会排在读屏软件已经在念的东西后面,而且可能还没轮到它,就被计时器移走了。失败也要在页面里报一遍。

long enough to read

默认是四秒,而四秒大约是念出十个词的时间:任何比一个短句更长的东西,都需要一个自己的 duration,否则剩下那部分还没被读到,就已经从页面上撤走了。消息也要压在「发生了什么」上——同时只看得见三条,其余的排队,所以一个每处理一项就 toast 一次的循环,展示的是最后三条,而其余的会在读者已经走开之后才送到。这个例子里刻意没有 Toaster:本页第一个例子挂的那一个,就是这一页该有的唯一一个。

not in a toast

同一个失败两遍:一遍在页面里,一遍挂在计时器上。任何读者必须去处理的东西,都不属于那个会消失的版本——四秒是一个从没告知过他们的期限,而那个关闭按钮住在 body 末尾的一个 portal 里,键盘最后才够得到。任何他们必须读第二遍的东西也不属于那儿:这里没有历史记录,所以计时器一到,那串编号就出了 DOM,再也找不回来。按一下按钮,看着那个数字走掉;上面那条 Alert 还在,而且还在说该做什么。