@haniffalab/cherita-react 1.0.0 → 1.1.0

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 (106) hide show
  1. package/LICENSE +1 -1
  2. package/dist/{components → cjs/components}/full-page/FullPage.js +32 -22
  3. package/dist/{components → cjs/components}/full-page/FullPagePseudospatial.js +7 -6
  4. package/dist/{components → cjs/components}/obs-list/ObsItem.js +88 -77
  5. package/dist/{components → cjs/components}/obs-list/ObsList.js +133 -50
  6. package/dist/cjs/components/obs-list/ObsToolbar.js +24 -0
  7. package/dist/{components → cjs/components}/obsm-list/ObsmList.js +8 -5
  8. package/dist/{components → cjs/components}/offcanvas/index.js +24 -20
  9. package/dist/{components → cjs/components}/pseudospatial/Pseudospatial.js +10 -9
  10. package/dist/{components → cjs/components}/pseudospatial/PseudospatialToolbar.js +4 -3
  11. package/dist/{components → cjs/components}/scatterplot/Scatterplot.js +33 -24
  12. package/dist/{components → cjs/components}/scatterplot/SpatialControls.js +43 -42
  13. package/dist/cjs/components/scatterplot/Toolbox.js +62 -0
  14. package/dist/{components → cjs/components}/search-bar/SearchBar.js +24 -7
  15. package/dist/{components → cjs/components}/search-bar/SearchResults.js +13 -17
  16. package/dist/{components → cjs/components}/var-list/VarItem.js +38 -29
  17. package/dist/{components → cjs/components}/var-list/VarList.js +59 -31
  18. package/dist/{components → cjs/components}/var-list/VarListToolbar.js +18 -14
  19. package/dist/{components → cjs/components}/var-list/VarSet.js +24 -20
  20. package/dist/{components → cjs/components}/violin/Violin.js +4 -3
  21. package/dist/{constants → cjs/constants}/constants.js +6 -2
  22. package/dist/{context → cjs/context}/DatasetContext.js +12 -11
  23. package/dist/{context → cjs/context}/FilterContext.js +4 -3
  24. package/dist/{context → cjs/context}/ZarrDataContext.js +4 -3
  25. package/dist/{helpers → cjs/helpers}/color-helper.js +12 -11
  26. package/dist/{helpers → cjs/helpers}/map-helper.js +8 -7
  27. package/dist/{helpers → cjs/helpers}/zarr-helper.js +30 -38
  28. package/dist/{utils → cjs/utils}/Filter.js +1 -1
  29. package/dist/{utils → cjs/utils}/Histogram.js +12 -8
  30. package/dist/{utils → cjs/utils}/ImageViewer.js +6 -5
  31. package/dist/{utils → cjs/utils}/Legend.js +8 -7
  32. package/dist/{utils → cjs/utils}/LoadingIndicators.js +5 -4
  33. package/dist/cjs/utils/Skeleton.js +19 -0
  34. package/dist/{utils → cjs/utils}/VirtualizedList.js +10 -9
  35. package/dist/{utils → cjs/utils}/requests.js +37 -39
  36. package/dist/{utils → cjs/utils}/string.js +9 -4
  37. package/dist/{utils → cjs/utils}/zarrData.js +12 -4
  38. package/dist/css/cherita.css +147 -152
  39. package/dist/css/cherita.css.map +1 -1
  40. package/dist/esm/components/dotplot/Dotplot.js +135 -0
  41. package/dist/esm/components/dotplot/DotplotControls.js +148 -0
  42. package/dist/esm/components/full-page/FullPage.js +143 -0
  43. package/dist/esm/components/full-page/FullPagePseudospatial.js +151 -0
  44. package/dist/esm/components/heatmap/Heatmap.js +105 -0
  45. package/dist/esm/components/heatmap/HeatmapControls.js +23 -0
  46. package/dist/esm/components/matrixplot/Matrixplot.js +107 -0
  47. package/dist/esm/components/matrixplot/MatrixplotControls.js +38 -0
  48. package/dist/esm/components/obs-list/ObsItem.js +484 -0
  49. package/dist/esm/components/obs-list/ObsList.js +338 -0
  50. package/dist/esm/components/obs-list/ObsToolbar.js +17 -0
  51. package/dist/esm/components/obsm-list/ObsmList.js +75 -0
  52. package/dist/esm/components/offcanvas/index.js +67 -0
  53. package/dist/esm/components/pseudospatial/Pseudospatial.js +228 -0
  54. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +123 -0
  55. package/dist/esm/components/scatterplot/Scatterplot.js +394 -0
  56. package/dist/esm/components/scatterplot/ScatterplotControls.js +71 -0
  57. package/dist/esm/components/scatterplot/SpatialControls.js +140 -0
  58. package/dist/esm/components/scatterplot/Toolbox.js +55 -0
  59. package/dist/esm/components/search-bar/SearchBar.js +90 -0
  60. package/dist/esm/components/search-bar/SearchResults.js +139 -0
  61. package/dist/esm/components/var-list/VarItem.js +254 -0
  62. package/dist/esm/components/var-list/VarList.js +291 -0
  63. package/dist/esm/components/var-list/VarListToolbar.js +87 -0
  64. package/dist/esm/components/var-list/VarSet.js +194 -0
  65. package/dist/esm/components/violin/Violin.js +141 -0
  66. package/dist/esm/components/violin/ViolinControls.js +24 -0
  67. package/dist/esm/constants/colorscales.js +22 -0
  68. package/dist/esm/constants/constants.js +88 -0
  69. package/dist/esm/context/DatasetContext.js +571 -0
  70. package/dist/esm/context/FilterContext.js +48 -0
  71. package/dist/esm/context/ZarrDataContext.js +26 -0
  72. package/dist/esm/helpers/color-helper.js +66 -0
  73. package/dist/esm/helpers/map-helper.js +53 -0
  74. package/dist/esm/helpers/zarr-helper.js +111 -0
  75. package/dist/esm/index.js +22 -0
  76. package/dist/esm/utils/Filter.js +147 -0
  77. package/dist/esm/utils/Histogram.js +44 -0
  78. package/dist/esm/utils/ImageViewer.js +27 -0
  79. package/dist/esm/utils/Legend.js +58 -0
  80. package/dist/esm/utils/LoadingIndicators.js +22 -0
  81. package/dist/esm/utils/Skeleton.js +12 -0
  82. package/dist/esm/utils/VirtualizedList.js +55 -0
  83. package/dist/esm/utils/errors.js +47 -0
  84. package/dist/esm/utils/requests.js +102 -0
  85. package/dist/esm/utils/search.js +39 -0
  86. package/dist/esm/utils/string.js +59 -0
  87. package/dist/esm/utils/zarrData.js +102 -0
  88. package/package.json +19 -7
  89. package/scss/cherita.scss +19 -50
  90. package/scss/components/accordions.scss +32 -0
  91. package/scss/components/layouts.scss +2 -1
  92. package/scss/components/lists.scss +14 -0
  93. package/dist/components/obs-list/ObsToolbar.js +0 -64
  94. package/dist/components/scatterplot/Toolbox.js +0 -31
  95. /package/dist/{components → cjs/components}/dotplot/Dotplot.js +0 -0
  96. /package/dist/{components → cjs/components}/dotplot/DotplotControls.js +0 -0
  97. /package/dist/{components → cjs/components}/heatmap/Heatmap.js +0 -0
  98. /package/dist/{components → cjs/components}/heatmap/HeatmapControls.js +0 -0
  99. /package/dist/{components → cjs/components}/matrixplot/Matrixplot.js +0 -0
  100. /package/dist/{components → cjs/components}/matrixplot/MatrixplotControls.js +0 -0
  101. /package/dist/{components → cjs/components}/scatterplot/ScatterplotControls.js +0 -0
  102. /package/dist/{components → cjs/components}/violin/ViolinControls.js +0 -0
  103. /package/dist/{constants → cjs/constants}/colorscales.js +0 -0
  104. /package/dist/{index.js → cjs/index.js} +0 -0
  105. /package/dist/{utils → cjs/utils}/errors.js +0 -0
  106. /package/dist/{utils → cjs/utils}/search.js +0 -0
