core-api: refactor createReactExtension to forward component types directly and avoid @types/react dependency

Co-authored-by: blam <ben@blam.sh>
This commit is contained in:
Patrik Oldsberg
2020-12-17 16:11:00 +01:00
parent aeb9fb254e
commit adb1afdc2b
6 changed files with 33 additions and 33 deletions
+3 -3
View File
@@ -17,7 +17,7 @@
import { renderWithEffects, withLogCollector } from '@backstage/test-utils';
import { lightTheme } from '@backstage/theme';
import { render, screen } from '@testing-library/react';
import React from 'react';
import React, { PropsWithChildren } from 'react';
import { BrowserRouter, Routes } from 'react-router-dom';
import { createRoutableExtension } from '../extensions';
import { defaultSystemIcons } from '../icons';
@@ -66,14 +66,14 @@ describe('Integration Test', () => {
const HiddenComponent = plugin2.provide(
createRoutableExtension({
component: () => null,
component: (_: { path?: string }) => <div />,
mountPoint: plugin2RouteRef,
}),
);
const ExposedComponent = plugin1.provide(
createRoutableExtension({
component: () => {
component: (_: PropsWithChildren<{ path?: string }>) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const routeRefFunction = useRouteRef(externalRouteRef);
return <div>Our Route Is: {routeRefFunction({})}</div>;
@@ -30,7 +30,7 @@ const plugin = createPlugin({
describe('extensions', () => {
it('should create a react extension with component data', () => {
const Component = () => null;
const Component = () => <div />;
const extension = createReactExtension({
component: Component,
@@ -47,7 +47,7 @@ describe('extensions', () => {
});
it('should create react extensions of different types', () => {
const Component = () => null;
const Component = () => <div />;
const routeRef = createRouteRef({ path: '/foo', title: 'Foo' });
const extension1 = createComponentExtension({
+18 -25
View File
@@ -14,24 +14,14 @@
* limitations under the License.
*/
import React, {
NamedExoticComponent,
ComponentType,
PropsWithChildren,
} from 'react';
import React from 'react';
import { RouteRef } from '../routing';
import { attachComponentData } from './componentData';
import { Extension, BackstagePlugin } from '../plugin/types';
export function createRoutableExtension<Props extends {}>(options: {
component: ComponentType<Props>;
mountPoint: RouteRef;
// TODO(Rugvip): We want to carry forward the exact props type from the inner component, with
// or without children. ComponentType stops us from doing that though, as it always
// adds children to the props internally. We may want to work around this with custom types.
}): Extension<
NamedExoticComponent<PropsWithChildren<Props & { path?: string }>>
> {
export function createRoutableExtension<
T extends (props: any) => JSX.Element
>(options: { component: T; mountPoint: RouteRef }): Extension<T> {
const { component, mountPoint } = options;
return createReactExtension({
component,
@@ -41,21 +31,24 @@ export function createRoutableExtension<Props extends {}>(options: {
});
}
export function createComponentExtension<Props extends {}>(options: {
component: ComponentType<Props>;
}): Extension<NamedExoticComponent<Props>> {
export function createComponentExtension<
T extends (props: any) => JSX.Element
>(options: { component: T }): Extension<T> {
const { component } = options;
return createReactExtension({ component });
}
export function createReactExtension<Props extends {}>(options: {
component: ComponentType<Props>;
data?: Record<string, unknown>;
}): Extension<NamedExoticComponent<Props>> {
const { component: Component, data = {} } = options;
export function createReactExtension<
T extends (props: any) => JSX.Element
>(options: { component: T; data?: Record<string, unknown> }): Extension<T> {
const { data = {} } = options;
const Component = options.component as T & {
displayName?: string;
};
return {
expose(plugin: BackstagePlugin<any, any>): NamedExoticComponent<Props> {
const Result = (props: Props) => <Component {...props} />;
expose(plugin: BackstagePlugin<any, any>) {
const Result: any = (props: any) => <Component {...props} />;
attachComponentData(Result, 'core.plugin', plugin);
for (const [key, value] of Object.entries(data)) {
@@ -66,7 +59,7 @@ export function createReactExtension<Props extends {}>(options: {
if (name) {
Result.displayName = `Extension(${name})`;
}
return Result as NamedExoticComponent<Props>;
return Result;
},
};
}
@@ -30,7 +30,9 @@ import {
import { pluginCollector } from './collectors';
const mockConfig = () => ({ path: '/foo', title: 'Foo' });
const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}</>;
const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => (
<>{children}</>
);
const pluginA = createPlugin({ id: 'my-plugin-a' });
const pluginB = createPlugin({ id: 'my-plugin-b' });
@@ -28,7 +28,9 @@ import { createRoutableExtension } from '../extensions';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
const mockConfig = () => ({ path: '/foo', title: 'Foo' });
const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}</>;
const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => (
<>{children}</>
);
const plugin = createPlugin({ id: 'my-plugin' });
+4 -1
View File
@@ -47,7 +47,9 @@ const mockConfig = (extra?: Partial<RouteRefConfig<{}>>) => ({
title: 'Unused',
...extra,
});
const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}</>;
const MockComponent = ({ children }: PropsWithChildren<{ path?: string }>) => (
<>{children}</>
);
const plugin = createPlugin({ id: 'my-plugin' });
@@ -61,6 +63,7 @@ const eRefB = createExternalRouteRef();
const eRefC = createExternalRouteRef();
const MockRouteSource = <T extends { [name in string]: string }>(props: {
path?: string;
name: string;
routeRef: RouteRef<T> | ExternalRouteRef;
params?: T;