fix(web): restore "Copied" feedback state on copy buttons (#35513)

This commit is contained in:
yyh
2026-04-23 14:40:52 +08:00
committed by GitHub
parent 5b2c5da945
commit 91a1df96cb
3 changed files with 12 additions and 11 deletions

View File

@@ -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(<CopyFeedback content="test content" />)
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(<CopyFeedbackNew content="test content" />)
const clickableArea = container.querySelector('.cursor-pointer')!.firstChild as HTMLElement
fireEvent.mouseLeave(clickableArea)
expect(mockReset).toHaveBeenCalledTimes(1)
expect(mockReset).not.toHaveBeenCalled()
})
})
})

View File

@@ -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}
>
<ActionButton>
<div
onClick={handleCopy}
onMouseLeave={reset}
>
<div onClick={handleCopy}>
{copied && <RiClipboardFill className="h-4 w-4" />}
{!copied && <RiClipboardLine className="h-4 w-4" />}
</div>
@@ -52,7 +52,7 @@ export default CopyFeedback
export const CopyFeedbackNew = ({ content, className }: Pick<Props, 'className' | 'content'>) => {
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<Props, 'className'
>
<div
onClick={handleCopy}
onMouseLeave={reset}
className={`h-full w-full ${copyStyle.copyIcon} ${copied ? copyStyle.copied : ''}`}
>
</div>

View File

@@ -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)