@jbrowse/plugin-linear-genome-view 5.0.0-beta.2 → 5.0.0-beta.20

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 (177) hide show
  1. package/esm/LinearGenomeView/afterAttach.d.ts +22 -5
  2. package/esm/LinearGenomeView/afterAttach.js +129 -106
  3. package/esm/LinearGenomeView/axisConfigSchema.d.ts +18 -0
  4. package/esm/LinearGenomeView/axisConfigSchema.js +22 -0
  5. package/esm/LinearGenomeView/components/CenterLine.js +10 -5
  6. package/esm/LinearGenomeView/components/ConnectedHoverHighlight.js +2 -3
  7. package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
  8. package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +9 -4
  9. package/esm/LinearGenomeView/components/ExportSvgDialog.js +45 -8
  10. package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
  11. package/esm/LinearGenomeView/components/Header.js +11 -1
  12. package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
  13. package/esm/LinearGenomeView/components/HeaderPanControls.d.ts +3 -3
  14. package/esm/LinearGenomeView/components/HeaderPanControls.js +6 -3
  15. package/esm/LinearGenomeView/components/HeaderSearchBoxes.js +4 -1
  16. package/esm/LinearGenomeView/components/HeaderZoomControls.js +6 -35
  17. package/esm/LinearGenomeView/components/Highlight.js +27 -11
  18. package/esm/LinearGenomeView/components/HighlightBand.d.ts +11 -2
  19. package/esm/LinearGenomeView/components/HighlightBand.js +32 -13
  20. package/esm/LinearGenomeView/components/HighlightChip.d.ts +3 -3
  21. package/esm/LinearGenomeView/components/HighlightChip.js +13 -8
  22. package/esm/LinearGenomeView/components/HighlightLabelDialog.d.ts +6 -0
  23. package/esm/LinearGenomeView/components/HighlightLabelDialog.js +18 -0
  24. package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
  25. package/esm/LinearGenomeView/components/ImportForm.js +7 -9
  26. package/esm/LinearGenomeView/components/LinearGenomeView.js +5 -12
  27. package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +13 -14
  28. package/esm/LinearGenomeView/components/MiniControls.js +11 -5
  29. package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
  30. package/esm/LinearGenomeView/components/OverviewHighlightBand.d.ts +3 -2
  31. package/esm/LinearGenomeView/components/OverviewHighlightBand.js +6 -5
  32. package/esm/LinearGenomeView/components/OverviewRubberband.js +25 -48
  33. package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
  34. package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
  35. package/esm/LinearGenomeView/components/PaddingBlocks.js +3 -8
  36. package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
  37. package/esm/LinearGenomeView/components/RegionWidthEditorDialog.d.ts +3 -2
  38. package/esm/LinearGenomeView/components/RegionWidthEditorDialog.js +4 -4
  39. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
  40. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +74 -0
  41. package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
  42. package/esm/LinearGenomeView/components/Rubberband.js +3 -2
  43. package/esm/LinearGenomeView/components/SVGHighlightBand.d.ts +10 -1
  44. package/esm/LinearGenomeView/components/SVGHighlightBand.js +16 -5
  45. package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
  46. package/esm/LinearGenomeView/components/Scalebar.js +8 -5
  47. package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +51 -36
  48. package/esm/LinearGenomeView/components/SearchBox.js +10 -16
  49. package/esm/LinearGenomeView/components/SearchPanelForm.d.ts +3 -2
  50. package/esm/LinearGenomeView/components/SearchPanelForm.js +4 -2
  51. package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +4 -8
  52. package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -4
  53. package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +4 -7
  54. package/esm/LinearGenomeView/components/SearchResultsTable.js +25 -53
  55. package/esm/LinearGenomeView/components/SequenceFeatureHoverHighlight.js +2 -3
  56. package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
  57. package/esm/LinearGenomeView/components/StrandCheckboxes.d.ts +3 -2
  58. package/esm/LinearGenomeView/components/StrandCheckboxes.js +4 -2
  59. package/esm/LinearGenomeView/components/TrackContainer.d.ts +2 -3
  60. package/esm/LinearGenomeView/components/TrackContainer.js +63 -10
  61. package/esm/LinearGenomeView/components/TrackLabel.js +14 -4
  62. package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
  63. package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +4 -5
  64. package/esm/LinearGenomeView/components/TrackLabelMenu.js +11 -14
  65. package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.d.ts +3 -4
  66. package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.js +23 -10
  67. package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +6 -4
  68. package/esm/LinearGenomeView/components/TrackRenderingContainer.js +12 -24
  69. package/esm/LinearGenomeView/components/TracksContainer.js +11 -23
  70. package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
  71. package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
  72. package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
  73. package/esm/LinearGenomeView/components/fetchSequence.js +15 -7
  74. package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
  75. package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
  76. package/esm/LinearGenomeView/components/useRangeSelect.js +26 -61
  77. package/esm/LinearGenomeView/components/useSearchBoxPrefs.d.ts +3 -1
  78. package/esm/LinearGenomeView/components/useSearchBoxPrefs.js +4 -2
  79. package/esm/LinearGenomeView/components/useSideScroll.d.ts +17 -2
  80. package/esm/LinearGenomeView/components/useSideScroll.js +156 -102
  81. package/esm/LinearGenomeView/components/util.d.ts +4 -0
  82. package/esm/LinearGenomeView/components/util.js +4 -2
  83. package/esm/LinearGenomeView/consts.d.ts +2 -0
  84. package/esm/LinearGenomeView/consts.js +3 -1
  85. package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
  86. package/esm/LinearGenomeView/containingLgv.js +23 -0
  87. package/esm/LinearGenomeView/headerFit.d.ts +4 -2
  88. package/esm/LinearGenomeView/headerFit.js +20 -7
  89. package/esm/LinearGenomeView/index.d.ts +2 -7
  90. package/esm/LinearGenomeView/index.js +5 -7
  91. package/esm/LinearGenomeView/keyboardHandler.d.ts +8 -7
  92. package/esm/LinearGenomeView/keyboardHandler.js +61 -23
  93. package/esm/LinearGenomeView/launchKeys.d.ts +1 -1
  94. package/esm/LinearGenomeView/launchKeys.js +11 -6
  95. package/esm/LinearGenomeView/lazyDialogs.d.ts +16 -3
  96. package/esm/LinearGenomeView/lazyDialogs.js +1 -0
  97. package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
  98. package/esm/LinearGenomeView/linkedViewSync.js +27 -49
  99. package/esm/LinearGenomeView/menuItems.d.ts +16 -18
  100. package/esm/LinearGenomeView/menuItems.js +264 -164
  101. package/esm/LinearGenomeView/model.d.ts +1192 -560
  102. package/esm/LinearGenomeView/model.js +805 -590
  103. package/esm/LinearGenomeView/rExport/exportLinearView.d.ts +17 -0
  104. package/esm/LinearGenomeView/rExport/exportLinearView.js +117 -0
  105. package/esm/LinearGenomeView/rExport/rScript.d.ts +110 -0
  106. package/esm/LinearGenomeView/rExport/rScript.js +524 -0
  107. package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
  108. package/esm/LinearGenomeView/sharedScaleContainer.js +2 -12
  109. package/esm/LinearGenomeView/showFiles.d.ts +2 -0
  110. package/esm/LinearGenomeView/showFiles.js +19 -0
  111. package/esm/LinearGenomeView/showRegionsWithUndo.d.ts +1 -1
  112. package/esm/LinearGenomeView/showRegionsWithUndo.js +13 -5
  113. package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
  114. package/esm/LinearGenomeView/stickyChrome.js +5 -9
  115. package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
  116. package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
  117. package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
  118. package/esm/LinearGenomeView/svgcomponents/SVGHighlights.d.ts +3 -1
  119. package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +9 -9
  120. package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.d.ts +3 -1
  121. package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +5 -5
  122. package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +13 -18
  123. package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
  124. package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
  125. package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
  126. package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
  127. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +26 -0
  128. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
  129. package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +21 -13
  130. package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -5
  131. package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +7 -6
  132. package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +2 -3
  133. package/esm/LinearGenomeView/svgcomponents/SVGView.js +17 -3
  134. package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +24 -20
  135. package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +42 -29
  136. package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +74 -77
  137. package/esm/LinearGenomeView/svgcomponents/util.d.ts +28 -12
  138. package/esm/LinearGenomeView/svgcomponents/util.js +41 -29
  139. package/esm/LinearGenomeView/types.d.ts +13 -10
  140. package/esm/LinearGenomeView/types.js +0 -1
  141. package/esm/LinearGenomeView/util.d.ts +103 -46
  142. package/esm/LinearGenomeView/util.js +222 -170
  143. package/esm/MultiLevelRubberband/MultiLevelRubberband.js +9 -6
  144. package/esm/MultiLevelRubberband/index.d.ts +2 -0
  145. package/esm/MultiLevelRubberband/index.js +2 -0
  146. package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
  147. package/esm/MultiLevelRubberband/menuItems.js +52 -0
  148. package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
  149. package/esm/MultiLevelRubberband/rowLabel.js +27 -0
  150. package/esm/MultiLevelRubberband/types.d.ts +1 -0
  151. package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
  152. package/esm/MultiLevelRubberband/useRangeSelect.js +45 -59
  153. package/esm/TrackModifiers/index.d.ts +83 -0
  154. package/esm/TrackModifiers/index.js +231 -0
  155. package/esm/displayKitTests/perRegionTestEnv.d.ts +244 -68
  156. package/esm/displayKitTests/perRegionTestEnv.js +30 -26
  157. package/esm/index.d.ts +21 -99
  158. package/esm/index.js +17 -38
  159. package/esm/searchUtils.d.ts +26 -10
  160. package/esm/searchUtils.js +137 -137
  161. package/esm/shared/RubberbandSpan.d.ts +3 -2
  162. package/esm/shared/RubberbandSpan.js +6 -3
  163. package/esm/shared/coordLabels.d.ts +11 -4
  164. package/esm/shared/coordLabels.js +20 -5
  165. package/esm/shared/useWindowDrag.d.ts +18 -0
  166. package/esm/shared/useWindowDrag.js +47 -0
  167. package/package.json +12 -11
  168. package/esm/FeatureTrack/configSchema.d.ts +0 -124
  169. package/esm/FeatureTrack/configSchema.js +0 -54
  170. package/esm/FeatureTrack/index.d.ts +0 -2
  171. package/esm/FeatureTrack/index.js +0 -13
  172. package/esm/LinearGenomeView/initKeys.d.ts +0 -12
  173. package/esm/LinearGenomeView/initKeys.js +0 -68
  174. package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
  175. package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
  176. package/esm/lazyPluginExports.d.ts +0 -23
  177. package/esm/lazyPluginExports.js +0 -36
