@haniffalab/cherita-react 1.2.0 → 1.3.0-dev.2025-05-28.9afc380f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/cjs/components/controls/Controls.js +60 -0
  2. package/dist/cjs/components/dotplot/Dotplot.js +47 -38
  3. package/dist/cjs/components/dotplot/DotplotControls.js +77 -114
  4. package/dist/cjs/components/full-page/FullPage.js +29 -33
  5. package/dist/cjs/components/full-page/FullPagePseudospatial.js +30 -33
  6. package/dist/cjs/components/heatmap/Heatmap.js +33 -22
  7. package/dist/cjs/components/heatmap/HeatmapControls.js +2 -19
  8. package/dist/cjs/components/matrixplot/Matrixplot.js +35 -24
  9. package/dist/cjs/components/matrixplot/MatrixplotControls.js +4 -34
  10. package/dist/cjs/components/obs-list/ObsItem.js +63 -51
  11. package/dist/cjs/components/obs-list/ObsList.js +53 -48
  12. package/dist/cjs/components/obsm-list/ObsmList.js +17 -12
  13. package/dist/cjs/components/offcanvas/index.js +14 -11
  14. package/dist/cjs/components/pseudospatial/Pseudospatial.js +78 -68
  15. package/dist/cjs/components/pseudospatial/PseudospatialToolbar.js +27 -21
  16. package/dist/cjs/components/scatterplot/Scatterplot.js +82 -76
  17. package/dist/cjs/components/scatterplot/ScatterplotControls.js +18 -31
  18. package/dist/cjs/components/scatterplot/SpatialControls.js +53 -23
  19. package/dist/cjs/components/scatterplot/Toolbox.js +1 -18
  20. package/dist/cjs/components/search-bar/SearchBar.js +156 -59
  21. package/dist/cjs/components/search-bar/SearchInfo.js +182 -0
  22. package/dist/cjs/components/search-bar/SearchResults.js +90 -60
  23. package/dist/cjs/components/var-list/VarItem.js +52 -75
  24. package/dist/cjs/components/var-list/VarList.js +47 -172
  25. package/dist/cjs/components/var-list/VarListToolbar.js +7 -8
  26. package/dist/cjs/components/var-list/VarSet.js +66 -57
  27. package/dist/cjs/components/violin/Violin.js +54 -43
  28. package/dist/cjs/components/violin/ViolinControls.js +4 -20
  29. package/dist/cjs/context/DatasetContext.js +26 -513
  30. package/dist/cjs/context/FilterContext.js +9 -8
  31. package/dist/cjs/context/SettingsContext.js +539 -0
  32. package/dist/cjs/context/ZarrDataContext.js +1 -2
  33. package/dist/cjs/helpers/color-helper.js +8 -8
  34. package/dist/cjs/helpers/zarr-helper.js +19 -16
  35. package/dist/cjs/utils/Filter.js +25 -21
  36. package/dist/cjs/utils/Histogram.js +4 -3
  37. package/dist/cjs/utils/ImageViewer.js +1 -2
  38. package/dist/cjs/utils/Legend.js +18 -12
  39. package/dist/cjs/utils/LoadingIndicators.js +1 -1
  40. package/dist/cjs/utils/VirtualizedList.js +16 -13
  41. package/dist/cjs/utils/errors.js +20 -22
  42. package/dist/cjs/utils/requests.js +13 -10
  43. package/dist/cjs/utils/zarrData.js +31 -50
  44. package/dist/css/cherita.css +84 -24
  45. package/dist/css/cherita.css.map +1 -1
  46. package/dist/esm/components/controls/Controls.js +51 -0
  47. package/dist/esm/components/dotplot/Dotplot.js +47 -37
  48. package/dist/esm/components/dotplot/DotplotControls.js +77 -112
  49. package/dist/esm/components/full-page/FullPage.js +29 -32
  50. package/dist/esm/components/full-page/FullPagePseudospatial.js +30 -32
  51. package/dist/esm/components/heatmap/Heatmap.js +32 -20
  52. package/dist/esm/components/heatmap/HeatmapControls.js +3 -20
  53. package/dist/esm/components/matrixplot/Matrixplot.js +34 -22
  54. package/dist/esm/components/matrixplot/MatrixplotControls.js +5 -35
  55. package/dist/esm/components/obs-list/ObsItem.js +63 -49
  56. package/dist/esm/components/obs-list/ObsList.js +53 -47
  57. package/dist/esm/components/obsm-list/ObsmList.js +17 -11
  58. package/dist/esm/components/offcanvas/index.js +14 -11
  59. package/dist/esm/components/pseudospatial/Pseudospatial.js +77 -66
  60. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +27 -20
  61. package/dist/esm/components/scatterplot/Scatterplot.js +81 -74
  62. package/dist/esm/components/scatterplot/ScatterplotControls.js +18 -29
  63. package/dist/esm/components/scatterplot/SpatialControls.js +54 -23
  64. package/dist/esm/components/scatterplot/Toolbox.js +1 -18
  65. package/dist/esm/components/search-bar/SearchBar.js +156 -59
  66. package/dist/esm/components/search-bar/SearchInfo.js +173 -0
  67. package/dist/esm/components/search-bar/SearchResults.js +91 -60
  68. package/dist/esm/components/var-list/VarItem.js +53 -76
  69. package/dist/esm/components/var-list/VarList.js +47 -171
  70. package/dist/esm/components/var-list/VarListToolbar.js +6 -6
  71. package/dist/esm/components/var-list/VarSet.js +67 -57
  72. package/dist/esm/components/violin/Violin.js +53 -41
  73. package/dist/esm/components/violin/ViolinControls.js +5 -21
  74. package/dist/esm/context/DatasetContext.js +25 -510
  75. package/dist/esm/context/FilterContext.js +8 -6
  76. package/dist/esm/context/SettingsContext.js +528 -0
  77. package/dist/esm/helpers/color-helper.js +8 -8
  78. package/dist/esm/helpers/zarr-helper.js +19 -16
  79. package/dist/esm/utils/Filter.js +25 -21
  80. package/dist/esm/utils/Histogram.js +4 -3
  81. package/dist/esm/utils/Legend.js +17 -10
  82. package/dist/esm/utils/LoadingIndicators.js +1 -1
  83. package/dist/esm/utils/VirtualizedList.js +15 -11
  84. package/dist/esm/utils/errors.js +20 -22
  85. package/dist/esm/utils/requests.js +13 -10
  86. package/dist/esm/utils/zarrData.js +33 -51
  87. package/package.json +6 -3
  88. package/scss/cherita.scss +50 -9
  89. package/scss/components/layouts.scss +24 -13
  90. package/scss/components/lists.scss +10 -0
  91. package/scss/components/plots.scss +3 -5
