@@ -160,4 +160,16 @@ describe('RoutedTabs', () => {
|
||||
rendered.queryByText('tabbed-test-content-2'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the tabs as <a> links', async () => {
|
||||
const routes = [testRoute2, testRoute1, testRoute3];
|
||||
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', routes[Number(k)].path);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,38 +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: {
|
||||
...tabProps,
|
||||
component: Link,
|
||||
to,
|
||||
},
|
||||
};
|
||||
}),
|
||||
[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}
|
||||
tabProps={{
|
||||
component: Link,
|
||||
}}
|
||||
/>
|
||||
<HeaderTabs tabs={headerTabs} selectedIndex={index} />
|
||||
<Content>
|
||||
<Helmet title={route?.title} />
|
||||
{element}
|
||||
|
||||
Reference in New Issue
Block a user