"""A React Error Boundary component that catches unhandled frontend exceptions.""" from __future__ import annotations from typing import Dict, Tuple from reflex.components.component import Component from reflex.components.datadisplay.logo import svg_logo from reflex.components.el import a, button, details, div, h2, hr, p, pre, summary from reflex.event import EventHandler, set_clipboard from reflex.state import FrontendEventExceptionState from reflex.vars.base import Var from reflex.vars.function import ArgsFunctionOperation from reflex.vars.object import ObjectVar def on_error_spec( error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]] ) -> Tuple[Var[str], Var[str]]: """The spec for the on_error event handler. Args: error: The error message. info: Additional information about the error. Returns: The arguments for the event handler. """ return ( error.stack, info.componentStack, ) class ErrorBoundary(Component): """A React Error Boundary component that catches unhandled frontend exceptions.""" library = "react-error-boundary" tag = "ErrorBoundary" # Fired when the boundary catches an error. on_error: EventHandler[on_error_spec] # Rendered instead of the children when an error is caught. fallback_render: Var[Component] @classmethod def create(cls, *children, **props): """Create an ErrorBoundary component. Args: *children: The children of the component. **props: The props of the component. Returns: The ErrorBoundary component. """ if "on_error" not in props: props["on_error"] = FrontendEventExceptionState.handle_frontend_exception if "fallback_render" not in props: props["fallback_render"] = ArgsFunctionOperation.create( ("event_args",), Var.create( div( div( div( h2( "An error occurred while rendering this page.", font_size="1.25rem", font_weight="bold", ), p( "This is an error with the application itself.", opacity="0.75", ), details( summary("Error message", padding="0.5rem"), div( div( pre( Var( _js_expr="event_args.error.stack", ), ), padding="0.5rem", width="fit-content", ), width="100%", max_height="50vh", overflow="auto", background="#000", color="#fff", border_radius="0.25rem", ), button( "Copy", on_click=set_clipboard( Var(_js_expr="event_args.error.stack"), ), padding="0.35rem 0.75rem", margin="0.5rem", background="#fff", color="#000", border="1px solid #000", border_radius="0.25rem", font_weight="bold", ), ), display="flex", flex_direction="column", gap="1rem", max_width="50ch", border="1px solid #888888", border_radius="0.25rem", padding="1rem", ), hr( border_color="currentColor", opacity="0.25", ), a( div( "Built with ", svg_logo("currentColor"), display="flex", align_items="baseline", justify_content="center", font_family="monospace", gap="0.5rem", ), href="https://reflex.dev", ), display="flex", flex_direction="column", gap="1rem", ), height="100%", width="100%", position="absolute", display="flex", align_items="center", justify_content="center", ) ), _var_type=Component, ) else: props["fallback_render"] = ArgsFunctionOperation.create( ("event_args",), props["fallback_render"], _var_type=Component, ) return super().create(*children, **props) error_boundary = ErrorBoundary.create