@uiw/react-json-view 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,7 @@ react-json-view
4
4
  [![CI](https://github.com/uiwjs/react-json-view/actions/workflows/ci.yml/badge.svg)](https://github.com/uiwjs/react-json-view/actions/workflows/ci.yml)
5
5
  [![npm version](https://img.shields.io/npm/v/@uiw/react-json-view.svg)](https://www.npmjs.com/package/@uiw/react-json-view)
6
6
  [![react@^18](https://shields.io/badge/react-^18-green?style=flat&logo=react)](https://github.com/facebook/react/releases)
7
+ [![Coverage Status](https://uiwjs.github.io/react-json-view/badges.svg)](https://uiwjs.github.io/react-json-view/lcov-report/)
7
8
 
8
9
  A React component for displaying and editing javascript arrays and JSON objects.
9
10
 
@@ -22,7 +23,8 @@ A React component for displaying and editing javascript arrays and JSON objects.
22
23
  📚 Use Typescript to write, better code hints.
23
24
  🎨 Support theme customization & [`online editing`](https://uiwjs.github.io/react-json-view/#online-editing-theme) theme
24
25
  🌒 Support dark/light mode
25
- 📦 Zero dependencies
26
+ 📦 Zero dependencies
27
+ ♻️ Whether to highlight updates.
26
28
 
27
29
  ## Quick Start
28
30
 
@@ -111,6 +113,7 @@ const customTheme = {
111
113
  '--w-rjv-line-color': '#323232',
112
114
  '--w-rjv-arrow-color': 'var(--w-rjv-color)',
113
115
  '--w-rjv-info-color': '#656565',
116
+ '--w-rjv-update-color': '#ebcb8b',
114
117
  '--w-rjv-copied-color': '#9cdcfe',
115
118
  '--w-rjv-copied-success-color': '#28a745',
116
119
 
@@ -140,7 +143,7 @@ export default function Demo() {
140
143
  Online custom style example, please check in the [documentation website](https://uiwjs.github.io/react-json-view/)
141
144
 
142
145
  ```tsx mdx:preview:&title=Online Editing Theme
143
- import React, { useState, useRef } from 'react';
146
+ import React, { useState, useEffect, useRef } from 'react';
144
147
  import Colorful from '@uiw/react-color-colorful';
145
148
  import JsonView from '@uiw/react-json-view';
146
149
 
@@ -172,6 +175,7 @@ const customTheme = {
172
175
  '--w-rjv-line-color': '#323232',
173
176
  '--w-rjv-arrow-color': '#9cdcfe',
174
177
  '--w-rjv-info-color': '#656565',
178
+ '--w-rjv-update-color': '#ebcb8b',
175
179
  '--w-rjv-copied-color': '#0184a6',
176
180
  '--w-rjv-copied-success-color': '#28a745',
177
181
 
@@ -197,10 +201,23 @@ export default function Demo() {
197
201
  setHex(hexa);
198
202
  setTheme({ ...theme, [cssvar]: hexa });
199
203
  };
204
+
205
+ const [src, setSrc] = useState({ ...object })
206
+ useEffect(() => {
207
+ const loop = () => {
208
+ setSrc(src => ({
209
+ ...src,
210
+ timer: src.timer + 1
211
+ }))
212
+ }
213
+ const id = setInterval(loop, 1000)
214
+ return () => clearInterval(id)
215
+ }, []);
216
+
200
217
  return (
201
218
  <React.Fragment>
202
219
  <div style={{ display: 'flex', gap: '1rem' }}>
203
- <JsonView value={object} keyName="root" style={{ flex: 1, ...theme }} />
220
+ <JsonView value={src} keyName="root" style={{ flex: 1, ...theme }} />
204
221
  <div>
205
222
  <Colorful color={hex} onChange={onChange} />
206
223
  <div style={{ display: 'flex', gap: '0.4rem', flexWrap: 'wrap' }}>
@@ -305,6 +322,50 @@ export default function Demo() {
305
322
  }
306
323
  ```
307
324
 
325
+ ## Highlight Updates
326
+
327
+ ```tsx mdx:preview
328
+ import React, { useState, useEffect } from 'react';
329
+ import JsonView from '@uiw/react-json-view';
330
+ import { TriangleArrow } from '@uiw/react-json-view/triangle-arrow';
331
+ import { TriangleSolidArrow } from '@uiw/react-json-view/triangle-solid-arrow';
332
+
333
+ const object = {
334
+ string: 'Lorem ipsum dolor sit amet',
335
+ integer: 42,
336
+ timer: 0,
337
+ object: { 'first-child': true, 'second-child': false, 'last-child': null },
338
+ }
339
+ export default function Demo() {
340
+ const [src, setSrc] = useState({ ...object })
341
+ useEffect(() => {
342
+ const loop = () => {
343
+ setSrc(src => ({
344
+ ...src,
345
+ timer: src.timer + 1
346
+ }))
347
+ }
348
+ const id = setInterval(loop, 1000)
349
+ return () => clearInterval(id)
350
+ }, []);
351
+
352
+ return (
353
+ <JsonView
354
+ value={src}
355
+ keyName="root"
356
+ style={{
357
+ '--w-rjv-background-color': '#ffffff',
358
+ '--w-rjv-border-left': '1px dashed #ebebeb',
359
+ // ✅ Change default update background color ✅
360
+ '--w-rjv-update-color': '#ff6ffd',
361
+ }}
362
+ />
363
+ )
364
+ }
365
+ ```
366
+
367
+ This feature can be disabled with `highlightUpdates={false}`, and the default color can be changed with `--w-rjv-update-color`.
368
+
308
369
  ## Modify Icon Style
309
370
 
310
371
  Use built-in default icons.
@@ -424,6 +485,10 @@ export interface JsonViewProps<T> extends React.DetailedHTMLProps<React.HTMLAttr
424
485
  keyName?: string | number;
425
486
  /** The user can copy objects and arrays to clipboard by clicking on the clipboard icon. @default true */
426
487
  enableClipboard?: boolean;
488
+ /** Whether to highlight updates. @default true */
489
+ highlightUpdates?: boolean;
490
+ /** Whether sort keys through `String.prototype.localeCompare()` @default false */
491
+ objectSortKeys?: boolean | ((a: string, b: string) => number);
427
492
  /** Display for quotes in object-key @default " */
428
493
  quotes?: "'" | '"' | '';
429
494
  /** When set to true, all nodes will be collapsed by default. Use an integer value to collapse at a particular depth. @default false */
@@ -435,6 +500,8 @@ export interface JsonViewProps<T> extends React.DetailedHTMLProps<React.HTMLAttr
435
500
  keyid: string;
436
501
  keyName?: string | number;
437
502
  }) => void;
503
+ /** Fires event when you copy */
504
+ onCopied?: CopiedProps<T>['onCopied'];
438
505
  /** Redefine interface elements to re-render. */
439
506
  components?: {
440
507
  braces?: MetaProps['render'];
@@ -442,6 +509,7 @@ export interface JsonViewProps<T> extends React.DetailedHTMLProps<React.HTMLAttr
442
509
  arrow?: JSX.Element;
443
510
  objectKey?: SemicolonProps['render'];
444
511
  value?: ValueViewProps<T>['renderValue'];
512
+ copied?: CopiedProps<T>['render'];
445
513
  };
446
514
  }
447
515
  declare const JsonView: React.ForwardRefExoticComponent<Omit<JsonViewProps<object>, "ref"> & React.RefAttributes<HTMLDivElement>>;
package/cjs/copied.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  export interface CopiedProps<T = object> extends React.SVGProps<SVGSVGElement> {
3
3
  show?: boolean;
4
4
  text?: T;
5
- onCopied?: (text: string, obj: T) => void;
5
+ onCopied?: (text: string, obj: T | '') => void;
6
6
  render?: (props: Omit<CopiedProps<T>, 'render'>) => JSX.Element;
7
7
  }
8
8
  export declare function Copied<T>(props: CopiedProps<T>): JSX.Element | null;
package/cjs/copied.js CHANGED
@@ -10,12 +10,13 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
10
10
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
11
11
  var _react = require("react");
12
12
  var _jsxRuntime = require("react/jsx-runtime");
13
- var _excluded = ["children", "style", "text", "render", "show"];
13
+ var _excluded = ["children", "style", "text", "onCopied", "render", "show"];
14
14
  function Copied(props) {
15
15
  var children = props.children,
16
16
  style = props.style,
17
17
  _props$text = props.text,
18
18
  text = _props$text === void 0 ? '' : _props$text,
19
+ onCopied = props.onCopied,
19
20
  render = props.render,
20
21
  show = props.show,
21
22
  reset = (0, _objectWithoutProperties2["default"])(props, _excluded);
@@ -26,7 +27,7 @@ function Copied(props) {
26
27
  setCopied = _useState2[1];
27
28
  var click = function click(event) {
28
29
  event.stopPropagation();
29
- var copyText = JSON.stringify(text, function (key, value) {
30
+ var copyText = JSON.stringify(text || '', function (key, value) {
30
31
  if (typeof value === 'bigint') {
31
32
  return value.toString();
32
33
  }
@@ -34,6 +35,7 @@ function Copied(props) {
34
35
  }, 2);
35
36
  if (text === Infinity) copyText = Infinity;
36
37
  navigator.clipboard.writeText(copyText).then(function () {
38
+ onCopied && onCopied(copyText, text);
37
39
  setCopied(true);
38
40
  var timer = setTimeout(function () {
39
41
  setCopied(false);
package/cjs/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { MetaProps, SemicolonProps, EllipsisProps } from './node';
2
+ import { MetaProps, EllipsisProps } from './node';
3
+ import { SemicolonProps } from './semicolon';
3
4
  import { ValueViewProps } from './value';
4
5
  import { CopiedProps } from './copied';
5
6
  export * from './node';
@@ -17,6 +18,10 @@ export interface JsonViewProps<T extends object> extends React.DetailedHTMLProps
17
18
  keyName?: string | number;
18
19
  /** The user can copy objects and arrays to clipboard by clicking on the clipboard icon. @default true */
19
20
  enableClipboard?: boolean;
21
+ /** Whether to highlight updates. @default true */
22
+ highlightUpdates?: boolean;
23
+ /** Whether sort keys through `String.prototype.localeCompare()` @default false */
24
+ objectSortKeys?: boolean | ((a: string, b: string) => number);
20
25
  /** Display for quotes in object-key @default " */
21
26
  quotes?: "'" | '"' | '';
22
27
  /** When set to true, all nodes will be collapsed by default. Use an integer value to collapse at a particular depth. @default false */
package/cjs/node.d.ts CHANGED
@@ -11,13 +11,6 @@ export interface EllipsisProps extends React.HTMLAttributes<HTMLSpanElement> {
11
11
  render?: (props: EllipsisProps) => JSX.Element;
12
12
  }
13
13
  export declare const Ellipsis: FC<PropsWithChildren<EllipsisProps>>;
14
- export interface SemicolonProps extends LabelProps {
15
- show?: boolean;
16
- quotes?: JsonViewProps<object>['quotes'];
17
- value?: object;
18
- render?: (props: Omit<SemicolonProps, 'show'> & {}) => JSX.Element;
19
- }
20
- export declare const Semicolon: FC<PropsWithChildren<SemicolonProps>>;
21
14
  export declare const CountInfo: FC<PropsWithChildren<LabelProps>>;
22
15
  export interface RooNodeProps<T extends object> extends JsonViewProps<T> {
23
16
  keyName?: string | number;
package/cjs/node.js CHANGED
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.Ellipsis = exports.CountInfo = void 0;
8
8
  exports.Meta = Meta;
9
9
  exports.RooNode = RooNode;
10
- exports.Semicolon = void 0;
11
10
  var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
12
11
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
13
12
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
@@ -17,11 +16,11 @@ var _value = require("./value");
17
16
  var _TriangleArrow = require("./arrow/TriangleArrow");
18
17
  var _store = require("./store");
19
18
  var _copied = require("./copied");
19
+ var _semicolon = require("./semicolon");
20
20
  var _jsxRuntime = require("react/jsx-runtime");
21
21
  var _excluded = ["isArray", "start", "className", "render"],
22
22
  _excluded2 = ["style", "render"],
23
- _excluded3 = ["children", "render", "color", "value", "className", "show", "quotes"],
24
- _excluded4 = ["value", "keyName", "displayDataTypes", "components", "displayObjectSize", "enableClipboard", "indentWidth", "collapsed", "level", "keyid", "quotes", "onCopied", "onExpand"];
23
+ _excluded3 = ["value", "keyName", "className", "displayDataTypes", "components", "displayObjectSize", "enableClipboard", "highlightUpdates", "objectSortKeys", "indentWidth", "collapsed", "level", "keyid", "quotes", "onCopied", "onExpand"];
25
24
  function Meta(props) {
26
25
  var _props$isArray = props.isArray,
27
26
  isArray = _props$isArray === void 0 ? false : _props$isArray,
@@ -69,36 +68,8 @@ var Ellipsis = function Ellipsis(_ref) {
69
68
  }));
70
69
  };
71
70
  exports.Ellipsis = Ellipsis;
72
- var Semicolon = function Semicolon(_ref2) {
73
- var children = _ref2.children,
74
- render = _ref2.render,
75
- color = _ref2.color,
76
- value = _ref2.value,
77
- _ref2$className = _ref2.className,
78
- className = _ref2$className === void 0 ? 'w-rjv-object-key' : _ref2$className,
79
- show = _ref2.show,
80
- quotes = _ref2.quotes,
81
- props = (0, _objectWithoutProperties2["default"])(_ref2, _excluded3);
82
- var content = show ? "".concat(quotes).concat(children).concat(quotes) : children;
83
- if (render) return render((0, _objectSpread2["default"])((0, _objectSpread2["default"])({
84
- className: className
85
- }, props), {}, {
86
- value: value,
87
- style: {
88
- color: color
89
- },
90
- children: content
91
- }));
92
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_value.Label, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({
93
- className: className,
94
- color: color
95
- }, props), {}, {
96
- children: content
97
- }));
98
- };
99
- exports.Semicolon = Semicolon;
100
- var CountInfo = function CountInfo(_ref3) {
101
- var children = _ref3.children;
71
+ var CountInfo = function CountInfo(_ref2) {
72
+ var children = _ref2.children;
102
73
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_value.Label, {
103
74
  style: {
104
75
  paddingLeft: 4,
@@ -115,6 +86,7 @@ function RooNode(props) {
115
86
  var _props$value = props.value,
116
87
  value = _props$value === void 0 ? {} : _props$value,
117
88
  keyName = props.keyName,
89
+ className = props.className,
118
90
  _props$displayDataTyp = props.displayDataTypes,
119
91
  displayDataTypes = _props$displayDataTyp === void 0 ? true : _props$displayDataTyp,
120
92
  _props$components = props.components,
@@ -123,6 +95,10 @@ function RooNode(props) {
123
95
  displayObjectSize = _props$displayObjectS === void 0 ? true : _props$displayObjectS,
124
96
  _props$enableClipboar = props.enableClipboard,
125
97
  enableClipboard = _props$enableClipboar === void 0 ? true : _props$enableClipboar,
98
+ _props$highlightUpdat = props.highlightUpdates,
99
+ highlightUpdates = _props$highlightUpdat === void 0 ? true : _props$highlightUpdat,
100
+ _props$objectSortKeys = props.objectSortKeys,
101
+ objectSortKeys = _props$objectSortKeys === void 0 ? false : _props$objectSortKeys,
126
102
  _props$indentWidth = props.indentWidth,
127
103
  indentWidth = _props$indentWidth === void 0 ? 15 : _props$indentWidth,
128
104
  collapsed = props.collapsed,
@@ -134,11 +110,8 @@ function RooNode(props) {
134
110
  quotes = _props$quotes === void 0 ? '"' : _props$quotes,
135
111
  onCopied = props.onCopied,
136
112
  onExpand = props.onExpand,
137
- reset = (0, _objectWithoutProperties2["default"])(props, _excluded4);
113
+ reset = (0, _objectWithoutProperties2["default"])(props, _excluded3);
138
114
  var isArray = Array.isArray(value);
139
- var nameKeys = isArray ? Object.keys(value).map(function (m) {
140
- return Number(m);
141
- }) : Object.keys(value);
142
115
  var subkeyid = (0, _react.useId)();
143
116
  var expands = (0, _store.useExpandsStatus)();
144
117
  var expand = (_expands$keyid = expands[keyid]) !== null && _expands$keyid !== void 0 ? _expands$keyid : typeof collapsed === 'boolean' ? collapsed : typeof collapsed === 'number' ? level <= collapsed : true;
@@ -161,6 +134,7 @@ function RooNode(props) {
161
134
  displayDataTypes: displayDataTypes,
162
135
  displayObjectSize: displayObjectSize,
163
136
  enableClipboard: enableClipboard,
137
+ highlightUpdates: highlightUpdates,
164
138
  onCopied: onCopied,
165
139
  onExpand: onExpand,
166
140
  collapsed: collapsed,
@@ -205,8 +179,31 @@ function RooNode(props) {
205
179
  return setShowTools(false);
206
180
  };
207
181
  }
182
+ var nameKeys = isArray ? Object.keys(value).map(function (m) {
183
+ return Number(m);
184
+ }) : Object.keys(value);
185
+
186
+ // object
187
+ var entries = isArray ? Object.entries(value).map(function (m) {
188
+ return [Number(m[0]), m[1]];
189
+ }) : Object.entries(value);
190
+ if (objectSortKeys) {
191
+ entries = objectSortKeys === true ? entries.sort(function (_ref3, _ref4) {
192
+ var _ref5 = (0, _slicedToArray2["default"])(_ref3, 1),
193
+ a = _ref5[0];
194
+ var _ref6 = (0, _slicedToArray2["default"])(_ref4, 1),
195
+ b = _ref6[0];
196
+ return typeof a === 'string' && typeof b === 'string' ? a.localeCompare(b) : 0;
197
+ }) : entries.sort(function (_ref7, _ref8) {
198
+ var _ref9 = (0, _slicedToArray2["default"])(_ref7, 1),
199
+ a = _ref9[0];
200
+ var _ref10 = (0, _slicedToArray2["default"])(_ref8, 1),
201
+ b = _ref10[0];
202
+ return typeof a === 'string' && typeof b === 'string' ? objectSortKeys(a, b) : 0;
203
+ });
204
+ }
208
205
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", (0, _objectSpread2["default"])((0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, reset), {}, {
209
- className: "w-rjv-inner"
206
+ className: "".concat(className, " w-rjv-inner")
210
207
  }, eventProps), {}, {
211
208
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_value.Line, {
212
209
  style: {
@@ -215,7 +212,7 @@ function RooNode(props) {
215
212
  },
216
213
  onClick: handle,
217
214
  children: [arrowView, (typeof keyName === 'string' || typeof keyName === 'number') && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
218
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Semicolon, {
215
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_semicolon.Semicolon, {
219
216
  value: value,
220
217
  quotes: quotes,
221
218
  render: components.objectKey,
@@ -241,11 +238,15 @@ function RooNode(props) {
241
238
  borderLeft: 'var(--w-rjv-border-left-width, 1px) solid var(--w-rjv-line-color, #ebebeb)',
242
239
  marginLeft: 6
243
240
  },
244
- children: nameKeys.length > 0 && nameKeys.map(function (key, idx) {
245
- var item = value[key];
246
- var renderKey = /*#__PURE__*/(0, _jsxRuntime.jsx)(Semicolon, {
241
+ children: entries.length > 0 && entries.map(function (_ref11, idx) {
242
+ var _ref12 = (0, _slicedToArray2["default"])(_ref11, 2),
243
+ key = _ref12[0],
244
+ itemVal = _ref12[1];
245
+ var item = itemVal;
246
+ var renderKey = /*#__PURE__*/(0, _jsxRuntime.jsx)(_semicolon.Semicolon, {
247
247
  value: item,
248
248
  quotes: quotes,
249
+ highlightUpdates: highlightUpdates,
249
250
  render: components.objectKey,
250
251
  color: typeof key === 'number' ? _value.typeMap['number'].color : '',
251
252
  show: typeof key === 'string',
@@ -271,7 +272,7 @@ function RooNode(props) {
271
272
  value: item,
272
273
  keyName: key
273
274
  }, subNodeProps))
274
- }, key + idx);
275
+ }, key + '' + idx);
275
276
  }
276
277
  if (typeof item === 'function') {
277
278
  return;
@@ -0,0 +1,12 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { LabelProps } from './value';
3
+ import { JsonViewProps } from './';
4
+ export declare function usePrevious<T>(value: T): T | undefined;
5
+ export interface SemicolonProps extends LabelProps {
6
+ show?: boolean;
7
+ highlightUpdates?: boolean;
8
+ quotes?: JsonViewProps<object>['quotes'];
9
+ value?: object;
10
+ render?: (props: Omit<SemicolonProps, 'show'> & {}) => JSX.Element;
11
+ }
12
+ export declare const Semicolon: FC<PropsWithChildren<SemicolonProps>>;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.Semicolon = void 0;
8
+ exports.usePrevious = usePrevious;
9
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
10
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
11
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
12
+ var _react = require("react");
13
+ var _value = require("./value");
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+ var _excluded = ["children", "render", "color", "value", "className", "show", "highlightUpdates", "quotes", "style"];
16
+ function usePrevious(value) {
17
+ var ref = (0, _react.useRef)();
18
+ (0, _react.useEffect)(function () {
19
+ ref.current = value;
20
+ });
21
+ return ref.current;
22
+ }
23
+ var Semicolon = function Semicolon(_ref) {
24
+ var children = _ref.children,
25
+ render = _ref.render,
26
+ color = _ref.color,
27
+ value = _ref.value,
28
+ _ref$className = _ref.className,
29
+ className = _ref$className === void 0 ? 'w-rjv-object-key' : _ref$className,
30
+ show = _ref.show,
31
+ highlightUpdates = _ref.highlightUpdates,
32
+ quotes = _ref.quotes,
33
+ style = _ref.style,
34
+ props = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
35
+ var prevValue = usePrevious(value);
36
+ var highlightContainer = (0, _react.useRef)(null);
37
+ var isHighlight = (0, _react.useMemo)(function () {
38
+ if (!highlightUpdates || prevValue === undefined) return false;
39
+ // highlight if value type changed
40
+ if ((0, _typeof2["default"])(value) !== (0, _typeof2["default"])(prevValue)) {
41
+ return true;
42
+ }
43
+ if (typeof value === 'number') {
44
+ // notice: NaN !== NaN
45
+ if (isNaN(value) && isNaN(prevValue)) return false;
46
+ return value !== prevValue;
47
+ }
48
+ // highlight if isArray changed
49
+ if (Array.isArray(value) !== Array.isArray(prevValue)) {
50
+ return true;
51
+ }
52
+ // not highlight object/function
53
+ // deep compare they will be slow
54
+ if ((0, _typeof2["default"])(value) === 'object' || typeof value === 'function') {
55
+ return false;
56
+ }
57
+
58
+ // highlight if not equal
59
+ if (value !== prevValue) {
60
+ return true;
61
+ }
62
+ return false;
63
+ }, [highlightUpdates, value]);
64
+ (0, _react.useEffect)(function () {
65
+ if (highlightContainer.current && isHighlight && 'animate' in highlightContainer.current) {
66
+ highlightContainer.current.animate([{
67
+ backgroundColor: 'var(--w-rjv-update-color, #ebcb8b)'
68
+ }, {
69
+ backgroundColor: ''
70
+ }], {
71
+ duration: 1000,
72
+ easing: 'ease-in'
73
+ });
74
+ }
75
+ }, [isHighlight, value]);
76
+ var content = show ? "".concat(quotes).concat(children).concat(quotes) : children;
77
+ if (render) return render((0, _objectSpread2["default"])((0, _objectSpread2["default"])({
78
+ className: className
79
+ }, props), {}, {
80
+ value: value,
81
+ style: (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, style), {}, {
82
+ color: color
83
+ }),
84
+ children: content
85
+ }));
86
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_value.Label, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({
87
+ className: className,
88
+ color: color
89
+ }, props), {}, {
90
+ ref: highlightContainer,
91
+ children: content
92
+ }));
93
+ };
94
+ exports.Semicolon = Semicolon;
@@ -5,6 +5,7 @@ export declare const darkTheme: {
5
5
  '--w-rjv-line-color': string;
6
6
  '--w-rjv-arrow-color': string;
7
7
  '--w-rjv-info-color': string;
8
+ '--w-rjv-update-color': string;
8
9
  '--w-rjv-copied-color': string;
9
10
  '--w-rjv-copied-success-color': string;
10
11
  '--w-rjv-curlybraces-color': string;
package/cjs/theme/dark.js CHANGED
@@ -11,6 +11,7 @@ var darkTheme = {
11
11
  '--w-rjv-line-color': '#323232',
12
12
  '--w-rjv-arrow-color': 'var(--w-rjv-color)',
13
13
  '--w-rjv-info-color': '#656565',
14
+ '--w-rjv-update-color': '#ebcb8b',
14
15
  '--w-rjv-copied-color': '#0184a6',
15
16
  '--w-rjv-copied-success-color': '#28a745',
16
17
  '--w-rjv-curlybraces-color': '#1896b6',
@@ -5,6 +5,7 @@ export declare const lightTheme: {
5
5
  '--w-rjv-line-color': string;
6
6
  '--w-rjv-arrow-color': string;
7
7
  '--w-rjv-info-color': string;
8
+ '--w-rjv-update-color': string;
8
9
  '--w-rjv-copied-color': string;
9
10
  '--w-rjv-copied-success-color': string;
10
11
  '--w-rjv-curlybraces-color': string;
@@ -11,6 +11,7 @@ var lightTheme = {
11
11
  '--w-rjv-line-color': '#ebebeb',
12
12
  '--w-rjv-arrow-color': 'var(--w-rjv-color)',
13
13
  '--w-rjv-info-color': '#0000004d',
14
+ '--w-rjv-update-color': '#ebcb8b',
14
15
  '--w-rjv-copied-color': '#002b36',
15
16
  '--w-rjv-copied-success-color': '#28a745',
16
17
  '--w-rjv-curlybraces-color': '#236a7c',
package/cjs/value.d.ts CHANGED
@@ -41,7 +41,7 @@ export declare const typeMap: {
41
41
  };
42
42
  export declare const Colon: FC<PropsWithChildren<React.HTMLAttributes<HTMLSpanElement>>>;
43
43
  export interface ValueViewProps<T> extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
44
- keyName?: string;
44
+ keyName?: string | number;
45
45
  value?: T;
46
46
  displayDataTypes: boolean;
47
47
  displayObjectSize: boolean;
@@ -60,7 +60,7 @@ export interface LabelProps extends React.HTMLAttributes<HTMLSpanElement> {
60
60
  opacity?: number;
61
61
  paddingRight?: number;
62
62
  }
63
- export declare const Label: FC<PropsWithChildren<LabelProps>>;
63
+ export declare const Label: import("react").ForwardRefExoticComponent<LabelProps & import("react").RefAttributes<HTMLSpanElement>>;
64
64
  export interface TypeProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
65
65
  type: keyof typeof typeMap;
66
66
  }
package/cjs/value.js CHANGED
@@ -174,6 +174,7 @@ function ValueView(props) {
174
174
  });
175
175
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Line, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, eventProps), {}, {
176
176
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(Label, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, reset), {}, {
177
+ ref: null,
177
178
  children: [renderKey, /*#__PURE__*/(0, _jsxRuntime.jsx)(Colon, {}), typeView, valueView, tools]
178
179
  }))
179
180
  }));
@@ -193,11 +194,12 @@ function ValueView(props) {
193
194
  });
194
195
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Line, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, eventProps), {}, {
195
196
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(Label, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, reset), {}, {
197
+ ref: null,
196
198
  children: [renderKey, /*#__PURE__*/(0, _jsxRuntime.jsx)(Colon, {}), typeView, empty, tools]
197
199
  }))
198
200
  }));
199
201
  }
200
- var Label = function Label(_ref2) {
202
+ var Label = /*#__PURE__*/(0, _react.forwardRef)(function (_ref2, ref) {
201
203
  var children = _ref2.children,
202
204
  color = _ref2.color,
203
205
  fontSize = _ref2.fontSize,
@@ -213,9 +215,10 @@ var Label = function Label(_ref2) {
213
215
  paddingRight: paddingRight
214
216
  }, style)
215
217
  }, reset), {}, {
218
+ ref: ref,
216
219
  children: children
217
220
  }));
218
- };
221
+ });
219
222
  exports.Label = Label;
220
223
  var Type = function Type(props) {
221
224
  var _typeMap$type2, _typeMap$type3;
package/esm/copied.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  export interface CopiedProps<T = object> extends React.SVGProps<SVGSVGElement> {
3
3
  show?: boolean;
4
4
  text?: T;
5
- onCopied?: (text: string, obj: T) => void;
5
+ onCopied?: (text: string, obj: T | '') => void;
6
6
  render?: (props: Omit<CopiedProps<T>, 'render'>) => JSX.Element;
7
7
  }
8
8
  export declare function Copied<T>(props: CopiedProps<T>): JSX.Element | null;
package/esm/copied.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
3
- var _excluded = ["children", "style", "text", "render", "show"];
3
+ var _excluded = ["children", "style", "text", "onCopied", "render", "show"];
4
4
  import { useState } from 'react';
5
5
  import { jsx as _jsx } from "react/jsx-runtime";
6
6
  export function Copied(props) {
7
7
  var {
8
8
  style,
9
9
  text = '',
10
+ onCopied,
10
11
  render,
11
12
  show
12
13
  } = props,
@@ -15,7 +16,7 @@ export function Copied(props) {
15
16
  var [copied, setCopied] = useState(false);
16
17
  var click = event => {
17
18
  event.stopPropagation();
18
- var copyText = JSON.stringify(text, (key, value) => {
19
+ var copyText = JSON.stringify(text || '', (key, value) => {
19
20
  if (typeof value === 'bigint') {
20
21
  return value.toString();
21
22
  }
@@ -23,6 +24,7 @@ export function Copied(props) {
23
24
  }, 2);
24
25
  if (text === Infinity) copyText = Infinity;
25
26
  navigator.clipboard.writeText(copyText).then(() => {
27
+ onCopied && onCopied(copyText, text);
26
28
  setCopied(true);
27
29
  var timer = setTimeout(() => {
28
30
  setCopied(false);
package/esm/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { MetaProps, SemicolonProps, EllipsisProps } from './node';
2
+ import { MetaProps, EllipsisProps } from './node';
3
+ import { SemicolonProps } from './semicolon';
3
4
  import { ValueViewProps } from './value';
4
5
  import { CopiedProps } from './copied';
5
6
  export * from './node';
@@ -17,6 +18,10 @@ export interface JsonViewProps<T extends object> extends React.DetailedHTMLProps
17
18
  keyName?: string | number;
18
19
  /** The user can copy objects and arrays to clipboard by clicking on the clipboard icon. @default true */
19
20
  enableClipboard?: boolean;
21
+ /** Whether to highlight updates. @default true */
22
+ highlightUpdates?: boolean;
23
+ /** Whether sort keys through `String.prototype.localeCompare()` @default false */
24
+ objectSortKeys?: boolean | ((a: string, b: string) => number);
20
25
  /** Display for quotes in object-key @default " */
21
26
  quotes?: "'" | '"' | '';
22
27
  /** When set to true, all nodes will be collapsed by default. Use an integer value to collapse at a particular depth. @default false */
package/esm/node.d.ts CHANGED
@@ -11,13 +11,6 @@ export interface EllipsisProps extends React.HTMLAttributes<HTMLSpanElement> {
11
11
  render?: (props: EllipsisProps) => JSX.Element;
12
12
  }
13
13
  export declare const Ellipsis: FC<PropsWithChildren<EllipsisProps>>;
14
- export interface SemicolonProps extends LabelProps {
15
- show?: boolean;
16
- quotes?: JsonViewProps<object>['quotes'];
17
- value?: object;
18
- render?: (props: Omit<SemicolonProps, 'show'> & {}) => JSX.Element;
19
- }
20
- export declare const Semicolon: FC<PropsWithChildren<SemicolonProps>>;
21
14
  export declare const CountInfo: FC<PropsWithChildren<LabelProps>>;
22
15
  export interface RooNodeProps<T extends object> extends JsonViewProps<T> {
23
16
  keyName?: string | number;
package/esm/node.js CHANGED
@@ -2,13 +2,13 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
3
3
  var _excluded = ["isArray", "start", "className", "render"],
4
4
  _excluded2 = ["style", "render"],
5
- _excluded3 = ["children", "render", "color", "value", "className", "show", "quotes"],
6
- _excluded4 = ["value", "keyName", "displayDataTypes", "components", "displayObjectSize", "enableClipboard", "indentWidth", "collapsed", "level", "keyid", "quotes", "onCopied", "onExpand"];
5
+ _excluded3 = ["value", "keyName", "className", "displayDataTypes", "components", "displayObjectSize", "enableClipboard", "highlightUpdates", "objectSortKeys", "indentWidth", "collapsed", "level", "keyid", "quotes", "onCopied", "onExpand"];
7
6
  import { Fragment, useId, cloneElement, useState } from 'react';
8
7
  import { ValueView, Colon, Label, Line, typeMap } from './value';
9
8
  import { TriangleArrow } from './arrow/TriangleArrow';
10
9
  import { useExpandsStatus, store } from './store';
11
10
  import { Copied } from './copied';
11
+ import { Semicolon } from './semicolon';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
14
14
  export function Meta(props) {
@@ -59,38 +59,10 @@ export var Ellipsis = _ref => {
59
59
  children: "..."
60
60
  }));
61
61
  };
62
- export var Semicolon = _ref2 => {
63
- var {
64
- children,
65
- render,
66
- color,
67
- value,
68
- className = 'w-rjv-object-key',
69
- show,
70
- quotes
71
- } = _ref2,
72
- props = _objectWithoutPropertiesLoose(_ref2, _excluded3);
73
- var content = show ? "" + quotes + children + quotes : children;
74
- if (render) return render(_extends({
75
- className
76
- }, props, {
77
- value,
78
- style: {
79
- color
80
- },
81
- children: content
82
- }));
83
- return /*#__PURE__*/_jsx(Label, _extends({
84
- className: className,
85
- color: color
86
- }, props, {
87
- children: content
88
- }));
89
- };
90
- export var CountInfo = _ref3 => {
62
+ export var CountInfo = _ref2 => {
91
63
  var {
92
64
  children
93
- } = _ref3;
65
+ } = _ref2;
94
66
  return /*#__PURE__*/_jsx(Label, {
95
67
  style: {
96
68
  paddingLeft: 4,
@@ -106,10 +78,13 @@ export function RooNode(props) {
106
78
  var {
107
79
  value = {},
108
80
  keyName,
81
+ className,
109
82
  displayDataTypes = true,
110
83
  components = {},
111
84
  displayObjectSize = true,
112
85
  enableClipboard = true,
86
+ highlightUpdates = true,
87
+ objectSortKeys = false,
113
88
  indentWidth = 15,
114
89
  collapsed,
115
90
  level = 1,
@@ -118,9 +93,8 @@ export function RooNode(props) {
118
93
  onCopied,
119
94
  onExpand
120
95
  } = props,
121
- reset = _objectWithoutPropertiesLoose(props, _excluded4);
96
+ reset = _objectWithoutPropertiesLoose(props, _excluded3);
122
97
  var isArray = Array.isArray(value);
123
- var nameKeys = isArray ? Object.keys(value).map(m => Number(m)) : Object.keys(value);
124
98
  var subkeyid = useId();
125
99
  var expands = useExpandsStatus();
126
100
  var expand = (_expands$keyid = expands[keyid]) != null ? _expands$keyid : typeof collapsed === 'boolean' ? collapsed : typeof collapsed === 'number' ? level <= collapsed : true;
@@ -143,6 +117,7 @@ export function RooNode(props) {
143
117
  displayDataTypes,
144
118
  displayObjectSize,
145
119
  enableClipboard,
120
+ highlightUpdates,
146
121
  onCopied,
147
122
  onExpand,
148
123
  collapsed,
@@ -180,8 +155,23 @@ export function RooNode(props) {
180
155
  eventProps.onMouseEnter = () => setShowTools(true);
181
156
  eventProps.onMouseLeave = () => setShowTools(false);
182
157
  }
158
+ var nameKeys = isArray ? Object.keys(value).map(m => Number(m)) : Object.keys(value);
159
+
160
+ // object
161
+ var entries = isArray ? Object.entries(value).map(m => [Number(m[0]), m[1]]) : Object.entries(value);
162
+ if (objectSortKeys) {
163
+ entries = objectSortKeys === true ? entries.sort((_ref3, _ref4) => {
164
+ var [a] = _ref3;
165
+ var [b] = _ref4;
166
+ return typeof a === 'string' && typeof b === 'string' ? a.localeCompare(b) : 0;
167
+ }) : entries.sort((_ref5, _ref6) => {
168
+ var [a] = _ref5;
169
+ var [b] = _ref6;
170
+ return typeof a === 'string' && typeof b === 'string' ? objectSortKeys(a, b) : 0;
171
+ });
172
+ }
183
173
  return /*#__PURE__*/_jsxs("div", _extends({}, reset, {
184
- className: "w-rjv-inner"
174
+ className: className + " w-rjv-inner"
185
175
  }, eventProps, {
186
176
  children: [/*#__PURE__*/_jsxs(Line, {
187
177
  style: {
@@ -216,11 +206,13 @@ export function RooNode(props) {
216
206
  borderLeft: 'var(--w-rjv-border-left-width, 1px) solid var(--w-rjv-line-color, #ebebeb)',
217
207
  marginLeft: 6
218
208
  },
219
- children: nameKeys.length > 0 && nameKeys.map((key, idx) => {
220
- var item = value[key];
209
+ children: entries.length > 0 && entries.map((_ref7, idx) => {
210
+ var [key, itemVal] = _ref7;
211
+ var item = itemVal;
221
212
  var renderKey = /*#__PURE__*/_jsx(Semicolon, {
222
213
  value: item,
223
214
  quotes: quotes,
215
+ highlightUpdates: highlightUpdates,
224
216
  render: components.objectKey,
225
217
  color: typeof key === 'number' ? typeMap['number'].color : '',
226
218
  show: typeof key === 'string',
@@ -246,7 +238,7 @@ export function RooNode(props) {
246
238
  value: item,
247
239
  keyName: key
248
240
  }, subNodeProps))
249
- }, key + idx);
241
+ }, key + '' + idx);
250
242
  }
251
243
  if (typeof item === 'function') {
252
244
  return;
@@ -0,0 +1,12 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { LabelProps } from './value';
3
+ import { JsonViewProps } from './';
4
+ export declare function usePrevious<T>(value: T): T | undefined;
5
+ export interface SemicolonProps extends LabelProps {
6
+ show?: boolean;
7
+ highlightUpdates?: boolean;
8
+ quotes?: JsonViewProps<object>['quotes'];
9
+ value?: object;
10
+ render?: (props: Omit<SemicolonProps, 'show'> & {}) => JSX.Element;
11
+ }
12
+ export declare const Semicolon: FC<PropsWithChildren<SemicolonProps>>;
@@ -0,0 +1,85 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
3
+ var _excluded = ["children", "render", "color", "value", "className", "show", "highlightUpdates", "quotes", "style"];
4
+ import { useMemo, useRef, useEffect } from 'react';
5
+ import { Label } from './value';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export function usePrevious(value) {
8
+ var ref = useRef();
9
+ useEffect(() => {
10
+ ref.current = value;
11
+ });
12
+ return ref.current;
13
+ }
14
+ export var Semicolon = _ref => {
15
+ var {
16
+ children,
17
+ render,
18
+ color,
19
+ value,
20
+ className = 'w-rjv-object-key',
21
+ show,
22
+ highlightUpdates,
23
+ quotes,
24
+ style
25
+ } = _ref,
26
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
27
+ var prevValue = usePrevious(value);
28
+ var highlightContainer = useRef(null);
29
+ var isHighlight = useMemo(() => {
30
+ if (!highlightUpdates || prevValue === undefined) return false;
31
+ // highlight if value type changed
32
+ if (typeof value !== typeof prevValue) {
33
+ return true;
34
+ }
35
+ if (typeof value === 'number') {
36
+ // notice: NaN !== NaN
37
+ if (isNaN(value) && isNaN(prevValue)) return false;
38
+ return value !== prevValue;
39
+ }
40
+ // highlight if isArray changed
41
+ if (Array.isArray(value) !== Array.isArray(prevValue)) {
42
+ return true;
43
+ }
44
+ // not highlight object/function
45
+ // deep compare they will be slow
46
+ if (typeof value === 'object' || typeof value === 'function') {
47
+ return false;
48
+ }
49
+
50
+ // highlight if not equal
51
+ if (value !== prevValue) {
52
+ return true;
53
+ }
54
+ return false;
55
+ }, [highlightUpdates, value]);
56
+ useEffect(() => {
57
+ if (highlightContainer.current && isHighlight && 'animate' in highlightContainer.current) {
58
+ highlightContainer.current.animate([{
59
+ backgroundColor: 'var(--w-rjv-update-color, #ebcb8b)'
60
+ }, {
61
+ backgroundColor: ''
62
+ }], {
63
+ duration: 1000,
64
+ easing: 'ease-in'
65
+ });
66
+ }
67
+ }, [isHighlight, value]);
68
+ var content = show ? "" + quotes + children + quotes : children;
69
+ if (render) return render(_extends({
70
+ className
71
+ }, props, {
72
+ value,
73
+ style: _extends({}, style, {
74
+ color
75
+ }),
76
+ children: content
77
+ }));
78
+ return /*#__PURE__*/_jsx(Label, _extends({
79
+ className: className,
80
+ color: color
81
+ }, props, {
82
+ ref: highlightContainer,
83
+ children: content
84
+ }));
85
+ };
@@ -5,6 +5,7 @@ export declare const darkTheme: {
5
5
  '--w-rjv-line-color': string;
6
6
  '--w-rjv-arrow-color': string;
7
7
  '--w-rjv-info-color': string;
8
+ '--w-rjv-update-color': string;
8
9
  '--w-rjv-copied-color': string;
9
10
  '--w-rjv-copied-success-color': string;
10
11
  '--w-rjv-curlybraces-color': string;
package/esm/theme/dark.js CHANGED
@@ -5,6 +5,7 @@ export var darkTheme = {
5
5
  '--w-rjv-line-color': '#323232',
6
6
  '--w-rjv-arrow-color': 'var(--w-rjv-color)',
7
7
  '--w-rjv-info-color': '#656565',
8
+ '--w-rjv-update-color': '#ebcb8b',
8
9
  '--w-rjv-copied-color': '#0184a6',
9
10
  '--w-rjv-copied-success-color': '#28a745',
10
11
  '--w-rjv-curlybraces-color': '#1896b6',
@@ -5,6 +5,7 @@ export declare const lightTheme: {
5
5
  '--w-rjv-line-color': string;
6
6
  '--w-rjv-arrow-color': string;
7
7
  '--w-rjv-info-color': string;
8
+ '--w-rjv-update-color': string;
8
9
  '--w-rjv-copied-color': string;
9
10
  '--w-rjv-copied-success-color': string;
10
11
  '--w-rjv-curlybraces-color': string;
@@ -5,6 +5,7 @@ export var lightTheme = {
5
5
  '--w-rjv-line-color': '#ebebeb',
6
6
  '--w-rjv-arrow-color': 'var(--w-rjv-color)',
7
7
  '--w-rjv-info-color': '#0000004d',
8
+ '--w-rjv-update-color': '#ebcb8b',
8
9
  '--w-rjv-copied-color': '#002b36',
9
10
  '--w-rjv-copied-success-color': '#28a745',
10
11
  '--w-rjv-curlybraces-color': '#236a7c',
package/esm/value.d.ts CHANGED
@@ -41,7 +41,7 @@ export declare const typeMap: {
41
41
  };
42
42
  export declare const Colon: FC<PropsWithChildren<React.HTMLAttributes<HTMLSpanElement>>>;
43
43
  export interface ValueViewProps<T> extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
44
- keyName?: string;
44
+ keyName?: string | number;
45
45
  value?: T;
46
46
  displayDataTypes: boolean;
47
47
  displayObjectSize: boolean;
@@ -60,7 +60,7 @@ export interface LabelProps extends React.HTMLAttributes<HTMLSpanElement> {
60
60
  opacity?: number;
61
61
  paddingRight?: number;
62
62
  }
63
- export declare const Label: FC<PropsWithChildren<LabelProps>>;
63
+ export declare const Label: import("react").ForwardRefExoticComponent<LabelProps & import("react").RefAttributes<HTMLSpanElement>>;
64
64
  export interface TypeProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
65
65
  type: keyof typeof typeMap;
66
66
  }
package/esm/value.js CHANGED
@@ -3,7 +3,7 @@ import _extends from "@babel/runtime/helpers/extends";
3
3
  var _excluded = ["children", "style"],
4
4
  _excluded2 = ["value", "keyName", "indentWidth", "renderKey", "renderValue", "renderBraces", "enableClipboard", "displayObjectSize", "displayDataTypes"],
5
5
  _excluded3 = ["children", "color", "fontSize", "opacity", "paddingRight", "style"];
6
- import { Fragment, useState } from 'react';
6
+ import { Fragment, forwardRef, useState } from 'react';
7
7
  import { Meta, CountInfo } from './node';
8
8
  import { Copied } from './copied';
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -152,6 +152,7 @@ export function ValueView(props) {
152
152
  });
153
153
  return /*#__PURE__*/_jsx(Line, _extends({}, eventProps, {
154
154
  children: /*#__PURE__*/_jsxs(Label, _extends({}, reset, {
155
+ ref: null,
155
156
  children: [renderKey, /*#__PURE__*/_jsx(Colon, {}), typeView, valueView, tools]
156
157
  }))
157
158
  }));
@@ -171,11 +172,12 @@ export function ValueView(props) {
171
172
  });
172
173
  return /*#__PURE__*/_jsx(Line, _extends({}, eventProps, {
173
174
  children: /*#__PURE__*/_jsxs(Label, _extends({}, reset, {
175
+ ref: null,
174
176
  children: [renderKey, /*#__PURE__*/_jsx(Colon, {}), typeView, empty, tools]
175
177
  }))
176
178
  }));
177
179
  }
178
- export var Label = _ref2 => {
180
+ export var Label = /*#__PURE__*/forwardRef((_ref2, ref) => {
179
181
  var {
180
182
  children,
181
183
  color,
@@ -193,9 +195,10 @@ export var Label = _ref2 => {
193
195
  paddingRight
194
196
  }, style)
195
197
  }, reset, {
198
+ ref: ref,
196
199
  children: children
197
200
  }));
198
- };
201
+ });
199
202
  export var Type = props => {
200
203
  var _typeMap$type2, _typeMap$type3;
201
204
  var {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uiw/react-json-view",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "JSON viewer for react.",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -74,7 +74,10 @@
74
74
  "treeview"
75
75
  ],
76
76
  "devDependencies": {
77
+ "@testing-library/react": "^14.0.0",
78
+ "@types/react-test-renderer": "^18.0.0",
77
79
  "react": "^18.2.0",
78
- "react-dom": "^18.2.0"
80
+ "react-dom": "^18.2.0",
81
+ "react-test-renderer": "^18.2.0"
79
82
  }
80
83
  }