@haniffalab/cherita-react 1.4.4 → 1.4.6-dev.2026-01-12.f157a881

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.
@@ -14,11 +14,6 @@ var _requests = require("../../utils/requests");
14
14
  var _Skeleton = require("../../utils/Skeleton");
15
15
  var _jsxRuntime = require("react/jsx-runtime");
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
- 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; }
18
- 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; }
19
- 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; }
20
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
21
- 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); }
22
17
  function ObsmKeysList(_ref) {
23
18
  let {
24
19
  setHasObsm
@@ -27,18 +22,11 @@ function ObsmKeysList(_ref) {
27
22
  const dataset = (0, _DatasetContext.useDataset)();
28
23
  const settings = (0, _SettingsContext.useSettings)();
29
24
  const dispatch = (0, _SettingsContext.useSettingsDispatch)();
30
- const [obsmKeysList, setObsmKeysList] = (0, _react.useState)([]);
25
+ const [keysList, setKeysList] = (0, _react.useState)([]);
31
26
  const [active, setActive] = (0, _react.useState)(null);
32
- const [params, setParams] = (0, _react.useState)({
27
+ const params = (0, _react.useMemo)(() => ({
33
28
  url: dataset.url
34
- });
35
- (0, _react.useEffect)(() => {
36
- setParams(p => {
37
- return _objectSpread(_objectSpread({}, p), {}, {
38
- url: dataset.url
39
- });
40
- });
41
- }, [dataset.url]);
29
+ }), [dataset.url]);
42
30
  const {
43
31
  fetchedData,
44
32
  isPending,
@@ -48,17 +36,34 @@ function ObsmKeysList(_ref) {
48
36
  });
49
37
  (0, _react.useEffect)(() => {
50
38
  if (!isPending && !serverError) {
51
- if (!fetchedData || !fetchedData.length) {
39
+ const obsmKeysArray = Array.isArray(fetchedData) ? fetchedData : [];
40
+ if (obsmKeysArray.length === 0) {
52
41
  setHasObsm(false);
42
+ setKeysList([]);
43
+ if (settings.selectedObsm) {
44
+ dispatch({
45
+ type: 'select.obsm',
46
+ obsm: null
47
+ });
48
+ }
53
49
  } else {
54
50
  setHasObsm(true);
55
- setObsmKeysList(fetchedData);
56
-
57
- // Set default obsm if in keys list and not selected
58
- if (!settings.selectedObsm) {
51
+ setKeysList(obsmKeysArray);
52
+ if (settings.selectedObsm) {
53
+ // If selected obsm is not in keys list, reset to null
54
+ if (!_lodash.default.includes(obsmKeysArray, settings.selectedObsm)) {
55
+ dispatch({
56
+ type: 'select.obsm',
57
+ obsm: null
58
+ });
59
+ } else {
60
+ setActive(settings.selectedObsm);
61
+ }
62
+ } else {
63
+ // Set default obsm if in keys list and not selected
59
64
  // Follow DEFAULT_OBSM_KEYS order
60
65
  _lodash.default.each(_constants.DEFAULT_OBSM_KEYS, k => {
61
- const defaultObsm = _lodash.default.find(fetchedData, item => item.toLowerCase() === k);
66
+ const defaultObsm = _lodash.default.find(obsmKeysArray, item => item.toLowerCase() === k);
62
67
  if (defaultObsm) {
63
68
  dispatch({
64
69
  type: 'select.obsm',
@@ -69,20 +74,16 @@ function ObsmKeysList(_ref) {
69
74
  });
70
75
  }
71
76
  }
77
+ } else if (!isPending && serverError) {
72
78
  if (settings.selectedObsm) {
73
- // If selected obsm is not in keys list, reset to null
74
- if (!_lodash.default.includes(fetchedData || [], settings.selectedObsm)) {
75
- dispatch({
76
- type: 'select.obsm',
77
- obsm: null
78
- });
79
- } else {
80
- setActive(settings.selectedObsm);
81
- }
79
+ dispatch({
80
+ type: 'select.obsm',
81
+ obsm: null
82
+ });
82
83
  }
83
84
  }
84
85
  }, [dispatch, fetchedData, isPending, serverError, setHasObsm, settings.selectedObsm]);
85
- const obsmList = obsmKeysList.map(item => {
86
+ const obsmList = keysList.map(item => {
86
87
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Dropdown.Item, {
87
88
  className: "custom ".concat(active === item && 'active'),
88
89
  onClick: () => {
@@ -165,13 +165,11 @@ function SelectionItem(_ref3) {
165
165
  selectVar();
166
166
  },
167
167
  disabled: isNotInData,
168
- title: isNotInData ? 'Not present in data' : 'Set as color encoding',
169
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
168
+ title: isNotInData ? 'Not present in data' : isMultiple ? isActive ? 'Remove from plot' : 'Add to plot' : 'Set as color encoding',
169
+ children: [!isMultiple && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
170
170
  icon: _freeSolidSvgIcons.faDroplet
171
171
  }), isMultiple && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
172
- icon: _freeSolidSvgIcons.faPlus,
173
- size: "xs",
174
- className: "ps-xs-1"
172
+ icon: _freeSolidSvgIcons.faCheck
175
173
  })]
176
174
  }, item.matrix_index), showRemove && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Button, {
177
175
  type: "button",
@@ -9,10 +9,10 @@ var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
9
9
  var _reactFontawesome = require("@fortawesome/react-fontawesome");
10
10
  var _lodash = _interopRequireDefault(require("lodash"));
11
11
  var _reactBootstrap = require("react-bootstrap");
12
- var _VarItem = require("./VarItem");
13
12
  var _constants = require("../../constants/constants");
14
13
  var _SettingsContext = require("../../context/SettingsContext");
15
14
  var _SearchBar = require("../search-bar/SearchBar");
15
+ var _VarItem = require("./VarItem");
16
16
  var _jsxRuntime = require("react/jsx-runtime");
17
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
18
  // @TODO: add button to score genes and plot
@@ -101,13 +101,11 @@ function SelectionSet(_ref) {
101
101
  selectSet();
102
102
  },
103
103
  disabled: !set.vars.length,
104
- title: "Set as color encoding",
105
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
104
+ title: !set.vars.length ? 'No variables in set' : isMultiple ? isActive ? 'Remove from plot' : 'Add to plot' : 'Set as color encoding',
105
+ children: [!isMultiple && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
106
106
  icon: _freeSolidSvgIcons.faDroplet
107
107
  }), isMultiple && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
108
- icon: _freeSolidSvgIcons.faPlus,
109
- size: "xs",
110
- className: "ps-xs-1"
108
+ icon: _freeSolidSvgIcons.faCheck
111
109
  })]
112
110
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Button, {
113
111
  type: "button",
@@ -60,7 +60,7 @@ const persistOptions = {
60
60
  return false;
61
61
  }
62
62
  },
63
- buster: "1.4.4" || '0.0.0'
63
+ buster: "1.4.6-dev.2026-01-12.f157a881" || '0.0.0'
64
64
  // @TODO: add maxAge and api version numbers as buster
65
65
  };
66
66
  const initialDataset = {
@@ -173,7 +173,7 @@ function SettingsProvider(_ref2) {
173
173
 
174
174
  // If the buster is not set or does not match the current package version,
175
175
  // reset localSettings to avoid stale data
176
- if (!buster || buster !== "1.4.4") {
176
+ if (!buster || buster !== "1.4.6-dev.2026-01-12.f157a881") {
177
177
  localSettings = {};
178
178
  }
179
179
  const initSettings = (0, _react.useRef)(initializer({
@@ -198,7 +198,7 @@ function SettingsProvider(_ref2) {
198
198
  if (canOverrideSettings && settings) {
199
199
  try {
200
200
  localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
201
- buster: "1.4.4" || '0.0.0',
201
+ buster: "1.4.6-dev.2026-01-12.f157a881" || '0.0.0',
202
202
  timestamp: Date.now()
203
203
  }, _lodash.default.omit(settings, 'data'))));
204
204
  } catch (err) {
@@ -3,69 +3,60 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.useZarr = exports.useMultipleZarr = exports.ZarrHelper = exports.GET_OPTIONS = void 0;
6
+ exports.useZarr = exports.useMultipleZarr = exports.ZarrHelper = void 0;
7
7
  var _react = require("react");
8
8
  var _reactQuery = require("@tanstack/react-query");
9
- var _zarr = require("zarr");
9
+ var zarr = _interopRequireWildcard(require("zarrita"));
10
+ var _ndarray = require("@zarrita/ndarray");
11
+ var _ndarrayUnpack = _interopRequireDefault(require("ndarray-unpack"));
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
14
  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; }
11
15
  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; }
12
16
  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; }
13
17
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
14
18
  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); }
15
- const GET_OPTIONS = exports.GET_OPTIONS = {
16
- concurrencyLimit: 10,
17
- // max number of concurrent requests (default 10)
18
- progressCallback: _ref => {
19
- let {
20
- progress,
21
- queueSize
22
- } = _ref;
23
- console.debug("".concat(progress / queueSize * 100, "% complete."));
24
- } // callback executed after each request
25
- };
26
19
  class ZarrHelper {
27
20
  async open(url, path) {
28
- const z = await (0, _zarr.openArray)({
29
- store: url,
30
- path: path,
31
- mode: 'r'
32
- });
21
+ const root = zarr.root(new zarr.FetchStore(url));
22
+ const z = await zarr.open(root.resolve(path));
33
23
  return z;
34
24
  }
35
25
  }
36
26
  exports.ZarrHelper = ZarrHelper;
37
- const fetchDataFromZarr = async (url, path, s, opts) => {
27
+ const fetchDataFromZarr = async (url, path, s) => {
38
28
  try {
39
29
  const zarrHelper = new ZarrHelper();
40
30
  const z = await zarrHelper.open(url, path);
41
- const result = await z.get(s, opts);
42
- return result.data;
31
+ const result = await (0, _ndarray.get)(z, s);
32
+ if (result.dtype === 'bigint64') throw new Error('bigint64 dtype not supported');
33
+ const arr = (0, _ndarrayUnpack.default)(result);
34
+ return arr;
43
35
  } catch (error) {
44
- if (error instanceof _zarr.ArrayNotFoundError || error instanceof _zarr.GroupNotFoundError) {
36
+ if (error instanceof zarr.NodeNotFoundError) {
45
37
  error.status = 404;
46
38
  }
47
39
  throw error;
48
40
  }
49
41
  };
50
- const useZarr = function (_ref2) {
42
+ const useZarr = function (_ref) {
51
43
  let {
52
44
  url,
53
45
  path,
54
46
  s = null
55
- } = _ref2;
56
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GET_OPTIONS;
57
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
47
+ } = _ref;
48
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
58
49
  const {
59
50
  data = null,
60
51
  isLoading: isPending = false,
61
52
  error: serverError = null
62
53
  } = (0, _reactQuery.useQuery)(_objectSpread({
63
54
  queryKey: ['zarr', url, path, s],
64
- queryFn: () => fetchDataFromZarr(url, path, s, options),
65
- retry: (failureCount, _ref3) => {
55
+ queryFn: () => fetchDataFromZarr(url, path, s),
56
+ retry: (failureCount, _ref2) => {
66
57
  let {
67
58
  error
68
- } = _ref3;
59
+ } = _ref2;
69
60
  if ([400, 401, 403, 404, 422].includes(error === null || error === void 0 ? void 0 : error.status)) return false;
70
61
  return failureCount < 3;
71
62
  }
@@ -86,9 +77,8 @@ const aggregateData = (inputs, data) => {
86
77
  return dataObject;
87
78
  };
88
79
  const useMultipleZarr = function (inputs) {
89
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GET_OPTIONS;
90
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
91
- let agg = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : aggregateData;
80
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
81
+ let agg = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : aggregateData;
92
82
  const combine = (0, _react.useCallback)(results => {
93
83
  return {
94
84
  data: agg(inputs, results.map(result => result.data)),
@@ -103,11 +93,11 @@ const useMultipleZarr = function (inputs) {
103
93
  } = (0, _reactQuery.useQueries)({
104
94
  queries: inputs.map(input => _objectSpread({
105
95
  queryKey: ['zarr', input.url, input.path, input.s],
106
- queryFn: () => fetchDataFromZarr(input.url, input.path, input.s, options),
107
- retry: (failureCount, _ref4) => {
96
+ queryFn: () => fetchDataFromZarr(input.url, input.path, input.s),
97
+ retry: (failureCount, _ref3) => {
108
98
  let {
109
99
  error
110
- } = _ref4;
100
+ } = _ref3;
111
101
  if ([400, 401, 403, 404, 422].includes(error === null || error === void 0 ? void 0 : error.status)) return false;
112
102
  return failureCount < 3;
113
103
  }
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useXData = exports.useObsmData = exports.useObsData = exports.useLabelObsData = void 0;
7
7
  var _react = require("react");
8
8
  var _lodash = _interopRequireDefault(require("lodash"));
9
- var _zarr = require("zarr");
9
+ var _zarrita = require("zarrita");
10
10
  var _Resolver = require("./Resolver");
11
11
  var _constants = require("../constants/constants");
12
12
  var _DatasetContext = require("../context/DatasetContext");
@@ -22,9 +22,9 @@ const useObsmData = function () {
22
22
  const obsmParams = (0, _react.useMemo)(() => ({
23
23
  url: dataset.url,
24
24
  path: 'obsm/' + obsm,
25
- s: [null, (0, _zarr.slice)(null, 2)] // load only [:, :2]
25
+ s: [null, (0, _zarrita.slice)(null, 2)] // load only [:, :2]
26
26
  }), [dataset.url, obsm]);
27
- return (0, _zarrHelper.useZarr)(obsmParams, _zarrHelper.GET_OPTIONS, {
27
+ return (0, _zarrHelper.useZarr)(obsmParams, {
28
28
  enabled: !!obsm
29
29
  });
30
30
  };
@@ -52,7 +52,7 @@ const useXData = function () {
52
52
  s: [null, v.matrix_index]
53
53
  };
54
54
  }), [dataset.url, selectedVar]);
55
- return (0, _zarrHelper.useMultipleZarr)(xParams, _zarrHelper.GET_OPTIONS, {
55
+ return (0, _zarrHelper.useMultipleZarr)(xParams, {
56
56
  enabled: !!xParams.length
57
57
  }, agg);
58
58
  };
@@ -70,7 +70,7 @@ const useObsData = function () {
70
70
  path: 'obs/' + ((_obs = obs) === null || _obs === void 0 ? void 0 : _obs.name) + (((_obs2 = obs) === null || _obs2 === void 0 ? void 0 : _obs2.type) === _constants.OBS_TYPES.CATEGORICAL ? '/codes' : '')
71
71
  };
72
72
  }, [dataset.url, (_obs3 = obs) === null || _obs3 === void 0 ? void 0 : _obs3.name, (_obs4 = obs) === null || _obs4 === void 0 ? void 0 : _obs4.type]);
73
- return (0, _zarrHelper.useZarr)(obsParams, _zarrHelper.GET_OPTIONS, {
73
+ return (0, _zarrHelper.useZarr)(obsParams, {
74
74
  enabled: !!obs
75
75
  });
76
76
  };
@@ -86,7 +86,7 @@ const useLabelObsData = () => {
86
86
  key: obs.name
87
87
  };
88
88
  }), [dataset.url, settings.data.obs, settings.labelObs]);
89
- return (0, _zarrHelper.useMultipleZarr)(labelObsParams, _zarrHelper.GET_OPTIONS, {
89
+ return (0, _zarrHelper.useMultipleZarr)(labelObsParams, {
90
90
  enabled: !!labelObsParams.length
91
91
  });
92
92
  };
@@ -1,9 +1,4 @@
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 { useEffect, useState } from 'react';
1
+ import { useEffect, useState, useMemo } from 'react';
7
2
  import _ from 'lodash';
8
3
  import { Button, ButtonGroup, Dropdown, DropdownButton, OverlayTrigger, Tooltip } from 'react-bootstrap';
9
4
  import { DEFAULT_OBSM_KEYS } from '../../constants/constants';
@@ -20,18 +15,11 @@ export function ObsmKeysList(_ref) {
20
15
  const dataset = useDataset();
21
16
  const settings = useSettings();
22
17
  const dispatch = useSettingsDispatch();
23
- const [obsmKeysList, setObsmKeysList] = useState([]);
18
+ const [keysList, setKeysList] = useState([]);
24
19
  const [active, setActive] = useState(null);
25
- const [params, setParams] = useState({
20
+ const params = useMemo(() => ({
26
21
  url: dataset.url
27
- });
28
- useEffect(() => {
29
- setParams(p => {
30
- return _objectSpread(_objectSpread({}, p), {}, {
31
- url: dataset.url
32
- });
33
- });
34
- }, [dataset.url]);
22
+ }), [dataset.url]);
35
23
  const {
36
24
  fetchedData,
37
25
  isPending,
@@ -41,17 +29,34 @@ export function ObsmKeysList(_ref) {
41
29
  });
42
30
  useEffect(() => {
43
31
  if (!isPending && !serverError) {
44
- if (!fetchedData || !fetchedData.length) {
32
+ const obsmKeysArray = Array.isArray(fetchedData) ? fetchedData : [];
33
+ if (obsmKeysArray.length === 0) {
45
34
  setHasObsm(false);
35
+ setKeysList([]);
36
+ if (settings.selectedObsm) {
37
+ dispatch({
38
+ type: 'select.obsm',
39
+ obsm: null
40
+ });
41
+ }
46
42
  } else {
47
43
  setHasObsm(true);
48
- setObsmKeysList(fetchedData);
49
-
50
- // Set default obsm if in keys list and not selected
51
- if (!settings.selectedObsm) {
44
+ setKeysList(obsmKeysArray);
45
+ if (settings.selectedObsm) {
46
+ // If selected obsm is not in keys list, reset to null
47
+ if (!_.includes(obsmKeysArray, settings.selectedObsm)) {
48
+ dispatch({
49
+ type: 'select.obsm',
50
+ obsm: null
51
+ });
52
+ } else {
53
+ setActive(settings.selectedObsm);
54
+ }
55
+ } else {
56
+ // Set default obsm if in keys list and not selected
52
57
  // Follow DEFAULT_OBSM_KEYS order
53
58
  _.each(DEFAULT_OBSM_KEYS, k => {
54
- const defaultObsm = _.find(fetchedData, item => item.toLowerCase() === k);
59
+ const defaultObsm = _.find(obsmKeysArray, item => item.toLowerCase() === k);
55
60
  if (defaultObsm) {
56
61
  dispatch({
57
62
  type: 'select.obsm',
@@ -62,20 +67,16 @@ export function ObsmKeysList(_ref) {
62
67
  });
63
68
  }
64
69
  }
70
+ } else if (!isPending && serverError) {
65
71
  if (settings.selectedObsm) {
66
- // If selected obsm is not in keys list, reset to null
67
- if (!_.includes(fetchedData || [], settings.selectedObsm)) {
68
- dispatch({
69
- type: 'select.obsm',
70
- obsm: null
71
- });
72
- } else {
73
- setActive(settings.selectedObsm);
74
- }
72
+ dispatch({
73
+ type: 'select.obsm',
74
+ obsm: null
75
+ });
75
76
  }
76
77
  }
77
78
  }, [dispatch, fetchedData, isPending, serverError, setHasObsm, settings.selectedObsm]);
78
- const obsmList = obsmKeysList.map(item => {
79
+ const obsmList = keysList.map(item => {
79
80
  return /*#__PURE__*/_jsx(Dropdown.Item, {
80
81
  className: "custom ".concat(active === item && 'active'),
81
82
  onClick: () => {
@@ -4,7 +4,7 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
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 { useEffect, useState } from 'react';
7
- import { faDroplet, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
7
+ import { faCheck, faDroplet, faTrash } from '@fortawesome/free-solid-svg-icons';
8
8
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
9
9
  import { MoreVert } from '@mui/icons-material';
10
10
  import _ from 'lodash';
@@ -156,13 +156,11 @@ export function SelectionItem(_ref3) {
156
156
  selectVar();
157
157
  },
158
158
  disabled: isNotInData,
159
- title: isNotInData ? 'Not present in data' : 'Set as color encoding',
160
- children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
159
+ title: isNotInData ? 'Not present in data' : isMultiple ? isActive ? 'Remove from plot' : 'Add to plot' : 'Set as color encoding',
160
+ children: [!isMultiple && /*#__PURE__*/_jsx(FontAwesomeIcon, {
161
161
  icon: faDroplet
162
162
  }), isMultiple && /*#__PURE__*/_jsx(FontAwesomeIcon, {
163
- icon: faPlus,
164
- size: "xs",
165
- className: "ps-xs-1"
163
+ icon: faCheck
166
164
  })]
167
165
  }, item.matrix_index), showRemove && /*#__PURE__*/_jsx(Button, {
168
166
  type: "button",
@@ -1,12 +1,12 @@
1
1
  import { useState } from 'react';
2
- import { faChevronDown, faChevronUp, faCircleInfo, faDroplet, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
2
+ import { faCheck, faChevronDown, faChevronUp, faCircleInfo, faDroplet, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
3
3
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
4
  import _ from 'lodash';
5
5
  import { Button, Collapse, ListGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
6
- import { SelectionItem } from './VarItem';
7
6
  import { COLOR_ENCODINGS, SELECTION_MODES } from '../../constants/constants';
8
7
  import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
9
8
  import { SearchModal } from '../search-bar/SearchBar';
9
+ import { SelectionItem } from './VarItem';
10
10
 
11
11
  // @TODO: add button to score genes and plot
12
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
@@ -95,13 +95,11 @@ function SelectionSet(_ref) {
95
95
  selectSet();
96
96
  },
97
97
  disabled: !set.vars.length,
98
- title: "Set as color encoding",
99
- children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
98
+ title: !set.vars.length ? 'No variables in set' : isMultiple ? isActive ? 'Remove from plot' : 'Add to plot' : 'Set as color encoding',
99
+ children: [!isMultiple && /*#__PURE__*/_jsx(FontAwesomeIcon, {
100
100
  icon: faDroplet
101
101
  }), isMultiple && /*#__PURE__*/_jsx(FontAwesomeIcon, {
102
- icon: faPlus,
103
- size: "xs",
104
- className: "ps-xs-1"
102
+ icon: faCheck
105
103
  })]
106
104
  }), /*#__PURE__*/_jsx(Button, {
107
105
  type: "button",
@@ -51,7 +51,7 @@ const persistOptions = {
51
51
  return false;
52
52
  }
53
53
  },
54
- buster: "1.4.4" || '0.0.0'
54
+ buster: "1.4.6-dev.2026-01-12.f157a881" || '0.0.0'
55
55
  // @TODO: add maxAge and api version numbers as buster
56
56
  };
57
57
  const initialDataset = {
@@ -163,7 +163,7 @@ export function SettingsProvider(_ref2) {
163
163
 
164
164
  // If the buster is not set or does not match the current package version,
165
165
  // reset localSettings to avoid stale data
166
- if (!buster || buster !== "1.4.4") {
166
+ if (!buster || buster !== "1.4.6-dev.2026-01-12.f157a881") {
167
167
  localSettings = {};
168
168
  }
169
169
  const initSettings = useRef(initializer({
@@ -188,7 +188,7 @@ export function SettingsProvider(_ref2) {
188
188
  if (canOverrideSettings && settings) {
189
189
  try {
190
190
  localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
191
- buster: "1.4.4" || '0.0.0',
191
+ buster: "1.4.6-dev.2026-01-12.f157a881" || '0.0.0',
192
192
  timestamp: Date.now()
193
193
  }, _.omit(settings, 'data'))));
194
194
  } catch (err) {
@@ -5,60 +5,49 @@ 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 { useCallback } from 'react';
7
7
  import { useQueries, useQuery } from '@tanstack/react-query';
8
- import { ArrayNotFoundError, GroupNotFoundError, openArray } from 'zarr';
9
- export const GET_OPTIONS = {
10
- concurrencyLimit: 10,
11
- // max number of concurrent requests (default 10)
12
- progressCallback: _ref => {
13
- let {
14
- progress,
15
- queueSize
16
- } = _ref;
17
- console.debug("".concat(progress / queueSize * 100, "% complete."));
18
- } // callback executed after each request
19
- };
8
+ import * as zarr from 'zarrita';
9
+ import { get } from '@zarrita/ndarray';
10
+ import unpack from 'ndarray-unpack';
20
11
  export class ZarrHelper {
21
12
  async open(url, path) {
22
- const z = await openArray({
23
- store: url,
24
- path: path,
25
- mode: 'r'
26
- });
13
+ const root = zarr.root(new zarr.FetchStore(url));
14
+ const z = await zarr.open(root.resolve(path));
27
15
  return z;
28
16
  }
29
17
  }
30
- const fetchDataFromZarr = async (url, path, s, opts) => {
18
+ const fetchDataFromZarr = async (url, path, s) => {
31
19
  try {
32
20
  const zarrHelper = new ZarrHelper();
33
21
  const z = await zarrHelper.open(url, path);
34
- const result = await z.get(s, opts);
35
- return result.data;
22
+ const result = await get(z, s);
23
+ if (result.dtype === 'bigint64') throw new Error('bigint64 dtype not supported');
24
+ const arr = unpack(result);
25
+ return arr;
36
26
  } catch (error) {
37
- if (error instanceof ArrayNotFoundError || error instanceof GroupNotFoundError) {
27
+ if (error instanceof zarr.NodeNotFoundError) {
38
28
  error.status = 404;
39
29
  }
40
30
  throw error;
41
31
  }
42
32
  };
43
- export const useZarr = function (_ref2) {
33
+ export const useZarr = function (_ref) {
44
34
  let {
45
35
  url,
46
36
  path,
47
37
  s = null
48
- } = _ref2;
49
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GET_OPTIONS;
50
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
38
+ } = _ref;
39
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
51
40
  const {
52
41
  data = null,
53
42
  isLoading: isPending = false,
54
43
  error: serverError = null
55
44
  } = useQuery(_objectSpread({
56
45
  queryKey: ['zarr', url, path, s],
57
- queryFn: () => fetchDataFromZarr(url, path, s, options),
58
- retry: (failureCount, _ref3) => {
46
+ queryFn: () => fetchDataFromZarr(url, path, s),
47
+ retry: (failureCount, _ref2) => {
59
48
  let {
60
49
  error
61
- } = _ref3;
50
+ } = _ref2;
62
51
  if ([400, 401, 403, 404, 422].includes(error === null || error === void 0 ? void 0 : error.status)) return false;
63
52
  return failureCount < 3;
64
53
  }
@@ -78,9 +67,8 @@ const aggregateData = (inputs, data) => {
78
67
  return dataObject;
79
68
  };
80
69
  export const useMultipleZarr = function (inputs) {
81
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GET_OPTIONS;
82
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
83
- let agg = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : aggregateData;
70
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
71
+ let agg = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : aggregateData;
84
72
  const combine = useCallback(results => {
85
73
  return {
86
74
  data: agg(inputs, results.map(result => result.data)),
@@ -95,11 +83,11 @@ export const useMultipleZarr = function (inputs) {
95
83
  } = useQueries({
96
84
  queries: inputs.map(input => _objectSpread({
97
85
  queryKey: ['zarr', input.url, input.path, input.s],
98
- queryFn: () => fetchDataFromZarr(input.url, input.path, input.s, options),
99
- retry: (failureCount, _ref4) => {
86
+ queryFn: () => fetchDataFromZarr(input.url, input.path, input.s),
87
+ retry: (failureCount, _ref3) => {
100
88
  let {
101
89
  error
102
- } = _ref4;
90
+ } = _ref3;
103
91
  if ([400, 401, 403, 404, 422].includes(error === null || error === void 0 ? void 0 : error.status)) return false;
104
92
  return failureCount < 3;
105
93
  }
@@ -1,11 +1,11 @@
1
1
  import { useMemo } from 'react';
2
2
  import _ from 'lodash';
3
- import { slice } from 'zarr';
3
+ import { slice } from 'zarrita';
4
4
  import { useSelectedObs, useSelectedVar } from './Resolver';
5
5
  import { OBS_TYPES } from '../constants/constants';
6
6
  import { useDataset } from '../context/DatasetContext';
7
7
  import { useSettings } from '../context/SettingsContext';
8
- import { GET_OPTIONS, useZarr, useMultipleZarr } from '../helpers/zarr-helper';
8
+ import { useZarr, useMultipleZarr } from '../helpers/zarr-helper';
9
9
 
10
10
  // @TODO: support specifying slice to load from context
11
11
  export const useObsmData = function () {
@@ -18,7 +18,7 @@ export const useObsmData = function () {
18
18
  path: 'obsm/' + obsm,
19
19
  s: [null, slice(null, 2)] // load only [:, :2]
20
20
  }), [dataset.url, obsm]);
21
- return useZarr(obsmParams, GET_OPTIONS, {
21
+ return useZarr(obsmParams, {
22
22
  enabled: !!obsm
23
23
  });
24
24
  };
@@ -45,7 +45,7 @@ export const useXData = function () {
45
45
  s: [null, v.matrix_index]
46
46
  };
47
47
  }), [dataset.url, selectedVar]);
48
- return useMultipleZarr(xParams, GET_OPTIONS, {
48
+ return useMultipleZarr(xParams, {
49
49
  enabled: !!xParams.length
50
50
  }, agg);
51
51
  };
@@ -62,7 +62,7 @@ export const useObsData = function () {
62
62
  path: 'obs/' + ((_obs = obs) === null || _obs === void 0 ? void 0 : _obs.name) + (((_obs2 = obs) === null || _obs2 === void 0 ? void 0 : _obs2.type) === OBS_TYPES.CATEGORICAL ? '/codes' : '')
63
63
  };
64
64
  }, [dataset.url, (_obs3 = obs) === null || _obs3 === void 0 ? void 0 : _obs3.name, (_obs4 = obs) === null || _obs4 === void 0 ? void 0 : _obs4.type]);
65
- return useZarr(obsParams, GET_OPTIONS, {
65
+ return useZarr(obsParams, {
66
66
  enabled: !!obs
67
67
  });
68
68
  };
@@ -77,7 +77,7 @@ export const useLabelObsData = () => {
77
77
  key: obs.name
78
78
  };
79
79
  }), [dataset.url, settings.data.obs, settings.labelObs]);
80
- return useMultipleZarr(labelObsParams, GET_OPTIONS, {
80
+ return useMultipleZarr(labelObsParams, {
81
81
  enabled: !!labelObsParams.length
82
82
  });
83
83
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haniffalab/cherita-react",
3
- "version": "1.4.4",
3
+ "version": "1.4.6-dev.2026-01-12.f157a881",
4
4
  "author": "Haniffa Lab",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -42,9 +42,11 @@
42
42
  "@tanstack/react-virtual": "^3.7.0",
43
43
  "@turf/turf": "^7.0.0",
44
44
  "@uidotdev/usehooks": "^2.4.1",
45
+ "@zarrita/ndarray": "^0.1.5",
45
46
  "bootstrap": "^5.3.3",
46
47
  "deck.gl": "8.8.27",
47
48
  "jquery": "^3.7.1",
49
+ "ndarray-unpack": "^1.0.0",
48
50
  "nebula.gl": "^1.0.4",
49
51
  "numbro": "^2.5.0",
50
52
  "plotly.js": "^2.23.2",
@@ -52,7 +54,7 @@
52
54
  "react-bootstrap": "^2.7.4",
53
55
  "react-plotly.js": "^2.6.0",
54
56
  "react-scripts": "^5.0.1",
55
- "zarr": "^0.6.3"
57
+ "zarrita": "^0.5.4"
56
58
  },
57
59
  "peerDependencies": {
58
60
  "react": "^18.2.0",
@@ -139,5 +141,6 @@
139
141
  "bugs": {
140
142
  "url": "https://github.com/haniffalab/cherita-react/issues"
141
143
  },
142
- "homepage": "https://github.com/haniffalab/cherita-react#readme"
143
- }
144
+ "homepage": "https://github.com/haniffalab/cherita-react#readme",
145
+ "prereleaseSha": "f157a88143d77d5a3d69296e84895802f0c39073"
146
+ }