1/**
2 * Copyright (c) 650 Industries.
3 * Copyright (c) Meta Platforms, Inc. and affiliates.
4 *
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8import React, { useCallback, useEffect, useState } from 'react';
9import { Keyboard, ScrollView, View, StyleSheet } from 'react-native';
10import * as LogBoxData from './Data/LogBoxData';
11import { useLogs, useSelectedLog } from './Data/LogContext';
12import * as LogBoxStyle from './UI/LogBoxStyle';
13import { LogBoxInspectorCodeFrame } from './overlay/LogBoxInspectorCodeFrame';
14import { LogBoxInspectorFooter as ErrorOverlayFooter } from './overlay/LogBoxInspectorFooter';
15import { LogBoxInspectorHeader as ErrorOverlayHeader } from './overlay/LogBoxInspectorHeader';
16import { LogBoxInspectorMessageHeader } from './overlay/LogBoxInspectorMessageHeader';
17import { LogBoxInspectorStackFrames } from './overlay/LogBoxInspectorStackFrames';
18const HEADER_TITLE_MAP = {
19    warn: 'Console Warning',
20    error: 'Console Error',
21    fatal: 'Uncaught Error',
22    syntax: 'Syntax Error',
23    static: 'Static Rendering Error (Node.js)',
24    component: 'Render Error',
25};
26export function LogBoxInspectorContainer() {
27    const { selectedLogIndex, logs } = useLogs();
28    const log = logs[selectedLogIndex];
29    if (log == null) {
30        return null;
31    }
32    return React.createElement(LogBoxInspector, { log: log, selectedLogIndex: selectedLogIndex, logs: logs });
33}
34export function LogBoxInspector({ log, selectedLogIndex, logs, }) {
35    const onDismiss = useCallback(() => {
36        // Here we handle the cases when the log is dismissed and it
37        // was either the last log, or when the current index
38        // is now outside the bounds of the log array.
39        const logsArray = Array.from(logs);
40        if (selectedLogIndex != null) {
41            if (logsArray.length - 1 <= 0) {
42                LogBoxData.setSelectedLog(-1);
43            }
44            else if (selectedLogIndex >= logsArray.length - 1) {
45                LogBoxData.setSelectedLog(selectedLogIndex - 1);
46            }
47            LogBoxData.dismiss(logsArray[selectedLogIndex]);
48        }
49    }, [selectedLogIndex]);
50    const onMinimize = useCallback(() => {
51        LogBoxData.setSelectedLog(-1);
52    }, []);
53    const onChangeSelectedIndex = useCallback((index) => {
54        LogBoxData.setSelectedLog(index);
55    }, []);
56    useEffect(() => {
57        if (log) {
58            LogBoxData.symbolicateLogNow('stack', log);
59            LogBoxData.symbolicateLogNow('component', log);
60        }
61    }, [log]);
62    useEffect(() => {
63        // Optimistically symbolicate the last and next logs.
64        if (logs.length > 1) {
65            const selected = selectedLogIndex;
66            const lastIndex = logs.length - 1;
67            const prevIndex = selected - 1 < 0 ? lastIndex : selected - 1;
68            const nextIndex = selected + 1 > lastIndex ? 0 : selected + 1;
69            for (const type of ['component', 'stack']) {
70                LogBoxData.symbolicateLogLazy(type, logs[prevIndex]);
71                LogBoxData.symbolicateLogLazy(type, logs[nextIndex]);
72            }
73        }
74    }, [logs, selectedLogIndex]);
75    useEffect(() => {
76        Keyboard.dismiss();
77    }, []);
78    const _handleRetry = useCallback((type) => {
79        LogBoxData.retrySymbolicateLogNow(type, log);
80    }, [log]);
81    return (React.createElement(View, { style: styles.container },
82        React.createElement(ErrorOverlayHeader, { onSelectIndex: onChangeSelectedIndex, level: log.level }),
83        React.createElement(ErrorOverlayBody, { onRetry: _handleRetry }),
84        React.createElement(ErrorOverlayFooter, { onDismiss: onDismiss, onMinimize: onMinimize })));
85}
86export function ErrorOverlayBody({ onRetry }) {
87    const log = useSelectedLog();
88    return React.createElement(ErrorOverlayBodyContents, { log: log, onRetry: onRetry });
89}
90export function ErrorOverlayBodyContents({ log, onRetry, }) {
91    const [collapsed, setCollapsed] = useState(true);
92    useEffect(() => {
93        setCollapsed(true);
94    }, [log]);
95    const headerTitle = HEADER_TITLE_MAP[log.isComponentError ? 'component' : log.level] ?? log.type;
96    const header = (React.createElement(LogBoxInspectorMessageHeader, { collapsed: collapsed, onPress: () => setCollapsed(!collapsed), message: log.message, level: log.level, title: headerTitle }));
97    return (React.createElement(React.Fragment, null,
98        collapsed && header,
99        React.createElement(ScrollView, { style: styles.scrollBody },
100            !collapsed && header,
101            React.createElement(LogBoxInspectorCodeFrame, { codeFrame: log.codeFrame }),
102            React.createElement(LogBoxInspectorStackFrames, { type: "stack",
103                // eslint-disable-next-line react/jsx-no-bind
104                onRetry: onRetry.bind(onRetry, 'stack') }),
105            !!log?.componentStack?.length && (React.createElement(LogBoxInspectorStackFrames, { type: "component",
106                // eslint-disable-next-line react/jsx-no-bind
107                onRetry: onRetry.bind(onRetry, 'component') })))));
108}
109const styles = StyleSheet.create({
110    scrollBody: {
111        backgroundColor: LogBoxStyle.getBackgroundColor(1),
112        flex: 1,
113    },
114    container: {
115        top: 0,
116        left: 0,
117        bottom: 0,
118        right: 0,
119        zIndex: 999,
120        flex: 1,
121        // @ts-expect-error: fixed is not in the RN types but it works on web
122        position: 'fixed',
123    },
124});
125export default LogBoxData.withSubscription(LogBoxInspectorContainer);
126//# sourceMappingURL=ErrorOverlay.js.map