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:
@@ -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({
|
||||
|
||||
@@ -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' });
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user