@jbrowse/plugin-linear-genome-view 5.0.0-beta.1 → 5.0.0-beta.11

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 (148) hide show
  1. package/esm/FeatureTrack/configSchema.d.ts +142 -50
  2. package/esm/LaunchLinearGenomeView/index.js +2 -13
  3. package/esm/LinearGenomeView/afterAttach.d.ts +5 -5
  4. package/esm/LinearGenomeView/afterAttach.js +75 -62
  5. package/esm/LinearGenomeView/components/CenterLine.js +5 -3
  6. package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
  7. package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +3 -2
  8. package/esm/LinearGenomeView/components/ExportSvgDialog.js +6 -2
  9. package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
  10. package/esm/LinearGenomeView/components/Header.js +11 -1
  11. package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
  12. package/esm/LinearGenomeView/components/HeaderPanControls.js +2 -1
  13. package/esm/LinearGenomeView/components/HeaderZoomControls.js +4 -34
  14. package/esm/LinearGenomeView/components/Highlight.js +7 -7
  15. package/esm/LinearGenomeView/components/HighlightBand.d.ts +9 -1
  16. package/esm/LinearGenomeView/components/HighlightBand.js +15 -3
  17. package/esm/LinearGenomeView/components/HighlightChip.d.ts +1 -2
  18. package/esm/LinearGenomeView/components/HighlightChip.js +5 -7
  19. package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
  20. package/esm/LinearGenomeView/components/ImportForm.js +2 -2
  21. package/esm/LinearGenomeView/components/LinearGenomeView.js +3 -3
  22. package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +3 -4
  23. package/esm/LinearGenomeView/components/MiniControls.js +3 -2
  24. package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
  25. package/esm/LinearGenomeView/components/OverviewHighlightBand.js +2 -3
  26. package/esm/LinearGenomeView/components/OverviewRubberband.js +20 -45
  27. package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
  28. package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
  29. package/esm/LinearGenomeView/components/PaddingBlocks.d.ts +1 -1
  30. package/esm/LinearGenomeView/components/PaddingBlocks.js +14 -9
  31. package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
  32. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
  33. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +71 -0
  34. package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
  35. package/esm/LinearGenomeView/components/Rubberband.js +3 -2
  36. package/esm/LinearGenomeView/components/SVGHighlightBand.js +2 -3
  37. package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
  38. package/esm/LinearGenomeView/components/Scalebar.js +8 -5
  39. package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +49 -34
  40. package/esm/LinearGenomeView/components/SearchBox.js +8 -7
  41. package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +2 -1
  42. package/esm/LinearGenomeView/components/SearchResultsDialog.js +2 -2
  43. package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +2 -1
  44. package/esm/LinearGenomeView/components/SearchResultsTable.js +12 -29
  45. package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
  46. package/esm/LinearGenomeView/components/TrackContainer.js +63 -9
  47. package/esm/LinearGenomeView/components/TrackLabel.js +10 -3
  48. package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
  49. package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +2 -2
  50. package/esm/LinearGenomeView/components/TrackLabelMenu.js +3 -2
  51. package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +4 -1
  52. package/esm/LinearGenomeView/components/TrackRenderingContainer.js +11 -23
  53. package/esm/LinearGenomeView/components/TracksContainer.js +10 -22
  54. package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
  55. package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
  56. package/esm/LinearGenomeView/components/ZoomButton.js +6 -1
  57. package/esm/LinearGenomeView/components/ZoomTransform.js +4 -0
  58. package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
  59. package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
  60. package/esm/LinearGenomeView/components/searchModes.d.ts +1 -1
  61. package/esm/LinearGenomeView/components/searchModes.js +1 -1
  62. package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
  63. package/esm/LinearGenomeView/components/useRangeSelect.js +20 -59
  64. package/esm/LinearGenomeView/components/useSideScroll.d.ts +16 -2
  65. package/esm/LinearGenomeView/components/useSideScroll.js +153 -103
  66. package/esm/LinearGenomeView/components/util.d.ts +4 -0
  67. package/esm/LinearGenomeView/components/util.js +4 -2
  68. package/esm/LinearGenomeView/consts.d.ts +2 -0
  69. package/esm/LinearGenomeView/consts.js +3 -1
  70. package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
  71. package/esm/LinearGenomeView/containingLgv.js +23 -0
  72. package/esm/LinearGenomeView/headerFit.d.ts +4 -2
  73. package/esm/LinearGenomeView/headerFit.js +20 -7
  74. package/esm/LinearGenomeView/index.d.ts +1 -5
  75. package/esm/LinearGenomeView/index.js +10 -7
  76. package/esm/LinearGenomeView/keyboardHandler.d.ts +2 -0
  77. package/esm/LinearGenomeView/keyboardHandler.js +15 -1
  78. package/esm/LinearGenomeView/launchKeys.d.ts +2 -0
  79. package/esm/LinearGenomeView/launchKeys.js +27 -0
  80. package/esm/LinearGenomeView/lazyDialogs.d.ts +2 -4
  81. package/esm/LinearGenomeView/lazyDialogs.js +1 -0
  82. package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
  83. package/esm/LinearGenomeView/linkedViewSync.js +27 -43
  84. package/esm/LinearGenomeView/menuItems.d.ts +16 -18
  85. package/esm/LinearGenomeView/menuItems.js +242 -151
  86. package/esm/LinearGenomeView/model.d.ts +2027 -200
  87. package/esm/LinearGenomeView/model.js +560 -395
  88. package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
  89. package/esm/LinearGenomeView/showRegionsWithUndo.js +7 -1
  90. package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
  91. package/esm/LinearGenomeView/stickyChrome.js +5 -9
  92. package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
  93. package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
  94. package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
  95. package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +8 -8
  96. package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +3 -3
  97. package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +7 -11
  98. package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
  99. package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
  100. package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
  101. package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
  102. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +27 -0
  103. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
  104. package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +2 -1
  105. package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +29 -16
  106. package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -4
  107. package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +6 -5
  108. package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +1 -1
  109. package/esm/LinearGenomeView/svgcomponents/SVGView.js +1 -1
  110. package/esm/LinearGenomeView/svgcomponents/figureContract.js +14 -14
  111. package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +1 -0
  112. package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +1 -1
  113. package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +50 -68
  114. package/esm/LinearGenomeView/svgcomponents/util.d.ts +20 -8
  115. package/esm/LinearGenomeView/svgcomponents/util.js +50 -29
  116. package/esm/LinearGenomeView/types.d.ts +8 -11
  117. package/esm/LinearGenomeView/util.d.ts +60 -45
  118. package/esm/LinearGenomeView/util.js +131 -160
  119. package/esm/MultiLevelRubberband/MultiLevelRubberband.js +7 -4
  120. package/esm/MultiLevelRubberband/index.d.ts +2 -0
  121. package/esm/MultiLevelRubberband/index.js +2 -0
  122. package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
  123. package/esm/MultiLevelRubberband/menuItems.js +52 -0
  124. package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
  125. package/esm/MultiLevelRubberband/rowLabel.js +27 -0
  126. package/esm/MultiLevelRubberband/types.d.ts +1 -0
  127. package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
  128. package/esm/MultiLevelRubberband/useRangeSelect.js +31 -47
  129. package/esm/displayKitTests/perRegionTestEnv.d.ts +244 -86
  130. package/esm/displayKitTests/perRegionTestEnv.js +30 -29
  131. package/esm/index.d.ts +15 -85
  132. package/esm/index.js +13 -36
  133. package/esm/searchUtils.d.ts +18 -9
  134. package/esm/searchUtils.js +85 -69
  135. package/esm/shared/RubberbandSpan.js +2 -1
  136. package/esm/shared/coordLabels.d.ts +7 -0
  137. package/esm/shared/coordLabels.js +15 -1
  138. package/esm/shared/useWindowDrag.d.ts +18 -0
  139. package/esm/shared/useWindowDrag.js +45 -0
  140. package/package.json +10 -10
  141. package/esm/LinearGenomeView/FloatingSvgOverlay.d.ts +0 -5
  142. package/esm/LinearGenomeView/FloatingSvgOverlay.js +0 -25
  143. package/esm/LinearGenomeView/initKeys.d.ts +0 -13
  144. package/esm/LinearGenomeView/initKeys.js +0 -104
  145. package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
  146. package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
  147. package/esm/lazyPluginExports.d.ts +0 -23
  148. package/esm/lazyPluginExports.js +0 -36
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
2
3
  import ScrollZoomToggle from '@jbrowse/core/ui/ScrollZoomToggle';