@@ -1,9 +1,9 @@
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
+ import { observer } from 'mobx-react';
5
+ // A single absolute-positioned band over the overview scalebar. The 1px border
6
+ // keeps very narrow bands visible.
7
7
  const useStyles = makeStyles()({
8
8
  highlight: {
9
9
  height: '100%',
@@ -11,7 +11,7 @@ const useStyles = makeStyles()({
11
11
  left: 0,
12
12
  },
13
13
  });
14
- export default function OverviewHighlightBand({ coords, background, borderColor, tooltip, }) {
14
+ const OverviewHighlightBand = observer(function OverviewHighlightBand({ coords, background, borderColor, tooltip, }) {
15
15
  const { classes } = useStyles();
16
16
  const band = (_jsx("div", { className: classes.highlight, style: {
17
17
  transform: `translateX(${coords.left}px)`,
@@ -23,4 +23,5 @@ export default function OverviewHighlightBand({ coords, background, borderColor,
23
23
  }),
24
24
  } }));
25
25
  return tooltip ? (_jsx(Tooltip, { title: tooltip, arrow: true, children: band })) : (band);
26
- }
26
+ });
27
+ export default OverviewHighlightBand;
@@ -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,61 +26,37 @@ 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
- event.preventDefault();
81
- event.stopPropagation();
82
- setStartX(getRelativeX(event, controlsRef.current));
55
+ if (event.button === 0) {
56
+ event.preventDefault();
57
+ event.stopPropagation();
58
+ setStartX(getRelativeX(event, controlsRef.current));
59
+ }
83
60
  }
84
61
  function mouseMove(event) {
85
62
  setGuideX(getRelativeX(event, controlsRef.current));
@@ -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;
@@ -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,
@@ -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;
@@ -1,5 +1,6 @@
1
1
  import type { LinearGenomeViewModel } from '../model.ts';
2
- export default function RegionWidthEditorDialog({ model, handleClose, }: {
2
+ declare const RegionWidthEditorDialog: ({ model, handleClose, }: {
3
3
  model: LinearGenomeViewModel;
4
4
  handleClose: () => void;
5
- }): import("react").JSX.Element;
5
+ }) => import("react").JSX.Element;
6
+ export default RegionWidthEditorDialog;
@@ -3,12 +3,11 @@ import { useState } from 'react';
3
3
  import { SubmitDialog } from '@jbrowse/core/ui';
4
4
  import { parseBpString, toLocale } from '@jbrowse/core/util';
5
5
  import { TextField, Typography } from '@mui/material';
6
+ import { observer } from 'mobx-react';
6
7
  function format(n) {
7
8
  return toLocale(Math.floor(n));
8
9
  }
9
- // not an observer: the initial value is seeded once and the field is
10
- // user-edited thereafter, so it shouldn't reactively reset if bpPerPx changes
11
- export default function RegionWidthEditorDialog({ model, handleClose, }) {
10
+ const RegionWidthEditorDialog = observer(function RegionWidthEditorDialog({ model, handleClose, }) {
12
11
  const [val, setVal] = useState(() => format(model.bpPerPx * model.width));
13
12
  const bp = parseBpString(val);
14
13
  const valid = bp !== undefined && bp > 0;
@@ -20,4 +19,5 @@ export default function RegionWidthEditorDialog({ model, handleClose, }) {
20
19
  }, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 30 }, children: [_jsx(Typography, { children: "Enter a specific number of base pairs to change the viewport to show, either in full or abbreviated as e.g. 500kb or 1.5Mbp. This is approximate and does not account for padding between regions or off-screen scrolling" }), _jsx(TextField, { label: "Zoom level (bp)", autoFocus: true, fullWidth: true, variant: "outlined", value: val, onChange: event => {
21
20
  setVal(event.target.value);
22
21
  } })] }) }));
