bun add @icen.ai/ui
先模拟一次失败,再尝试真实复制。等待时可以继续阅读,重复点击不会重复执行。
选择一项,复制后会在这里确认。
<div class="demo-row"> <button type="button" class="icen-copy-btn icen-copy-btn--sm" data-icen-copy="bun add @icen.ai/ui">复制安装命令</button> <button type="button" class="icen-copy-btn icen-copy-btn--md icen-copy-btn--ghost" data-icen-copy="https://ui.icen.ai/modern/">复制作品链接</button> <button type="button" class="icen-copy-btn icen-copy-btn--lg" disabled data-icen-copy="">暂不可用</button></div><div class="icen-copy-scope demo-row" style="margin-block:var(--icen-density-space-lg);padding:var(--icen-density-space-md);border:1px solid var(--icen-token-line-soft);border-radius:var(--icen-radius-md)"> <code class="icen-code-inline">bun add @icen.ai/ui</code> <button type="button" class="icen-copy-btn icen-copy-btn--icon icen-copy-btn--ghost icen-copy-btn--quiet" data-icen-copy="bun add @icen.ai/ui" data-icen-copy-icon aria-label="复制安装命令"></button></div><div id="copy-retry-demo"> <p class="icen-muted" dir="auto">先模拟一次失败,再尝试真实复制。等待时可以继续阅读,重复点击不会重复执行。</p> <button type="button" class="icen-copy-btn icen-copy-btn--md" data-icen-copy="https://ui.icen.ai/modern/">复制分享地址</button></div><p id="copy-demo-log" class="icen-muted" dir="auto" role="status" style="margin-block-start:var(--icen-density-space-md)">选择一项,复制后会在这里确认。</p>
特性
- 形态:文本钮 / 透明钮 / 图标钮,三档尺寸共用同一行为
- 反馈:等待与完成不改变按钮宽度,原始插槽节点始终保留;失败显示可读提示,点原按钮即可重试
- quiet 变体:上下文内随悬停或焦点显现,触屏常显
- 剪贴板:默认系统剪贴板 + 兼容回退;可传
write接入原生桥或权限流程
接口
- 初始化
initCopy()(kit 一行入口可直接命名导入)- 导出
-
copyTextinitCopy - 事件
-
icen:copy-erroricen:copy-successdetail 契约见IcenEventMap - 类型
dist/behaviors/copy.d.mts(随 npm 包发布,含全部 JSDoc 约束)
安装
bun add @icen.ai/ui pnpm add @icen.ai/ui npm install @icen.ai/ui yarn add @icen.ai/ui 一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):
import { initCopy } from '@icen.ai/ui/kit/copy';initCopy();
也可以用脚手架直接打印引入行:
bunx --bun @icen.ai/ui add copy
Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/copy.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。
用法
import { initCopy, copyText } from '@icen.ai/ui/behaviors/copy';const dispose = initCopy(container); // 省略容器即全页;动态插入同样生效// 宿主卸载时 dispose(),回收状态、监听、计时器和异步反馈<button type="button" class="icen-copy-btn" data-icen-copy="bun add @icen.ai/ui">复制命令</button><!-- 空图标槽自动使用共享 copy/check SVG,仍需提供可访问名称 --><button type="button" class="icen-copy-btn icen-copy-btn--icon" data-icen-copy="…" data-icen-copy-icon aria-label="复制地址"></button><!-- 尺寸:--sm(默认)/ --md / --lg;透明:--ghost --><!-- 上下文操作:父容器 .icen-copy-scope + 按钮 .icen-copy-btn--quiet -->// 可选:原生桥接或异步权限流程;false/抛错显示重试,true/void 视为成功const release = initCopy(nativeContainer, { write: async (text, { signal }) => nativeClipboard.write(text, { signal }),});// 也可只使用底层写入:const { ok, reason } = await copyText(text, { signal });// 事件:icen:copy-success { text } / icen:copy-error { text, reason }// signal 取消反馈与尚未开始的兼容回退;已交给系统的写入无法撤回。