feat: accept a wider range of React components

This commit is contained in:
mathuo 2024-02-09 20:15:14 +00:00
parent 30c7fa2c6a
commit 874da1c7d9
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
2 changed files with 35 additions and 10 deletions

View File

@ -1,4 +1,4 @@
import { ReactPart } from '../react';
import { ReactPart, isReactComponent } from '../react';
import * as React from 'react';
import { render, screen, act } from '@testing-library/react';
@ -40,6 +40,25 @@ describe('react', () => {
expect(screen.getByTestId('valueB').textContent).toBe('22');
});
});
describe('isReactElement', () => {
test('functional component', () => {
const FunctionalComponent: React.FC = () => <div />;
expect(isReactComponent(FunctionalComponent)).toBeTruthy();
});
test('React.memo component', () => {
const memoComponent = React.memo(() => <div />);
expect(isReactComponent(memoComponent)).toBeTruthy();
});
test('forward ref component', () => {
const ForwardRefComponent = React.forwardRef((props, ref) => (
<div />
));
expect(isReactComponent(ForwardRefComponent)).toBeTruthy();
});
});
});
const Component = (props: TestInterface) => {

View File

@ -102,14 +102,14 @@ export class ReactPart<P extends object, C extends object = {}>
throw new Error('invalid operation: resource is already disposed');
}
if (typeof this.component !== 'function') {
if (!isReactComponent(this.component)) {
/**
* we know this isn't a React.FunctionComponent so throw an error here.
* if we do not intercept this the React library will throw a very obsure error
* for the same reason, at least at this point we will emit a sensible stacktrace.
* if we do not intercept then React library will throw a very obsure error
* for the same reason... at least at this point we will emit a sensible stacktrace.
*/
throw new Error(
'Invalid Operation. dockview only supports React Functional Components.'
'Dockview: Only React.memo(...), React.ForwardRef(...) and functional components are accepted as components'
);
}
@ -192,9 +192,15 @@ export const usePortalsLifecycle: PortalLifecycleHook = () => {
return [portals, addPortal];
};
// it does the job...
export function isReactElement(
element: unknown
): element is React.ReactElement {
return !!(element as React.ReactElement)?.type;
export function isReactComponent(component: any): boolean {
/**
* Yes, we could use "react-is" but that would introduce an unwanted peer dependency
* so for now we will check in a rather crude fashion...
*/
return (
typeof component === 'function' /** Functional Componnts */ ||
!!(component as React.ExoticComponent)
?.$$typeof /** React.memo(...) Components */
);
}