mirror of
				https://github.com/reduxjs/redux-devtools.git
				synced 2025-10-31 16:07:45 +03:00 
			
		
		
		
	tentative diff highlight
This commit is contained in:
		
							parent
							
								
									61250b5562
								
							
						
					
					
						commit
						fb83a18614
					
				|  | @ -14,7 +14,7 @@ export function getDefaultStyle(props) { | |||
|     zIndex: 999, | ||||
|     fontSize: 17, | ||||
|     overflow: 'hidden', | ||||
|     opacity: 0.95, | ||||
|     opacity: 0.9, | ||||
|     color: 'white', | ||||
|     left: left ? 0 : undefined, | ||||
|     right: right ? 0 : undefined, | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ import reactMixin from 'react-mixin'; | |||
| import { ExpandedStateHandlerMixin } from './mixins'; | ||||
| import JSONArrow from './JSONArrow'; | ||||
| import grabNode from './grab-node'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -56,10 +57,14 @@ export default class JSONArrayNode extends React.Component { | |||
|   // generated them previously, we return from cache, otherwise we create
 | ||||
|   // them.
 | ||||
|   getChildNodes() { | ||||
|     let childNodes = []; | ||||
|     if (this.state.expanded && this.needsChildNodes) { | ||||
|       let childNodes = []; | ||||
|       this.props.data.forEach((element, idx) => { | ||||
|         childNodes.push(grabNode(idx, element, this.props.theme)); | ||||
|         let prevData; | ||||
|         if (typeof this.props.previousData !== 'undefined') { | ||||
|           prevData = this.props.previousData[idx]; | ||||
|         } | ||||
|         childNodes.push(grabNode(idx, element, prevData, this.props.theme)); | ||||
|       }); | ||||
|       this.needsChildNodes = false; | ||||
|       this.renderedChildren = childNodes; | ||||
|  | @ -84,11 +89,22 @@ export default class JSONArrayNode extends React.Component { | |||
|       listStyle: 'none', | ||||
|       display: (this.state.expanded) ? 'block' : 'none' | ||||
|     }; | ||||
|     let containerStyle = { ...styles.base, ...styles.parentNode }; | ||||
|     let backgroundColor = 'transparent'; | ||||
|     let containerStyle; | ||||
|     let spanStyle = { | ||||
|       ...styles.span, | ||||
|       color: this.props.theme.base0E | ||||
|     }; | ||||
|     if (typeof this.props.previousData !== 'undefined' && this.props.previousData === this.data) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     containerStyle = { | ||||
|       ...styles.base, | ||||
|       ...styles.parentNode, | ||||
|       backgroundColor | ||||
|     } | ||||
| 
 | ||||
|     if (this.state.expanded) { | ||||
|       spanStyle = { | ||||
|         ...spanStyle, | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import React from 'react'; | ||||
| import reactMixin from 'react-mixin'; | ||||
| import { SquashClickEventMixin } from './mixins'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -20,8 +21,13 @@ const styles = { | |||
| export default class JSONBooleanNode extends React.Component { | ||||
|   render() { | ||||
|     const truthString = (this.props.value) ? 'true' : 'false'; | ||||
|     let backgroundColor = 'transparent'; | ||||
|     if (this.props.previousValue !== this.props.value) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     return ( | ||||
|       <li style={styles.base} onClick={::this.handleClick}> | ||||
|       <li style={{ ...styles.base, backgroundColor }} onClick={::this.handleClick}> | ||||
|         <label style={{ | ||||
|           ...styles.label, | ||||
|           color: this.props.theme.base0D | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import React from 'react'; | ||||
| import reactMixin from 'react-mixin'; | ||||
| import { SquashClickEventMixin } from './mixins'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -19,8 +20,13 @@ const styles = { | |||
| @reactMixin.decorate(SquashClickEventMixin) | ||||
| export default class JSONNullNode extends React.Component { | ||||
|   render() { | ||||
|     let backgroundColor = 'transparent'; | ||||
|     if (this.props.previousValue !== this.props.value) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     return ( | ||||
|       <li style={styles.base} onClick={::this.handleClick}> | ||||
|       <li style={{ ...styles.base, backgroundColor }} onClick={::this.handleClick}> | ||||
|         <label style={{ | ||||
|           ...styles.label, | ||||
|           color: this.props.theme.base0D | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import React from 'react'; | ||||
| import reactMixin from 'react-mixin'; | ||||
| import { SquashClickEventMixin } from './mixins'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -19,8 +20,13 @@ const styles = { | |||
| @reactMixin.decorate(SquashClickEventMixin) | ||||
| export default class JSONNumberNode extends React.Component { | ||||
|   render() { | ||||
|     let backgroundColor = 'transparent'; | ||||
|     if (this.props.previousValue !== this.props.value) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     return ( | ||||
|       <li style={styles.base} onClick={::this.handleClick}> | ||||
|       <li style={{ ...styles.base, backgroundColor }} onClick={::this.handleClick}> | ||||
|         <label style={{ | ||||
|           ...styles.label, | ||||
|           color: this.props.theme.base0D | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ import reactMixin from 'react-mixin'; | |||
| import { ExpandedStateHandlerMixin } from './mixins'; | ||||
| import JSONArrow from './JSONArrow'; | ||||
| import grabNode from './grab-node'; | ||||
| import shallowEqual from '../../utils/shallowEqual'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -60,7 +62,11 @@ export default class JSONObjectNode extends React.Component { | |||
|       let childNodes = []; | ||||
|       for (let k in obj) { | ||||
|         if (obj.hasOwnProperty(k)) { | ||||
|           childNodes.push(grabNode(k, obj[k], this.props.theme)); | ||||
|           let prevData; | ||||
|           if (typeof this.props.previousData !== 'undefined') { | ||||
|             prevData = this.props.previousData[k]; | ||||
|           } | ||||
|           childNodes.push(grabNode(k, obj[k], prevData, this.props.theme)); | ||||
|         } | ||||
|       } | ||||
|       this.needsChildNodes = false; | ||||
|  | @ -86,11 +92,21 @@ export default class JSONObjectNode extends React.Component { | |||
|       listStyle: 'none', | ||||
|       display: (this.state.expanded) ? 'block' : 'none' | ||||
|     }; | ||||
|     let containerStyle = { ...styles.base, ...styles.parentNode }; | ||||
|     let backgroundColor = 'transparent'; | ||||
|     let containerStyle; | ||||
|     let spanStyle = { | ||||
|       ...styles.span, | ||||
|       color: this.props.theme.base0B | ||||
|     }; | ||||
|     if (typeof this.props.previousData !== 'undefined' && !shallowEqual(this.props.data, this.props.previousData || {})) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     containerStyle = { | ||||
|       ...styles.base, | ||||
|       ...styles.parentNode, | ||||
|       backgroundColor | ||||
|     }; | ||||
|     if (this.state.expanded) { | ||||
|       spanStyle = { | ||||
|         ...spanStyle, | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import React from 'react'; | ||||
| import reactMixin from 'react-mixin'; | ||||
| import { SquashClickEventMixin } from './mixins'; | ||||
| import hexToRgb from '../../utils/hexToRgb'; | ||||
| 
 | ||||
| const styles = { | ||||
|   base: { | ||||
|  | @ -19,8 +20,13 @@ const styles = { | |||
| @reactMixin.decorate(SquashClickEventMixin) | ||||
| export default class JSONStringNode extends React.Component { | ||||
|   render() { | ||||
|     let backgroundColor = 'transparent'; | ||||
|     if (this.props.previousValue !== this.props.value) { | ||||
|       const bgColor = hexToRgb(this.props.theme.base08); | ||||
|       backgroundColor = `rgba(${bgColor.r}, ${bgColor.g}, ${bgColor.b}, 0.04)`; | ||||
|     } | ||||
|     return ( | ||||
|       <li style={styles.base} onClick={::this.handleClick}> | ||||
|       <li style={{ ...styles.base, backgroundColor }} onClick={::this.handleClick}> | ||||
|         <label style={{ | ||||
|           ...styles.label, | ||||
|           color: this.props.theme.base0D | ||||
|  |  | |||
|  | @ -7,21 +7,21 @@ import JSONNumberNode from './JSONNumberNode'; | |||
| import JSONBooleanNode from './JSONBooleanNode'; | ||||
| import JSONNullNode from './JSONNullNode'; | ||||
| 
 | ||||
| export default function(key, value, theme) { | ||||
| export default function(key, value, prevValue, theme) { | ||||
|   const nodeType = objType(value); | ||||
|   const aKey = key + Date.now(); | ||||
|   if (nodeType === 'Object') { | ||||
|     return <JSONObjectNode data={value} theme={theme} keyName={key} key={aKey} />; | ||||
|     return <JSONObjectNode data={value} previousData={prevValue} theme={theme} keyName={key} key={aKey} />; | ||||
|   } else if (nodeType === 'Array') { | ||||
|     return <JSONArrayNode data={value} theme={theme} keyName={key} key={aKey} />; | ||||
|     return <JSONArrayNode data={value} previousData={prevValue} theme={theme} keyName={key} key={aKey} />; | ||||
|   } else if (nodeType === 'String') { | ||||
|     return <JSONStringNode keyName={key} theme={theme} value={value} key={aKey} />; | ||||
|     return <JSONStringNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={aKey} />; | ||||
|   } else if (nodeType === 'Number') { | ||||
|     return <JSONNumberNode keyName={key} theme={theme} value={value} key={aKey} />; | ||||
|     return <JSONNumberNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={aKey} />; | ||||
|   } else if (nodeType === 'Boolean') { | ||||
|     return <JSONBooleanNode keyName={key} theme={theme} value={value} key={aKey} />; | ||||
|     return <JSONBooleanNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={aKey} />; | ||||
|   } else if (nodeType === 'Null') { | ||||
|     return <JSONNullNode keyName={key} theme={theme} value={value} key={aKey} />; | ||||
|     return <JSONNullNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={aKey} />; | ||||
|   } | ||||
|   console.error('Unknown node type:', nodeType); | ||||
|   return false; | ||||
|  |  | |||
|  | @ -38,9 +38,9 @@ export default class JSONTree extends React.Component { | |||
|     let rootNode = false; | ||||
|     const keyName = this.props.keyName || 'root'; | ||||
|     if (nodeType === 'Object') { | ||||
|       rootNode = <JSONObjectNode theme={this.props.theme} data={this.props.data} keyName={keyName} initialExpanded={true} />; | ||||
|       rootNode = <JSONObjectNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} keyName={keyName} initialExpanded={true} />; | ||||
|     } else if (nodeType === 'Array') { | ||||
|       rootNode = <JSONArrayNode theme={this.props.theme} data={this.props.data} initialExpanded={true} keyName={keyName} />; | ||||
|       rootNode = <JSONArrayNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} initialExpanded={true} keyName={keyName} />; | ||||
|     } | ||||
|     return ( | ||||
|       <ul style={styles.tree}> | ||||
|  |  | |||
|  | @ -76,7 +76,6 @@ export default class LogMonitor { | |||
|     if (!node) { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (this.scrollDown) { | ||||
|       const { offsetHeight, scrollHeight } = node; | ||||
|       node.scrollTop = scrollHeight - offsetHeight; | ||||
|  | @ -137,7 +136,10 @@ export default class LogMonitor { | |||
|     for (let i = 0; i < stagedActions.length; i++) { | ||||
|       const action = stagedActions[i]; | ||||
|       const { state, error } = computedStates[i]; | ||||
| 
 | ||||
|       let previousState; | ||||
|       if (i > 0) { | ||||
|         previousState = computedStates[i - 1].state; | ||||
|       } | ||||
|       elements.push( | ||||
|         <LogMonitorEntry key={i} | ||||
|                          index={i} | ||||
|  | @ -145,6 +147,7 @@ export default class LogMonitor { | |||
|                          select={select} | ||||
|                          action={action} | ||||
|                          state={state} | ||||
|                          previousState={previousState} | ||||
|                          collapsed={skippedActions[i]} | ||||
|                          error={error} | ||||
|                          onActionClick={::this.handleToggleAction} /> | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ export default class LogMonitorEntry { | |||
|     let errorText = error; | ||||
|     if (!errorText) { | ||||
|       try { | ||||
|         return <JSONTree theme={this.props.theme} keyName={'state'} data={this.props.select(state)} />; | ||||
|         return <JSONTree theme={this.props.theme} keyName={'state'} data={this.props.select(state)} previousData={this.props.select(this.props.previousState)}/>; | ||||
|       } catch (err) { | ||||
|         errorText = 'Error selecting state.'; | ||||
|       } | ||||
|  |  | |||
							
								
								
									
										8
									
								
								src/utils/hexToRgb.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/utils/hexToRgb.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| export default function(hex) { | ||||
|   var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | ||||
|   return result ? { | ||||
|     r: parseInt(result[1], 16), | ||||
|     g: parseInt(result[2], 16), | ||||
|     b: parseInt(result[3], 16) | ||||
|   } : null; | ||||
| } | ||||
							
								
								
									
										23
									
								
								src/utils/shallowEqual.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/utils/shallowEqual.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| export default function shallowEqual(objA, objB) { | ||||
|   if (objA === objB) { | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   const keysA = Object.keys(objA); | ||||
|   const keysB = Object.keys(objB); | ||||
| 
 | ||||
|   if (keysA.length !== keysB.length) { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   // Test for A's keys different from B.
 | ||||
|   const hasOwn = Object.prototype.hasOwnProperty; | ||||
|   for (let i = 0; i < keysA.length; i++) { | ||||
|     if (!hasOwn.call(objB, keysA[i]) || | ||||
|         objA[keysA[i]] !== objB[keysA[i]]) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user