@@ -0,0 +1,90 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import SearchIcon from "@mui/icons-material/Search";
3
+ import _ from "lodash";
4
+ import { Dropdown, Form, FormGroup, InputGroup } from "react-bootstrap";
5
+ import { DiseasesSearchResults, VarSearchResults } from "./SearchResults";
6
+ function onVarSelect(dispatch, item) {
7
+ dispatch({
8
+ type: "select.var",
9
+ var: item
10
+ });
11
+ dispatch({
12
+ type: "select.multivar",
13
+ var: item
14
+ });
15
+ dispatch({
16
+ type: "set.colorEncoding",
17
+ value: "var"
18
+ });
19
+ }
20
+ export function SearchBar(_ref) {
21
+ let {
22
+ searchVar = true,
23
+ searchDiseases = false,
24
+ handleSelect = onVarSelect
25
+ } = _ref;
26
+ const [showSuggestions, setShowSuggestions] = useState(false);
27
+ const [text, setText] = useState("");
28
+ const inputRef = useRef(null);
29
+ const displayText = [...(searchVar ? ["features"] : []), ...(searchDiseases ? ["diseases"] : [])].join(" and ");
30
+ useEffect(() => {
31
+ if (text.length > 0) {
32
+ setShowSuggestions(true);
33
+ }
34
+ }, [text]);
35
+
36
+ //@TODO: Abstract styles
37
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Form, {
38
+ onSubmit: e => {
39
+ e.preventDefault();
40
+ }
41
+ }, /*#__PURE__*/React.createElement(FormGroup, null, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(Form.Control, {
42
+ ref: inputRef,
43
+ onFocus: () => {
44
+ setShowSuggestions(text.length > 0);
45
+ },
46
+ onBlur: () => {
47
+ _.delay(() => {
48
+ setShowSuggestions(false);
49
+ }, 150);
50
+ },
51
+ type: "text",
52
+ placeholder: "Search " + displayText,
53
+ value: text,
54
+ onChange: e => {
55
+ setText(e.target.value);
56
+ },
57
+ style: {
58
+ paddingLeft: "2.5rem",
59
+ borderRadius: "5px"
60
+ }
61
+ }), /*#__PURE__*/React.createElement("div", {
62
+ style: {
63
+ position: "absolute",
64
+ left: "10px",
65
+ top: "50%",
66
+ transform: "translateY(-50%)",
67
+ pointerEvents: "none",
68
+ zIndex: 10
69
+ }
70
+ }, /*#__PURE__*/React.createElement(SearchIcon, null))), /*#__PURE__*/React.createElement(Dropdown, {
71
+ show: showSuggestions,
72
+ onMouseDown: e => {
73
+ e.preventDefault();
74
+ },
75
+ onSelect: () => {
76
+ inputRef.current.blur();
77
+ }
78
+ }, /*#__PURE__*/React.createElement(Dropdown.Menu, {
79
+ style: {
80
+ width: "90%"
81
+ }
82
+ }, searchVar && /*#__PURE__*/React.createElement(VarSearchResults, {
83
+ text: text,
84
+ setShowSuggestions: setShowSuggestions,
85
+ handleSelect: handleSelect
86
+ }), searchVar && searchDiseases && /*#__PURE__*/React.createElement(Dropdown.Divider, null), searchDiseases && /*#__PURE__*/React.createElement(DiseasesSearchResults, {
87
+ text: text,
88
+ setShowSuggestions: setShowSuggestions
89
+ }))))));
90
+ }
@@ -0,0 +1,139 @@
1
+ import React, { useState, useEffect, useMemo, useDeferredValue } from "react";
2
+ import _ from "lodash";
3
+ import { Dropdown } from "react-bootstrap";
4
+ import { useDatasetDispatch } from "../../context/DatasetContext";
5
+ import { useDiseaseSearch, useVarSearch } from "../../utils/search";
6
+ export function VarSearchResults(_ref) {
7
+ let {
8
+ text,
9
+ setShowSuggestions,
10
+ handleSelect
11
+ } = _ref;
12
+ const [suggestions, setSuggestions] = useState([]);
13
+ const dispatch = useDatasetDispatch();
14
+ const {
15
+ setParams,
16
+ data: {
17
+ fetchedData = [],
18
+ isPending,
19
+ serverError
20
+ }
21
+ } = useVarSearch();
22
+ const deferredData = useDeferredValue(suggestions);
23
+ const isStale = deferredData !== fetchedData;
24
+ const updateParams = useMemo(() => {
25
+ const setData = text => {
26
+ if (text.length) {
27
+ setParams(p => {
28
+ return {
29
+ ...p,
30
+ text: text
31
+ };
32
+ });
33
+ } else {
34
+ setSuggestions([]);
35
+ setShowSuggestions(false);
36
+ }
37
+ };
38
+ return _.debounce(setData, 300);
39
+ }, [setParams, setShowSuggestions]);
40
+ useEffect(() => {
41
+ updateParams(text);
42
+ }, [text, updateParams]);
43
+ useEffect(() => {
44
+ if (!isPending && !serverError) {
45
+ setSuggestions(fetchedData);
46
+ setShowSuggestions(true);
47
+ }
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", {
65
+ className: "search-results"
66
+ }, deferredData?.length ? suggestionsList : /*#__PURE__*/React.createElement(Dropdown.Item, {
67
+ key: "empty",
68
+ as: "button",
69
+ disabled: true
70
+ }, !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data")));
71
+ }
72
+ export function DiseasesSearchResults(_ref2) {
73
+ let {
74
+ text,
75
+ setShowSuggestions
76
+ } = _ref2;
77
+ const [suggestions, setSuggestions] = useState([]);
78
+ const dispatch = useDatasetDispatch();
79
+ const {
80
+ setParams,
81
+ data: {
82
+ fetchedData = [],
83
+ isPending,
84
+ serverError
85
+ }
86
+ } = useDiseaseSearch();
87
+ const deferredData = useDeferredValue(suggestions);
88
+ const isStale = deferredData !== fetchedData;
89
+ const updateParams = useMemo(() => {
90
+ const setData = text => {
91
+ if (text.length) {
92
+ setParams(p => {
93
+ return {
94
+ ...p,
95
+ text: text
96
+ };
97
+ });
98
+ } else {
99
+ setSuggestions([]);
100
+ }
101
+ };
102
+ return _.debounce(setData, 300);
103
+ }, [setParams]);
104
+ useEffect(() => {
105
+ updateParams(text);
106
+ }, [text, updateParams]);
107
+ useEffect(() => {
108
+ if (!isPending && !serverError) {
109
+ setSuggestions(fetchedData);
110
+ setShowSuggestions(true);
111
+ }
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", {
133
+ className: "search-results"
134
+ }, deferredData?.length ? suggestionsList : /*#__PURE__*/React.createElement(Dropdown.Item, {
135
+ key: "empty",
136
+ as: "button",
137
+ disabled: true
138
+ }, !serverError ? isStale || isPending ? "Loading..." : "No items found" : "Failed to fetch data")));
139
+ }
@@ -0,0 +1,254 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { faDroplet, faTrash } from "@fortawesome/free-solid-svg-icons";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import { MoreVert } from "@mui/icons-material";
5
+ import _ from "lodash";
6
+ import { Button, Collapse, ListGroup, Table } from "react-bootstrap";
7
+ import { COLOR_ENCODINGS, SELECTION_MODES } from "../../constants/constants";
8
+ import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
9
+ import { useFilteredData } from "../../context/FilterContext";
10
+ import { Histogram } from "../../utils/Histogram";
11
+ import { useFetch, useDebouncedFetch } from "../../utils/requests";
12
+ import { VirtualizedList } from "../../utils/VirtualizedList";
13
+ function VarHistogram(_ref) {
14
+ let {
15
+ item
16
+ } = _ref;
17
+ const ENDPOINT = "var/histograms";
18
+ const dataset = useDataset();
19
+ const {
20
+ obsIndices
21
+ } = useFilteredData();
22
+ // @TODO: consider using Filter's isSliced; would trigger more re-renders/requests
23
+ // const { obsIndices, isSliced } = useFilteredData();
24
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
25
+ const [params, setParams] = useState({
26
+ url: dataset.url,
27
+ varKey: item.matrix_index,
28
+ obsIndices: isSliced ? [...(obsIndices || [])] : null
29
+ });
30
+ useEffect(() => {
31
+ setParams(p => {
32
+ return {
33
+ ...p,
34
+ obsIndices: isSliced ? [...(obsIndices || [])] : null
35
+ };
36
+ });
37
+ }, [obsIndices, isSliced]);
38
+ const {
39
+ fetchedData,
40
+ isPending,
41
+ serverError
42
+ } = useDebouncedFetch(ENDPOINT, params, {
43
+ refetchOnMount: false
44
+ });
45
+ return !serverError && /*#__PURE__*/React.createElement(Histogram, {
46
+ data: fetchedData,
47
+ isPending: isPending,
48
+ altColor: isSliced
49
+ });
50
+ }
51
+ function VarDiseaseInfoItem(item) {
52
+ const dispatch = useDatasetDispatch();
53
+ return /*#__PURE__*/React.createElement(ListGroup.Item, {
54
+ key: item.disease_name,
55
+ className: "feature-disease-info"
56
+ }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
57
+ type: "button",
58
+ className: "btn btn-link",
59
+ onClick: () => {
60
+ dispatch({
61
+ type: "select.disease",
62
+ id: item.disease_id,
63
+ name: item.disease_name
64
+ });
65
+ }
66
+ }, item.disease_name), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Table, {
67
+ striped: true
68
+ }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Confidence"), /*#__PURE__*/React.createElement("td", null, item.confidence || "unknown")), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Organ", item.organs.length > 1 ? "s" : ""), /*#__PURE__*/React.createElement("td", null, item.organs.map(o => o.name).join(", "))), !_.isEmpty(item.metadata) && _.map(item.metadata, (value, key) => {
69
+ if (value !== null && value !== undefined) {
70
+ return /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, key), /*#__PURE__*/React.createElement("td", null, value));
71
+ }
72
+ })))));
73
+ }
74
+ function VarDiseaseInfo(_ref2) {
75
+ let {
76
+ data
77
+ } = _ref2;
78
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ListGroup, null, /*#__PURE__*/React.createElement(VirtualizedList, {
79
+ getDataAtIndex: index => data[index],
80
+ count: data.length,
81
+ estimateSize: 140,
82
+ maxHeight: "100%",
83
+ ItemComponent: VarDiseaseInfoItem
84
+ })));
85
+ }
86
+ export function SingleSelectionItem(_ref3) {
87
+ let {
88
+ item,
89
+ isActive,
90
+ selectVar,
91
+ removeVar,
92
+ isDiseaseGene = false,
93
+ showSetColorEncoding = true,
94
+ showRemove = true
95
+ } = _ref3;
96
+ const ENDPOINT = "disease/gene";
97
+ const [openInfo, setOpenInfo] = useState(false);
98
+ const dataset = useDataset();
99
+ const params = {
100
+ geneName: item.name,
101
+ diseaseDatasets: dataset.diseaseDatasets
102
+ };
103
+ const isNotInData = item.matrix_index === -1;
104
+ const {
105
+ fetchedData,
106
+ isPending,
107
+ serverError
108
+ } = useFetch(ENDPOINT, params, {
109
+ refetchOnMount: false,
110
+ enabled: !!dataset.diseaseDatasets.length
111
+ });
112
+ const hasDiseaseInfo = !isPending && !serverError && !!fetchedData?.length;
113
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
114
+ className: `d-flex justify-content-between ${hasDiseaseInfo ? "cursor-pointer" : ""}`,
115
+ onClick: () => {
116
+ setOpenInfo(o => !o);
117
+ }
118
+ }, /*#__PURE__*/React.createElement("div", {
119
+ className: "d-flex justify-content-between align-items-center w-100"
120
+ }, /*#__PURE__*/React.createElement("div", null, item.name), /*#__PURE__*/React.createElement("div", {
121
+ className: "d-flex align-items-center gap-1"
122
+ }, hasDiseaseInfo && /*#__PURE__*/React.createElement(MoreVert, null), !isDiseaseGene && /*#__PURE__*/React.createElement(VarHistogram, {
123
+ item: item
124
+ }), showSetColorEncoding && /*#__PURE__*/React.createElement(Button, {
125
+ type: "button",
126
+ key: item.matrix_index,
127
+ variant: isActive ? "primary" : isNotInData ? "outline-secondary" : "outline-primary",
128
+ className: "m-0 p-0 px-1",
129
+ onClick: e => {
130
+ e.stopPropagation();
131
+ selectVar();
132
+ },
133
+ disabled: isNotInData,
134
+ title: isNotInData ? "Not present in data" : "Set as color encoding"
135
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
136
+ icon: faDroplet
137
+ })), (!isDiseaseGene || !showRemove) && /*#__PURE__*/React.createElement(Button, {
138
+ type: "button",
139
+ className: "m-0 p-0 px-1",
140
+ variant: "outline-secondary",
141
+ title: "Remove from list",
142
+ onClick: e => {
143
+ e.stopPropagation();
144
+ removeVar();
145
+ }
146
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
147
+ icon: faTrash
148
+ }))))), hasDiseaseInfo && /*#__PURE__*/React.createElement(Collapse, {
149
+ in: openInfo
150
+ }, /*#__PURE__*/React.createElement("div", {
151
+ className: "mt-2 var-disease-info-collapse"
152
+ }, /*#__PURE__*/React.createElement(VarDiseaseInfo, {
153
+ data: fetchedData
154
+ }))));
155
+ }
156
+ function MultipleSelectionItem(_ref4) {
157
+ let {
158
+ item,
159
+ isActive,
160
+ toggleVar
161
+ } = _ref4;
162
+ const isNotInData = item.matrix_index === -1;
163
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
164
+ className: "d-flex"
165
+ }, /*#__PURE__*/React.createElement("div", {
166
+ className: "flex-grow-1"
167
+ }, /*#__PURE__*/React.createElement(Button, {
168
+ type: "button",
169
+ key: item.matrix_index,
170
+ variant: isActive ? "primary" : "outline-primary",
171
+ className: "m-0 p-0 px-1",
172
+ onClick: toggleVar,
173
+ disabled: isNotInData,
174
+ title: isNotInData ? "Not present in data" : item.name
175
+ }, item.name))));
176
+ }
177
+ export function VarItem(_ref5) {
178
+ let {
179
+ item,
180
+ active,
181
+ setVarButtons,
182
+ mode = SELECTION_MODES.SINGLE,
183
+ isDiseaseGene = false
184
+ } = _ref5;
185
+ const dataset = useDataset();
186
+ const dispatch = useDatasetDispatch();
187
+ const selectVar = () => {
188
+ if (mode === SELECTION_MODES.SINGLE) {
189
+ dispatch({
190
+ type: "select.var",
191
+ var: item
192
+ });
193
+ dispatch({
194
+ type: "set.colorEncoding",
195
+ value: COLOR_ENCODINGS.VAR
196
+ });
197
+ } else if (mode === SELECTION_MODES.MULTIPLE) {
198
+ dispatch({
199
+ type: "select.multivar",
200
+ var: item
201
+ });
202
+ dispatch({
203
+ type: "set.colorEncoding",
204
+ value: COLOR_ENCODINGS.VAR
205
+ });
206
+ }
207
+ };
208
+ const removeVar = () => {
209
+ setVarButtons(b => {
210
+ return b.filter(i => i.name !== item.name);
211
+ });
212
+ if (mode === SELECTION_MODES.SINGLE) {
213
+ if (active === item.matrix_index) {
214
+ dispatch({
215
+ type: "reset.var"
216
+ });
217
+ }
218
+ } else if (mode === SELECTION_MODES.MULTIPLE) {
219
+ if (active.includes(item.matrix_index)) {
220
+ dispatch({
221
+ type: "deselect.multivar",
222
+ var: item
223
+ });
224
+ }
225
+ }
226
+ };
227
+ const toggleVar = () => {
228
+ if (active.includes(item.matrix_index)) {
229
+ dispatch({
230
+ type: "deselect.multivar",
231
+ var: item
232
+ });
233
+ } else {
234
+ selectVar(item);
235
+ }
236
+ };
237
+ if (item && mode === SELECTION_MODES.SINGLE) {
238
+ return /*#__PURE__*/React.createElement(SingleSelectionItem, {
239
+ item: item,
240
+ isActive: dataset.colorEncoding === COLOR_ENCODINGS.VAR && active === item.matrix_index,
241
+ selectVar: selectVar,
242
+ removeVar: removeVar,
243
+ isDiseaseGene: isDiseaseGene
244
+ });
245
+ } else if (mode === SELECTION_MODES.MULTIPLE) {
246
+ return /*#__PURE__*/React.createElement(MultipleSelectionItem, {
247
+ item: item,
248
+ isActive: item.matrix_index !== -1 && _.includes(active, item.matrix_index),
249
+ toggleVar: toggleVar
250
+ });
251
+ } else {
252
+ return null;
253
+ }
254
+ }