23
- }
22
+ });
23
+ export default RegionWidthEditorDialog;
@@ -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;
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useLayoutEffect, useRef } from 'react';
3
+ import { ResizeHandle } from '@jbrowse/core/ui';
4
+ import { scrollPortOf } from '@jbrowse/core/util/hooks';
5
+ import { isAlive } from '@jbrowse/mobx-state-tree';
6
+ import { observer } from 'mobx-react';
7
+ import { RESIZE_ALL_HANDLE_HEIGHT } from '../consts.js';
8
+ function useScrollPortExcess(ref, model, enabled) {
9
+ useLayoutEffect(() => {
10
+ const box = ref.current?.closest('[data-testid^="view-container-"]') ??
11
+ ref.current?.closest('[data-testid^="linear-genome-view-"]');
12
+ if (!enabled || !box || !('ResizeObserver' in window)) {
13
+ return;
14
+ }
15
+ const port = scrollPortOf(box);
16
+ const measure = () => {
17
+ const { marginTop, marginBottom } = getComputedStyle(box);
18
+ const outer = box.getBoundingClientRect().height +
19
+ Number.parseFloat(marginTop) +
20
+ Number.parseFloat(marginBottom);
21
+ model.setScrollPortExcess(Math.round(outer - (port?.clientHeight ?? window.innerHeight)));
22
+ };
23
+ measure();
24
+ const observer = new ResizeObserver(measure);
25
+ observer.observe(box);
26
+ if (port) {
27
+ observer.observe(port);
28
+ }
29
+ else {
30
+ window.addEventListener('resize', measure);
31
+ }
32
+ return () => {
33
+ observer.disconnect();
34
+ window.removeEventListener('resize', measure);
35
+ if (isAlive(model)) {
36
+ model.setScrollPortExcess(undefined);
37
+ }
38
+ };
39
+ }, [ref, model, enabled]);
40
+ }
41
+ const ResizeAllTracksHandle = observer(function ResizeAllTracksHandle({ model, }) {
42
+ const ref = useRef(null);
43
+ const drag = useRef({ from: new Map() });
44
+ const { isTopLevelView } = model;
45
+ useScrollPortExcess(ref, model, isTopLevelView);
46
+ return (_jsx("div", { ref: ref, style: isTopLevelView
47
+ ? { position: 'sticky', bottom: 0, zIndex: 300 }
48
+ : { position: 'relative', height: 0, zIndex: 300 }, children: _jsx(ResizeHandle, { grip: isTopLevelView || 'hover', "data-testid": "resize-all-tracks", title: isTopLevelView
49
+ ? 'Drag to resize all tracks, double-click to fit them to the window'
50
+ : 'Drag to resize all tracks', style: isTopLevelView
51
+ ? { height: RESIZE_ALL_HANDLE_HEIGHT }
52
+ : {
53
+ height: RESIZE_ALL_HANDLE_HEIGHT,
54
+ position: 'absolute',
55
+ bottom: 0,
56
+ }, onDragStart: () => {
57
+ drag.current = { from: model.resizableTrackHeights };
58
+ for (const track of model.tracks) {
59
+ track.setResizing(true);
60
+ }
61
+ },
62
+ // no value, so the distance from the press, every track scaled from
63
+ // where it was
64
+ onChange: distance => {
65
+ model.resizeTracks(distance, drag.current.from);
66
+ }, onDragEnd: () => {
67
+ for (const track of model.tracks) {
68
+ track.setResizing(false);
69
+ }
70
+ }, onDoubleClick: () => {
71
+ model.fitTracksToWindow();
72
+ } }) }));
73
+ });
74
+ export default ResizeAllTracksHandle;
@@ -1,7 +1,6 @@
1
1
  import type { LinearGenomeViewModel } from '../index.ts';
