From 8b429c03a73856d8e4a56ff5a5e146c6261aff70 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 18 Apr 2020 18:20:11 +0200 Subject: [PATCH] packages/core/components/CopyTextButton: refactor to functional component + provide errorApi in storybook --- .../CopyTextButton/CopyTextButton.js | 106 ++++++++---------- .../CopyTextButton/CopyTextButton.stories.tsx | 18 +++ .../CopyTextButton/CopyTextButton.test.js | 26 ++++- 3 files changed, 89 insertions(+), 61 deletions(-) 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();