@@ -1,16 +1,26 @@
1
- import React, { useState, useEffect, useMemo, useDeferredValue } from "react";
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React, { useDeferredValue, useEffect, useMemo, useState } from "react";
7
+ import { faPlus } from "@fortawesome/free-solid-svg-icons";
8
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
2
9
  import _ from "lodash";
3
- import { Dropdown } from "react-bootstrap";
4
- import { useDatasetDispatch } from "../../context/DatasetContext";
10
+ import { Button, ListGroup } from "react-bootstrap";
11
+ import { useSettingsDispatch } from "../../context/SettingsContext";
5
12
  import { useDiseaseSearch, useVarSearch } from "../../utils/search";
13
+ import { VirtualizedList } from "../../utils/VirtualizedList";
6
14
  export function VarSearchResults(_ref) {
7
15
  let {
8
16
  text,
9
- setShowSuggestions,
10
- handleSelect
17
+ handleSelect,
18
+ selectedResult,
19
+ setSelectedResult,
20
+ setResultsLength
11
21
  } = _ref;
12
22
  const [suggestions, setSuggestions] = useState([]);
13
- const dispatch = useDatasetDispatch();
23
+ const dispatch = useSettingsDispatch();
14
24
  const {
15
25
  setParams,
16
26
  data: {
@@ -25,57 +35,76 @@ export function VarSearchResults(_ref) {
25
35
  const setData = text => {
26
36
  if (text.length) {
27
37
  setParams(p => {
28
- return {
29
- ...p,
38
+ return _objectSpread(_objectSpread({}, p), {}, {
30
39
  text: text
31
- };
40
+ });
32
41
  });
33
42
  } else {
34
43
  setSuggestions([]);
35
- setShowSuggestions(false);
36
44
  }
37
45
  };
38
46
  return _.debounce(setData, 300);
39
- }, [setParams, setShowSuggestions]);
47
+ }, [setParams]);
40
48
  useEffect(() => {
41
49
  updateParams(text);
42
50
  }, [text, updateParams]);
