Add error boundary around object viewers
Wrap the resolved viewer in an error boundary so a render failure (e.g. WebGL context loss or a model/texture load error) is contained to the inspector pane instead of crashing the page. The fallback shows the error message and stack trace.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { Component, type ErrorInfo, type ReactNode } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
/** Optional fallback rendered in place of `children` when an error is caught. */
|
||||
fallback?: (error: Error) => ReactNode;
|
||||
}
|
||||
|
||||
interface State {
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Catches render errors in its subtree and renders a fallback instead of
|
||||
* letting them crash the whole page. Used to isolate failures in object
|
||||
* viewers (e.g. WebGL context loss, model/texture load errors).
|
||||
*/
|
||||
export default class ErrorBoundary extends Component<Props, State> {
|
||||
override state: State = { error: null };
|
||||
|
||||
static getDerivedStateFromError(error: Error): State {
|
||||
return { error };
|
||||
}
|
||||
|
||||
override componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
// Surface the error for debugging without breaking the UI.
|
||||
console.error('Viewer error:', error, info.componentStack);
|
||||
}
|
||||
|
||||
override render() {
|
||||
if (this.state.error) {
|
||||
return this.props.fallback
|
||||
? this.props.fallback(this.state.error)
|
||||
: <DefaultFallback error={this.state.error} />;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
function DefaultFallback({ error }: { error: Error }) {
|
||||
return (
|
||||
<div className="flex h-80 flex-col items-center justify-center gap-2 overflow-auto rounded-lg border border-zinc-800 bg-zinc-900 p-4 text-center">
|
||||
<p className="text-sm font-medium text-zinc-200">Couldn't render this object</p>
|
||||
<p className="max-w-sm wrap-break-word font-mono text-xs text-zinc-400">
|
||||
{error.message}
|
||||
</p>
|
||||
{error.stack && (
|
||||
<pre className="mt-2 max-h-40 w-full overflow-auto whitespace-pre-wrap text-left font-mono text-[10px] leading-relaxed text-zinc-600">
|
||||
{error.stack}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user