diff --git a/apps/www/src/registry/default/plate-ui/image-element.tsx b/apps/www/src/registry/default/plate-ui/image-element.tsx index 21c4ea0eeb..d3bd85951f 100644 --- a/apps/www/src/registry/default/plate-ui/image-element.tsx +++ b/apps/www/src/registry/default/plate-ui/image-element.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PlateElement, PlateElementProps, Value } from '@udecode/plate-common'; +import { PlateElement, PlateElementProps, Value, withHOC } from '@udecode/plate-common'; import { ELEMENT_IMAGE, Image, @@ -18,12 +18,12 @@ import { ResizeHandle, } from './resizable'; -function InnerImageElement({ +const ImageElement = withHOC(ResizableProvider, ({ className, children, nodeProps, ...props -}: PlateElementProps) { +}: PlateElementProps) => { const { readOnly, focused, selected, align = 'center' } = useMediaState(); const width = useResizableStore().get.width(); @@ -69,12 +69,7 @@ function InnerImageElement({ ); -} +}); +ImageElement.displayName = 'ImageElement'; -export function ImageElement(props: PlateElementProps) { - return ( - - - - ); -} +export { ImageElement }; diff --git a/apps/www/src/registry/default/plate-ui/media-embed-element.tsx b/apps/www/src/registry/default/plate-ui/media-embed-element.tsx index 897c8b6b8f..a32f0238b1 100644 --- a/apps/www/src/registry/default/plate-ui/media-embed-element.tsx +++ b/apps/www/src/registry/default/plate-ui/media-embed-element.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PlateElement, PlateElementProps, Value } from '@udecode/plate-common'; +import { PlateElement, PlateElementProps, Value, withHOC } from '@udecode/plate-common'; import { ELEMENT_MEDIA_EMBED, parseTwitterUrl, @@ -21,7 +21,7 @@ import { ResizeHandle, } from './resizable'; -const InnerMediaEmbedElement = React.forwardRef< +const MediaEmbedElement = withHOC(ResizableProvider, React.forwardRef< React.ElementRef, PlateElementProps >(({ className, children, ...props }, ref) => { @@ -135,16 +135,7 @@ const InnerMediaEmbedElement = React.forwardRef< ); -}); -InnerMediaEmbedElement.displayName = 'InnerMediaEmbedElement'; - -const MediaEmbedElement: typeof InnerMediaEmbedElement = React.forwardRef( - (props, ref) => ( - - - - ) -); +})); MediaEmbedElement.displayName = 'MediaEmbedElement'; export { MediaEmbedElement }; diff --git a/packages/core/src/utils/__snapshots__/withHOC.spec.tsx.snap b/packages/core/src/utils/__snapshots__/withHOC.spec.tsx.snap new file mode 100644 index 0000000000..6dd738f0da --- /dev/null +++ b/packages/core/src/utils/__snapshots__/withHOC.spec.tsx.snap @@ -0,0 +1,53 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`withHOC renders component with HOC 1`] = ` +
+
+ {} + null +
+ {"myProp":"component-prop"} + null +
+
+
+`; + +exports[`withHOC renders component with HOC and HOC props 1`] = ` +
+
+ {"myProp":"hoc-prop"} + null +
+ {"myProp":"component-prop"} + null +
+
+
+`; + +exports[`withHOC renders component with HOC and HOC ref 1`] = ` +
+
+ {} + {"current":{"myRef":"hoc-ref"}} +
+ {"myProp":"component-prop"} + null +
+
+
+`; + +exports[`withHOC renders component with HOC and component ref 1`] = ` +
+
+ {} + null +
+ {"myProp":"component-prop"} + {"current":{"myRef":"component-ref"}} +
+
+
+`; diff --git a/packages/core/src/utils/withHOC.spec.tsx b/packages/core/src/utils/withHOC.spec.tsx new file mode 100644 index 0000000000..bde3593b50 --- /dev/null +++ b/packages/core/src/utils/withHOC.spec.tsx @@ -0,0 +1,67 @@ +import React, { ReactNode } from 'react'; +import { render } from '@testing-library/react'; + +import { withHOC } from './withHOC'; + +/* eslint-disable react/display-name */ +describe('withHOC', () => { + type DummyRef = { myRef: string }; + type DummyProps = { myProp: string }; + + const HOC = React.forwardRef( + ({ children, ...props }, ref) => ( +
+ {JSON.stringify(props)} + {JSON.stringify(ref)} + {children} +
+ ) + ); + + const Component = React.forwardRef((props, ref) => ( +
+ {JSON.stringify(props)} + {JSON.stringify(ref)} +
+ )); + + it('renders component with HOC', () => { + const WithHOC = withHOC(HOC, Component); + + const { container } = render(); + + expect(container).toHaveTextContent('component-prop'); + expect(container).toMatchSnapshot(); + }); + + it('renders component with HOC and HOC props', () => { + const WithHOC = withHOC(HOC, Component, { myProp: 'hoc-prop' }); + + const { container } = render(); + + expect(container).toHaveTextContent('hoc-prop'); + expect(container).toMatchSnapshot(); + }); + + it('renders component with HOC and HOC ref', () => { + const hocRef = { current: { myRef: 'hoc-ref' } }; + const WithHOC = withHOC(HOC, Component, undefined, hocRef); + + const { container } = render(); + + expect(container).toHaveTextContent('hoc-ref'); + expect(container).toMatchSnapshot(); + }); + + it('renders component with HOC and component ref', () => { + const componentRef = { current: { myRef: 'component-ref' } }; + const WithHOC = withHOC(HOC, Component); + + const { container } = render( + + ); + + expect(container).toHaveTextContent('component-ref'); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/packages/core/src/utils/withHOC.tsx b/packages/core/src/utils/withHOC.tsx index 854184e69a..0baffc6854 100644 --- a/packages/core/src/utils/withHOC.tsx +++ b/packages/core/src/utils/withHOC.tsx @@ -1,14 +1,18 @@ -import React, { FunctionComponent } from 'react'; +import React from 'react'; -export const withHOC = ( - HOC: FunctionComponent, - Component: FunctionComponent, - hocProps?: any -): FunctionComponent => - function hoc(props: T) { - return ( - - - - ); - }; +type RefComponent = React.FC

& { + ref?: React.Ref; +}; + +/* eslint-disable react/display-name */ +export const withHOC = ( + HOC: RefComponent, + Component: RefComponent, + hocProps?: Omit, + hocRef?: React.Ref +) => + React.forwardRef((props, componentRef) => ( + + + + ));