Skip to content

Commit

Permalink
feat: 为了醋包了饺子
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyair committed Mar 28, 2024
1 parent 27e9af0 commit dca7164
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 37 deletions.
74 changes: 38 additions & 36 deletions 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';
Expand All @@ -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';

Expand Down Expand Up @@ -180,47 +180,49 @@ const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {

// ========================== Copyable ==========================
const [enableCopy, copyConfig] = useMergedConfig<CopyConfig>(copyable);
const [copied, setCopied] = React.useState(false);
const copyIdRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
// const [copied, setCopied] = React.useState(false);
// const copyIdRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);

const copyOptions: Pick<CopyConfig, 'format'> = {};
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<HTMLDivElement>) => {
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<HTMLDivElement>) => {
// 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);
Expand Down
62 changes: 62 additions & 0 deletions 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<ReturnType<typeof setTimeout> | null>(null);

const cleanCopyId = () => {
if (copyIdRef.current) {
clearTimeout(copyIdRef.current);
}
};

const copyOptions: Pick<CopyConfig, 'format'> = {};
if (copyConfig.format) {
copyOptions.format = copyConfig.format;
}

React.useEffect(() => cleanCopyId, []);

return {
copied,
copyLoading,
onClick: async (e?: React.MouseEvent<HTMLDivElement>) => {
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;
21 changes: 20 additions & 1 deletion components/typography/__tests__/copy.test.tsx
Expand Up @@ -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(() => {});
Expand Down Expand Up @@ -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');
}
});
});
});

0 comments on commit dca7164

Please sign in to comment.