@haniffalab/cherita-react 1.3.0-dev.2025-05-29.ee7e9b72 → 1.3.0-dev.2025-06-04.bee6fd81

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 (32) hide show
  1. package/dist/cjs/components/dotplot/Dotplot.js +35 -5
  2. package/dist/cjs/components/full-page/FullPage.js +108 -50
  3. package/dist/cjs/components/full-page/PlotTypeSelector.js +57 -0
  4. package/dist/cjs/components/heatmap/Heatmap.js +35 -5
  5. package/dist/cjs/components/matrixplot/Matrixplot.js +35 -5
  6. package/dist/cjs/components/obs-list/ObsItem.js +15 -4
  7. package/dist/cjs/components/obs-list/ObsList.js +4 -3
  8. package/dist/cjs/components/scatterplot/SpatialControls.js +3 -3
  9. package/dist/cjs/components/toolbar/Toolbar.js +102 -0
  10. package/dist/cjs/components/violin/Violin.js +37 -6
  11. package/dist/cjs/constants/constants.js +14 -2
  12. package/dist/cjs/index.js +15 -21
  13. package/dist/css/cherita.css +76 -23
  14. package/dist/css/cherita.css.map +1 -1
  15. package/dist/esm/components/dotplot/Dotplot.js +36 -6
  16. package/dist/esm/components/full-page/FullPage.js +110 -50
  17. package/dist/esm/components/full-page/PlotTypeSelector.js +50 -0
  18. package/dist/esm/components/heatmap/Heatmap.js +36 -6
  19. package/dist/esm/components/matrixplot/Matrixplot.js +36 -6
  20. package/dist/esm/components/obs-list/ObsItem.js +15 -4
  21. package/dist/esm/components/obs-list/ObsList.js +4 -3
  22. package/dist/esm/components/scatterplot/SpatialControls.js +3 -3
  23. package/dist/esm/components/toolbar/Toolbar.js +91 -0
  24. package/dist/esm/components/violin/Violin.js +39 -8
  25. package/dist/esm/constants/constants.js +13 -1
  26. package/dist/esm/index.js +4 -4
  27. package/package.json +2 -2
  28. package/scss/cherita.scss +0 -1
  29. package/scss/components/layouts.scss +69 -1
  30. package/scss/components/plotly.scss +19 -14
  31. package/dist/cjs/components/full-page/FullPagePseudospatial.js +0 -157
  32. package/dist/esm/components/full-page/FullPagePseudospatial.js +0 -149
@@ -5,15 +5,25 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
5
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
6
  import React, { useCallback, useEffect, useRef, useState } from "react";
7
7
  import _ from "lodash";
8
- import { Alert } from "react-bootstrap";
8
+ import { Alert, Button } from "react-bootstrap";
9
9
  import Plot from "react-plotly.js";
10
+ import { PLOTLY_MODEBAR_BUTTONS } from "../../constants/constants";
10
11
  import { useDataset } from "../../context/DatasetContext";
11
12
  import { useFilteredData } from "../../context/FilterContext";
12
13
  import { useSettings } from "../../context/SettingsContext";
13
14
  import { LoadingSpinner } from "../../utils/LoadingIndicators";
14
15
  import { useDebouncedFetch } from "../../utils/requests";
15
- export function Heatmap() {
16
+ import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
17
+ export function Heatmap(_ref) {
16
18
  var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
19
+ let {
20
+ showObsBtn = false,
21
+ showVarsBtn = false,
22
+ showCtrlsBtn = false,
23
+ setShowObs,
24
+ setShowVars,
25
+ setShowControls
26
+ } = _ref;
17
27
  const ENDPOINT = "heatmap";
18
28
  const dataset = useDataset();
19
29
  const settings = useSettings();
@@ -90,17 +100,29 @@ export function Heatmap() {
90
100
  colorscale.current = settings.controls.colorScale;
91
101
  updateColorscale(colorscale.current);
92
102
  }, [settings.controls.colorScale, updateColorscale]);
103
+ const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
104
+ onClick: setShowObs
105
+ }), showVarsBtn && VarPlotlyToolbar({
106
+ onClick: setShowVars
107
+ }), showCtrlsBtn && ControlsPlotlyToolbar({
108
+ onClick: setShowControls
109
+ })]);
110
+ const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
93
111
  if (!serverError) {
94
112
  if (hasSelections) {
95
113
  return /*#__PURE__*/React.createElement("div", {
96
- className: "cherita-heatmap position-relative"
114
+ className: "cherita-plot cherita-heatmap position-relative"
97
115
  }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
98
116
  data: data,
99
117
  layout: layout,
100
118
  useResizeHandler: true,
101
119
  style: {
102
- maxWidth: "100%",
103
- maxHeight: "100%"
120
+ width: "100%",
121
+ height: "100%"
122
+ },
123
+ config: {
124
+ displaylogo: false,
125
+ modeBarButtons: modeBarButtons
104
126
  }
105
127
  }));
106
128
  }
@@ -108,7 +130,15 @@ export function Heatmap() {
108
130
  className: "cherita-heatmap"
109
131
  }, /*#__PURE__*/React.createElement(Alert, {
110
132
  variant: "light"
111
- }, "Select features and a category"));
133
+ }, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
134
+ variant: "link",
135
+ className: "border-0 p-0 align-baseline",
136
+ onClick: setShowVars
137
+ }, "features") : "features", " ", "and a", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
138
+ variant: "link",
139
+ className: "border-0 p-0 align-baseline",
140
+ onClick: setShowObs
141
+ }, "category") : "category"));
112
142
  } else {
113
143
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
114
144
  variant: "danger"
@@ -5,15 +5,25 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
5
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
6
  import React, { useCallback, useEffect, useRef, useState } from "react";
7
7
  import _ from "lodash";
8
- import { Alert } from "react-bootstrap";
8
+ import { Alert, Button } from "react-bootstrap";
9
9
  import Plot from "react-plotly.js";
10
+ import { PLOTLY_MODEBAR_BUTTONS } from "../../constants/constants";
10
11
  import { useDataset } from "../../context/DatasetContext";
11
12
  import { useFilteredData } from "../../context/FilterContext";
12
13
  import { useSettings } from "../../context/SettingsContext";
13
14
  import { LoadingSpinner } from "../../utils/LoadingIndicators";
14
15
  import { useDebouncedFetch } from "../../utils/requests";
15
- export function Matrixplot() {
16
+ import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
17
+ export function Matrixplot(_ref) {
16
18
  var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
19
+ let {
20
+ showObsBtn = false,
21
+ showVarsBtn = false,
22
+ showCtrlsBtn = false,
23
+ setShowObs,
24
+ setShowVars,
25
+ setShowControls
26
+ } = _ref;
17
27
  const ENDPOINT = "matrixplot";
18
28
  const dataset = useDataset();
19
29
  const settings = useSettings();
@@ -92,17 +102,29 @@ export function Matrixplot() {
92
102
  colorscale.current = settings.controls.colorScale;
93
103
  updateColorscale(colorscale.current);
94
104
  }, [settings.controls.colorScale, updateColorscale]);
105
+ const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
106
+ onClick: setShowObs
107
+ }), showVarsBtn && VarPlotlyToolbar({
108
+ onClick: setShowVars
109
+ }), showCtrlsBtn && ControlsPlotlyToolbar({
110
+ onClick: setShowControls
111
+ })]);
112
+ const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
95
113
  if (!serverError) {
96
114
  if (hasSelections) {
97
115
  return /*#__PURE__*/React.createElement("div", {
98
- className: "cherita-matrixplot position-relative"
116
+ className: "cherita-plot cherita-matrixplot position-relative"
99
117
  }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
100
118
  data: data,
101
119
  layout: layout,
102
120
  useResizeHandler: true,
103
121
  style: {
104
- maxWidth: "100%",
105
- maxHeight: "100%"
122
+ width: "100%",
123
+ height: "100%"
124
+ },
125
+ config: {
126
+ displaylogo: false,
127
+ modeBarButtons: modeBarButtons
106
128
  }
107
129
  }));
108
130
  }
@@ -110,7 +132,15 @@ export function Matrixplot() {
110
132
  className: "cherita-matrixplot"
111
133
  }, /*#__PURE__*/React.createElement(Alert, {
112
134
  variant: "light"
113
- }, "Select features and a category"));
135
+ }, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
136
+ variant: "link",
137
+ className: "border-0 p-0 align-baseline",
138
+ onClick: setShowVars
139
+ }, "features") : "features", " ", "and a", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
140
+ variant: "link",
141
+ className: "border-0 p-0 align-baseline",
142
+ onClick: setShowObs
143
+ }, "category") : "category"));
114
144
  } else {
115
145
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
116
146
  variant: "danger"
@@ -370,21 +370,23 @@ function ObsContinuousStats(_ref3) {
370
370
  }
371
371
 
372
372
  // @TODO: add bin controls
373
- // @TODO: add histogram
374
373
  export function ContinuousObs(_ref4) {
375
374
  let {
376
375
  obs,
377
376
  toggleAll,
378
377
  toggleObs
379
378
  } = _ref4;
379
+ const settings = useSettings();
380
380
  const {
381
381
  isSliced
382
382
  } = useFilteredData();
383
383
  const totalCounts = _.sum(_.values(obs.value_counts));
384
384
  const min = _.min(_.values(obs.codes));
385
385
  const max = _.max(_.values(obs.codes));
386
+ const obsHistograms = useObsHistogram(obs);
386
387
  const filteredObsData = useFilteredObsData(obs);
387
- const getDataAtIndex = index => {
388
+ const getDataAtIndex = useCallback(index => {
389
+ var _obsHistograms$fetche2;
388
390
  return {
389
391
  value: obs.values[index],
390
392
  code: obs.codes[obs.values[index]],
@@ -394,13 +396,21 @@ export function ContinuousObs(_ref4) {
394
396
  },
395
397
  isOmitted: _.includes(obs.omit, obs.codes[obs.values[index]]),
396
398
  label: isNaN(obs.values[index]) ? "NaN" : getContinuousLabel(obs.codes[obs.values[index]], obs.bins.binEdges),
399
+ histogramData: settings.colorEncoding === COLOR_ENCODINGS.VAR ? {
400
+ data: (_obsHistograms$fetche2 = obsHistograms.fetchedData) === null || _obsHistograms$fetche2 === void 0 ? void 0 : _obsHistograms$fetche2[obs.values[index]],
401
+ isPending: obsHistograms.isPending,
402
+ altColor: isSliced
403
+ } : {
404
+ data: null,
405
+ isPending: false
406
+ },
397
407
  filteredStats: {
398
408
  value_counts: (filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.value_counts[obs.values[index]]) || 0,
399
409
  pct: (filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.pct[obs.values[index]]) || 0
400
410
  },
401
411
  isSliced: isSliced
402
412
  };
403
- };
413
+ }, [filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.pct, filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.value_counts, isSliced, obs.bins.binEdges, obs.codes, obs.omit, obs.value_counts, obs.values, obsHistograms.fetchedData, obsHistograms.isPending, settings.colorEncoding, totalCounts]);
404
414
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ListGroup, {
405
415
  variant: "flush",
406
416
  className: "cherita-list"
@@ -417,7 +427,8 @@ export function ContinuousObs(_ref4) {
417
427
  min: min,
418
428
  max: max,
419
429
  onChange: toggleObs,
420
- showColor: false
430
+ showColor: false,
431
+ estimateSize: 42
421
432
  })), /*#__PURE__*/React.createElement(ObsContinuousStats, {
422
433
  obs: obs
423
434
  }));
