diff --git a/examples/basic/pages/index.tsx b/examples/basic/pages/index.tsx
index 4548c884..8336e0b6 100644
--- a/examples/basic/pages/index.tsx
+++ b/examples/basic/pages/index.tsx
@@ -35,9 +35,12 @@ const loopArray = [
loopArray[1] = loopArray
+const longArray = Array.from({ length: 1000 }).map((_, i) => i)
+
const example = {
loopObject,
loopArray,
+ longArray,
string: 'this is a string',
integer: 42,
array: [19, 19, 810, 'test', NaN],
diff --git a/src/components/DataKeyPair.tsx b/src/components/DataKeyPair.tsx
index bad294d0..244be6d7 100644
--- a/src/components/DataKeyPair.tsx
+++ b/src/components/DataKeyPair.tsx
@@ -18,27 +18,29 @@ import { DataBox } from './mui/DataBox'
export type DataKeyPairProps = {
value: unknown
- nested?: boolean
+ nestedIndex?: number
path: (string | number)[]
}
-const IconBox = styled(props => )`
+const IconBox = styled(props => )`
cursor: pointer;
padding-left: 0.7rem;
` as typeof Box
export const DataKeyPair: React.FC = (props) => {
- const { value, path } = props
+ const { value, path, nestedIndex } = props
const [tempValue, setTempValue] = useState(value)
const depth = path.length
const key = path[depth - 1]
const hoverPath = useJsonViewerStore(store => store.hoverPath)
const isHover = useMemo(() => {
- return hoverPath && path.every((value, index) => value === hoverPath[index])
- }, [hoverPath, path])
+ return hoverPath && path.every(
+ (value, index) => value === hoverPath.path[index] && nestedIndex ===
+ hoverPath.nestedIndex)
+ }, [hoverPath, path, nestedIndex])
const setHover = useJsonViewerStore(store => store.setHover)
const root = useJsonViewerStore(store => store.value)
- const [inspect, setInspect] = useInspect(path, value)
+ const [inspect, setInspect] = useInspect(path, value, nestedIndex)
const [editing, setEditing] = useState(false)
const onChange = useJsonViewerStore(store => store.onChange)
const keyColor = useTextColor()
@@ -106,18 +108,18 @@ export const DataKeyPair: React.FC = (props) => {
{
copied
? (
-
+
)
: (
-
+
)
}
@@ -146,9 +148,9 @@ export const DataKeyPair: React.FC = (props) => {
const KeyRenderer = useJsonViewerStore(store => store.keyRenderer)
return (
setHover(path), [setHover, path])
- }
+ onMouseEnter={
+ useCallback(() => setHover(path, nestedIndex), [setHover, path, nestedIndex])
+ }
>
= (props) => {
{
KeyRenderer.when(downstreamProps)
?
- : !props.nested && (
- isNumberKey
- ? {displayKey}
- : <>"{displayKey}">
- )
+ : nestedIndex === undefined && (
+ isNumberKey
+ ? {displayKey}
+ : <>"{displayKey}">
+ )
}
{
- !props.nested && (
+ nestedIndex === undefined && (
:
)
}
@@ -188,11 +190,11 @@ export const DataKeyPair: React.FC = (props) => {
{
editing
- ? (Editor && )
+ ? (Editor && )
: (Component)
?
: {`fallback: ${value}`}
+ className='data-value-fallback'>{`fallback: ${value}`}
}
{PostComponent && }
{(isHover && expandable && !inspect) && actionIcons}
diff --git a/src/components/DataTypes/Object.tsx b/src/components/DataTypes/Object.tsx
index 9fa7bb2b..df8e9cce 100644
--- a/src/components/DataTypes/Object.tsx
+++ b/src/components/DataTypes/Object.tsx
@@ -111,7 +111,7 @@ export const ObjectType: React.FC> = (props) => {
return value.map((list, index) => {
const path = [...props.path]
return (
-
+
)
})
} else {
diff --git a/src/hooks/useInspect.ts b/src/hooks/useInspect.ts
index 824ee173..639da586 100644
--- a/src/hooks/useInspect.ts
+++ b/src/hooks/useInspect.ts
@@ -11,7 +11,7 @@ import {
} from '../stores/JsonViewerStore'
import { useIsCycleReference } from './useIsCycleReference'
-export function useInspect (path: (string | number)[], value: any) {
+export function useInspect (path: (string | number)[], value: any, nestedIndex?: number) {
const depth = path.length
const isTrap = useIsCycleReference(path, value)
const getInspectCache = useJsonViewerStore(store => store.getInspectCache)
@@ -19,25 +19,25 @@ export function useInspect (path: (string | number)[], value: any) {
const defaultInspectDepth = useJsonViewerStore(
store => store.defaultInspectDepth)
useEffect(() => {
- const inspect = getInspectCache(path)
+ const inspect = getInspectCache(path, nestedIndex)
if (inspect === undefined) {
- // do not inspect when it is a cycle reference, otherwise there will have a loop
- const inspect = isTrap
- ? false
- : depth < defaultInspectDepth
- setInspectCache(path, inspect)
+ if (nestedIndex !== undefined) {
+ setInspectCache(path, false, nestedIndex)
+ } else {
+ // do not inspect when it is a cycle reference, otherwise there will have a loop
+ const inspect = isTrap
+ ? false
+ : depth < defaultInspectDepth
+ setInspectCache(path, inspect)
+ }
}
- }, [
- defaultInspectDepth,
- depth,
- getInspectCache,
- isTrap,
- path,
- setInspectCache
- ])
+ }, [defaultInspectDepth, depth, getInspectCache, isTrap, nestedIndex, path, setInspectCache])
const [inspect, set] = useState(() => {
- const shouldInspect = getInspectCache(path)
+ const shouldInspect = getInspectCache(path, nestedIndex)
if (shouldInspect === undefined) {
+ if (nestedIndex !== undefined) {
+ return false
+ }
return isTrap
? false
: depth < defaultInspectDepth
@@ -47,9 +47,9 @@ export function useInspect (path: (string | number)[], value: any) {
const setInspect = useCallback>>((apply) => {
set((oldState) => {
const newState = typeof apply === 'boolean' ? apply : apply(oldState)
- setInspectCache(path, newState)
+ setInspectCache(path, newState, nestedIndex)
return newState
})
- }, [path, setInspectCache])
+ }, [nestedIndex, path, setInspectCache])
return [inspect, setInspect] as const
}
diff --git a/src/stores/JsonViewerStore.ts b/src/stores/JsonViewerStore.ts
index 1e228b86..6769777d 100644
--- a/src/stores/JsonViewerStore.ts
+++ b/src/stores/JsonViewerStore.ts
@@ -3,7 +3,7 @@ import create from 'zustand'
import createContext from 'zustand/context'
import { combine } from 'zustand/middleware'
-import type { JsonViewerOnChange } from '..'
+import type { JsonViewerOnChange, Path } from '..'
import type { ColorNamespace } from '../theme/base16'
import { lightColorNamespace } from '../theme/base16'
import type { JsonViewerKeyRenderer } from '../type'
@@ -13,7 +13,7 @@ DefaultKeyRenderer.when = () => false
export type JsonViewerState = {
inspectCache: Record
- hoverPath: (string | number)[] | null
+ hoverPath: { path: Path; nestedIndex?: number } | null
groupArraysAfterLength: number
defaultInspectDepth: number
colorNamespace: ColorNamespace
@@ -25,9 +25,10 @@ export type JsonViewerState = {
}
export type JsonViewerActions = {
- getInspectCache: (path: (string | number)[]) => boolean
- setInspectCache: (path: (string | number)[], action: SetStateAction) => void
- setHover: (path: (string | number)[] | null) => void
+ getInspectCache: (path: Path, nestedIndex?: number) => boolean
+ setInspectCache: (
+ path: Path, action: SetStateAction, nestedIndex?: number) => void
+ setHover: (path: Path | null, nestedIndex?: number) => void
}
export const createJsonViewerStore = () =>
@@ -46,21 +47,36 @@ export const createJsonViewerStore = () =>
keyRenderer: DefaultKeyRenderer
},
(set, get) => ({
- getInspectCache: (path) => {
- return get().inspectCache[path.join('.')]
+ getInspectCache: (path, nestedIndex) => {
+ const target = nestedIndex !== undefined
+ ? path.join('.') +
+ `[${nestedIndex}]nt`
+ : path.join('.')
+ return get().inspectCache[target]
},
- setInspectCache: (path, action) => {
- const target = path.join('.')
+ setInspectCache: (path, action, nestedIndex) => {
+ const target = nestedIndex !== undefined
+ ? path.join('.') +
+ `[${nestedIndex}]nt`
+ : path.join('.')
set(state => ({
inspectCache: {
...state.inspectCache,
- [target]: typeof action === 'function' ? action(state.inspectCache[target]) : action
+ [target]: typeof action === 'function'
+ ? action(
+ state.inspectCache[target])
+ : action
}
}))
},
- setHover: (path) => {
+ setHover: (path, nestedIndex) => {
set({
hoverPath: path
+ ? ({
+ path,
+ nestedIndex
+ })
+ : null
})
}
})
diff --git a/src/stores/typeRegistry.tsx b/src/stores/typeRegistry.tsx
index 0b11f730..2af0a5db 100644
--- a/src/stores/typeRegistry.tsx
+++ b/src/stores/typeRegistry.tsx
@@ -21,9 +21,10 @@ export function matchTypeComponents (value: Value): DataType {
for (const T of typeRegistry) {
if (T.is(value)) {
potential = T
- }
- if (typeof value === 'object' && value === null) {
- return T
+ if (typeof value === 'object') {
+ // early return for case like `null`
+ return T
+ }
}
}
if (potential === undefined) {
diff --git a/src/type.ts b/src/type.ts
index 67c2afa9..95a3fd57 100644
--- a/src/type.ts
+++ b/src/type.ts
@@ -1,7 +1,7 @@
import type { Dispatch, SetStateAction } from 'react'
import type React from 'react'
-type Path = (string | number)[]
+export type Path = (string | number)[]
export interface DataItemProps {
inspect: boolean