refactor: add LinkButton in favor of Button
Signed-off-by: Kurt King <kurtaking@gmail.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import { Link, LinkProps } from '../Link';
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
* @deprecated use `LinkButtonProps` instead
|
||||
*
|
||||
* See {@link https://v4.mui.com/api/button/#props | Material-UI Button Props} for all properties
|
||||
*/
|
||||
@@ -43,8 +44,7 @@ const LinkWrapper = React.forwardRef<any, LinkProps>((props, ref) => (
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* Makes the Button to utilize react-router
|
||||
* @deprecated use `LinkButton` instead
|
||||
*/
|
||||
export const Button = React.forwardRef<any, ButtonProps>((props, ref) => (
|
||||
<MaterialButton ref={ref} component={LinkWrapper} {...props} />
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { ComponentType } from 'react';
|
||||
import { LinkButton } from './LinkButton';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { createRouteRef, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import MaterialButton from '@material-ui/core/Button';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { Link } from '../Link';
|
||||
|
||||
const routeRef = createRouteRef({
|
||||
id: 'storybook.test-route',
|
||||
});
|
||||
|
||||
const Location = () => {
|
||||
const location = useLocation();
|
||||
return <pre>Current location: {location.pathname}</pre>;
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Inputs/Button',
|
||||
component: LinkButton,
|
||||
decorators: [
|
||||
(Story: ComponentType<{}>) =>
|
||||
wrapInTestApp(
|
||||
<>
|
||||
<Typography>
|
||||
A collection of buttons that should be used in the Backstage
|
||||
interface. These leverage the properties inherited from{' '}
|
||||
<Link to="https://material-ui.com/components/buttons/">
|
||||
Material-UI Button
|
||||
</Link>
|
||||
, but include an opinionated set that align to the Backstage design.
|
||||
</Typography>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<Location />
|
||||
</div>
|
||||
<Story />
|
||||
</div>
|
||||
</>,
|
||||
{ mountedRoutes: { '/hello': routeRef } },
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export const Default = () => {
|
||||
const link = useRouteRef(routeRef);
|
||||
// Design Permutations:
|
||||
// color = default | primary | secondary
|
||||
// variant = contained | outlined | text
|
||||
return (
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemText>
|
||||
<Typography variant="h6">Default Button:</Typography>
|
||||
This is the default button design which should be used in most cases.
|
||||
<br />
|
||||
<pre>color="primary" variant="contained"</pre>
|
||||
</ListItemText>
|
||||
|
||||
<LinkButton to={link()} color="primary" variant="contained">
|
||||
Register Component
|
||||
</LinkButton>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText>
|
||||
<Typography variant="h6">Secondary Button:</Typography>
|
||||
Used for actions that cancel, skip, and in general perform negative
|
||||
functions, etc.
|
||||
<br />
|
||||
<pre>color="secondary" variant="contained"</pre>
|
||||
</ListItemText>
|
||||
|
||||
<LinkButton to={link()} color="secondary" variant="contained">
|
||||
Cancel
|
||||
</LinkButton>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText>
|
||||
<Typography variant="h6">Tertiary Button:</Typography>
|
||||
Used commonly in a ButtonGroup and when the button function itself is
|
||||
not a primary function on a page.
|
||||
<br />
|
||||
<pre>color="default" variant="outlined"</pre>
|
||||
</ListItemText>
|
||||
|
||||
<LinkButton to={link()} color="default" variant="outlined">
|
||||
View Details
|
||||
</LinkButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export const ButtonLinks = () => {
|
||||
const link = useRouteRef(routeRef);
|
||||
|
||||
const handleClick = () => {
|
||||
return 'Your click worked!';
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<List>
|
||||
{
|
||||
// TODO: Refactor to use new routing mechanisms
|
||||
}
|
||||
<ListItem>
|
||||
<LinkButton to={link()} color="default" variant="outlined">
|
||||
Route Ref
|
||||
</LinkButton>
|
||||
has props for both Material-UI's component as well as for
|
||||
react-router-dom's Route object.
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<LinkButton to="/staticpath" color="default" variant="outlined">
|
||||
Static Path
|
||||
</LinkButton>
|
||||
links to a statically defined route. In general, this should be
|
||||
avoided.
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<MaterialButton
|
||||
href="https://backstage.io"
|
||||
color="default"
|
||||
variant="outlined"
|
||||
>
|
||||
View URL
|
||||
</MaterialButton>
|
||||
links to a defined URL using Material-UI's Button.
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<MaterialButton
|
||||
onClick={handleClick}
|
||||
color="default"
|
||||
variant="outlined"
|
||||
>
|
||||
Trigger Event
|
||||
</MaterialButton>
|
||||
triggers an onClick event using Material-UI's Button.
|
||||
</ListItem>
|
||||
</List>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, fireEvent, act } from '@testing-library/react';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { LinkButton } from './LinkButton';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
|
||||
describe('<LinkButton />', () => {
|
||||
it('navigates using react-router', async () => {
|
||||
const testString = 'This is test string';
|
||||
const linkButtonLabel = 'Navigate!';
|
||||
const { getByText } = render(
|
||||
wrapInTestApp(
|
||||
<>
|
||||
<LinkButton to="/test">{linkButtonLabel}</LinkButton>
|
||||
<Routes>
|
||||
<Route path="/test" element={<p>{testString}</p>} />
|
||||
</Routes>
|
||||
</>,
|
||||
),
|
||||
);
|
||||
|
||||
expect(() => getByText(testString)).toThrow();
|
||||
await act(async () => {
|
||||
fireEvent.click(getByText(linkButtonLabel));
|
||||
});
|
||||
expect(getByText(testString)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import MaterialButton, {
|
||||
ButtonProps as MaterialButtonProps,
|
||||
} from '@material-ui/core/Button';
|
||||
import React from 'react';
|
||||
import { Link, LinkProps } from '../Link';
|
||||
|
||||
/**
|
||||
* Properties for {@link LinkButton}
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://v4.mui.com/api/button/#props | Material-UI Button Props} for all properties
|
||||
*/
|
||||
export type LinkButtonProps = MaterialButtonProps &
|
||||
Omit<LinkProps, 'variant' | 'color'>;
|
||||
|
||||
/**
|
||||
* This wrapper is here to reset the color of the Link and make typescript happy.
|
||||
*/
|
||||
const LinkWrapper = React.forwardRef<any, LinkProps>((props, ref) => (
|
||||
<Link ref={ref} {...props} color="initial" />
|
||||
));
|
||||
|
||||
/**
|
||||
* Thin wrapper on top of material-ui's {@link https://v4.mui.com/components/buttons/ | Button} component
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* Makes the Button to utilize react-router
|
||||
*/
|
||||
export const LinkButton = React.forwardRef<any, LinkButtonProps>(
|
||||
(props, ref) => (
|
||||
<MaterialButton ref={ref} component={LinkWrapper} {...props} />
|
||||
),
|
||||
) as (props: LinkButtonProps) => JSX.Element;
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { LinkButton } from './LinkButton';
|
||||
export type { LinkButtonProps } from './LinkButton';
|
||||
@@ -30,6 +30,7 @@ export * from './HeaderIconLinkRow';
|
||||
export * from './HorizontalScrollGrid';
|
||||
export * from './Lifecycle';
|
||||
export * from './Link';
|
||||
export * from './LinkButton';
|
||||
export * from './LogViewer';
|
||||
export * from './MarkdownContent';
|
||||
export * from './OAuthRequestDialog';
|
||||
|
||||
Reference in New Issue
Block a user