diff --git a/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx b/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx index 9a84fe08fa..e20a35ff84 100644 --- a/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx +++ b/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx @@ -22,4 +22,59 @@ describe('createComponentRef', () => { expect(ref.id).toBe('foo'); expect(String(ref)).toBe('ComponentRef{id=foo}'); }); + + it('should allow defining a default component implementation', () => { + const Test = () =>
test
; + + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + mode: 'sync', + defaultComponent: ({ bar }) => , + }); + + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + mode: 'async', + defaultComponent: async () => , + }); + + // @ts-expect-error - this should be an error as mode is sync + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + mode: 'sync', + defaultComponent: async ({ bar }) => , + }); + + // todo: why do we have two errors here? + // @ts-expect-error - this should be an error as mode is async + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + mode: 'async', + defaultComponent: ({ bar }) => , + }); + + // todo: why does this not work? + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + // @ts-expect-error - this should be an error as default mode is async + defaultComponent: ({ bar }) => , + }); + + expect(Test).toBeDefined(); + }); + + it('should allow transformings props', () => { + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + transformProps: props => ({ foo: props.bar }), + }); + + createComponentRef<{ foo: string }, { bar: string }>({ + id: 'foo', + // @ts-expect-error - this should be an error as foo is not a string + transformProps: props => ({ foo: 1 }), + }); + + expect(true).toBe(true); + }); }); diff --git a/packages/frontend-plugin-api/src/components/createComponentRef.tsx b/packages/frontend-plugin-api/src/components/createComponentRef.tsx index 88181dd079..9f36e7f21e 100644 --- a/packages/frontend-plugin-api/src/components/createComponentRef.tsx +++ b/packages/frontend-plugin-api/src/components/createComponentRef.tsx @@ -15,20 +15,82 @@ */ /** @public */ -export type ComponentRef = { +export type ComponentRef< + TInnerComponentProps, + TExternalComponentProps, + TMode extends 'sync' | 'async' = 'async', +> = { id: string; - T: T; + mode: TMode; + transformProps?: (props: TExternalComponentProps) => TInnerComponentProps; + defaultComponent?: TMode extends 'async' + ? (props: TExternalComponentProps) => Promise + : (props: TExternalComponentProps) => JSX.Element; }; -/** @public */ -export function createComponentRef(options: { +export interface ComponentRefOptions< + TInnerComponentProps, + TExternalComponentProps, + TMode extends 'sync' | 'async' = 'async', +> { id: string; -}): ComponentRef { - const { id } = options; + mode?: TMode; + defaultComponent?: TMode extends 'async' + ? (props: TExternalComponentProps) => Promise + : (props: TExternalComponentProps) => JSX.Element; + transformProps?: (props: TExternalComponentProps) => TInnerComponentProps; +} + +/** + * Creates a new component ref that is synchronous. + * @public + */ +export function createComponentRef< + TInnerComponentProps, + TExternalComponentProps, +>( + options: ComponentRefOptions< + TInnerComponentProps, + TExternalComponentProps, + 'sync' + >, +): ComponentRef; + +/** + * Creates a new component ref that is asynchronous. + * @public + */ +export function createComponentRef< + TInnerComponentProps, + TExternalComponentProps, +>( + options: ComponentRefOptions< + TInnerComponentProps, + TExternalComponentProps, + 'async' + >, +): ComponentRef; + +export function createComponentRef< + TInnerComponentProps, + TExternalComponentProps, + TMode extends 'sync' | 'async', +>( + options: ComponentRefOptions< + TInnerComponentProps, + TExternalComponentProps, + TMode + >, +): ComponentRef { + const { id, mode = 'async', defaultComponent, transformProps } = options; + return { id, + mode, + defaultComponent, + transformProps, toString() { return `ComponentRef{id=${id}}`; }, - } as ComponentRef; + } as ComponentRef; }