Skip to content

Commit b9fd642

Browse files
committed
feat(next): use TreeView
1 parent 6335512 commit b9fd642

File tree

4 files changed

+138
-27
lines changed

4 files changed

+138
-27
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"dependencies": {
5151
"@emotion/react": "^11.10.4",
5252
"@emotion/styled": "^11.10.4",
53+
"@mui/icons-material": "^5.10.3",
54+
"@mui/lab": "^5.0.0-alpha.99",
5355
"@mui/material": "^5.10.5",
5456
"copy-to-clipboard": "^3.3.2",
5557
"events": "^3.3.0",

src/next.tsx

+80-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { Box, createTheme, Stack, ThemeProvider } from '@mui/material'
1+
import ChevronRightIcon from '@mui/icons-material/ChevronRight'
2+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
3+
import { TreeItem, TreeView } from '@mui/lab'
4+
import { Box, createTheme, ThemeProvider } from '@mui/material'
25
import type React from 'react'
3-
import { useDebugValue, useEffect, useMemo } from 'react'
6+
import { useCallback, useDebugValue, useEffect, useMemo } from 'react'
47

58
import {
69
createJsonViewerStore,
@@ -9,6 +12,8 @@ import {
912
import type { ReactJsonViewProps } from './type'
1013

1114
export type DataProps<Data = unknown> = {
15+
father: string
16+
isRoot: boolean
1217
value: Data
1318
currentIndent: number
1419
}
@@ -24,40 +29,88 @@ function getType (value: unknown) {
2429
return 'date'
2530
} else if (value === null) {
2631
return 'null'
32+
} else if (Array.isArray(value)) {
33+
return 'array'
2734
}
2835
}
2936
return type
3037
}
3138

3239
const ObjectJson: React.FC<DataProps> = ({
3340
value,
34-
currentIndent
41+
currentIndent,
42+
isRoot,
43+
father
3544
}) => {
3645
const type = useMemo(() => getType(value), [value])
3746
useDebugValue(type, type => `value type: ${type}`)
3847
const indentWidth = useJsonViewerStore(store => store.indentWidth)
48+
const expanded = useJsonViewerStore(store => store.expanded)
49+
const setExpanded = useJsonViewerStore(store => store.setExpanded)
50+
const handleToggle = useCallback(
51+
(event: React.SyntheticEvent, nodeIds: string[]) => {
52+
setExpanded(nodeIds)
53+
}, [setExpanded])
3954
const elements = useMemo(() => {
4055
if (type === 'object') {
41-
return Object.entries(value as object).map(([key, value]) => (
42-
<Box
43-
key={key}
44-
sx={{
45-
pl: currentIndent
46-
}}
47-
>
48-
<Stack direction='row' spacing={1}>
49-
<Box>{key}</Box>
50-
<Box component='div'>
51-
<ObjectJson value={value}
52-
currentIndent={currentIndent + indentWidth}/>
53-
</Box>
54-
</Stack>
55-
</Box>
56-
))
56+
if (isRoot) {
57+
return (
58+
<TreeView
59+
defaultCollapseIcon={<ExpandMoreIcon/>}
60+
defaultExpandIcon={<ChevronRightIcon/>}
61+
expanded={expanded}
62+
onNodeToggle={handleToggle}
63+
>
64+
<TreeItem nodeId='data-viewer-root' label='root'>
65+
{
66+
Object.entries(value as object).map(([key, value]) => {
67+
const path = `${father}${father ? '.' : ''}${key}`
68+
const isExpend = expanded.includes(path)
69+
return (
70+
<TreeItem
71+
nodeId={path}
72+
key={key}
73+
label={isExpend ? path : `${key} : ${value}`}
74+
>
75+
<ObjectJson
76+
father={key}
77+
value={value}
78+
currentIndent={currentIndent + indentWidth}
79+
isRoot={false}
80+
/>
81+
</TreeItem>
82+
)
83+
})
84+
}
85+
</TreeItem>
86+
</TreeView>
87+
)
88+
} else {
89+
return (
90+
Object.entries(value as object).map(([key, value]) => {
91+
const path = `${father}${father ? '.' : ''}${key}`
92+
return (
93+
<TreeItem
94+
nodeId={path}
95+
key={key}
96+
label={`${value}`}
97+
>
98+
<ObjectJson
99+
father={key}
100+
value={value}
101+
currentIndent={currentIndent + indentWidth}
102+
isRoot={false}
103+
/>
104+
</TreeItem>
105+
)
106+
})
107+
)
108+
}
57109
} else {
58-
return `${value}`
110+
const path = `${father}${father ? '.' : ''}${value}`
111+
return <TreeItem nodeId={path} label={`${value}`}/>
59112
}
60-
}, [currentIndent, indentWidth, type, value])
113+
}, [currentIndent, expanded, father, handleToggle, indentWidth, isRoot, type, value])
61114
return <>{elements}</>
62115
}
63116