2
2
  type LGV = LinearGenomeViewModel;
3
- declare const Rubberband: ({ model, ControlComponent, }: {
3
+ declare const Rubberband: ({ model }: {
4
4
  model: LGV;
5
- ControlComponent?: React.ReactElement;
6
5
  }) => import("react").JSX.Element;
7
6
  export default Rubberband;
@@ -4,6 +4,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react';
4
4
  import { observer } from 'mobx-react';
5
5
  import { stickyChromeTops } from '../stickyChrome.js';
6
6
  import RangeSelectOverlay from './RangeSelectOverlay.js';
7
+ import Scalebar from './Scalebar.js';
7
8
  import { useRangeSelect } from './useRangeSelect.js';
8
9
  const useStyles = makeStyles()({
9
10
  rubberbandControl: {
@@ -13,7 +14,7 @@ const useStyles = makeStyles()({
13
14
  zIndex: 825,
14
15
  },
15
16
  });
16
- const Rubberband = observer(function Rubberband({ model, ControlComponent = _jsx("div", {}), }) {
17
+ const Rubberband = observer(function Rubberband({ model }) {
17
18
  const ref = useRef(null);
18
19
  const { classes } = useStyles();
19
20
  const { stickyViewHeaders, headerHeight } = model;
@@ -24,6 +25,6 @@ const Rubberband = observer(function Rubberband({ model, ControlComponent = _jsx
24
25
  // (TracksContainer): mouseout bubbles from every child, so crossing a
25
26
  // refName or coordinate label inside the scalebar cleared the guide and
26
27
  // the next mousemove put it straight back
27
- onMouseLeave: range.mouseOut, children: ControlComponent })] }));
28
+ onMouseLeave: range.mouseOut, children: _jsx(Scalebar, { model: model }) })] }));
28
29
  });
