import { useState } from "react"; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, TextInput, ViewStyle, } from "react-native"; import { Search, Edit3, Check, X } from "../../icons"; import { gameUIColors } from "../gameUI"; import { CopyButton } from "./CopyButton"; interface DataInspectorProps { data: any; mode?: "view" | "edit" | "diff"; syntax?: "json" | "xml" | "text"; theme?: "dark" | "light"; collapsible?: boolean; searchable?: boolean; onEdit?: (newData: any) => void; style?: ViewStyle; title?: string; } export function DataInspector({ data, mode = "view", syntax = "json", theme = "dark", collapsible = true, searchable = true, onEdit, style, title, }: DataInspectorProps) { const [searchQuery, setSearchQuery] = useState(""); const [isEditing, setIsEditing] = useState(false); const [editedData, setEditedData] = useState(""); const formatData = () => { if (syntax === "json") { try { return JSON.stringify(data, null, 2); } catch { return String(data); } } return String(data); }; const highlightSearch = (text: string) => { if (!searchQuery) return text; const parts = text.split(new RegExp(`(${searchQuery})`, "gi")); return parts.map((part, index) => { if (part.toLowerCase() === searchQuery.toLowerCase()) { return ( {part} ); } return part; }); }; const handleEdit = () => { if (!isEditing) { setEditedData(formatData()); setIsEditing(true); } else { try { const newData = syntax === "json" ? JSON.parse(editedData) : editedData; onEdit?.(newData); setIsEditing(false); } catch (error) { console.error("Failed to parse edited data", error); } } }; const cancelEdit = () => { setIsEditing(false); setEditedData(""); }; const formattedData = formatData(); return ( {(title || searchable || mode === "edit") && ( {title && {title}} {searchable && !isEditing && ( )} {mode === "edit" && ( handleEdit()} > {isEditing ? ( ) : ( )} )} {isEditing && ( )} {!isEditing && } )} {isEditing ? ( ) : ( {searchQuery ? (highlightSearch(formattedData) as any) : formattedData} )} ); } interface JsonViewerProps { data: any; searchable?: boolean; style?: ViewStyle; } DataInspector.Json = function JsonViewer({ data, searchable, style, }: JsonViewerProps) { return ( ); }; interface EditableProps { data: any; onSave: (newData: any) => void; style?: ViewStyle; } DataInspector.Editable = function Editable({ data, onSave, style, }: EditableProps) { return ( ); }; interface DiffViewProps { oldData: any; newData: any; style?: ViewStyle; } DataInspector.Diff = function DiffView({ oldData, newData, style, }: DiffViewProps) { const [showMode, setShowMode] = useState<"old" | "new" | "diff">("diff"); return ( setShowMode("old")} > Old setShowMode("new")} > New setShowMode("diff")} > Diff {showMode === "old" && ( )} {showMode === "new" && ( )} {showMode === "diff" && ( Old New )} ); }; const styles = StyleSheet.create({ container: { backgroundColor: gameUIColors.background, borderRadius: 8, overflow: "hidden", }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", padding: 8, borderBottomWidth: 1, borderBottomColor: gameUIColors.border + "20", }, title: { fontSize: 12, fontWeight: "600", color: gameUIColors.text, }, controls: { flexDirection: "row", gap: 8, }, searchContainer: { flexDirection: "row", alignItems: "center", backgroundColor: gameUIColors.panel, borderRadius: 4, paddingHorizontal: 8, gap: 4, }, searchInput: { fontSize: 11, color: gameUIColors.text, minWidth: 100, paddingVertical: 4, }, editButton: { padding: 4, borderRadius: 4, backgroundColor: gameUIColors.primary + "20", }, cancelButton: { padding: 4, borderRadius: 4, backgroundColor: gameUIColors.error + "20", }, scrollView: { maxHeight: 300, }, codeText: { fontFamily: "monospace", fontSize: 11, color: gameUIColors.text, padding: 12, lineHeight: 16, }, editor: { fontFamily: "monospace", fontSize: 11, color: gameUIColors.text, padding: 12, lineHeight: 16, minHeight: 200, }, highlight: { backgroundColor: gameUIColors.warning + "40", color: gameUIColors.text, }, diffControls: { flexDirection: "row", gap: 8, padding: 8, }, diffButton: { paddingHorizontal: 12, paddingVertical: 4, borderRadius: 4, backgroundColor: gameUIColors.panel, }, diffButtonActive: { backgroundColor: gameUIColors.primary, }, diffButtonText: { fontSize: 11, color: gameUIColors.text, fontWeight: "500", }, diffContainer: { flexDirection: "row", gap: 8, }, diffPane: { flex: 1, }, diffPaneTitle: { fontSize: 10, fontWeight: "600", color: gameUIColors.secondary, padding: 8, textTransform: "uppercase", }, });