Skip to content

Commit

Permalink
feat: add typograph copy render (#2408)
Browse files Browse the repository at this point in the history
* feat: custom render copy button

* chore: update declaration format

---------

Co-authored-by: pointhalo <88709023+pointhalo@users.noreply.github.com>
  • Loading branch information
sylingd and pointhalo authored Aug 20, 2024
1 parent 3f91922 commit 765161d
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 5 deletions.
15 changes: 14 additions & 1 deletion content/basic/typography/index-en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,11 @@ Copying of text can be supported by configuring the `copyable` property.
When copyable is configured as true, the default copied content is children itself. Note that at this time, children only support string type.
When copyable is configured as object, you can specify the content copied to the clipboard through `copyable.content`, which is no longer strongly associated with children.
At this time, children will no longer limit the type, but `copyable.content` still needs to be a string.
You can use the `copyable.render` attribute to customize the copyable button render.
```jsx live=true
import React from 'react';
import { Typography, TextArea } from '@douyinfe/semi-ui';
import { Typography, TextArea, Button } from '@douyinfe/semi-ui';
import { IconSetting } from '@douyinfe/semi-icons';
function Demo() {
Expand All @@ -308,6 +309,18 @@ function Demo() {
<Paragraph copyable={{ onCopy: () => Toast.success({ content: 'Successfully copied.' }) }}>Click the right icon to copy.</Paragraph>
Timestamp: <Numeral truncate="ceil" copyable underline>{new Date().getTime()/1000}s</Numeral>
<Paragraph copyable={{ icon: <IconSetting style={{ color: 'var(--semi-color-link)' }}/> }}>Custom Copy Node</Paragraph>
<Paragraph copyable={{
content: 'Custom render!',
render: (copied, doCopy, config) => {
return (
<Button size="small" onClick={doCopy}>
<span>{copied ? 'Copy success' : `Click to copy: ${config.content}`}</span>
</Button>
);
}
}}>
Custom Copy Render
</Paragraph>
<br/>
<br/>
<Text type="secondary">Paste here: </Text>
Expand Down
15 changes: 14 additions & 1 deletion content/basic/typography/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,11 @@ function Demo() {
可通过配置 copyable 属性支持文本的复制。
当 copyable 配置为 true时,默认复制内容为 children 本身,注意,此时 children 只支持 string类型传入
当 copyable 配置为 object 时,可通过 `copyable.content` 指定复制至粘贴板的内容,与 children 不再强关联, 此时 children 将不再限定类型,但 `copyable.content` 仍需要为 string
可以通过 `copyable.render` 属性,自定义复制按钮的渲染逻辑

```jsx live=true
import React from 'react';
import { Typography, TextArea } from '@douyinfe/semi-ui';
import { Typography, TextArea, Button } from '@douyinfe/semi-ui';
import { IconSetting } from '@douyinfe/semi-icons';

function Demo() {
Expand All @@ -296,6 +297,18 @@ function Demo() {
<Paragraph copyable={{ onCopy: () => Toast.success({ content: '复制文本成功' }) }}>点击右边的图标复制文本。</Paragraph>
时间戳: <Numeral truncate="ceil" copyable underline>{new Date().getTime()/1000}s</Numeral>
<Paragraph copyable={{ icon: <IconSetting style={{ color: 'var(--semi-color-link)' }}/> }}>自定义复制节点</Paragraph>
<Paragraph copyable={{
content: 'Custom render!',
render: (copied, doCopy, config) => {
return (
<Button size="small" onClick={doCopy}>
<span>{copied ? '复制成功' : `点击复制:${config.content}`}</span>
</Button>
);
}
}}>
自定义复制渲染
</Paragraph>
<br/>
<br/>
<Text type="secondary">粘贴区域:</Text>
Expand Down
35 changes: 35 additions & 0 deletions packages/semi-ui/typography/__test__/typography.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,39 @@ describe(`Typography`, () => {
expect(typographyParagraph.find('.semi-typography').children().at(0).text()).toEqual('Key: code');
});

it('custom copy render', () => {
const { Text } = Typography;
const code = 'code';

const typographyParagraph = mount(
<Text
style={{ marginTop: 6, color: 'var(--semi-color-text-2)' }}
ellipsis={{ showTooltip: { opts: { style: { wordBreak: 'break-word' } } } }}
copyable={{
content: code,
render: (copied, doCopy, config) => {
return (
<span className="test-copy-button" onClick={doCopy}>
<span className="test-copied">{String(copied)}</span>
<span className="test-copy-content">{config.content}</span>
</span>
);
}
}}
>
Key: {code}
</Text>
);

// test basic render
expect(typographyParagraph.find('.test-copied').text()).toEqual('false');
expect(typographyParagraph.find('.test-copy-content').text()).toEqual(code);

// test copy
const trigger = typographyParagraph.find('.test-copy-button');
expect(trigger.length).toEqual(1);
trigger.at(0).simulate('click');
expect(typographyParagraph.find('.test-copied').text()).toEqual('true');
});

});
10 changes: 8 additions & 2 deletions packages/semi-ui/typography/copyable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IconCopy, IconTick } from '@douyinfe/semi-icons';
import { BaseProps } from '../_base/baseComponent';
import { Locale } from '../locale/interface';
import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
import { CopyableConfig } from './title';

const prefixCls = cssClasses.PREFIX;

Expand All @@ -20,7 +21,8 @@ export interface CopyableProps extends BaseProps {
forwardRef?: React.RefObject<any>;
successTip?: React.ReactNode;
icon?: React.ReactNode;
onCopy?: (e: React.MouseEvent, content: string, res: boolean) => void
onCopy?: (e: React.MouseEvent, content: string, res: boolean) => void;
render?: (copied: boolean, doCopy: (e: React.MouseEvent) => void, configs: CopyableConfig) => React.ReactNode
}
interface CopyableState {
copied: boolean;
Expand Down Expand Up @@ -133,13 +135,17 @@ export class Copyable extends React.PureComponent<CopyableProps, CopyableState>
}

render() {
const { style, className, forwardRef, copyTip } = this.props;
const { style, className, forwardRef, copyTip, render } = this.props;
const { copied } = this.state;
const finalCls = cls(className, {
[`${prefixCls}-action-copy`]: !copied,
[`${prefixCls}-action-copied`]: copied,
});

if (render) {
return render(copied, this.copy, this.props);
}

return (
<LocaleConsumer componentName="Typography">
{(locale: Locale['Typography']) => (
Expand Down
4 changes: 3 additions & 1 deletion packages/semi-ui/typography/title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export interface CopyableConfig {
successTip?: React.ReactNode;
icon?: React.ReactNode;

onCopy?(e: React.MouseEvent, content: string, res: boolean): void
onCopy?: (e: React.MouseEvent, content: string, res: boolean) => void;

render?: (copied: boolean, doCopy: (e: React.MouseEvent) => void, configs: CopyableConfig) => React.ReactNode
}

export type LinkType = React.AnchorHTMLAttributes<HTMLAnchorElement> | boolean;
Expand Down

0 comments on commit 765161d

Please sign in to comment.