@jbrowse/plugin-linear-genome-view 1.3.4 → 1.5.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 (34) hide show
  1. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +3 -2
  2. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +20 -10
  3. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
  4. package/dist/LinearBareDisplay/model.d.ts +10 -9
  5. package/dist/LinearBasicDisplay/model.d.ts +13 -9
  6. package/dist/LinearGenomeView/components/Header.d.ts +2 -4
  7. package/dist/LinearGenomeView/components/RefNameAutocomplete.d.ts +1 -11
  8. package/dist/LinearGenomeView/components/ScaleBar.d.ts +46 -14
  9. package/dist/LinearGenomeView/components/util.d.ts +2 -0
  10. package/dist/LinearGenomeView/index.d.ts +13 -2
  11. package/dist/index.d.ts +47 -56
  12. package/dist/plugin-linear-genome-view.cjs.development.js +642 -423
  13. package/dist/plugin-linear-genome-view.cjs.development.js.map +1 -1
  14. package/dist/plugin-linear-genome-view.cjs.production.min.js +1 -1
  15. package/dist/plugin-linear-genome-view.cjs.production.min.js.map +1 -1
  16. package/dist/plugin-linear-genome-view.esm.js +652 -433
  17. package/dist/plugin-linear-genome-view.esm.js.map +1 -1
  18. package/package.json +4 -2
  19. package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +100 -21
  20. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +10 -10
  21. package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +15 -13
  22. package/src/LinearBasicDisplay/model.ts +25 -3
  23. package/src/LinearGenomeView/components/ExportSvgDialog.tsx +17 -8
  24. package/src/LinearGenomeView/components/Header.tsx +101 -104
  25. package/src/LinearGenomeView/components/ImportForm.tsx +146 -113
  26. package/src/LinearGenomeView/components/LinearGenomeView.test.js +6 -6
  27. package/src/LinearGenomeView/components/OverviewScaleBar.tsx +4 -1
  28. package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +196 -169
  29. package/src/LinearGenomeView/components/SearchResultsDialog.tsx +1 -16
  30. package/src/LinearGenomeView/components/SequenceDialog.tsx +59 -58
  31. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +5 -177
  32. package/src/LinearGenomeView/components/util.ts +8 -0
  33. package/src/LinearGenomeView/index.tsx +39 -28
  34. package/src/index.ts +3 -1
@@ -1,11 +1,11 @@
1
- import React, { useState, useRef, useEffect, useMemo, lazy } from 'react';
1
+ import React, { useRef, useState, useMemo, useEffect, lazy } from 'react';
2
2
  import { ConfigurationSchema, getConf, readConfObject, ConfigurationReference as ConfigurationReference$1 } from '@jbrowse/core/configuration';
3
3
  import { BaseDisplay, BaseViewModel, createBaseTrackConfig, createBaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
4
4
  import TrackType from '@jbrowse/core/pluggableElementTypes/TrackType';
5
5
  import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType';
6
6
  import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType';
7
7
  import Plugin from '@jbrowse/core/Plugin';
8
- import { getContainingView, getContainingDisplay, makeAbortableReaction, assembleLocString, getSession, isSessionModelWithWidgets, isSelectionContainer, useDebounce, stringify, useDebouncedCallback, clamp, isViewContainer, parseLocString, findLastIndex, springAnimate, isAbstractMenuManager } from '@jbrowse/core/util';
8
+ import { getContainingView, getContainingDisplay, makeAbortableReaction, assembleLocString, getSession, isSessionModelWithWidgets, isSelectionContainer, useDebounce, measureText, stringify, useDebouncedCallback, clamp, isViewContainer, parseLocString, findLastIndex, springAnimate, isAbstractMenuManager } from '@jbrowse/core/util';
9
9
  import LineStyleIcon from '@material-ui/icons/LineStyle';
10
10
  import CompositeMap from '@jbrowse/core/util/compositeMap';
11
11
  import { isFeature } from '@jbrowse/core/util/simpleFeature';
@@ -15,12 +15,14 @@ import Typography from '@material-ui/core/Typography';
15
15
  import MenuOpenIcon from '@material-ui/icons/MenuOpen';
16
16
  import { autorun, when, transaction } from 'mobx';
17
17
  import { getParent, types, cast, isAlive, addDisposer, getEnv, resolveIdentifier, getRoot, getSnapshot } from 'mobx-state-tree';
18
+ import { useTheme, makeStyles as makeStyles$1, alpha, Portal, TextField, Typography as Typography$1, Popper, CircularProgress, InputAdornment, Tooltip as Tooltip$1, Popover, FormGroup, Button as Button$1, Dialog, DialogTitle, IconButton as IconButton$1, Divider, DialogContent, DialogContentText, TableContainer, Paper as Paper$1, Table, TableHead, TableRow, TableCell, TableBody, DialogActions, Container, Grid, FormControlLabel, Checkbox } from '@material-ui/core';
18
19
  import { Menu, ResizeHandle } from '@jbrowse/core/ui';
19
- import { makeStyles, useTheme, alpha } from '@material-ui/core/styles';
20
20
  import { observer, PropTypes } from 'mobx-react';
21
- import MUITooltip from '@material-ui/core/Tooltip';
21
+ import { usePopper } from 'react-popper';
22
+ import { makeStyles, alpha as alpha$1, useTheme as useTheme$1 } from '@material-ui/core/styles';
22
23
  import { ContentBlock as ContentBlock$1, ElidedBlock as ElidedBlock$1, InterRegionPaddingBlock as InterRegionPaddingBlock$1 } from '@jbrowse/core/util/blockTypes';
23
24
  import { Region, ElementId } from '@jbrowse/core/util/types/mst';
25
+ import { isRetryException } from '@jbrowse/core/util/types';
24
26
  import RefreshIcon from '@material-ui/icons/Refresh';
25
27
  import { ConfigurationReference } from '@jbrowse/core/configuration/configurationSchema';
26
28
  import calculateDynamicBlocks from '@jbrowse/core/util/calculateDynamicBlocks';
@@ -36,15 +38,11 @@ import ZoomIn from '@material-ui/icons/ZoomIn';
36
38
  import clone from 'clone';
37
39
  import { saveAs } from 'file-saver';
38
40
  import { renderToStaticMarkup } from 'react-dom/server';
39
- import { InputAdornment, Tooltip as Tooltip$1, Popover, Typography as Typography$1, Dialog, DialogTitle, IconButton as IconButton$1, Divider, DialogContent, DialogContentText, TableContainer, Paper as Paper$1, Table, TableHead, TableRow, TableCell, TableBody, Button as Button$1, DialogActions, Container, Grid, CircularProgress as CircularProgress$1, makeStyles as makeStyles$1, TextField as TextField$1, FormControlLabel, Checkbox } from '@material-ui/core';
40
- import FormGroup from '@material-ui/core/FormGroup';
41
41
  import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
42
42
  import ArrowBackIcon from '@material-ui/icons/ArrowBack';
43
43
  import BaseResult, { RefSequenceResult } from '@jbrowse/core/TextSearch/BaseResults';
44
- import CircularProgress from '@material-ui/core/CircularProgress';
45
- import TextField from '@material-ui/core/TextField';
46
44
  import SearchIcon from '@material-ui/icons/Search';
47
- import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';
45
+ import Autocomplete from '@material-ui/lab/Autocomplete';
48
46
  import LinearProgress from '@material-ui/core/LinearProgress';
49
47
  import clsx from 'clsx';
50
48
  import ReactPropTypes from 'prop-types';
@@ -56,8 +54,9 @@ import MoreVertIcon from '@material-ui/icons/MoreVert';
56
54
  import DragIcon from '@material-ui/icons/DragIndicator';
57
55
  import CloseIcon from '@material-ui/icons/Close';
58
56
  import normalizeWheel from 'normalize-wheel';
59
- import { alpha as alpha$1 } from '@material-ui/core/styles/colorManipulator';
57
+ import { alpha as alpha$2 } from '@material-ui/core/styles/colorManipulator';
60
58
  import Popover$1 from '@material-ui/core/Popover';
59
+ import Tooltip$2 from '@material-ui/core/Tooltip';
61
60
  import AssemblySelector from '@jbrowse/core/ui/AssemblySelector';
62
61
  import ArrowDown from '@material-ui/icons/KeyboardArrowDown';
63
62
  import Menu$1 from '@jbrowse/core/ui/Menu';
@@ -283,6 +282,8 @@ function _assertThisInitialized(self) {
283
282
  function _possibleConstructorReturn(self, call) {
284
283
  if (call && (typeof call === "object" || typeof call === "function")) {
285
284
  return call;
285
+ } else if (call !== void 0) {
286
+ throw new TypeError("Derived constructors may only return object or undefined");
286
287
  }
287
288
 
288
289
  return _assertThisInitialized(self);
@@ -546,11 +547,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
546
547
 
547
548
 
548
549
  var IteratorPrototype = {};
549
-
550
- IteratorPrototype[iteratorSymbol] = function () {
550
+ define(IteratorPrototype, iteratorSymbol, function () {
551
551
  return this;
552
- };
553
-
552
+ });
554
553
  var getProto = Object.getPrototypeOf;
555
554
  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
556
555
 
@@ -561,8 +560,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
561
560
  }
562
561
 
563
562
  var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
564
- GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
565
- GeneratorFunctionPrototype.constructor = GeneratorFunction;
563
+ GeneratorFunction.prototype = GeneratorFunctionPrototype;
564
+ define(Gp, "constructor", GeneratorFunctionPrototype);
565
+ define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
566
566
  GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
567
567
  // Iterator interface in terms of a single ._invoke method.
568
568
 
@@ -667,11 +667,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
667
667
  }
668
668
 
669
669
  defineIteratorMethods(AsyncIterator.prototype);
670
-
671
- AsyncIterator.prototype[asyncIteratorSymbol] = function () {
670
+ define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
672
671
  return this;
673
- };
674
-
672
+ });
675
673
  exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
676
674
  // AsyncIterator objects; they just return a Promise for the value of
677
675
  // the final result produced by the iterator.
@@ -848,13 +846,12 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
848
846
  // object to not be returned from this call. This ensures that doesn't happen.
849
847
  // See https://github.com/facebook/regenerator/issues/274 for more details.
850
848
 
851
- Gp[iteratorSymbol] = function () {
849
+ define(Gp, iteratorSymbol, function () {
852
850
  return this;
853
- };
854
-
855
- Gp.toString = function () {
851
+ });
852
+ define(Gp, "toString", function () {
856
853
  return "[object Generator]";
857
- };
854
+ });
858
855
 
859
856
  function pushTryEntry(locs) {
860
857
  var entry = {
@@ -1166,14 +1163,19 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
1166
1163
  } catch (accidentalStrictMode) {
1167
1164
  // This module should not be running in strict mode, so the above
1168
1165
  // assignment should always work unless something is misconfigured. Just
1169
- // in case runtime.js accidentally runs in strict mode, we can escape
1166
+ // in case runtime.js accidentally runs in strict mode, in modern engines
1167
+ // we can explicitly access globalThis. In older engines we can escape
1170
1168
  // strict mode using a global Function call. This could conceivably fail
1171
1169
  // if a Content Security Policy forbids using Function, but in that case
1172
1170
  // the proper solution is to fix the accidental strict mode problem. If
1173
1171
  // you've misconfigured your bundler to force strict mode and applied a
1174
1172
  // CSP to forbid Function, and you're not willing to fix either of those
1175
1173
  // problems, please detail your unique predicament in a GitHub issue.
1176
- Function("r", "regeneratorRuntime = r")(runtime);
1174
+ if (typeof globalThis === "object") {
1175
+ globalThis.regeneratorRuntime = runtime;
1176
+ } else {
1177
+ Function("r", "regeneratorRuntime = r")(runtime);
1178
+ }
1177
1179
  }
1178
1180
  });
