Skip to content

Commit

Permalink
refactor(CopyToClipboard): replaced class component by functional com…
Browse files Browse the repository at this point in the history
…ponent
  • Loading branch information
atroynikov committed Dec 21, 2023
1 parent 84f8c97 commit 74f0738
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 69 deletions.
90 changes: 27 additions & 63 deletions src/components/CopyToClipboard/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,41 @@ import React from 'react';

import ReactCopyToClipboard from 'react-copy-to-clipboard';

import type {
CopyToClipboardBaseProps,
CopyToClipboardContent,
CopyToClipboardStatus,
} from './types';
import type {CopyToClipboardProps, CopyToClipboardStatus} from './types';

interface CopyToClipboardGeneralProps extends CopyToClipboardBaseProps {
children: CopyToClipboardContent;
}

interface CopyToClipboardDefaultProps {
timeout: number;
}
const INITIAL_STATUS: CopyToClipboardStatus = 'pending';

interface CopyToClipboardInnerProps
extends CopyToClipboardGeneralProps,
CopyToClipboardDefaultProps {}
export function CopyToClipboard(props: CopyToClipboardProps) {
const {children, text, options, timeout, onCopy} = props;

export interface CopyToClipboardProps
extends CopyToClipboardGeneralProps,
Partial<CopyToClipboardDefaultProps> {}
const [status, setStatus] = React.useState<CopyToClipboardStatus>(INITIAL_STATUS);

interface CopyToClipboardState {
status: CopyToClipboardStatus;
}
const timerIdRef = React.useRef<number>();

export class CopyToClipboard extends React.Component<
CopyToClipboardInnerProps,
CopyToClipboardState
> {
static INITIAL_STATUS: CopyToClipboardStatus = 'pending';
const content = React.useMemo(() => children(status), [children, status]);

state: CopyToClipboardState = {
status: CopyToClipboard.INITIAL_STATUS,
};
const handleCopy = React.useCallback<Required<ReactCopyToClipboard.Props>['onCopy']>(
(copyText, result) => {
setStatus(result ? 'success' : 'error');
window.clearTimeout(timerIdRef.current);
timerIdRef.current = window.setTimeout(() => {
setStatus(INITIAL_STATUS);
timerIdRef.current = undefined;
}, timeout);
onCopy?.(copyText, result);
},
[onCopy, timeout],
);

private timerId?: number;
React.useEffect(() => () => window.clearTimeout(timerIdRef.current), []);

componentWillUnmount() {
clearTimeout(this.timerId);
if (!React.isValidElement(content)) {
throw new Error('Content must be a valid react element');
}

render() {
const {children, text, options} = this.props;
const {status} = this.state;
const content = children(status);

if (!React.isValidElement(content)) {
throw new Error('Content must be a valid react element');
}

return (
<ReactCopyToClipboard text={String(text)} onCopy={this.handleCopy} options={options}>
{content}
</ReactCopyToClipboard>
);
}

private handleCopy = (text: string, result: boolean) => {
const {timeout, onCopy} = this.props;

this.setState({
status: result ? 'success' : 'error',
});

clearTimeout(this.timerId);
this.timerId = window.setTimeout(() => {
this.setState({status: CopyToClipboard.INITIAL_STATUS});
this.timerId = undefined;
}, timeout);

onCopy?.(text, result);
};
return (
<ReactCopyToClipboard text={String(text)} onCopy={handleCopy} options={options}>
{content}
</ReactCopyToClipboard>
);
}
11 changes: 5 additions & 6 deletions src/components/CopyToClipboard/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type React from 'react';

import type ReactCopyToClipboard from 'react-copy-to-clipboard';

export type CopyToClipboardStatus = 'pending' | 'success' | 'error';
Expand All @@ -6,13 +8,10 @@ export type OnCopyHandler = (text: string, result: boolean) => void;

export type CopyToClipboardContent = (status: CopyToClipboardStatus) => React.ReactElement;

export interface CopyToClipboardBaseProps {
/** Text to copy */
export interface CopyToClipboardProps {
text: string;

/** Handler that would be invoked after copy to clipboard */
timeout: number;
children: CopyToClipboardContent;
onCopy?: OnCopyHandler;

/** copy-to-clipboard options */
options?: ReactCopyToClipboard.Options;
}

0 comments on commit 74f0738

Please sign in to comment.