4
+ import { getSession } from '@jbrowse/core/util';
3
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
4
6
  import useMeasure from '@jbrowse/core/util/useMeasure';
7
+ import MenuIcon from '@mui/icons-material/Menu';
8
+ import { useMediaQuery } from '@mui/material';
5
9
  import { observer } from 'mobx-react';
6
10
  import { HEADER_BAR_HEIGHT } from '../consts.js';
7
11
  import { headerFit } from '../headerFit.js';
@@ -35,12 +39,18 @@ const Controls = observer(function Controls({ model, }) {
35
39
  // row
36
40
  const [ref, { width }] = useMeasure('width');
37
41
  const highlighted = highlightedDisplays(model);
42
+ const viewMenu = getSession(model).viewTitleBars === false;
43
+ const touch = useMediaQuery('(pointer: coarse)', {
44
+ noSsr: true,
45
+ });
38
46
  const fit = headerFit({
39
47
  width,
40
48
  searchBoxPx: searchBoxWidth(model.coarseVisibleLocStrings),
41
49
  clearHighlight: highlighted.length > 0,
50
+ viewMenu,
51
+ touch,
42
52
  });
43
- return (_jsxs("div", { className: classes.headerBar, ref: ref, children: [_jsx(HeaderTrackSelectorButton, { model: model, indent: fit.trackSelectorIndent }), _jsx(ScrollZoomToggle, { model: model, iconOnly: !fit.scrollZoomLabel }), _jsx("div", { className: classes.spacer }), _jsx(HeaderPanControls, { model: model, compact: !fit.panButtonSpacing }), _jsx(SearchBox, { model: model }), _jsx(HeaderClearHighlightButton, { highlighted: highlighted }), fit.regionWidth ? _jsx(HeaderRegionWidth, { model: model }) : null, _jsx(HeaderZoomControls, { model: model, showSlider: fit.zoomSlider }), _jsx("div", { className: classes.spacer })] }));
53
+ return (_jsxs("div", { className: classes.headerBar, ref: ref, children: [viewMenu ? (_jsx(CascadingMenuButton, { menuItems: () => model.menuItems(), "data-testid": "view_menu_icon", children: _jsx(MenuIcon, {}) })) : null, _jsx(HeaderTrackSelectorButton, { model: model, indent: fit.trackSelectorIndent }), touch ? null : (_jsx(ScrollZoomToggle, { model: model, iconOnly: !fit.scrollZoomLabel })), _jsx("div", { className: classes.spacer }), touch ? null : (_jsx(HeaderPanControls, { model: model, compact: !fit.panButtonSpacing })), _jsx(SearchBox, { model: model }), _jsx(HeaderClearHighlightButton, { highlighted: highlighted }), fit.regionWidth ? _jsx(HeaderRegionWidth, { model: model }) : null, _jsx(HeaderZoomControls, { model: model, showSlider: fit.zoomSlider }), _jsx("div", { className: classes.spacer })] }));
44
54
  });
