visualifyjs 2.5.3-2.dev → 2.5.3-9-dev

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of visualifyjs might be problematic. Click here for more details.

Files changed (139) hide show
  1. package/.github/workflows/{static.yml.bak → build.yaml} +51 -51
  2. package/LICENSE +674 -674
  3. package/README.md +40 -58
  4. package/config-overrides.js +31 -31
  5. package/dist/visualify.js +3 -3
  6. package/docs/CLI.md +15 -0
  7. package/docs/{docs/README.md → README.md} +41 -65
  8. package/docs/{docs/Rechart → Rechart}/bar.md +190 -190
  9. package/docs/{docs/Rechart → Rechart}/funnel.md +193 -241
  10. package/docs/{docs/Rechart → Rechart}/line.md +355 -355
  11. package/docs/{docs/Rechart → Rechart}/pie.md +225 -225
  12. package/docs/{docs/Rechart → Rechart}/radar.md +253 -253
  13. package/docs/{docs/_404.md → _404.md} +51 -51
  14. package/docs/{docs/_coverpage.md → _coverpage.md} +11 -11
  15. package/docs/{docs/_sidebar.md → _sidebar.md} +42 -44
  16. package/docs/{docs/components → components}/dotBio.md +34 -34
  17. package/docs/{docs/components → components}/echart.md +82 -82
  18. package/docs/{docs/components → components}/html.md +34 -34
  19. package/docs/{docs/components → components}/macaron.md +145 -145
  20. package/docs/components/markdown.md +0 -0
  21. package/docs/{docs/components → components}/more.md +142 -142
  22. package/docs/{docs/components → components}/plotly.md +62 -62
  23. package/docs/{docs/components → components}/scatterL.md +70 -70
  24. package/docs/{docs/components → components}/visium.md +56 -56
  25. package/docs/{docs/configuration.md → configuration.md} +123 -121
  26. package/docs/{docs/deploy.md → deploy.md} +23 -31
  27. package/docs/index.html +70 -70
  28. package/docs/log.md +1 -0
  29. package/docs/manifest.json +23 -23
  30. package/docs/{docs/more-pages.md → more-pages.md} +23 -23
  31. package/docs/{docs/quickstart.md → quickstart.md} +115 -124
  32. package/docs/{docs/rechart-attributes.md → rechart-attributes.md} +74 -74
  33. package/docs/{docs/rechart-basic-usage.md → rechart-basic-usage.md} +162 -162
  34. package/docs/static/css/fluff-stuff.css +169 -169
  35. package/docs/static/css/font-awesome.min.css +4 -4
  36. package/docs/static/css/visualify.css +25 -25
  37. package/docs/static/js/configuration.js +448 -448
  38. package/docs/static/js/visualify.js +24 -23
  39. package/docs/theme.md +3 -0
  40. package/package.json +74 -83
  41. package/rollup.config.mjs +75 -75
  42. package/src/_css/404.css +115 -115
  43. package/src/_css/App.css +37 -37
  44. package/src/_css/autoSuggestion.css +26 -26
  45. package/src/_css/circular-progress.css +32 -32
  46. package/src/_css/index.css +36 -36
  47. package/src/_css/modern.css +24 -24
  48. package/src/_media/corner.svg +8 -8
  49. package/src/_media/download.svg +3 -3
  50. package/src/_media/logo.svg +14 -14
  51. package/src/_test/App.test.js +15 -15
  52. package/src/_utils/reportWebVitals.js +13 -13
  53. package/src/core/appContext.js +27 -27
  54. package/src/core/components/Scatter.js +188 -188
  55. package/src/core/components/ScatterBio.js +572 -572
  56. package/src/core/components/VisiumPlot.js +165 -165
  57. package/src/core/components/browser.js +42 -42
  58. package/src/core/components/dotplot.js +413 -413
  59. package/src/core/components/html.js +29 -29
  60. package/src/core/components/list.js +178 -178
  61. package/src/core/components/macaron.js +201 -201
  62. package/src/core/components/markdown.js +56 -56
  63. package/src/core/components/parser.scatterBio.js +579 -587
  64. package/src/core/components/ratio.js +80 -80
  65. package/src/core/components/scatterL.js +173 -173
  66. package/src/core/components/searchbar.js +131 -131
  67. package/src/core/components/selection.js +193 -193
  68. package/src/core/components/timeline.js +281 -281
  69. package/src/core/components/visium.js +97 -97
  70. package/src/core/fetch/condfetch.js +82 -82
  71. package/src/core/fetch/fetch.js +92 -92
  72. package/src/core/fetch/json.js +29 -29
  73. package/src/core/fetch/vfetch.js +42 -42
  74. package/src/core/liveEditor.js +44 -44
  75. package/src/core/modules/codeEditorWithPreview.js +104 -104
  76. package/src/core/modules/echarts/common.js +20 -20
  77. package/src/core/modules/echarts/presetHandler.js +41 -41
  78. package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
  79. package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
  80. package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
  81. package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
  82. package/src/core/modules/echarts.js +71 -71
  83. package/src/core/modules/echartsUtils.js +43 -43
  84. package/src/core/modules/echartswitcher.js +152 -152
  85. package/src/core/modules/replotly/presetHandler.js +24 -24
  86. package/src/core/modules/replotly/presets/minimum.js +18 -18
  87. package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
  88. package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
  89. package/src/core/modules/replotly.js +71 -71
  90. package/src/core/pages/404.js +50 -50
  91. package/src/core/pages/error.js +27 -27
  92. package/src/core/pages/jsonPage.js +62 -62
  93. package/src/core/pages/loading.js +44 -44
  94. package/src/core/parser/echart.data.js +183 -183
  95. package/src/core/parser/echart.features.js +125 -125
  96. package/src/core/parser/echart.general.js +143 -147
  97. package/src/core/parser/echart.hilbert.js +57 -57
  98. package/src/core/parser/echart.parser.js +210 -210
  99. package/src/core/parser/echart.series.js +67 -67
  100. package/src/core/parser/echart.types.js +76 -76
  101. package/src/core/parser/plotly.config.js +10 -10
  102. package/src/core/parser/plotly.data.js +132 -132
  103. package/src/core/parser/plotly.layout.js +9 -9
  104. package/src/core/parser/plotly.violin.js +18 -18
  105. package/src/core/recharts.js +62 -62
  106. package/src/core/router/alias.js +49 -49
  107. package/src/core/router/jsonRouter.js +31 -31
  108. package/src/core/themes/modern.js +32 -32
  109. package/src/core/themes/themeSelector.js +33 -33
  110. package/src/core/visualify.js +47 -47
  111. package/src/core/widgets/circularProgress.js +23 -23
  112. package/src/core/widgets/controller.js +83 -83
  113. package/src/core/widgets/errorBoundary.js +36 -36
  114. package/src/core/widgets/footer.js +177 -177
  115. package/src/core/widgets/header.js +234 -234
  116. package/src/core/widgets/layout/Grid.js +31 -31
  117. package/src/core/widgets/layout.js +36 -36
  118. package/src/core/widgets/mapping.js +42 -42
  119. package/src/index.js +62 -62
  120. package/src/setupTests.js +5 -5
  121. package/docs/docs/CLI.md +0 -34
  122. package/docs/docs/Rechart/scatter.md +0 -298
  123. package/docs/docs/log.md +0 -9
  124. package/docs/docs/static/logo/favicon.ico +0 -0
  125. package/docs/docs/static/logo/logo_128x128.png +0 -0
  126. package/docs/docs/static/logo/logo_192x192.png +0 -0
  127. package/docs/docs/static/logo/logo_256x256.png +0 -0
  128. package/docs/docs/static/logo/logo_512x512.png +0 -0
  129. package/docs/docs/static/logo/logo_64x64.png +0 -0
  130. package/docs/docs/theme.md +0 -5
  131. /package/docs/{docs/Rechart → Rechart}/geo.md +0 -0
  132. /package/docs/{docs/Rechart → Rechart}/liquidfill.md +0 -0
  133. /package/docs/{docs/Rechart → Rechart}/polar.md +0 -0
  134. /package/docs/{docs/Rechart → Rechart}/sankey.md +0 -0
  135. /package/docs/{docs/Rechart/sunburst.md → Rechart/scatter.md} +0 -0
  136. /package/docs/{docs/Rechart/tree.md → Rechart/sunburst.md} +0 -0
  137. /package/docs/{docs/Rechart/wordcloud.md → Rechart/tree.md} +0 -0
  138. /package/docs/{docs/components/markdown.md → Rechart/wordcloud.md} +0 -0
  139. /package/docs/{docs/static → static}/_images/deploy-github-pages.png +0 -0
