diff --git a/README.md b/README.md index ddbeb3e..560e475 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ npm install @microlink/react-json-view --save ```js import ReactJsonView from '@microlink/react-json-view' - + }} + showComma +/> ``` ### API @@ -84,6 +87,7 @@ import ReactJsonView from '@microlink/react-json-view' | `displayArrayKey` | `boolean` | `true` | When set to `true`, the index of the elements prefix values. | | `escapeStrings` | `boolean` | `true` | When set to `true`, strings sequences such as \n, \t, \r, \f will be escaped. | | `bigNumber` | `Class` | `null` | A custom class for handling large numbers. The class should have a constructor that accepts a numeric string/value and a `name` property for display purposes. You can use existing libraries like `bignumber.js`, `decimal.js`, `big.js`, or provide your own implementation. | +| `showComma` | `boolean` | `true` | When set to `true`, commas are displayed between object properties and array elements for better readability. Interactive tools (clipboard, edit, delete icons) appear after the comma when hovering over JSON elements. | #### Callbacks diff --git a/dev-server/src/index.js b/dev-server/src/index.js index 229ae0e..9fee0bc 100644 --- a/dev-server/src/index.js +++ b/dev-server/src/index.js @@ -64,6 +64,53 @@ ReactDom.render( return false }} defaultValue='' + showComma={true} + /> + +
+ + {/* Same example without commas for comparison */} + { + 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={'dev-server (no commas)'} + 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='' + showComma={false} />
@@ -98,6 +145,7 @@ ReactDom.render( src.constructor.name === 'Moment' } selectOnFocus + showComma={true} />
diff --git a/src/js/components/ArrayGroup.js b/src/js/components/ArrayGroup.js index 55d6122..f819c92 100644 --- a/src/js/components/ArrayGroup.js +++ b/src/js/components/ArrayGroup.js @@ -109,6 +109,8 @@ export default class extends React.PureComponent { type='array' parent_type='array_group' theme={theme} + showComma={this.props.showComma} + isLast={i === groups - 1} {...rest} /> ) diff --git a/src/js/components/DataTypes/Object.js b/src/js/components/DataTypes/Object.js index a7a0605..0334d4e 100644 --- a/src/js/components/DataTypes/Object.js +++ b/src/js/components/DataTypes/Object.js @@ -144,7 +144,6 @@ class RjvObject extends React.PureComponent { {object_type === 'array' ? '[' : '{'} - {expanded ? this.getObjectMetaData(src) : null} ) } @@ -167,7 +166,6 @@ class RjvObject extends React.PureComponent { {object_type === 'array' ? '[' : '{'} - {expanded ? this.getObjectMetaData(src) : null} ) } @@ -185,6 +183,8 @@ class RjvObject extends React.PureComponent { theme, jsvRoot, iconStyle, + showComma, + isLast, ...rest } = this.props @@ -222,8 +222,13 @@ class RjvObject extends React.PureComponent { > {object_type === 'array' ? ']' : '}'} - {expanded ? null : this.getObjectMetaData(src)} + {showComma && !isLast && !jsvRoot && ( + + , + + )} + {this.getObjectMetaData(src)} ) } @@ -234,7 +239,8 @@ class RjvObject extends React.PureComponent { parent_type, index_offset, groupArraysAfterLength, - namespace + namespace, + showComma, } = this.props const { object_type } = this.state const elements = [] @@ -244,8 +250,9 @@ class RjvObject extends React.PureComponent { keys = keys.sort() } - keys.forEach(name => { + keys.forEach((name, index) => { variable = new JsonVariable(name, variables[name], props.bigNumber) + const isLast = index === keys.length - 1 if (parent_type === 'array_group' && index_offset) { variable.name = parseInt(variable.name) + index_offset @@ -260,6 +267,8 @@ class RjvObject extends React.PureComponent { src={variable.value} namespace={namespace.concat(variable.name)} parent_type={object_type} + isLast={isLast} + showComma={showComma} {...props} /> ) @@ -282,6 +291,8 @@ class RjvObject extends React.PureComponent { namespace={namespace.concat(variable.name)} type='array' parent_type={object_type} + isLast={isLast} + showComma={showComma} {...props} /> ) @@ -294,6 +305,8 @@ class RjvObject extends React.PureComponent { singleIndent={SINGLE_INDENT} namespace={namespace} type={this.props.type} + isLast={isLast} + showComma={showComma} {...props} /> ) diff --git a/src/js/components/VariableEditor.js b/src/js/components/VariableEditor.js index d0bcb32..2d14b10 100644 --- a/src/js/components/VariableEditor.js +++ b/src/js/components/VariableEditor.js @@ -57,7 +57,9 @@ class VariableEditor extends React.PureComponent { onSelect, displayArrayKey, quotesOnKeys, - keyModifier + keyModifier, + showComma, + isLast } = this.props const { editMode } = this.state return ( @@ -126,6 +128,11 @@ class VariableEditor extends React.PureComponent { > {this.getValue(variable, editMode)} + {showComma && !isLast && ( + + , + + )} {enableClipboard ? ( e.metaKey || e.ctrlKey, - bigNumber: null + bigNumber: null, + showComma: true } // will trigger whenever setState() is called, or parent passes in new props. diff --git a/src/js/themes/getStyle.js b/src/js/themes/getStyle.js index a8b290d..dff05f0 100644 --- a/src/js/themes/getStyle.js +++ b/src/js/themes/getStyle.js @@ -386,6 +386,13 @@ const getDefaultThemeStyling = theme => { color: colors.validationFailure.iconColor, fontSize: constants.iconFontSize, transform: 'rotate(45deg)' + }, + comma: { + display: 'inline-block', + color: constants.commaColor, + fontSize: constants.commaFontSize, + marginRight: constants.commaMarginRight, + cursor: 'default' } } } diff --git a/src/js/themes/styleConstants.js b/src/js/themes/styleConstants.js index 98c1ba6..4b921a6 100644 --- a/src/js/themes/styleConstants.js +++ b/src/js/themes/styleConstants.js @@ -91,5 +91,9 @@ export default { addKeyModalWidth: '200px', addKeyModalMargin: 'auto', addKeyModalPadding: '10px', - addKeyModalRadius: '3px' -} + addKeyModalRadius: '3px', + + commaColor: '#666', + commaFontSize: '12px', + commaMarginRight: '4px' +}; diff --git a/test/tests/js/Index-test.js b/test/tests/js/Index-test.js index ed409bb..d8d22c5 100644 --- a/test/tests/js/Index-test.js +++ b/test/tests/js/Index-test.js @@ -128,4 +128,48 @@ describe('', function () { ) expect(wrapper.find('.object-size')).to.have.length(1) }) + + it('should show commas when showComma is true', function () { + const wrapper = render( + + ) + // Check that commas are present in the rendered output + expect(wrapper.text()).to.include(',') + }) + + it('should not show commas when showComma is false', function () { + const wrapper = render( + + ) + // Check that commas are not present in the rendered output + expect(wrapper.text()).to.not.include(',') + }) + + it('should default to showing commas when showComma is not specified', function () { + const wrapper = render( + + ) + // Check that commas are present by default + expect(wrapper.text()).to.include(',') + }) }) diff --git a/test/tests/js/components/DataTypes/Object-test.js b/test/tests/js/components/DataTypes/Object-test.js index e85d497..7c01c0b 100644 --- a/test/tests/js/components/DataTypes/Object-test.js +++ b/test/tests/js/components/DataTypes/Object-test.js @@ -373,4 +373,97 @@ describe('', function () { ) expect(wrapper.text()).to.equal('"":{"d":"d""b":"b""a":"a""c":"c"}') }) + + it('Object should show comma when showComma is true and not last element', function () { + let src = { + prop1: 1, + prop2: 2 + } + + const wrapper = shallow( + + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.true + }) + + it('Object should not show comma when showComma is false', function () { + let src = { + prop1: 1, + prop2: 2 + } + + const wrapper = shallow( + + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.false + }) + + it('Object should not show comma when isLast is true', function () { + let src = { + prop1: 1, + prop2: 2 + } + + const wrapper = shallow( + + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.false + }) + + it('Object should not show comma when jsvRoot is true', function () { + let src = { + prop1: 1, + prop2: 2 + } + + const wrapper = shallow( + + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.false + }) }) diff --git a/test/tests/js/components/VariableEditor-test.js b/test/tests/js/components/VariableEditor-test.js index 9d1f57c..075a998 100644 --- a/test/tests/js/components/VariableEditor-test.js +++ b/test/tests/js/components/VariableEditor-test.js @@ -372,4 +372,86 @@ describe('', function () { '\\\n\t\r\f\\n' ) }) + + it('VariableEditor should show comma when showComma is true and not last element', function () { + const wrapper = shallow( + { }} + rjvId={rjvId} + showComma + isLast={false} + variable={{ + name: 'test', + value: 5, + type: 'int' + }} + /> + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.true + }) + + it('VariableEditor should not show comma when showComma is false', function () { + const wrapper = shallow( + { }} + rjvId={rjvId} + showComma={false} + isLast={false} + variable={{ + name: 'test', + value: 5, + type: 'int' + }} + /> + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.false + }) + + it('VariableEditor should not show comma when isLast is true', function () { + const wrapper = shallow( + { }} + rjvId={rjvId} + showComma + isLast + variable={{ + name: 'test', + value: 5, + type: 'int' + }} + /> + ) + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.false + }) + + it('VariableEditor should render comma before tools when showComma is true', function () { + const wrapper = shallow( + { }} + rjvId={rjvId} + showComma + isLast={false} + variable={{ + name: 'test', + value: 5, + type: 'int' + }} + /> + ) + + // Check that comma exists + expect(wrapper.find('span').someWhere(node => node.text() === ',')).to.be.true + + // Check that tools (edit icon) exist + const editIcon = wrapper.find('.click-to-edit-icon') + expect(editIcon).to.have.length(1) + }) })