Last active
August 9, 2024 17:45
-
-
Save chepetime/752cf94209fa487c02ec794b4f5d07cd to your computer and use it in GitHub Desktop.
TS + React + Tailwind Component for debugging objects in the browser, with toggles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* eslint-disable @typescript-eslint/no-explicit-any */ | |
| "use client"; | |
| import React, { useState } from "react"; | |
| interface JsonDebuggerProps { | |
| data: any; | |
| } | |
| export const JsonDebugger: React.FC<JsonDebuggerProps> = ({ data }) => { | |
| const [expanded, setExpanded] = useState<{ [key: string]: boolean }>({}); | |
| const expandAll = (obj: any, path: string[] = []) => { | |
| if (typeof obj === "object" && obj !== null) { | |
| const newExpanded: { [key: string]: boolean } = {}; | |
| const traverse = (obj: any, path: string[]) => { | |
| Object.keys(obj).forEach((key) => { | |
| const currentPath = [...path, key].join("."); | |
| newExpanded[currentPath] = true; | |
| if (typeof obj[key] === "object" && obj[key] !== null) { | |
| traverse(obj[key], [...path, key]); | |
| } | |
| }); | |
| }; | |
| traverse(obj, path); | |
| setExpanded(newExpanded); | |
| } | |
| }; | |
| const collapseAll = (obj: any, path: string[] = []) => { | |
| if (typeof obj === "object" && obj !== null) { | |
| const newCollapsed: { [key: string]: boolean } = {}; | |
| const traverse = (obj: any, path: string[]) => { | |
| Object.keys(obj).forEach((key) => { | |
| const currentPath = [...path, key].join("."); | |
| newCollapsed[currentPath] = false; | |
| if (typeof obj[key] === "object" && obj[key] !== null) { | |
| traverse(obj[key], [...path, key]); | |
| } | |
| }); | |
| }; | |
| traverse(obj, path); | |
| setExpanded(newCollapsed); | |
| } | |
| }; | |
| const toggleExpand = (key: string) => { | |
| setExpanded((prev) => ({ ...prev, [key]: !prev[key] })); | |
| }; | |
| const renderJson = (obj: any, path: string[] = []): JSX.Element | string => { | |
| if (typeof obj !== "object" || obj === null) { | |
| return <span>{JSON.stringify(obj)}</span>; | |
| } | |
| return ( | |
| <div className="ml-4"> | |
| {"{"} | |
| {Object.entries(obj).map(([key, value], index, array) => { | |
| const currentPath = [...path, key].join("."); | |
| const isExpanded = expanded[currentPath]; | |
| return ( | |
| <div key={currentPath}> | |
| <strong | |
| onClick={() => toggleExpand(currentPath)} | |
| className="cursor-pointer bg-gray-800 px-1 text-pink-600 hover:bg-gray-200" | |
| > | |
| {key}: | |
| </strong> | |
| {typeof value === "object" && value !== null ? ( | |
| isExpanded ? ( | |
| <div>{renderJson(value, [...path, key])}</div> | |
| ) : ( | |
| <span | |
| onClick={() => toggleExpand(currentPath)} | |
| className="cursor-pointer text-cyan-500 hover:bg-gray-200" | |
| > | |
| {" "} | |
| {"{...}"} | |
| </span> | |
| ) | |
| ) : ( | |
| <span> {JSON.stringify(value)}</span> | |
| )} | |
| {index < array.length - 1 && ","} | |
| </div> | |
| ); | |
| })} | |
| {"}"} | |
| </div> | |
| ); | |
| }; | |
| return ( | |
| <div className="mx-auto max-w-7xl px-4 py-20"> | |
| <div className="mb-4 flex justify-between"> | |
| <button | |
| onClick={() => expandAll(data)} | |
| className="rounded bg-blue-500 px-4 py-2 text-white" | |
| > | |
| Expand All | |
| </button> | |
| <button | |
| onClick={() => collapseAll(data)} | |
| className="rounded bg-red-500 px-4 py-2 text-white" | |
| > | |
| Collapse All | |
| </button> | |
| </div> | |
| <div className="max-h-[75vh] overflow-auto rounded-lg border bg-gray-900 p-4 text-white shadow-lg"> | |
| <pre className="whitespace-pre-wrap text-sm text-gray-100"> | |
| {renderJson(data)} | |
| </pre> | |
| </div> | |
| </div> | |
| ); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment