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.
- package/.github/workflows/{static.yml.bak → build.yaml} +51 -51
- package/LICENSE +674 -674
- package/README.md +40 -58
- package/config-overrides.js +31 -31
- package/dist/visualify.js +3 -3
- package/docs/CLI.md +15 -0
- package/docs/{docs/README.md → README.md} +41 -65
- package/docs/{docs/Rechart → Rechart}/bar.md +190 -190
- package/docs/{docs/Rechart → Rechart}/funnel.md +193 -241
- package/docs/{docs/Rechart → Rechart}/line.md +355 -355
- package/docs/{docs/Rechart → Rechart}/pie.md +225 -225
- package/docs/{docs/Rechart → Rechart}/radar.md +253 -253
- package/docs/{docs/_404.md → _404.md} +51 -51
- package/docs/{docs/_coverpage.md → _coverpage.md} +11 -11
- package/docs/{docs/_sidebar.md → _sidebar.md} +42 -44
- package/docs/{docs/components → components}/dotBio.md +34 -34
- package/docs/{docs/components → components}/echart.md +82 -82
- package/docs/{docs/components → components}/html.md +34 -34
- package/docs/{docs/components → components}/macaron.md +145 -145
- package/docs/components/markdown.md +0 -0
- package/docs/{docs/components → components}/more.md +142 -142
- package/docs/{docs/components → components}/plotly.md +62 -62
- package/docs/{docs/components → components}/scatterL.md +70 -70
- package/docs/{docs/components → components}/visium.md +56 -56
- package/docs/{docs/configuration.md → configuration.md} +123 -121
- package/docs/{docs/deploy.md → deploy.md} +23 -31
- package/docs/index.html +70 -70
- package/docs/log.md +1 -0
- package/docs/manifest.json +23 -23
- package/docs/{docs/more-pages.md → more-pages.md} +23 -23
- package/docs/{docs/quickstart.md → quickstart.md} +115 -124
- package/docs/{docs/rechart-attributes.md → rechart-attributes.md} +74 -74
- package/docs/{docs/rechart-basic-usage.md → rechart-basic-usage.md} +162 -162
- package/docs/static/css/fluff-stuff.css +169 -169
- package/docs/static/css/font-awesome.min.css +4 -4
- package/docs/static/css/visualify.css +25 -25
- package/docs/static/js/configuration.js +448 -448
- package/docs/static/js/visualify.js +24 -23
- package/docs/theme.md +3 -0
- package/package.json +74 -83
- package/rollup.config.mjs +75 -75
- package/src/_css/404.css +115 -115
- package/src/_css/App.css +37 -37
- package/src/_css/autoSuggestion.css +26 -26
- package/src/_css/circular-progress.css +32 -32
- package/src/_css/index.css +36 -36
- package/src/_css/modern.css +24 -24
- package/src/_media/corner.svg +8 -8
- package/src/_media/download.svg +3 -3
- package/src/_media/logo.svg +14 -14
- package/src/_test/App.test.js +15 -15
- package/src/_utils/reportWebVitals.js +13 -13
- package/src/core/appContext.js +27 -27
- package/src/core/components/Scatter.js +188 -188
- package/src/core/components/ScatterBio.js +572 -572
- package/src/core/components/VisiumPlot.js +165 -165
- package/src/core/components/browser.js +42 -42
- package/src/core/components/dotplot.js +413 -413
- package/src/core/components/html.js +29 -29
- package/src/core/components/list.js +178 -178
- package/src/core/components/macaron.js +201 -201
- package/src/core/components/markdown.js +56 -56
- package/src/core/components/parser.scatterBio.js +579 -587
- package/src/core/components/ratio.js +80 -80
- package/src/core/components/scatterL.js +173 -173
- package/src/core/components/searchbar.js +131 -131
- package/src/core/components/selection.js +193 -193
- package/src/core/components/timeline.js +281 -281
- package/src/core/components/visium.js +97 -97
- package/src/core/fetch/condfetch.js +82 -82
- package/src/core/fetch/fetch.js +92 -92
- package/src/core/fetch/json.js +29 -29
- package/src/core/fetch/vfetch.js +42 -42
- package/src/core/liveEditor.js +44 -44
- package/src/core/modules/codeEditorWithPreview.js +104 -104
- package/src/core/modules/echarts/common.js +20 -20
- package/src/core/modules/echarts/presetHandler.js +41 -41
- package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
- package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
- package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
- package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
- package/src/core/modules/echarts.js +71 -71
- package/src/core/modules/echartsUtils.js +43 -43
- package/src/core/modules/echartswitcher.js +152 -152
- package/src/core/modules/replotly/presetHandler.js +24 -24
- package/src/core/modules/replotly/presets/minimum.js +18 -18
- package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
- package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
- package/src/core/modules/replotly.js +71 -71
- package/src/core/pages/404.js +50 -50
- package/src/core/pages/error.js +27 -27
- package/src/core/pages/jsonPage.js +62 -62
- package/src/core/pages/loading.js +44 -44
- package/src/core/parser/echart.data.js +183 -183
- package/src/core/parser/echart.features.js +125 -125
- package/src/core/parser/echart.general.js +143 -147
- package/src/core/parser/echart.hilbert.js +57 -57
- package/src/core/parser/echart.parser.js +210 -210
- package/src/core/parser/echart.series.js +67 -67
- package/src/core/parser/echart.types.js +76 -76
- package/src/core/parser/plotly.config.js +10 -10
- package/src/core/parser/plotly.data.js +132 -132
- package/src/core/parser/plotly.layout.js +9 -9
- package/src/core/parser/plotly.violin.js +18 -18
- package/src/core/recharts.js +62 -62
- package/src/core/router/alias.js +49 -49
- package/src/core/router/jsonRouter.js +31 -31
- package/src/core/themes/modern.js +32 -32
- package/src/core/themes/themeSelector.js +33 -33
- package/src/core/visualify.js +47 -47
- package/src/core/widgets/circularProgress.js +23 -23
- package/src/core/widgets/controller.js +83 -83
- package/src/core/widgets/errorBoundary.js +36 -36
- package/src/core/widgets/footer.js +177 -177
- package/src/core/widgets/header.js +234 -234
- package/src/core/widgets/layout/Grid.js +31 -31
- package/src/core/widgets/layout.js +36 -36
- package/src/core/widgets/mapping.js +42 -42
- package/src/index.js +62 -62
- package/src/setupTests.js +5 -5
- package/docs/docs/CLI.md +0 -34
- package/docs/docs/Rechart/scatter.md +0 -298
- package/docs/docs/log.md +0 -9
- package/docs/docs/static/logo/favicon.ico +0 -0
- package/docs/docs/static/logo/logo_128x128.png +0 -0
- package/docs/docs/static/logo/logo_192x192.png +0 -0
- package/docs/docs/static/logo/logo_256x256.png +0 -0
- package/docs/docs/static/logo/logo_512x512.png +0 -0
- package/docs/docs/static/logo/logo_64x64.png +0 -0
- package/docs/docs/theme.md +0 -5
- /package/docs/{docs/Rechart → Rechart}/geo.md +0 -0
- /package/docs/{docs/Rechart → Rechart}/liquidfill.md +0 -0
- /package/docs/{docs/Rechart → Rechart}/polar.md +0 -0
- /package/docs/{docs/Rechart → Rechart}/sankey.md +0 -0
- /package/docs/{docs/Rechart/sunburst.md → Rechart/scatter.md} +0 -0
- /package/docs/{docs/Rechart/tree.md → Rechart/sunburst.md} +0 -0
- /package/docs/{docs/Rechart/wordcloud.md → Rechart/tree.md} +0 -0
- /package/docs/{docs/components/markdown.md → Rechart/wordcloud.md} +0 -0
- /package/docs/{docs/static → static}/_images/deploy-github-pages.png +0 -0
@@ -1,131 +1,131 @@
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
2
|
-
import '../../_css/autoSuggestion.css';
|
3
|
-
import { useAppContext } from '../appContext';
|
4
|
-
import conditionalFetch from '../fetch/condfetch';
|
5
|
-
|
6
|
-
function SearchBar({ props, style }) {
|
7
|
-
const [suggestions, setSuggestions] = useState([]);
|
8
|
-
const [wordlist, setWordlist] = useState([]);
|
9
|
-
const [inputValue, setInputValue] = useState('');
|
10
|
-
|
11
|
-
const { sharedData, setSharedData } = useAppContext();
|
12
|
-
|
13
|
-
const {
|
14
|
-
id,
|
15
|
-
title = 'Search',
|
16
|
-
className,
|
17
|
-
style: _style = { height: '130px', width: '200px' },
|
18
|
-
placeholder = 'Search...',
|
19
|
-
wordlimit = 15,
|
20
|
-
suggestLen = 3,
|
21
|
-
searchStyle = {
|
22
|
-
borderRadius: '15px',
|
23
|
-
width: '100%',
|
24
|
-
},
|
25
|
-
config = {},
|
26
|
-
debug,
|
27
|
-
} = props;
|
28
|
-
|
29
|
-
if (config.save && typeof config.save !== 'string') config.save = id;
|
30
|
-
|
31
|
-
useEffect(() => {
|
32
|
-
if (config.source) {
|
33
|
-
const fetchWordlist = async () => {
|
34
|
-
const response = await conditionalFetch(
|
35
|
-
config.source,
|
36
|
-
sharedData,
|
37
|
-
null,
|
38
|
-
null,
|
39
|
-
);
|
40
|
-
if (response) {
|
41
|
-
const newWordlist =
|
42
|
-
response[config.source.responseKey] || response;
|
43
|
-
setWordlist(newWordlist);
|
44
|
-
} else if (config.source.trigger) {
|
45
|
-
console.log('wait for trigger');
|
46
|
-
} else {
|
47
|
-
console.error('Error fetching wordlist.');
|
48
|
-
}
|
49
|
-
};
|
50
|
-
|
51
|
-
if (Array.isArray(config.source)) {
|
52
|
-
setWordlist(config.source);
|
53
|
-
} else if (typeof config.source === 'object') {
|
54
|
-
fetchWordlist();
|
55
|
-
}
|
56
|
-
}
|
57
|
-
}, [config.source, debug, sharedData]);
|
58
|
-
|
59
|
-
useEffect(() => {
|
60
|
-
// 更新inputValue,但不要影响其他组件的共享数据
|
61
|
-
setInputValue(sharedData[id] || '');
|
62
|
-
}, [sharedData, id]);
|
63
|
-
|
64
|
-
const handleInputChange = (e) => {
|
65
|
-
const inputValue = e.target.value;
|
66
|
-
const inputValueLowerCase = inputValue.trim().toLowerCase();
|
67
|
-
setInputValue(inputValue);
|
68
|
-
|
69
|
-
if (inputValue.length >= suggestLen) {
|
70
|
-
setSuggestions(
|
71
|
-
wordlist
|
72
|
-
.filter((word) =>
|
73
|
-
word.toLowerCase().includes(inputValueLowerCase),
|
74
|
-
)
|
75
|
-
.slice(0, wordlimit),
|
76
|
-
);
|
77
|
-
}
|
78
|
-
|
79
|
-
if (
|
80
|
-
config.save &&
|
81
|
-
(wordlist.includes(inputValue) || inputValue === '')
|
82
|
-
) {
|
83
|
-
setSharedData((prevSharedData) => ({
|
84
|
-
...prevSharedData,
|
85
|
-
[config.save]: inputValue,
|
86
|
-
}));
|
87
|
-
}
|
88
|
-
};
|
89
|
-
|
90
|
-
const handleSuggestionClick = (suggestion) => {
|
91
|
-
setInputValue(suggestion);
|
92
|
-
setSuggestions([]);
|
93
|
-
|
94
|
-
if (config.save) {
|
95
|
-
setSharedData((prevSharedData) => ({
|
96
|
-
...prevSharedData,
|
97
|
-
[config.save]: suggestion,
|
98
|
-
}));
|
99
|
-
}
|
100
|
-
};
|
101
|
-
|
102
|
-
return (
|
103
|
-
<div
|
104
|
-
id={id}
|
105
|
-
style={{ ...style, ..._style }}
|
106
|
-
className={className}>
|
107
|
-
{title && <h3>{title}</h3>}
|
108
|
-
<div className='autosuggestion'>
|
109
|
-
<input
|
110
|
-
type='text'
|
111
|
-
placeholder={placeholder}
|
112
|
-
style={searchStyle}
|
113
|
-
value={inputValue}
|
114
|
-
onChange={handleInputChange}
|
115
|
-
/>
|
116
|
-
<ul className='suggestion-list'>
|
117
|
-
{suggestions.map((suggestion, index) => (
|
118
|
-
<li
|
119
|
-
key={index}
|
120
|
-
className='suggestion-item'
|
121
|
-
onClick={() => handleSuggestionClick(suggestion)}>
|
122
|
-
{suggestion}
|
123
|
-
</li>
|
124
|
-
))}
|
125
|
-
</ul>
|
126
|
-
</div>
|
127
|
-
</div>
|
128
|
-
);
|
129
|
-
}
|
130
|
-
|
131
|
-
export default SearchBar;
|
1
|
+
import React, { useState, useEffect } from 'react';
|
2
|
+
import '../../_css/autoSuggestion.css';
|
3
|
+
import { useAppContext } from '../appContext';
|
4
|
+
import conditionalFetch from '../fetch/condfetch';
|
5
|
+
|
6
|
+
function SearchBar({ props, style }) {
|
7
|
+
const [suggestions, setSuggestions] = useState([]);
|
8
|
+
const [wordlist, setWordlist] = useState([]);
|
9
|
+
const [inputValue, setInputValue] = useState('');
|
10
|
+
|
11
|
+
const { sharedData, setSharedData } = useAppContext();
|
12
|
+
|
13
|
+
const {
|
14
|
+
id,
|
15
|
+
title = 'Search',
|
16
|
+
className,
|
17
|
+
style: _style = { height: '130px', width: '200px' },
|
18
|
+
placeholder = 'Search...',
|
19
|
+
wordlimit = 15,
|
20
|
+
suggestLen = 3,
|
21
|
+
searchStyle = {
|
22
|
+
borderRadius: '15px',
|
23
|
+
width: '100%',
|
24
|
+
},
|
25
|
+
config = {},
|
26
|
+
debug,
|
27
|
+
} = props;
|
28
|
+
|
29
|
+
if (config.save && typeof config.save !== 'string') config.save = id;
|
30
|
+
|
31
|
+
useEffect(() => {
|
32
|
+
if (config.source) {
|
33
|
+
const fetchWordlist = async () => {
|
34
|
+
const response = await conditionalFetch(
|
35
|
+
config.source,
|
36
|
+
sharedData,
|
37
|
+
null,
|
38
|
+
null,
|
39
|
+
);
|
40
|
+
if (response) {
|
41
|
+
const newWordlist =
|
42
|
+
response[config.source.responseKey] || response;
|
43
|
+
setWordlist(newWordlist);
|
44
|
+
} else if (config.source.trigger) {
|
45
|
+
console.log('wait for trigger');
|
46
|
+
} else {
|
47
|
+
console.error('Error fetching wordlist.');
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
if (Array.isArray(config.source)) {
|
52
|
+
setWordlist(config.source);
|
53
|
+
} else if (typeof config.source === 'object') {
|
54
|
+
fetchWordlist();
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}, [config.source, debug, sharedData]);
|
58
|
+
|
59
|
+
useEffect(() => {
|
60
|
+
// 更新inputValue,但不要影响其他组件的共享数据
|
61
|
+
setInputValue(sharedData[id] || '');
|
62
|
+
}, [sharedData, id]);
|
63
|
+
|
64
|
+
const handleInputChange = (e) => {
|
65
|
+
const inputValue = e.target.value;
|
66
|
+
const inputValueLowerCase = inputValue.trim().toLowerCase();
|
67
|
+
setInputValue(inputValue);
|
68
|
+
|
69
|
+
if (inputValue.length >= suggestLen) {
|
70
|
+
setSuggestions(
|
71
|
+
wordlist
|
72
|
+
.filter((word) =>
|
73
|
+
word.toLowerCase().includes(inputValueLowerCase),
|
74
|
+
)
|
75
|
+
.slice(0, wordlimit),
|
76
|
+
);
|
77
|
+
}
|
78
|
+
|
79
|
+
if (
|
80
|
+
config.save &&
|
81
|
+
(wordlist.includes(inputValue) || inputValue === '')
|
82
|
+
) {
|
83
|
+
setSharedData((prevSharedData) => ({
|
84
|
+
...prevSharedData,
|
85
|
+
[config.save]: inputValue,
|
86
|
+
}));
|
87
|
+
}
|
88
|
+
};
|
89
|
+
|
90
|
+
const handleSuggestionClick = (suggestion) => {
|
91
|
+
setInputValue(suggestion);
|
92
|
+
setSuggestions([]);
|
93
|
+
|
94
|
+
if (config.save) {
|
95
|
+
setSharedData((prevSharedData) => ({
|
96
|
+
...prevSharedData,
|
97
|
+
[config.save]: suggestion,
|
98
|
+
}));
|
99
|
+
}
|
100
|
+
};
|
101
|
+
|
102
|
+
return (
|
103
|
+
<div
|
104
|
+
id={id}
|
105
|
+
style={{ ...style, ..._style }}
|
106
|
+
className={className}>
|
107
|
+
{title && <h3>{title}</h3>}
|
108
|
+
<div className='autosuggestion'>
|
109
|
+
<input
|
110
|
+
type='text'
|
111
|
+
placeholder={placeholder}
|
112
|
+
style={searchStyle}
|
113
|
+
value={inputValue}
|
114
|
+
onChange={handleInputChange}
|
115
|
+
/>
|
116
|
+
<ul className='suggestion-list'>
|
117
|
+
{suggestions.map((suggestion, index) => (
|
118
|
+
<li
|
119
|
+
key={index}
|
120
|
+
className='suggestion-item'
|
121
|
+
onClick={() => handleSuggestionClick(suggestion)}>
|
122
|
+
{suggestion}
|
123
|
+
</li>
|
124
|
+
))}
|
125
|
+
</ul>
|
126
|
+
</div>
|
127
|
+
</div>
|
128
|
+
);
|
129
|
+
}
|
130
|
+
|
131
|
+
export default SearchBar;
|
@@ -1,193 +1,193 @@
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
2
|
-
import { useAppContext } from '../appContext';
|
3
|
-
import simplefetch from '../fetch/fetch';
|
4
|
-
import Select from 'react-select';
|
5
|
-
|
6
|
-
function Selection({ props, style }) {
|
7
|
-
const { debug } = props;
|
8
|
-
const { style: _style } = props;
|
9
|
-
|
10
|
-
// Render title if it exists
|
11
|
-
const { title } = props;
|
12
|
-
const renderTitle = () => {
|
13
|
-
return title && <h3>{title}</h3>;
|
14
|
-
};
|
15
|
-
|
16
|
-
// If val is exist, store it to SharedData
|
17
|
-
const { sharedData, setSharedData } = useAppContext();
|
18
|
-
|
19
|
-
// store attr in state so that we can update it when it changes
|
20
|
-
const [selected, setSelected] = useState([]);
|
21
|
-
|
22
|
-
// store options in state so that we can update it when it changes
|
23
|
-
const [selectionOptions, setSelectionOptions] = useState([]);
|
24
|
-
|
25
|
-
const [menuIsOpen, setMenuIsOpen] = useState();
|
26
|
-
|
27
|
-
useEffect(() => {
|
28
|
-
const { selection, urlval, rm_suffix, nested = false, entry } = props;
|
29
|
-
|
30
|
-
const fetchData = async () => {
|
31
|
-
if (nested) {
|
32
|
-
if (entry) {
|
33
|
-
const entryValue = sharedData[entry];
|
34
|
-
if (entryValue && entryValue.length > 0) {
|
35
|
-
if (debug)
|
36
|
-
console.log('Selection: entryValue:', entryValue);
|
37
|
-
if (debug)
|
38
|
-
console.log(
|
39
|
-
'Selection: nested url:',
|
40
|
-
selection + entryValue[0],
|
41
|
-
urlval,
|
42
|
-
);
|
43
|
-
try {
|
44
|
-
const response = await simplefetch(
|
45
|
-
selection + entryValue[0],
|
46
|
-
{
|
47
|
-
key: urlval,
|
48
|
-
debug: debug,
|
49
|
-
},
|
50
|
-
);
|
51
|
-
// remove the suffix "_metadata" from the options
|
52
|
-
try {
|
53
|
-
const removed_suffix = response.map((item) =>
|
54
|
-
item.replace(rm_suffix, ''),
|
55
|
-
);
|
56
|
-
// insert the "None" into removed_Suffix
|
57
|
-
removed_suffix.unshift('None');
|
58
|
-
if (debug)
|
59
|
-
console.log(
|
60
|
-
'Removed suffix:',
|
61
|
-
removed_suffix,
|
62
|
-
);
|
63
|
-
setSelectionOptions(removed_suffix);
|
64
|
-
} catch (error) {
|
65
|
-
setSelectionOptions([]);
|
66
|
-
}
|
67
|
-
} catch (error) {
|
68
|
-
console.error('Error fetching options:', error);
|
69
|
-
}
|
70
|
-
}
|
71
|
-
} else
|
72
|
-
console.error(
|
73
|
-
'Error: nested is true but entry is not defined.',
|
74
|
-
);
|
75
|
-
} else {
|
76
|
-
try {
|
77
|
-
const response = await simplefetch(selection, {
|
78
|
-
key: urlval,
|
79
|
-
debug: debug,
|
80
|
-
});
|
81
|
-
// remove the suffix "_metadata" from the options
|
82
|
-
try {
|
83
|
-
const removed_suffix = response.map((item) =>
|
84
|
-
item.replace(rm_suffix, ''),
|
85
|
-
);
|
86
|
-
//console.log("Removed suffix:", removed_suffix);
|
87
|
-
setSelectionOptions(removed_suffix);
|
88
|
-
} catch (error) {
|
89
|
-
setSelectionOptions(response);
|
90
|
-
}
|
91
|
-
} catch (error) {
|
92
|
-
console.error('Error fetching options:', error);
|
93
|
-
}
|
94
|
-
}
|
95
|
-
};
|
96
|
-
|
97
|
-
fetchData();
|
98
|
-
}, [props, setSelectionOptions, sharedData, debug]);
|
99
|
-
|
100
|
-
const handleChange = (selectedOptions) => {
|
101
|
-
if (single) {
|
102
|
-
// If single selection, selectedOptions will be an object
|
103
|
-
setSelected(selectedOptions ? [selectedOptions] : []);
|
104
|
-
} else {
|
105
|
-
// If multi-selection, selectedOptions will be an array
|
106
|
-
setSelected(selectedOptions || []);
|
107
|
-
}
|
108
|
-
};
|
109
|
-
|
110
|
-
const onInputChange = (inputValue, { action, prevInputValue }) => {
|
111
|
-
if (action === 'input-change') return inputValue;
|
112
|
-
if (action === 'menu-close') {
|
113
|
-
if (prevInputValue) setMenuIsOpen(true);
|
114
|
-
else setMenuIsOpen(undefined);
|
115
|
-
}
|
116
|
-
return prevInputValue;
|
117
|
-
};
|
118
|
-
|
119
|
-
// ----------------- Selection bar ------------------------------------------------
|
120
|
-
const { config = {} } = props;
|
121
|
-
const {
|
122
|
-
bar_width = '300px',
|
123
|
-
bar_margin = '0 auto',
|
124
|
-
bar_maxHeight = '300px',
|
125
|
-
menu_maxHeight = '300px',
|
126
|
-
single = false,
|
127
|
-
} = config;
|
128
|
-
|
129
|
-
const renderSelection = () => {
|
130
|
-
const options = selectionOptions.map((item) => ({
|
131
|
-
value: item,
|
132
|
-
label: item,
|
133
|
-
}));
|
134
|
-
|
135
|
-
return (
|
136
|
-
<div className='select-wrapper'>
|
137
|
-
<Select
|
138
|
-
isMulti={!single}
|
139
|
-
options={options}
|
140
|
-
value={selected}
|
141
|
-
onChange={handleChange}
|
142
|
-
onInputChange={onInputChange}
|
143
|
-
menuIsOpen={menuIsOpen}
|
144
|
-
styles={{
|
145
|
-
container: (provided) => ({
|
146
|
-
...provided,
|
147
|
-
width: bar_width,
|
148
|
-
margin: bar_margin,
|
149
|
-
maxHeight: bar_maxHeight,
|
150
|
-
}),
|
151
|
-
valueContainer: (provided) => ({
|
152
|
-
...provided,
|
153
|
-
maxHeight: bar_maxHeight ?? 'auto',
|
154
|
-
overflowY: 'auto',
|
155
|
-
}),
|
156
|
-
menu: (provided) => ({
|
157
|
-
...provided,
|
158
|
-
maxHeight: menu_maxHeight ?? 'auto', // Set the max height as required
|
159
|
-
overflowY: 'auto', // Enable scroll if exceeds max height
|
160
|
-
}),
|
161
|
-
}}
|
162
|
-
/>
|
163
|
-
</div>
|
164
|
-
);
|
165
|
-
};
|
166
|
-
|
167
|
-
// Store value to SharedData
|
168
|
-
const { id, val } = props;
|
169
|
-
|
170
|
-
useEffect(() => {
|
171
|
-
if (val) {
|
172
|
-
setSharedData((prevSharedData) => {
|
173
|
-
const selectedValues = selected
|
174
|
-
? selected.map((option) => option.value)
|
175
|
-
: [];
|
176
|
-
//console.log("Selection: selected:", selectedValues);
|
177
|
-
return { ...prevSharedData, [val]: selectedValues };
|
178
|
-
});
|
179
|
-
}
|
180
|
-
}, [selected, val, setSharedData]);
|
181
|
-
|
182
|
-
return (
|
183
|
-
<div
|
184
|
-
key={id}
|
185
|
-
style={{ ...style, ..._style }}
|
186
|
-
className='selection-box-container'>
|
187
|
-
{renderTitle()}
|
188
|
-
{renderSelection()}
|
189
|
-
</div>
|
190
|
-
);
|
191
|
-
}
|
192
|
-
|
193
|
-
export default Selection;
|
1
|
+
import React, { useEffect, useState } from 'react';
|
2
|
+
import { useAppContext } from '../appContext';
|
3
|
+
import simplefetch from '../fetch/fetch';
|
4
|
+
import Select from 'react-select';
|
5
|
+
|
6
|
+
function Selection({ props, style }) {
|
7
|
+
const { debug } = props;
|
8
|
+
const { style: _style } = props;
|
9
|
+
|
10
|
+
// Render title if it exists
|
11
|
+
const { title } = props;
|
12
|
+
const renderTitle = () => {
|
13
|
+
return title && <h3>{title}</h3>;
|
14
|
+
};
|
15
|
+
|
16
|
+
// If val is exist, store it to SharedData
|
17
|
+
const { sharedData, setSharedData } = useAppContext();
|
18
|
+
|
19
|
+
// store attr in state so that we can update it when it changes
|
20
|
+
const [selected, setSelected] = useState([]);
|
21
|
+
|
22
|
+
// store options in state so that we can update it when it changes
|
23
|
+
const [selectionOptions, setSelectionOptions] = useState([]);
|
24
|
+
|
25
|
+
const [menuIsOpen, setMenuIsOpen] = useState();
|
26
|
+
|
27
|
+
useEffect(() => {
|
28
|
+
const { selection, urlval, rm_suffix, nested = false, entry } = props;
|
29
|
+
|
30
|
+
const fetchData = async () => {
|
31
|
+
if (nested) {
|
32
|
+
if (entry) {
|
33
|
+
const entryValue = sharedData[entry];
|
34
|
+
if (entryValue && entryValue.length > 0) {
|
35
|
+
if (debug)
|
36
|
+
console.log('Selection: entryValue:', entryValue);
|
37
|
+
if (debug)
|
38
|
+
console.log(
|
39
|
+
'Selection: nested url:',
|
40
|
+
selection + entryValue[0],
|
41
|
+
urlval,
|
42
|
+
);
|
43
|
+
try {
|
44
|
+
const response = await simplefetch(
|
45
|
+
selection + entryValue[0],
|
46
|
+
{
|
47
|
+
key: urlval,
|
48
|
+
debug: debug,
|
49
|
+
},
|
50
|
+
);
|
51
|
+
// remove the suffix "_metadata" from the options
|
52
|
+
try {
|
53
|
+
const removed_suffix = response.map((item) =>
|
54
|
+
item.replace(rm_suffix, ''),
|
55
|
+
);
|
56
|
+
// insert the "None" into removed_Suffix
|
57
|
+
removed_suffix.unshift('None');
|
58
|
+
if (debug)
|
59
|
+
console.log(
|
60
|
+
'Removed suffix:',
|
61
|
+
removed_suffix,
|
62
|
+
);
|
63
|
+
setSelectionOptions(removed_suffix);
|
64
|
+
} catch (error) {
|
65
|
+
setSelectionOptions([]);
|
66
|
+
}
|
67
|
+
} catch (error) {
|
68
|
+
console.error('Error fetching options:', error);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
} else
|
72
|
+
console.error(
|
73
|
+
'Error: nested is true but entry is not defined.',
|
74
|
+
);
|
75
|
+
} else {
|
76
|
+
try {
|
77
|
+
const response = await simplefetch(selection, {
|
78
|
+
key: urlval,
|
79
|
+
debug: debug,
|
80
|
+
});
|
81
|
+
// remove the suffix "_metadata" from the options
|
82
|
+
try {
|
83
|
+
const removed_suffix = response.map((item) =>
|
84
|
+
item.replace(rm_suffix, ''),
|
85
|
+
);
|
86
|
+
//console.log("Removed suffix:", removed_suffix);
|
87
|
+
setSelectionOptions(removed_suffix);
|
88
|
+
} catch (error) {
|
89
|
+
setSelectionOptions(response);
|
90
|
+
}
|
91
|
+
} catch (error) {
|
92
|
+
console.error('Error fetching options:', error);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
};
|
96
|
+
|
97
|
+
fetchData();
|
98
|
+
}, [props, setSelectionOptions, sharedData, debug]);
|
99
|
+
|
100
|
+
const handleChange = (selectedOptions) => {
|
101
|
+
if (single) {
|
102
|
+
// If single selection, selectedOptions will be an object
|
103
|
+
setSelected(selectedOptions ? [selectedOptions] : []);
|
104
|
+
} else {
|
105
|
+
// If multi-selection, selectedOptions will be an array
|
106
|
+
setSelected(selectedOptions || []);
|
107
|
+
}
|
108
|
+
};
|
109
|
+
|
110
|
+
const onInputChange = (inputValue, { action, prevInputValue }) => {
|
111
|
+
if (action === 'input-change') return inputValue;
|
112
|
+
if (action === 'menu-close') {
|
113
|
+
if (prevInputValue) setMenuIsOpen(true);
|
114
|
+
else setMenuIsOpen(undefined);
|
115
|
+
}
|
116
|
+
return prevInputValue;
|
117
|
+
};
|
118
|
+
|
119
|
+
// ----------------- Selection bar ------------------------------------------------
|
120
|
+
const { config = {} } = props;
|
121
|
+
const {
|
122
|
+
bar_width = '300px',
|
123
|
+
bar_margin = '0 auto',
|
124
|
+
bar_maxHeight = '300px',
|
125
|
+
menu_maxHeight = '300px',
|
126
|
+
single = false,
|
127
|
+
} = config;
|
128
|
+
|
129
|
+
const renderSelection = () => {
|
130
|
+
const options = selectionOptions.map((item) => ({
|
131
|
+
value: item,
|
132
|
+
label: item,
|
133
|
+
}));
|
134
|
+
|
135
|
+
return (
|
136
|
+
<div className='select-wrapper'>
|
137
|
+
<Select
|
138
|
+
isMulti={!single}
|
139
|
+
options={options}
|
140
|
+
value={selected}
|
141
|
+
onChange={handleChange}
|
142
|
+
onInputChange={onInputChange}
|
143
|
+
menuIsOpen={menuIsOpen}
|
144
|
+
styles={{
|
145
|
+
container: (provided) => ({
|
146
|
+
...provided,
|
147
|
+
width: bar_width,
|
148
|
+
margin: bar_margin,
|
149
|
+
maxHeight: bar_maxHeight,
|
150
|
+
}),
|
151
|
+
valueContainer: (provided) => ({
|
152
|
+
...provided,
|
153
|
+
maxHeight: bar_maxHeight ?? 'auto',
|
154
|
+
overflowY: 'auto',
|
155
|
+
}),
|
156
|
+
menu: (provided) => ({
|
157
|
+
...provided,
|
158
|
+
maxHeight: menu_maxHeight ?? 'auto', // Set the max height as required
|
159
|
+
overflowY: 'auto', // Enable scroll if exceeds max height
|
160
|
+
}),
|
161
|
+
}}
|
162
|
+
/>
|
163
|
+
</div>
|
164
|
+
);
|
165
|
+
};
|
166
|
+
|
167
|
+
// Store value to SharedData
|
168
|
+
const { id, val } = props;
|
169
|
+
|
170
|
+
useEffect(() => {
|
171
|
+
if (val) {
|
172
|
+
setSharedData((prevSharedData) => {
|
173
|
+
const selectedValues = selected
|
174
|
+
? selected.map((option) => option.value)
|
175
|
+
: [];
|
176
|
+
//console.log("Selection: selected:", selectedValues);
|
177
|
+
return { ...prevSharedData, [val]: selectedValues };
|
178
|
+
});
|
179
|
+
}
|
180
|
+
}, [selected, val, setSharedData]);
|
181
|
+
|
182
|
+
return (
|
183
|
+
<div
|
184
|
+
key={id}
|
185
|
+
style={{ ...style, ..._style }}
|
186
|
+
className='selection-box-container'>
|
187
|
+
{renderTitle()}
|
188
|
+
{renderSelection()}
|
189
|
+
</div>
|
190
|
+
);
|
191
|
+
}
|
192
|
+
|
193
|
+
export default Selection;
|