diff --git a/package.json b/package.json index f701aa93..87597a55 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "antd-style": "^3.6.2", "axios": "^1.7.2", "classnames": "^2.5.1", + "clipboard": "^2.0.11", "crypto-js": "^4.2.0", "dayjs": "^1.11.11", "echarts": "^5.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c025a86..c658b1b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: classnames: specifier: ^2.5.1 version: 2.5.1 + clipboard: + specifier: ^2.0.11 + version: 2.0.11 crypto-js: specifier: ^4.2.0 version: 4.2.0 @@ -4435,7 +4438,7 @@ packages: dependencies: '@babel/core': 7.24.5 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss@8.4.38) transitivePeerDependencies: - supports-color dev: false @@ -4476,7 +4479,7 @@ packages: postcss-syntax: '>=0.36.2' dependencies: postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss@8.4.38) remark: 13.0.0 unist-util-find-all-after: 3.0.2 transitivePeerDependencies: @@ -7837,6 +7840,14 @@ packages: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false + /clipboard@2.0.11: + resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==, tarball: https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz} + dependencies: + good-listener: 1.2.2 + select: 1.1.2 + tiny-emitter: 2.1.0 + dev: false + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -8483,6 +8494,10 @@ packages: engines: {node: '>=0.4.0'} dev: false + /delegate@3.2.0: + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==, tarball: https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz} + dev: false + /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -10318,6 +10333,12 @@ packages: minimist: 1.2.8 dev: false + /good-listener@1.2.2: + resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==, tarball: https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz} + dependencies: + delegate: 3.2.0 + dev: false + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -13072,7 +13093,7 @@ packages: dependencies: htmlparser2: 3.10.1 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss@8.4.38) dev: false /postcss-image-set-function@4.0.7(postcss@8.4.38): @@ -13546,30 +13567,6 @@ packages: lodash: 4.17.21 postcss: 8.4.38 - /postcss-syntax@0.36.2(postcss@7.0.39): - resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==} - peerDependencies: - postcss: '>=5.0.0' - postcss-html: '*' - postcss-jsx: '*' - postcss-less: '*' - postcss-markdown: '*' - postcss-scss: '*' - peerDependenciesMeta: - postcss-html: - optional: true - postcss-jsx: - optional: true - postcss-less: - optional: true - postcss-markdown: - optional: true - postcss-scss: - optional: true - dependencies: - postcss: 7.0.39 - dev: false - /postcss-syntax@0.36.2(postcss@8.4.38): resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==} peerDependencies: @@ -16044,6 +16041,10 @@ packages: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} dev: false + /select@1.1.2: + resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==, tarball: https://registry.npmjs.org/select/-/select-1.1.2.tgz} + dev: false + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, tarball: https://registry.npmjs.org/semver/-/semver-5.7.2.tgz} hasBin: true @@ -16723,7 +16724,7 @@ packages: postcss-sass: 0.4.4 postcss-scss: 2.1.1 postcss-selector-parser: 6.0.16 - postcss-syntax: 0.36.2(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss@8.4.38) postcss-value-parser: 4.2.0 resolve-from: 5.0.0 slash: 3.0.0 @@ -17032,6 +17033,10 @@ packages: next-tick: 1.1.0 dev: false + /tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==, tarball: https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz} + dev: false + /tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==, tarball: https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz} dev: false diff --git a/src/components/copy-button/index.tsx b/src/components/copy-button/index.tsx index 26cb9e8f..1ffebdc4 100644 --- a/src/components/copy-button/index.tsx +++ b/src/components/copy-button/index.tsx @@ -1,6 +1,8 @@ -import useCopyToClipboard from '@/hooks/use-copy-to-clipboard'; import { CheckCircleFilled, CopyOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; +import { useIntl } from '@umijs/max'; +import { Button, message } from 'antd'; +import ClipboardJS from 'clipboard'; +import { useEffect, useRef, useState } from 'react'; type CopyButtonProps = { text: string; @@ -21,19 +23,45 @@ const CopyButton: React.FC = ({ style, size = 'middle' }) => { - const { copied, copyToClipboard } = useCopyToClipboard(); + const intl = useIntl(); + const [copied, setCopied] = useState(false); + const buttonRef = useRef(null); + const clipboardRef = useRef(null); - const handleCopy = async (e: any) => { - e.stopPropagation(); - await copyToClipboard(text); + const initClipboard = () => { + if (buttonRef.current) { + clipboardRef.current = new ClipboardJS(buttonRef.current); + clipboardRef.current.on('success', () => { + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 3000); + }); + + clipboardRef.current.on('error', (e: any) => { + message.success( + intl.formatMessage({ id: 'common.copy.fail' }) as string + ); + e.clearSelection(); + }); + } }; + + useEffect(() => { + initClipboard(); + return () => { + clipboardRef.current?.destroy(); + }; + }, [buttonRef]); + return (