import { useState, memo } from 'react'; import { CopyButton } from './CopyButton'; interface JsonViewerProps { value: unknown; /** Default-open nesting depth */ defaultOpenDepth?: number; } /** Strings longer than this get an inline expand affordance instead of a * truncated preview-only display. */ const LONG_STRING_THRESHOLD = 200; export function JsonViewer({ value, defaultOpenDepth = 2 }: JsonViewerProps) { return (
); } interface NodeProps { value: unknown; depth: number; defaultOpenDepth: number; keyPath: string; keyLabel?: string | number; isLast?: boolean; } const Node = memo(function Node({ value, depth, defaultOpenDepth, keyPath, keyLabel, isLast, }: NodeProps) { const [open, setOpen] = useState(depth < defaultOpenDepth); if (value === null) return ; if (value === undefined) return ; if (typeof value === 'boolean') return ; if (typeof value === 'number') return ; if (typeof value === 'string') { if (value.length <= LONG_STRING_THRESHOLD) { return ( ); } return (
{open ? (
                {value}
              
) : null}
); } if (Array.isArray(value)) { if (value.length === 0) return ; return (
{open ? (
{value.map((v, i) => ( ))}
) : null}
); } if (typeof value === 'object') { const entries = Object.entries(value as Record); if (entries.length === 0) return ; return (
{open ? (
{entries.map(([k, v], i) => ( ))}
) : null}
); } return ; }); function Leaf({ keyLabel, repr, color, }: { keyLabel?: string | number; repr: string; color: string; isLast?: boolean; }) { return (
{keyLabel !== undefined ? ( <> {keyLabel} : ) : null} {repr}
); }