import classNames from 'classnames'; import type { ReactNode } from 'react'; import { useMemo, useState } from 'react'; import { Icon } from './Icon'; interface Props { depth?: number; attrValue: any; attrKey?: string | number; attrKeyJsonPath?: string; } export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPath }: Props) => { attrKeyJsonPath = attrKeyJsonPath ?? `${attrKey}`; const [isExpanded, setIsExpanded] = useState(depth === 0); const toggleExpanded = () => setIsExpanded((v) => !v); const { isExpandable, children, label, labelClassName } = useMemo<{ isExpandable: boolean; children: ReactNode; label?: string; labelClassName?: string; }>(() => { const jsonType = Object.prototype.toString.call(attrValue); if (jsonType === '[object Object]') { return { children: isExpanded ? Object.keys(attrValue) .sort((a, b) => a.localeCompare(b)) .flatMap((k) => ( )) : null, isExpandable: true, label: isExpanded ? '{ }' : `{⋯}`, labelClassName: 'text-gray-600', }; } else if (jsonType === '[object Array]') { return { children: isExpanded ? attrValue.flatMap((v: any, i: number) => ( )) : null, isExpandable: true, label: isExpanded ? '[ ]' : `[⋯]`, labelClassName: 'text-gray-600', }; } else { return { children: null, isExpandable: false, label: jsonType === '[object String]' ? `"${attrValue}"` : `${attrValue}`, labelClassName: classNames( jsonType === '[object Boolean]' && 'text-pink-600', jsonType === '[object Number]' && 'text-blue-600', jsonType === '[object String]' && 'text-yellow-600', jsonType === '[object Null]' && 'text-red-600', ), }; } }, [attrValue, attrKeyJsonPath, isExpanded, depth]); const labelEl = ( {label} ); return (
{isExpandable ? ( ) : ( <> {attrKey}: {labelEl} )}
{children &&
{children}
}
); }; function joinObjectKey(baseKey: string | undefined, key: string): string { const quotedKey = key.match(/^[a-z0-9_]+$/i) ? key : `\`${key}\``; if (baseKey == null) return quotedKey; else return `${baseKey}.${quotedKey}`; } function joinArrayKey(baseKey: string | undefined, index: number): string { return `${baseKey ?? ''}[${index}]`; }