main
js 117 lines 2.85 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11
12 import styles from './ChartNode.css';
13 import typeof {SyntheticMouseEvent} from 'react-dom-bindings/src/events/SyntheticEvent';
14
15 type Props = {
16 color: string,
17 height: number,
18 isCurrentSearchMatch?: boolean,
19 isDimmed?: boolean,
20 isSearchMatch?: boolean,
21 label: string,
22 onClick: (event: SyntheticMouseEvent) => mixed,
23 onDoubleClick?: (event: SyntheticMouseEvent) => mixed,
24 onMouseEnter: (event: SyntheticMouseEvent) => mixed,
25 onMouseLeave: (event: SyntheticMouseEvent) => mixed,
26 placeLabelAboveNode?: boolean,
27 searchRegExp?: RegExp | null,
28 textStyle?: Object,
29 width: number,
30 x: number,
31 y: number,
32 };
33
34 const minWidthToDisplay = 35;
35
36 // Wrap the matched substring of `label` in a highlight, like the Components
37 // panel search does (see IndexableDisplayName).
38 function highlightLabel(
39 label: string,
40 searchRegExp: RegExp,
41 isCurrentSearchMatch: boolean,
42 ): React.Node {
43 const match = searchRegExp.exec(label);
44 if (match === null) {
45 return label;
46 }
47 const start = match.index;
48 const stop = start + match[0].length;
49 return (
50 <>
51 {start > 0 ? label.slice(0, start) : null}
52 <mark
53 className={
54 isCurrentSearchMatch ? styles.CurrentHighlight : styles.Highlight
55 }>
56 {label.slice(start, stop)}
57 </mark>
58 {stop < label.length ? label.slice(stop) : null}
59 </>
60 );
61 }
62
63 export default function ChartNode({
64 color,
65 height,
66 isCurrentSearchMatch = false,
67 isDimmed = false,
68 isSearchMatch = false,
69 label,
70 onClick,
71 onMouseEnter,
72 onMouseLeave,
73 onDoubleClick,
74 searchRegExp,
75 textStyle,
76 width,
77 x,
78 y,
79 }: Props): React.Node {
80 const content =
81 isSearchMatch && searchRegExp != null
82 ? highlightLabel(label, searchRegExp, isCurrentSearchMatch)
83 : label;
84 return (
85 <g className={styles.Group} transform={`translate(${x},${y})`}>
86 <rect
87 width={width}
88 height={height}
89 fill={color}
90 onClick={onClick}
91 onMouseEnter={onMouseEnter}
92 onMouseLeave={onMouseLeave}
93 onDoubleClick={onDoubleClick}
94 className={styles.Rect}
95 style={{
96 opacity: isDimmed ? 0.5 : 1,
97 }}
98 />
99 {width >= minWidthToDisplay && (
100 <foreignObject
101 width={width}
102 height={height}
103 className={styles.ForeignObject}
104 style={{
105 paddingLeft: x < 0 ? -x : 0,
106 opacity: isDimmed ? 0.75 : 1,
107 display: width < minWidthToDisplay ? 'none' : 'block',
108 }}
109 y={0}>
110 <div className={styles.Div} style={textStyle}>
111 {content}
112 </div>
113 </foreignObject>
114 )}
115 </g>
116 );
117 }