Merge pull request #25701 from backstage/blam/fixing-header-tabs
Move the `Link` component to `RoutedTabs` instead of `HeaderTabs`
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component
|
||||
@@ -160,4 +160,17 @@ describe('RoutedTabs', () => {
|
||||
rendered.queryByText('tabbed-test-content-2'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the tabs as <a> links', async () => {
|
||||
const routes = [testRoute1, testRoute2, testRoute3];
|
||||
const expectedHrefs = ['/', '/some-other-path', '/some-other-path-similar'];
|
||||
const rendered = await renderInTestApp(<RoutedTabs routes={routes} />);
|
||||
|
||||
const tabs = rendered.queryAllByRole('tab');
|
||||
|
||||
for (const [k, v] of Object.entries(tabs)) {
|
||||
expect(v.tagName).toBe('A');
|
||||
expect(v).toHaveAttribute('href', expectedHrefs[Number(k)]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,15 +15,11 @@
|
||||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import {
|
||||
matchRoutes,
|
||||
useNavigate,
|
||||
useParams,
|
||||
useRoutes,
|
||||
} from 'react-router-dom';
|
||||
import { matchRoutes, useParams, useRoutes } from 'react-router-dom';
|
||||
import { Content } from '../../layout/Content';
|
||||
import { HeaderTabs } from '../../layout/HeaderTabs';
|
||||
import { SubRoute } from './types';
|
||||
import { Link } from '../Link';
|
||||
|
||||
export function useSelectedSubRoute(subRoutes: SubRoute[]): {
|
||||
index: number;
|
||||
@@ -68,35 +64,33 @@ export function useSelectedSubRoute(subRoutes: SubRoute[]): {
|
||||
|
||||
export function RoutedTabs(props: { routes: SubRoute[] }) {
|
||||
const { routes } = props;
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { index, route, element } = useSelectedSubRoute(routes);
|
||||
const headerTabs = useMemo(
|
||||
() =>
|
||||
routes.map(t => ({
|
||||
id: t.path,
|
||||
label: t.title,
|
||||
tabProps: t.tabProps,
|
||||
})),
|
||||
routes.map(t => {
|
||||
const { path, title, tabProps } = t;
|
||||
let to = path;
|
||||
// Remove trailing /*
|
||||
to = to.replace(/\/\*$/, '');
|
||||
// And remove leading / for relative navigation
|
||||
to = to.replace(/^\//, '');
|
||||
return {
|
||||
id: path,
|
||||
label: title,
|
||||
tabProps: {
|
||||
component: Link,
|
||||
to,
|
||||
...tabProps,
|
||||
},
|
||||
};
|
||||
}),
|
||||
[routes],
|
||||
);
|
||||
|
||||
const onTabChange = (tabIndex: number) => {
|
||||
let { path } = routes[tabIndex];
|
||||
// Remove trailing /*
|
||||
path = path.replace(/\/\*$/, '');
|
||||
// And remove leading / for relative navigation
|
||||
path = path.replace(/^\//, '');
|
||||
// Note! route resolves relative to the position in the React tree,
|
||||
// not relative to current location
|
||||
navigate(path);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<HeaderTabs
|
||||
tabs={headerTabs}
|
||||
selectedIndex={index}
|
||||
onChange={onTabChange}
|
||||
/>
|
||||
<HeaderTabs tabs={headerTabs} selectedIndex={index} />
|
||||
<Content>
|
||||
<Helmet title={route?.title} />
|
||||
{element}
|
||||
|
||||
@@ -95,13 +95,4 @@ describe('<HeaderTabs />', () => {
|
||||
await user.click(rendered.getByText('Docs'));
|
||||
expect(mockOnChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should render 2 nav tabs', async () => {
|
||||
const rendered = await renderInTestApp(<HeaderTabs tabs={mockTabs} />);
|
||||
const tabs = rendered.queryAllByTestId(id => id.startsWith('header-tab'));
|
||||
expect(tabs).toHaveLength(2);
|
||||
tabs.forEach(tab => {
|
||||
expect(tab.tagName.toLocaleLowerCase('en-US')).toBe('a');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,7 +18,6 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import TabUI, { TabProps } from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Link } from '../../components/Link';
|
||||
|
||||
// TODO(blam): Remove this implementation when the Tabs are ready
|
||||
// This is just a temporary solution to implementing tabs for now
|
||||
@@ -96,9 +95,7 @@ export function HeaderTabs(props: HeaderTabsProps) {
|
||||
setSelectedTab(selectedIndex);
|
||||
}
|
||||
}, [selectedIndex]);
|
||||
function removeLeadingSlash(path: string) {
|
||||
return path.replace(/^\//, '');
|
||||
}
|
||||
|
||||
return (
|
||||
<Box className={styles.tabsWrapper}>
|
||||
<Tabs
|
||||
@@ -115,8 +112,6 @@ export function HeaderTabs(props: HeaderTabsProps) {
|
||||
data-testid={`header-tab-${index}`}
|
||||
label={tab.label}
|
||||
key={tab.id}
|
||||
component={Link}
|
||||
to={removeLeadingSlash(tab.id)}
|
||||
value={index}
|
||||
className={styles.defaultTab}
|
||||
classes={{ selected: styles.selected, root: styles.tabRoot }}
|
||||
|
||||
Reference in New Issue
Block a user