Skip to content

Commit c46382e

Browse files
MarkTeetsjasnoominzo-kimyuanjackie1
committed
Tooltip json tree integration and styling
Co-authored-by: Jasmine Noor <[email protected]> Co-authored-by: Minzo Kim <[email protected]> Co-authored-by: Jackie Yuan <[email protected]>
1 parent 6312da1 commit c46382e

File tree

4 files changed

+128
-93
lines changed

4 files changed

+128
-93
lines changed

src/app/components/StateRoute/ComponentMap/ComponentMap.tsx

Lines changed: 18 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { localPoint } from '@visx/event';
1717
import { useTooltip, useTooltipInPortal, defaultStyles } from '@visx/tooltip';
1818
import LinkControls from './LinkControls';
1919
import getLinkComponent from './getLinkComponent';
20+
import ToolTipDataDisplay from './ToolTipDataDisplay';
2021
import { toggleExpanded, setCurrentTabInApp } from '../../../actions/actions';
2122
import { useStoreContext } from '../../../store';
2223

@@ -122,19 +123,6 @@ export default function ComponentMap({
122123
return `${renderTime} ms `;
123124
};
124125

125-
const formatData = (data, type) => {
126-
const contextFormat = [];
127-
for (const key in data) {
128-
// Suggestion: update the front end to display as a list if we have object
129-
let inputData = data[key];
130-
if (inputData !== null && typeof inputData === 'object') {
131-
inputData = JSON.stringify(inputData);
132-
}
133-
contextFormat.push(<p className={`${type}-item`}>{`${key}: ${inputData}`}</p>);
134-
}
135-
return contextFormat;
136-
};
137-
138126
const formatState = (state) => {
139127
if (state === 'stateless') return ['stateless'];
140128
return ['stateful'];
@@ -296,19 +284,13 @@ export default function ComponentMap({
296284
onMouseEnter={(event) => {
297285
/** This 'if' statement block checks to see if you've just left another component node
298286
* by seeing if there's a current setTimeout waiting to close that component node's
299-
* tooltip (see onMouseLeave immediately below).
300-
* This setTimeout gives the mouse time to enter the tooltip element so the tooltip
301-
* can persist. If instead of entering said tooltip element you've left the previous
302-
* component node to enter this component node, this logic will clear the timeout event,
303-
* and close the tooltip. */
287+
* tooltip (see onMouseLeave immediately below). If so it clears the tooltip generated
288+
* from that component node so a new tooltip for the node you've just entered can render. */
304289
if (toolTipTimeoutID.current !== null) {
305290
clearTimeout(toolTipTimeoutID.current);
306291
hideTooltip();
307292
}
308-
/** The following line resets the toolTipTimeoutID.current to null, showing that there
309-
* are no current setTimeouts running. I placed this outside of the above if statement
310-
* to make sure there are no edge cases that would allow for the toolTipTimeoutID.current
311-
* to hold onto an old reference. */
293+
// Removes the previous timeoutID to avoid errors
312294
toolTipTimeoutID.current = null;
313295
//This generates a tooltip for the component node the mouse has entered.
314296
handleMouseAndClickOver(event);
@@ -322,13 +304,11 @@ export default function ComponentMap({
322304
* If the mouse enters the tooltip before the timeout delay has passed, the
323305
* setTimeout event will be canceled. */
324306
onMouseLeave={() => {
325-
// This line invokes setTimeout and saves its ID to the useRef var toolTipTimeoutID
307+
// Store setTimeout ID so timeout can be cleared if necessary
326308
toolTipTimeoutID.current = setTimeout(() => {
327309
// hideTooltip unmounts the tooltip
328310
hideTooltip();
329-
// As the timeout has been executed, the timeoutID can be reset to null
330311
toolTipTimeoutID.current = null;
331-
//There is a delay of 300 ms
332312
}, 300);
333313
}}
334314
/>
@@ -361,23 +341,16 @@ export default function ComponentMap({
361341
style={tooltipStyles}
362342

363343
//------------- Mouse Over TooltipInPortal--------------------------------------------------------------------
364-
/** This onMouseEnter fires when the mouse first moves/hovers over the tooltip
365-
* The supplied event listener callback stops the setTimeout that was going to
366-
* close the tooltip from firing */
367-
344+
/** After the mouse enters the tooltip, it's able to persist by clearing the setTimeout
345+
* that would've unmounted it */
368346
onMouseEnter={() => {
369-
// The setTimeoutID stored in toolTipTimeoutID.current is from the setTimeout initiated by leaving the
370-
// component node that generated the tooltip. If you've triggered an onMouseEnter event in that tooltip,
371347
clearTimeout(toolTipTimeoutID.current);
372-
// This line resets the timeoutID to null
373348
toolTipTimeoutID.current = null;
374349
}}
375350

376351
//------------- Mouse Leave TooltipInPortal -----------------------------------------------------------------
377-
/** This onMouseLeave event fires when the mouse leaves the tooltip
378-
* The supplied event listener callback unmounts the tooltip */
352+
/** When the mouse leaves the tooltip, the tooltip unmounts */
379353
onMouseLeave={() => {
380-
// hideTooltip unmounts the tooltip
381354
hideTooltip();
382355
}}
383356
>
@@ -391,26 +364,18 @@ export default function ComponentMap({
391364
State: {formatState(tooltipData.state)}
392365
</div>
393366
<div style={React.scrollStyle}>
394-
<div className='tooltipWrapper'>
395-
<h2>Props:</h2>
396-
{formatData(tooltipData.componentData.props, 'props')}
397-
</div>
398367

399-
{/* Currently no use for this field
400-
<div className='tooltipWrapper'>
401-
<h2>Initial Context:</h2>
402-
{formatData(tooltipData.componentData.context, 'context')}
403-
</div> */}
368+
<ToolTipDataDisplay
369+
containerName='Props'
370+
dataObj={tooltipData.componentData.props}
371+
/>
404372

405-
<div className='tooltipWrapper'>
406-
<h2>State:</h2>
407-
{formatData(
408-
tooltipData.componentData.hooksIndex
409-
? tooltipData.componentData.hooksState
410-
: tooltipData.componentData.state,
411-
'state',
412-
)}
413-
</div>
373+
<ToolTipDataDisplay
374+
containerName='State'
375+
dataObj={tooltipData.componentData.hooksIndex
376+
? tooltipData.componentData.hooksState
377+
: tooltipData.componentData.state}
378+
/>
414379
</div>
415380
</div>
416381
</TooltipInPortal>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react';
2+
import JSONTree from 'react-json-tree';
3+
4+
5+
const colors = {
6+
scheme: 'paraiso',
7+
author: 'jan t. sott',
8+
base00: '#2f1e2e',
9+
base01: '#41323f',
10+
base02: '#4f424c',
11+
base03: '#776e71',
12+
base04: '#8d8687',
13+
base05: '#a39e9b',
14+
base06: '#b9b6b0',
15+
base07: '#e7e9db',
16+
base08: '#ef6155',
17+
//base09 is orange for booleans and numbers. This base in particular fails to match the entered color.
18+
base09: '#824508',
19+
// base09: '#592bad', // alternative purple
20+
base0A: '#fec418',
21+
base0B: '#48b685',
22+
base0C: '#5bc4bf',
23+
base0D: '#06b6ef',
24+
base0E: '#815ba4',
25+
base0F: '#e96ba8',
26+
};
27+
28+
29+
const ToolTipDataDisplay = ({ containerName, dataObj }) => {
30+
//The key:value properties of printableObject will be rendered in the JSON Tree
31+
const printableObject = {}
32+
//If state is null rather than an object, print "State: null" in tooltip
33+
if (!dataObj) {
34+
printableObject[containerName] = dataObj;
35+
} else {
36+
// Props often contain circular references and messages from the backend must be sent as JSON
37+
// objects (strings). JSON objects can't contain circular ref's, so the backend filters out problematic
38+
// values by stringifying the values of object properties and ignoring any values that fail the
39+
// conversion due to a circular ref.
40+
// The following logic converts these values back to JS so they display clearly and are collapsible.
41+
const data = {};
42+
for (const key in dataObj) {
43+
if (typeof dataObj[key] === 'string') {
44+
try {
45+
data[key] = JSON.parse(dataObj[key]);
46+
} catch {
47+
data[key] = dataObj[key];
48+
}
49+
} else {
50+
data[key] = dataObj[key];
51+
}
52+
}
53+
// Adds container name (State, Props, future different names for hooks) at top of object
54+
// so everything nested in it will collapse when you click on it.
55+
printableObject[containerName] = data
56+
}
57+
58+
return (
59+
<div
60+
className='tooltipData'
61+
key={`${containerName}-data-container`}
62+
>
63+
<JSONTree
64+
data={printableObject}
65+
theme={{ extend: colors, tree: () => ({ className: `tooltipData-JSONTree` }) }}
66+
shouldExpandNode={() => true}
67+
hideRoot={true}
68+
/>
69+
</div>
70+
)
71+
};
72+
73+
export default ToolTipDataDisplay;

src/app/styles/layout/_stateContainer.scss

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -219,41 +219,63 @@
219219

220220
// tool tip styles
221221

222-
223222
.visx-tooltip{
224223
overflow-y: auto;
225224
overflow-wrap: break-word;
226225
pointer-events:all !important;
227226
}
228-
.props, .stateTip{
227+
228+
.stateTip{
229229
margin-top: 3px;
230230
line-height: 1;
231231
height: 100%;
232232
overflow-y: hidden;
233233
max-height: 400px;
234234
}
235-
.props{
236-
margin-top: 3px;
237-
}
238-
.props p{
239-
line-height:1;
240-
margin-top: 3px;
241-
margin-bottom: 0px;
242-
}
243-
.stateTip p{
235+
236+
.stateTip p {
244237
line-height:1;
245238
margin-top: 3px;
246239
margin-bottom: 0px;
247240
}
241+
248242
.historyToolTip{
249243
z-index: 2;
250244
}
251245

252-
253246
.state-container .router-link {
254247
border: 0.5px solid black;
255248
}
256-
/* if state view is width is less than 500px, stack the body containers */
257-
// @media (max-width: 500px) {
258249

259-
// }
250+
.tooltipData {
251+
background-color: #373737;
252+
margin-top: 4px;
253+
margin-bottom: 4px;
254+
padding: 2px;
255+
max-height: 30vh;
256+
// border: 5px solid rgba(0, 0, 0, 0.9);
257+
}
258+
259+
.tooltipData-JSONTree {
260+
list-style: none;
261+
margin-top: 1px;
262+
margin-bottom: 1px;
263+
margin-left: 2px;
264+
margin-right: 2px;
265+
padding: 0px;
266+
overflow-y: auto;
267+
max-height: 30vh;
268+
scrollbar-color:#919499 #51565e;
269+
270+
}
271+
272+
.tooltipData-JSONTree::-webkit-scrollbar-thumb {
273+
background:#919499;
274+
275+
}
276+
277+
.tooltipData-JSONTree::-webkit-scrollbar-track{
278+
background:#51565e;
279+
}
280+
281+

src/app/styles/main.scss

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,6 @@
55
font-family: 'Roboto', sans-serif;
66
}
77

8-
.tooltipWrapper {
9-
background-color: #505050;
10-
color: rgb(216, 216, 216);
11-
margin-top: 3px;
12-
margin-bottom: 3px;
13-
padding: 2px;
14-
}
15-
16-
.tooltipWrapper h2 {
17-
margin-top: 1px;
18-
margin-bottom: 1px;
19-
margin-left: 1px;
20-
font-size: small;
21-
font-weight: bolder;
22-
}
23-
24-
.tooltipWrapper p {
25-
margin-top: 1px;
26-
margin-bottom: 1px;
27-
margin-left: 10px;
28-
margin-right: 3px;
29-
}
30-
318
/* width */
329
::-webkit-scrollbar {
3310
width: 5px;
@@ -50,8 +27,6 @@
5027
background: rgb(97, 97, 97);
5128
}
5229

53-
// fixing the tooltip display for overflow scrolling
54-
5530
// 1. Configuration and helpers
5631
@import 'abstracts/variables';
5732

0 commit comments

Comments
 (0)