Merge pull request #25701 from backstage/blam/fixing-header-tabs

Move the `Link` component to `RoutedTabs` instead of `HeaderTabs`
This commit is contained in:
Patrik Oldsberg
2024-07-23 12:52:57 +02:00
committed by GitHub
5 changed files with 40 additions and 42 deletions
+5
View File
@@ -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 }}