From 3b8ea07a8a646237c66e209f53a9ae234126a40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Wed, 11 Sep 2024 20:01:10 +0800 Subject: [PATCH] fix: Typography copyable support array children (#50813) * test: test driven * test: test driven * fix: test case --- components/_util/toList.ts | 5 +++++ components/mentions/index.tsx | 5 +++-- components/typography/__tests__/copy.test.tsx | 20 +++++++++++++++++++ components/typography/hooks/useCopyClick.ts | 3 ++- components/watermark/index.tsx | 3 ++- components/watermark/useClips.ts | 3 ++- 6 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 components/_util/toList.ts diff --git a/components/_util/toList.ts b/components/_util/toList.ts new file mode 100644 index 0000000000..ae29f448c7 --- /dev/null +++ b/components/_util/toList.ts @@ -0,0 +1,5 @@ +export default function toList(candidate: T | T[], skipEmpty = false): T[] { + if (skipEmpty && (candidate === undefined || candidate === null)) return []; + + return Array.isArray(candidate) ? candidate : [candidate]; +} diff --git a/components/mentions/index.tsx b/components/mentions/index.tsx index 3b98a7c475..29fa94a2d9 100644 --- a/components/mentions/index.tsx +++ b/components/mentions/index.tsx @@ -13,12 +13,13 @@ import getAllowClear from '../_util/getAllowClear'; import genPurePanel from '../_util/PurePanel'; import type { InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils'; +import toList from '../_util/toList'; import { devUseWarning } from '../_util/warning'; import { ConfigContext } from '../config-provider'; +import type { Variant } from '../config-provider'; import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty'; import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import { FormItemInputContext } from '../form/context'; -import type { Variant } from '../config-provider'; import useVariant from '../form/hooks/useVariants'; import Spin from '../spin'; import useStyle from './style'; @@ -238,7 +239,7 @@ Mentions._InternalPanelDoNotUseOrYouWillBeFired = PurePanel; Mentions.getMentions = (value = '', config: MentionsConfig = {}): MentionsEntity[] => { const { prefix = '@', split = ' ' } = config; - const prefixList: string[] = Array.isArray(prefix) ? prefix : [prefix]; + const prefixList: string[] = toList(prefix); return value .split(split) diff --git a/components/typography/__tests__/copy.test.tsx b/components/typography/__tests__/copy.test.tsx index 9e4bdb64d0..9d7559797d 100644 --- a/components/typography/__tests__/copy.test.tsx +++ b/components/typography/__tests__/copy.test.tsx @@ -352,4 +352,24 @@ describe('Typography copy', () => { fireEvent.click(container.querySelectorAll('.ant-typography-copy')[0]); expect(container.querySelector('.ant-tooltip-inner')?.textContent).toBe('Copied'); }); + + it('copy array children', () => { + const spy = jest.spyOn(copyObj, 'default'); + + const bamboo = 'bamboo'; + const little = 'little'; + + const { container } = render( + + {bamboo} + {little} + , + ); + fireEvent.click(container.querySelector('.ant-typography-copy')!); + + // Check copy content + expect(spy.mock.calls[0][0]).toBe(`${bamboo}${little}`); + + spy.mockRestore(); + }); }); diff --git a/components/typography/hooks/useCopyClick.ts b/components/typography/hooks/useCopyClick.ts index 837acae00b..8bf361f78e 100644 --- a/components/typography/hooks/useCopyClick.ts +++ b/components/typography/hooks/useCopyClick.ts @@ -2,6 +2,7 @@ import * as React from 'react'; import copy from 'copy-to-clipboard'; import { useEvent } from 'rc-util'; +import toList from '../../_util/toList'; import type { CopyConfig } from '../Base'; const useCopyClick = ({ @@ -38,7 +39,7 @@ const useCopyClick = ({ try { const text = typeof copyConfig.text === 'function' ? await copyConfig.text() : copyConfig.text; - copy(text || String(children) || '', copyOptions); + copy(text || toList(children, true).join('') || '', copyOptions); setCopyLoading(false); setCopied(true); diff --git a/components/watermark/index.tsx b/components/watermark/index.tsx index d846706dd8..6d22de4f33 100644 --- a/components/watermark/index.tsx +++ b/components/watermark/index.tsx @@ -10,6 +10,7 @@ import useClips, { FontGap } from './useClips'; import useRafDebounce from './useRafDebounce'; import useWatermark from './useWatermark'; import { getPixelRatio, reRendering } from './utils'; +import toList from '../_util/toList'; export interface WatermarkProps { zIndex?: number; @@ -145,7 +146,7 @@ const Watermark: React.FC = (props) => { let defaultHeight = 64; if (!image && ctx.measureText) { ctx.font = `${Number(fontSize)}px ${fontFamily}`; - const contents = Array.isArray(content) ? content : [content]; + const contents = toList(content); const sizes = contents.map((item) => { const metrics = ctx.measureText(item!); diff --git a/components/watermark/useClips.ts b/components/watermark/useClips.ts index 83edd98572..a791ab546f 100644 --- a/components/watermark/useClips.ts +++ b/components/watermark/useClips.ts @@ -1,4 +1,5 @@ import type { WatermarkProps } from '.'; +import toList from '../_util/toList'; export const FontGap = 3; @@ -55,7 +56,7 @@ export default function useClips() { ctx.fillStyle = color; ctx.textAlign = textAlign; ctx.textBaseline = 'top'; - const contents = Array.isArray(content) ? content : [content]; + const contents = toList(content); contents?.forEach((item, index) => { ctx.fillText(item ?? '', contentWidth / 2, index * (mergedFontSize + FontGap * ratio)); });