import { h, signal } from '@ui-arch/frame'; import type { CopyButtonProps } from './types.js'; /*** 复制按钮:点击把 text 写入剪贴板,成功后短暂换成已复制文案再还原;clipboard API 不可用时降级 execCommand ***/ export function copyButton(props: CopyButtonProps): HTMLElement { const label = signal(props.label ?? '复制'); // 文案信号:成功后短暂切换(h() 对函数型子节点响应式刷新) let timer = 0; // 还原定时器句柄:连点时先清旧计时,避免文案提前回跳 /*** 写入剪贴板:标准 API 优先,失败(http 上下文 / 旧浏览器)走隐藏 textarea + execCommand 兜底 ***/ const write = async (): Promise => { const text = typeof props.text === 'function' ? props.text() : props.text; // 函数形式取实时值 try { await navigator.clipboard.writeText(text); } catch { const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.append(ta); ta.select(); document.execCommand('copy'); // 降级路径:依赖临时选区 ta.remove(); } label(props.copiedLabel ?? '已复制'); if (props.onCopied) props.onCopied(text); clearTimeout(timer); timer = window.setTimeout(() => label(props.label ?? '复制'), 2000); // 2s 后还原文案 }; // 直接构造按钮(ButtonProps.label 收窄为 string,无法传信号,复用会破坏其类型口径) return h('button', { class: `ua-btn ua-btn-${props.variant ?? 'ghost'}${props.size && props.size !== 'md' ? ` is-${props.size}` : ''}`, type: 'button', disabled: props.disabled, onClick: () => { void write(); } }, label); }