{({ measureRef: previewRef }) => {
- const { children, logger } = this.props;
+ const { renderCustomPreview, logger } = this.props;
return (
- {children ? (
+ {renderCustomPreview ? (
{
logger={logger}
onPreviewError={this.onPreviewError}
onPreviewLoad={this.onPreviewLoad}
- >
- {children}
-
+ />
) : null}
);
diff --git a/src/elements/content-preview/CustomPreviewWrapper.js b/src/elements/content-preview/CustomPreviewWrapper.js
index f7b7769160..addc70900f 100644
--- a/src/elements/content-preview/CustomPreviewWrapper.js
+++ b/src/elements/content-preview/CustomPreviewWrapper.js
@@ -11,15 +11,23 @@ type CustomPreviewOnError = (error: Error | ErrorType | ElementsXhrError) => voi
type CustomPreviewOnLoad = (data: Object) => void;
/**
- * Props that are automatically injected into ContentPreview children.
+ * Props passed to the renderCustomPreview function.
* Import this type to ensure your custom preview component accepts the required props.
*
* @example
* import type { ContentPreviewChildProps } from 'box-ui-elements';
*
+ * // Define your custom preview component
* const MyCustomPreview = ({ fileId, token, apiHost, file, onError, onLoad }: ContentPreviewChildProps) => {
* // Your implementation
* };
+ *
+ * // Use with ContentPreview
+ * }
+ * />
*/
export type ContentPreviewChildProps = {
fileId: string,
@@ -31,7 +39,7 @@ export type ContentPreviewChildProps = {
};
type Props = {
- children: React.Node,
+ renderCustomPreview: (props: ContentPreviewChildProps) => React.Node,
apiHost: string,
file: BoxItem,
fileId: string,
@@ -43,11 +51,11 @@ type Props = {
/**
* Wrapper component for custom preview content.
- * Clones the child element and injects props (fileId, token, apiHost, file, onError, onLoad).
- * Wraps children in ErrorBoundary and transforms errors to ContentPreview error format.
+ * Calls the render function with props (fileId, token, apiHost, file, onError, onLoad).
+ * Wraps rendered content in ErrorBoundary and transforms errors to ContentPreview error format.
*/
function CustomPreviewWrapper({
- children,
+ renderCustomPreview,
apiHost,
file,
fileId,
@@ -93,19 +101,22 @@ function CustomPreviewWrapper({
}
};
- // Clone child element and inject props
- const childWithProps = React.cloneElement((children: any), {
+ // Build props object for render function
+ const childProps: ContentPreviewChildProps = {
fileId,
token,
apiHost,
file,
onError: handleCustomError,
onLoad: onPreviewLoad,
- });
+ };
+
+ // Call render function with props and wrap in fragment to ensure it's a valid React.Element
+ const customContent = <>{renderCustomPreview(childProps)}>;
return (
- {childWithProps}
+ {customContent}
);
}
diff --git a/src/elements/content-preview/__tests__/ContentPreview.test.js b/src/elements/content-preview/__tests__/ContentPreview.test.js
index 75e9c1c8ab..0b0ceecbc9 100644
--- a/src/elements/content-preview/__tests__/ContentPreview.test.js
+++ b/src/elements/content-preview/__tests__/ContentPreview.test.js
@@ -1687,7 +1687,7 @@ describe('elements/content-preview/ContentPreview', () => {
});
});
- describe('children (custom preview content)', () => {
+ describe('renderCustomPreview (custom preview content)', () => {
const CustomPreview = () => Custom Content
;
let onError;
let onLoad;
@@ -1703,7 +1703,7 @@ describe('elements/content-preview/ContentPreview', () => {
token: 'token',
fileId: file.id,
apiHost: 'https://api.box.com',
- children: ,
+ renderCustomPreview: childProps => ,
onError,
onLoad,
};
@@ -1722,7 +1722,7 @@ describe('elements/content-preview/ContentPreview', () => {
});
describe('loadPreview()', () => {
- test('should return early without loading Box.Preview when children is provided', async () => {
+ test('should return early without loading Box.Preview when renderCustomPreview is provided', async () => {
const wrapper = getWrapper(props);
wrapper.setState({ file });
const instance = wrapper.instance();
@@ -1735,9 +1735,9 @@ describe('elements/content-preview/ContentPreview', () => {
expect(instance.preview).toBeUndefined();
});
- test('should load Box.Preview normally when children is not provided', async () => {
+ test('should load Box.Preview normally when renderCustomPreview is not provided', async () => {
const propsWithoutCustom = { ...props };
- delete propsWithoutCustom.children;
+ delete propsWithoutCustom.renderCustomPreview;
const wrapper = getWrapper(propsWithoutCustom);
wrapper.setState({ file });
const instance = wrapper.instance();
@@ -1751,7 +1751,7 @@ describe('elements/content-preview/ContentPreview', () => {
});
describe('onKeyDown()', () => {
- test('should return early when children is provided', () => {
+ test('should return early when renderCustomPreview is provided', () => {
const wrapper = getWrapper({ ...props, useHotkeys: true });
const instance = wrapper.instance();
const event = {
@@ -1766,13 +1766,13 @@ describe('elements/content-preview/ContentPreview', () => {
expect(event.stopPropagation).not.toHaveBeenCalled();
});
- test('should not return early due to children when it is not provided', () => {
+ test('should not return early due to renderCustomPreview when it is not provided', () => {
const propsWithoutCustom = { ...props, useHotkeys: true };
- delete propsWithoutCustom.children;
+ delete propsWithoutCustom.renderCustomPreview;
const wrapper = getWrapper(propsWithoutCustom);
const instance = wrapper.instance();
- // Spy on getViewer to verify we get past the children check
+ // Spy on getViewer to verify we get past the renderCustomPreview check
const getViewerSpy = jest.spyOn(instance, 'getViewer');
const event = {
@@ -1786,15 +1786,15 @@ describe('elements/content-preview/ContentPreview', () => {
instance.onKeyDown(event);
- // If we got past the children check, getViewer should have been called
- // This proves the early return for children didn't trigger
+ // If we got past the renderCustomPreview check, getViewer should have been called
+ // This proves the early return for renderCustomPreview didn't trigger
expect(getViewerSpy).toHaveBeenCalled();
getViewerSpy.mockRestore();
});
});
describe('render()', () => {
- test('should render custom preview content inside .bcpr-content when children is provided', () => {
+ test('should render custom preview content inside .bcpr-content when renderCustomPreview is provided', () => {
const wrapper = getWrapper(props);
wrapper.setState({ file });
@@ -1809,9 +1809,9 @@ describe('elements/content-preview/ContentPreview', () => {
// Now verify CustomPreviewWrapper is rendered
expect(measureContent.find('CustomPreviewWrapper').exists()).toBe(true);
- // Verify children are passed to the wrapper
+ // Verify renderCustomPreview is passed to the wrapper
const wrapperInstance = measureContent.find('CustomPreviewWrapper');
- expect(wrapperInstance.prop('children')).toEqual(props.children);
+ expect(wrapperInstance.prop('renderCustomPreview')).toEqual(props.renderCustomPreview);
});
test('should pass correct props to custom preview content', () => {
@@ -1832,23 +1832,25 @@ describe('elements/content-preview/ContentPreview', () => {
expect(wrapperInstance.prop('token')).toBe(props.token);
expect(wrapperInstance.prop('apiHost')).toBe(props.apiHost);
expect(wrapperInstance.prop('file')).toBe(file);
- expect(wrapperInstance.prop('children')).toEqual(props.children);
+ expect(wrapperInstance.prop('renderCustomPreview')).toEqual(props.renderCustomPreview);
expect(wrapperInstance.prop('onPreviewError')).toBe(instance.onPreviewError);
expect(wrapperInstance.prop('onPreviewLoad')).toBe(instance.onPreviewLoad);
- // Shallow dive into CustomPreviewWrapper to verify children are cloned with injected props
+ // Shallow dive into CustomPreviewWrapper to verify render function is called with props
const wrapperChildren = wrapperInstance.dive();
const errorBoundary = wrapperChildren.find('ErrorBoundary');
expect(errorBoundary.exists()).toBe(true);
- // The cloned child is inside ErrorBoundary
- const clonedChild = errorBoundary.prop('children');
- expect(clonedChild.props.fileId).toBe(file.id);
- expect(clonedChild.props.token).toBe(props.token);
- expect(clonedChild.props.apiHost).toBe(props.apiHost);
- expect(clonedChild.props.file).toBe(file);
- expect(typeof clonedChild.props.onError).toBe('function');
- expect(typeof clonedChild.props.onLoad).toBe('function');
+ // The rendered content is wrapped in a fragment inside ErrorBoundary
+ const fragment = errorBoundary.prop('children');
+ // The actual custom preview content is inside the fragment
+ const renderedContent = fragment.props.children;
+ expect(renderedContent.props.fileId).toBe(file.id);
+ expect(renderedContent.props.token).toBe(props.token);
+ expect(renderedContent.props.apiHost).toBe(props.apiHost);
+ expect(renderedContent.props.file).toBe(file);
+ expect(typeof renderedContent.props.onError).toBe('function');
+ expect(typeof renderedContent.props.onLoad).toBe('function');
});
test('should not render custom preview content when file is not loaded', () => {
@@ -1868,9 +1870,9 @@ describe('elements/content-preview/ContentPreview', () => {
}
});
- test('should render normal preview when children is not provided', () => {
+ test('should render normal preview when renderCustomPreview is not provided', () => {
const propsWithoutCustom = { ...props };
- delete propsWithoutCustom.children;
+ delete propsWithoutCustom.renderCustomPreview;
const wrapper = getWrapper(propsWithoutCustom);
wrapper.setState({ file });