import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, ScrollView, TouchableOpacity, StyleSheet } from 'react-native'; import type { PluginComponentProps, DebuggerPlugin } from '../../core/types'; import { navigationStore } from './navigationStore'; import { safeStringify, copyToClipboard, formatTimestamp } from '../../core/utils'; const NavigationInspectorPanel: React.FC = ({ theme }) => { const [state, setState] = useState | null>(null); const [currentRoute, setCurrentRoute] = useState<{ name: string; params?: Record; } | null>(null); const [history, setHistory] = useState< { name: string; params?: Record; timestamp: number }[] >([]); const [, forceUpdate] = useState(0); const refresh = useCallback(() => { setState(navigationStore.getState() as Record | null); setCurrentRoute(navigationStore.getCurrentRoute()); setHistory(navigationStore.getHistory()); forceUpdate((n) => n + 1); }, []); useEffect(() => { const unsub = navigationStore.subscribe(refresh); refresh(); const interval = setInterval(refresh, 2000); return () => { unsub(); clearInterval(interval); }; }, [refresh]); const hasRef = !!navigationStore.getRef(); if (!hasRef) { return ( 🧭 No Navigation Ref Pass your navigation ref:{'\n\n'} {'setNavigationRef(navigationRef)'} ); } return ( {/* Current Route */} {currentRoute && ( CURRENT ROUTE {currentRoute.name} {currentRoute.params && Object.keys(currentRoute.params).length > 0 && ( copyToClipboard(safeStringify(currentRoute.params))} activeOpacity={0.7} > Params {safeStringify(currentRoute.params)} )} )} {/* Navigation State */} {state && ( STATE TREE copyToClipboard(safeStringify(state))} activeOpacity={0.7} > Copy {String(safeStringify(state))} )} {/* History */} {history.length > 0 && ( ROUTE HISTORY {history.map((entry, i) => ( {entry.name} {formatTimestamp(entry.timestamp)} ))} )} ); }; const styles = StyleSheet.create({ container: { flex: 1 }, emptyContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32, }, emptyIcon: { fontSize: 48, marginBottom: 16 }, emptyTitle: { fontSize: 16, fontWeight: '700', marginBottom: 8 }, emptyDesc: { fontSize: 13, textAlign: 'center', lineHeight: 20 }, section: { margin: 12, borderRadius: 12, padding: 12 }, sectionTitle: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 1, marginBottom: 8, }, sectionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8, }, copyBtn: { fontSize: 12, fontWeight: '600' }, routeCard: { padding: 12, borderRadius: 8, alignItems: 'center' }, routeName: { fontSize: 18, fontWeight: '800', color: '#FFF' }, paramsBlock: { padding: 12, borderRadius: 8, marginTop: 8 }, paramsTitle: { fontSize: 10, fontWeight: '700', marginBottom: 4, textTransform: 'uppercase' }, paramsText: { fontSize: 11, fontFamily: 'monospace', lineHeight: 16 }, codeBlock: { padding: 12, borderRadius: 8 }, codeText: { fontSize: 11, fontFamily: 'monospace', lineHeight: 16 }, historyRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 8, borderBottomWidth: StyleSheet.hairlineWidth, }, historyInfo: { flex: 1, flexDirection: 'row', justifyContent: 'space-between' }, historyRoute: { fontSize: 13, fontWeight: '600' }, historyTime: { fontSize: 10 }, }); export function createNavigationInspectorPlugin(): DebuggerPlugin { return { id: 'navigation-inspector', name: 'Nav', icon: '🧭', component: NavigationInspectorPanel, order: 90, }; }