From a938839b3514bd9f96236f0b67f1c9394a6746dd Mon Sep 17 00:00:00 2001 From: jinphicjfli Date: Fri, 26 May 2023 16:17:46 +0800 Subject: [PATCH] feat: add copy --- docs/demo/allow-copy.md | 8 ++++++ docs/examples/allow-copy.tsx | 15 +++++++++++ src/BaseInput.tsx | 52 ++++++++++++++++++++++++++++++++++-- src/DefaultCopyIcon.tsx | 22 +++++++++++++++ src/interface.ts | 5 ++++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 docs/demo/allow-copy.md create mode 100644 docs/examples/allow-copy.tsx create mode 100644 src/DefaultCopyIcon.tsx diff --git a/docs/demo/allow-copy.md b/docs/demo/allow-copy.md new file mode 100644 index 0000000..7d45f60 --- /dev/null +++ b/docs/demo/allow-copy.md @@ -0,0 +1,8 @@ +--- +title: allow-copy +nav: + title: Demo + path: /demo +--- + + diff --git a/docs/examples/allow-copy.tsx b/docs/examples/allow-copy.tsx new file mode 100644 index 0000000..141b835 --- /dev/null +++ b/docs/examples/allow-copy.tsx @@ -0,0 +1,15 @@ +import Input from 'rc-input'; +import type { FC } from 'react'; +import React from 'react'; +import '../../assets/index.less'; + +const Demo: FC = () => ( + <> + +
+
+ + +); + +export default Demo; diff --git a/src/BaseInput.tsx b/src/BaseInput.tsx index 21788f3..66688d7 100644 --- a/src/BaseInput.tsx +++ b/src/BaseInput.tsx @@ -1,9 +1,25 @@ import clsx from 'classnames'; import type { FC, ReactElement } from 'react'; import React, { cloneElement, useRef } from 'react'; +import DefaultCopyIcon from './DefaultCopyIcon'; import type { BaseInputProps } from './interface'; import { hasAddon, hasPrefixSuffix } from './utils/commonUtils'; +const copyText = (text?: string): void => { + if (!text) { + return; + } + const textarea = document.createElement('textarea'); + textarea.setAttribute('readonly', 'readonly'); + textarea.innerHTML = text; + document.body.appendChild(textarea); + textarea.select(); + if (document.execCommand('copy')) { + document.execCommand('copy'); + } + document.body.removeChild(textarea); +}; + const BaseInput: FC = (props) => { const { inputElement, @@ -26,6 +42,8 @@ const BaseInput: FC = (props) => { classNames, dataAttrs, styles, + allowCopy, + copyCallback, } = props; const containerRef = useRef(null); @@ -76,7 +94,9 @@ const BaseInput: FC = (props) => { ) || null, style: { ...inputElement.props?.style, - ...(!hasPrefixSuffix(props) && !hasAddon(props) ? style : {}), + ...(!hasPrefixSuffix(props) && !hasAddon(props) && !allowCopy + ? style + : {}), }, }); @@ -132,6 +152,20 @@ const BaseInput: FC = (props) => { ); } + const CopyIcon = React.createElement( + 'span', + { + onClick: () => { + if (typeof copyCallback === 'function') { + copyCallback(value, inputElement); + } else { + copyText(value?.toString()); + } + }, + }, + DefaultCopyIcon, + ); + // ================== Addon ================== // if (hasAddon(props)) { const wrapperCls = `${prefixCls}-group`; @@ -159,11 +193,25 @@ const BaseInput: FC = (props) => { hidden: null, })} {addonAfter && {addonAfter}} + {allowCopy ? CopyIcon : null} ); } - return element; + return ( + <> + {CopyIcon ? ( +
+ {element} + {allowCopy ? CopyIcon : null} +
+ ) : ( + element + )} + + ); }; export default BaseInput; diff --git a/src/DefaultCopyIcon.tsx b/src/DefaultCopyIcon.tsx new file mode 100644 index 0000000..e515acf --- /dev/null +++ b/src/DefaultCopyIcon.tsx @@ -0,0 +1,22 @@ +import type { ReactNode } from 'react'; +import React from 'react'; + +const DefaultCopyIcon: ReactNode = ( + + + +); + +export default DefaultCopyIcon; diff --git a/src/interface.ts b/src/interface.ts index 3727420..b71e50e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -10,6 +10,11 @@ import type { InputFocusOptions } from './utils/commonUtils'; import type { LiteralUnion } from './utils/types'; export interface CommonInputProps { + allowCopy?: ReactNode | boolean; + copyCallback?: ( + v: InputHTMLAttributes['value'], + ele: ReactElement>, + ) => void; prefix?: ReactNode; suffix?: ReactNode; addonBefore?: ReactNode;