core-api: add naive implementation of param-relative routing

Co-authored-by: blam <ben@blam.sh>
This commit is contained in:
Patrik Oldsberg
2020-11-27 16:10:19 +01:00
parent cf2855dc9e
commit 64993c1dd2
2 changed files with 44 additions and 7 deletions
+38 -2
View File
@@ -38,6 +38,7 @@ const ref1 = createRouteRef(mockConfig());
const ref2 = createRouteRef(mockConfig());
const ref3 = createRouteRef(mockConfig());
const ref4 = createRouteRef(mockConfig());
const ref5 = createRouteRef(mockConfig());
const MockRouteSource = (props: {
name: string;
@@ -47,7 +48,7 @@ const MockRouteSource = (props: {
const routeFunc = useRouteRef(props.routeRef);
return (
<div>
Path at {props.name}: {routeFunc?.(props.params)}
Path at {props.name}: {routeFunc(props.params)}
</div>
);
};
@@ -64,6 +65,9 @@ const Extension3 = plugin.provide(
const Extension4 = plugin.provide(
createRoutableExtension({ component: MockRouteSource, mountPoint: ref4 }),
);
const Extension5 = plugin.provide(
createRoutableExtension({ component: MockComponent, mountPoint: ref5 }),
);
describe('discovery', () => {
it('should handle simple routeRef path creation for routeRefs used in other parts of the app', () => {
@@ -100,7 +104,7 @@ describe('discovery', () => {
it('should handle routeRefs with parameters', () => {
const root = (
<MemoryRouter initialEntries={['/foo/bar/:id']}>
<MemoryRouter initialEntries={['/foo/bar/wat']}>
<Routes>
<Extension1 path="/foo">
<Extension4
@@ -141,4 +145,36 @@ describe('discovery', () => {
rendered.getByText('Path at outside: /foo/bar/blob'),
).toBeInTheDocument();
});
it('should handle relative routing within parameterized routes', () => {
const root = (
<MemoryRouter initialEntries={['/foo/blob/bar']}>
<Routes>
<Extension5 path="/foo/:id">
<Extension2 path="/bar" name="inside" routeRef={ref3} />
<Extension3 path="/baz" />
</Extension5>
</Routes>
</MemoryRouter>
);
const { routes, routeParents } = traverseElementTree({
root,
discoverers: [childDiscoverer, routeElementDiscoverer],
collectors: {
routes: routeCollector,
routeParents: routeParentCollector,
},
});
const rendered = render(
<RoutingProvider routes={routes} routeParents={routeParents}>
{root}
</RoutingProvider>,
);
expect(
rendered.getByText('Path at inside: /foo/blob/baz'),
).toBeInTheDocument();
});
});
+6 -5
View File
@@ -16,7 +16,7 @@
import React, { createContext, ReactNode, useContext } from 'react';
import { RouteRef } from './types';
import { generatePath } from 'react-router-dom';
import { generatePath, useParams } from 'react-router-dom';
export type RouteFunc = (params?: Record<string, string>) => string;
@@ -26,7 +26,7 @@ class RouteResolver {
private readonly routeParents: Map<RouteRef, RouteRef | undefined>,
) {}
resolve(routeRef: RouteRef): RouteFunc {
resolve(routeRef: RouteRef, parentParams: Record<string, string>): RouteFunc {
let currentRouteRef: RouteRef | undefined = routeRef;
let fullPath = '';
@@ -40,20 +40,21 @@ class RouteResolver {
}
return (params?: Record<string, string>) => {
return generatePath(fullPath, params);
return generatePath(fullPath, { ...params, ...parentParams });
};
}
}
const RoutingContext = createContext<RouteResolver | undefined>(undefined);
export function useRouteRef(routeRef: RouteRef): RouteFunc | undefined {
export function useRouteRef(routeRef: RouteRef): RouteFunc {
const resolver = useContext(RoutingContext);
const params = useParams();
if (!resolver) {
throw new Error('No route resolver found in context');
}
return resolver.resolve(routeRef);
return resolver.resolve(routeRef, params);
}
type ProviderProps = {