Skip to content

Commit

Permalink
feat: accept a wider range of React components
Browse files Browse the repository at this point in the history
  • Loading branch information
mathuo committed Feb 9, 2024
1 parent 30c7fa2 commit 874da1c
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 10 deletions.
21 changes: 20 additions & 1 deletion packages/dockview/src/__tests__/react.spec.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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) => {
Expand Down
24 changes: 15 additions & 9 deletions packages/dockview/src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
);
}

Expand Down Expand Up @@ -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 */
);
}

0 comments on commit 874da1c

Please sign in to comment.