1
1
import { Box } from '@mui/material'
2
2
import type { ComponentProps , FC , MouseEvent } from 'react'
3
- import { useCallback , useMemo , useState } from 'react'
3
+ import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
4
4
5
5
import { useTextColor } from '../hooks/useColor'
6
6
import { useClipboard } from '../hooks/useCopyToClipboard'
@@ -21,6 +21,7 @@ import { DataBox } from './mui/DataBox'
21
21
22
22
export type DataKeyPairProps = {
23
23
value : unknown
24
+ prevValue ?: unknown
24
25
nestedIndex ?: number
25
26
editable ?: boolean
26
27
path : ( string | number ) [ ]
@@ -41,7 +42,7 @@ const IconBox: FC<IconBoxProps> = (props) => (
41
42
)
42
43
43
44
export const DataKeyPair : FC < DataKeyPairProps > = ( props ) => {
44
- const { value, path, nestedIndex } = props
45
+ const { value, prevValue , path, nestedIndex } = props
45
46
const propsEditable = props . editable ?? undefined
46
47
const storeEditable = useJsonViewerStore ( store => store . editable )
47
48
const editable = useMemo ( ( ) => {
@@ -73,6 +74,7 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
73
74
const onChange = useJsonViewerStore ( store => store . onChange )
74
75
const keyColor = useTextColor ( )
75
76
const numberKeyColor = useJsonViewerStore ( store => store . colorspace . base0C )
77
+ const highlightColor = useJsonViewerStore ( store => store . colorspace . base0F )
76
78
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents ( value , path )
77
79
const quotesOnKeys = useJsonViewerStore ( store => store . quotesOnKeys )
78
80
const rootName = useJsonViewerStore ( store => store . rootName )
@@ -82,6 +84,49 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
82
84
const enableClipboard = useJsonViewerStore ( store => store . enableClipboard )
83
85
const { copy, copied } = useClipboard ( )
84
86
87
+ const highlightUpdates = useJsonViewerStore ( store => store . highlightUpdates )
88
+ const isHighlight = useMemo ( ( ) => {
89
+ if ( ! highlightUpdates || prevValue === undefined ) return false
90
+
91
+ // highlight if value type changed
92
+ if ( typeof value !== typeof prevValue ) {
93
+ return true
94
+ }
95
+
96
+ // highlight if isArray changed
97
+ if ( Array . isArray ( value ) !== Array . isArray ( prevValue ) ) {
98
+ return true
99
+ }
100
+
101
+ // not highlight object/function
102
+ // deep compare they will be slow
103
+ if ( typeof value === 'object' || typeof value === 'function' ) {
104
+ return false
105
+ }
106
+
107
+ // highlight if not equal
108
+ if ( value !== prevValue ) {
109
+ return true
110
+ }
111
+
112
+ return false
113
+ } , [ highlightUpdates , prevValue , value ] )
114
+ const highlightContainer = useRef < HTMLElement > ( )
115
+ useEffect ( ( ) => {
116
+ if ( highlightContainer . current && isHighlight && 'animate' in highlightContainer . current ) {
117
+ highlightContainer . current . animate (
118
+ [
119
+ { backgroundColor : highlightColor } ,
120
+ { backgroundColor : '' }
121
+ ] ,
122
+ {
123
+ duration : 1000 ,
124
+ easing : 'ease-in'
125
+ }
126
+ )
127
+ }
128
+ } , [ highlightColor , isHighlight , prevValue , value ] )
129
+
85
130
const actionIcons = useMemo ( ( ) => {
86
131
if ( editing ) {
87
132
return (
@@ -166,8 +211,9 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
166
211
path,
167
212
inspect,
168
213
setInspect,
169
- value
170
- } ) , [ inspect , path , setInspect , value ] )
214
+ value,
215
+ prevValue
216
+ } ) , [ inspect , path , setInspect , value , prevValue ] )
171
217
return (
172
218
< Box
173
219
className = 'data-key-pair'
@@ -220,20 +266,22 @@ export const DataKeyPair: FC<DataKeyPairProps> = (props) => {
220
266
)
221
267
: null
222
268
}
223
- {
224
- ( isRoot
225
- ? rootName !== false
226
- ? ( quotesOnKeys ? < > "{ rootName } "</ > : < > { rootName } </ > )
227
- : null
228
- : KeyRenderer . when ( downstreamProps )
229
- ? < KeyRenderer { ...downstreamProps } />
230
- : nestedIndex === undefined && (
231
- isNumberKey
232
- ? < Box component = 'span' style = { { color : numberKeyColor } } > { key } </ Box >
233
- : quotesOnKeys ? < > "{ key } "</ > : < > { key } </ >
234
- )
235
- )
236
- }
269
+ < Box ref = { highlightContainer } component = 'span' >
270
+ {
271
+ ( isRoot
272
+ ? rootName !== false
273
+ ? ( quotesOnKeys ? < > "{ rootName } "</ > : < > { rootName } </ > )
274
+ : null
275
+ : KeyRenderer . when ( downstreamProps )
276
+ ? < KeyRenderer { ...downstreamProps } />
277
+ : nestedIndex === undefined && (
278
+ isNumberKey
279
+ ? < Box component = 'span' style = { { color : numberKeyColor } } > { key } </ Box >
280
+ : quotesOnKeys ? < > "{ key } "</ > : < > { key } </ >
281
+ )
282
+ )
283
+ }
284
+ </ Box >
237
285
{
238
286
(
239
287
isRoot
0 commit comments