Skip to content
Merged
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [1.27.0](https://github.com/n1c0de/react-json-view/compare/v1.26.3...v1.27.0) (2025-05-26)


### Features

- **json viewer:** add a new prop to add custom buttons according to the data type ([e8df37a](https://github.com/n1c0de/react-json-view/commit/e8df37aa76e2eaeb586a63a6b5dd1cc0c05892b4))

### [1.26.3](https://github.com/n1c0de/react-json-view/compare/v1.26.2...v1.26.3) (2025-05-26)

### [1.26.2](https://github.com/microlinkhq/react-json-view/compare/v1.26.1...v1.26.2) (2025-05-16)
Expand Down
200 changes: 199 additions & 1 deletion dev-server/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ ReactDom.render(

<br />

{/*demo array support*/}
{/* demo array support */}
<JsonViewer
src={getExampleArray()}
theme='solarized'
Expand Down Expand Up @@ -201,6 +201,172 @@ ReactDom.render(
name='String with special escape sequences'
src={getExampleWithStringEscapeSequences()}
/>

{/* Custom buttons according to the value type */}
<JsonViewer
bigNumber={BigNumber}
sortKeys
style={{ padding: '30px', backgroundColor: 'white' }}
src={getExampleJson5()}
quotesOnKeys={false}
collapseStringsAfterLength={12}
customButtons={{
boolean: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
integer: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: (element) => element.src === 27
? <path d='M0 14l6-6-6-6z' />
: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: (element) => element.src === 27
? '0 0 15 15'
: '0 0 40 40',
title: (element) => element.src === 27
? 'Special title'
: 'Example title',
className: (element) => element.src === 27
? 'special-class'
: 'class-example'
},
float: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
bigNumber: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
date: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
string: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: (element) => element.variableName === 'string-key-test'
? <path d='M1344 800v64q0 14-9 23t-23 9h-352v352q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23v-352h-352q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h352v-352q0-14 9-23t23-9h64q14 0 23 9t9 23v352h352q14 0 23 9t9 23zm128 448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z' />
: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: (element) => element.variableName === 'string-key-test'
?'0 0 1792 1792'
:'0 0 40 40',
title: (element) => element.variableName === 'string-key-test'
? 'Special title'
: 'Title example',
className: (element) => element.variableName === 'string-key-test'
? 'special-class'
: 'class-example'
},
regexp: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
array: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
empty_array: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
object: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
empty_object: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
function: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
undefined: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
null: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
nan: {
clickCallback: (element) => { console.log(JSON.stringify(element, null, 4)) },
path: <path d="m31.7 16.4q0-0.6-0.4-1l-2.1-2.1q-0.4-0.4-1-0.4t-1 0.4l-9.1 9.1-5-5q-0.5-0.4-1-0.4t-1 0.4l-2.1 2q-0.4 0.4-0.4 1 0 0.6 0.4 1l8.1 8.1q0.4 0.4 1 0.4 0.6 0 1-0.4l12.2-12.1q0.4-0.4 0.4-1z m5.6 3.6q0 4.7-2.3 8.6t-6.3 6.2-8.6 2.3-8.6-2.3-6.2-6.2-2.3-8.6 2.3-8.6 6.2-6.2 8.6-2.3 8.6 2.3 6.3 6.2 2.3 8.6z" />,
viewBox: '0 0 40 40',
title: 'A title example',
className: 'class-example'
},
}}
onEdit={e => {
console.log('edit callback', e)
if (e.new_value == 'error') {
return false
}
}}
onDelete={e => {
console.log('delete callback', e)
}}
onAdd={e => {
console.log('add callback', e)
if (e.new_value == 'error') {
return false
}
}}
onSelect={e => {
console.log('select callback', e)
console.log(e.namespace)
}}
displayObjectSize={true}
name={'custom-buttons'}
enableClipboard={copy => {
console.log('you copied to clipboard!', copy)
}}
shouldCollapse={({ src, namespace, type }) => {
if (type === 'array' && src.indexOf('test') > -1) {
return true
} else if (namespace.indexOf('moment') > -1) {
return true
}
return false
}}
defaultValue=''
/>
</div>,
document.getElementById('app-container')
)
Expand Down Expand Up @@ -320,3 +486,35 @@ function getExampleArray () {
function getExampleWithStringEscapeSequences () {
return { '\\\n\t\r\f\\n': '\\\n\t\r\f\\n' }
}

function getExampleJson5 () {
return {
string: 'this is a test string',
'string-key-test': 'this is another test string',
integer: 42,
'integer-key-test': 27,
empty_array: [],
empty_object: {},
array: [1, 2, 3, 'test'],
float: -2.757,
undefined_var: undefined,
parent: {
sibling1: true,
sibling2: false,
sibling3: null,
sibling4: NaN,
isString: value => {
if (typeof value === 'string') {
return 'string'
} else {
return 'other'
}
}
},
string_number: '1234',
date: new Date(),
moment: Moment(),
regexp: /[0-9]/gi,
bigNumber: new BigNumber('0.0060254656709730629123'),
}
}
16 changes: 16 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ export interface ReactJsonViewProps {
* Default: true
*/
escapeStrings?: boolean
/**
* Adds custom buttons according to the value type.
*
* Default: null
*/
customButtons?: TypeCustomButtons
}

export interface OnCopyProps {
Expand Down Expand Up @@ -308,5 +314,15 @@ export type ThemeKeys =
| 'tube'
| 'twilight'

export type TypeCustomButtons = {
[valueType: string]: {
clickCallback: (element: { variableName: string; src: string; namespace: Array<string>; name: string; }) => void
path: React.ReactElement<React.SVGProps<SVGPathElement>> | ((element: { variableName: string; src: string; namespace: Array<string>; name: string; }) => React.ReactElement<React.SVGProps<SVGPathElement>>)
viewBox?: string | ((element: { variableName: string; src: string; namespace: Array<string>; name: string; }) => string)
title?: string | ((element: { variableName: string; src: string; namespace: Array<string>; name: string; }) => string)
className?: string | ((element: { variableName: string; src: string; namespace: Array<string>; name: string; }) => string)
}
}

declare const ReactJson: React.ComponentType<ReactJsonViewProps>
export default ReactJson
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@microlink/react-json-view",
"description": "Interactive react component for displaying javascript arrays and JSON objects.",
"homepage": "https://github.com/microlinkhq/react-json-view",
"version": "1.26.3",
"version": "1.27.0",
"main": "dist/main.js",
"author": {
"name": "Mac Gainor"
Expand Down
3 changes: 2 additions & 1 deletion src/js/components/ArrayGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default class extends React.PureComponent {
jsvRoot,
namespace,
parent_type,
customButtons,
...rest
} = this.props

Expand All @@ -74,7 +75,7 @@ export default class extends React.PureComponent {
<ObjectName {...this.props} />

<span>
<VariableMeta size={src.length} {...this.props} />
<VariableMeta customButtons={customButtons} size={src.length} {...this.props} />
</span>
{[...Array(groups)].map((_, i) => (
<div
Expand Down
83 changes: 83 additions & 0 deletions src/js/components/CustomButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react'
import { CustomIcon } from './icons'
import Theme from './../themes/getStyle'

export default class extends React.PureComponent {
constructor(props) {
super(props)
}

handleClick = () => {
const { clickCallback, src, namespace, variableName } = this.props

clickCallback({
variableName: variableName,
src: src,
namespace: namespace,
name: namespace[namespace.length - 1]
})
}

getClippyIcon = () => {
const { theme } = this.props

return (
<CustomIcon
className='custom-icon'
{...this.props}
{...Theme(theme, 'custom-icon')}
/>
)
}

render () {
const { src, theme, hidden, rowHovered, namespace, variableName, title, className } = this.props;
const style = Theme(theme, 'custom-button').style
let display = 'inline'

if (hidden) {
display = 'none'
}

return (
<span
className={typeof className === 'function'
? className({
variableName: variableName,
src: src,
namespace: namespace,
name: namespace[namespace.length - 1]
})
: typeof className === 'string'
? className
: ''
}
title={typeof title === 'function'
? title({
variableName: variableName,
src: src,
namespace: namespace,
name: namespace[namespace.length - 1]
})
: typeof title === 'string'
? title
: ''
}
style={{
verticalAlign: 'top',
display: rowHovered ? 'inline-block' : 'none'
}}
>
<span
style={{
...style,
display: display
}}
onClick={this.handleClick}
>
{this.getClippyIcon()}
</span>
</span>
)
}
}
4 changes: 2 additions & 2 deletions src/js/components/DataTypes/Object.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ class RjvObject extends React.PureComponent {
}

getObjectMetaData = src => {
const { rjvId, theme } = this.props
const { rjvId, theme, customButtons } = this.props
const { size, hovered } = this.state
return <VariableMeta rowHovered={hovered} size={size} {...this.props} />
return <VariableMeta customButtons={customButtons} rowHovered={hovered} size={size} {...this.props} />
}

getBraceStart (object_type, expanded) {
Expand Down
2 changes: 1 addition & 1 deletion src/js/components/JsonViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class extends React.PureComponent {
return (
<div className='pretty-json-container object-container'>
<div className='object-content'>
<ObjectComponent namespace={namespace} depth={0} jsvRoot {...props} />
<ObjectComponent namespace={namespace} depth={0} jsvRoot customButtons={{}} {...props} />
</div>
</div>
)
Expand Down
Loading