45
55
  const LinearGenomeViewHeader = observer(function LinearGenomeViewHeader({ model, }) {
46
56
  const { hideHeader, hideHeaderOverview } = model;
@@ -24,9 +24,9 @@ export function highlightedDisplays(model) {
24
24
  .filter(isFeatureHighlightCapable)
25
25
  .filter(d => d.featureHighlights.length > 0);
26
26
  }
27
- // Clears every highlight in the view at once. Shown only while there is one.
27
+ // Clears every feature highlight in the view. Shown only while there is one.
28
28
  const HeaderClearHighlightButton = observer(function HeaderClearHighlightButton({ highlighted, }) {
29
- return highlighted.length > 0 ? (_jsx(IconButton, { "data-testid": "clear_search_highlight", title: "Clear highlights", onClick: () => {
29
+ return highlighted.length > 0 ? (_jsx(IconButton, { "data-testid": "clear_search_highlight", title: "Clear feature highlights", onClick: () => {
30
30
  for (const d of highlighted) {
31
31
  d.clearFeatureHighlights();
32
32
  }
@@ -1,8 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { alpha } from '@jbrowse/core/ui/palette';
2
3
  import { makeStyles } from '@jbrowse/core/util/tss-react';
3
4
  import ArrowBackIcon from '@mui/icons-material/ArrowBack';
4
5
  import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
5
- import { Button, alpha } from '@mui/material';
6
+ import { Button } from '@mui/material';
6
7
  import { SPACING, WIDGET_HEIGHT } from '../consts.js';
7
8
  const useStyles = makeStyles()(theme => ({
8
9
  panButton: {
@@ -1,14 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { lazy, useState } from 'react';
2
+ import { useState } from 'react';
3
3
  import { SingleSlider } from '@jbrowse/core/ui';
4
4
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
5
- import { getBpDisplayStr, getDialogHost } from '@jbrowse/core/util';
5
+ import { getBpDisplayStr } from '@jbrowse/core/util';
6
6
  import { makeStyles } from '@jbrowse/core/util/tss-react';
7
7
  import MoreVert from '@mui/icons-material/MoreVert';
8
8
  import { observer } from 'mobx-react';
9
- import { showAllRegionsMenuItem } from '../menuItems.js';
9
+ import { zoomMenuItems } from '../menuItems.js';
10
10
  import ZoomButton from './ZoomButton.js';
11
- const RegionWidthEditorDialog = lazy(() => import('./RegionWidthEditorDialog.js'));
12
11
  const useStyles = makeStyles()(theme => ({
13
12
  container: {
14
13
  display: 'flex',
@@ -29,35 +28,6 @@ const useStyles = makeStyles()(theme => ({
29
28
  },
30
29
  },
31
30
  }));
32
- function getZoomMenuItems(model) {
33
- return [
34
- ...[10, 50, 100].map(r => ({
35
- label: `Zoom in ${r}x`,
36
- onClick: () => {
37
- model.zoom(model.bpPerPx / r);
38
- },
39
- })),
40
- ...[10, 50, 100].map(r => ({
41
- label: `Zoom out ${r}x`,
42
- onClick: () => {
43
- model.zoom(model.bpPerPx * r);
44
- },
45
- })),
46
- showAllRegionsMenuItem(model),
47
- {
48
- label: 'Custom zoom',
49
- onClick: () => {
50
- getDialogHost(model).queueDialog(handleClose => [
51
- RegionWidthEditorDialog,
52
- {
53
- model,
54
- handleClose,
55
- },
56
- ]);
57
- },
58
- },
59
- ];
60
- }
61
31
  // The slider tracks live `bpPerPx`, which changes on every animation frame of a
62
32
  // zoom. Isolated into its own observer so the surrounding zoom buttons/menu —
63
33
  // whose MUI Tooltip/IconButton machinery is comparatively expensive and only
@@ -82,6 +52,6 @@ const ZoomSlider = observer(function ZoomSlider({ model, }) {
82
52
  });
83
53
  const HeaderZoomControls = observer(function HeaderZoomControls({ model, showSlider = true, }) {
84
54
  const { classes } = useStyles();
85
- return (_jsxs("div", { className: classes.container, children: [_jsx(ZoomButton, { model: model, direction: "out" }), showSlider ? _jsx(ZoomSlider, { model: model }) : null, _jsx(ZoomButton, { model: model, direction: "in" }), _jsx(CascadingMenuButton, { menuItems: () => getZoomMenuItems(model), children: _jsx(MoreVert, {}) })] }));
55
+ return (_jsxs("div", { className: classes.container, children: [_jsx(ZoomButton, { model: model, direction: "out" }), showSlider ? _jsx(ZoomSlider, { model: model }) : null, _jsx(ZoomButton, { model: model, direction: "in" }), _jsx(CascadingMenuButton, { menuItems: () => zoomMenuItems(model), children: _jsx(MoreVert, {}) })] }));
86
56
  });
87
57
  export default HeaderZoomControls;
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useHighlightChip } from '@jbrowse/core/ui/highlightChipReveal';
2
+ import { useStyleTheme } from '@jbrowse/core/ui/PaletteContext';
3
3
  import { getSession } from '@jbrowse/core/util';
4
4
  import CloseIcon from '@mui/icons-material/Close';
5
5
  import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
6
- import { useTheme } from '@mui/material';
7
6
  import { observer } from 'mobx-react';
8
7
  import HighlightBand from './HighlightBand.js';
9
8
  import HighlightChip from './HighlightChip.js';
@@ -12,17 +11,18 @@ import { getHighlightColor } from './util.js';
12
11
  // width the chip is dropped (the band itself still draws).
13
12
  const CHIP_MIN_WIDTH = 24;
14
13
  const Highlight = observer(function Highlight({ model, highlight, }) {
15
- const theme = useTheme();
14
+ const theme = useStyleTheme();
16
15
  const coords = model.getHighlightCoords(highlight);
17
16
  const bandColor = getHighlightColor(highlight, theme);
18
- const label = model.labelsVisible ? highlight.label : undefined;
19
- const { chipVisible, setMenuOpen } = useHighlightChip(coords, model.showHighlightChips);
20
- return coords ? (_jsx(HighlightBand, { coords: coords, background: bandColor.toRgbString(), label: label, children: chipVisible && coords.width >= CHIP_MIN_WIDTH ? (_jsx(HighlightChip, { color: bandColor, label: label, tooltip: highlight.label ?? 'Highlighted region', setOpen: setMenuOpen, menuItems: [
17
+ const label = getSession(model).highlightLabelsVisible
18
+ ? highlight.label
19
+ : undefined;
20
+ return coords ? (_jsx(HighlightBand, { coords: coords, background: bandColor.toRgbString(), label: label, gaps: model.nonGenomicTrackBands(), children: coords.width >= CHIP_MIN_WIDTH ? (_jsx(HighlightChip, { color: bandColor, label: label, tooltip: highlight.label ?? 'Highlighted region', menuItems: [
21
21
  {
22
22
  label: 'Dismiss highlight',
23
23
  icon: CloseIcon,
24
24
  onClick: () => {
25
- model.removeHighlight(highlight);
25
+ getSession(model).removeHighlight(highlight);
26
26
  },
27
27
  },
28
28
  {
@@ -1,9 +1,17 @@
1
- export default function HighlightBand({ coords, background, label, children, }: {
1
+ export declare function gapMask(gaps: {
2
+ top: number;
3
+ height: number;
4
+ }[]): string;
5
+ export default function HighlightBand({ coords, background, label, gaps, children, }: {
2
6
  coords: {
3
7
  left: number;
4
8
  width: number;
5
9
  };
6
10
  background: string;
7
11
  label?: string;
12
+ gaps?: {
13
+ top: number;
14
+ height: number;
15
+ }[];
8
16
  children?: React.ReactNode;
9
17
  }): import("react").JSX.Element;
@@ -24,11 +24,20 @@ const useStyles = makeStyles()(theme => ({
24
24
  color: theme.palette.text.primary,
25
25
  },
26
26
  }));
27
- // Shared band renderer for LGV and grid-bookmark highlights; OverviewHighlight
28
- // stays separate (different bpToPx API). A non-interactive colored band with an
27
+ export function gapMask(gaps) {
28
+ const stops = gaps.flatMap(g => [
29
+ `#000 ${g.top}px`,
30
+ `transparent ${g.top}px`,
31
+ `transparent ${g.top + g.height}px`,
32
+ `#000 ${g.top + g.height}px`,
33
+ ]);
34
+ return `linear-gradient(to bottom, ${stops.join(', ')})`;
35
+ }
36
+ // OverviewHighlight stays separate (different bpToPx API). A non-interactive
37
+ // colored band with an
29
38
  // optional top label; when `children` (the highlight chip) is passed it renders
30
39
  // that instead of the plain label. Visibility is toggled from the view menu
31
- export default function HighlightBand({ coords, background, label, children, }) {
40
+ export default function HighlightBand({ coords, background, label, gaps, children, }) {
32
41
  const { classes } = useStyles();
33
42
  const content = children ??
34
43
  (label ? (_jsx(Typography, { variant: "caption", className: classes.label, noWrap: true, children: label })) : null);
@@ -36,5 +45,8 @@ export default function HighlightBand({ coords, background, label, children, })
36
45
  transform: `translateX(${coords.left}px)`,
37
46
  width: coords.width,
38
47
  background,
48
+ ...(gaps?.length
49
+ ? { maskImage: gapMask(gaps), WebkitMaskImage: gapMask(gaps) }
50
+ : undefined),
39
51
  }, children: coords.width > 3 && content ? (_jsx("div", { className: classes.overlay, children: content })) : null }));
40
52
  }
@@ -1,9 +1,8 @@
1
1
  import type { MenuItem } from '@jbrowse/core/ui';
2
2
  import type { Colord } from '@jbrowse/core/util/colord';
3
- export default function HighlightChip({ color, label, tooltip, menuItems, setOpen, }: {
3
+ export default function HighlightChip({ color, label, tooltip, menuItems, }: {
4
4
  color: Colord;
5
5
  label?: string;
6
6
  tooltip?: string;
7
7
  menuItems: MenuItem[];
8
- setOpen?: (arg: boolean) => void;
9
8
  }): import("react").JSX.Element;
@@ -2,14 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
3
3
  import LinkIcon from '@mui/icons-material/Link';
4
4
  import { Box, Tooltip, Typography } from '@mui/material';
5
- // Interactive chip drawn inside a highlight band while the band is revealing it
6
- // (see `useHighlightChip`): a link icon tinted to the band color plus an
7
- // optional inline label, wrapped in a context menu. Sets its own pointer-events
8
- // since the band is click-through. `setOpen` is how the band learns to keep the
9
- // chip drawn while the menu is up.
10
- export default function HighlightChip({ color, label, tooltip, menuItems, setOpen, }) {
5
+ // Interactive chip drawn inside a highlight band: a link icon tinted to the
6
+ // band color plus an optional inline label, wrapped in a context menu. Sets its
7
+ // own pointer-events since the band is click-through.
8
+ export default function HighlightChip({ color, label, tooltip, menuItems, }) {
11
9
  // hide the icon color when the band is fully transparent ("label-only"
12
10
  // highlight); otherwise bump to 0.8 alpha so the chip stays legible
13
11
  const chipAlpha = color.alpha() === 0 ? 0 : 0.8;
14
- return (_jsx(Box, { sx: { pointerEvents: 'auto' }, children: _jsx(CascadingMenuButton, { "data-testid": "highlight-chip", menuItems: menuItems, setOpen: setOpen, children: _jsx(Tooltip, { title: tooltip, arrow: true, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [_jsx(LinkIcon, { fontSize: "small", sx: { color: color.alpha(chipAlpha).toRgbString() } }), label ? (_jsx(Typography, { variant: "caption", noWrap: true, children: label })) : null] }) }) }) }));
12
+ return (_jsx(Box, { sx: { pointerEvents: 'auto' }, children: _jsx(CascadingMenuButton, { "data-testid": "highlight-chip", menuItems: menuItems, children: _jsx(Tooltip, { title: tooltip, arrow: true, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [_jsx(LinkIcon, { fontSize: "small", sx: { color: color.alpha(chipAlpha).toRgbString() } }), label ? (_jsx(Typography, { variant: "caption", noWrap: true, children: label })) : null] }) }) }) }));
15
13
  }
@@ -6,9 +6,9 @@ const useStyles = makeStyles()(theme => ({
6
6
  highlight: {
7
7
  height: '100%',
8
8
  position: 'absolute',
9
- background: alpha(theme.palette.primary.main, 0.4),
10
- borderLeft: `2px solid ${theme.palette.primary.main}`,
11
- borderRight: `2px solid ${theme.palette.primary.main}`,
9
+ background: alpha(theme.palette.accent, 0.4),
10
+ borderLeft: `2px solid ${theme.palette.accent}`,
11
+ borderRight: `2px solid ${theme.palette.accent}`,
12
12
  pointerEvents: 'none',
13
13
  zIndex: 10,
14
14
  },
@@ -84,12 +84,12 @@ const LinearGenomeViewImportForm = observer(function LinearGenomeViewImportForm(
84
84
  // reason.
85
85
  model.setError(undefined);
86
86
  setSelectedAssemblyName(val);
87
- }, session: session, selected: selectedAsm }), selectedAsm ? (assemblyError ? (_jsx(CloseIcon, { color: "error" })) : regions ? (_jsx(RefNameAutocomplete, { fetchResults: (queryString, stopToken) => fetchResults({
87
+ }, session: session, selected: selectedAsm }), selectedAsm ? (assemblyError ? (_jsx(CloseIcon, { color: "error" })) : regions ? (_jsx(RefNameAutocomplete, { fetchResults: (queryString, signal) => fetchResults({
88
88
  queryString,
89
89
  assembly,
90
90
  textSearchManager,
91
91
  assemblyName: selectedAsm,
92
- stopToken,
92
+ signal,
93
93
  }), session: session, assemblyName: selectedAsm, value: value, minWidth: 270, adornmentWidth: adornmentReservePx({
94
94
  menuItemCount: recentMenuItems.length,
95
95
  }), onChange: v => {
@@ -6,9 +6,9 @@ import LinearGenomeViewContainer from './LinearGenomeViewContainer.js';
6
6
  // lazies
7
7
  const ImportForm = lazy(() => import('./ImportForm.js'));
8
8
  const LinearGenomeView = observer(function LinearGenomeView({ model, }) {
9
- const { showLoading, showImportForm, loadingMessage, loadingProgress } = model;
10
- if (showLoading) {
11
- return (_jsx(ViewLoadingScreen, { message: loadingMessage, fraction: loadingProgress, source: model.loadingSource }));
9
+ const { loading, showImportForm } = model;
10
+ if (loading) {
11
+ return _jsx(ViewLoadingScreen, { ...loading });
12
12
  }
13
13
  else if (showImportForm) {
14
14
  return _jsx(ImportForm, { model: model });
@@ -7,13 +7,12 @@ import { makeStyles } from '@jbrowse/core/util/tss-react';
7
7
  import { useWheelZoom } from '@jbrowse/core/util/usePanZoom';
8
8
  import Paper from '@mui/material/Paper';
9
9
  import { observer } from 'mobx-react';
10
- import { SCALE_BAR_HEIGHT } from '../consts.js';
11
10
  import { stickyChromeTops } from '../stickyChrome.js';
12
11
  import Header from './Header.js';
13
12
  import MiniControls from './MiniControls.js';
14
13
  import NavigationAnnouncer from './NavigationAnnouncer.js';
14
+ import ResizeAllTracksHandle from './ResizeAllTracksHandle.js';
15
15
  import Rubberband from './Rubberband.js';
16
- import Scalebar from './Scalebar.js';
17
16
  import TrackContainer from './TrackContainer.js';
18
17
  import TracksContainer from './TracksContainer.js';
19
18
  // lazies
@@ -105,7 +104,7 @@ const LinearGenomeViewContainer = observer(function LinearGenomeViewContainer({
105
104
  .map(d => d.hoveredFeature)
106
105
  .find(Boolean);
107
106
  session.setHovered({ hoverPosition, hoverFeature });
108
- }, children: [_jsx(NavigationAnnouncer, { model: model }), _jsxs("div", { ref: headerRef, className: classes.header, style: { position: stickyViewHeaders ? 'sticky' : undefined }, children: [_jsx(Header, { model: model }), hideHeader ? _jsx(MiniControls, { model: model }) : null] }), _jsx("div", { ref: tracksRef, children: model.scalebarOnly ? (_jsx(Rubberband, { model: model, ControlComponent: _jsx(Scalebar, { model: model, style: { height: SCALE_BAR_HEIGHT, boxSizing: 'border-box' } }) })) : (_jsx(TracksContainer, { model: model, children: !tracks.length ? (_jsx(Suspense, { fallback: null, children: _jsx(NoTracksActiveButton, { model: model }) })) : (_jsxs(_Fragment, { children: [pinnedTracks.length ? (_jsx(Paper, { elevation: 6, className: classes.pinnedTracks, style: {
107
+ }, children: [_jsx(NavigationAnnouncer, { model: model }), _jsxs("div", { ref: headerRef, "data-testid": `lgv-header-${model.id}`, className: classes.header, style: { position: stickyViewHeaders ? 'sticky' : undefined }, children: [_jsx(Header, { model: model }), hideHeader ? _jsx(MiniControls, { model: model }) : null] }), _jsx("div", { ref: tracksRef, children: model.scalebarOnly ? (_jsx(Rubberband, { model: model })) : (_jsx(TracksContainer, { model: model, children: !tracks.length ? (_jsx(Suspense, { fallback: null, children: _jsx(NoTracksActiveButton, { model: model }) })) : (_jsxs(_Fragment, { children: [pinnedTracks.length ? (_jsx(Paper, { elevation: 2, "data-testid": "pinned-tracks", className: classes.pinnedTracks, style: {
109
108
  top: stickyTops.pinnedTracks,
110
109
  // the scroll port this sticks in, not the window: it is
111
110
  // under the app bar in the classic stack, a dockview
@@ -113,6 +112,6 @@ const LinearGenomeViewContainer = observer(function LinearGenomeViewContainer({
113
112
  // The fallback is what an unbounded embed gets, where
114
113
  // the page itself is the scroller
115
114
  maxHeight: `calc(var(${SCROLL_PORT_HEIGHT_VAR}, 100vh) - ${stickyTops.pinnedTracks})`,
116
- }, children: pinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id))) })) : null, unpinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id)))] })) })) })] }) }));
115
+ }, children: pinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id))) })) : null, unpinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id))), _jsx(ResizeAllTracksHandle, { model: model })] })) })) })] }) }));
117
116
  });
118
117
  export default LinearGenomeViewContainer;
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
3
3
  import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons';
4
+ import { alpha } from '@jbrowse/core/ui/palette';
4
5
  import { getSession } from '@jbrowse/core/util';
5
6
  import { makeStyles } from '@jbrowse/core/util/tss-react';
6
7
  import AddIcon from '@mui/icons-material/Add';
7
8
  import MoreVertIcon from '@mui/icons-material/MoreVert';
8
9
  import RemoveIcon from '@mui/icons-material/Remove';
9
- import { IconButton, Paper, Tooltip, alpha } from '@mui/material';
10
+ import { IconButton, Paper, Tooltip } from '@mui/material';
10
11
  import { observer } from 'mobx-react';
11
12
  import ZoomButton from './ZoomButton.js';
12
13
  const useStyles = makeStyles()(theme => ({
@@ -27,7 +28,7 @@ const MiniControls = observer(function MiniControls({ model, }) {
27
28
  const { focusedViewId } = getSession(model);
28
29
  return (_jsx(Paper, { className: classes.background, children: _jsxs(Paper, { className: focusedViewId === id ? classes.focusedBackground : undefined, children: [_jsx(Tooltip, { title: "Open track selector", children: _jsx(IconButton, { size: "small", onClick: () => {
29
30
  model.activateTrackSelector();
30
- }, children: _jsx(TrackSelectorIcon, { fontSize: "small" }) }) }), _jsx(CascadingMenuButton, { menuItems: () => model.menuItems(), children: _jsx(MoreVertIcon, { fontSize: "small" }) }), _jsx(Tooltip, { title: scalebarOnly ? 'Expand tracks' : 'Collapse to ruler', children: _jsx(IconButton, { size: "small", onClick: () => {
31
+ }, children: _jsx(TrackSelectorIcon, { fontSize: "small" }) }) }), _jsx(CascadingMenuButton, { menuItems: () => model.menuItems(), children: _jsx(MoreVertIcon, { fontSize: "small" }) }), _jsx(Tooltip, { title: scalebarOnly ? 'Show tracks' : 'Show ruler only', children: _jsx(IconButton, { size: "small", onClick: () => {
31
32
  model.setScalebarOnly(!scalebarOnly);
32
33
  }, children: scalebarOnly ? (_jsx(AddIcon, { fontSize: "small" })) : (_jsx(RemoveIcon, { fontSize: "small" })) }) }), _jsx(ZoomButton, { model: model, direction: "out", small: true }), _jsx(ZoomButton, { model: model, direction: "in", small: true })] }) }));
33
34
  });
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useStyleTheme } from '@jbrowse/core/ui/PaletteContext';
2
3
  import { getSession, notEmpty } from '@jbrowse/core/util';
3
4
  import { colord } from '@jbrowse/core/util/colord';
4
- import { useTheme } from '@mui/material';
5
5
  import { observer } from 'mobx-react';
6
6
  import OverviewHighlightBand from './OverviewHighlightBand.js';
7
7
  import { getHighlightColor, highlightKey } from './util.js';
8
8
  const OverviewHighlight = observer(function OverviewHighlight({ model, }) {
9
- const theme = useTheme();
9
+ const theme = useStyleTheme();
10
10
  const themed = colord(theme.palette.highlight.main);
11
11
  // gate on highlightsVisible to match the main-view band, scalebar band, and
12
12
  // SVG export — otherwise "Turn off highlights" leaves the overview bands up
13
13
  return getSession(model).highlightsVisible
14
- ? model.highlight
14
+ ? model.highlights
15
15
  .map(highlight => {
16
16
  const coords = model.getOverviewHighlightCoords(highlight);
17
17
  return coords ? { coords, highlight } : undefined;
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { makeStyles } from '@jbrowse/core/util/tss-react';
3
3
  import { Tooltip } from '@mui/material';
4
- // Renders a single absolute-positioned band over the overview scalebar. Used
5
- // for both LGV `view.highlight` entries and grid-bookmark bookmark highlights.
6
- // The 1px border keeps very narrow bands visible.
4
+ // A single absolute-positioned band over the overview scalebar. The 1px border
5
+ // keeps very narrow bands visible.
7
6
  const useStyles = makeStyles()({
8
7
  highlight: {
9
8
  height: '100%',
@@ -1,10 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
2
+ import { useRef, useState } from 'react';
3
3
  import { getNotificationSink, stringify } from '@jbrowse/core/util';
4
4
  import { getRelativeX } from '@jbrowse/core/util/getRelativeX';
5
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
6
6
  import { observer } from 'mobx-react';
7
7
  import RubberbandSpan from '../../shared/RubberbandSpan.js';
8
+ import { useWindowDrag } from '../../shared/useWindowDrag.js';
8
9
  import OverviewRubberbandHoverTooltip from './OverviewRubberbandHoverTooltip.js';
9
10
  import { overviewPxToBp } from './util.js';
10
11
  const useStyles = makeStyles()({
@@ -25,57 +26,31 @@ const OverviewRubberband = observer(function OverviewRubberband({ model, overvie
25
26
  const controlsRef = useRef(null);
26
27
  const { classes } = useStyles();
27
28
  const mouseDragging = startX !== undefined;
28
- useEffect(() => {
29
- const el = controlsRef.current;
30
- if (!mouseDragging || !el) {
31
- return;
32
- }
33
- // the container's left edge is fixed for the duration of a drag, so measure
34
- // it once here rather than calling getBoundingClientRect on every mousemove
35
- const { left } = el.getBoundingClientRect();
36
- function globalMouseMove(event) {
37
- setCurrentX(event.clientX - left);
38
- }
39
- function globalMouseUp(event) {
40
- // read the up position from the event so currentX state doesn't need to
41
- // be a dep (which would re-subscribe these listeners every mousemove)
42
- if (startX !== undefined) {
43
- const offsetX = event.clientX - left;
44
- if (Math.abs(offsetX - startX) > 3) {
45
- const leftPx = Math.min(startX, offsetX);
46
- const rightPx = Math.max(startX, offsetX);
47
- model.moveTo(overviewPxToBp(overview, leftPx, cytobandOffset), overviewPxToBp(overview, rightPx, cytobandOffset));
29
+ useWindowDrag(controlsRef, startX, {
30
+ onMove: setCurrentX,
31
+ onEnd: ({ startX, endX, isClick }) => {
32
+ if (!isClick) {
33
+ model.moveTo(overviewPxToBp(overview, Math.min(startX, endX), cytobandOffset), overviewPxToBp(overview, Math.max(startX, endX), cytobandOffset));
34
+ }
35
+ else {
36
+ const click = overviewPxToBp(overview, startX, cytobandOffset);
37
+ if (click.refName) {
38
+ model.centerAt(click.coord0, click.refName, click.index);
48
39
  }
49
40
  else {
50
- const click = overviewPxToBp(overview, startX, cytobandOffset);
51
- if (click.refName) {
52
- model.centerAt(click.coord0, click.refName, click.index);
53
- }
54
- else {
55
- getNotificationSink(model).notify('unknown position clicked');
56
- console.error('unknown position clicked', click);
57
- }
41
+ getNotificationSink(model).notify('unknown position clicked');
42
+ console.error('unknown position clicked', click);
58
43
  }
59
44
  }
60
45
  setStartX(undefined);
61
46
  setCurrentX(undefined);
62
47
  setGuideX(undefined);
63
- }
64
- function globalKeyDown(event) {
65
- if (event.key === 'Escape') {
66
- setStartX(undefined);
67
- setCurrentX(undefined);
68
- }
69
- }
70
- window.addEventListener('mousemove', globalMouseMove);
71
- window.addEventListener('mouseup', globalMouseUp);
72
- window.addEventListener('keydown', globalKeyDown);
73
- return () => {
74
- window.removeEventListener('mousemove', globalMouseMove);
75
- window.removeEventListener('mouseup', globalMouseUp);
76
- window.removeEventListener('keydown', globalKeyDown);
77
- };
78
- }, [startX, mouseDragging, model, overview, cytobandOffset]);
48
+ },
49
+ onCancel: () => {
50
+ setStartX(undefined);
51
+ setCurrentX(undefined);
52
+ },
53
+ });
79
54
  function mouseDown(event) {
80
55
  event.preventDefault();
81
56
  event.stopPropagation();
@@ -1,8 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PluggableElements } from '@jbrowse/core/ui';
3
+ import { alpha } from '@jbrowse/core/ui/palette';
3
4
  import { getEnv, getSession } from '@jbrowse/core/util';
4
5
  import { cx, makeStyles } from '@jbrowse/core/util/tss-react';
5
- import { Typography, alpha, useTheme } from '@mui/material';
6
+ import { Typography } from '@mui/material';
6
7
  import { observer } from 'mobx-react';
7
8
  import { HEADER_BAR_HEIGHT, HEADER_OVERVIEW_HEIGHT } from '../consts.js';
8
9
  import { REF_NAME_LABEL_FONT_SIZE, getBlockRefName, showRefNameLabels, } from '../util.js';
@@ -89,8 +90,7 @@ const useStyles = makeStyles()(theme => ({
89
90
  },
90
91
  }));
91
92
  const OverviewBox = observer(function OverviewBox({ model, block, showRefName, }) {
92
- const { classes } = useStyles();
93
- const theme = useTheme();
93
+ const { classes, theme } = useStyles();
94
94
  const { cytobandOffset, effectiveShowCytobands, overviewLayout: overview, } = model;
95
95
  const { reversed, refName, assemblyName } = block;
96
96
  const { assemblyManager } = getSession(model);
@@ -120,8 +120,7 @@ const OverviewBox = observer(function OverviewBox({ model, block, showRefName, }
120
120
  }, children: [showRefName ? (_jsx(Typography, { style: { color: refNameColor, left: 3 }, className: classes.scalebarRefName, children: refName })) : null, _jsx(OverviewScalebarTickLabels, { model: model, block: block, refNameColor: refNameColor, showRefName: showRefName })] }));
121
121
  });
122
122
  const VisibleRegionBox = observer(function VisibleRegionBox({ model, }) {
123
- const { classes } = useStyles();
124
- const theme = useTheme();
123
+ const { classes, theme } = useStyles();
125
124
  const { effectiveShowCytobands, cytobandOffset, overviewRegionPxSpan: span, } = model;
126
125
  if (!span) {
127
126
  return null;
@@ -24,10 +24,12 @@ function trapezoidPoints(top, bottom, height) {
24
24
  // class computed once per theme (makeStyles memoizes) — an on-screen zoom frame
25
25
  // then does zero color parsing. SVG export can't carry a CSS class, so that path
26
26
  // serializes explicit fill/stroke attributes instead (see `exportSvg` below).
27
+ const FILL_OPACITY = 0.3;
28
+ const STROKE_OPACITY = 0.8;
27
29
  const useStyles = makeStyles()(theme => ({
28
30
  polygon: {
29
- fill: alpha(theme.palette.tertiary.light, 0.3),
30
- stroke: alpha(theme.palette.tertiary.light, 0.8),
31
+ fill: alpha(theme.palette.tertiary.light, FILL_OPACITY),
32
+ stroke: alpha(theme.palette.tertiary.light, STROKE_OPACITY),
31
33
  },
32
34
  }));
33
35
  /**
@@ -57,6 +59,6 @@ const OverviewScalebarPolygon = observer(function OverviewScalebarPolygon({ mode
57
59
  const top = transformPxSpan(extent, bpPerPx / overview.bpPerPx, overviewOffsetPx);
58
60
  const bottom = transformPxSpan(extent, 1, -offsetPx);
59
61
  const points = trapezoidPoints(top, bottom, HEADER_BAR_HEIGHT);
60
- return exportSvg ? (_jsx("polygon", { points: points, ...getFillProps(alpha(theme.palette.tertiary.light, 0.3)), ...getStrokeProps(alpha(theme.palette.tertiary.light, 0.8)) })) : (_jsx("polygon", { points: points, className: classes.polygon }));
62
+ return exportSvg ? (_jsx("polygon", { points: points, ...getFillProps(alpha(theme.palette.tertiary.light, FILL_OPACITY)), ...getStrokeProps(alpha(theme.palette.tertiary.light, STROKE_OPACITY)) })) : (_jsx("polygon", { points: points, className: classes.polygon }));
61
63
  });
62
64
  export default OverviewScalebarPolygon;
@@ -3,5 +3,5 @@ type LGV = LinearGenomeViewModel;
3
3
  declare const PaddingBlocks: ({ model, offset, }: {
4
4
  model: LGV;
5
5
  offset?: number;
6
- }) => import("react").JSX.Element;
6
+ }) => import("react").JSX.Element | null;
7
7
  export default PaddingBlocks;
@@ -16,15 +16,10 @@ const useStyles = makeStyles()(theme => ({
16
16
  boundaryBlock: {
17
17
  background: theme.palette.action.disabledBackground,
18
18
  },
19
+ // opaque, since a translucent fill would darken unevenly where the
20
+ // container-level and per-track PaddingBlocks overlap
19
21
  regionSeparator: {
20
- // opaque (not text.disabled, which is translucent): regions are now laid
21
- // out contiguously so the separator paints directly over track data on both
22
- // sides. A translucent fill would tint the data instead of masking it, and
23
- // would darken unevenly where the container-level and per-track
24
- // PaddingBlocks overlap. An opaque grey masks cleanly and stays seamless.
25
- background: theme.palette.mode === 'dark'
26
- ? theme.palette.grey[500]
27
- : theme.palette.grey[600],
22
+ background: theme.palette.regionSeparator,
28
23
  },
29
24
  elided: {
30
25
  ...elidedBlockStyles,
@@ -41,11 +36,21 @@ const PaddingBlocks = observer(function PaddingBlocks({ model, offset = 0, }) {
41
36
  // the geometry is `model.paddingSpans` -- shared with any host drawing this
42
37
  // itself, so a seam here and a seam in an embedder's own chrome can't be
43
38
  // computed two different ways. This file owns only what the spans look like.
39
+ const spans = model.paddingSpans;
40
+ // Nothing to mask, so no positioned container to hold it — the common case,
41
+ // since a view sitting inside one contig has no seam, elision or boundary.
42
+ // The wrapper is not free: `ZoomTransform` reads `staticBlocks`, so an empty
43
+ // one still re-rendered and rewrote its transform on every gesture frame, per
44
+ // track. The view returns one shared array here, so this bails without even
45
+ // re-rendering.
46
+ if (spans.length === 0) {
47
+ return null;
48
+ }
44
49
  const kindClass = {
45
50
  seam: classes.regionSeparator,
46
51
  elided: classes.elided,
47
52
  boundary: classes.boundaryBlock,
48
53
  };
49
- return (_jsx(ZoomTransform, { model: model, offset: offset, children: _jsx("div", { className: classes.absoluteFill, children: model.paddingSpans.map(({ key, x, width, kind }) => (_jsx("div", { className: cx(classes.block, kindClass[kind]), style: { transform: `translateX(${x}px)`, width } }, key))) }) }));
54
+ return (_jsx(ZoomTransform, { model: model, offset: offset, children: _jsx("div", { className: classes.absoluteFill, children: spans.map(({ x, width, kind }, i) => (_jsx("div", { className: cx(classes.block, kindClass[kind]), style: { transform: `translateX(${x}px)`, width } }, i))) }) }));
50
55
  });
51
56
  export default PaddingBlocks;
@@ -1,20 +1,19 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, lazy } from 'react';
3
2
  import { Menu } from '@jbrowse/core/ui';
4
3
  import { getBpDisplayStr, stringify } from '@jbrowse/core/util';
5
4
  import { observer } from 'mobx-react';
5
+ import RubberbandSpan from '../../shared/RubberbandSpan.js';
6
6
  import { stickyChromeTops } from '../stickyChrome.js';
7
7
  import VerticalGuide from './VerticalGuide.js';
8
- const RubberbandSpan = lazy(() => import('../../shared/RubberbandSpan.js'));
9
8
  const RangeSelectOverlay = observer(function RangeSelectOverlay({ model, range, menuOffsetX = 0, }) {
10
9
  const { stickyViewHeaders, headerHeight, isScalebarRefNameMenuOpen } = model;
11
10
  const { scalebar } = stickyChromeTops({ stickyViewHeaders, headerHeight });
12
- const { guideX, rubberbandOn, rubberband, anchorPosition, open, isClick, clickBpOffset, handleMenuItemClick, handleClose, } = range;
13
- return (_jsxs(_Fragment, { children: [guideX !== undefined && !isScalebarRefNameMenuOpen ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn && rubberband ? (_jsx(Suspense, { fallback: null, children: _jsx(RubberbandSpan, { left: rubberband.left, width: rubberband.width, viewWidth: model.width, stickyTop: scalebar, leftLabel: stringify(rubberband.leftBpOffset), rightLabel: stringify(rubberband.rightBpOffset), size: getBpDisplayStr(rubberband.numOfBpSelected) }) })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
11
+ const { guideX, rubberband, anchorPosition, isClick, handleMenuItemClick, handleClose, } = range;
12
+ return (_jsxs(_Fragment, { children: [guideX !== undefined && !isScalebarRefNameMenuOpen ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberband && !isClick ? (_jsx(RubberbandSpan, { left: rubberband.left, width: rubberband.width, viewWidth: model.width, stickyTop: scalebar, leftLabel: stringify(rubberband.leftBpOffset), rightLabel: stringify(rubberband.rightBpOffset), size: getBpDisplayStr(rubberband.numOfBpSelected) })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
14
13
  left: anchorPosition.clientX + menuOffsetX,
15
14
  top: anchorPosition.clientY,
16
- }, onMenuItemClick: handleMenuItemClick, open: open, onClose: handleClose, menuItems: isClick && clickBpOffset
17
- ? model.rubberbandClickMenuItems(clickBpOffset)
15
+ }, onMenuItemClick: handleMenuItemClick, open: true, onClose: handleClose, menuItems: isClick
16
+ ? model.rubberbandClickMenuItems(model.pxToBp(anchorPosition.offsetX))
18
17
  : model.rubberBandMenuItems() })) : null] }));
19
18
  });
20
19
  export default RangeSelectOverlay;
@@ -0,0 +1,5 @@
1
+ import type { LinearGenomeViewModel } from '../index.ts';
2
+ declare const ResizeAllTracksHandle: ({ model, }: {
3
+ model: LinearGenomeViewModel;
4
+ }) => import("react").JSX.Element;
5
+ export default ResizeAllTracksHandle;