diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/UiEditorCopyPathButton.tsx b/apps/ai-game-creator-shell/src/view/ui-editor/components/UiEditorCopyPathButton.tsx index ea19e48bf..b33d9e62a 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/UiEditorCopyPathButton.tsx +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/UiEditorCopyPathButton.tsx @@ -1,31 +1,36 @@ import { writeText } from '@tauri-apps/plugin-clipboard-manager'; import { Copy } from 'lucide-react'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; + +type CopyState = 'idle' | 'copied' | 'failed'; export function UiEditorCopyPathButton({ relativePath, }: { relativePath: string; }) { - const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>( - 'idle', - ); - - useEffect(() => setCopyState('idle'), [relativePath]); + // 复制态跟着具体路径走:路径变了就等于回到未复制。这里不用 effect 事后重置, + // 因为延迟执行的 effect 会晚于复制结果落盘,把「已复制」覆盖回未复制。 + const [copyState, setCopyState] = useState<{ + relativePath: string; + value: CopyState; + }>({ relativePath, value: 'idle' }); + const value = + copyState.relativePath === relativePath ? copyState.value : 'idle'; async function copyPath() { - setCopyState('idle'); + setCopyState({ relativePath, value: 'idle' }); try { await writeText(relativePath); - setCopyState('copied'); + setCopyState({ relativePath, value: 'copied' }); } catch { - setCopyState('failed'); + setCopyState({ relativePath, value: 'failed' }); } } return ( <> - {copyState === 'failed' ? ( + {value === 'failed' ? (

复制失败,请手动复制路径。

@@ -36,7 +41,7 @@ export function UiEditorCopyPathButton({ onClick={() => void copyPath()} >