From dca716403aa913fe8b0544f25c8308abd8352abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B6=E6=9E=AB?= <645381995@qq.com> Date: Thu, 28 Mar 2024 17:15:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=E4=BA=86=E9=86=8B=E5=8C=85?= =?UTF-8?q?=E4=BA=86=E9=A5=BA=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/typography/Base/index.tsx | 74 ++++++++++--------- components/typography/Base/useCopyClick.ts | 62 ++++++++++++++++ components/typography/__tests__/copy.test.tsx | 21 +++++- 3 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 components/typography/Base/useCopyClick.ts diff --git a/components/typography/Base/index.tsx b/components/typography/Base/index.tsx index 3f4d7b12eb7f..1e4134e281dd 100644 --- a/components/typography/Base/index.tsx +++ b/components/typography/Base/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import EditOutlined from '@ant-design/icons/EditOutlined'; import classNames from 'classnames'; -import copy from 'copy-to-clipboard'; import ResizeObserver from 'rc-resize-observer'; import type { AutoSizeType } from 'rc-textarea'; import toArray from 'rc-util/lib/Children/toArray'; @@ -24,6 +23,7 @@ import Typography from '../Typography'; import CopyBtn from './CopyBtn'; import Ellipsis from './Ellipsis'; import EllipsisTooltip from './EllipsisTooltip'; +import useCopyClick from './useCopyClick'; export type BaseType = 'secondary' | 'success' | 'warning' | 'danger'; @@ -180,47 +180,49 @@ const Base = React.forwardRef((props, ref) => { // ========================== Copyable ========================== const [enableCopy, copyConfig] = useMergedConfig(copyable); - const [copied, setCopied] = React.useState(false); - const copyIdRef = React.useRef | null>(null); + // const [copied, setCopied] = React.useState(false); + // const copyIdRef = React.useRef | null>(null); const copyOptions: Pick = {}; if (copyConfig.format) { copyOptions.format = copyConfig.format; } - const cleanCopyId = () => { - if (copyIdRef.current) { - clearTimeout(copyIdRef.current); - } - }; - const [copyLoading, setCopyLoading] = React.useState(false); - - const onCopyClick = async (e?: React.MouseEvent) => { - e?.preventDefault(); - e?.stopPropagation(); - setCopyLoading(true); - try { - const text = - typeof copyConfig.text === 'function' ? await copyConfig.text() : copyConfig.text; - copy(text || String(children) || '', copyOptions); - setCopyLoading(false); - - setCopied(true); - - // Trigger tips update - cleanCopyId(); - copyIdRef.current = setTimeout(() => { - setCopied(false); - }, 3000); - - copyConfig.onCopy?.(e); - } catch (error) { - setCopyLoading(false); - throw error; - } - }; - - React.useEffect(() => cleanCopyId, []); + // const cleanCopyId = () => { + // if (copyIdRef.current) { + // clearTimeout(copyIdRef.current); + // } + // }; + // const [copyLoading, setCopyLoading] = React.useState(false); + + // const onCopyClick = async (e?: React.MouseEvent) => { + // e?.preventDefault(); + // e?.stopPropagation(); + // setCopyLoading(true); + // try { + // const text = + // typeof copyConfig.text === 'function' ? await copyConfig.text() : copyConfig.text; + // copy(text || String(children) || '', copyOptions); + // setCopyLoading(false); + + // setCopied(true); + + // // Trigger tips update + // cleanCopyId(); + // copyIdRef.current = setTimeout(() => { + // setCopied(false); + // }, 3000); + + // copyConfig.onCopy?.(e); + // } catch (error) { + // setCopyLoading(false); + // throw error; + // } + // }; + + // React.useEffect(() => cleanCopyId, []); + + const { copied, copyLoading, onClick: onCopyClick } = useCopyClick({ copyConfig, children }); // ========================== Ellipsis ========================== const [isLineClampSupport, setIsLineClampSupport] = React.useState(false); diff --git a/components/typography/Base/useCopyClick.ts b/components/typography/Base/useCopyClick.ts new file mode 100644 index 000000000000..29f43532c261 --- /dev/null +++ b/components/typography/Base/useCopyClick.ts @@ -0,0 +1,62 @@ +import React from 'react'; +import copy from 'copy-to-clipboard'; + +import type { CopyConfig } from '.'; + +const useCopyClick = ({ + copyConfig, + children, +}: { + copyConfig: CopyConfig; + children?: React.ReactNode; +}) => { + const [copied, setCopied] = React.useState(false); + + const [copyLoading, setCopyLoading] = React.useState(false); + + const copyIdRef = React.useRef | null>(null); + + const cleanCopyId = () => { + if (copyIdRef.current) { + clearTimeout(copyIdRef.current); + } + }; + + const copyOptions: Pick = {}; + if (copyConfig.format) { + copyOptions.format = copyConfig.format; + } + + React.useEffect(() => cleanCopyId, []); + + return { + copied, + copyLoading, + onClick: async (e?: React.MouseEvent) => { + e?.preventDefault(); + e?.stopPropagation(); + setCopyLoading(true); + try { + const text = + typeof copyConfig.text === 'function' ? await copyConfig.text() : copyConfig.text; + copy(text || String(children) || '', copyOptions); + setCopyLoading(false); + + setCopied(true); + + // Trigger tips update + cleanCopyId(); + copyIdRef.current = setTimeout(() => { + setCopied(false); + }, 3000); + + copyConfig.onCopy?.(e); + } catch (error) { + setCopyLoading(false); + throw error; + } + }, + }; +}; + +export default useCopyClick; diff --git a/components/typography/__tests__/copy.test.tsx b/components/typography/__tests__/copy.test.tsx index a7813ede6b2f..26072dd53155 100644 --- a/components/typography/__tests__/copy.test.tsx +++ b/components/typography/__tests__/copy.test.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { LikeOutlined, SmileOutlined } from '@ant-design/icons'; import * as copyObj from 'copy-to-clipboard'; -import { fireEvent, render, waitFakeTimer, waitFor } from '../../../tests/utils'; +import { fireEvent, render, renderHook, waitFakeTimer, waitFor } from '../../../tests/utils'; import Base from '../Base'; +import useCopyClick from '../Base/useCopyClick'; describe('Typography copy', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); @@ -290,5 +291,23 @@ describe('Typography copy', () => { jest.useRealTimers(); expect(wrapper.querySelectorAll('.anticon-loading')[0]).toBeFalsy(); }); + test('useCopyClick error', async () => { + const { result } = renderHook(() => + useCopyClick({ + copyConfig: { + text: () => { + const error = 'error'; + return Promise.reject(error); + }, + }, + }), + ); + expect.assertions(1); + try { + await result.current?.onClick?.(); + } catch (error) { + expect(error).toMatch('error'); + } + }); }); });