@jbrowse/core 2.9.0 → 2.10.1

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.
@@ -33,9 +33,10 @@ const material_1 = require("@mui/material");
33
33
  const types_1 = require("../../util/types");
34
34
  const LocalFileChooser_1 = __importDefault(require("./LocalFileChooser"));
35
35
  const UrlChooser_1 = __importDefault(require("./UrlChooser"));
36
+ const util_1 = require("../../util");
36
37
  // icons
37
38
  const ArrowDropDown_1 = __importDefault(require("@mui/icons-material/ArrowDropDown"));
38
- const util_1 = require("../../util");
39
+ const NUM_SHOWN = 2;
39
40
  function ToggleButtonWithTooltip(props) {
40
41
  const { title, children, ...other } = props;
41
42
  return (react_1.default.createElement(material_1.Tooltip, { title: title || '' },
@@ -53,35 +54,40 @@ const FileSelector = (0, mobx_react_1.observer)(function (props) {
53
54
  const [toggleButtonValue, setToggleButtonValue] = (0, react_1.useState)(location && 'internetAccountId' in location && location.internetAccountId
54
55
  ? location.internetAccountId
55
56
  : fileOrUrl);
56
- const accts = (0, types_1.isAppRootModel)(rootModel) ? [...rootModel.internetAccounts] : [];
57
- const numShown = 2;
58
- const [shownAccts, setShownAccts] = (0, react_1.useState)(accts.slice(0, numShown));
59
- const [hiddenAccts, setHiddenAccts] = (0, react_1.useState)(accts.slice(numShown));
57
+ const accounts = (0, types_1.isAppRootModel)(rootModel)
58
+ ? rootModel.internetAccounts.filter(f => f.type !== 'HTTPBasicInternetAccount')
59
+ : [];
60
+ const [recentlyUsedInternetAccounts, setRecentlyUsedInternetAccounts] = (0, util_1.useLocalStorage)('fileSelector-recentlyUsedInternetAccounts', []);
61
+ const map = Object.fromEntries(accounts.map(a => [a.internetAccountId, a]));
62
+ const arr = [...new Set(accounts.map(s => s.internetAccountId))].sort((a, b) => recentlyUsedInternetAccounts.indexOf(a) -
63
+ recentlyUsedInternetAccounts.indexOf(b));
64
+ const shownAccounts = arr.slice(0, NUM_SHOWN);
65
+ const hiddenAccounts = arr.slice(NUM_SHOWN);
60
66
  const [anchorEl, setAnchorEl] = (0, react_1.useState)(null);
61
- const selectedAcct = accts.find(i => i.internetAccountId === toggleButtonValue);
62
- const setLocationWithAcct = (0, react_1.useCallback)((location) => {
67
+ const selectedAccount = map[toggleButtonValue];
68
+ const setLocationWithAccount = (0, react_1.useCallback)((location) => {
63
69
  setLocation({
64
70
  ...location,
65
71
  ...((0, types_1.isUriLocation)(location)
66
- ? { internetAccountId: selectedAcct === null || selectedAcct === void 0 ? void 0 : selectedAcct.internetAccountId }
72
+ ? { internetAccountId: selectedAccount === null || selectedAccount === void 0 ? void 0 : selectedAccount.internetAccountId }
67
73
  : {}),
68
74
  });
69
- }, [setLocation, selectedAcct]);
75
+ }, [setLocation, selectedAccount]);
70
76
  (0, react_1.useEffect)(() => {
71
77
  // if you swap account selection after inputting url
72
- if (selectedAcct &&
78
+ if (selectedAccount &&
73
79
  (0, types_1.isUriLocation)(location) &&
74
- location.internetAccountId !== selectedAcct.internetAccountId) {
75
- setLocationWithAcct(location);
80
+ location.internetAccountId !== selectedAccount.internetAccountId) {
81
+ setLocationWithAccount(location);
76
82
  }
77
- }, [location, selectedAcct, setLocationWithAcct]);
78
- let locationInput = (react_1.default.createElement(UrlChooser_1.default, { ...props, setLocation: setLocationWithAcct, label: selectedAcct === null || selectedAcct === void 0 ? void 0 : selectedAcct.selectorLabel }));
83
+ }, [location, selectedAccount, setLocationWithAccount]);
84
+ let locationInput = (react_1.default.createElement(UrlChooser_1.default, { ...props, setLocation: setLocationWithAccount, label: selectedAccount === null || selectedAccount === void 0 ? void 0 : selectedAccount.selectorLabel }));
79
85
  if (toggleButtonValue === 'file') {
80
86
  locationInput = react_1.default.createElement(LocalFileChooser_1.default, { ...props });
81
87
  }
82
- if (selectedAcct === null || selectedAcct === void 0 ? void 0 : selectedAcct.SelectorComponent) {
83
- const { SelectorComponent } = selectedAcct;
84
- locationInput = (react_1.default.createElement(SelectorComponent, { ...props, setLocation: setLocationWithAcct }));
88
+ if (selectedAccount === null || selectedAccount === void 0 ? void 0 : selectedAccount.SelectorComponent) {
89
+ const { SelectorComponent } = selectedAccount;
90
+ locationInput = (react_1.default.createElement(SelectorComponent, { ...props, setLocation: setLocationWithAccount }));
85
91
  }
86
92
  return (react_1.default.createElement(react_1.default.Fragment, null,
87
93
  react_1.default.createElement(material_1.Box, { display: "flex" },
@@ -89,34 +95,42 @@ const FileSelector = (0, mobx_react_1.observer)(function (props) {
89
95
  react_1.default.createElement(material_1.Box, { display: "flex", flexDirection: "row" },
90
96
  react_1.default.createElement(material_1.Box, null,
91
97
  react_1.default.createElement(material_1.ToggleButtonGroup, { value: toggleButtonValue, exclusive: true, onChange: (_event, newState) => {
98
+ setRecentlyUsedInternetAccounts([
99
+ ...new Set([newState, ...recentlyUsedInternetAccounts].filter(util_1.notEmpty)),
100
+ ]);
92
101
  if (newState) {
93
102
  setToggleButtonValue(newState);
94
103
  }
95
104
  if ((0, types_1.isUriLocation)(location)) {
96
- setLocationWithAcct(location);
105
+ setLocationWithAccount(location);
97
106
  }
98
107
  }, "aria-label": "file, url, or account picker" },
99
108
  new URLSearchParams(window.location.search).get('adminKey') ? null : (react_1.default.createElement(material_1.ToggleButton, { value: "file", "aria-label": "local file" }, "File")),
100
109
  react_1.default.createElement(material_1.ToggleButton, { value: "url", "aria-label": "url" }, "URL"),
101
- shownAccts.map(({ internetAccountId, toggleContents, name }) => (react_1.default.createElement(ToggleButtonWithTooltip, { key: internetAccountId, value: internetAccountId, "aria-label": name, title: name }, typeof toggleContents === 'string'
102
- ? shorten(toggleContents, 5)
103
- : toggleContents || shorten(name, 5)))),
104
- hiddenAccts.length > 0 ? (
110
+ shownAccounts.map(id => {
111
+ const { internetAccountId, name, toggleContents } = map[id];
112
+ return (react_1.default.createElement(ToggleButtonWithTooltip, { key: id, value: internetAccountId, title: name }, typeof toggleContents === 'string'
113
+ ? shorten(toggleContents, 5)
114
+ : toggleContents || shorten(name, 5)));
115
+ }),
116
+ hiddenAccounts.length > 0 ? (
105
117
  // @ts-expect-error
106
118
  react_1.default.createElement(material_1.ToggleButton, { onClick: event => setAnchorEl(event.target), selected: false },
107
119
  "More",
108
120
  react_1.default.createElement(ArrowDropDown_1.default, null))) : null),
109
- react_1.default.createElement(material_1.Menu, { open: Boolean(anchorEl), anchorEl: anchorEl, onClose: () => setAnchorEl(null), anchorOrigin: { vertical: 'bottom', horizontal: 'center' }, transformOrigin: { vertical: 'top', horizontal: 'center' } }, hiddenAccts === null || hiddenAccts === void 0 ? void 0 : hiddenAccts.map((acct, idx) => (react_1.default.createElement(material_1.MenuItem, { key: acct.internetAccountId, value: acct.internetAccountId, onClick: () => {
110
- const prev = shownAccts.at(-1);
111
- setShownAccts([...shownAccts.slice(0, -1), acct]);
112
- setHiddenAccts([
113
- prev,
114
- ...hiddenAccts.slice(0, idx),
115
- ...hiddenAccts.slice(idx + 1),
116
- ].filter(util_1.notEmpty));
117
- setToggleButtonValue(acct.internetAccountId);
118
- setAnchorEl(null);
119
- } }, acct.name)))))),
121
+ react_1.default.createElement(material_1.Menu, { open: Boolean(anchorEl), anchorEl: anchorEl, onClose: () => setAnchorEl(null), anchorOrigin: { vertical: 'bottom', horizontal: 'center' }, transformOrigin: { vertical: 'top', horizontal: 'center' } }, hiddenAccounts === null || hiddenAccounts === void 0 ? void 0 : hiddenAccounts.map(id => {
122
+ const { internetAccountId, name } = map[id];
123
+ return (react_1.default.createElement(material_1.MenuItem, { key: id, value: internetAccountId, onClick: () => {
124
+ setRecentlyUsedInternetAccounts([
125
+ ...new Set([
126
+ internetAccountId,
127
+ ...recentlyUsedInternetAccounts,
128
+ ].filter(util_1.notEmpty)),
129
+ ]);
130
+ setToggleButtonValue(internetAccountId);
131
+ setAnchorEl(null);
132
+ } }, name));
133
+ })))),
120
134
  locationInput,
121
135
  react_1.default.createElement(material_1.FormHelperText, null, description)));
122
136
  });
package/util/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import PluginManager from '../PluginManager';
3
3
  import { IAnyStateTreeNode, IStateTreeNode, Instance } from 'mobx-state-tree';
4
4
  import { IReactionPublic, IReactionOptions } from 'mobx';
@@ -16,7 +16,7 @@ export * from './offscreenCanvasUtils';
16
16
  export declare function useDebounce<T>(value: T, delay: number): T;
17
17
  export declare function useWidthSetter(view: {
18
18
  setWidth: (arg: number) => void;
19
- }, padding: string): import("react").RefObject<HTMLDivElement>;
19
+ }, padding: string): React.RefObject<HTMLDivElement>;
20
20
  export declare function useDebouncedCallback<T>(callback: (...args: T[]) => void, wait?: number): (...args: T[]) => void;
21
21
  /**
22
22
  * find the first node in the hierarchy that matches the given predicate
@@ -213,7 +213,7 @@ export declare function renameRegionsIfNeeded<ARGTYPE extends {
213
213
  assemblyName?: string;
214
214
  regions?: Region[];
215
215
  signal?: AbortSignal;
216
- adapterConfig: unknown;
216
+ adapterConfig: Record<string, unknown>;
217
217
  sessionId: string;
218
218
  statusCallback?: (arg: string) => void;
219
219
  }>(assemblyManager: AssemblyManager, args: ARGTYPE): Promise<ARGTYPE & {
@@ -389,6 +389,9 @@ interface BasicFeature {
389
389
  refName: string;
390
390
  }
391
391
  export declare function gatherOverlaps(regions: BasicFeature[]): BasicFeature[];
392
- export { default as SimpleFeature, type Feature, type SimpleFeatureSerialized, isFeature, } from './simpleFeature';
393
392
  export declare function stripAlpha(str: string): string;
393
+ export declare function renderToStaticMarkup(node: React.ReactElement, createRootFn?: (elt: Element | DocumentFragment) => {
394
+ render: (node: React.ReactElement) => unknown;
395
+ }): string;
396
+ export { default as SimpleFeature, type Feature, type SimpleFeatureSerialized, isFeature, } from './simpleFeature';
394
397
  export { blobToDataURL } from './blobToDataURL';
package/util/index.js CHANGED
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
20
  exports.toLocale = exports.getBpDisplayStr = exports.isSupportedIndexingAdapter = exports.bytesForRegions = exports.objectHash = exports.hashCode = exports.updateStatus = exports.generateCodonTable = exports.defaultCodonTable = exports.defaultStops = exports.defaultStarts = exports.measureText = exports.rIC = exports.complement = exports.reverse = exports.revcom = exports.isElectron = exports.stringify = exports.shorten = exports.minmax = exports.renameRegionsIfNeeded = exports.renameRegionIfNeeded = exports.makeAbortableReaction = exports.findLast = exports.findLastIndex = exports.iterMap = exports.bpSpanPx = exports.featureSpanPx = exports.cartesianToPolar = exports.polarToCartesian = exports.degToRad = exports.radToDeg = exports.bpToPx = exports.clamp = exports.compareLocStrings = exports.compareLocs = exports.parseLocString = exports.parseLocStringOneBased = exports.assembleLocStringFast = exports.assembleLocString = exports.getContainingDisplay = exports.getContainingTrack = exports.getContainingView = exports.getSession = exports.findParentThatIs = exports.springAnimate = exports.findParentThat = exports.useDebouncedCallback = exports.useWidthSetter = exports.useDebounce = void 0;
21
- exports.blobToDataURL = exports.stripAlpha = exports.isFeature = exports.SimpleFeature = exports.gatherOverlaps = exports.mergeIntervals = exports.notEmpty = exports.groupBy = exports.avg = exports.sum = exports.min = exports.max = exports.localStorageSetItem = exports.localStorageGetItem = exports.getEnv = exports.measureGridWidth = exports.linkify = exports.coarseStripHTML = exports.getStr = exports.getUriLink = exports.useLocalStorage = exports.getLayoutId = exports.getViewParams = exports.getTickDisplayStr = void 0;
21
+ exports.blobToDataURL = exports.isFeature = exports.SimpleFeature = exports.renderToStaticMarkup = exports.stripAlpha = exports.gatherOverlaps = exports.mergeIntervals = exports.notEmpty = exports.groupBy = exports.avg = exports.sum = exports.min = exports.max = exports.localStorageSetItem = exports.localStorageGetItem = exports.getEnv = exports.measureGridWidth = exports.linkify = exports.coarseStripHTML = exports.getStr = exports.getUriLink = exports.useLocalStorage = exports.getLayoutId = exports.getViewParams = exports.getTickDisplayStr = void 0;
22
22
  /* eslint-disable @typescript-eslint/no-explicit-any */
23
23
  const react_1 = require("react");
24
24
  const is_object_1 = __importDefault(require("is-object"));
@@ -30,6 +30,8 @@ const types_2 = require("./types");
30
30
  // has to be the full path and not the relative path to get the jest mock
31
31
  const useMeasure_1 = __importDefault(require("@jbrowse/core/util/useMeasure"));
32
32
  const colord_1 = require("./colord");
33
+ // eslint-disable-next-line react/no-deprecated
34
+ const react_dom_1 = require("react-dom");
33
35
  __exportStar(require("./types"), exports);
34
36
  __exportStar(require("./aborting"), exports);
35
37
  __exportStar(require("./when"), exports);
@@ -1132,13 +1134,27 @@ function gatherOverlaps(regions) {
1132
1134
  return Object.values(memo).flatMap(group => mergeIntervals(group.sort((a, b) => a.start - b.start)));
1133
1135
  }
1134
1136
  exports.gatherOverlaps = gatherOverlaps;
1135
- var simpleFeature_1 = require("./simpleFeature");
1136
- Object.defineProperty(exports, "SimpleFeature", { enumerable: true, get: function () { return __importDefault(simpleFeature_1).default; } });
1137
- Object.defineProperty(exports, "isFeature", { enumerable: true, get: function () { return simpleFeature_1.isFeature; } });
1138
1137
  function stripAlpha(str) {
1139
1138
  const c = (0, colord_1.colord)(str);
1140
1139
  return c.alpha(1).toHex();
1141
1140
  }
1142
1141
  exports.stripAlpha = stripAlpha;
1142
+ // https://react.dev/reference/react-dom/server/renderToString#removing-rendertostring-from-the-client-code
1143
+ function renderToStaticMarkup(node, createRootFn) {
1144
+ const div = document.createElement('div');
1145
+ (0, react_dom_1.flushSync)(() => {
1146
+ if (createRootFn) {
1147
+ createRootFn(div).render(node);
1148
+ }
1149
+ else {
1150
+ (0, react_dom_1.render)(node, div);
1151
+ }
1152
+ });
1153
+ return div.innerHTML;
1154
+ }
1155
+ exports.renderToStaticMarkup = renderToStaticMarkup;
1156
+ var simpleFeature_1 = require("./simpleFeature");
1157
+ Object.defineProperty(exports, "SimpleFeature", { enumerable: true, get: function () { return __importDefault(simpleFeature_1).default; } });
1158
+ Object.defineProperty(exports, "isFeature", { enumerable: true, get: function () { return simpleFeature_1.isFeature; } });
1143
1159
  var blobToDataURL_1 = require("./blobToDataURL");
1144
1160
  Object.defineProperty(exports, "blobToDataURL", { enumerable: true, get: function () { return blobToDataURL_1.blobToDataURL; } });
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { Buffer } from 'buffer';
2
3
  import { RemoteFile, PolyfilledResponse } from 'generic-filehandle';
3
4
  export interface BinaryRangeResponse {
4
5
  headers: Record<string, string>;