43
51
  useEffect(() => {
44
52
  if (!isPending && !serverError) {
45
53
  setSuggestions(fetchedData);
46
- setShowSuggestions(true);
54
+ setResultsLength(fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.length);
55
+ }
56
+ }, [fetchedData, isPending, serverError, setResultsLength]);
57
+ const getDataAtIndex = index => deferredData[index];
58
+ const ItemComponent = item => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
59
+ className: "virtualized-list-wrapper"
60
+ }, /*#__PURE__*/React.createElement(ListGroup.Item, {
61
+ key: item,
62
+ onClick: () => {
63
+ setSelectedResult(item);
64
+ },
65
+ active: (selectedResult === null || selectedResult === void 0 ? void 0 : selectedResult.index) === item.index
66
+ }, /*#__PURE__*/React.createElement("div", {
67
+ className: "d-flex justify-content-between align-items-center w-100"
68
+ }, /*#__PURE__*/React.createElement("div", null, item.name), /*#__PURE__*/React.createElement("div", {
69
+ className: "d-flex align-items-center gap-1"
70
+ }, /*#__PURE__*/React.createElement(Button, {
71
+ type: "button",
72
+ className: "m-0 p-0 px-1",
73
+ variant: "outline-secondary",
74
+ title: "Add to list",
75
+ disabled: isStale,
76
+ onClick: () => {
77
+ handleSelect(dispatch, item);
47
78
  }
48
- }, [fetchedData, isPending, serverError, setShowSuggestions]);
49
- const suggestionsList = useMemo(() => {
50
- return deferredData?.map(item => {
51
- return /*#__PURE__*/React.createElement(Dropdown.Item, {
52
- key: item.name,
53
- as: "button",
54
- disabled: isStale,
55
- onClick: () => {
56
- handleSelect(dispatch, item);
57
- _.delay(() => {
58
- setShowSuggestions(false);
59
- }, 150);
60
- }
61
- }, item.name);
62
- });
63
- }, [deferredData, dispatch, handleSelect, isStale, setShowSuggestions]);
64
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Dropdown.Header, null, "Features"), /*#__PURE__*/React.createElement("div", {
79
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
80
+ icon: faPlus
81
+ })))))));
82
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
65
83
  className: "search-results"