1179
1181
 
@@ -1327,49 +1329,125 @@ LinearBlocks.propTypes = {
1327
1329
  };
1328
1330
  var LinearBlocks$1 = /*#__PURE__*/observer(LinearBlocks);
1329
1331
 
1330
- var useStyles$2 = /*#__PURE__*/makeStyles({
1331
- display: {
1332
- position: 'relative',
1333
- whiteSpace: 'nowrap',
1334
- textAlign: 'left',
1335
- width: '100%',
1336
- minHeight: '100%'
1337
- }
1332
+ function round(value) {
1333
+ return Math.round(value * 1e5) / 1e5;
1334
+ }
1335
+
1336
+ var useStyles$2 = /*#__PURE__*/makeStyles$1(function (theme) {
1337
+ return {
1338
+ display: {
1339
+ position: 'relative',
1340
+ whiteSpace: 'nowrap',
1341
+ textAlign: 'left',
1342
+ width: '100%',
1343
+ minHeight: '100%'
1344
+ },
1345
+ // these styles come from
1346
+ // https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
1347
+ tooltip: {
1348
+ pointerEvents: 'none',
1349
+ backgroundColor: alpha(theme.palette.grey[700], 0.9),
1350
+ borderRadius: theme.shape.borderRadius,
1351
+ color: theme.palette.common.white,
1352
+ fontFamily: theme.typography.fontFamily,
1353
+ padding: '4px 8px',
1354
+ fontSize: theme.typography.pxToRem(10),
1355
+ lineHeight: "".concat(round(14 / 10), "em"),
1356
+ maxWidth: 300,
1357
+ wordWrap: 'break-word',
1358
+ fontWeight: theme.typography.fontWeightMedium
1359
+ }
1360
+ };
1338
1361
  });
1339
- var Tooltip = /*#__PURE__*/observer(function (props) {
1340
- var model = props.model,
1341
- mouseCoord = props.mouseCoord;
1362
+ var TooltipContents = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
1363
+ var message = _ref.message;
1364
+ return /*#__PURE__*/React.createElement("div", {
1365
+ ref: ref
1366
+ }, message);
1367
+ });
1368
+ var Tooltip = /*#__PURE__*/observer(function (_ref2) {
1369
+ var model = _ref2.model,
1370
+ clientMouseCoord = _ref2.clientMouseCoord;
1371
+ var classes = useStyles$2();
1342
1372
  var featureUnderMouse = model.featureUnderMouse;
1343
- var mouseover = featureUnderMouse ? getConf(model, 'mouseover', {
1373
+
1374
+ var _useState = useState(0),
1375
+ _useState2 = _slicedToArray(_useState, 2),
1376
+ width = _useState2[0],
1377
+ setWidth = _useState2[1];
1378
+
1379
+ var _useState3 = useState(null),
1380
+ _useState4 = _slicedToArray(_useState3, 2),
1381
+ popperElt = _useState4[0],
1382
+ setPopperElt = _useState4[1]; // must be memoized a la https://github.com/popperjs/react-popper/issues/391
1383
+
1384
+
1385
+ var virtElement = useMemo(function () {
1386
+ return {
1387
+ getBoundingClientRect: function getBoundingClientRect() {
1388
+ var x = clientMouseCoord[0] + width / 2 + 20;
1389
+ var y = clientMouseCoord[1];
1390
+ return {
1391
+ top: y,
1392
+ left: x,
1393
+ bottom: y,
1394
+ right: x,
1395
+ width: 0,
1396
+ height: 0,
1397
+ x: x,
1398
+ y: y,
1399
+ toJSON: function toJSON() {}
1400
+ };
1401
+ }
1402
+ };
1403
+ }, [clientMouseCoord, width]);
1404
+
1405
+ var _usePopper = usePopper(virtElement, popperElt),
1406
+ styles = _usePopper.styles,
1407
+ attributes = _usePopper.attributes;
1408
+
1409
+ var contents = featureUnderMouse ? getConf(model, 'mouseover', {
1344
1410
  feature: featureUnderMouse
1345
1411
  }) : undefined;
1346
- return mouseover ? /*#__PURE__*/React.createElement(MUITooltip, {
1347
- title: mouseover,
1348
- open: true,
1349
- placement: "right"
1350
- }, /*#__PURE__*/React.createElement("div", {
1351
- style: {
1352
- position: 'absolute',
1353
- left: mouseCoord[0],
1354
- top: mouseCoord[1]
1355
- }
1356
- }, ' ')) : null;
1412
+ return featureUnderMouse && contents ? /*#__PURE__*/React.createElement(Portal, null, /*#__PURE__*/React.createElement("div", Object.assign({
1413
+ ref: setPopperElt,
1414
+ className: classes.tooltip,
1415
+ // zIndex needed to go over widget drawer
1416
+ style: _objectSpread2(_objectSpread2({}, styles.popper), {}, {
1417
+ zIndex: 100000
1418
+ })
1419
+ }, attributes.popper), /*#__PURE__*/React.createElement(TooltipContents, {
1420
+ ref: function ref(elt) {
1421
+ return setWidth((elt === null || elt === void 0 ? void 0 : elt.getBoundingClientRect().width) || 0);
1422
+ },
1423
+ message: contents
1424
+ }))) : null;
1357
1425
  });
1358
1426
  var BaseLinearDisplay = /*#__PURE__*/observer(function (props) {
1359
1427
  var classes = useStyles$2();
1360
1428
  var theme = useTheme();
1429
+ var ref = useRef(null);
1361
1430
 
1362
- var _useState = useState([0, 0]),
1363
- _useState2 = _slicedToArray(_useState, 2),
1364
- mouseCoord = _useState2[0],
1365
- setMouseCoord = _useState2[1];
1431
+ var _useState5 = useState(),
1432
+ _useState6 = _slicedToArray(_useState5, 2),
1433
+ clientRect = _useState6[0],
1434
+ setClientRect = _useState6[1];
1366
1435
 
1367
- var _useState3 = useState(),
1368
- _useState4 = _slicedToArray(_useState3, 2),
1369
- contextCoord = _useState4[0],
1370
- setContextCoord = _useState4[1];
1436
+ var _useState7 = useState([0, 0]),
1437
+ _useState8 = _slicedToArray(_useState7, 2),
1438
+ offsetMouseCoord = _useState8[0],
1439
+ setOffsetMouseCoord = _useState8[1];
1440
+
1441
+ var _useState9 = useState([0, 0]),
1442
+ _useState10 = _slicedToArray(_useState9, 2),
1443
+ clientMouseCoord = _useState10[0],
1444
+ setClientMouseCoord = _useState10[1];
1445
+
1446
+ var _useState11 = useState(),
1447
+ _useState12 = _slicedToArray(_useState11, 2),
1448
+ contextCoord = _useState12[0],
1449
+ setContextCoord = _useState12[1];
1371
1450
 
1372
- var ref = useRef(null);
1373
1451
  var model = props.model,
1374
1452
  children = props.children;
1375
1453
  var TooltipComponent = model.TooltipComponent,
@@ -1394,7 +1472,9 @@ var BaseLinearDisplay = /*#__PURE__*/observer(function (props) {
1394
1472
  onMouseMove: function onMouseMove(event) {
1395
1473
  if (ref.current) {
1396
1474
  var rect = ref.current.getBoundingClientRect();
1397
- setMouseCoord([event.clientX - rect.left, event.clientY - rect.top]);
1475
+ setOffsetMouseCoord([event.clientX - rect.left, event.clientY - rect.top]);
1476
+ setClientMouseCoord([event.clientX, event.clientY]);
1477
+ setClientRect(rect);
1398
1478
  }
1399
1479
  },
1400
1480
  role: "presentation"
@@ -1403,7 +1483,10 @@ var BaseLinearDisplay = /*#__PURE__*/observer(function (props) {
1403
1483
  }) : /*#__PURE__*/React.createElement(LinearBlocks$1, Object.assign({}, props)), children, /*#__PURE__*/React.createElement(TooltipComponent, {
1404
1484
  model: model,
1405
1485
  height: height,
1406
- mouseCoord: mouseCoord
1486
+ offsetMouseCoord: offsetMouseCoord,
1487
+ clientMouseCoord: clientMouseCoord,
1488
+ clientRect: clientRect,
1489
+ mouseCoord: offsetMouseCoord
1407
1490
  }), /*#__PURE__*/React.createElement(Menu, {
1408
1491
  open: Boolean(contextCoord) && Boolean(contextMenuItems().length),
1409
1492
  onMenuItemClick: function onMenuItemClick(_, callback) {
@@ -1699,6 +1782,10 @@ var blockState = /*#__PURE__*/types.model('BlockState', {
1699
1782
  self.error = error;
1700
1783
  self.renderProps = undefined;
1701
1784
  renderInProgress = undefined;
1785
+
1786
+ if (isRetryException(error)) {
1787
+ this.reload();
1788
+ }
1702
1789
  },
1703
1790
  reload: function reload() {
1704
1791
  self.renderInProgress = undefined;
@@ -1936,8 +2023,9 @@ var BaseLinearDisplay$1 = /*#__PURE__*/types.compose('BaseLinearDisplay', BaseDi
1936
2023
  */
1937
2024
  get selectedFeatureId() {
1938
2025
  if (isAlive(self)) {
1939
- var session = getSession(self);
1940
- var selection = session.selection; // does it quack like a feature?
2026
+ var _getSession = getSession(self),
2027
+ selection = _getSession.selection; // does it quack like a feature?
2028
+
1941
2029
 
1942
2030
  if (isFeature(selection)) {
1943
2031
  return selection.id();
@@ -1994,7 +2082,13 @@ var BaseLinearDisplay$1 = /*#__PURE__*/types.compose('BaseLinearDisplay', BaseDi
1994
2082
 
1995
2083
  return (_self$blockState$get = self.blockState.get(blockKey)) === null || _self$blockState$get === void 0 ? void 0 : (_self$blockState$get$ = _self$blockState$get.layout) === null || _self$blockState$get$ === void 0 ? void 0 : _self$blockState$get$.getByCoord(x, y);
1996
2084
  },
1997
- getFeatureByID: function getFeatureByID(id) {
2085
+ getFeatureByID: function getFeatureByID(blockKey, id) {
2086
+ var _self$blockState$get2, _self$blockState$get3;
2087
+
2088
+ return (_self$blockState$get2 = self.blockState.get(blockKey)) === null || _self$blockState$get2 === void 0 ? void 0 : (_self$blockState$get3 = _self$blockState$get2.layout) === null || _self$blockState$get3 === void 0 ? void 0 : _self$blockState$get3.getByID(id);
2089
+ },
2090
+ // if block key is not supplied, can look at all blocks
2091
+ searchFeatureByID: function searchFeatureByID(id) {
1998
2092
  var ret;
1999
2093
  self.blockState.forEach(function (block) {
2000
2094
  var _block$layout;
@@ -2324,51 +2418,36 @@ function stateModelFactory(configSchema) {
2324
2418
  });
2325
2419
  }
2326
2420
 
2327
- var filter = /*#__PURE__*/createFilterOptions({
2328
- trim: true,
2329
- ignoreCase: true,
2330
- limit: 100
2331
- });
2332
-
2333
2421
  function fetchResults(_x, _x2, _x3) {
2334
2422
  return _fetchResults.apply(this, arguments);
2335
- }
2423
+ } // the logic of this method is to only apply a filter to RefSequenceResults
2424
+ // because they do not have a matchedObject. the trix search results already
2425
+ // filter so don't need re-filtering
2426
+
2336
2427
 
2337
2428
  function _fetchResults() {
2338
2429
  _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(self, query, assemblyName) {
2339
- var session, _getEnv, pluginManager, rankSearchResults, textSearchManager, searchScope, args, searchResults;
2430
+ var _getSession, textSearchManager, rankSearchResults, searchScope;
2340
2431
 
2341
2432
  return runtime_1.wrap(function _callee2$(_context2) {
2342
2433
  while (1) {
2343
2434
  switch (_context2.prev = _context2.next) {
2344
2435
  case 0:
2345
- session = getSession(self);
2346
- _getEnv = getEnv(session), pluginManager = _getEnv.pluginManager;
2436
+ _getSession = getSession(self), textSearchManager = _getSession.textSearchManager;
2347
2437
  rankSearchResults = self.rankSearchResults;
2348
- textSearchManager = pluginManager.rootModel.textSearchManager;
2349
2438
  searchScope = self.searchScope(assemblyName);
2350
- args = {
2439
+ return _context2.abrupt("return", textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
2351
2440
  queryString: query,
2352
2441
  searchType: 'prefix'
2353
- };
2354
- _context2.next = 8;
2355
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search(args, searchScope, rankSearchResults);
2356
-
2357
- case 8:
2358
- _context2.t0 = _context2.sent;
2359
-
2360
- if (_context2.t0) {
2361
- _context2.next = 11;
2362
- break;
2363
- }
2364
-
2365
- _context2.t0 = [];
2366
-
2367
- case 11:
2368
- searchResults = _context2.t0;
2369
- return _context2.abrupt("return", searchResults);
2442
+ }, searchScope, rankSearchResults).then(function (results) {
2443
+ return results.filter(function (elem, index, self) {
2444
+ return index === self.findIndex(function (t) {
2445
+ return t.label === elem.label;
2446
+ });
2447
+ });
2448
+ }));
2370
2449
 
2371
- case 13:
2450
+ case 4:
2372
2451
  case "end":
2373
2452
  return _context2.stop();
2374
2453
  }
@@ -2378,6 +2457,27 @@ function _fetchResults() {
2378
2457
  return _fetchResults.apply(this, arguments);
2379
2458
  }
2380
2459
 
2460
+ function _filterOptions(options, searchQuery) {
2461
+ return options.filter(function (option) {
2462
+ var result = option.result;
2463
+ return result.getLabel().toLowerCase().includes(searchQuery) || result.matchedObject;
2464
+ });
2465
+ } // MyPopper used to expand search results box wider if needed
2466
+ // xref https://stackoverflow.com/a/63583835/2129219
2467
+
2468
+
2469
+ var MyPopper = function MyPopper(props) {
2470
+ var style = props.style;
2471
+ return /*#__PURE__*/React.createElement(Popper, Object.assign({}, props, {
2472
+ style: {
2473
+ width: 'fit-content',
2474
+ minWidth: Math.min(+((style === null || style === void 0 ? void 0 : style.width) || 0), 200),
2475
+ background: 'white'
2476
+ },
2477
+ placement: "bottom-start"
2478
+ }));
2479
+ };
2480
+
2381
2481
  function RefNameAutocomplete(_ref) {
2382
2482
  var model = _ref.model,
2383
2483
  onSelect = _ref.onSelect,
@@ -2387,36 +2487,41 @@ function RefNameAutocomplete(_ref) {
2387
2487
  _ref$TextFieldProps = _ref.TextFieldProps,
2388
2488
  TextFieldProps = _ref$TextFieldProps === void 0 ? {} : _ref$TextFieldProps;
2389
2489
  var session = getSession(model);
2490
+ var assemblyManager = session.assemblyManager;
2390
2491
 
2391
2492
  var _useState = useState(false),
2392
2493
  _useState2 = _slicedToArray(_useState, 2),
2393
2494
  open = _useState2[0],
2394
2495
  setOpen = _useState2[1];
2395
2496
 
2396
- var _useState3 = useState(),
2497
+ var _useState3 = useState(true),
2397
2498
  _useState4 = _slicedToArray(_useState3, 2),
2398
- error = _useState4[0],
2399
- setError = _useState4[1];
2499
+ loaded = _useState4[0],
2500
+ setLoaded = _useState4[1];
2400
2501
 
2401
2502
  var _useState5 = useState(''),
2402
2503
  _useState6 = _slicedToArray(_useState5, 2),
2403
2504
  currentSearch = _useState6[0],
2404
2505
  setCurrentSearch = _useState6[1];
2405
2506
 
2406
- var debouncedSearch = useDebounce(currentSearch, 300);
2407
-
2408
- var _useState7 = useState([]),
2507
+ var _useState7 = useState(''),
2409
2508
  _useState8 = _slicedToArray(_useState7, 2),
2410
- searchOptions = _useState8[0],
2411
- setSearchOptions = _useState8[1];
2509
+ inputValue = _useState8[0],
2510
+ setInputValue = _useState8[1];
2412
2511
 
2413
- var assemblyManager = session.assemblyManager;
2414
- var coarseVisibleLocStrings = model.coarseVisibleLocStrings;
2512
+ var _useState9 = useState([]),
2513
+ _useState10 = _slicedToArray(_useState9, 2),
2514
+ searchOptions = _useState10[0],
2515
+ setSearchOptions = _useState10[1];
2516
+
2517
+ var debouncedSearch = useDebounce(currentSearch, 300);
2518
+ var coarseVisibleLocStrings = model.coarseVisibleLocStrings,
2519
+ hasDisplayedRegions = model.hasDisplayedRegions;
2415
2520
  var assembly = assemblyName ? assemblyManager.get(assemblyName) : undefined; // eslint-disable-next-line react-hooks/exhaustive-deps
2416
2521
 
2417
2522
  var regions = (assembly === null || assembly === void 0 ? void 0 : assembly.regions) || [];
2418
2523
  var options = useMemo(function () {
2419
- var defaultOptions = regions.map(function (option) {
2524
+ return regions.map(function (option) {
2420
2525
  return {
2421
2526
  result: new RefSequenceResult({
2422
2527
  refName: option.refName,
@@ -2425,40 +2530,43 @@ function RefNameAutocomplete(_ref) {
2425
2530
  })
2426
2531
  };
2427
2532
  });
2428
- return defaultOptions;
2429
2533
  }, [regions]);
2430
2534
  useEffect(function () {
2431
2535
  var active = true;
2432
2536
 
2433
2537
  _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
2434
- var results, searchResults, adapterResults;
2538
+ var results;
2435
2539
  return runtime_1.wrap(function _callee$(_context) {
2436
2540
  while (1) {
2437
2541
  switch (_context.prev = _context.next) {
2438
2542
  case 0:
2439
2543
  _context.prev = 0;
2440
- results = [];
2441
2544
 
2442
- if (!(debouncedSearch && debouncedSearch !== '' && assemblyName)) {
2443
- _context.next = 7;
2545
+ if (!(debouncedSearch === '' || !assemblyName)) {
2546
+ _context.next = 3;
2444
2547
  break;
2445
2548
  }
2446
2549
 
2447
- _context.next = 5;
2550
+ return _context.abrupt("return");
2551
+
2552
+ case 3:
2553
+ setLoaded(false);
2554
+ _context.next = 6;
2448
2555
  return fetchResults(model, debouncedSearch, assemblyName);
2449
2556
 
2450
- case 5:
2451
- searchResults = _context.sent;
2452
- results = results.concat(searchResults);
2557
+ case 6:
2558
+ results = _context.sent;
2453
2559
 
2454
- case 7:
2455
- if (results.length > 0 && active) {
2456
- adapterResults = results.map(function (result) {
2457
- return {
2458
- result: result
2459
- };
2460
- });
2461
- setSearchOptions(adapterResults);
2560
+ if (active) {
2561
+ if (results && results.length >= 0) {
2562
+ setSearchOptions(results.map(function (result) {
2563
+ return {
2564
+ result: result
2565
+ };
2566
+ }));
2567
+ }
2568
+
2569
+ setLoaded(true);
2462
2570
  }
2463
2571
 
2464
2572
  _context.next = 14;
@@ -2470,7 +2578,7 @@ function RefNameAutocomplete(_ref) {
2470
2578
  console.error(_context.t0);
2471
2579
 
2472
2580
  if (active) {
2473
- setError(_context.t0);
2581
+ session.notify("".concat(_context.t0), 'error');
2474
2582
  }
2475
2583
 
2476
2584
  case 14:
@@ -2484,87 +2592,98 @@ function RefNameAutocomplete(_ref) {
2484
2592
  return function () {
2485
2593
  active = false;
2486
2594
  };
2487
- }, [assemblyName, debouncedSearch, model]);
2595
+ }, [assemblyName, debouncedSearch, session, model]);
2596
+ var inputBoxVal = coarseVisibleLocStrings || value || ''; // heuristic, text width + icon width, minimum 200
2488
2597
 
2489
- function _onChange(selectedOption) {
2490
- if (selectedOption && assemblyName) {
2491
- if (typeof selectedOption === 'string') {
2492
- // handles string inputs on keyPress enter
2493
- var newResult = new BaseResult({
2494
- label: selectedOption
2495
- });
2496
- onSelect(newResult);
2497
- } else {
2498
- var result = selectedOption.result;
2499
- onSelect(result);
2500
- }
2501
- }
2502
- }
2598
+ var width = Math.min(Math.max(measureText(inputBoxVal, 16) + 25, 200), 550); // notes on implementation:
2599
+ // The selectOnFocus setting helps highlight the field when clicked
2503
2600
 
2504
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Autocomplete, {
2601
+ return /*#__PURE__*/React.createElement(Autocomplete, {
2505
2602
  id: "refNameAutocomplete-".concat(model.id),
2506
2603
  "data-testid": "autocomplete",
2507
- freeSolo: true,
2508
2604
  disableListWrap: true,
2509
2605
  disableClearable: true,
2606
+ PopperComponent: MyPopper,
2607
+ disabled: !assemblyName,
2608
+ freeSolo: true,
2510
2609
  includeInputInList: true,
2511
- clearOnBlur: true,
2512
2610
  selectOnFocus: true,
2513
- disabled: !!error || !assemblyName,
2514
- style: style,
2515
- value: coarseVisibleLocStrings || value || '',
2611
+ style: _objectSpread2(_objectSpread2({}, style), {}, {
2612
+ width: width
2613
+ }),
2614
+ value: inputBoxVal,
2615
+ loading: !loaded,
2616
+ inputValue: inputValue,
2617
+ onInputChange: function onInputChange(event, newInputValue) {
2618
+ return setInputValue(newInputValue);
2619
+ },
2620
+ loadingText: "loading results",
2516
2621
  open: open,
2517
2622
  onOpen: function onOpen() {
2518
2623
  return setOpen(true);
2519
2624
  },
2520
2625
  onClose: function onClose() {
2521
2626
  setOpen(false);
2522
- setCurrentSearch('');
2523
- setSearchOptions([]);
2627
+ setLoaded(true);
2628
+
2629
+ if (hasDisplayedRegions) {
2630
+ setCurrentSearch('');
2631
+ setSearchOptions([]);
2632
+ }
2633
+ },
2634
+ onChange: function onChange(_event, selectedOption) {
2635
+ if (!selectedOption || !assemblyName) {
2636
+ return;
2637
+ }
2638
+
2639
+ if (typeof selectedOption === 'string') {
2640
+ // handles string inputs on keyPress enter
2641
+ onSelect(new BaseResult({
2642
+ label: selectedOption
2643
+ }));
2644
+ } else {
2645
+ onSelect(selectedOption.result);
2646
+ }
2647
+
2648
+ setInputValue(inputBoxVal);
2524
2649
  },
2525
2650
  options: searchOptions.length === 0 ? options : searchOptions,
2526
2651
  getOptionDisabled: function getOptionDisabled(option) {
2527
2652
  return (option === null || option === void 0 ? void 0 : option.group) === 'limitOption';
2528
2653
  },
2529
- filterOptions: function filterOptions(possibleOptions, params) {
2530
- var filtered = filter(possibleOptions, params);
2531
- return filtered.length >= 100 ? filtered.concat([{
2654
+ filterOptions: function filterOptions(options, params) {
2655
+ var filtered = _filterOptions(options, params.inputValue.toLocaleLowerCase());
2656
+
2657
+ return [].concat(_toConsumableArray(filtered.slice(0, 100)), _toConsumableArray(filtered.length > 100 ? [{
2532
2658
  group: 'limitOption',
2533
2659
  result: new BaseResult({
2534
- label: 'keep typing for more results',
2535
- renderingComponent: /*#__PURE__*/React.createElement(Typography, null, 'keep typing for more results')
2660
+ label: 'keep typing for more results'
2536
2661
  })
2537
- }]) : filtered;
2538
- },
2539
- ListboxProps: {
2540
- style: {
2541
- maxHeight: 250
2542
- }
2543
- },
2544
- onChange: function onChange(_, selectedOption) {
2545
- return _onChange(selectedOption);
2662
+ }] : []));
2546
2663
  },
2547
2664
  renderInput: function renderInput(params) {
2548
2665
  var helperText = TextFieldProps.helperText,
2549
2666
  _TextFieldProps$Input = TextFieldProps.InputProps,
2550
2667
  InputProps = _TextFieldProps$Input === void 0 ? {} : _TextFieldProps$Input;
2551
-
2552
- var TextFieldInputProps = _objectSpread2(_objectSpread2(_objectSpread2({}, params.InputProps), InputProps), {}, {
2553
- endAdornment: /*#__PURE__*/React.createElement(React.Fragment, null, regions.length === 0 && searchOptions.length === 0 ? /*#__PURE__*/React.createElement(CircularProgress, {
2554
- color: "inherit",
2555
- size: 20
2556
- }) : /*#__PURE__*/React.createElement(InputAdornment, {
2557
- position: "end",
2558
- style: {
2559
- marginRight: 7
2560
- }
2561
- }, /*#__PURE__*/React.createElement(SearchIcon, null)), params.InputProps.endAdornment)
2562
- });
2563
-
2564
- return /*#__PURE__*/React.createElement(TextField, Object.assign({}, params, TextFieldProps, {
2668
+ return /*#__PURE__*/React.createElement(TextField, Object.assign({
2669
+ onBlur: function onBlur() {
2670
+ // this is used to restore a refName or the non-user-typed input
2671
+ // to the box on blurring
2672
+ setInputValue(inputBoxVal);
2673
+ }
2674
+ }, params, TextFieldProps, {
2565
2675
  helperText: helperText,
2566
- value: coarseVisibleLocStrings || value || '',
2567
- InputProps: TextFieldInputProps,
2676
+ InputProps: _objectSpread2(_objectSpread2(_objectSpread2({}, params.InputProps), InputProps), {}, {
2677
+ endAdornment: /*#__PURE__*/React.createElement(React.Fragment, null, regions.length === 0 ? /*#__PURE__*/React.createElement(CircularProgress, {
2678
+ color: "inherit",
2679
+ size: 20
2680
+ }) : /*#__PURE__*/React.createElement(InputAdornment, {
2681
+ position: "end",
2682
+ style: {
2683
+ marginRight: 7
2684
+ }
2685
+ }, /*#__PURE__*/React.createElement(SearchIcon, null)), params.InputProps.endAdornment)
2686
+ }),
2568
2687
  placeholder: "Search for location",
2569
2688
  onChange: function onChange(e) {
2570
2689
  setCurrentSearch(e.target.value);
@@ -2573,28 +2692,20 @@ function RefNameAutocomplete(_ref) {
2573
2692
  },
2574
2693
  renderOption: function renderOption(option) {
2575
2694
  var result = option.result;
2576
- var rendering = result.getLabel(); // if renderingComponent is provided render that
2577
-
2578
2695
  var component = result.getRenderingComponent();
2579
2696
 
2580
- if (component) {
2581
- if ( /*#__PURE__*/React.isValidElement(component)) {
2582
- return component;
2583
- }
2697
+ if (component && /*#__PURE__*/React.isValidElement(component)) {
2698
+ return component;
2584
2699
  }
2585
2700
 
2586
- return /*#__PURE__*/React.createElement(Typography, {
2701
+ return /*#__PURE__*/React.createElement(Typography$1, {
2587
2702
  noWrap: true
2588
- }, rendering);
2703
+ }, result.getDisplayString());
2589
2704
  },
2590
2705
  getOptionLabel: function getOptionLabel(option) {
2591
- // needed for filtering options and value
2592
2706
  return (typeof option === 'string' ? option : option.result.getLabel()) || '';
2593
2707
  }
2594
- }), error ? /*#__PURE__*/React.createElement(Typography, {
2595
- variant: "h6",
2596
- color: "error"
2597
- }, "".concat(error)) : null);
2708
+ });
2598
2709
  }
2599
2710
 
2600
2711
  var RefNameAutocomplete$1 = /*#__PURE__*/observer(RefNameAutocomplete);
@@ -2684,7 +2795,7 @@ function makeTicks(start, end, bpPerPx) {
2684
2795
  }
2685
2796
 
2686
2797
  var useStyles$4 = /*#__PURE__*/makeStyles(function (theme) {
2687
- var background = theme.palette.tertiary ? alpha(theme.palette.tertiary.main, 0.7) : alpha(theme.palette.primary.main, 0.7);
2798
+ var background = theme.palette.tertiary ? alpha$1(theme.palette.tertiary.main, 0.7) : alpha$1(theme.palette.primary.main, 0.7);
2688
2799
  return {
2689
2800
  rubberBand: {
2690
2801
  height: '100%',
@@ -2990,7 +3101,7 @@ var useStyles$5 = /*#__PURE__*/makeStyles(function (theme) {
2990
3101
  pointerEvents: 'none'
2991
3102
  },
2992
3103
  scaleBarVisibleRegion: {
2993
- background: alpha(scaleBarColor, 0.3),
3104
+ background: alpha$1(scaleBarColor, 0.3),
2994
3105
  position: 'absolute',
2995
3106
  height: HEADER_OVERVIEW_HEIGHT,
2996
3107
  pointerEvents: 'none',
@@ -2998,7 +3109,7 @@ var useStyles$5 = /*#__PURE__*/makeStyles(function (theme) {
2998
3109
  zIndex: 100,
2999
3110
  borderWidth: 1,
3000
3111
  borderStyle: 'solid',
3001
- borderColor: alpha(scaleBarColor, 0.8),
3112
+ borderColor: alpha$1(scaleBarColor, 0.8),
3002
3113
  boxSizing: 'content-box'
3003
3114
  },
3004
3115
  overview: {
@@ -3014,7 +3125,7 @@ var wholeSeqSpacer = 2;
3014
3125
  var Polygon = /*#__PURE__*/observer(function (_ref) {
3015
3126
  var model = _ref.model,
3016
3127
  overview = _ref.overview;
3017
- var theme = useTheme();
3128
+ var theme = useTheme$1();
3018
3129
  var classes = useStyles$5();
3019
3130
  var offsetPx = model.offsetPx,
3020
3131
  _model$dynamicBlocks = model.dynamicBlocks,
@@ -3047,8 +3158,8 @@ var Polygon = /*#__PURE__*/observer(function (_ref) {
3047
3158
  className: classes.overviewSvg
3048
3159
  }, points && /*#__PURE__*/React.createElement("polygon", {
3049
3160
  points: points.toString(),
3050
- fill: alpha(polygonColor, 0.3),
3051
- stroke: alpha(polygonColor, 0.8)
3161
+ fill: alpha$1(polygonColor, 0.3),
3162
+ stroke: alpha$1(polygonColor, 0.8)
3052
3163
  }));
3053
3164
  });
3054
3165
  var ScaleBar = /*#__PURE__*/observer(function (_ref2) {
@@ -3123,7 +3234,8 @@ var ScaleBar = /*#__PURE__*/observer(function (_ref2) {
3123
3234
  }
3124
3235
  }, /*#__PURE__*/React.createElement(Typography$1, {
3125
3236
  style: {
3126
- color: refNameColor
3237
+ color: refNameColor,
3238
+ zIndex: 100
3127
3239
  },
3128
3240
  className: classes.scaleBarRefName
3129
3241
  }, seq.refName), tickLabels.map(function (tickLabel, labelIdx) {
@@ -3241,9 +3353,17 @@ function ZoomControls(_ref) {
3241
3353
 
3242
3354
  var ZoomControls$1 = /*#__PURE__*/observer(ZoomControls);
3243
3355
 
3356
+ function dedupe(results) {
3357
+ return results === null || results === void 0 ? void 0 : results.filter(function (elem, index, self) {
3358
+ return index === self.findIndex(function (t) {
3359
+ return t.getId() === elem.getId();
3360
+ });
3361
+ });
3362
+ }
3363
+
3244
3364
  var WIDGET_HEIGHT = 32;
3245
3365
  var SPACING = 7;
3246
- var useStyles$7 = /*#__PURE__*/makeStyles(function (theme) {
3366
+ var useStyles$7 = /*#__PURE__*/makeStyles$1(function (theme) {
3247
3367
  return {
3248
3368
  headerBar: {
3249
3369
  height: HEADER_BAR_HEIGHT,
@@ -3283,7 +3403,7 @@ var useStyles$7 = /*#__PURE__*/makeStyles(function (theme) {
3283
3403
  var Controls = /*#__PURE__*/observer(function (_ref) {
3284
3404
  var model = _ref.model;
3285
3405
  var classes = useStyles$7();
3286
- return /*#__PURE__*/React.createElement(Button, {
3406
+ return /*#__PURE__*/React.createElement(Button$1, {
3287
3407
  onClick: model.activateTrackSelector,
3288
3408
  className: classes.toggleButton,
3289
3409
  title: "Open track selector",
@@ -3297,13 +3417,13 @@ var Controls = /*#__PURE__*/observer(function (_ref) {
3297
3417
  function PanControls(_ref2) {
3298
3418
  var model = _ref2.model;
3299
3419
  var classes = useStyles$7();
3300
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
3420
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button$1, {
3301
3421
  variant: "outlined",
3302
3422
  className: classes.panButton,
3303
3423
  onClick: function onClick() {
3304
3424
  return model.slide(-0.9);
3305
3425
  }
3306
- }, /*#__PURE__*/React.createElement(ArrowBackIcon, null)), /*#__PURE__*/React.createElement(Button, {
3426
+ }, /*#__PURE__*/React.createElement(ArrowBackIcon, null)), /*#__PURE__*/React.createElement(Button$1, {
3307
3427
  variant: "outlined",
3308
3428
  className: classes.panButton,
3309
3429
  onClick: function onClick() {
@@ -3316,7 +3436,7 @@ var RegionWidth = /*#__PURE__*/observer(function (_ref3) {
3316
3436
  var model = _ref3.model;
3317
3437
  var classes = useStyles$7();
3318
3438
  var coarseTotalBp = model.coarseTotalBp;
3319
- return /*#__PURE__*/React.createElement(Typography, {
3439
+ return /*#__PURE__*/React.createElement(Typography$1, {
3320
3440
  variant: "body2",
3321
3441
  color: "textSecondary",
3322
3442
  className: classes.bp
@@ -3327,104 +3447,121 @@ var LinearGenomeViewHeader = /*#__PURE__*/observer(function (_ref4) {
3327
3447
  var classes = useStyles$7();
3328
3448
  var theme = useTheme();
3329
3449
  var session = getSession(model);
3330
- var assemblyManager = session.assemblyManager;
3331
-
3332
- var _getEnv = getEnv(session),
3333
- pluginManager = _getEnv.pluginManager;
3334
-
3335
- var textSearchManager = pluginManager.rootModel.textSearchManager;
3336
- var contentBlocks = model.coarseDynamicBlocks,
3337
- displayedRegions = model.displayedRegions,
3450
+ var textSearchManager = session.textSearchManager,
3451
+ assemblyManager = session.assemblyManager;
3452
+ var assemblyNames = model.assemblyNames,
3338
3453
  rankSearchResults = model.rankSearchResults;
3339
-
3340
- var _ref5 = contentBlocks[0] || {
3341
- refName: ''
3342
- },
3343
- assemblyName = _ref5.assemblyName,
3344
- refName = _ref5.refName;
3345
-
3346
- var assembly = assemblyName && assemblyManager.get(assemblyName);
3347
- var regions = assembly && assembly.regions || [];
3454
+ var assemblyName = assemblyNames[0];
3455
+ var assembly = assemblyManager.get(assemblyName);
3348
3456
  var searchScope = model.searchScope(assemblyName);
3349
3457
 
3350
- function setDisplayedRegion(_x) {
3351
- return _setDisplayedRegion.apply(this, arguments);
3458
+ function fetchResults(_x) {
3459
+ return _fetchResults.apply(this, arguments);
3352
3460
  }
3353
3461
 
3354
- function _setDisplayedRegion() {
3355
- _setDisplayedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(result) {
3356
- var newRegionValue, newRegion, results;
3462
+ function _fetchResults() {
3463
+ _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(queryString) {
3464
+ var results;
3357
3465
  return runtime_1.wrap(function _callee$(_context) {
3358
3466
  while (1) {
3359
3467
  switch (_context.prev = _context.next) {
3360
3468
  case 0:
3361
- if (!result) {
3362
- _context.next = 15;
3363
- break;
3469
+ if (!textSearchManager) {
3470
+ console.warn('No text search manager');
3364
3471
  }
3365
3472
 
3366
- newRegionValue = result.getLocation(); // need to fix finding region
3473
+ _context.next = 3;
3474
+ return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
3475
+ queryString: queryString.toLowerCase(),
3476
+ searchType: 'exact'
3477
+ }, searchScope, rankSearchResults);
3367
3478
 
3368
- newRegion = regions.find(function (region) {
3369
- return newRegionValue === region.refName;
3370
- });
3479
+ case 3:
3480
+ results = _context.sent;
3481
+ return _context.abrupt("return", dedupe(results));
3371
3482
 
3372
- if (!newRegion) {
3373
- _context.next = 8;
3483
+ case 5:
3484
+ case "end":
3485
+ return _context.stop();
3486
+ }
3487
+ }
3488
+ }, _callee);
3489
+ }));
3490
+ return _fetchResults.apply(this, arguments);
3491
+ }
3492
+
3493
+ function handleSelectedRegion(_x2) {
3494
+ return _handleSelectedRegion.apply(this, arguments);
3495
+ }
3496
+
3497
+ function _handleSelectedRegion() {
3498
+ _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(option) {
3499
+ var trackId, location, label, _assembly$refNames, results;
3500
+
3501
+ return runtime_1.wrap(function _callee2$(_context2) {
3502
+ while (1) {
3503
+ switch (_context2.prev = _context2.next) {
3504
+ case 0:
3505
+ trackId = option.getTrackId();
3506
+ location = option.getLocation();
3507
+ label = option.getLabel();
3508
+ _context2.prev = 3;
3509
+
3510
+ if (!(assembly !== null && assembly !== void 0 && (_assembly$refNames = assembly.refNames) !== null && _assembly$refNames !== void 0 && _assembly$refNames.includes(location))) {
3511
+ _context2.next = 8;
3374
3512
  break;
3375
3513
  }
3376
3514
 
3377
- model.setDisplayedRegions([newRegion]); // we use showAllRegions after setDisplayedRegions to make the entire
3378
- // region visible, xref #1703
3379
-
3380
- model.showAllRegions();
3381
- _context.next = 15;
3515
+ model.navToLocString(location);
3516
+ _context2.next = 19;
3382
3517
  break;
3383
3518
 
3384
3519
  case 8:
3385
- _context.next = 10;
3386
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
3387
- queryString: newRegionValue.toLocaleLowerCase(),
3388
- searchType: 'exact'
3389
- }, searchScope, rankSearchResults);
3520
+ _context2.next = 10;
3521
+ return fetchResults(label);
3390
3522
 
3391
3523
  case 10:
3392
- _context.t0 = _context.sent;
3524
+ results = _context2.sent;
3393
3525
 
3394
- if (_context.t0) {
3395
- _context.next = 13;
3526
+ if (!(results && results.length > 1)) {
3527
+ _context2.next = 16;
3396
3528
  break;
3397
3529
  }
3398
3530
 
3399
- _context.t0 = [];
3400
-
3401
- case 13:
3402
- results = _context.t0;
3403
-
3404
- // distinguishes between locstrings and search strings
3405
- if (results.length > 0) {
3406
- model.setSearchResults(results, newRegionValue.toLocaleLowerCase());
3407
- } else {
3408
- try {
3409
- newRegionValue !== '' && model.navToLocString(newRegionValue);
3410
- } catch (e) {
3411
- if ("".concat(e) === "Error: Unknown reference sequence \"".concat(newRegionValue, "\"")) {
3412
- model.setSearchResults(results, newRegionValue.toLocaleLowerCase());
3413
- } else {
3414
- console.warn(e);
3415
- session.notify("".concat(e), 'warning');
3416
- }
3417
- }
3531
+ model.setSearchResults(results, label.toLowerCase());
3532
+ return _context2.abrupt("return");
3533
+
3534
+ case 16:
3535
+ if ((results === null || results === void 0 ? void 0 : results.length) === 1) {
3536
+ location = results[0].getLocation();
3537
+ trackId = results[0].getTrackId();
3418
3538
  }
3419
3539
 
3420
- case 15:
3540
+ case 17:
3541
+ model.navToLocString(location, assemblyName);
3542
+
3543
+ if (trackId) {
3544
+ model.showTrack(trackId);
3545
+ }
3546
+
3547
+ case 19:
3548
+ _context2.next = 25;
3549
+ break;
3550
+
3551
+ case 21:
3552
+ _context2.prev = 21;
3553
+ _context2.t0 = _context2["catch"](3);
3554
+ console.error(_context2.t0);
3555
+ session.notify("".concat(_context2.t0), 'warning');
3556
+
3557
+ case 25:
3421
3558
  case "end":
3422
- return _context.stop();
3559
+ return _context2.stop();
3423
3560
  }
3424
3561
  }
3425
- }, _callee);
3562
+ }, _callee2, null, [[3, 21]]);
3426
3563
  }));
3427
- return _setDisplayedRegion.apply(this, arguments);
3564
+ return _handleSelectedRegion.apply(this, arguments);
3428
3565
  }
3429
3566
 
3430
3567
  var controls = /*#__PURE__*/React.createElement("div", {
@@ -3439,9 +3576,8 @@ var LinearGenomeViewHeader = /*#__PURE__*/observer(function (_ref4) {
3439
3576
  }, /*#__PURE__*/React.createElement(PanControls, {
3440
3577
  model: model
3441
3578
  }), /*#__PURE__*/React.createElement(RefNameAutocomplete$1, {
3442
- onSelect: setDisplayedRegion,
3579
+ onSelect: handleSelectedRegion,
3443
3580
  assemblyName: assemblyName,
3444
- value: displayedRegions.length > 1 ? '' : refName,
3445
3581
  model: model,
3446
3582
  TextFieldProps: {
3447
3583
  variant: 'outlined',
@@ -3478,7 +3614,7 @@ var LinearGenomeViewHeader = /*#__PURE__*/observer(function (_ref4) {
3478
3614
  var useStyles$8 = /*#__PURE__*/makeStyles(function (theme) {
3479
3615
  return {
3480
3616
  root: {
3481
- background: alpha(theme.palette.background.paper, 0.8),
3617
+ background: alpha$1(theme.palette.background.paper, 0.8),
3482
3618
  '&:hover': {
3483
3619
  background: theme.palette.background.paper
3484
3620
  },
@@ -3735,7 +3871,7 @@ function TrackContainer(props) {
3735
3871
  var TrackContainer$1 = /*#__PURE__*/observer(TrackContainer);
3736
3872
 
3737
3873
  var useStyles$a = /*#__PURE__*/makeStyles(function (theme) {
3738
- var background = theme.palette.tertiary ? alpha$1(theme.palette.tertiary.main, 0.7) : alpha$1(theme.palette.primary.main, 0.7);
3874
+ var background = theme.palette.tertiary ? alpha$2(theme.palette.tertiary.main, 0.7) : alpha$2(theme.palette.primary.main, 0.7);
3739
3875
  return {
3740
3876
  rubberBand: {
3741
3877
  height: '100%',
@@ -3774,7 +3910,7 @@ var VerticalGuide = /*#__PURE__*/observer(function (_ref) {
3774
3910
  var model = _ref.model,
3775
3911
  coordX = _ref.coordX;
3776
3912
  var classes = useStyles$a();
3777
- return /*#__PURE__*/React.createElement(MUITooltip, {
3913
+ return /*#__PURE__*/React.createElement(Tooltip$2, {
3778
3914
  open: true,
3779
3915
  placement: "top",
3780
3916
  title: stringify(model.pxToBp(coordX)),
@@ -4565,19 +4701,6 @@ function SearchResultsDialog(_ref) {
4565
4701
  }
4566
4702
  }
4567
4703
 
4568
- function handleShowTrack(trackId) {
4569
- var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
4570
- var configuration = resolveIdentifier(trackConfigSchema, getRoot(model), trackId); // check if we have any tracks with that configuration
4571
-
4572
- var shownTracks = model.tracks.filter(function (t) {
4573
- return t.configuration === configuration;
4574
- });
4575
-
4576
- if (shownTracks.length === 0) {
4577
- model.showTrack(trackId);
4578
- }
4579
- }
4580
-
4581
4704
  function getTrackName(trackId) {
4582
4705
  if (trackId) {
4583
4706
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
@@ -4642,7 +4765,7 @@ function SearchResultsDialog(_ref) {
4642
4765
  var resultTrackId = result.getTrackId();
4643
4766
 
4644
4767
  if (resultTrackId) {
4645
- handleShowTrack(resultTrackId);
4768
+ model.showTrack(resultTrackId);
4646
4769
  }
4647
4770
 
4648
4771
  handleClose();
@@ -4664,9 +4787,6 @@ var useStyles$g = /*#__PURE__*/makeStyles$1(function (theme) {
4664
4787
  importFormContainer: {
4665
4788
  padding: theme.spacing(2)
4666
4789
  },
4667
- importFormEntry: {
4668
- minWidth: 180
4669
- },
4670
4790
  button: {
4671
4791
  margin: theme.spacing(2)
4672
4792
  }
@@ -4680,18 +4800,14 @@ var ErrorDisplay = /*#__PURE__*/observer(function (_ref) {
4680
4800
  }, "".concat(error));
4681
4801
  });
4682
4802
  var ImportForm = /*#__PURE__*/observer(function (_ref2) {
4683
- var _regions$;
4803
+ var _regions$, _regions$2;
4684
4804
 
4685
4805
  var model = _ref2.model;
4686
4806
  var classes = useStyles$g();
4687
4807
  var session = getSession(model);
4688
4808
  var assemblyNames = session.assemblyNames,
4689
- assemblyManager = session.assemblyManager;
4690
-
4691
- var _getEnv = getEnv(session),
4692
- pluginManager = _getEnv.pluginManager;
4693
-
4694
- var textSearchManager = pluginManager.rootModel.textSearchManager;
4809
+ assemblyManager = session.assemblyManager,
4810
+ textSearchManager = session.textSearchManager;
4695
4811
  var rankSearchResults = model.rankSearchResults,
4696
4812
  isSearchDialogDisplayed = model.isSearchDialogDisplayed,
4697
4813
  modelError = model.error;
@@ -4715,69 +4831,139 @@ var ImportForm = /*#__PURE__*/observer(function (_ref2) {
4715
4831
 
4716
4832
  var _useState5 = useState(),
4717
4833
  _useState6 = _slicedToArray(_useState5, 2),
4718
- mySelectedRegion = _useState6[0],
4719
- setSelectedRegion = _useState6[1];
4834
+ myOption = _useState6[0],
4835
+ setOption = _useState6[1]; // use this instead of useState initializer because the useState initializer
4836
+ // won't update in response to an observable
4720
4837
 
4721
- var selectedRegion = mySelectedRegion || ((_regions$ = regions[0]) === null || _regions$ === void 0 ? void 0 : _regions$.refName);
4722
4838
 
4723
- function handleSelectedRegion(_x) {
4724
- return _handleSelectedRegion.apply(this, arguments);
4839
+ var option = myOption || new RefSequenceResult({
4840
+ refName: (_regions$ = regions[0]) === null || _regions$ === void 0 ? void 0 : _regions$.refName,
4841
+ label: (_regions$2 = regions[0]) === null || _regions$2 === void 0 ? void 0 : _regions$2.refName
4842
+ });
4843
+ var selectedRegion = option === null || option === void 0 ? void 0 : option.getLocation();
4844
+
4845
+ function fetchResults(_x) {
4846
+ return _fetchResults.apply(this, arguments);
4725
4847
  }
4848
+ /**
4849
+ * gets a string as input, or use stored option results from previous query,
4850
+ * then re-query and
4851
+ * 1) if it has multiple results: pop a dialog
4852
+ * 2) if it's a single result navigate to it
4853
+ * 3) else assume it's a locstring and navigate to it
4854
+ */
4726
4855
 
4727
- function _handleSelectedRegion() {
4728
- _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(input) {
4729
- var newRegion, results;
4856
+
4857
+ function _fetchResults() {
4858
+ _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(queryString) {
4859
+ var results;
4730
4860
  return runtime_1.wrap(function _callee$(_context) {
4731
4861
  while (1) {
4732
4862
  switch (_context.prev = _context.next) {
4733
4863
  case 0:
4734
- newRegion = regions.find(function (r) {
4735
- return selectedRegion === r.refName;
4736
- });
4864
+ if (!textSearchManager) {
4865
+ console.warn('No text search manager');
4866
+ }
4737
4867
 
4738
- if (!newRegion) {
4739
- _context.next = 6;
4868
+ _context.next = 3;
4869
+ return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
4870
+ queryString: queryString.toLowerCase(),
4871
+ searchType: 'exact'
4872
+ }, searchScope, rankSearchResults);
4873
+
4874
+ case 3:
4875
+ results = _context.sent;
4876
+ return _context.abrupt("return", dedupe(results));
4877
+
4878
+ case 5:
4879
+ case "end":
4880
+ return _context.stop();
4881
+ }
4882
+ }
4883
+ }, _callee);
4884
+ }));
4885
+ return _fetchResults.apply(this, arguments);
4886
+ }
4887
+
4888
+ function handleSelectedRegion(_x2) {
4889
+ return _handleSelectedRegion.apply(this, arguments);
4890
+ } // implementation notes:
4891
+ // having this wrapped in a form allows intuitive use of enter key to submit
4892
+
4893
+
4894
+ function _handleSelectedRegion() {
4895
+ _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(input) {
4896
+ var trackId, location, _assembly$refNames, results;
4897
+
4898
+ return runtime_1.wrap(function _callee2$(_context2) {
4899
+ while (1) {
4900
+ switch (_context2.prev = _context2.next) {
4901
+ case 0:
4902
+ if (option) {
4903
+ _context2.next = 2;
4740
4904
  break;
4741
4905
  }
4742
4906
 
4743
- model.setDisplayedRegions([newRegion]); // we use showAllRegions after setDisplayedRegions to make the entire
4744
- // region visible, xref #1703
4907
+ return _context2.abrupt("return");
4745
4908
 
4746
- model.showAllRegions();
4747
- _context.next = 10;
4909
+ case 2:
4910
+ trackId = option.getTrackId();
4911
+ location = input || option.getLocation() || '';
4912
+ _context2.prev = 4;
4913
+
4914
+ if (!(assembly !== null && assembly !== void 0 && (_assembly$refNames = assembly.refNames) !== null && _assembly$refNames !== void 0 && _assembly$refNames.includes(location))) {
4915
+ _context2.next = 9;
4916
+ break;
4917
+ }
4918
+
4919
+ model.navToLocString(location, selectedAsm);
4920
+ _context2.next = 20;
4748
4921
  break;
4749
4922
 
4750
- case 6:
4751
- _context.next = 8;
4752
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
4753
- queryString: input.toLocaleLowerCase(),
4754
- searchType: 'exact'
4755
- }, searchScope, rankSearchResults);
4923
+ case 9:
4924
+ _context2.next = 11;
4925
+ return fetchResults(input);
4756
4926
 
4757
- case 8:
4758
- results = _context.sent;
4927
+ case 11:
4928
+ results = _context2.sent;
4759
4929
 
4760
- if ((results === null || results === void 0 ? void 0 : results.length) > 0) {
4761
- model.setSearchResults(results, input.toLocaleLowerCase());
4762
- } else {
4763
- try {
4764
- input && model.navToLocString(input, selectedAsm);
4765
- } catch (e) {
4766
- if ("".concat(e) === "Error: Unknown reference sequence \"".concat(input, "\"")) {
4767
- model.setSearchResults(results, input.toLocaleLowerCase());
4768
- } else {
4769
- console.warn(e);
4770
- session.notify("".concat(e), 'warning');
4771
- }
4772
- }
4930
+ if (!(results && results.length > 1)) {
4931
+ _context2.next = 17;
4932
+ break;
4773
4933
  }
4774
4934
 
4775
- case 10:
4935
+ model.setSearchResults(results, input.toLowerCase());
4936
+ return _context2.abrupt("return");
4937
+
4938
+ case 17:
4939
+ if ((results === null || results === void 0 ? void 0 : results.length) === 1) {
4940
+ location = results[0].getLocation();
4941
+ trackId = results[0].getTrackId();
4942
+ }
4943
+
4944
+ case 18:
4945
+ model.navToLocString(location, selectedAsm);
4946
+
4947
+ if (trackId) {
4948
+ model.showTrack(trackId);
4949
+ }
4950
+
4951
+ case 20:
4952
+ _context2.next = 26;
4953
+ break;
4954
+
4955
+ case 22:
4956
+ _context2.prev = 22;
4957
+ _context2.t0 = _context2["catch"](4);
4958
+ console.error(_context2.t0);
4959
+ session.notify("".concat(_context2.t0), 'warning');
4960
+
4961
+ case 26:
4776
4962
  case "end":
4777
- return _context.stop();
4963
+ return _context2.stop();
4778
4964
  }
4779
4965
  }
4780
- }, _callee);
4966
+ }, _callee2, null, [[4, 22]]);
4781
4967
  }));
4782
4968
  return _handleSelectedRegion.apply(this, arguments);
4783
4969
  }
@@ -4786,6 +4972,10 @@ var ImportForm = /*#__PURE__*/observer(function (_ref2) {
4786
4972
  error: err
4787
4973
  }) : null, /*#__PURE__*/React.createElement(Container, {
4788
4974
  className: classes.importFormContainer
4975
+ }, /*#__PURE__*/React.createElement("form", {
4976
+ onSubmit: function onSubmit(event) {
4977
+ event.preventDefault();
4978
+ }
4789
4979
  }, /*#__PURE__*/React.createElement(Grid, {
4790
4980
  container: true,
4791
4981
  spacing: 1,
@@ -4809,35 +4999,21 @@ var ImportForm = /*#__PURE__*/observer(function (_ref2) {
4809
4999
  assemblyName: message ? undefined : selectedAsm,
4810
5000
  value: selectedRegion,
4811
5001
  onSelect: function onSelect(option) {
4812
- return setSelectedRegion(option.getLocation());
5002
+ setOption(option);
4813
5003
  },
4814
5004
  TextFieldProps: {
4815
5005
  margin: 'normal',
4816
5006
  variant: 'outlined',
4817
- helperText: 'Enter a sequence or location',
4818
- className: classes.importFormEntry,
4819
- onBlur: function onBlur(event) {
4820
- if (event.target.value !== '') {
4821
- setSelectedRegion(event.target.value);
4822
- }
4823
- },
4824
- onKeyPress: function onKeyPress(event) {
4825
- var elt = event.target; // maybe check regular expression here to see if it's a
4826
- // locstring try defaulting exact matches to first exact
4827
- // match
4828
-
4829
- if (event.key === 'Enter') {
4830
- handleSelectedRegion(elt.value);
4831
- }
4832
- }
5007
+ helperText: 'Enter a sequence or location'
4833
5008
  }
4834
- }) : /*#__PURE__*/React.createElement(CircularProgress$1, {
5009
+ }) : /*#__PURE__*/React.createElement(CircularProgress, {
4835
5010
  role: "progressbar",
4836
5011
  size: 20,
4837
5012
  disableShrink: true
4838
5013
  }) : null), /*#__PURE__*/React.createElement(Grid, {
4839
5014
  item: true
4840
5015
  }, /*#__PURE__*/React.createElement(Button$1, {
5016
+ type: "submit",
4841
5017
  disabled: !selectedRegion,
4842
5018
  className: classes.button,
4843
5019
  onClick: function onClick() {
@@ -4858,7 +5034,7 @@ var ImportForm = /*#__PURE__*/observer(function (_ref2) {
4858
5034
  },
4859
5035
  variant: "contained",
4860
5036
  color: "secondary"
4861
- }, "Show all regions in assembly")))), isSearchDialogDisplayed ? /*#__PURE__*/React.createElement(SearchResultsDialog, {
5037
+ }, "Show all regions in assembly"))))), isSearchDialogDisplayed ? /*#__PURE__*/React.createElement(SearchResultsDialog, {
4862
5038
  model: model,
4863
5039
  optAssemblyName: selectedAsm,
4864
5040
  handleClose: function handleClose() {
@@ -4916,7 +5092,7 @@ var MiniControls = /*#__PURE__*/observer(function (props) {
4916
5092
  }));
4917
5093
  });
4918
5094
 
4919
- var useStyles$h = /*#__PURE__*/makeStyles(function (theme) {
5095
+ var useStyles$h = /*#__PURE__*/makeStyles$1(function (theme) {
4920
5096
  return {
4921
5097
  loadingMessage: {
4922
5098
  padding: theme.spacing(5)
@@ -4944,7 +5120,7 @@ function fetchSequence(_x, _x2, _x3) {
4944
5120
  }
4945
5121
 
4946
5122
  function _fetchSequence() {
4947
- _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(model, selectedRegions, signal) {
5123
+ _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(model, regions, signal) {
4948
5124
  var session, leftOffset, rightOffset, rpcManager, assemblyManager, assemblyName, assembly, adapterConfig, sessionId, chunks;
4949
5125
  return runtime_1.wrap(function _callee2$(_context2) {
4950
5126
  while (1) {
@@ -4984,7 +5160,7 @@ function _fetchSequence() {
4984
5160
  adapterConfig = readConfObject(assembly.configuration, ['sequence', 'adapter']);
4985
5161
  sessionId = 'getSequence';
4986
5162
  _context2.next = 15;
4987
- return Promise.all(selectedRegions.map(function (region) {
5163
+ return Promise.all(regions.map(function (region) {
4988
5164
  return rpcManager.call(sessionId, 'CoreGetFeatures', {
4989
5165
  adapterConfig: adapterConfig,
4990
5166
  region: region,
@@ -5020,12 +5196,12 @@ function SequenceDialog(_ref) {
5020
5196
  error = _useState2[0],
5021
5197
  setError = _useState2[1];
5022
5198
 
5023
- var _useState3 = useState(''),
5199
+ var _useState3 = useState(),
5024
5200
  _useState4 = _slicedToArray(_useState3, 2),
5025
5201
  sequence = _useState4[0],
5026
5202
  setSequence = _useState4[1];
5027
5203
 
5028
- var loading = Boolean(!sequence) || Boolean(error);
5204
+ var loading = Boolean(sequence === undefined);
5029
5205
  var leftOffset = model.leftOffset,
5030
5206
  rightOffset = model.rightOffset; // avoid infinite looping of useEffect
5031
5207
  // random note: the current selected region can't be a computed because it
@@ -5038,25 +5214,6 @@ function SequenceDialog(_ref) {
5038
5214
  var active = true;
5039
5215
  var controller = new AbortController();
5040
5216
 
5041
- function formatSequence(seqChunks) {
5042
- return formatSeqFasta(seqChunks.map(function (chunk) {
5043
- var chunkSeq = chunk.get('seq');
5044
- var chunkRefName = chunk.get('refName');
5045
- var chunkStart = chunk.get('start') + 1;
5046
- var chunkEnd = chunk.get('end');
5047
- var chunkLocstring = "".concat(chunkRefName, ":").concat(chunkStart, "-").concat(chunkEnd);
5048
-
5049
- if ((chunkSeq === null || chunkSeq === void 0 ? void 0 : chunkSeq.length) !== chunkEnd - chunkStart + 1) {
5050
- throw new Error("".concat(chunkLocstring, " returned ").concat(chunkSeq.length.toLocaleString(), " bases, but should have returned ").concat((chunkEnd - chunkStart).toLocaleString()));
5051
- }
5052
-
5053
- return {
5054
- header: chunkLocstring,
5055
- seq: chunkSeq
5056
- };
5057
- }));
5058
- }
5059
-
5060
5217
  _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
5061
5218
  var chunks;
5062
5219
  return runtime_1.wrap(function _callee$(_context) {
@@ -5077,7 +5234,24 @@ function SequenceDialog(_ref) {
5077
5234
  chunks = _context.sent;
5078
5235
 
5079
5236
  if (active) {
5080
- setSequence(formatSequence(chunks));
5237
+ setSequence(formatSeqFasta(chunks.filter(function (f) {
5238
+ return !!f;
5239
+ }).map(function (chunk) {
5240
+ var chunkSeq = chunk.get('seq');
5241
+ var chunkRefName = chunk.get('refName');
5242
+ var chunkStart = chunk.get('start') + 1;
5243
+ var chunkEnd = chunk.get('end');
5244
+ var chunkLocstring = "".concat(chunkRefName, ":").concat(chunkStart, "-").concat(chunkEnd);
5245
+
5246
+ if ((chunkSeq === null || chunkSeq === void 0 ? void 0 : chunkSeq.length) !== chunkEnd - chunkStart + 1) {
5247
+ throw new Error("".concat(chunkLocstring, " returned ").concat(chunkSeq.length.toLocaleString(), " bases, but should have returned ").concat((chunkEnd - chunkStart).toLocaleString()));
5248
+ }
5249
+
5250
+ return {
5251
+ header: chunkLocstring,
5252
+ seq: chunkSeq
5253
+ };
5254
+ })));
5081
5255
  }
5082
5256
 
5083
5257
  _context.next = 9;
@@ -5112,7 +5286,7 @@ function SequenceDialog(_ref) {
5112
5286
  active = false;
5113
5287
  };
5114
5288
  }, [model, session, regionsSelected, setSequence]);
5115
- var sequenceTooLarge = sequence.length > 1000000;
5289
+ var sequenceTooLarge = sequence ? sequence.length > 1000000 : false;
5116
5290
  return /*#__PURE__*/React.createElement(Dialog, {
5117
5291
  "data-testid": "sequence-dialog",
5118
5292
  maxWidth: "xl",
@@ -5131,13 +5305,13 @@ function SequenceDialog(_ref) {
5131
5305
  }
5132
5306
  }, /*#__PURE__*/React.createElement(CloseIcon, null)) : null), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(DialogContent, null, error ? /*#__PURE__*/React.createElement(Typography$1, {
5133
5307
  color: "error"
5134
- }, "".concat(error)) : null, loading && !error ? /*#__PURE__*/React.createElement(Container, null, "Retrieving reference sequence...", /*#__PURE__*/React.createElement(CircularProgress$1, {
5308
+ }, "".concat(error)) : null, loading && !error ? /*#__PURE__*/React.createElement(Container, null, "Retrieving reference sequence...", /*#__PURE__*/React.createElement(CircularProgress, {
5135
5309
  style: {
5136
5310
  marginLeft: 10
5137
5311
  },
5138
5312
  size: 20,
5139
5313
  disableShrink: true
5140
- })) : null, sequence !== undefined ? /*#__PURE__*/React.createElement(TextField$1, {
5314
+ })) : null, /*#__PURE__*/React.createElement(TextField, {
5141
5315
  "data-testid": "rubberband-sequence",
5142
5316
  variant: "outlined",
5143
5317
  multiline: true,
@@ -5152,12 +5326,12 @@ function SequenceDialog(_ref) {
5152
5326
  input: classes.textAreaFont
5153
5327
  }
5154
5328
  }
5155
- }) : null), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button$1, {
5329
+ })), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button$1, {
5156
5330
  onClick: function onClick() {
5157
5331
  copy(sequence || '');
5158
5332
  session.notify('Copied to clipboard', 'success');
5159
5333
  },
5160
- disabled: loading || sequenceTooLarge,
5334
+ disabled: loading || !!error || sequenceTooLarge,
5161
5335
  color: "primary",
5162
5336
  startIcon: /*#__PURE__*/React.createElement(ContentCopy, null)
5163
5337
  }, "Copy to clipboard"), /*#__PURE__*/React.createElement(Button$1, {
@@ -5167,7 +5341,7 @@ function SequenceDialog(_ref) {
5167
5341
  });
5168
5342
  saveAs(seqFastaFile, 'jbrowse_ref_seq.fa');
5169
5343
  },
5170
- disabled: loading,
5344
+ disabled: loading || !!error,
5171
5345
  color: "primary",
5172
5346
  startIcon: /*#__PURE__*/React.createElement(GetAppIcon, null)
5173
5347
  }, "Download FASTA"), /*#__PURE__*/React.createElement(Button$1, {
@@ -5188,20 +5362,17 @@ function mathPower(num) {
5188
5362
  }
5189
5363
 
5190
5364
  var useStyles$i = /*#__PURE__*/makeStyles(function () {
5191
- return (
5192
- /* theme */
5193
- {
5194
- majorTickLabel: {
5195
- fontSize: '11px'
5196
- },
5197
- majorTick: {
5198
- stroke: '#555'
5199
- },
5200
- minorTick: {
5201
- stroke: '#999'
5202
- }
5365
+ return {
5366
+ majorTickLabel: {
5367
+ fontSize: '11px'
5368
+ },
5369
+ majorTick: {
5370
+ stroke: '#555'
5371
+ },
5372
+ minorTick: {
5373
+ stroke: '#999'
5203
5374
  }
5204
- );
5375
+ };
5205
5376
  });
5206
5377
 
5207
5378
  function Ruler(_ref) {
@@ -5620,8 +5791,10 @@ var useStyles$k = /*#__PURE__*/makeStyles(function (theme) {
5620
5791
  function ExportSvgDlg(_ref) {
5621
5792
  var model = _ref.model,
5622
5793
  handleClose = _ref.handleClose;
5794
+ // @ts-ignore
5795
+ var offscreenCanvas = typeof OffscreenCanvas !== 'undefined';
5623
5796
 
5624
- var _useState = useState(typeof OffscreenCanvas !== 'undefined'),
5797
+ var _useState = useState(offscreenCanvas),
5625
5798
  _useState2 = _slicedToArray(_useState, 2),
5626
5799
  rasterizeLayers = _useState2[0],
5627
5800
  setRasterizeLayers = _useState2[1];
@@ -5647,14 +5820,14 @@ function ExportSvgDlg(_ref) {
5647
5820
  style: {
5648
5821
  color: 'red'
5649
5822
  }
5650
- }, "".concat(error)) : loading ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(CircularProgress$1, {
5823
+ }, "".concat(error)) : loading ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(CircularProgress, {
5651
5824
  size: 20,
5652
5825
  style: {
5653
5826
  marginRight: 20
5654
5827
  }
5655
5828
  }), /*#__PURE__*/React.createElement(Typography$1, {
5656
5829
  display: "inline"
5657
- }, "Creating SVG")) : null, typeof OffscreenCanvas !== 'undefined' ? /*#__PURE__*/React.createElement(FormControlLabel, {
5830
+ }, "Creating SVG")) : null, offscreenCanvas ? /*#__PURE__*/React.createElement(FormControlLabel, {
5658
5831
  control: /*#__PURE__*/React.createElement(Checkbox, {
5659
5832
  checked: rasterizeLayers,
5660
5833
  onChange: function onChange() {
@@ -5664,7 +5837,13 @@ function ExportSvgDlg(_ref) {
5664
5837
  }
5665
5838
  }),
5666
5839
  label: "Rasterize canvas based tracks? File may be much larger if this is turned off"
5667
- }) : /*#__PURE__*/React.createElement(Typography$1, null, "Note: rasterizing layers not yet supported in this browser, so SVG size may be large"), /*#__PURE__*/React.createElement(Button$1, {
5840
+ }) : /*#__PURE__*/React.createElement(Typography$1, null, "Note: rasterizing layers not yet supported in this browser, so SVG size may be large")), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button$1, {
5841
+ variant: "contained",
5842
+ color: "secondary",
5843
+ onClick: function onClick() {
5844
+ return handleClose();
5845
+ }
5846
+ }, "Cancel"), /*#__PURE__*/React.createElement(Button$1, {
5668
5847
  variant: "contained",
5669
5848
  color: "primary",
5670
5849
  type: "submit",
@@ -5684,25 +5863,26 @@ function ExportSvgDlg(_ref) {
5684
5863
 
5685
5864
  case 5:
5686
5865
  handleClose();
5687
- _context.next = 11;
5866
+ _context.next = 12;
5688
5867
  break;
5689
5868
 
5690
5869
  case 8:
5691
5870
  _context.prev = 8;
5692
5871
  _context.t0 = _context["catch"](2);
5872
+ console.error(_context.t0);
5693
5873
  setError(_context.t0);
5694
5874
 
5695
- case 11:
5696
- _context.prev = 11;
5875
+ case 12:
5876
+ _context.prev = 12;
5697
5877
  setLoading(false);
5698
- return _context.finish(11);
5878
+ return _context.finish(12);
5699
5879
 
5700
- case 14:
5880
+ case 15:
5701
5881
  case "end":
5702
5882
  return _context.stop();
5703
5883
  }
5704
5884
  }
5705
- }, _callee, null, [[2, 8, 11, 14]]);
5885
+ }, _callee, null, [[2, 8, 12, 15]]);
5706
5886
  }));
5707
5887
 
5708
5888
  function onClick() {
@@ -6217,7 +6397,12 @@ function stateModelFactory$1(pluginManager) {
6217
6397
  var displayInitialSnapshot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6218
6398
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
6219
6399
  var configuration = resolveIdentifier(trackConfigSchema, getRoot(self), trackId);
6220
- var trackType = pluginManager.getTrackType(configuration.type);
6400
+
6401
+ if (!configuration) {
6402
+ throw new Error("Could not resolve identifier");
6403
+ }
6404
+
6405
+ var trackType = pluginManager.getTrackType(configuration === null || configuration === void 0 ? void 0 : configuration.type);
6221
6406
 
6222
6407
  if (!trackType) {
6223
6408
  throw new Error("unknown track type ".concat(configuration.type));
@@ -6235,16 +6420,24 @@ function stateModelFactory$1(pluginManager) {
6235
6420
  throw new Error("could not find a compatible display for view type ".concat(self.type));
6236
6421
  }
6237
6422
 
6238
- var track = trackType.stateModel.create(_objectSpread2(_objectSpread2({}, initialSnapshot), {}, {
6239
- type: configuration.type,
6240
- configuration: configuration,
6241
- displays: [_objectSpread2({
6242
- type: displayConf.type,
6243
- configuration: displayConf
6244
- }, displayInitialSnapshot)]
6245
- }));
6246
- self.tracks.push(track);
6247
- return track;
6423
+ var shownTracks = self.tracks.filter(function (t) {
6424
+ return t.configuration === configuration;
6425
+ });
6426
+
6427
+ if (shownTracks.length === 0) {
6428
+ var track = trackType.stateModel.create(_objectSpread2(_objectSpread2({}, initialSnapshot), {}, {
6429
+ type: configuration.type,
6430
+ configuration: configuration,
6431
+ displays: [_objectSpread2({
6432
+ type: displayConf.type,
6433
+ configuration: displayConf
6434
+ }, displayInitialSnapshot)]
6435
+ }));
6436
+ self.tracks.push(track);
6437
+ return track;
6438
+ }
6439
+
6440
+ return shownTracks[0];
6248
6441
  },
6249
6442
  hideTrack: function hideTrack(trackId) {
6250
6443
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
@@ -6802,8 +6995,7 @@ function stateModelFactory$1(pluginManager) {
6802
6995
  self.zoomTo(self.bpPerPx);
6803
6996
 
6804
6997
  if ( // already zoomed all the way in
6805
- targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx || // already zoomed all the way out
6806
- targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx) {
6998
+ targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx || targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx) {
6807
6999
  return;
6808
7000
  }
6809
7001
 
@@ -6833,8 +7025,11 @@ function stateModelFactory$1(pluginManager) {
6833
7025
  var menuItems = [{
6834
7026
  label: 'Return to import form',
6835
7027
  onClick: function onClick() {
6836
- getSession(self).setDialogComponent(ReturnToImportFormDlg, {
6837
- model: self
7028
+ getSession(self).queueDialog(function (doneCallback) {
7029
+ return [ReturnToImportFormDlg, {
7030
+ model: self,
7031
+ handleClose: doneCallback
7032
+ }];
6838
7033
  });
6839
7034
  },
6840
7035
  icon: FolderOpenIcon
@@ -6842,8 +7037,11 @@ function stateModelFactory$1(pluginManager) {
6842
7037
  label: 'Export SVG',
6843
7038
  icon: PhotoCameraIcon,
6844
7039
  onClick: function onClick() {
6845
- getSession(self).setDialogComponent(ExportSvgDlg, {
6846
- model: self
7040
+ getSession(self).queueDialog(function (doneCallback) {
7041
+ return [ExportSvgDlg, {
7042
+ model: self,
7043
+ handleClose: doneCallback
7044
+ }];
6847
7045
  });
6848
7046
  }
6849
7047
  }, {
@@ -7062,6 +7260,7 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7062
7260
  return types.compose('LinearBasicDisplay', BaseLinearDisplay$1, types.model({
7063
7261
  type: types.literal('LinearBasicDisplay'),
7064
7262
  trackShowLabels: types.maybe(types["boolean"]),
7263
+ trackShowDescriptions: types.maybe(types["boolean"]),
7065
7264
  trackDisplayMode: types.maybe(types.string),
7066
7265
  trackMaxHeight: types.maybe(types.number),
7067
7266
  configuration: ConfigurationReference$1(configSchema)
@@ -7076,6 +7275,11 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7076
7275
  return self.trackShowLabels !== undefined ? self.trackShowLabels : showLabels;
7077
7276
  },
7078
7277
 
7278
+ get showDescriptions() {
7279
+ var showDescriptions = getConf(self, ['renderer', 'showLabels']);
7280
+ return self.trackShowDescriptions !== undefined ? self.trackShowDescriptions : showDescriptions;
7281
+ },
7282
+
7079
7283
  get maxHeight() {
7080
7284
  var maxHeight = getConf(self, ['renderer', 'maxHeight']);
7081
7285
  return self.trackMaxHeight !== undefined ? self.trackMaxHeight : maxHeight;
@@ -7090,6 +7294,7 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7090
7294
  var configBlob = getConf(self, ['renderer']) || {};
7091
7295
  return self.rendererType.configSchema.create(_objectSpread2(_objectSpread2({}, configBlob), {}, {
7092
7296
  showLabels: this.showLabels,
7297
+ showDescriptions: this.showDescriptions,
7093
7298
  displayMode: this.displayMode,
7094
7299
  maxHeight: this.maxHeight
7095
7300
  }), getEnv(self));
@@ -7101,6 +7306,9 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7101
7306
  toggleShowLabels: function toggleShowLabels() {
7102
7307
  self.trackShowLabels = !self.showLabels;
7103
7308
  },
7309
+ toggleShowDescriptions: function toggleShowDescriptions() {
7310
+ self.trackShowDescriptions = !self.showDescriptions;
7311
+ },
7104
7312
  setDisplayMode: function setDisplayMode(val) {
7105
7313
  self.trackDisplayMode = val;
7106
7314
  },
@@ -7127,6 +7335,14 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7127
7335
  onClick: function onClick() {
7128
7336
  self.toggleShowLabels();
7129
7337
  }
7338
+ }, {
7339
+ label: 'Show descriptions',
7340
+ icon: VisibilityIcon,
7341
+ type: 'checkbox',
7342
+ checked: self.showDescriptions,
7343
+ onClick: function onClick() {
7344
+ self.toggleShowDescriptions();
7345
+ }
7130
7346
  }, {
7131
7347
  label: 'Display mode',
7132
7348
  icon: VisibilityIcon,
@@ -7141,8 +7357,11 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7141
7357
  }, {
7142
7358
  label: 'Set max height',
7143
7359
  onClick: function onClick() {
7144
- getSession(self).setDialogComponent(SetMaxHeightDlg, {
7145
- model: self
7360
+ getSession(self).queueDialog(function (doneCallback) {
7361
+ return [SetMaxHeightDlg, {
7362
+ model: self,
7363
+ handleClose: doneCallback
7364
+ }];
7146
7365
  });
7147
7366
  }
7148
7367
  }]);
@@ -7253,7 +7472,7 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
7253
7472
  key: "configure",
7254
7473
  value: function configure(pluginManager) {
7255
7474
  if (isAbstractMenuManager(pluginManager.rootModel)) {
7256
- pluginManager.rootModel.appendToSubMenu(['File', 'Add'], {
7475
+ pluginManager.rootModel.appendToSubMenu(['Add'], {
7257
7476
  label: 'Linear genome view',
7258
7477
  icon: LineStyleIcon,
7259
7478
  onClick: function onClick(session) {
@@ -7309,7 +7528,7 @@ function SetMaxHeightDlg$1(props) {
7309
7528
  onClick: handleClose
7310
7529
  }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement("div", {
7311
7530
  className: classes.root
7312
- }, /*#__PURE__*/React.createElement(Typography$1, null, "Set max height for the track"), /*#__PURE__*/React.createElement(TextField$1, {
7531
+ }, /*#__PURE__*/React.createElement(Typography$1, null, "Set max height for the track"), /*#__PURE__*/React.createElement(TextField, {
7313
7532
  value: max,
7314
7533
  onChange: function onChange(event) {
7315
7534
  setMax(event.target.value);
@@ -7337,5 +7556,5 @@ var SetMaxHeight$1 = {
7337
7556
  };
7338
7557
 
7339
7558
  export default LinearGenomeViewPlugin;
7340
- export { BaseLinearDisplay$1 as BaseLinearDisplay, BaseLinearDisplay as BaseLinearDisplayComponent, baseLinearDisplayConfigSchema, configSchemaFactory as linearBareDisplayConfigSchemaFactory, configSchemaFactory$1 as linearBasicDisplayConfigSchemaFactory, stateModelFactory$2 as linearBasicDisplayModelFactory, renderToSvg };
7559
+ export { BaseLinearDisplay$1 as BaseLinearDisplay, BaseLinearDisplay as BaseLinearDisplayComponent, RefNameAutocomplete$1 as RefNameAutocomplete, baseLinearDisplayConfigSchema, configSchemaFactory as linearBareDisplayConfigSchemaFactory, configSchemaFactory$1 as linearBasicDisplayConfigSchemaFactory, stateModelFactory$2 as linearBasicDisplayModelFactory, renderToSvg };
7341
7560
  //# sourceMappingURL=plugin-linear-genome-view.esm.js.map