Skip to content

Add parent path to know the real path of change #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/components/json-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,21 @@ import type { CustomizeNode, CustomizeOptions } from '../types'
interface Props {
node: any
depth: number
parentPath: any[]
deleteHandle?: (indexOrName: string | number) => void
editHandle?: (indexOrName: string | number, newValue: any, oldValue: any) => void
indexOrName?: number | string
parent?: Record<string, any> | Array<any>
}

export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, indexOrName, parent, editHandle }: Props) {
export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, parentPath, indexOrName, parent, editHandle }: Props) {
// prettier-ignore
const { collapseStringsAfterLength, enableClipboard, editable, src, onDelete, onChange, customizeNode, matchesURL, urlRegExp, EditComponent, DoneComponent, CancelComponent, CustomOperation } = useContext(JsonViewContext)

let customReturn: ReturnType<CustomizeNode> | undefined
if (typeof customizeNode === 'function') customReturn = safeCall(customizeNode, [{ node, depth, indexOrName }])
const customReturn: ReturnType<CustomizeNode> | undefined = useMemo(() => {
if (typeof customizeNode === 'function') return safeCall(customizeNode, [{ parentPath, node, depth, indexOrName }])
return undefined
}, []);

if (customReturn) {
if (isValidElement(customReturn)) return customReturn
Expand All @@ -50,6 +53,7 @@ export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, ind
if (Array.isArray(node) || isObject(node)) {
return (
<ObjectNode
parentPath={parentPath}
node={node}
depth={depth}
indexOrName={indexOrName}
Expand Down Expand Up @@ -106,6 +110,7 @@ export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, ind
depth,
src,
indexOrName: indexOrName!,
parentPath: parentPath,
parentType: Array.isArray(parent) ? 'array' : 'object',
type: 'delete'
})
Expand Down Expand Up @@ -169,7 +174,7 @@ export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, ind
)

let className = 'json-view--string'

switch (type) {
case 'number':
case 'bigint':
Expand All @@ -182,7 +187,7 @@ export default function JsonNode({ node, depth, deleteHandle: _deleteHandle, ind
className = 'json-view--null'
break
}

if (typeof (customReturn as CustomizeOptions)?.className === 'string') className += ' ' + (customReturn as CustomizeOptions).className

if (deleting) className += ' json-view--deleting'
Expand Down
9 changes: 6 additions & 3 deletions src/components/json-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { stringifyForCopying } from '../utils'

type OnEdit = (params: { newValue: any; oldValue: any; depth: number; src: any; indexOrName: string | number; parentType: 'object' | 'array' | null }) => void
type OnDelete = (params: { value: any; indexOrName: string | number; depth: number; src: any; parentType: 'object' | 'array' | null }) => void
type OnAdd = (params: { indexOrName: string | number; depth: number; src: any; parentType: 'object' | 'array' }) => void
type OnAdd = (params: { indexOrName: string | number; depth: number; src: any; parentType: 'object' | 'array', parentPath: any[] }) => void
type OnChange = (params: {
indexOrName: string | number
depth: number
src: any
parentPath: any[]
parentType: 'object' | 'array' | null
type: 'add' | 'edit' | 'delete'
}) => void
Expand Down Expand Up @@ -59,7 +60,7 @@ export const JsonViewContext = createContext({
EditComponent: undefined as
| React.FC<{ onClick: (event: React.MouseEvent) => void; className: string }>
| React.Component<{ onClick: (event: React.MouseEvent) => void; className: string }>
| undefined,
| undefined,
CancelComponent: undefined as
| React.FC<{ onClick: (event: React.MouseEvent) => void; className: string; style: React.CSSProperties }>
| React.Component<{ onClick: (event: React.MouseEvent) => void; className: string; style: React.CSSProperties }>
Expand Down Expand Up @@ -225,6 +226,7 @@ export default function JsonView({
className={'json-view' + (dark ? ' dark' : '') + (theme && theme !== 'default' ? ' json-view_' + theme : '') + (className ? ' ' + className : '')}
style={style}>
<JsonNode
parentPath={[]}
node={src}
depth={1}
editHandle={(indexOrName: number | string, newValue: any, oldValue: any) => {
Expand All @@ -238,7 +240,7 @@ export default function JsonView({
indexOrName: indexOrName,
parentType: null
})
if (onChange) onChange({ type: 'edit', depth: 1, src, indexOrName: indexOrName, parentType: null })
if (onChange) onChange({ type: 'edit', depth: 1, src, indexOrName: indexOrName, parentPath: [], parentType: null })
}}
deleteHandle={() => {
setSrc(undefined)
Expand All @@ -255,6 +257,7 @@ export default function JsonView({
depth: 1,
src,
indexOrName: '',
parentPath: [],
parentType: null,
type: 'delete'
})
Expand Down
6 changes: 4 additions & 2 deletions src/components/large-array-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ interface Props {
originNode: Array<any>
node: Array<any>
depth: number
parentPath: any[]
index: number
deleteHandle?: (_: string | number) => void
customOptions?: CustomizeOptions
startIndex: number
}

export default function LargeArrayNode({ originNode, node, depth, index, deleteHandle: _deleteSelf, customOptions, startIndex }: Props) {
export default function LargeArrayNode({ originNode, parentPath, node, depth, index, deleteHandle: _deleteSelf, customOptions, startIndex }: Props) {
const { enableClipboard, src, onEdit, onChange, forceUpdate, displaySize, CustomOperation } = useContext(JsonViewContext)

const [fold, setFold] = useState(true)
Expand All @@ -34,7 +35,7 @@ export default function LargeArrayNode({ originNode, node, depth, index, deleteH
indexOrName,
parentType: 'array'
})
if (onChange) onChange({ type: 'edit', depth, src, indexOrName, parentType: 'array' })
if (onChange) onChange({ type: 'edit', depth, src, indexOrName, parentPath, parentType: 'array' })
forceUpdate()
},
[node, onEdit, onChange, forceUpdate]
Expand Down Expand Up @@ -71,6 +72,7 @@ export default function LargeArrayNode({ originNode, node, depth, index, deleteH
<div className='jv-indent'>
{node.map((n, i) => (
<NameValue
parentPath={parentPath}
key={String(index) + String(i)}
indexOrName={i + startIndex}
value={n}
Expand Down
10 changes: 6 additions & 4 deletions src/components/large-array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import { ReactComponent as CancelSVG } from '../svgs/cancel.svg'
interface Props {
node: Array<any>
depth: number
parentPath: any[]
indexOrName?: number | string
deleteHandle?: (_: string | number) => void
customOptions?: CustomizeOptions
}

export default function LargeArray({ node, depth, deleteHandle: _deleteSelf, indexOrName, customOptions }: Props) {
export default function LargeArray({ node, parentPath, depth, deleteHandle: _deleteSelf, indexOrName, customOptions }: Props) {
const nestCollapsedArray: any[] = []
for (let i = 0; i < node.length; i += 100) {
nestCollapsedArray.push(node.slice(i, i + 100))
Expand All @@ -44,6 +45,7 @@ export default function LargeArray({ node, depth, deleteHandle: _deleteSelf, ind
depth,
src,
indexOrName: indexOrName!,
parentPath,
parentType: 'array'
})
}
Expand All @@ -53,8 +55,8 @@ export default function LargeArray({ node, depth, deleteHandle: _deleteSelf, ind
const add = () => {
const arr = node as unknown as any[]
arr.push(null)
if (onAdd) onAdd({ indexOrName: arr.length - 1, depth, src, parentType: 'array' })
if (onChange) onChange({ type: 'add', indexOrName: arr.length - 1, depth, src, parentType: 'array' })
if (onAdd) onAdd({ indexOrName: arr.length - 1, depth, src, parentType: 'array', parentPath })
if (onChange) onChange({ type: 'add', indexOrName: arr.length - 1, depth, src, parentPath, parentType: 'array' })
forceUpdate()
}

Expand Down Expand Up @@ -102,7 +104,7 @@ export default function LargeArray({ node, depth, deleteHandle: _deleteSelf, ind
{!fold ? (
<div className='jv-indent'>
{nestCollapsedArray.map((item, index) => (
<LargeArrayNode key={String(indexOrName) + String(index)} originNode={node} node={item} depth={depth} index={index} startIndex={index * 100} />
<LargeArrayNode parentPath={parentPath} key={String(indexOrName) + String(index)} originNode={node} node={item} depth={depth} index={index} startIndex={index * 100} />
))}
</div>
) : (
Expand Down
5 changes: 3 additions & 2 deletions src/components/name-value.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import JsonNode from './json-node'
interface Props {
indexOrName: number | string
value: any
parentPath: any[]
depth: number
parent?: Record<string, any> | Array<any>
deleteHandle: (indexOrName: string | number) => void
editHandle: (indexOrName: string | number, newValue: any, oldValue: any) => void
}

export default function NameValue({ indexOrName, value, depth, parent, deleteHandle, editHandle }: Props) {
export default function NameValue({ indexOrName, value, depth, parent, parentPath, deleteHandle, editHandle }: Props) {
const { displayArrayIndex } = useContext(JsonViewContext)
const isArray = Array.isArray(parent)

Expand All @@ -25,7 +26,7 @@ export default function NameValue({ indexOrName, value, depth, parent, deleteHan
) : (
<></>
)}
<JsonNode node={value} depth={depth + 1} deleteHandle={deleteHandle} editHandle={editHandle} parent={parent} indexOrName={indexOrName} />
<JsonNode parentPath={[...parentPath, indexOrName]} node={value} depth={depth + 1} deleteHandle={deleteHandle} editHandle={editHandle} parent={parent} indexOrName={indexOrName} />
</div>
)
}
18 changes: 11 additions & 7 deletions src/components/object-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import LargeArray from './large-array'
interface Props {
node: Record<string, any> | Array<any>
depth: number
parentPath: any[]
indexOrName?: number | string
deleteHandle?: (_: string | number) => void
customOptions?: CustomizeOptions
}

export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _deleteSelf, customOptions }: Props) {
export default function ObjectNode({ node, depth, parentPath, indexOrName, deleteHandle: _deleteSelf, customOptions }: Props) {
const {
collapsed,
onCollapse,
Expand All @@ -38,7 +39,7 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
} = useContext(JsonViewContext)

if (!ignoreLargeArray && Array.isArray(node) && node.length > 100) {
return <LargeArray node={node} depth={depth} indexOrName={indexOrName} deleteHandle={_deleteSelf} customOptions={customOptions} />
return <LargeArray parentPath={parentPath} node={node} depth={depth} indexOrName={indexOrName} deleteHandle={_deleteSelf} customOptions={customOptions} />
}

const isPlainObject = isObject(node)
Expand Down Expand Up @@ -71,7 +72,7 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
indexOrName: indexOrName,
parentType: isPlainObject ? 'object' : 'array'
})
if (onChange) onChange({ type: 'edit', depth, src, indexOrName: indexOrName, parentType: isPlainObject ? 'object' : 'array' })
if (onChange) onChange({ type: 'edit', depth, src, indexOrName: indexOrName, parentPath, parentType: isPlainObject ? 'object' : 'array' })
forceUpdate()
},
[node, onEdit, onChange, forceUpdate]
Expand Down Expand Up @@ -99,6 +100,7 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
depth,
src,
indexOrName: indexOrName!,
parentPath,
parentType: isPlainObject ? 'object' : 'array'
})
}
Expand All @@ -116,14 +118,14 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
if (inputRef.current) inputRef.current.value = ''
setAdding(false)

if (onAdd) onAdd({ indexOrName: inputName, depth, src, parentType: 'object' })
if (onChange) onChange({ type: 'add', indexOrName: inputName, depth, src, parentType: 'object' })
if (onAdd) onAdd({ indexOrName: inputName, depth, src, parentType: 'object', parentPath })
if (onChange) onChange({ type: 'add', indexOrName: inputName, depth, src, parentPath, parentType: 'object' })
}
} else if (Array.isArray(node)) {
const arr = node as unknown as any[]
arr.push(null)
if (onAdd) onAdd({ indexOrName: arr.length - 1, depth, src, parentType: 'array' })
if (onChange) onChange({ type: 'add', indexOrName: arr.length - 1, depth, src, parentType: 'array' })
if (onAdd) onAdd({ indexOrName: arr.length - 1, depth, src, parentType: 'array', parentPath })
if (onChange) onChange({ type: 'add', indexOrName: arr.length - 1, depth, src, parentPath, parentType: 'array' })
}
forceUpdate()
}
Expand Down Expand Up @@ -189,6 +191,7 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
<div className='jv-indent'>
{node.map((n, i) => (
<NameValue
parentPath={parentPath}
key={String(indexOrName) + String(i)}
indexOrName={i}
value={n}
Expand Down Expand Up @@ -225,6 +228,7 @@ export default function ObjectNode({ node, depth, indexOrName, deleteHandle: _de
<div className='jv-indent'>
{Object.entries(node).map(([name, value]) => (
<NameValue
parentPath={parentPath}
key={String(indexOrName) + String(name)}
indexOrName={name}
value={value}
Expand Down
4 changes: 2 additions & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import JsonView, { defaultURLRegExp, JsonViewProps } from './components/json-view'
import JsonView, { defaultURLRegExp, JsonViewProps, JsonViewContext } from './components/json-view'
import { stringifyForCopying as stringify } from './utils'

import { ReactComponent as EditSVG } from './svgs/edit.svg'
Expand All @@ -9,5 +9,5 @@ import { ReactComponent as CopySVG } from './svgs/copy.svg'
import { ReactComponent as CopiedSVG } from './svgs/copied.svg'
import { ReactComponent as LinkSVG } from './svgs/link.svg'

export { JsonView as default, stringify, defaultURLRegExp, EditSVG, DeleteSVG, DoneSVG, CancelSVG, CopySVG, CopiedSVG, LinkSVG }
export { JsonViewContext, JsonView as default, stringify, defaultURLRegExp, EditSVG, DeleteSVG, DoneSVG, CancelSVG, CopySVG, CopiedSVG, LinkSVG }
export type { JsonViewProps }
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export declare type CustomizeOptions = {
className?: string
}
export declare type CustomizeNode = (params: {
parentPath: any[]
node: any
indexOrName: number | string | undefined
depth: number
Expand Down
Loading