关于 sileo-react-toasts
Sileo 是 React 提示通知组件,用于显示简短状态消息,并可展开描述。它结合 SVG 形变与弹簧动画,提供按状态和 Promise 驱动的 API。
主要功能
- 01成功、错误、警告和信息通知
- 02Promise 加载到结果通知
- 03操作按钮和可展开描述
- 04六种视口位置
- 05主题与样式定制
- 06滑动关闭并支持减少动态效果
适用场景
- 01确认更改已保存
- 02报告 API 请求结果
- 03在更新后提供操作选项
- 04显示上传过程的状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ xoverlap/ sileo-skill --skill sileo-react-toasts安装后在 Claude Code 中输入/sileo-react-toasts确认已加载。
详细介绍
技能:Sileo(React Toast 通知)
官方文档: https://sileo.aaryan.design/docs API 参考: https://sileo.aaryan.design/docs/api Toaster API: https://sileo.aaryan.design/docs/api/toaster 样式指南: https://sileo.aaryan.design/docs/styling 在线体验: https://sileo.aaryan.design/play GitHub: https://github.com/hiaaryan/sileo
什么是 Sileo?
Sileo 是一款轻量、风格鲜明、基于物理效果的 React Toast 组件。它使用黏稠感 SVG 变形(通过 feGaussianBlur + feColorMatrix 滤镜链实现)和弹簧动画(由 motion/react 驱动,前身为 Framer Motion),无需任何配置即可创建默认效果出众、过渡顺滑的通知。
Sileo 并非通用通知中心,而是一套经过精心打磨、视觉风格鲜明的 Toast 系统,专为单行反馈消息设计,并支持可选的可展开描述。
主要特点:
- 框架:仅支持 React(内置
"use client"指令,兼容 Next.js App Router) - 对等依赖:
motion(弹簧物理引擎,motion/react) - 架构:基于 SVG 渲染,在药丸形(收起)和卡片形(展开)状态之间实现黏稠感 Blob 变形
- TypeScript 优先:导出所有类型(
SileoOptions、SileoPosition、SileoState、SileoStyles、SileoButton) - 无障碍:在视口区块中使用
aria-live="polite",并遵循prefers-reduced-motion - 滑动关闭:内置基于指针事件的垂直滑动手势(阈值为 30px)
安装
npm install sileo
Sileo 需要将 react 和 motion 作为对等依赖。
快速设置
- 在应用的根布局中挂载一次
<Toaster />。 - 导入
sileo,即可在任意位置触发 Toast。
import { sileo, Toaster } from "sileo";
export default function App() {
return (
<>
<Toaster position="top-right" />
<YourApp />
</>
);
}
由于
sileo内置了"use client",因此无需额外包装,即可在 Next.js App Router 中无缝运行。
基本用法
Sileo 提供全局控制器 sileo,并针对不同状态提供快捷方法:
import { sileo } from "sileo";
// State shortcuts (each returns the toast `id` as a string)
sileo.success({ title: "Saved", description: "Your changes were stored." });
sileo.error({ title: "Failed", description: "Could not save." });
sileo.warning({ title: "Warning", description: "Disk space low." });
sileo.info({ title: "Tip", description: "Try the new feature." });
// Generic toast (defaults to success, but accepts `type` for dynamic state)
sileo.show({ title: "Done", type: "success" });
// Dynamic state selection
sileo.show({
type: response.ok ? "success" : "error",
title: "Upload complete",
});
sileo 的所有方法
| 方法 | 返回值 | 说明 |
|---|---|---|
sileo.success(options) | string(id) | 绿色成功 Toast |
sileo.error(options) | string(id) | 红色错误 Toast |
sileo.warning(options) | string(id) | 琥珀色警告 Toast |
sileo.info(options) | string(id) | 蓝色信息 Toast |
sileo.action(options) | string(id) | 带操作按钮的 Toast |
sileo.show(options) | string(id) | 通用 Toast。使用 options.type 设置状态,默认为 "success" |
sileo.promise(promise, opts) | Promise<T> | 加载 -> 成功/错误流程。返回原始 Promise |
sileo.dismiss(id) | void | 按 id 关闭指定 Toast |
sileo.clear(position?) | void | 清除所有 Toast,或仅清除指定位置的 Toast |
SileoOptions
传递给每次 sileo.*() 调用。
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | -- | Toast 标题(显示在胶囊中) |
description | ReactNode | string | -- | 正文内容(展开时显示)。支持使用 JSX 添加丰富内容 |
type | SileoState | -- | sileo.show() 的动态状态。可选值为 "success" | "loading" | "error" | "warning" | "info" | "action" |
position | SileoPosition | Toaster default | 覆盖此条 toast 的位置 |
duration | number | null | 6000 | 自动关闭的毫秒数。null = 固定显示(不会自动关闭) |
icon | ReactNode | null | State icon | 替换徽章圆圈中默认图标的自定义图标 |
fill | string | "#FFFFFF" | Toast 背景形状的 SVG 填充颜色 |
styles | SileoStyles | -- | 子元素的 CSS 类覆盖项 |
roundness | number | 16 | SVG 形状的像素圆角半径 |
autopilot | boolean | { expand?: number; collapse?: number } | true | 自动展开/收起的时机。false = 仅悬停时触发 |
button | SileoButton | -- | 操作按钮配置 |
操作 Toast
操作 toast 会在展开区域内包含一个可点击的按钮:
sileo.action({
title: "New version available",
description: "Reload to update",
button: {
title: "Reload",
onClick: () => window.location.reload(),
},
});
SileoButton
interface SileoButton {
title: string;
onClick: () => void;
}
Promise Toast
sileo.promise 可通过一个 Promise 串联 loading -> success/error 状态。它会返回原始 Promise,因此你可以继续链式调用。
- 第一个参数可以是
Promise<T>或函数() => Promise<T>(适用于延迟执行)。 success和error可以是静态选项,也可以是接收已解决/已拒绝值的回调。- 如果提供可选的
action字段,它会将成功 toast 替换为操作状态 toast。
type User = { name: string };
const result = await sileo.promise<User>(createUser(data), {
loading: { title: "Creating account..." },
success: (user) => ({
title: `Welcome, ${user.name}!`,
}),
error: (err: any) => ({
title: "Signup failed",
description: err?.message ?? "Unknown error",
}),
});
// `result` is the resolved User object
使用延迟执行的 Promise(函数):
sileo.promise(() => fetch("/api/data").then((r) => r.json()), {
loading: { title: "Fetching data..." },
success: { title: "Data loaded" },
error: { title: "Failed to load" },
});
使用操作 toast 替换成功 toast:
sileo.promise<{ url: string }>(uploadFile(file), {
loading: { title: "Uploading..." },
success: { title: "Uploaded" }, // Ignored when `action` is present
error: { title: "Upload failed" },
action: (data) => ({
title: "File ready",
description: "Click to open",
button: {
title: "Open",
onClick: () => window.open(data.url),
},
}),
});
SileoPromiseOptions<T>
interface SileoPromiseOptions<T = unknown> {
loading: SileoOptions;
success: SileoOptions | ((data: T) => SileoOptions);
error: SileoOptions | ((err: unknown) => SileoOptions);
action?: SileoOptions | ((data: T) => SileoOptions);
position?: SileoPosition;
}
位置
提供六种位置。可在 <Toaster /> 上设置默认位置,也可针对每条 toast 覆盖:
type SileoPosition =
| "top-left"
| "top-center"
| "top-right" // default
| "bottom-left"
| "bottom-center"
| "bottom-right";
<Toaster position="bottom-center" />
// Override for a specific toast
sileo.success({ title: "Saved", position: "top-left" });
导出的 SILEO_POSITIONS 常量数组也可用于迭代:
import { SILEO_POSITIONS } from "sileo"; // Not exported from index (internal)
Toaster(视口组件)
<Toaster /> 是用于渲染 toast 的视口组件。在根布局中添加一次即可。
import { Toaster } from "sileo";
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | -- | 与 toast 一同渲染的应用内容 |
position | SileoPosition | "top-right" | 所有 toast 的默认位置 |
offset | number | string | { top?, right?, bottom?, left? } | -- | 与视口边缘的距离 |
options | Partial<SileoOptions> | -- | 合并到每条 toast 中的默认选项 |
theme | "light" | "dark" | "system" | -- | 根据配色方案自动设置填充颜色。"system" 遵循操作系统偏好 |
主题
theme 属性会根据选定的配色方案自动设置 toast 的 fill 颜色,无需手动配置深色/浅色填充:
"light"-> 填充颜色为#1a1a1a(浅色背景上的深色 toast)+ 浅色描述文本"dark"-> 填充颜色为#f2f2f2(深色背景上的浅色 toast)+ 深色描述文本"system"-> 遵循prefers-color-scheme媒体查询,并在操作系统设置更改时实时更新
<Toaster position="top-right" theme="system" />
设置 theme 后,视口会渲染 data-theme="light" 或 data-theme="dark",CSS 会利用该属性自动设置描述文本的不透明度。
如果同时设置了
theme和单条 toast 的fill,则优先使用该条 toast 的fill。
偏移
接受数字(px)、CSS 字符串或按边设置的对象:
<Toaster offset={20} />
<Toaster offset="1.5rem" />
<Toaster offset={{ top: 20, right: 16 }} />
默认选项(全局)
<Toaster
options={{
fill: "#171717",
styles: { description: "text-white/75!" },
}}
/>
每条 toast 都会继承这些默认值。单条 toast 的选项会覆盖默认值。styles 对象会进行浅合并(单条 toast 的样式会覆盖全局样式)。
样式设置
Sileo 开箱即用,效果出色。需要自定义时,有多种灵活的调整方式。
填充颜色
fill 设置提示条形状的 SVG 背景颜色。默认值:"#FFFFFF"。
对于深色提示条,请使用深色 fill,并通过 styles 搭配浅色文本:
sileo.success({
title: "Dark toast",
fill: "#171717",
styles: {
title: "text-white!",
description: "text-white/75!",
},
});
样式覆盖(styles)
覆盖各个子元素上的 CSS 类。使用 Tailwind 时,请添加 ! 以提高优先级。
SileoStyles
interface SileoStyles {
title?: string; // The heading text
description?: string; // The body/description area
badge?: string; // The icon badge circle
button?: string; // The action button
}
可用的数据属性选择器
| 键 | 元素 | CSS 选择器 |
|---|---|---|
title | 标题文本 | [data-sileo-title] |
description | 正文/描述区域 | [data-sileo-description] |
badge | 图标徽章圆形 | [data-sileo-badge] |
button | 操作按钮 | [data-sileo-button] |
可用于 CSS 选择的其他数据属性:
| 选择器 | 描述 |
|---|---|
[data-sileo-toast] | 最外层的提示条元素(一个 <button>) |
[data-sileo-toast][data-state="success"] | 按状态筛选的提示条 |
[data-sileo-toast][data-expanded="true"] | 已展开的提示条 |
[data-sileo-toast][data-exiting="true"] | 正在播放退出动画的提示条 |
[data-sileo-viewport] | 固定的视口 <section> |
[data-sileo-viewport][data-position="top-right"] | 按位置筛选的视口 |
[data-sileo-viewport][data-theme="dark"] | 已应用主题的视口 |
[data-sileo-canvas] | SVG 画布包装器 |
[data-sileo-svg] | 内部 SVG 元素 |
[data-sileo-pill] | 动画收起状态的药丸矩形 |
[data-sileo-body] | 动画展开状态的主体矩形 |
[data-sileo-header] | 标题行容器 |
[data-sileo-content] | 可展开的内容区域 |
示例:使用 Tailwind 的完整深色主题
sileo.success({
title: "Custom styled",
fill: "black",
styles: {
title: "text-white!",
description: "text-white/75!",
badge: "bg-white/20!",
button: "bg-white/10!",
},
});
自定义图标
将任意 React 节点作为 icon 传入,以替换默认状态图标:
sileo.info({
title: "Custom icon",
icon: <MyIcon />,
});
传入 icon: null 可完全隐藏图标。
各状态的默认图标(内联的 Lucide 风格 SVG):
success-> 对勾error-> Xwarning-> 带感叹号的圆圈info-> 救生圈loading-> 旋转圆圈(CSS 动画)action-> 右箭头
自定义描述(JSX)
description 接受 JSX,可在展开区域中显示丰富内容:
sileo.info({
title: "Rich content",
description: (
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
<span>Multiple elements supported</span>
<img src="/preview.png" alt="Preview" width={120} />
</div>
),
});
圆角
通过 roundness 控制边框圆角(默认值为 16):
sileo.success({ title: "Sharp", roundness: 8 }); // Sharper corners
sileo.success({ title: "Pill", roundness: 24 }); // More pill-like
**性能:**更高的
roundness会增大黏稠形变效果的 SVG 模糊半径(blur = roundness * 0.5),从而增加渲染开销。推荐值为16。
自动驾驶
默认情况下,提示条会在约 150ms 后自动展开,并在关闭前约 4 秒收起。可控制此行为:
// Disable entirely (hover to expand, click away to collapse)
sileo.info({ title: "Manual", autopilot: false });
// Custom timing (milliseconds)
sileo.info({
title: "Custom timing",
autopilot: { expand: 250, collapse: 300 },
});
内部默认值(根据 DEFAULT_TOAST_DURATION 的 6000ms 计算得出):
AUTO_EXPAND_DELAY= 150ms(6000 * 0.025)AUTO_COLLAPSE_DELAY= 4000ms(6000 - 2000)
当 autopilot 为 false,或 duration 为 null/0 时,将禁用自动展开/收起。
关闭/清除
// Dismiss a specific toast
const id = sileo.success({ title: "Will dismiss" });
sileo.dismiss(id);
// Clear all toasts
sileo.clear();
// Clear only toasts at a specific position
sileo.clear("bottom-center");
也可以垂直滑动(阈值为 30px)来关闭提示条。这是内置的指针事件滑动手势行为。
粘性提示条
将 duration: null 设为不自动关闭。提示条会一直显示,直到通过程序关闭或滑动关闭:
sileo.warning({
title: "Requires attention",
description: "This won't go away on its own.",
duration: null,
});
全局默认值(一致的深色主题)
<Toaster
position="top-right"
options={{
fill: "#171717",
roundness: 16,
styles: {
title: "text-white!",
description: "text-white/75!",
badge: "bg-white/10!",
button: "bg-white/10! hover:bg-white/15!",
},
}}
/>
CSS 变量
Sileo 提供 CSS 自定义属性供全局覆盖。可在 :root 或任意父元素中覆盖这些属性:
:root {
/* State colors (oklch format) */
--sileo-state-success: oklch(0.723 0.219 142.136);
--sileo-state-loading: oklch(0.556 0 0);
--sileo-state-error: oklch(0.637 0.237 25.331);
--sileo-state-warning: oklch(0.795 0.184 86.047);
--sileo-state-info: oklch(0.685 0.169 237.323);
--sileo-state-action: oklch(0.623 0.214 259.815);
/* Dimensions */
--sileo-width: 350px;
--sileo-height: 40px;
/* Animation */
--sileo-duration: 600ms;
}
示例:自定义品牌成功颜色:
:root {
--sileo-state-success: oklch(0.7 0.2 200);
}
内部 CSS 变量(每个提示条单独设置,通过内联样式应用)
这些变量按每个提示条分别计算,并作为 CSS 自定义属性设置在 [data-sileo-toast] 上:
| 变量 | 描述 |
|---|---|
--_h | 当前提示条高度(收起或展开) |
--_pw | 药丸宽度 |
--_px | 药丸 X 轴偏移量 |
--_ht | 标题变换(平移 + 缩放) |
--_co | 内容不透明度(0 或 1) |
内部颜色变量(每种状态,通过 CSS 设置)
| 变量 | 描述 |
|---|---|
--sileo-tone | 徽章/标题使用的解析后状态颜色 |
--sileo-tone-bg | 徽章背景使用的 20% 透明度状态颜色 |
--sileo-btn-color | 按钮文字颜色(等于状态颜色) |
--sileo-btn-bg | 按钮背景(状态颜色的 15% 透明度) |
--sileo-btn-bg-hover | 按钮悬停背景(状态颜色的 25% 透明度) |
TypeScript 导出
所有类型均从 "sileo" 导出:
import type {
SileoButton,
SileoOptions,
SileoPosition,
SileoState,
SileoStyles,
} from "sileo";
// SileoState = "success" | "loading" | "error" | "warning" | "info" | "action"
SileoPromiseOptions<T> 类型也从 toast 模块导出。
无障碍
- 视口使用
<section>和aria-live="polite",让屏幕阅读器播报新提示,而不会打断用户。 - toast 根元素是
<button>,可通过键盘聚焦。 - 每个 SVG 图标都包含
<title>元素,用于屏幕阅读器标注。 - 当操作系统设置了
prefers-reduced-motion: reduce偏好时,Sileo 会遵循该设置,禁用所有动画和过渡效果。
架构(内部细节)
了解 Sileo 的内部机制有助于调试或进行深度自定义:
-
全局存储: 模块级单例(
store)保存所有活动 toast,并通过监听器Set通知 React。Toaster组件订阅此存储,并在 toast 发生变化时重新渲染。 -
Toast ID: 用户未提供
id时,toast 会使用"sileo-default"作为其 ID。这意味着反复调用sileo.success(...)而不提供id,会替换之前的 toast(相同 ID 的更新行为)。如需同时显示多个相同状态的 toast,请提供唯一的id。 -
SVG 粘液效果: 每个 toast 都会渲染一个
<svg>,其中包含:- 一个
<filter>,包含feGaussianBlur(stdDeviation =roundness * 0.5)+feColorMatrix+feComposite - 两个
<motion.rect>元素(胶囊 + 主体),通过motion/react弹簧过渡进行动画处理 - 粘液滤镜会在胶囊和展开后的卡片之间产生自然的融合效果
- 一个
-
弹簧物理效果: 动画使用
motion/react的弹簧过渡,设置bounce: 0.25,并使用计算得出的duration(默认值为 0.6s)。CSS 过渡使用linear()缓动函数近似相同的弹簧曲线。 -
展开方向: 位于
top-*位置的 toast 向下展开;位于bottom-*位置的 toast 向上展开(通过画布上的 CSSscaleY(-1)变换实现)。 -
计时器管理: 每个 Toaster 实例都会为每个 toast 管理自动关闭计时器。将鼠标悬停在任何 toast 上都会暂停所有计时器;移开后则恢复计时。此悬停暂停行为由 Toaster 级别统一管理,而非针对单个 toast。
-
标题变形: toast 状态发生变化时(例如,通过 promise 从 loading 变为 success),标题会在旧状态和新状态之间执行基于模糊效果的交叉淡入淡出动画,使用两个堆叠图层(
current+prev)。
集成检查清单
- 安装
sileo(并确保motion对等依赖可用) - 在根布局中挂载一个
<Toaster /> - 根据上下文使用
sileo.success/error/warning/info/show/action - 对于异步流程,优先使用
sileo.promise(...) - 如需主题化,可使用
theme属性,或手动设置fill、styles和 CSS 变量 - 如需通过代码关闭 toast,请使用
dismiss(id)或clear(...) - 当多个 toast 需要同时显示时,请提供唯一的
id值
常见模式
表单提交反馈
const handleSubmit = async (data: FormData) => {
await sileo.promise(saveForm(data), {
loading: { title: "Saving..." },
success: { title: "Form saved" },
error: (err: any) => ({
title: "Save failed",
description: err?.message,
}),
});
};
撤销操作 toast
const id = sileo.action({
title: "Item deleted",
description: "This action can be undone",
duration: 8000,
button: {
title: "Undo",
onClick: () => {
restoreItem(itemId);
sileo.dismiss(id);
},
},
});
多个 toast 同时显示
// Use unique ids to prevent replacement
sileo.info({ title: "Downloading file 1...", id: "download-1", duration: null });
sileo.info({ title: "Downloading file 2...", id: "download-2", duration: null });
// Dismiss individually
sileo.dismiss("download-1");
sileo.dismiss("download-2");