Bläddra i källkod

feat: [Typography] Copy nodes in Typograpy support customization (#1439)

* feat: [Typography] Copy nodes in Typograpy support customization

* feat: [Typography] Copy nodes in Typograpy support customization

* docs: change params order

* feat: [Typography] Copy nodes in Typograpy support customization

* chore: update yarn.lock

* fix: fix type defination

---------

Co-authored-by: pointhalo <[email protected]>
YyumeiZhang 2 år sedan
förälder
incheckning
cad55343d3

+ 5 - 2
content/basic/typography/index-en-US.md

@@ -287,6 +287,7 @@ Copyable text.
 ```jsx live=true
 import React from 'react';
 import { Typography, TextArea } from '@douyinfe/semi-ui';
+import { IconSetting } from '@douyinfe/semi-icons';
 
 function Demo() {
     const { Paragraph, Text, Numeral } = Typography;
@@ -295,8 +296,9 @@ function Demo() {
         <div>
             <Paragraph copyable>Click the right icon to copy text.</Paragraph>
             <Paragraph copyable={{ content: 'Hello, Semi Design!' }}>Click to copy text.</Paragraph>
-            <Paragraph copyable={{ onCopy: () => Toast.success({ content: 'Successfully copied.'}) }}>Click the right icon to copy.</Paragraph>
+            <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>
             <br/>
             <br/>
             <Text type="secondary">Paste here: </Text>
@@ -515,8 +517,9 @@ function Demo() {
 | ---------- | --------------------------------------- | ---------------------------------------------- | ------- | ------- |
 | content    | Copied content                          | string                                         | -       | 0.27.0  |
 | copyTip    | Tooltip content when hovering over icon | React.node                                     | -       | 1.0.0   |
-| successTip | Successful tip content                  | React.node                                     | -       | 0.33.0  |
+| icon       | Custom Render Duplicate Node            | React.node                                     | -       | 2.31.0  |
 | onCopy     | Callback for copy action                | Function(e:Event, content:string, res:boolean) | -       | 0.27.0  |
+| successTip | Successful tip content                  | React.node                                     | -       | 0.33.0  |
 
 ## Content Guidelines
 

+ 6 - 2
content/basic/typography/index.md

@@ -274,6 +274,7 @@ function Demo() {
 ```jsx live=true
 import React from 'react';
 import { Typography, TextArea } from '@douyinfe/semi-ui';
+import { IconSetting } from '@douyinfe/semi-icons';
 
 function Demo() {
     const { Paragraph, Text, Numeral } = Typography;
@@ -282,8 +283,9 @@ function Demo() {
         <div>
             <Paragraph copyable>点击右边的图标复制文本。</Paragraph>
             <Paragraph copyable={{ content: 'Hello, Semi Design!' }}>点击复制文本。</Paragraph>
-            <Paragraph copyable={{ onCopy: () => Toast.success({ content: '复制文本成功'}) }}>点击右边的图标复制文本。</Paragraph>
+            <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>
             <br/>
             <br/>
             <Text type="secondary">粘贴区域:</Text>
@@ -503,8 +505,10 @@ function Demo() {
 | ---------- | --------------------------- | ---------------------------------------------- | ------ | ------ |
 | content    | 复制出的文本                | string                                         | -      | 0.27.0 |
 | copyTip    | 复制图标的 tooltip 展示内容 | React.node                                     | -      | 1.0.0  |
-| successTip | 复制成功的展示内容          | React.node                                     | -      | 0.33.0 |
+| icon       | 自定义渲染复制节点       | React.node                                       | -      | 2.31.0 |
 | onCopy     | 复制回调                    | Function(e:Event, content:string, res:boolean) | -      | 0.27.0 |
+| successTip | 复制成功的展示内容          | React.node                                     | -      | 0.33.0 |
+
 
 
 ## 文案规范

+ 13 - 1
packages/semi-ui/typography/_story/typography.stories.jsx

@@ -3,7 +3,7 @@ import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import Icon from '../../icons';
 import Typography from '../index';
-import { IconLink, IconTick } from '@douyinfe/semi-icons';
+import { IconLink, IconTick, IconSetting } from '@douyinfe/semi-icons';
 
 export default {
   title: 'Typography'
@@ -633,5 +633,17 @@ export const Copyable = () => (
         Web 应用。 ➡️
       </span>
     </Paragraph>
+    <Paragraph 
+      spacing="extended" 
+      copyable={{
+        successTip: 'success'
+      }}
+    >测试 renderCopyNode 属性</Paragraph>
+    <Paragraph 
+      spacing="extended" 
+      copyable={{
+        icon: <IconSetting style={{ color: 'var(--semi-color-link)' }}/>
+      }}
+    >测试 renderCopyNode 属性</Paragraph>
   </div>
 );

+ 28 - 11
packages/semi-ui/typography/copyable.tsx

@@ -12,12 +12,14 @@ import { Locale } from '../locale/interface';
 import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
 
 const prefixCls = cssClasses.PREFIX;
+
 export interface CopyableProps extends BaseProps {
     content?: string;
     copyTip?: React.ReactNode;
     duration?: number;
     forwardRef?: React.RefObject<any>;
     successTip?: React.ReactNode;
+    icon?: React.ReactNode;
     onCopy?: (e: React.MouseEvent, content: string, res: boolean) => void
 }
 interface CopyableState {
@@ -33,6 +35,7 @@ export class Copyable extends React.PureComponent<CopyableProps, CopyableState>
         duration: PropTypes.number,
         style: PropTypes.object,
         className: PropTypes.string,
+        icon: PropTypes.node,
     };
 
     static defaultProps = {
@@ -105,6 +108,30 @@ export class Copyable extends React.PureComponent<CopyableProps, CopyableState>
         );
     };
 
+    renderCopyIcon = () => {
+        const { icon } = this.props;
+        const copyProps = {
+            role: "button",
+            tabIndex: 0,
+            onClick: this.copy,
+            onKeyPress: e => isEnterPress(e) && this.copy(e as any),
+        };
+
+        {/* TODO: replace `a` tag with `span` in next major version
+            NOTE: may have effect on style */}
+        const defaultIcon = (
+            // eslint-disable-next-line jsx-a11y/anchor-is-valid
+            <a className={`${prefixCls}-action-copy-icon`}>
+                <IconCopy
+                    onClick={this.copy}
+                    {...copyProps}
+                />
+            </a>
+        );
+
+        return React.isValidElement(icon) ? React.cloneElement(icon, copyProps) : defaultIcon;
+    }
+
     render() {
         const { style, className, forwardRef, copyTip } = this.props;
         const { copied } = this.state;
@@ -121,17 +148,7 @@ export class Copyable extends React.PureComponent<CopyableProps, CopyableState>
                             this.renderSuccessTip()
                         ) : (
                             <Tooltip content={typeof copyTip !== 'undefined' ? copyTip : locale.copy}>
-                                {/* TODO: replace `a` tag with `span` in next major version
-                                NOTE: may have effect on style */}
-                                {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
-                                <a className={`${prefixCls}-action-copy-icon`}>
-                                    <IconCopy
-                                        role="button"
-                                        tabIndex={0}
-                                        onClick={this.copy}
-                                        onKeyPress={e => isEnterPress(e) && this.copy(e as any)}
-                                    />
-                                </a>
+                                {this.renderCopyIcon()}
                             </Tooltip>
                         )}
                     </span>

+ 74 - 0
yarn.lock

@@ -1456,6 +1456,15 @@
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
+"@douyinfe/[email protected]":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.30.1.tgz#57e71f3033c7cf4f669e48444a45d8d7810863a0"
+  integrity sha512-jp10yP7Ax9XYSQDGVdD+CfxOw9Af75o178wf8cSY8Qq9hirCGBIjHsM6Ys29qpy7ezxqoRRYgQQZmDyhwCPgng==
+  dependencies:
+    "@douyinfe/semi-animation" "2.12.0"
+    "@douyinfe/semi-animation-styled" "2.23.2"
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.9.1.tgz#f2e4c6ef7899729ee6145edf0579598ba195bfdd"
@@ -1486,6 +1495,13 @@
     "@babel/runtime-corejs3" "^7.15.4"
     bezier-easing "^2.1.0"
 
+"@douyinfe/[email protected]":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.30.1.tgz#bef74d90f21b7dd829c5a481c65e410da80603e4"
+  integrity sha512-T7JCqTdq1WHkPeshVk45N96ZOIhNW+qFG3bPrTVB3SOWuPL6B9FIsZt33yaURZ3rZ3eCAS0ZXO7NLbrsaNTjoA==
+  dependencies:
+    bezier-easing "^2.1.0"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.9.1.tgz#4345fd86823b51e7c6fb5e9079d8f5c3ffe608f8"
@@ -1494,6 +1510,20 @@
     "@babel/runtime-corejs3" "^7.15.4"
     bezier-easing "^2.1.0"
 
+"@douyinfe/[email protected]":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.30.1.tgz#b3d8d4f857827a89183fb76953e04dc03b557cb9"
+  integrity sha512-pVdGvXUCCiC2pIovGE+9ez/OJ/x+/HHV7GJU1L6YHoNyotlhRm8AsQGKvyfankZUtNvS+IJOojuvMiyx9aADyA==
+  dependencies:
+    "@douyinfe/semi-animation" "2.12.0"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    memoize-one "^5.2.1"
+    scroll-into-view-if-needed "^2.2.24"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.9.1.tgz#1300bb97d6ceb92274ca4c9e6c66c5c16dc284ea"
@@ -1509,6 +1539,13 @@
     memoize-one "^5.2.1"
     scroll-into-view-if-needed "^2.2.24"
 
+"@douyinfe/[email protected]", "@douyinfe/semi-icons@^2.0.0":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.30.1.tgz#bcb4efbc9dd57a5f0ae02b8190bfa85580c9c07b"
+  integrity sha512-Uo2BRshy4cEWJNFXNet9VKQbM+MUga+im9c31lzEYNR8+7semzIdM6HEJdoWT86ePmmLeI1N7ZS4TfRyIFtWIA==
+  dependencies:
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]", "@douyinfe/semi-icons@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.9.1.tgz#7a04e1a77070220b04f63e6f65aac30155ed8ddd"
@@ -1517,6 +1554,11 @@
     "@babel/runtime-corejs3" "^7.15.4"
     classnames "^2.2.6"
 
+"@douyinfe/[email protected]":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.30.1.tgz#9c6a52c17d699c4ea6014442b6814e8cb7e6e9d0"
+  integrity sha512-woJdcuEmUMa+TmUNaOgd68nXsXzH6TWtToJNon+8dtr5bD4qf7+vowDFAK/t1+F/pJnPuBYJCCNldmv2vnvDWg==
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.9.1.tgz#1a448d1854ee1beeba57ea612da052b549ea105f"
@@ -1590,6 +1632,13 @@
     monaco-themes "^0.3.3"
     react-live "^2.2.2"
 
+"@douyinfe/[email protected]":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.30.1.tgz#88f66c5af1680cb396f821430bf4361dc3421ca6"
+  integrity sha512-QPLYV0ubmlv6flgLi1ldFIBicSDRcj8m17hy8u7He6YBGP9HVyh2nM/N4H/l3DiKkSYYuh5vO9OL3FkCyC99cA==
+  dependencies:
+    glob "^7.1.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.9.1.tgz#734113e9783ca58b69afe1769005e7e57e5a4da7"
@@ -1597,6 +1646,31 @@
   dependencies:
     glob "^7.1.6"
 
+"@douyinfe/semi-ui@^2.0.0":
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.30.1.tgz#8b39e267df55a63a197ef6874d3c3f639bc01cfe"
+  integrity sha512-LXGknmKqH+PnFXELl9GdIpMPk2rI4c7BUbauK7YxUc1WFJfWazE7MVEW+UAI90aud7Uc2VQ4T7evaHdl8WCbXg==
+  dependencies:
+    "@douyinfe/semi-animation" "2.30.1"
+    "@douyinfe/semi-animation-react" "2.30.1"
+    "@douyinfe/semi-foundation" "2.30.1"
+    "@douyinfe/semi-icons" "2.30.1"
+    "@douyinfe/semi-illustrations" "2.30.1"
+    "@douyinfe/semi-theme-default" "2.30.1"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    copy-text-to-clipboard "^2.1.1"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    prop-types "^15.7.2"
+    react-resizable "^1.8.0"
+    react-sortable-hoc "^2.0.0"
+    react-window "^1.8.2"
+    resize-observer-polyfill "^1.5.1"
+    scroll-into-view-if-needed "^2.2.24"
+    utility-types "^3.10.0"
+
 "@douyinfe/semi-ui@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.9.1.tgz#505d4783ea1fa73d307b75f62091030f1fee9332"