@@ -1,281 +1,281 @@
1
- import React, { useEffect, useState } from 'react';
2
- import simplefetch from '../fetch/fetch';
3
- import { useAppContext } from '../appContext';
4
-
5
- const generateNodes = (data, split_pattern) => {
6
- return data.reduce((groups, item) => {
7
- const parts = item.split(split_pattern);
8
- const main = parts[0];
9
- const sub = parts.slice(1).join(split_pattern);
10
-
11
- if (sub) {
12
- if (!groups[main]) {
13
- groups[main] = [];
14
- }
15
- groups[main].push(sub);
16
- } else {
17
- groups[main] = null;
18
- }
19
-
20
- return groups;
21
- }, {});
22
- };
23
-
24
- function Timeline({ props, style }) {
25
- const { debug } = props;
26
-
27
- const { style: _style_parsed = {} } = props;
28
- const { class: className, ...customStyle } = _style_parsed;
29
-
30
- // if debug is true, then border is red, else no border
31
- style = {
32
- ...style,
33
- border: debug ? '1px solid red' : 'none',
34
- maxHeight: '500px',
35
- overflowY: 'auto',
36
- overflowX: 'hidden',
37
- ...customStyle,
38
- position: 'relative',
39
- };
40
-
41
- const { id, val, config = {}, title } = props;
42
-
43
- const {
44
- split_pattern = '_',
45
- node_width = '50%',
46
- sort_pattern = new RegExp(/E(\d+)/),
47
- distance_pattern = undefined,
48
- basicGap = 1,
49
- } = config;
50
- // Render title if it exists
51
- const renderTitle = () => {
52
- return title && <h3>{title}</h3>;
53
- };
54
-
55
- const [nodes, setNodes] = useState([]);
56
-
57
- useEffect(() => {
58
- const { selection, urlval, rm_suffix } = props;
59
-
60
- const fetchData = async () => {
61
- try {
62
- const response = await simplefetch(selection, { key: urlval });
63
- // remove the suffix "_metadata" from the options
64
- try {
65
- const removed_suffix = response.map((item) =>
66
- item.replace(rm_suffix, ''),
67
- );
68
- //console.log('Removed suffix:', removed_suffix);
69
- const groupedNodes = generateNodes(
70
- removed_suffix,
71
- split_pattern,
72
- );
73
- setNodes(groupedNodes);
74
- } catch (error) {
75
- setNodes(response);
76
- }
77
- } catch (error) {
78
- console.error('Error fetching options:', error);
79
- }
80
- };
81
-
82
- fetchData();
83
- }, [props, split_pattern, debug]);
84
-
85
- const { setSharedData } = useAppContext();
86
-
87
- const handleNodeClick = (node) => {
88
- if (debug) console.log(`Node [${node}] clicked!`);
89
- if (val) {
90
- setSharedData((prevSharedData) => {
91
- return { ...prevSharedData, [val]: [node] };
92
- });
93
- alert(`Clicked: ${node}`);
94
- }
95
- };
96
-
97
- const _sort_pattern =
98
- typeof sort_pattern === 'string'
99
- ? new RegExp(sort_pattern)
100
- : sort_pattern;
101
-
102
- const sortedNodes = Object.keys(nodes)
103
- .sort((a, b) => {
104
- //console.log('a:', a, 'b:', b, 'sort_pattern:', _sort_pattern);
105
- const numA = parseInt(a.match(_sort_pattern)[1]);
106
- const numB = parseInt(b.match(_sort_pattern)[1]);
107
- return numA - numB;
108
- })
109
- .reduce((acc, key) => {
110
- acc[key] = nodes[key];
111
- return acc;
112
- }, {});
113
-
114
- const extractNumber = (str) => {
115
- const matchE = str.match(/E(\d+)/);
116
-
117
- if (distance_pattern && distance_pattern.regex) {
118
- const dis_regex =
119
- typeof distance_pattern?.regex === 'string'
120
- ? new RegExp(distance_pattern.regex)
121
- : distance_pattern.regex;
122
-
123
- const match = str.match(dis_regex);
124
-
125
- //console.log('str', str, 'match:', match, 'distance_pattern:', dis_regex);
126
- if (match) {
127
- for (let i = distance_pattern.pos; i >= 1; i--) {
128
- if (match[i]) {
129
- return parseInt(match[i]);
130
- }
131
- }
132
- }
133
- } else if (matchE) {
134
- return parseInt(matchE[1]);
135
- }
136
- return 0;
137
- };
138
-
139
- const calculateDistance = (main, previousMain) => {
140
- if (!previousMain) return 0;
141
-
142
- const numA = extractNumber(main);
143
- const numB = extractNumber(previousMain);
144
-
145
- //console.log('numA:', numA, 'numB:', numB, 'diff:', Math.abs(numA - numB));
146
-
147
- return Math.abs(numA - numB) * basicGap; // Distance based on the basic gap value
148
- };
149
-
150
- let previousMain = null;
151
-
152
- return (
153
- <div
154
- key={id}
155
- style={{ ...style }}
156
- className={className}>
157
- {renderTitle()}
158
- <div
159
- key={id + '.timeline'}
160
- style={{
161
- display: 'flex',
162
- flexDirection: 'column',
163
- alignItems: 'flex-start',
164
- position: 'relative',
165
- }}>
166
- <div
167
- style={{
168
- borderLeft: '10px solid black',
169
- //minHeight: '350px',
170
- height: '100%',
171
- position: 'absolute',
172
- left: '0px',
173
- top: '0px',
174
- }}
175
- />
176
- <div
177
- style={{ ...style }}
178
- className={className}>
179
- <div
180
- style={{
181
- maxHeight: '500px',
182
- overflowY: 'auto',
183
- overflowX: 'hidden',
184
- }}>
185
- {Object.keys(sortedNodes).map((main, index) => {
186
- const distance = calculateDistance(
187
- main,
188
- previousMain,
189
- );
190
- previousMain = main; // Update previousMain for the next iteration
191
- return (
192
- <div
193
- key={index}
194
- style={{
195
- display: 'flex',
196
- alignItems: 'center',
197
- marginTop: distance + 'px', // Apply distance here
198
- position: 'relative',
199
- flexDirection: 'column',
200
- }}>
201
- <div
202
- style={{
203
- position: 'absolute',
204
- left: '0%',
205
- top: '10px',
206
- width: node_width ?? '50%',
207
- height: '2px',
208
- background: 'black',
209
- }}
210
- />
211
- <div
212
- id='Timeline.Dot'
213
- style={{
214
- position: 'absolute',
215
- left: '0%',
216
- top: '15px',
217
- width: '10px',
218
- height: '10px',
219
- borderRadius: '50%',
220
- background: 'black',
221
- }}
222
- />
223
- {nodes[main] ? (
224
- <>
225
- <div style={{ marginLeft: '15%' }}>
226
- {main}
227
- </div>
228
- <div
229
- style={{
230
- marginLeft: '15%',
231
- display: 'flex',
232
- flexWrap: 'wrap',
233
- }}>
234
- {nodes[main].map(
235
- (sub, subIndex) => (
236
- <button
237
- key={subIndex}
238
- style={{
239
- padding:
240
- '5px 3px',
241
- marginLeft:
242
- '2px',
243
- border: '1px solid black',
244
- cursor: 'pointer',
245
- }}
246
- onClick={() =>
247
- handleNodeClick(
248
- `${main}_${sub}`,
249
- )
250
- }>
251
- {sub}
252
- </button>
253
- ),
254
- )}
255
- </div>
256
- </>
257
- ) : (
258
- <div
259
- style={{
260
- marginLeft: '15%',
261
- padding: '5px 3px',
262
- border: '1px solid black',
263
- cursor: 'pointer',
264
- }}
265
- onClick={() =>
266
- handleNodeClick(main)
267
- }>
268
- {main}
269
- </div>
270
- )}
271
- </div>
272
- );
273
- })}
274
- </div>
275
- </div>
276
- </div>
277
- </div>
278
- );
279
- }
280
-
281
- export default Timeline;
1
+ import React, { useEffect, useState } from 'react';
2
+ import simplefetch from '../fetch/fetch';
3
+ import { useAppContext } from '../appContext';
4
+
5
+ const generateNodes = (data, split_pattern) => {
6
+ return data.reduce((groups, item) => {
7
+ const parts = item.split(split_pattern);
8
+ const main = parts[0];
9
+ const sub = parts.slice(1).join(split_pattern);
10
+
11
+ if (sub) {
12
+ if (!groups[main]) {
13
+ groups[main] = [];
14
+ }
15
+ groups[main].push(sub);
16
+ } else {
17
+ groups[main] = null;
18
+ }
19
+
20
+ return groups;
21
+ }, {});
22
+ };
23
+
24
+ function Timeline({ props, style }) {
25
+ const { debug } = props;
26
+
27
+ const { style: _style_parsed = {} } = props;
28
+ const { class: className, ...customStyle } = _style_parsed;
29
+
30
+ // if debug is true, then border is red, else no border
31
+ style = {
32
+ ...style,
33
+ border: debug ? '1px solid red' : 'none',
34
+ maxHeight: '500px',
35
+ overflowY: 'auto',
36
+ overflowX: 'hidden',
37
+ ...customStyle,
38
+ position: 'relative',
39
+ };
40
+
41
+ const { id, val, config = {}, title } = props;
42
+
43
+ const {
44
+ split_pattern = '_',
45
+ node_width = '50%',
46
+ sort_pattern = new RegExp(/E(\d+)/),
47
+ distance_pattern = undefined,
48
+ basicGap = 1,
49
+ } = config;
50
+ // Render title if it exists
51
+ const renderTitle = () => {
52
+ return title && <h3>{title}</h3>;
53
+ };
54
+
55
+ const [nodes, setNodes] = useState([]);
56
+
57
+ useEffect(() => {
58
+ const { selection, urlval, rm_suffix } = props;
59
+
60
+ const fetchData = async () => {
61
+ try {
62
+ const response = await simplefetch(selection, { key: urlval });
63
+ // remove the suffix "_metadata" from the options
64
+ try {
65
+ const removed_suffix = response.map((item) =>
66
+ item.replace(rm_suffix, ''),
67
+ );
68
+ //console.log('Removed suffix:', removed_suffix);
69
+ const groupedNodes = generateNodes(
70
+ removed_suffix,
71
+ split_pattern,
72
+ );
73
+ setNodes(groupedNodes);
74
+ } catch (error) {
75
+ setNodes(response);
76
+ }
77
+ } catch (error) {
78
+ console.error('Error fetching options:', error);
79
+ }
80
+ };
81
+
82
+ fetchData();
83
+ }, [props, split_pattern, debug]);
84
+
85
+ const { setSharedData } = useAppContext();
86
+
87
+ const handleNodeClick = (node) => {
88
+ if (debug) console.log(`Node [${node}] clicked!`);
89
+ if (val) {
90
+ setSharedData((prevSharedData) => {
91
+ return { ...prevSharedData, [val]: [node] };
92
+ });
93
+ alert(`Clicked: ${node}`);
94
+ }
95
+ };
96
+
97
+ const _sort_pattern =
98
+ typeof sort_pattern === 'string'
99
+ ? new RegExp(sort_pattern)
100
+ : sort_pattern;
101
+
102
+ const sortedNodes = Object.keys(nodes)
103
+ .sort((a, b) => {
104
+ //console.log('a:', a, 'b:', b, 'sort_pattern:', _sort_pattern);
105
+ const numA = parseInt(a.match(_sort_pattern)[1]);
106
+ const numB = parseInt(b.match(_sort_pattern)[1]);
107
+ return numA - numB;
108
+ })
109
+ .reduce((acc, key) => {
110
+ acc[key] = nodes[key];
111
+ return acc;
112
+ }, {});
113
+
114
+ const extractNumber = (str) => {
115
+ const matchE = str.match(/E(\d+)/);
116
+
117
+ if (distance_pattern && distance_pattern.regex) {
118
+ const dis_regex =
119
+ typeof distance_pattern?.regex === 'string'
120
+ ? new RegExp(distance_pattern.regex)
121
+ : distance_pattern.regex;
122
+
123
+ const match = str.match(dis_regex);
124
+
125
+ //console.log('str', str, 'match:', match, 'distance_pattern:', dis_regex);
126
+ if (match) {
127
+ for (let i = distance_pattern.pos; i >= 1; i--) {
128
+ if (match[i]) {
129
+ return parseInt(match[i]);
130
+ }
131
+ }
132
+ }
133
+ } else if (matchE) {
134
+ return parseInt(matchE[1]);
135
+ }
136
+ return 0;
137
+ };
138
+
139
+ const calculateDistance = (main, previousMain) => {
140
+ if (!previousMain) return 0;
141
+
142
+ const numA = extractNumber(main);
143
+ const numB = extractNumber(previousMain);
144
+
145
+ //console.log('numA:', numA, 'numB:', numB, 'diff:', Math.abs(numA - numB));
146
+
147
+ return Math.abs(numA - numB) * basicGap; // Distance based on the basic gap value
148
+ };
149
+
150
+ let previousMain = null;
151
+
152
+ return (
153
+ <div
154
+ key={id}
155
+ style={{ ...style }}
156
+ className={className}>
157
+ {renderTitle()}
158
+ <div
159
+ key={id + '.timeline'}
160
+ style={{
161
+ display: 'flex',
162
+ flexDirection: 'column',
163
+ alignItems: 'flex-start',
164
+ position: 'relative',
165
+ }}>
166
+ <div
167
+ style={{
168
+ borderLeft: '10px solid black',
169
+ //minHeight: '350px',
170
+ height: '100%',
171
+ position: 'absolute',
172
+ left: '0px',
173
+ top: '0px',
174
+ }}
175
+ />
176
+ <div
177
+ style={{ ...style }}
178
+ className={className}>
179
+ <div
180
+ style={{
181
+ maxHeight: '500px',
182
+ overflowY: 'auto',
183
+ overflowX: 'hidden',
184
+ }}>
185
+ {Object.keys(sortedNodes).map((main, index) => {
186
+ const distance = calculateDistance(
187
+ main,
188
+ previousMain,
189
+ );
190
+ previousMain = main; // Update previousMain for the next iteration
191
+ return (
192
+ <div
193
+ key={index}
194
+ style={{
195
+ display: 'flex',
196
+ alignItems: 'center',
197
+ marginTop: distance + 'px', // Apply distance here
198
+ position: 'relative',
199
+ flexDirection: 'column',
200
+ }}>
201
+ <div
202
+ style={{
203
+ position: 'absolute',
204
+ left: '0%',
205
+ top: '10px',
206
+ width: node_width ?? '50%',
207
+ height: '2px',
208
+ background: 'black',
209
+ }}
210
+ />
211
+ <div
212
+ id='Timeline.Dot'
213
+ style={{
214
+ position: 'absolute',
215
+ left: '0%',
216
+ top: '15px',
217
+ width: '10px',
218
+ height: '10px',
219
+ borderRadius: '50%',
220
+ background: 'black',
221
+ }}
222
+ />
223
+ {nodes[main] ? (
224
+ <>
225
+ <div style={{ marginLeft: '15%' }}>
226
+ {main}
227
+ </div>
228
+ <div
229
+ style={{
230
+ marginLeft: '15%',
231
+ display: 'flex',
232
+ flexWrap: 'wrap',
233
+ }}>
234
+ {nodes[main].map(
235
+ (sub, subIndex) => (
236
+ <button
237
+ key={subIndex}
238
+ style={{
239
+ padding:
240
+ '5px 3px',
241
+ marginLeft:
242
+ '2px',
243
+ border: '1px solid black',
244
+ cursor: 'pointer',
245
+ }}
246
+ onClick={() =>
247
+ handleNodeClick(
248
+ `${main}_${sub}`,
249
+ )
250
+ }>
251
+ {sub}
252
+ </button>
253
+ ),
254
+ )}
255
+ </div>
256
+ </>
257
+ ) : (
258
+ <div
259
+ style={{
260
+ marginLeft: '15%',
261
+ padding: '5px 3px',
262
+ border: '1px solid black',
263
+ cursor: 'pointer',
264
+ }}
265
+ onClick={() =>
266
+ handleNodeClick(main)
267
+ }>
268
+ {main}
269
+ </div>
270
+ )}
271
+ </div>
272
+ );
273
+ })}
274
+ </div>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ );
279
+ }
280
+
281
+ export default Timeline;