@@ -48,7 +48,8 @@ export function ObsColsList(_ref2) {
48
48
  var _settings$selectedObs;
49
49
  let {
50
50
  showColor = true,
51
- enableObsGroups = true
51
+ enableObsGroups = true,
52
+ showSelectedAsActive = false
52
53
  } = _ref2;
53
54
  const ENDPOINT = "obs/cols";
54
55
  const dataset = useDataset();
@@ -215,7 +216,7 @@ export function ObsColsList(_ref2) {
215
216
  }
216
217
  const inLabelObs = _.some(settings.labelObs, i => i.name === item.name);
217
218
  const inSliceObs = settings.sliceBy.obs && ((_settings$selectedObs5 = settings.selectedObs) === null || _settings$selectedObs5 === void 0 ? void 0 : _settings$selectedObs5.name) === item.name;
218
- const isColorEncoding = settings.colorEncoding === COLOR_ENCODINGS.OBS && ((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.name) === item.name;
219
+ const isColorEncoding = (showSelectedAsActive || settings.colorEncoding === COLOR_ENCODINGS.OBS) && ((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.name) === item.name;
219
220
  return /*#__PURE__*/React.createElement("div", {
220
221
  className: "accordion-item",
221
222
  key: item.name
@@ -242,7 +243,7 @@ export function ObsColsList(_ref2) {
242
243
  event.stopPropagation();
243
244
  toggleColor(item);
244
245
  },
245
- title: "Is color encoding"
246
+ title: showSelectedAsActive ? "Is selected" : "Is color encoding"
246
247
  }, /*#__PURE__*/React.createElement(WaterDropIcon, null)))), /*#__PURE__*/React.createElement(Accordion.Collapse, {
247
248
  eventKey: item.name
248
249
  }, /*#__PURE__*/React.createElement("div", {
@@ -8,9 +8,9 @@ import { OverlayTrigger, Tooltip } from "react-bootstrap";
8
8
  import Button from "react-bootstrap/Button";
9
9
  import ButtonGroup from "react-bootstrap/ButtonGroup";
10
10
  import Dropdown from "react-bootstrap/Dropdown";
11
- import { useDataset } from "../../context/DatasetContext";
12
11
  import { OffcanvasControls } from "../offcanvas";
13
12
  import { ScatterplotControls } from "./ScatterplotControls";
13
+ import { BREAKPOINTS } from "../../constants/constants";
14
14
  import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
15
15
  export function SpatialControls(_ref) {
16
16
  var _features$features;
@@ -32,8 +32,8 @@ export function SpatialControls(_ref) {
32
32
  const [showControls, setShowControls] = useState(false);
33
33
  const handleCloseControls = () => setShowControls(false);
34
34
  const handleShowControls = () => setShowControls(true);
35
- const LgBreakpoint = useMediaQuery("(max-width: 991.98px)");
36
- const XlBreakpoint = useMediaQuery("(max-width: 1199.98px)");
35
+ const LgBreakpoint = useMediaQuery(BREAKPOINTS.LG);
36
+ const XlBreakpoint = useMediaQuery(BREAKPOINTS.XL);
37
37
  const showObsBtn = isFullscreen ? LgBreakpoint : true;
38
38
  const showVarsBtn = isFullscreen ? XlBreakpoint : true;
39
39
  const onSelect = (eventKey, event) => {
@@ -0,0 +1,91 @@
1
+ import React from "react";
2
+ import { faList, faSearch, faSliders } from "@fortawesome/free-solid-svg-icons";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import { Container, Nav, Navbar } from "react-bootstrap";
5
+ export const Toolbar = _ref => {
6
+ let {
7
+ showObsBtn = true,
8
+ showVarsBtn = true,
9
+ showCtrlsBtn = true,
10
+ setShowObs,
11
+ setShowVars,
12
+ setShowControls
13
+ } = _ref;
14
+ return /*#__PURE__*/React.createElement(Navbar, {
15
+ expand: "md",
16
+ bg: "primary",
17
+ variant: "dark",
18
+ className: "cherita-navbar"
19
+ }, /*#__PURE__*/React.createElement(Container, {
20
+ fluid: true
21
+ }, /*#__PURE__*/React.createElement(Navbar.Toggle, {
22
+ "aria-controls": "navbarScroll"
23
+ }), /*#__PURE__*/React.createElement(Navbar.Collapse, {
24
+ id: "navbarScroll"
25
+ }, /*#__PURE__*/React.createElement(Nav, {
26
+ navbarScroll: true
27
+ }, showObsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
28
+ className: "me-2"
29
+ }, /*#__PURE__*/React.createElement(Nav.Link, {
30
+ onClick: () => setShowObs(true)
31
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
32
+ icon: faList,
33
+ className: "me-2"
34
+ }), "Explore Categories")), showVarsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
35
+ className: "me-2"
36
+ }, /*#__PURE__*/React.createElement(Nav.Link, {
37
+ onClick: () => setShowVars(true)
38
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
39
+ icon: faSearch,
40
+ className: "me-2"
41
+ }), "Search Genes")), showCtrlsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
42
+ className: "me-2"
43
+ }, /*#__PURE__*/React.createElement(Nav.Link, {
44
+ onClick: () => setShowControls(true)
45
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
46
+ icon: faSliders,
47
+ className: "me-2"
48
+ }), "Controls"))))));
49
+ };
50
+ export const ObsPlotlyToolbar = _ref2 => {
51
+ let {
52
+ onClick
53
+ } = _ref2;
54
+ return {
55
+ name: "Categories",
56
+ icon: {
57
+ width: 512,
58
+ height: 512,
59
+ path: faList.icon[4]
60
+ },
61
+ click: onClick
62
+ };
63
+ };
64
+ export const VarPlotlyToolbar = _ref3 => {
65
+ let {
66
+ onClick
67
+ } = _ref3;
68
+ return {
69
+ name: "Features",
70
+ icon: {
71
+ width: 512,
72
+ height: 512,
73
+ path: faSearch.icon[4]
74
+ },
75
+ click: onClick
76
+ };
77
+ };
78
+ export const ControlsPlotlyToolbar = _ref4 => {
79
+ let {
80
+ onClick
81
+ } = _ref4;
82
+ return {
83
+ name: "Controls",
84
+ icon: {
85
+ width: 512,
86
+ height: 512,
87
+ path: faSliders.icon[4]
88
+ },
89
+ click: onClick
90
+ };
91
+ };
@@ -7,18 +7,25 @@ import React, { useEffect, useState } from "react";
7
7
  import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
