import React, { useState, useRef, useEffect } from 'react';
|
import { Box, Typography, Paper, useTheme } from '@mui/material';
|
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import jsonLang from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
|
import { xcode, atomOneDark, a11yLight } from 'react-syntax-highlighter/dist/esm/styles/hljs';
|
|
// https://react-syntax-highlighter.github.io/react-syntax-highlighter/demo/
|
|
const parseJson = (jsonStr) => {
|
let json = '';
|
try {
|
const jsonObj = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr;
|
json = JSON.stringify(jsonObj, null, 2);
|
} catch (error) {
|
json = 'Invalid JSON';
|
}
|
return json;
|
}
|
|
SyntaxHighlighter.registerLanguage('json', jsonLang);
|
|
const JsonShow = ({ data, height = 500 }) => {
|
const theme = useTheme();
|
const themeMode = theme.palette.mode;
|
|
const [json, setJson] = useState(null);
|
|
useEffect(() => {
|
if (data) {
|
setJson(parseJson(data));
|
}
|
}, [data]);
|
|
return (
|
<Paper
|
elevation={3}
|
sx={{
|
padding: 2,
|
maxHeight: height,
|
overflow: 'auto',
|
backgroundColor: theme.palette.background.paper,
|
borderRadius: 2,
|
}}
|
>
|
<pre style={{ margin: 0, fontFamily: 'monospace', whiteSpace: 'pre-wrap' }}>
|
{json === 'Invalid JSON' ? (
|
<Typography color="error">Invalid JSON</Typography>
|
) : (
|
|
<SyntaxHighlighter
|
language="json"
|
style={themeMode === 'dark' ? atomOneDark : xcode}
|
customStyle={{
|
backgroundColor: 'transparent',
|
padding: 0,
|
fontSize: '0.875rem', // 14px
|
fontFamily: 'monospace',
|
whiteSpace: 'pre-wrap',
|
wordBreak: 'break-word',
|
// fontWeight: 'bold',
|
}}
|
showLineNumbers
|
>
|
{json}
|
</SyntaxHighlighter>
|
// renderFormattedJson(json)
|
)}
|
</pre>
|
</Paper>
|
);
|
}
|
|
const renderFormattedJson = (json) => {
|
const regex = /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(\.\d*)?([eE][+\-]?\d+)?) /g;
|
const parts = json.split(regex);
|
|
return parts.map((part, index) => {
|
if (!part) return null;
|
let style = {};
|
|
if (/^"/.test(part)) {
|
if (/:$/.test(part)) {
|
style = { color: '#b22222' }; // key
|
} else {
|
style = { color: '#1e90ff' }; // string
|
}
|
} else if (/true|false/.test(part)) {
|
style = { color: '#228B22' }; // boolean
|
} else if (/null/.test(part)) {
|
style = { color: '#808080' }; // null
|
} else if (/^-?\d+/.test(part)) {
|
style = { color: '#FF8C00' }; // number
|
}
|
|
return (
|
<span key={index} style={style}>
|
{part}
|
</span>
|
);
|
});
|
|
};
|
|
|
export default JsonShow;
|