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,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;