import { Component, type ErrorInfo, type ReactNode } from 'react'; interface Props { children: ReactNode; } interface State { error: Error | null; } /** * App-level error boundary. A render-time throw used to blank the entire window * — no boundary existed (issue #382), so any thrown error during render took the * whole UI down. This catches it and shows a recoverable fallback while playback * (driven by the Rust audio engine, outside React) keeps going. * * Deliberately hook-free and English-only: the fallback has to render even when * i18n, the theme, or app state is exactly what broke, so it must not depend on * any of them. The CSS uses literal fallbacks in `var(...)` for the same reason. */ export default class ErrorBoundary extends Component { state: State = { error: null }; static getDerivedStateFromError(error: Error): State { return { error }; } componentDidCatch(error: Error, info: ErrorInfo): void { console.error('[error-boundary]', error, info.componentStack); } private handleRetry = (): void => this.setState({ error: null }); private handleReload = (): void => window.location.reload(); render(): ReactNode { const { error } = this.state; if (!error) return this.props.children; return (

Something went wrong

This view hit an unexpected error and stopped rendering. Playback keeps going — try the view again, or reload the app.

{error.message}
); } }