8
8
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
9
9
  import _ from "lodash";
10
- import { Alert, OverlayTrigger, Tooltip } from "react-bootstrap";
10
+ import { Alert, Button, OverlayTrigger, Tooltip } from "react-bootstrap";
11
11
  import Plot from "react-plotly.js";
12
- import { VIOLIN_MODES } from "../../constants/constants";
12
+ import { PLOTLY_MODEBAR_BUTTONS, VIOLIN_MODES } from "../../constants/constants";
13
13
  import { useDataset } from "../../context/DatasetContext";
14
14
  import { useFilteredData } from "../../context/FilterContext";
15
15
  import { useSettings } from "../../context/SettingsContext";
16
16
  import { LoadingSpinner } from "../../utils/LoadingIndicators";
17
17
  import { useDebouncedFetch } from "../../utils/requests";
18
+ import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
18
19
  export function Violin(_ref) {
19
20
  var _settings$selectedVar, _settings$selectedVar2, _settings$selectedVar3, _settings$selectedVar4, _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
20
21
  let {
21
- mode = VIOLIN_MODES.MULTIKEY
22
+ mode = VIOLIN_MODES.MULTIKEY,
23
+ showObsBtn = false,
24
+ showVarsBtn = false,
25
+ showCtrlsBtn = false,
26
+ setShowObs,
27
+ setShowVars,
28
+ setShowControls
22
29
  } = _ref;
23
30
  const ENDPOINT = "violin";
24
31
  const dataset = useDataset();
@@ -117,17 +124,29 @@ export function Violin(_ref) {
117
124
  setLayout(fetchedData.layout);
118
125
  }
119
126
  }, [fetchedData, hasSelections, isPending, serverError]);
