diff --git a/.gitignore b/.gitignore
index b74cc500..958dbf39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,5 @@ npm-debug.log
/debug
/node_modules
-.nyc_output
\ No newline at end of file
+.nyc_output
+.idea
\ No newline at end of file
diff --git a/dev-server/src/index.js b/dev-server/src/index.js
index 169a2501..487d37c1 100644
--- a/dev-server/src/index.js
+++ b/dev-server/src/index.js
@@ -52,6 +52,7 @@ ReactDom.render(
return false;
}}
defaultValue=""
+ searchable={true}
/>
diff --git a/package-lock.json b/package-lock.json
index 9589552f..2d324d35 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,7 +1,7 @@
{
"name": "react-json-view",
- "version": "1.21.1",
- "lockfileVersion": 1,
+ "version": "1.21.3",
+ "lockfileVersion": 2,
"requires": true,
"dependencies": {
"@babel/code-frame": {
@@ -18896,6 +18896,15 @@
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
"dev": true
},
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
"string-length": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz",
@@ -18969,15 +18978,6 @@
"define-properties": "^1.1.3"
}
},
- "string_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
"stringify-object": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
diff --git a/src/js/components/ArrayGroup.js b/src/js/components/ArrayGroup.js
index deae3f8e..42795e2e 100644
--- a/src/js/components/ArrayGroup.js
+++ b/src/js/components/ArrayGroup.js
@@ -1,17 +1,17 @@
import React from 'react';
import Theme from './../themes/getStyle';
-import VariableMeta from './VariableMeta';
-import ObjectName from './ObjectName';
import ObjectComponent from './DataTypes/Object';
//icons
import { CollapsedIcon, ExpandedIcon } from './ToggleIcons';
+import { ObjectName } from './ObjectName';
+import { VariableMeta } from './VariableMeta';
//single indent is 5px
const SINGLE_INDENT = 5;
-export default class extends React.PureComponent {
+export class ArrayGroup extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
diff --git a/src/js/components/CopyToClipboard.js b/src/js/components/CopyToClipboard.js
index 62ea78df..762f7336 100644
--- a/src/js/components/CopyToClipboard.js
+++ b/src/js/components/CopyToClipboard.js
@@ -8,7 +8,7 @@ import { Clippy } from './icons';
//theme
import Theme from './../themes/getStyle';
-export default class extends React.PureComponent {
+export class CopyToClipboard extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
diff --git a/src/js/components/DataTypes/Boolean.js b/src/js/components/DataTypes/Boolean.js
index 886d3326..1038fd9f 100644
--- a/src/js/components/DataTypes/Boolean.js
+++ b/src/js/components/DataTypes/Boolean.js
@@ -1,10 +1,10 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
//theme
import Theme from './../../themes/getStyle';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonBoolean extends React.PureComponent {
render() {
const type_name = 'bool';
const { props } = this;
@@ -12,7 +12,9 @@ export default class extends React.PureComponent {
return (
- {props.value ? 'true' : 'false'}
+
+ {props.value ? 'true' : 'false'}
+
);
}
diff --git a/src/js/components/DataTypes/DataTypeLabel.js b/src/js/components/DataTypes/DataTypeLabel.js
index 5b61fdcb..f1e1fac8 100644
--- a/src/js/components/DataTypes/DataTypeLabel.js
+++ b/src/js/components/DataTypes/DataTypeLabel.js
@@ -3,7 +3,7 @@ import React from 'react';
//theme
import Theme from './../../themes/getStyle';
-export default class extends React.PureComponent {
+export class DataTypeLabel extends React.PureComponent {
render() {
const { rjvId, type_name, displayDataTypes, theme } = this.props;
if (displayDataTypes) {
diff --git a/src/js/components/DataTypes/DataTypes.js b/src/js/components/DataTypes/DataTypes.js
index de5c5016..948930a7 100644
--- a/src/js/components/DataTypes/DataTypes.js
+++ b/src/js/components/DataTypes/DataTypes.js
@@ -1,11 +1 @@
-export { default as JsonBoolean } from './Boolean';
-export { default as JsonDate } from './Date';
-export { default as JsonFloat } from './Float';
-export { default as JsonFunction } from './Function';
-export { default as JsonNan } from './Nan';
-export { default as JsonNull } from './Null';
-export { default as JsonInteger } from './Integer';
export { default as JsonObject } from './Object';
-export { default as JsonRegexp } from './Regexp';
-export { default as JsonString } from './String';
-export { default as JsonUndefined } from './Undefined';
diff --git a/src/js/components/DataTypes/Date.js b/src/js/components/DataTypes/Date.js
index 662d7556..f41a7aa3 100644
--- a/src/js/components/DataTypes/Date.js
+++ b/src/js/components/DataTypes/Date.js
@@ -1,10 +1,10 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
//theme
import Theme from './../../themes/getStyle';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonDate extends React.PureComponent {
render() {
const type_name = 'date';
const { props } = this;
@@ -19,7 +19,8 @@ export default class extends React.PureComponent {
return (
-
+
{props.value.toLocaleTimeString('en-us', display_options)}
diff --git a/src/js/components/DataTypes/Float.js b/src/js/components/DataTypes/Float.js
index 68bab7ab..caada36d 100644
--- a/src/js/components/DataTypes/Float.js
+++ b/src/js/components/DataTypes/Float.js
@@ -1,17 +1,17 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
//theme
import Theme from './../../themes/getStyle';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonFloat extends React.PureComponent {
render() {
const type_name = 'float';
const { props } = this;
return (
- {this.props.value}
+ {this.props.value}
);
}
diff --git a/src/js/components/DataTypes/Function.js b/src/js/components/DataTypes/Function.js
index 473afe9e..3855498f 100644
--- a/src/js/components/DataTypes/Function.js
+++ b/src/js/components/DataTypes/Function.js
@@ -1,13 +1,13 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
//theme
import Theme from './../../themes/getStyle';
//attribute store for storing collapsed state
import AttributeStore from './../../stores/ObjectAttributes';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonFunction extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
diff --git a/src/js/components/DataTypes/Integer.js b/src/js/components/DataTypes/Integer.js
index 21d173d6..2662c523 100644
--- a/src/js/components/DataTypes/Integer.js
+++ b/src/js/components/DataTypes/Integer.js
@@ -1,17 +1,17 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
//theme
import Theme from './../../themes/getStyle';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonInteger extends React.PureComponent {
render() {
const type_name = 'int';
const { props } = this;
return (
- {this.props.value}
+ {this.props.value}
);
}
diff --git a/src/js/components/DataTypes/Nan.js b/src/js/components/DataTypes/Nan.js
index ddc1aa96..99230d78 100644
--- a/src/js/components/DataTypes/Nan.js
+++ b/src/js/components/DataTypes/Nan.js
@@ -3,8 +3,11 @@ import React from 'react';
//theme
import Theme from './../../themes/getStyle';
-export default class extends React.PureComponent {
+export class JsonNan extends React.PureComponent {
render() {
- return NaN
;
+ const { props } = this;
+ return
+ NaN
+
;
}
}
diff --git a/src/js/components/DataTypes/Null.js b/src/js/components/DataTypes/Null.js
index 005729fd..da6d9d3b 100644
--- a/src/js/components/DataTypes/Null.js
+++ b/src/js/components/DataTypes/Null.js
@@ -3,8 +3,11 @@ import React from 'react';
//theme
import Theme from './../../themes/getStyle';
-export default class extends React.PureComponent {
+export class JsonNull extends React.PureComponent {
render() {
- return NULL
;
+ const { props } = this;
+ return
+ NULL
+
;
}
}
diff --git a/src/js/components/DataTypes/Object.js b/src/js/components/DataTypes/Object.js
index 4c7cb93f..09b32f08 100644
--- a/src/js/components/DataTypes/Object.js
+++ b/src/js/components/DataTypes/Object.js
@@ -5,11 +5,6 @@ import { toType } from './../../helpers/util';
//data type components
import { JsonObject } from './DataTypes';
-import VariableEditor from './../VariableEditor';
-import VariableMeta from './../VariableMeta';
-import ArrayGroup from './../ArrayGroup';
-import ObjectName from './../ObjectName';
-
//attribute store
import AttributeStore from './../../stores/ObjectAttributes';
@@ -18,6 +13,10 @@ import { CollapsedIcon, ExpandedIcon } from './../ToggleIcons';
//theme
import Theme from './../../themes/getStyle';
+import { ArrayGroup } from '../ArrayGroup';
+import { ObjectName } from '../ObjectName';
+import { VariableMeta } from '../VariableMeta';
+import { VariableEditor } from '../VariableEditor';
//increment 1 with each nested object & array
const DEPTH_INCREMENT = 1;
@@ -48,12 +47,13 @@ class RjvObject extends React.PureComponent {
}) === false) &&
//initialize closed if object has no items
size !== 0;
+ const path = props.namespace.join('.');
const state = {
expanded: AttributeStore.get(
props.rjvId,
props.namespace,
'expanded',
- expanded
+ expanded ? expanded :props.paths?.some(name => name.includes(path))
),
object_type: props.type === 'array' ? 'array' : 'object',
parent_type: props.type === 'array' ? 'array' : 'object',
diff --git a/src/js/components/DataTypes/Regexp.js b/src/js/components/DataTypes/Regexp.js
index 17af70a1..e6a82eca 100644
--- a/src/js/components/DataTypes/Regexp.js
+++ b/src/js/components/DataTypes/Regexp.js
@@ -1,17 +1,18 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
-
//theme
import Theme from './../../themes/getStyle';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonRegexp extends React.PureComponent {
render() {
const type_name = 'regexp';
const { props } = this;
return (
- {this.props.value.toString()}
+
+ {this.props.value.toString()}
+
);
}
diff --git a/src/js/components/DataTypes/String.js b/src/js/components/DataTypes/String.js
index cef5fc3b..84f969dc 100644
--- a/src/js/components/DataTypes/String.js
+++ b/src/js/components/DataTypes/String.js
@@ -1,14 +1,14 @@
import React from 'react';
-import DataTypeLabel from './DataTypeLabel';
-import { toType } from './../../helpers/util';
+import { toType } from '../../helpers/util';
//theme
import Theme from './../../themes/getStyle';
//attribute store for storing collapsed state
import AttributeStore from './../../stores/ObjectAttributes';
+import { DataTypeLabel } from './DataTypeLabel';
-export default class extends React.PureComponent {
+export class JsonString extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
@@ -65,6 +65,7 @@ export default class extends React.PureComponent {
class="string-value"
{...style}
onClick={this.toggleCollapsed}
+ style={{backgroundColor: props.isCurrent ? 'orange' : props.highlight ? 'yellow' : 'inherit'}}
>
"{value}"
diff --git a/src/js/components/DataTypes/Undefined.js b/src/js/components/DataTypes/Undefined.js
index 534132f2..ca1251e9 100644
--- a/src/js/components/DataTypes/Undefined.js
+++ b/src/js/components/DataTypes/Undefined.js
@@ -3,8 +3,13 @@ import React from 'react';
//theme
import Theme from './../../themes/getStyle';
-export default class extends React.PureComponent {
+export class JsonUndefined extends React.PureComponent {
render() {
- return undefined
;
+ const { props } = this;
+ return
+
+ undefined
+
+
;
}
}
diff --git a/src/js/components/JsonViewer.js b/src/js/components/JsonViewer.js
index 5c0278f8..3f1efca0 100644
--- a/src/js/components/JsonViewer.js
+++ b/src/js/components/JsonViewer.js
@@ -1,8 +1,8 @@
import React from 'react';
+import { ArrayGroup } from './ArrayGroup';
import JsonObject from './DataTypes/Object';
-import ArrayGroup from './ArrayGroup';
-export default class extends React.PureComponent {
+export class JsonViewer extends React.PureComponent {
render = () => {
const { props } = this;
const namespace = [props.name];
diff --git a/src/js/components/ObjectKeyModal/AddKeyRequest.js b/src/js/components/ObjectKeyModal/AddKeyRequest.js
index 65eb7b06..2e127fb6 100644
--- a/src/js/components/ObjectKeyModal/AddKeyRequest.js
+++ b/src/js/components/ObjectKeyModal/AddKeyRequest.js
@@ -1,13 +1,13 @@
import React from 'react';
import dispatcher from './../../helpers/dispatcher';
import ObjectAttributes from './../../stores/ObjectAttributes';
-import ObjectKeyModal from './ObjectKeyModal';
//global theme
import Theme from './../../themes/getStyle';
+import { ObjectKeyModal } from './ObjectKeyModal';
//this input appears when adding a new value to an object
-export default class extends React.PureComponent {
+export class AddKeyRequest extends React.PureComponent {
render() {
const { active, theme, rjvId } = this.props;
diff --git a/src/js/components/ObjectKeyModal/ObjectKeyModal.js b/src/js/components/ObjectKeyModal/ObjectKeyModal.js
index 67389154..7504f112 100644
--- a/src/js/components/ObjectKeyModal/ObjectKeyModal.js
+++ b/src/js/components/ObjectKeyModal/ObjectKeyModal.js
@@ -7,7 +7,7 @@ import { CheckCircle, Add as Cancel } from './../icons';
import Theme from './../../themes/getStyle';
//this input appears when adding a new value to an object
-export default class extends React.PureComponent {
+export class ObjectKeyModal extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
diff --git a/src/js/components/ObjectName.js b/src/js/components/ObjectName.js
index c1cfaac7..1d9ca4b7 100644
--- a/src/js/components/ObjectName.js
+++ b/src/js/components/ObjectName.js
@@ -1,7 +1,7 @@
import React from 'react';
import Theme from './../themes/getStyle';
-export default function getObjectName(props) {
+export function ObjectName(props) {
const {
parent_type,
namespace,
diff --git a/src/js/components/ValidationFailure.js b/src/js/components/ValidationFailure.js
index ea2981a3..e19daef3 100644
--- a/src/js/components/ValidationFailure.js
+++ b/src/js/components/ValidationFailure.js
@@ -8,7 +8,7 @@ import { Add as Clear } from './icons';
import Theme from './../themes/getStyle';
//this input appears when adding a new value to an object
-export default class extends React.PureComponent {
+export class ValidationFailure extends React.PureComponent {
render() {
const { message, active, theme, rjvId } = this.props;
diff --git a/src/js/components/VariableEditor.js b/src/js/components/VariableEditor.js
index a78aab4e..5b40ffe5 100644
--- a/src/js/components/VariableEditor.js
+++ b/src/js/components/VariableEditor.js
@@ -1,25 +1,22 @@
import React from 'react';
import AutosizeTextarea from 'react-textarea-autosize';
-import { toType } from './../helpers/util';
import dispatcher from './../helpers/dispatcher';
import parseInput from './../helpers/parseInput';
import stringifyVariable from './../helpers/stringifyVariable';
-import CopyToClipboard from './CopyToClipboard';
//data type components
-import {
- JsonBoolean,
- JsonDate,
- JsonFloat,
- JsonFunction,
- JsonInteger,
- JsonNan,
- JsonNull,
- JsonRegexp,
- JsonString,
- JsonUndefined
-} from './DataTypes/DataTypes';
+import { JsonString } from './DataTypes/String';
+import { JsonInteger } from './DataTypes/Integer';
+import { JsonFloat } from './DataTypes/Float';
+import { JsonBoolean } from './DataTypes/Boolean';
+import { JsonFunction } from './DataTypes/Function';
+import { JsonNull } from './DataTypes/Null';
+import { JsonNan } from './DataTypes/Nan';
+import { JsonUndefined } from './DataTypes/Undefined';
+import { JsonDate } from './DataTypes/Date';
+import { JsonRegexp } from './DataTypes/Regexp';
+import { CopyToClipboard } from './CopyToClipboard';
//clibboard icon
import { Edit, CheckCircle, RemoveCircle as Remove } from './icons';
@@ -27,7 +24,7 @@ import { Edit, CheckCircle, RemoveCircle as Remove } from './icons';
//theme
import Theme from './../themes/getStyle';
-class VariableEditor extends React.PureComponent {
+export class VariableEditor extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
@@ -54,10 +51,18 @@ class VariableEditor extends React.PureComponent {
onEdit,
onDelete,
onSelect,
+ paths,
+ refs,
+ current,
displayArrayKey,
quotesOnKeys
} = this.props;
const { editMode } = this.state;
+ const currentNamespace= [...namespace, variable.name];
+ const currentPath = currentNamespace.join('.');
+ const highlight = paths?.includes(currentPath);
+ const isCurrent = paths[current] === currentPath;
+
return (
{type == 'array' ? (
displayArrayKey ? (
@@ -127,7 +133,7 @@ class VariableEditor extends React.PureComponent {
cursor: onSelect === false ? 'default' : 'pointer'
})}
>
- {this.getValue(variable, editMode)}
+ {this.getValue(variable, editMode, highlight, isCurrent)}
{enableClipboard ? (
) : null}
{onEdit !== false && editMode == false
@@ -216,32 +222,32 @@ class VariableEditor extends React.PureComponent {
);
};
- getValue = (variable, editMode) => {
+ getValue = (variable, editMode, highlight, isCurrent) => {
const type = editMode ? false : variable.type;
const { props } = this;
switch (type) {
case false:
return this.getEditInput();
case 'string':
- return ;
+ return ;
case 'integer':
- return ;
+ return ;
case 'float':
- return ;
+ return ;
case 'boolean':
- return ;
+ return ;
case 'function':
- return ;
+ return ;
case 'null':
- return ;
+ return ;
case 'nan':
- return ;
+ return ;
case 'undefined':
- return ;
+ return ;
case 'date':
- return ;
+ return ;
case 'regexp':
- return ;
+ return ;
default:
// catch-all for types that weren't anticipated
return (
@@ -455,5 +461,3 @@ class VariableEditor extends React.PureComponent {
};
}
-//export component
-export default VariableEditor;
diff --git a/src/js/components/VariableMeta.js b/src/js/components/VariableMeta.js
index d6f6da74..5b005568 100644
--- a/src/js/components/VariableMeta.js
+++ b/src/js/components/VariableMeta.js
@@ -1,7 +1,6 @@
import React from 'react';
import dispatcher from './../helpers/dispatcher';
-import CopyToClipboard from './CopyToClipboard';
import { toType } from './../helpers/util';
//icons
@@ -9,8 +8,9 @@ import { RemoveCircle as Remove, AddCircle as Add } from './icons';
//theme
import Theme from './../themes/getStyle';
+import { CopyToClipboard } from './CopyToClipboard';
-export default class extends React.PureComponent {
+export class VariableMeta extends React.PureComponent {
getObjectSize = () => {
const { size, theme, displayObjectSize } = this.props;
if (displayObjectSize) {
diff --git a/src/js/helpers/util.js b/src/js/helpers/util.js
index 50ab5185..74519bc3 100644
--- a/src/js/helpers/util.js
+++ b/src/js/helpers/util.js
@@ -53,3 +53,67 @@ export function isTheme(theme) {
}
return false;
}
+
+
+export function searchJson(json, searchTerm, levelPath = 'root') {
+ const paths = [];
+
+ if (!searchTerm) {
+ return paths;
+ }
+
+ const normalized = searchTerm.toLowerCase();
+ for (const jsonElement of Object.keys(json).sort()) {
+ const path = `${levelPath}.${jsonElement}`;
+ if (typeof json[jsonElement] === 'string' && json[jsonElement].toLowerCase().includes(normalized)) {
+ paths.push(path);
+ } else if (
+ (typeof json[jsonElement] === 'number' ||
+ typeof json[jsonElement] === 'boolean' ||
+ json[jsonElement] === null ||
+ json[jsonElement] === undefined) &&
+ String(json[jsonElement]).includes(normalized)
+ ) {
+ paths.push(path);
+ } else if (typeof json[jsonElement] === 'object' && !(json[jsonElement] === null)) {
+ const result = searchJson(json[jsonElement], normalized, path);
+ if (result.length) {
+ paths.push(...result);
+ }
+ }
+ }
+ return paths;
+}
+
+export const jsonFlatPaths = (json, levelPath = 'root') => {
+ const paths = [];
+
+ for (const jsonElement in json) {
+ const path = `${levelPath}.${jsonElement}`;
+ if (typeof json[jsonElement] === 'object' && !(json[jsonElement] === null)) {
+ const result = jsonFlatPaths(json[jsonElement], path);
+ if (result.length) {
+ paths.push(...result);
+ }
+ } else {
+ paths.push(path);
+ }
+ }
+
+ return paths;
+};
+
+
+// source: https://codeburst.io/throttling-and-debouncing-in-javascript-646d076d0a44
+export function debounced(fn, delay) {
+ let timerId;
+ return function (...args) {
+ if (timerId) {
+ clearTimeout(timerId);
+ }
+ timerId = setTimeout(() => {
+ fn(...args);
+ timerId = null;
+ }, delay);
+ }
+}
diff --git a/src/js/index.js b/src/js/index.js
index f47338df..2f99df71 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -1,13 +1,13 @@
import React from 'react';
import { polyfill } from 'react-lifecycles-compat';
-import JsonViewer from './components/JsonViewer';
-import AddKeyRequest from './components/ObjectKeyModal/AddKeyRequest';
-import ValidationFailure from './components/ValidationFailure';
-import { toType, isTheme } from './helpers/util';
+import { toType, isTheme, searchJson, debounced, jsonFlatPaths } from './helpers/util';
import ObjectAttributes from './stores/ObjectAttributes';
//global theme
import Theme from './themes/getStyle';
+import { ValidationFailure } from './components/ValidationFailure';
+import { AddKeyRequest } from './components/ObjectKeyModal/AddKeyRequest';
+import { JsonViewer } from './components/JsonViewer';
//forward src through to JsonObject component
class ReactJsonView extends React.PureComponent {
@@ -18,7 +18,11 @@ class ReactJsonView extends React.PureComponent {
addKeyRequest: false,
editKeyRequest: false,
validationFailure: false,
+ paths: [],
+ refs: {},
+ current: 0,
src: ReactJsonView.defaultProps.src,
+ searchable: ReactJsonView.defaultProps.searchable,
name: ReactJsonView.defaultProps.name,
theme: ReactJsonView.defaultProps.theme,
validationMessage: ReactJsonView.defaultProps.validationMessage,
@@ -56,7 +60,8 @@ class ReactJsonView extends React.PureComponent {
style: {},
validationMessage: 'Validation Error',
defaultValue: null,
- displayArrayKey: true
+ displayArrayKey: true,
+ searchable: false
};
// will trigger whenever setState() is called, or parent passes in new props.
@@ -67,14 +72,22 @@ class ReactJsonView extends React.PureComponent {
nextProps.theme !== prevState.prevTheme
) {
// if we pass in new props, we re-validate
+ const allPaths = jsonFlatPaths(nextProps.src, nextProps.name);
+ const refs = allPaths.reduce((acc, value) => {
+ acc[value] = React.createRef();
+ return acc;
+ }, {});
+
const newPartialState = {
src: nextProps.src,
+ refs: refs,
name: nextProps.name,
theme: nextProps.theme,
validationMessage: nextProps.validationMessage,
prevSrc: nextProps.src,
prevName: nextProps.name,
- prevTheme: nextProps.theme
+ prevTheme: nextProps.theme,
+ searchable: nextProps.searchable
};
return ReactJsonView.validateState(newPartialState);
}
@@ -108,6 +121,13 @@ class ReactJsonView extends React.PureComponent {
editKeyRequest: false
});
}
+ if (prevState.current !== this.state.current && this.state.paths.length) {
+ console.log(this.state.paths[this.state.current]);
+ this.state.refs[this.state.paths[this.state.current]].current.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start',
+ });
+ }
if (prevProps.src !== this.state.src) {
ObjectAttributes.set(this.rjvId, 'global', 'src', this.state.src);
}
@@ -158,6 +178,32 @@ class ReactJsonView extends React.PureComponent {
};
};
+ setPaths = debounced(searchTerm => {
+ const paths = searchJson(this.state.src, searchTerm, this.state.name)
+ this.setState({
+ paths,
+ current: paths.length && 0
+ })
+ }, 300)
+
+ handleSearch(e) {
+ this.setPaths(e.target.value);
+ }
+
+ handleDown = () => {
+ const expectedIndex = this.state.current + 1;
+ this.setState({
+ current: expectedIndex >= this.state.paths.length ? 0: expectedIndex,
+ })
+ }
+
+ handleUp = () => {
+ const expectedIndex = this.state.current - 1;
+ this.setState({
+ current: expectedIndex < 0 ? this.state.paths.length - 1: expectedIndex,
+ })
+ }
+
render() {
const {
validationFailure,
@@ -165,7 +211,11 @@ class ReactJsonView extends React.PureComponent {
addKeyRequest,
theme,
src,
- name
+ name,
+ paths,
+ searchable,
+ refs,
+ current,
} = this.state;
const { style, defaultValue } = this.props;
@@ -181,9 +231,22 @@ class ReactJsonView extends React.PureComponent {
theme={theme}
rjvId={this.rjvId}
/>
+
+ {searchable &&
+
+
{Boolean(paths.length) && `${current + 1} of ${paths.length}`}
+
this.handleSearch(e)} />
+
+
+
+
}
+