Files
Genarrative/src/components/common/useCopyFeedback.ts
T
kdletters 1ad25e30f8 收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件
迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome
补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
2026-06-10 10:24:18 +08:00

55 lines
1.4 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react';
import { copyTextToClipboard } from '../../services/clipboard';
export type CopyFeedbackState = 'idle' | 'copied' | 'failed';
type UseCopyFeedbackOptions = {
resetDelayMs?: number;
};
/**
* 统一剪贴板复制反馈。
* 复制实现、成功/失败状态和定时复位集中在这里,调用方只负责渲染按钮文案。
*/
export function useCopyFeedback({
resetDelayMs = 1400,
}: UseCopyFeedbackOptions = {}) {
const [copyState, setCopyState] = useState<CopyFeedbackState>('idle');
const resetTimerRef = useRef<number | null>(null);
const clearResetTimer = useCallback(() => {
if (resetTimerRef.current !== null) {
window.clearTimeout(resetTimerRef.current);
resetTimerRef.current = null;
}
}, []);
const resetCopyState = useCallback(() => {
clearResetTimer();
setCopyState('idle');
}, [clearResetTimer]);
const copyText = useCallback(
async (value: string) => {
const copied = await copyTextToClipboard(value);
setCopyState(copied ? 'copied' : 'failed');
clearResetTimer();
resetTimerRef.current = window.setTimeout(() => {
resetTimerRef.current = null;
setCopyState('idle');
}, resetDelayMs);
return copied;
},
[clearResetTimer, resetDelayMs],
);
useEffect(() => resetCopyState, [resetCopyState]);
return {
copyState,
copyText,
resetCopyState,
};
}