127
+ const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
128
+ onClick: setShowObs
129
+ }), showVarsBtn && VarPlotlyToolbar({
130
+ onClick: setShowVars
131
+ }), showCtrlsBtn && ControlsPlotlyToolbar({
132
+ onClick: setShowControls
133
+ })]);
134
+ const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
120
135
  if (!serverError) {
121
136
  if (hasSelections) {
122
137
  return /*#__PURE__*/React.createElement("div", {
123
- className: "cherita-violin position-relative"
138
+ className: "cherita-plot cherita-violin position-relative"
124
139
  }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
125
140
  data: data,
126
141
  layout: layout,
127
142
  useResizeHandler: true,
128
143
  style: {
129
- maxWidth: "100%",
130
- maxHeight: "100%"
144
+ width: "100%",
145
+ height: "100%"
146
+ },
147
+ config: {
148
+ displaylogo: false,
149
+ modeBarButtons: modeBarButtons
131
150
  }
132
151
  }), (fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.resampled) && /*#__PURE__*/React.createElement(Alert, {
133
152
  variant: "warning"
@@ -142,9 +161,21 @@ export function Violin(_ref) {
142
161
  className: "cherita-violin"
143
162
  }, mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/React.createElement(Alert, {
144
163
  variant: "light"
145
- }, "Select features"), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/React.createElement(Alert, {
164
+ }, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
165
+ variant: "link",
166
+ className: "border-0 p-0 align-baseline",
167
+ onClick: setShowVars
168
+ }, "features") : "features"), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/React.createElement(Alert, {
146
169
  variant: "light"
147
- }, "Select categories and a feature"));
170
+ }, "Select", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
171
+ variant: "link",
172
+ className: "border-0 p-0 align-baseline",
173
+ onClick: setShowObs
174
+ }, "categories") : "categories", " ", "and a", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
175
+ variant: "link",
176
+ className: "border-0 p-0 align-baseline",
177
+ onClick: setShowVars
178
+ }, "feature") : "feature"));
148
179
  } else {
149
180
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
150
181
  variant: "danger"
@@ -1,4 +1,11 @@
1
1
  export const LOCAL_STORAGE_KEY = "CHERITA";
2
+ export const PLOT_TYPES = {
3
+ SCATTERPLOT: "scatterplot",
4
+ DOTPLOT: "dotplot",
5
+ HEATMAP: "heatmap",
6
+ MATRIXPLOT: "matrixplot",
7
+ VIOLINPLOT: "violinplot"
8
+ };
2
9
  export const COLOR_ENCODINGS = {
3
10
  VAR: "var",
4
11
  OBS: "obs"
@@ -85,4 +92,9 @@ export const PSEUDOSPATIAL_CATEGORICAL_MODES = {
85
92
 
86
93
  // `default` cols to be shown out of accordion, at top of obslist
87
94
  // default values from cellxgene schema
88
- export const DEFAULT_OBS_GROUP = ["assay", "cell_type", "development_stage", "disease", "donor_id", "organism", "self_reported_ethnicity", "sex", "suspension_type", "tissue", "tissue_type"];
95
+ export const DEFAULT_OBS_GROUP = ["assay", "cell_type", "development_stage", "disease", "donor_id", "organism", "self_reported_ethnicity", "sex", "suspension_type", "tissue", "tissue_type"];
96
+ export const PLOTLY_MODEBAR_BUTTONS = ["toImage", "zoom2d", "pan2d", "zoomIn2d", "zoomOut2d", "autoScale2d", "resetScale2d"];
97
+ export const BREAKPOINTS = {
98
+ LG: "(max-width: 991.98px)",
99
+ XL: "(max-width: 1199.98px)"
100
+ };
package/dist/esm/index.js CHANGED
@@ -1,22 +1,22 @@
1
1
  export { Dotplot } from "./components/dotplot/Dotplot";
2
2
  export { DotplotControls } from "./components/dotplot/DotplotControls";
3
+ export { FullPage } from "./components/full-page/FullPage";
3
4
  export { Heatmap } from "./components/heatmap/Heatmap";
4
5
  export { HeatmapControls } from "./components/heatmap/HeatmapControls";
5
6
  export { Matrixplot } from "./components/matrixplot/Matrixplot";
6
7
  export { MatrixplotControls } from "./components/matrixplot/MatrixplotControls";
7
8
  export { ObsColsList } from "./components/obs-list/ObsList";
8
9
  export { ObsmKeysList } from "./components/obsm-list/ObsmList";
10
+ export { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "./components/offcanvas";
9
11
  export { Pseudospatial } from "./components/pseudospatial/Pseudospatial";
10
12
  export { Scatterplot } from "./components/scatterplot/Scatterplot";
11
13
  export { ScatterplotControls } from "./components/scatterplot/ScatterplotControls";
12
14
  export { SearchBar } from "./components/search-bar/SearchBar";
15
+ export { Toolbar } from "./components/toolbar/Toolbar";
13
16
  export { VarNamesList } from "./components/var-list/VarList";
14
17
  export { Violin } from "./components/violin/Violin";
15
18
  export { ViolinControls } from "./components/violin/ViolinControls";
16
- export { FullPage, FullPagePlots, FullPageScatterplot } from "./components/full-page/FullPage";
17
- export { FullPagePseudospatial } from "./components/full-page/FullPagePseudospatial";
18
- export { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "./components/offcanvas";
19
19
  export { COLORSCALES } from "./constants/colorscales";
20
- export { SELECTION_MODES, VIOLIN_MODES } from "./constants/constants";
20
+ export { PLOT_TYPES, SELECTION_MODES, VIOLIN_MODES } from "./constants/constants";
21
21
  export { DatasetProvider } from "./context/DatasetContext";
22
22
  export { FilterProvider } from "./context/FilterContext";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haniffalab/cherita-react",
3
- "version": "1.3.0-dev.2025-05-29.ee7e9b72",
3
+ "version": "1.3.0-dev.2025-06-04.bee6fd81",
4
4
  "author": "Haniffa Lab",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -126,5 +126,5 @@
126
126
  "url": "https://github.com/haniffalab/cherita-react/issues"
127
127
  },
128
128
  "homepage": "https://github.com/haniffalab/cherita-react#readme",
129
- "prereleaseSha": "ee7e9b72ff17d43a4febc5169837417e48926f4a"
129
+ "prereleaseSha": "bee6fd816597b2a731ce2565b16db2d9fa63bb06"
130
130
  }
package/scss/cherita.scss CHANGED
@@ -58,7 +58,6 @@ $prefix: "bs-" !default;
58
58
  /* End scrollbar styling */
59
59
 
60
60
  .cherita-container-plot {
61
- margin-top: 76px;
62
61
  padding: 20px;
63
62
  position: relative;
64
63
  min-height: 400px;
@@ -1,5 +1,6 @@
1
1
  .cherita-app {
2
2
  position: relative;
3
+ width: 100%;
3
4
  }
4
5
 
5
6
  .cherita-app {
@@ -50,6 +51,21 @@
50
51
  overflow-y: hidden;
51
52
  }
52
53
 
54
+ .sidebar-plotselector {
55
+ padding: 6px;
56
+ border-bottom: 1px solid #dee2e6;
57
+
58
+ .plotselector-icon {
59
+ padding-bottom: 2px;
60
+ cursor: pointer;
61
+
62
+ .active {
63
+ opacity: 1;
64
+ border-bottom: 2px solid #007bff;
65
+ }
66
+ }
67
+ }
68
+
53
69
  .sidebar-pseudospatial {
54
70
  padding: 10px;
55
71
  border-bottom: 1px solid #dee2e6;
@@ -108,6 +124,58 @@
108
124
  border-left: 1px solid #dee2e6;
109
125
  }
110
126
 
127
+ .cherita-app-canvas {
128
+ .cherita-plot {
129
+ height: 100%;
130
+ min-height: 400px;
131
+ }
132
+ }
133
+
134
+ .cherita-app-container {
135
+ @extend .p-0;
136
+ display: flex;
137
+ flex-wrap: nowrap;
138
+ width: 100%;
139
+ height: 100%;
140
+
141
+ .cherita-app-obs {
142
+ flex: 0 0 auto;
143
+ min-width: 350px;
144
+ max-width: 20%;
145
+ overflow-y: auto;
146
+ }
147
+
148
+ .cherita-app-canvas {
149
+ @extend .p-1;
150
+ flex: 1 1 auto;
151
+ min-width: 400px;
152
+ position: relative;
153
+ max-height: 100%;
154
+ display: flex;
155
+ flex-direction: column;
156
+
157
+ .cherita-navbar {
158
+ @extend .m-0;
159
+ @extend .d-block;
160
+ position: relative;
161
+ }
162
+ }
163
+
164
+ .cherita-app-sidebar {
165
+ flex: 0 0 auto;
166
+ min-width: 350px;
167
+ max-width: 20%;
168
+ position: relative;
169
+ }
170
+
171
+ @media (max-width: 1400px) {
172
+ .cherita-app-obs,
173
+ .cherita-app-sidebar {
174
+ max-width: 25%;
175
+ }
176
+ }
177
+ }
178
+
111
179
  .ps-xs-1 {
112
180
  padding-left: 0.15rem !important;
113
- }
181
+ }
@@ -1,30 +1,35 @@
1
1
  .js-plotly-plot .plotly .modebar {
2
- border-radius: 5px;
3
- background-color: rgba(0, 0, 0, 0.6);
4
- padding: 0 4px !important;
5
2
 
6
3
  .modebar-group {
7
- margin: 0 !important;
8
- padding: 0 !important;
9
- background-color: transparent !important;
4
+ @extend .bg-primary;
5
+ @extend .mx-1;
6
+ border-radius: 5px;
7
+ padding: 4px !important;
10
8
 
11
9
  .modebar-btn {
12
- fill: white !important; /* Ensures white icons */
13
- color: white !important; /* Ensures text/icons are visible */
10
+ display: inline-flex;
11
+ justify-content: center;
14
12
  position: relative;
15
- font-size: 16px;
16
- padding: 4px;
13
+ font-size: 1.25rem;
14
+ padding: 0.25rem;
17
15
  height: auto;
18
16
  cursor: pointer;
19
17
  line-height: normal;
20
18
 
21
19
  svg {
22
20
  position: relative;
23
- top: auto;
24
- bottom: auto;
25
- left: auto;
26
- right: auto;
21
+ top: 1px;
22
+
23
+ path {
24
+ fill: white !important;
25
+ color: white !important;
26
+ }
27
27
  }
28
28
  }
29
29
  }
30
30
  }
31
+
32
+ .js-plotly-plot .plotly .modebar--hover > :not(.watermark) {
33
+ opacity: 0.5;
34
+ transition: opacity 0.3s;
35
+ }