parent
e6bd58453a
commit
99fc52039f
@ -1,139 +0,0 @@
|
|||||||
import Clipboard from 'clipboard';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import FormInputButton from 'Components/Form/FormInputButton';
|
|
||||||
import Icon from 'Components/Icon';
|
|
||||||
import { icons, kinds } from 'Helpers/Props';
|
|
||||||
import getUniqueElememtId from 'Utilities/getUniqueElementId';
|
|
||||||
import styles from './ClipboardButton.css';
|
|
||||||
|
|
||||||
class ClipboardButton extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this._id = getUniqueElememtId();
|
|
||||||
this._successTimeout = null;
|
|
||||||
this._testResultTimeout = null;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showSuccess: false,
|
|
||||||
showError: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this._clipboard = new Clipboard(`#${this._id}`, {
|
|
||||||
text: () => this.props.value,
|
|
||||||
container: document.getElementById(this._id)
|
|
||||||
});
|
|
||||||
|
|
||||||
this._clipboard.on('success', this.onSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
const {
|
|
||||||
showSuccess,
|
|
||||||
showError
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
if (showSuccess || showError) {
|
|
||||||
this._testResultTimeout = setTimeout(this.resetState, 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this._clipboard) {
|
|
||||||
this._clipboard.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._testResultTimeout) {
|
|
||||||
clearTimeout(this._testResultTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
resetState = () => {
|
|
||||||
this.setState({
|
|
||||||
showSuccess: false,
|
|
||||||
showError: false
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onSuccess = () => {
|
|
||||||
this.setState({
|
|
||||||
showSuccess: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onError = () => {
|
|
||||||
this.setState({
|
|
||||||
showError: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
value,
|
|
||||||
className,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
showSuccess,
|
|
||||||
showError
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const showStateIcon = showSuccess || showError;
|
|
||||||
const iconName = showError ? icons.DANGER : icons.CHECK;
|
|
||||||
const iconKind = showError ? kinds.DANGER : kinds.SUCCESS;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormInputButton
|
|
||||||
id={this._id}
|
|
||||||
className={className}
|
|
||||||
{...otherProps}
|
|
||||||
>
|
|
||||||
<span className={showStateIcon ? styles.showStateIcon : undefined}>
|
|
||||||
{
|
|
||||||
showSuccess &&
|
|
||||||
<span className={styles.stateIconContainer}>
|
|
||||||
<Icon
|
|
||||||
name={iconName}
|
|
||||||
kind={iconKind}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
<span className={styles.clipboardIconContainer}>
|
|
||||||
<Icon name={icons.CLIPBOARD} />
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</FormInputButton>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ClipboardButton.propTypes = {
|
|
||||||
className: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
ClipboardButton.defaultProps = {
|
|
||||||
className: styles.button
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ClipboardButton;
|
|
@ -0,0 +1,69 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import FormInputButton from 'Components/Form/FormInputButton';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
|
import { ButtonProps } from './Button';
|
||||||
|
import styles from './ClipboardButton.css';
|
||||||
|
|
||||||
|
export interface ClipboardButtonProps extends Omit<ButtonProps, 'children'> {
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ClipboardState = 'success' | 'error' | null;
|
||||||
|
|
||||||
|
export default function ClipboardButton({
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
className = styles.button,
|
||||||
|
...otherProps
|
||||||
|
}: ClipboardButtonProps) {
|
||||||
|
const [state, setState] = useState<ClipboardState>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setState(null);
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
|
const handleClick = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(value);
|
||||||
|
setState('success');
|
||||||
|
} catch (_) {
|
||||||
|
setState('error');
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormInputButton
|
||||||
|
className={className}
|
||||||
|
onClick={handleClick}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<span className={state ? styles.showStateIcon : undefined}>
|
||||||
|
{state ? (
|
||||||
|
<span className={styles.stateIconContainer}>
|
||||||
|
<Icon
|
||||||
|
name={state === 'error' ? icons.DANGER : icons.CHECK}
|
||||||
|
kind={state === 'error' ? kinds.DANGER : kinds.SUCCESS}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<span className={styles.clipboardIconContainer}>
|
||||||
|
<Icon name={icons.CLIPBOARD} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</FormInputButton>
|
||||||
|
);
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
// returns a HTML 4.0 compliant element IDs (http://stackoverflow.com/a/79022)
|
/**
|
||||||
|
* @deprecated Use React's useId() instead
|
||||||
|
* @returns An HTML 4.0 compliant element IDs (http://stackoverflow.com/a/79022)
|
||||||
|
*/
|
||||||
export default function getUniqueElementId() {
|
export default function getUniqueElementId() {
|
||||||
return `id-${i++}`;
|
return `id-${i++}`;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue