diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.js b/packages/core/src/components/CopyTextButton/CopyTextButton.js
index b6b5edc993..2df978ab2d 100644
--- a/packages/core/src/components/CopyTextButton/CopyTextButton.js
+++ b/packages/core/src/components/CopyTextButton/CopyTextButton.js
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-import React from 'react';
+import React, { useState, useRef } from 'react';
import PropTypes from 'prop-types';
-import { IconButton, Tooltip, withStyles } from '@material-ui/core';
+import { IconButton, Tooltip, makeStyles } from '@material-ui/core';
import CopyIcon from '@material-ui/icons/FileCopy';
-import { errorApiRef, useApi } from '../../api';
+import { errorApiRef, useApi } from 'api';
-const buttonStyles = theme => ({
+const useStyles = makeStyles(theme => ({
button: {
'&:hover': {
backgroundColor: theme.palette.highlight,
cursor: 'pointer',
},
},
-});
+}));
/**
* Copy text button with visual feedback in the form of
@@ -44,68 +44,56 @@ const buttonStyles = theme => ({
* Example:
*
*/
-class CopyTextButton extends React.Component {
- static propTypes = {
- text: PropTypes.string.isRequired,
- tooltipDelay: PropTypes.number,
- tooltipText: PropTypes.string,
- };
+const CopyTextButton = ({
+ text,
+ tooltipDelay = 1000,
+ tooltipText = 'Text copied to clipboard',
+}) => {
+ const classes = useStyles();
+ const errorApi = useApi(errorApiRef);
+ const inputRef = useRef();
+ const [open, setOpen] = useState(false);
- static defaultProps = {
- tooltipDelay: 1000,
- tooltipText: 'Text copied to clipboard',
- };
-
- state = {
- open: false,
- };
-
- handleTooltipClose = () => {
- this.setState({ open: false });
- };
-
- handleTooltipOpen = () => {
- this.setState({ open: true });
- };
-
- handleCopyClick = e => {
+ const handleCopyClick = e => {
e.stopPropagation();
- this.handleTooltipOpen();
+ setOpen(true);
+
try {
- this.clipboardInput.select();
+ inputRef.current.select();
document.execCommand('copy');
} catch (error) {
- const errorApi = useApi(errorApiRef);
errorApi.post(error);
}
};
- render() {
- const { classes, text, tooltipDelay, tooltipText } = this.props;
+ return (
+ <>
+
+ setOpen(false)}
+ open={open}
+ >
+
+
+
+
+ >
+ );
+};
- return (
- <>
- (this.clipboardInput = el)}
- type="text"
- style={{ position: 'absolute', top: -9999, left: 9999 }}
- defaultValue={text}
- />
-
-
-
-
-
- >
- );
- }
-}
+CopyTextButton.propTypes = {
+ text: PropTypes.string.isRequired,
+ tooltipDelay: PropTypes.number,
+ tooltipText: PropTypes.string,
+};
-export default withStyles(buttonStyles)(CopyTextButton);
+export default CopyTextButton;
diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.stories.tsx b/packages/core/src/components/CopyTextButton/CopyTextButton.stories.tsx
index 92db2073d3..7fd78f8057 100644
--- a/packages/core/src/components/CopyTextButton/CopyTextButton.stories.tsx
+++ b/packages/core/src/components/CopyTextButton/CopyTextButton.stories.tsx
@@ -16,10 +16,28 @@
import React from 'react';
import CopyTextButton from '.';
+import { ApiProvider, errorApiRef, ApiRegistry } from 'api';
export default {
title: 'CopyTextButton',
component: CopyTextButton,
+ decorators: [
+ storyFn => {
+ // TODO: move this to common storybook config, requires core package to be separate from components
+ const registry = ApiRegistry.from([
+ [
+ errorApiRef,
+ {
+ post(error) {
+ // eslint-disable-next-line no-alert
+ window.alert(`Component posted error, ${error}`);
+ },
+ },
+ ],
+ ]);
+ return ;
+ },
+ ],
};
export const Default = () => (
diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.test.js b/packages/core/src/components/CopyTextButton/CopyTextButton.test.js
index 81d2f9a863..ad8a9ce5cb 100644
--- a/packages/core/src/components/CopyTextButton/CopyTextButton.test.js
+++ b/packages/core/src/components/CopyTextButton/CopyTextButton.test.js
@@ -18,6 +18,7 @@ import React from 'react';
import { render } from '@testing-library/react';
import { wrapInThemedTestApp } from '@backstage/test-utils';
import CopyTextButton from './CopyTextButton';
+import { ApiRegistry, errorApiRef, ApiProvider } from 'api';
const props = {
text: 'mockText',
@@ -25,10 +26,25 @@ const props = {
tooltipText: 'mockTooltip',
};
+const apiRegistry = ApiRegistry.from([
+ [
+ errorApiRef,
+ {
+ post(error) {
+ throw error;
+ },
+ },
+ ],
+]);
+
describe('', () => {
it('renders without exploding', () => {
const { getByDisplayValue } = render(
- wrapInThemedTestApp(),
+ wrapInThemedTestApp(
+
+
+ ,
+ ),
);
getByDisplayValue('mockText');
});
@@ -38,7 +54,13 @@ describe('', () => {
it.skip('displays tooltip on click', () => {
const spy = jest.fn();
Object.defineProperty(document, 'execCommand', { value: spy });
- const rendered = render(wrapInThemedTestApp());
+ const rendered = render(
+ wrapInThemedTestApp(
+
+
+ ,
+ ),
+ );
const button = rendered.getByTitle('mockTooltip');
button.click();
expect(spy).toHaveBeenCalled();