29
30
  export default Rubberband;
@@ -1,9 +1,18 @@
1
- export default function SVGHighlightBand({ coords, height, color, label, labelColor, }: {
1
+ export interface BandGap {
2
+ top: number;
3
+ height: number;
4
+ }
5
+ export declare function spansAround(gaps: BandGap[], height: number): {
6
+ top: number;
7
+ height: number;
8
+ }[];
9
+ export default function SVGHighlightBand({ coords, height, gaps, color, label, labelColor, }: {
2
10
  coords: {
3
11
  left: number;
4
12
  width: number;
5
13
  };
6
14
  height: number;
15
+ gaps: BandGap[];
7
16
  color: string;
8
17
  label?: string;
9
18
  labelColor: string;
@@ -1,9 +1,20 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getFillProps } from '@jbrowse/core/util';
3
+ // The stretches of a band `height` tall left once the sorted, disjoint `gaps`
4
+ // are cut out of it.
5
+ export function spansAround(gaps, height) {
6
+ const edges = [0, ...gaps.flatMap(g => [g.top, g.top + g.height]), height];
7
+ return edges.flatMap((top, i) => {
8
+ const bottom = edges[i + 1];
9
+ return i % 2 === 0 && bottom !== undefined && bottom > top
10
+ ? [{ top, height: bottom - top }]
11
+ : [];
12
+ });
13
+ }
3
14
  // One full-height SVG highlight band with an optional label at the top,
4
- // mirroring the on-screen HighlightBand div. Shared by the LGV native-highlight
5
- // export (SVGHighlights) and the grid-bookmark export (LGVHighlightSVG). The
6
- // label is hidden on bands too narrow to fit it.
7
- export default function SVGHighlightBand({ coords, height, color, label, labelColor, }) {
8
- return (_jsxs(_Fragment, { children: [_jsx("rect", { x: coords.left, y: 0, width: coords.width, height: height, ...getFillProps(color) }), label && coords.width > 3 ? (_jsx("text", { x: coords.left + 3, y: 2, fontSize: 11, dominantBaseline: "hanging", ...getFillProps(labelColor), children: label })) : null] }));
15
+ // mirroring the on-screen HighlightBand div: a label wider than its band runs
16
+ // past the band's right edge, and the band leaves out `gaps`, the tracks that
17
+ // do not draw in genomic coordinates.
18
+ export default function SVGHighlightBand({ coords, height, gaps, color, label, labelColor, }) {
19
+ return (_jsxs(_Fragment, { children: [spansAround(gaps, height).map(span => (_jsx("rect", { x: coords.left, y: span.top, width: coords.width, height: span.height, ...getFillProps(color) }, span.top))), label ? (_jsx("text", { x: coords.left + 3, y: 2, fontSize: 11, dominantBaseline: "hanging", ...getFillProps(labelColor), children: label })) : null] }));
9
20
  }
@@ -1,10 +1,6 @@
1
1
  import type { LinearGenomeViewModel } from '../index.ts';
2
- import type React from 'react';
3
2
  type LGV = LinearGenomeViewModel;
4
- interface ScalebarProps {
3
+ declare const Scalebar: ({ model }: {
5
4
  model: LGV;
6
- style?: React.CSSProperties;
7
- className?: string;
8
- }
9
- declare const Scalebar: ({ model, style, className, }: ScalebarProps) => React.JSX.Element;
5
+ }) => import("react").JSX.Element;
10
6
  export default Scalebar;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cx, makeStyles } from '@jbrowse/core/util/tss-react';
2
+ import { makeStyles } from '@jbrowse/core/util/tss-react';
3
3
  import { Paper } from '@mui/material';
4
4
  import { observer } from 'mobx-react';
5
+ import { SCALE_BAR_HEIGHT } from '../consts.js';
5
6
  import Gridlines from './Gridlines.js';
6
7
  import PaddingBlocks from './PaddingBlocks.js';
7
8
  import ScalebarCoordinateLabels from './ScalebarCoordinateLabels.js';
@@ -14,15 +15,17 @@ const useStyles = makeStyles()({
14
15
  container: {
15
16
  overflow: 'clip',
16
17
  position: 'relative',
18
+ height: SCALE_BAR_HEIGHT,
19
+ boxSizing: 'border-box',
17
20
  },
18
21
  });
19
- const Scalebar = observer(function Scalebar({ model, style, className, }) {
22
+ const Scalebar = observer(function Scalebar({ model }) {
20
23
  const { classes } = useStyles();
21
24
  return (_jsxs(Paper
22
- // The rubberband owns presses on the scalebar (it wraps this as its
23
- // ControlComponent), so the view's click-drag pan must not also start one
25
+ // The rubberband owns presses on the scalebar (it wraps this), so the
26
+ // view's click-drag pan must not also start one
24
27
  // on the paths where the rubberband doesn't stopPropagation — a press with
25
28
  // the refName menu already open. See ResizeHandle for the marker contract.
26
- , { "data-gesture-owner": "true", className: cx(classes.container, className), variant: "outlined", style: style, children: [_jsx(Gridlines, { model: model, offset: 1 }), _jsx(PaddingBlocks, { model: model, offset: 1 }), _jsx(ScalebarCoordinateLabels, { model: model }), _jsx(ScalebarRefNameLabels, { model: model })] }));
29
+ , { "data-gesture-owner": "true", className: classes.container, variant: "outlined", children: [_jsx(Gridlines, { model: model, offset: 1 }), _jsx(PaddingBlocks, { model: model, offset: 1 }), _jsx(ScalebarCoordinateLabels, { model: model }), _jsx(ScalebarRefNameLabels, { model: model })] }));
27
30
  });
28
31
  export default Scalebar;