-
Notifications
You must be signed in to change notification settings - Fork 344
feat(ContentPreview): add customPreviewContent prop for custom content rendering #4452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mergify
merged 17 commits into
box:master
from
ahorowitz123:feature/custom-preview-content
Feb 26, 2026
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
c621921
feat(ContentPreview): add customPreviewContent prop for extensibility
ahorowitz123 52746a3
fix(ContentPreview): address deep review findings for customPreviewCo…
ahorowitz123 6e04e94
fix(ContentPreview): fix test failures for deep review changes
ahorowitz123 62da5d8
fix: resolve Flow and ESLint errors in customPreviewContent
ahorowitz123 489ead2
refactor: remove try-catch around onLoad callback
ahorowitz123 028da57
refactor: extract custom preview logic into CustomPreviewWrapper comp…
ahorowitz123 c498ce7
fix: align customPreviewContent onError signature with implementation
ahorowitz123 73dfd7a
fix: remove redundant runtime validation that rejects memoized compon…
ahorowitz123 be18567
refactor: change customPreviewContent from prop to children pattern
ahorowitz123 9b0dd3e
refactor: remove validation and export ContentPreviewChildProps type
ahorowitz123 5e3d889
fix: handle children prop transitions and simplify asset loading
ahorowitz123 b16e9b9
test: enhance assertions to verify CustomPreviewWrapper internals
ahorowitz123 fdc0cd9
chore: remove accidentally committed temp files
ahorowitz123 ccf4117
refactor: restore original endLoadingSession order
ahorowitz123 11f44ab
refactor: remove children prop transition handling
ahorowitz123 84f2a6c
Merge branch 'master' into feature/custom-preview-content
mergify[bot] 8eb4a3b
Merge branch 'master' into feature/custom-preview-content
mergify[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| // @flow | ||
| import * as React from 'react'; | ||
| import ErrorBoundary from '../common/error-boundary'; | ||
| import { ORIGIN_CONTENT_PREVIEW } from '../../constants'; | ||
| import type { Token, BoxItem } from '../../common/types/core'; | ||
| import type { ErrorType } from '../common/flowTypes'; | ||
| import type { ElementsXhrError } from '../../common/types/api'; | ||
| import type { LoggerProps } from '../../common/types/logging'; | ||
|
|
||
| type CustomPreviewOnError = (error: Error | ErrorType | ElementsXhrError) => void; | ||
| type CustomPreviewOnLoad = (data: Object) => void; | ||
|
|
||
| /** | ||
| * Props that are automatically injected into ContentPreview children. | ||
| * Import this type to ensure your custom preview component accepts the required props. | ||
| * | ||
| * @example | ||
| * import type { ContentPreviewChildProps } from 'box-ui-elements'; | ||
| * | ||
| * const MyCustomPreview = ({ fileId, token, apiHost, file, onError, onLoad }: ContentPreviewChildProps) => { | ||
| * // Your implementation | ||
| * }; | ||
| */ | ||
| export type ContentPreviewChildProps = { | ||
| fileId: string, | ||
| token: Token, | ||
| apiHost: string, | ||
| file: BoxItem, | ||
| onError: CustomPreviewOnError, | ||
| onLoad: CustomPreviewOnLoad, | ||
| }; | ||
|
|
||
| type Props = { | ||
| children: React.Node, | ||
| apiHost: string, | ||
| file: BoxItem, | ||
| fileId: string, | ||
| logger?: LoggerProps, | ||
| onPreviewError: (errorData: { error: ErrorType }) => void, | ||
| onPreviewLoad: CustomPreviewOnLoad, | ||
| token: Token, | ||
| }; | ||
|
|
||
| /** | ||
| * 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. | ||
| */ | ||
| function CustomPreviewWrapper({ | ||
| children, | ||
| apiHost, | ||
| file, | ||
| fileId, | ||
| logger, | ||
| onPreviewError, | ||
| onPreviewLoad, | ||
| token, | ||
| }: Props): React.Node { | ||
| // Create wrapper for onError to transform to PreviewLibraryError signature | ||
| const handleCustomError: CustomPreviewOnError = (customError: ErrorType | ElementsXhrError) => { | ||
| // Extract error code | ||
| const errorCodeValue = | ||
| customError && typeof customError === 'object' && 'code' in customError | ||
| ? customError.code | ||
| : 'error_custom_preview'; | ||
|
|
||
| // Extract error message | ||
| let errorMessageValue: string; | ||
| if (customError instanceof Error) { | ||
| errorMessageValue = customError.message; | ||
| } else if (customError && typeof customError === 'object' && 'message' in customError) { | ||
| errorMessageValue = customError.message || 'Unknown error'; | ||
| } else { | ||
| errorMessageValue = String(customError); | ||
| } | ||
|
|
||
| const errorObj: ErrorType = { | ||
| code: errorCodeValue, | ||
| message: errorMessageValue, | ||
| }; | ||
| onPreviewError({ error: errorObj }); | ||
| }; | ||
|
|
||
| // Error boundary handler for render errors | ||
| const handleRenderError = (elementsError: { code: string, message: string }) => { | ||
| const logError = logger?.logError; | ||
| if (logError) { | ||
| logError(new Error(elementsError.message), 'CUSTOM_PREVIEW_RENDER_ERROR', { | ||
| fileId, | ||
| fileName: file.name, | ||
| errorCode: elementsError.code, | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| // Clone child element and inject props | ||
| const childWithProps = React.cloneElement((children: any), { | ||
| fileId, | ||
| token, | ||
| apiHost, | ||
| file, | ||
| onError: handleCustomError, | ||
| onLoad: onPreviewLoad, | ||
| }); | ||
|
|
||
| return ( | ||
| <ErrorBoundary errorOrigin={ORIGIN_CONTENT_PREVIEW} onError={handleRenderError}> | ||
| {childWithProps} | ||
| </ErrorBoundary> | ||
| ); | ||
| } | ||
|
|
||
| export default CustomPreviewWrapper; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.