66
- }, deferredData?.length ? suggestionsList : /*#__PURE__*/React.createElement(Dropdown.Item, {
84
+ }, /*#__PURE__*/React.createElement(ListGroup, {
85
+ variant: "flush",
86
+ className: "cherita-list"
87
+ }, deferredData !== null && deferredData !== void 0 && deferredData.length ? /*#__PURE__*/React.createElement(VirtualizedList, {
88
+ getDataAtIndex: getDataAtIndex,
89
+ count: deferredData.length,
90
+ ItemComponent: ItemComponent,
91
+ overscan: 500,
92
+ estimateSize: 42,
93
+ maxHeight: "70vh"
94
+ }) : /*#__PURE__*/React.createElement(ListGroup.Item, {
67
95
  key: "empty",
68
96
  as: "button",
69
97
  disabled: true
70
- }, !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data")));
98
+ }, !text.length ? "Search features" : !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data"))));
71
99
  }
72
100
  export function DiseasesSearchResults(_ref2) {
73
101
  let {
74
102
  text,
75
- setShowSuggestions
103
+ selectedResult,
104
+ setSelectedResult,
105
+ setResultsLength
76
106
  } = _ref2;
77
107
  const [suggestions, setSuggestions] = useState([]);
78
- const dispatch = useDatasetDispatch();
79
108
  const {
80
109
  setParams,
81
110
  data: {
@@ -90,10 +119,9 @@ export function DiseasesSearchResults(_ref2) {
90
119
  const setData = text => {
91
120
  if (text.length) {
92
121
  setParams(p => {
93
- return {
94
- ...p,
122
+ return _objectSpread(_objectSpread({}, p), {}, {
95
123
  text: text
96
- };
124
+ });
97
125
  });
98
126
  } else {
99
127
  setSuggestions([]);
@@ -107,33 +135,36 @@ export function DiseasesSearchResults(_ref2) {
107
135
  useEffect(() => {
108
136
  if (!isPending && !serverError) {
109
137
  setSuggestions(fetchedData);
110
- setShowSuggestions(true);
138
+ setResultsLength(fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.length);
111
139
  }
112
- }, [fetchedData, isPending, serverError, setShowSuggestions]);
113
- const suggestionsList = useMemo(() => {
114
- return deferredData?.map(item => {
115
- return /*#__PURE__*/React.createElement(Dropdown.Item, {
116
- key: item.id,
117
- as: "button",
118
- disabled: isStale,
119
- onClick: () => {
120
- dispatch({
121
- type: "select.disease",
122
- id: item.disease_id,
123
- name: item.disease_name
124
- });
125
- _.delay(() => {
126
- setShowSuggestions(false);
127
- }, 150);
128
- }
129
- }, item.disease_name);
130
- });
131
- }, [deferredData, dispatch, isStale, setShowSuggestions]);
132
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Dropdown.Header, null, "Diseases"), /*#__PURE__*/React.createElement("div", {
140
+ }, [fetchedData, isPending, serverError, setResultsLength]);
141
+ const getDataAtIndex = index => deferredData[index];
142
+ const ItemComponent = item => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
143
+ className: "virtualized-list-wrapper"
144
+ }, /*#__PURE__*/React.createElement(ListGroup.Item, {
145
+ key: item.name,
146
+ onClick: () => {
147
+ setSelectedResult(item);
148
+ },
149
+ active: (selectedResult === null || selectedResult === void 0 ? void 0 : selectedResult.id) === item.id
150
+ }, /*#__PURE__*/React.createElement("div", {
151
+ className: "d-flex justify-content-between align-items-center w-100"
152
+ }, /*#__PURE__*/React.createElement("div", null, item.disease_name)))));
153
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
133
154
  className: "search-results"
134
- }, deferredData?.length ? suggestionsList : /*#__PURE__*/React.createElement(Dropdown.Item, {
155
+ }, /*#__PURE__*/React.createElement(ListGroup, {
156
+ variant: "flush",
157
+ className: "cherita-list"
158
+ }, deferredData !== null && deferredData !== void 0 && deferredData.length ? /*#__PURE__*/React.createElement(VirtualizedList, {
159
+ getDataAtIndex: getDataAtIndex,
160
+ count: deferredData.length,
161
+ ItemComponent: ItemComponent,
162
+ overscan: 250,
163
+ estimateSize: 32,
164
+ maxHeight: "70vh"
165
+ }) : /*#__PURE__*/React.createElement(ListGroup.Item, {
135
166
  key: "empty",
136
167
  as: "button",
137
168
  disabled: true
138
- }, !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data")));
169
+ }, !text.length ? "Search diseases" : !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data"))));
139
170
  }
@@ -1,27 +1,34 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
1
7
  import React, { useEffect, useState } from "react";
2
- import { faDroplet, faTrash } from "@fortawesome/free-solid-svg-icons";
8
+ import { faDroplet, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
3
9
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
10
  import { MoreVert } from "@mui/icons-material";
5
11
  import _ from "lodash";
6
12
  import { Button, Collapse, ListGroup, Table } from "react-bootstrap";
7
13
  import { COLOR_ENCODINGS, SELECTION_MODES } from "../../constants/constants";
8
- import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
14
+ import { useDataset } from "../../context/DatasetContext";
9
15
  import { useFilteredData } from "../../context/FilterContext";
16
+ import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
10
17
  import { Histogram } from "../../utils/Histogram";
11
- import { useFetch, useDebouncedFetch } from "../../utils/requests";
12
- import { VirtualizedList } from "../../utils/VirtualizedList";
18
+ import { useDebouncedFetch, useFetch } from "../../utils/requests";
13
19
  function VarHistogram(_ref) {
14
20
  let {
15
21
  item
16
22
  } = _ref;
17
23
  const ENDPOINT = "var/histograms";
18
24
  const dataset = useDataset();
25
+ const settings = useSettings();
19
26
  const {
20
27
  obsIndices
21
28
  } = useFilteredData();
22
29
  // @TODO: consider using Filter's isSliced; would trigger more re-renders/requests
23
30
  // const { obsIndices, isSliced } = useFilteredData();
24
- const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
31
+ const isSliced = settings.sliceBy.obs || settings.sliceBy.polygons;
25
32
  const [params, setParams] = useState({
26
33
  url: dataset.url,
27
34
  varKey: item.matrix_index,
@@ -29,10 +36,9 @@ function VarHistogram(_ref) {
29
36
  });
30
37
  useEffect(() => {
31
38
  setParams(p => {
32
- return {
33
- ...p,
39
+ return _objectSpread(_objectSpread({}, p), {}, {
34
40
  obsIndices: isSliced ? [...(obsIndices || [])] : null
35
- };
41
+ });
36
42
  });
37
43
  }, [obsIndices, isSliced]);
38
44
  const {
@@ -49,20 +55,12 @@ function VarHistogram(_ref) {
49
55
  });
50
56
  }
51
57
  function VarDiseaseInfoItem(item) {
52
- const dispatch = useDatasetDispatch();
53
58
  return /*#__PURE__*/React.createElement(ListGroup.Item, {
54
59
  key: item.disease_id,
55
60
  className: "feature-disease-info"
56
61
  }, /*#__PURE__*/React.createElement("button", {
57
62
  type: "button",
58
- className: "btn btn-link disease-link",
59
- onClick: () => {
60
- dispatch({
61
- type: "select.disease",
62
- id: item.disease_id,
63
- name: item.disease_name
64
- });
65
- }
63
+ className: "btn btn-link disease-link"
66
64
  }, item.disease_name), /*#__PURE__*/React.createElement(Table, {
67
65
  striped: true,
68
66
  size: "sm",
@@ -75,27 +73,27 @@ function VarDiseaseInfoItem(item) {
75
73
  }
76
74
  }))));
77
75
  }
78
- function VarDiseaseInfo(_ref2) {
76
+ export function VarDiseaseInfo(_ref2) {
79
77
  let {
80
78
  data
81
79
  } = _ref2;
82
- return /*#__PURE__*/React.createElement(VirtualizedList, {
83
- getDataAtIndex: index => data[index],
84
- count: data.length,
85
- estimateSize: 140,
86
- maxHeight: "40vh",
87
- ItemComponent: VarDiseaseInfoItem
88
- });
80
+ return /*#__PURE__*/React.createElement(ListGroup, {
81
+ className: "feature-disease-info-list"
82
+ }, data.map(item => {
83
+ return /*#__PURE__*/React.createElement(VarDiseaseInfoItem, _extends({
84
+ key: item.disease_id
85
+ }, item));
86
+ }));
89
87
  }
90
- export function SingleSelectionItem(_ref3) {
88
+ export function SelectionItem(_ref3) {
91
89
  let {
92
90
  item,
93
91
  isActive,
94
92
  selectVar,
95
93
  removeVar,
96
- isDiseaseGene = false,
97
94
  showSetColorEncoding = true,
98
- showRemove = true
95
+ showRemove = true,
96
+ isMultiple = false
99
97
  } = _ref3;
100
98
  const ENDPOINT = "disease/gene";
101
99
  const [openInfo, setOpenInfo] = useState(false);
@@ -113,9 +111,9 @@ export function SingleSelectionItem(_ref3) {
113
111
  refetchOnMount: false,
114
112
  enabled: !!dataset.diseaseDatasets.length
115
113
  });
116
- const hasDiseaseInfo = !isPending && !serverError && !!fetchedData?.length;
114
+ const hasDiseaseInfo = !isPending && !serverError && !!(fetchedData !== null && fetchedData !== void 0 && fetchedData.length);
117
115
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
118
- className: `d-flex justify-content-between ${hasDiseaseInfo ? "cursor-pointer" : ""}`,
116
+ className: "d-flex justify-content-between ".concat(hasDiseaseInfo ? "cursor-pointer" : ""),
119
117
  onClick: () => {
120
118
  setOpenInfo(o => !o);
121
119
  }
@@ -123,7 +121,7 @@ export function SingleSelectionItem(_ref3) {
123
121
  className: "d-flex justify-content-between align-items-center w-100"
124
122
  }, /*#__PURE__*/React.createElement("div", null, item.name), /*#__PURE__*/React.createElement("div", {
125
123
  className: "d-flex align-items-center gap-1"
126
- }, hasDiseaseInfo && /*#__PURE__*/React.createElement(MoreVert, null), !isDiseaseGene && /*#__PURE__*/React.createElement(VarHistogram, {
124
+ }, hasDiseaseInfo && /*#__PURE__*/React.createElement(MoreVert, null), /*#__PURE__*/React.createElement(VarHistogram, {
127
125
  item: item
128
126
  }), showSetColorEncoding && /*#__PURE__*/React.createElement(Button, {
129
127
  type: "button",
@@ -138,7 +136,11 @@ export function SingleSelectionItem(_ref3) {
138
136
  title: isNotInData ? "Not present in data" : "Set as color encoding"
139
137
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
140
138
  icon: faDroplet
141
- })), (!isDiseaseGene || !showRemove) && /*#__PURE__*/React.createElement(Button, {
139
+ }), isMultiple && /*#__PURE__*/React.createElement(FontAwesomeIcon, {
140
+ icon: faPlus,
141
+ size: "xs",
142
+ className: "ps-xs-1"
143
+ })), showRemove && /*#__PURE__*/React.createElement(Button, {
142
144
  type: "button",
143
145
  className: "m-0 p-0 px-1",
144
146
  variant: "outline-secondary",
@@ -157,37 +159,14 @@ export function SingleSelectionItem(_ref3) {
157
159
  data: fetchedData
158
160
  }))));
159
161
  }
160
- function MultipleSelectionItem(_ref4) {
161
- let {
162
- item,
163
- isActive,
164
- toggleVar
165
- } = _ref4;
166
- const isNotInData = item.matrix_index === -1;
167
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
168
- className: "d-flex"
169
- }, /*#__PURE__*/React.createElement("div", {
170
- className: "flex-grow-1"
171
- }, /*#__PURE__*/React.createElement(Button, {
172
- type: "button",
173
- key: item.matrix_index,
174
- variant: isActive ? "primary" : "outline-primary",
175
- className: "m-0 p-0 px-1",
176
- onClick: toggleVar,
177
- disabled: isNotInData,
178
- title: isNotInData ? "Not present in data" : item.name
179
- }, item.name))));
180
- }
181
- export function VarItem(_ref5) {
162
+ export function VarItem(_ref4) {
182
163
  let {
183
164
  item,
184
165
  active,
185
- setVarButtons,
186
- mode = SELECTION_MODES.SINGLE,
187
- isDiseaseGene = false
188
- } = _ref5;
189
- const dataset = useDataset();
190
- const dispatch = useDatasetDispatch();
166
+ mode = SELECTION_MODES.SINGLE
167
+ } = _ref4;
168
+ const settings = useSettings();
169
+ const dispatch = useSettingsDispatch();
191
170
  const selectVar = () => {
192
171
  if (mode === SELECTION_MODES.SINGLE) {
193
172
  dispatch({
@@ -210,8 +189,9 @@ export function VarItem(_ref5) {
210
189
  }
211
190
  };
212
191
  const removeVar = () => {
213
- setVarButtons(b => {
214
- return b.filter(i => i.name !== item.name);
192
+ dispatch({
193
+ type: "remove.var",
194
+ var: item
215
195
  });
216
196
  if (mode === SELECTION_MODES.SINGLE) {
217
197
  if (active === item.matrix_index) {
@@ -229,28 +209,25 @@ export function VarItem(_ref5) {
229
209
  }
230
210
  };
231
211
  const toggleVar = () => {
232
- if (active.includes(item.matrix_index)) {
233
- dispatch({
234
- type: "deselect.multivar",
235
- var: item
236
- });
237
- } else {
238
- selectVar(item);
239
- }
212
+ dispatch({
213
+ type: "toggle.multivar",
214
+ var: item
215
+ });
240
216
  };
241
217
  if (item && mode === SELECTION_MODES.SINGLE) {
242
- return /*#__PURE__*/React.createElement(SingleSelectionItem, {
218
+ return /*#__PURE__*/React.createElement(SelectionItem, {
243
219
  item: item,
244
- isActive: dataset.colorEncoding === COLOR_ENCODINGS.VAR && active === item.matrix_index,
220
+ isActive: settings.colorEncoding === COLOR_ENCODINGS.VAR && active === item.matrix_index,
245
221
  selectVar: selectVar,
246
- removeVar: removeVar,
247
- isDiseaseGene: isDiseaseGene
222
+ removeVar: removeVar
248
223
  });
249
224
  } else if (mode === SELECTION_MODES.MULTIPLE) {
250
- return /*#__PURE__*/React.createElement(MultipleSelectionItem, {
225
+ return /*#__PURE__*/React.createElement(SelectionItem, {
251
226
  item: item,
252
227
  isActive: item.matrix_index !== -1 && _.includes(active, item.matrix_index),
253
- toggleVar: toggleVar
228
+ selectVar: toggleVar,
229
+ removeVar: removeVar,
230
+ isMultiple: true
254
231
  });
255
232
  } else {
256
233
  return null;