@@ -73,7 +126,12 @@ const JsonViewerInner: React.FC<ReactJsonViewProps> = (props) => {
73126
// todo: still working on it
74127
return (
75128
<Box>
76-
<ObjectJson value={props.src} currentIndent={0}/>
129+
<ObjectJson
130+
value={props.src}
131+
currentIndent={0}
132+
isRoot
133+
father=''
134+
/>
77135
</Box>
78136
)
79137
}

src/stores/JsonViewerStore.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ export const DEFAULT_INDENT_WIDTH = 4
66

77
// todo
88
export const createJsonViewerStore = () => create(combine({
9-
src: {},
10-
indentWidth: DEFAULT_INDENT_WIDTH
11-
}, () => ({
12-
get: () => {},
13-
set: () => {}
9+
expanded: [] as string[],
10+
src: {} as any,
11+
indentWidth: DEFAULT_INDENT_WIDTH as number
12+
}, (set) => ({
13+
setExpanded: (expanded: string[]) => {
14+
set({
15+
expanded
16+
})
17+
}
1418
})))
1519
export type JsonViewerStore = ReturnType<typeof createJsonViewerStore>
1620

yarn.lock

+47
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,51 @@ __metadata:
11171117
languageName: node
11181118
linkType: hard
11191119

1120+
"@mui/icons-material@npm:^5.10.3":
1121+
version: 5.10.3
1122+
resolution: "@mui/icons-material@npm:5.10.3"
1123+
dependencies:
1124+
"@babel/runtime": ^7.18.9
1125+
peerDependencies:
1126+
"@mui/material": ^5.0.0
1127+
"@types/react": ^17.0.0 || ^18.0.0
1128+
react: ^17.0.0 || ^18.0.0
1129+
peerDependenciesMeta:
1130+
"@types/react":
1131+
optional: true
1132+
checksum: 9c32f3e9fc2be61b6518418818ead346469fb4650852307291fe23e16909fc1c2f4bc3b09a524fb0e90920aa1a26a6a41e91815e0da1d15d7e26ccad4f6915fa
1133+
languageName: node
1134+
linkType: hard
1135+
1136+
"@mui/lab@npm:^5.0.0-alpha.99":
1137+
version: 5.0.0-alpha.99
1138+
resolution: "@mui/lab@npm:5.0.0-alpha.99"
1139+
dependencies:
1140+
"@babel/runtime": ^7.18.9
1141+
"@mui/base": 5.0.0-alpha.97
1142+
"@mui/system": ^5.10.5
1143+
"@mui/utils": ^5.10.3
1144+
clsx: ^1.2.1
1145+
prop-types: ^15.8.1
1146+
react-is: ^18.2.0
1147+
peerDependencies:
1148+
"@emotion/react": ^11.5.0
1149+
"@emotion/styled": ^11.3.0
1150+
"@mui/material": ^5.0.0
1151+
"@types/react": ^17.0.0 || ^18.0.0
1152+
react: ^17.0.0 || ^18.0.0
1153+
react-dom: ^17.0.0 || ^18.0.0
1154+
peerDependenciesMeta:
1155+
"@emotion/react":
1156+
optional: true
1157+
"@emotion/styled":
1158+
optional: true
1159+
"@types/react":
1160+
optional: true
1161+
checksum: db54edffbd70bb8956605e67a28cc240edac422800e955f82f6603f53631697440780a83f3945307dd9adcd57823e48838ba73248771ae1095d3009af28c8843
1162+
languageName: node
1163+
linkType: hard
1164+
11201165
"@mui/material@npm:^5.10.5":
11211166
version: 5.10.5
11221167
resolution: "@mui/material@npm:5.10.5"
@@ -1595,6 +1640,8 @@ __metadata:
15951640
"@commitlint/config-angular": ^17.1.0
15961641
"@emotion/react": ^11.10.4
15971642
"@emotion/styled": ^11.10.4
1643+
"@mui/icons-material": ^5.10.3
1644+
"@mui/lab": ^5.0.0-alpha.99
15981645
"@mui/material": ^5.10.5
15991646
"@textea/dev-kit": ^0.12.16
16001647
"@types/events": ^3.0.0

0 commit comments

Comments
 (0)