diff --git a/web/app/components/base/copy-feedback/__tests__/index.spec.tsx b/web/app/components/base/copy-feedback/__tests__/index.spec.tsx index 8cc22693b6..83e873ab89 100644 --- a/web/app/components/base/copy-feedback/__tests__/index.spec.tsx +++ b/web/app/components/base/copy-feedback/__tests__/index.spec.tsx @@ -40,11 +40,11 @@ describe('CopyFeedback', () => { expect(mockCopy).toHaveBeenCalledWith('test content') }) - it('calls reset on mouse leave', () => { + it('does not reset on mouse leave (relies on hook timeout)', () => { render() const button = screen.getByRole('button') fireEvent.mouseLeave(button.firstChild as Element) - expect(mockReset).toHaveBeenCalledTimes(1) + expect(mockReset).not.toHaveBeenCalled() }) }) }) @@ -88,11 +88,11 @@ describe('CopyFeedbackNew', () => { expect(mockCopy).toHaveBeenCalledWith('test content') }) - it('calls reset on mouse leave', () => { + it('does not reset on mouse leave (relies on hook timeout)', () => { const { container } = render() const clickableArea = container.querySelector('.cursor-pointer')!.firstChild as HTMLElement fireEvent.mouseLeave(clickableArea) - expect(mockReset).toHaveBeenCalledTimes(1) + expect(mockReset).not.toHaveBeenCalled() }) }) }) diff --git a/web/app/components/base/copy-feedback/index.tsx b/web/app/components/base/copy-feedback/index.tsx index 5210066670..431b697a6a 100644 --- a/web/app/components/base/copy-feedback/index.tsx +++ b/web/app/components/base/copy-feedback/index.tsx @@ -19,7 +19,10 @@ const prefixEmbedded = 'overview.appInfo.embedded' const CopyFeedback = ({ content }: Props) => { const { t } = useTranslation() - const { copied, copy, reset } = useClipboard() + // Rely on useClipboard's own timer to flip `copied` back to false so the + // "Copied" tooltip stays visible long enough to be read, matching the + // KeyValueItem pattern. Do NOT reset on mouse leave. + const { copied, copy } = useClipboard({ timeout: 2000 }) const tooltipText = copied ? t(`${prefixEmbedded}.copied`, { ns: 'appOverview' }) @@ -36,10 +39,7 @@ const CopyFeedback = ({ content }: Props) => { popupContent={safeText} > -
+
{copied && } {!copied && }
@@ -52,7 +52,7 @@ export default CopyFeedback export const CopyFeedbackNew = ({ content, className }: Pick) => { const { t } = useTranslation() - const { copied, copy, reset } = useClipboard() + const { copied, copy } = useClipboard({ timeout: 2000 }) const tooltipText = copied ? t(`${prefixEmbedded}.copied`, { ns: 'appOverview' }) @@ -73,7 +73,6 @@ export const CopyFeedbackNew = ({ content, className }: Pick
diff --git a/web/hooks/use-clipboard.ts b/web/hooks/use-clipboard.ts index 6d24c04027..60ceeb4f18 100644 --- a/web/hooks/use-clipboard.ts +++ b/web/hooks/use-clipboard.ts @@ -43,12 +43,14 @@ export function useClipboard({ const copy = useCallback(async (valueToCopy: string) => { try { await writeTextToClipboard(valueToCopy) + handleCopyResult(true) } catch (e) { if (usePromptAsFallback) { try { // eslint-disable-next-line no-alert -- prompt as fallback in case of copy error window.prompt(promptFallbackText, valueToCopy) + handleCopyResult(true) } catch (e2) { handleCopyError(e2 as Error)