@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,11 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getContainingView } from '@jbrowse/core/util';
3
2
  import { makeStyles } from '@jbrowse/core/util/tss-react';
4
3
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
5
4
  import ArrowRightIcon from '@mui/icons-material/ArrowRight';
6
5
  import CloseIcon from '@mui/icons-material/Close';
7
6
  import { IconButton } from '@mui/material';
8
7
  import { observer } from 'mobx-react';
8
+ import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
9
9
  const useStyles = makeStyles()({
10
10
  iconButton: {
11
11
  padding: 0,
@@ -21,7 +21,7 @@ const useStyles = makeStyles()({
21
21
  // write it.
22
22
  export const TrackLabelCloseButton = observer(function TrackLabelCloseButton({ track, }) {
23
23
  const { classes } = useStyles();
24
- const view = getContainingView(track);
24
+ const view = containingLgv(track);
25
25
  return (_jsx(IconButton, { onClick: () => view.hideTrack(track.trackId), className: classes.iconButton, title: "close this track", "data-testid": `track-close-${track.trackId}`, children: _jsx(CloseIcon, { fontSize: "small" }) }));
26
26
  });
27
27
  export const TrackLabelMinimizeButton = observer(function TrackLabelMinimizeButton({ track }) {
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getContainingView } from '@jbrowse/core/util';
3
2
  import { makeStyles } from '@jbrowse/core/util/tss-react';
4
3
  import DragIcon from '@mui/icons-material/DragIndicator';
5
4
  import { observer } from 'mobx-react';
5
+ import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
6
6
  const useStyles = makeStyles()({
7
7
  dragHandle: {
8
8
  cursor: 'grab',
@@ -15,12 +15,11 @@ const useStyles = makeStyles()({
15
15
  });
16
16
  const TrackLabelDragHandle = observer(function TrackLabelDragHandle({ track, }) {
17
17
  const { classes } = useStyles();
18
- const view = getContainingView(track);
18
+ const view = containingLgv(track);
19
19
  const trackId = track.trackId;
20
20
  return (_jsx("span", { draggable: true, className: classes.dragHandle, onDragStart: event => {
21
- const target = event.currentTarget;
22
- if (target.parentNode) {
23
- const parent = target.parentNode;
21
+ const parent = event.currentTarget.parentElement;
22
+ if (parent) {
24
23
  event.dataTransfer.setDragImage(parent, 20, 20);
25
24
  view.setDraggingTrackId(track.id);
26
25
  }
@@ -1,10 +1,12 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
3
- import { getContainingView, getSession } from '@jbrowse/core/util';
3
+ import { TRACK_MENU_PRIORITY, subMenuIfAny } from '@jbrowse/core/ui/menuItems';
4
+ import { getSession } from '@jbrowse/core/util';
4
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
5
6
  import LowPriorityIcon from '@mui/icons-material/LowPriority';
6
7
  import MoreVertIcon from '@mui/icons-material/MoreVert';
7
8
  import { observer } from 'mobx-react';
9
+ import { containingLgv } from '../../LinearGenomeView/containingLgv.js';
8
10
  import { getTrackOrderSubMenu } from './trackLabelMenuItems.js';
9
11
  // IconButton's default 5px padding made this the tallest thing in the label
10
12
  // (27px), so it, not the text or the other controls, set the label height and
@@ -17,7 +19,7 @@ const useStyles = makeStyles()({
17
19
  });
18
20
  const TrackLabelMenu = observer(function TrackLabelMenu({ track, }) {
19
21
  const { classes } = useStyles();
20
- const view = getContainingView(track);
22
+ const view = containingLgv(track);
21
23
  const session = getSession(track);
22
24
  function getMenuItems() {
23
25
  const orderSubMenu = getTrackOrderSubMenu({ view, track });
@@ -26,21 +28,16 @@ const TrackLabelMenu = observer(function TrackLabelMenu({ track, }) {
26
28
  view,
27
29
  }) ?? [];
28
30
  return [
29
- ...(orderSubMenu.length
30
- ? [
31
- {
32
- label: 'Track order',
33
- icon: LowPriorityIcon,
34
- type: 'subMenu',
35
- priority: 1000,
36
- subMenu: orderSubMenu,
37
- },
38
- ]
39
- : []),
31
+ ...subMenuIfAny({
32
+ label: 'Track order',
33
+ icon: LowPriorityIcon,
34
+ priority: TRACK_MENU_PRIORITY.trackOrder,
35
+ subMenu: orderSubMenu,
36
+ }),
40
37
  ...sessionItems,
41
38
  track.saveTrackDataMenuItem,
42
39
  ...track.trackMenuItems(),
43
- ].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
40
+ ];
44
41
  }
45
42
  return (_jsx(CascadingMenuButton, { menuItems: getMenuItems, className: classes.menuButton, "data-testid": "track_menu_icon", "data-trackid": track.trackId, tooltip: "Track settings", children: _jsx(MoreVertIcon, { fontSize: "small" }) }));
46
43
  });
@@ -1,9 +1,8 @@
1
1
  import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
2
2
  /**
3
- * The track label's warning for a file whose reference names have nothing in
4
- * common with the assembly's — the commonest data-configuration mistake in
5
- * JBrowse, and until now a silent one: the track draws nothing and reads
6
- * exactly like a track with no features in view.
3
+ * The track label's warning for a file that does not fit its assembly: its
4
+ * reference names have nothing in common with the assembly's, so the track
5
+ * draws nothing, or its contig lengths say it was made against another build.
7
6
  *
8
7
  * The label rather than the display chrome, deliberately. The chrome's states
9
8
  * are `displayPhase`'s, which are mutually exclusive and two of which replace
@@ -1,6 +1,6 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { refNameMismatchMessage } from '@jbrowse/core/assemblyManager/assembly';
3
+ import { contigLengthMismatchMessage, refNameMismatchMessage, } from '@jbrowse/core/assemblyManager/assembly';
4
4
  import { InfoDialog } from '@jbrowse/core/ui';
5
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
6
6
  import WarningIcon from '@mui/icons-material/Warning';
@@ -12,11 +12,24 @@ const useStyles = makeStyles()(theme => ({
12
12
  color: theme.palette.warning.main,
13
13
  },
14
14
  }));
15
+ function warningFor(track) {
16
+ const { refNameMismatch, contigLengthMismatch } = track;
17
+ return refNameMismatch
18
+ ? {
19
+ title: 'Reference names do not match the assembly',
20
+ message: refNameMismatchMessage(refNameMismatch),
21
+ }
22
+ : contigLengthMismatch
23
+ ? {
24
+ title: 'Reference sequence lengths do not match the assembly',
25
+ message: contigLengthMismatchMessage(contigLengthMismatch),
26
+ }
27
+ : undefined;
28
+ }
15
29
  /**
16
- * The track label's warning for a file whose reference names have nothing in
17
- * common with the assembly's — the commonest data-configuration mistake in
18
- * JBrowse, and until now a silent one: the track draws nothing and reads
19
- * exactly like a track with no features in view.
30
+ * The track label's warning for a file that does not fit its assembly: its
31
+ * reference names have nothing in common with the assembly's, so the track
32
+ * draws nothing, or its contig lengths say it was made against another build.
20
33
  *
21
34
  * The label rather than the display chrome, deliberately. The chrome's states
22
35
  * are `displayPhase`'s, which are mutually exclusive and two of which replace
@@ -32,15 +45,15 @@ const useStyles = makeStyles()(theme => ({
32
45
  const TrackLabelRefNameWarning = observer(function TrackLabelRefNameWarning({ track, }) {
33
46
  const { classes } = useStyles();
34
47
  const [open, setOpen] = useState(false);
35
- const { refNameMismatch } = track;
36
- if (!refNameMismatch) {
48
+ const warning = warningFor(track);
49
+ if (!warning) {
37
50
  return null;
38
51
  }
39
- const message = refNameMismatchMessage(refNameMismatch);
52
+ const { title, message } = warning;
40
53
  return (_jsxs(_Fragment, { children: [_jsx(IconButton, { onClick: () => {
41
54
  setOpen(true);
42
- }, className: classes.iconButton, title: message, "data-testid": `track-refname-warning-${track.trackId}`, children: _jsx(WarningIcon, { fontSize: "small" }) }), open ? (_jsxs(InfoDialog, { open: true, title: "Reference names do not match the assembly", onClose: () => {
55
+ }, className: classes.iconButton, title: message, "data-testid": `track-refname-warning-${track.trackId}`, children: _jsx(WarningIcon, { fontSize: "small" }) }), open ? (_jsxs(InfoDialog, { open: true, title: title, onClose: () => {
43
56
  setOpen(false);
44
- }, children: [_jsx(Typography, { children: message }), _jsx(Typography, { variant: "body2", style: { marginTop: 8 }, children: "The track menu's \"About track\" shows every reference name the file uses." })] })) : null] }));
57
+ }, children: [_jsx(Typography, { children: message }), _jsx(Typography, { variant: "body2", style: { marginTop: 8 }, children: "The track menu's \"About track\" shows every reference name the file uses, with the lengths it states." })] })) : null] }));
45
58
  });
46
59
  export default TrackLabelRefNameWarning;
@@ -1,8 +1,10 @@
1
- import type { LinearGenomeViewModel } from '../index.ts';
2
- import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
1
+ import type { LinearGenomeViewModel, LinearGenomeViewTrack } from '../index.ts';
2
+ import type { LinearDisplayModel } from '@jbrowse/display-kit/types';
3
3
  type LGV = LinearGenomeViewModel;
4
- declare const TrackRenderingContainer: ({ model, track, }: {
4
+ declare const TrackRenderingContainer: ({ model, track, display, ref, }: {
5
5
  model: LGV;
6
- track: BaseTrackModel;
6
+ track: LinearGenomeViewTrack;
7
+ display: LinearDisplayModel;
8
+ ref?: React.Ref<HTMLDivElement>;
7
9
  }) => import("react").JSX.Element;
8
10
  export default TrackRenderingContainer;
@@ -1,11 +1,12 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, useCallback } from 'react';
2
+ import { Suspense } from 'react';
3
3
  import { LoadingOverlay } from '@jbrowse/core/ui';
4
- import { getSession } from '@jbrowse/core/util';
4
+ import { coarseStripHTML, getSession } from '@jbrowse/core/util';
5
5
  import { getTrackName } from '@jbrowse/core/util/tracks';
6
6
  import { makeStyles } from '@jbrowse/core/util/tss-react';
7
+ import { TrackOverlayPortal } from '@jbrowse/display-ui';
7
8
  import { observer } from 'mobx-react';
8
- import { MINIMIZED_TRACK_HEIGHT } from '../consts.js';
9
+ import { TRACK_OUTLINE_BORDER } from '../consts.js';
9
10
  const useStyles = makeStyles()({
10
11
  // aligns with block boundaries. check for example the breakpoint split view
11
12
  // demo to see if features align if wanting to change things. the -1 left
@@ -17,7 +18,7 @@ const useStyles = makeStyles()({
17
18
  width: '100%',
18
19
  },
19
20
  // Tracks never scroll natively on this outer container — every display owns
20
- // its own vertical scroll: canvas displays scroll an inner sticky-canvas
21
+ // its own vertical scroll: feature displays scroll an inner sticky-canvas
21
22
  // container (FeatureComponent), while alignments and variants draw a custom
22
23
  // VerticalScrollbar overlay and redraw the canvas at `scrollTop`. A native
23
24
  // scroll port here only produced a *second*, spurious scrollbar whenever a
@@ -68,32 +69,19 @@ const useStyles = makeStyles()({
68
69
  // nothing. `figure` names the box and keeps what is inside it reachable. Revisit
69
70
  // if inline interactive chrome ever goes away.
70
71
  const TrackDisplayRegion = observer(function TrackDisplayRegion({ model, track, children, ...divProps }) {
71
- const trackName = getTrackName(track.configuration, getSession(track));
72
+ const trackName = coarseStripHTML(getTrackName(track.configuration, getSession(track)));
72
73
  const loc = model.coarseVisibleLocStrings;
73
74
  return (_jsx("div", { ...divProps, role: "figure", "aria-label": loc ? `${trackName} track, showing ${loc}` : `${trackName} track`, children: children }));
74
75
  });
75
- const TrackRenderingContainer = observer(function TrackRenderingContainer({ model, track, }) {
76
+ const TrackRenderingContainer = observer(function TrackRenderingContainer({ model, track, display, ref, }) {
76
77
  const { classes } = useStyles();
77
- // an LGV track always holds at least one linear display (activeDisplay =
78
- // displays[0]); narrow to the linear shape for height/RenderingComponent
79
- const display = track.activeDisplay;
80
- const { height, RenderingComponent, DisplayBlurb } = display;
81
- const { trackRefs, showTrackOutlines } = model;
78
+ const { RenderingComponent, DisplayBlurb } = display;
79
+ const { showTrackOutlines } = model;
82
80
  const trackId = track.trackId;
83
81
  const minimized = track.minimized;
84
- // callback ref keeps trackRefs in sync as the rendering div mounts/unmounts
85
- // (e.g. on minimize/restore), unlike a useEffect that misses the toggle
86
- const setRef = useCallback((el) => {
87
- if (el) {
88
- trackRefs[trackId] = el;
89
- }
90
- else {
91
- delete trackRefs[trackId];
92
- }
93
- }, [trackRefs, trackId]);
94
- return (_jsx("div", { className: classes.trackRenderingContainer, style: {
95
- height: minimized ? MINIMIZED_TRACK_HEIGHT : height,
96
- }, "data-testid": `trackRenderingContainer-${model.id}-${trackId}`, children: !minimized ? (_jsxs(_Fragment, { children: [_jsx(TrackDisplayRegion, { model: model, track: track, ref: setRef, className: classes.renderingComponentContainer, style: { left: showTrackOutlines ? -1 : 0 }, children: _jsx(Suspense, { fallback: _jsx(LoadingOverlay, { isVisible: true, immediate: true }), children: _jsx(RenderingComponent, { model: display, onHorizontalScroll: model.horizontalScroll }) }) }), DisplayBlurb ? (_jsx("div", { style: {
82
+ return (_jsx("div", { ref: ref, className: classes.trackRenderingContainer, style: {
83
+ height: model.trackHeight(track),
84
+ }, "data-testid": `trackRenderingContainer-${model.id}-${trackId}`, children: !minimized ? (_jsxs(_Fragment, { children: [_jsx(TrackDisplayRegion, { model: model, track: track, className: classes.renderingComponentContainer, style: { left: showTrackOutlines ? -TRACK_OUTLINE_BORDER : 0 }, children: _jsx(Suspense, { fallback: _jsx(TrackOverlayPortal, { children: _jsx(LoadingOverlay, { isVisible: true, immediate: true }) }), children: _jsx(RenderingComponent, { model: display, onHorizontalScroll: model.horizontalScroll }) }) }), DisplayBlurb ? (_jsx("div", { style: {
97
85
  position: 'absolute',
98
86
  left: 0,
99
87
  top: display.height - 20,
@@ -1,11 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Suspense, lazy, useRef } from 'react';
3
3
  import { PluggableElements } from '@jbrowse/core/ui';
4
- import { OverlayPointerProvider } from '@jbrowse/core/ui/highlightChipReveal';
5
- import { useMouseTracking } from '@jbrowse/core/ui/useMouseTracking';
4
+ import { useStyleTheme } from '@jbrowse/core/ui/PaletteContext';
6
5
  import { getEnv, getSession } from '@jbrowse/core/util';
7
6
  import { makeStyles } from '@jbrowse/core/util/tss-react';
8
- import { useTheme } from '@mui/material';
9
7
  import { observer } from 'mobx-react';
10
8
  import { SCALE_BAR_HEIGHT } from '../consts.js';
11
9
  import Gridlines from './Gridlines.js';
@@ -13,7 +11,6 @@ import OverviewHighlightBand from './OverviewHighlightBand.js';
13
11
  import PaddingBlocks from './PaddingBlocks.js';
14
12
  import RangeSelectOverlay from './RangeSelectOverlay.js';
15
13
  import Rubberband from './Rubberband.js';
16
- import Scalebar from './Scalebar.js';
17
14
  import VerticalGuide from './VerticalGuide.js';
18
15
  import { useRangeSelect } from './useRangeSelect.js';
19
16
  import { useSideScroll } from './useSideScroll.js';
@@ -24,6 +21,9 @@ const useStyles = makeStyles()({
24
21
  tracksContainer: {
25
22
  position: 'relative',
26
23
  contain: 'layout style',
24
+ // horizontal drags and pinches are the view's; vertical scroll stays the
25
+ // page's
26
+ touchAction: 'pan-y',
27
27
  },
28
28
  scalebarHighlights: {
29
29
  position: 'absolute',
@@ -39,40 +39,28 @@ const useStyles = makeStyles()({
39
39
  const TracksContainer = observer(function TracksContainer({ children, model, }) {
40
40
  const { classes } = useStyles();
41
41
  const { pluginManager } = getEnv(model);
42
- const { mouseDown: sideScrollMouseDown, mouseUp } = useSideScroll(model);
43
- const { showGridlines, showCenterLine } = model;
42
+ const sideScroll = useSideScroll(model);
43
+ const { axisGrid: showGridlines, showCenterLine } = model;
44
44
  const ref = useRef(null);
45
45
  // shift-drag range select over the whole tracks area. This is intentionally
46
46
  // a separate range-select instance from the one inside <Rubberband> (the
47
47
  // scalebar control); don't dedupe them — they cover different regions.
48
48
  const range = useRangeSelect(ref, model, true);
49
- // published rather than held (see `useMouseTracking`): the highlight bands
50
- // read it, and a position in state here would re-render the whole tracks area
51
- // every frame the pointer moves over it
52
- const { mouseTracker, handleMouseMove, handleMouseLeave } = useMouseTracking();
53
- return (_jsx("div", { ref: ref, "data-testid": "tracksContainer", className: classes.tracksContainer, onMouseDown: event => {
54
- sideScrollMouseDown(event);
55
- range.mouseDown(event);
56
- }, onMouseMove: event => {
57
- handleMouseMove(event);
49
+ return (_jsxs("div", { ref: ref, "data-testid": "tracksContainer", className: classes.tracksContainer, ...sideScroll, onMouseDown: range.mouseDown, onMouseMove: event => {
58
50
  range.mouseMove(event);
59
51
  }, onMouseLeave: () => {
60
- handleMouseLeave();
61
52
  range.mouseOut();
62
- }, onMouseUp: mouseUp, children: _jsxs(OverlayPointerProvider, { value: mouseTracker, children: [showGridlines ? (_jsxs(_Fragment, { children: [_jsx(Gridlines, { model: model }), _jsx(PaddingBlocks, { model: model })] })) : null, _jsx(Suspense, { fallback: null, children: showCenterLine ? _jsx(CenterLine, { model: model }) : null }), _jsx(RangeSelectOverlay, { model: model, range: range }), model.volatileGuides.map((guide, idx) => (_jsx(VerticalGuide, { model: model, coordX: guide.xPos }, idx))), _jsx(Rubberband, { model: model, ControlComponent: _jsx(Scalebar, { model: model, style: {
63
- height: SCALE_BAR_HEIGHT,
64
- boxSizing: 'border-box',
65
- } }) }), _jsx(ScalebarHighlightGroup, { model: model }), _jsx(HighlightGroup, { model: model }), _jsx(PluggableElements, { pluginManager: pluginManager, name: "LinearGenomeView-TracksContainerComponent", props: { model } }), children] }) }));
53
+ }, children: [showGridlines ? (_jsxs(_Fragment, { children: [_jsx(Gridlines, { model: model }), _jsx(PaddingBlocks, { model: model })] })) : null, _jsx(Suspense, { fallback: null, children: showCenterLine ? _jsx(CenterLine, { model: model }) : null }), _jsx(RangeSelectOverlay, { model: model, range: range }), model.volatileGuides.map((guide, idx) => (_jsx(VerticalGuide, { model: model, coordX: guide.xPos }, idx))), _jsx(Rubberband, { model: model }), _jsx(ScalebarHighlightGroup, { model: model }), _jsx(HighlightGroup, { model: model }), _jsx(PluggableElements, { pluginManager: pluginManager, name: "LinearGenomeView-TracksContainerComponent", props: { model } }), children] }));
66
54
  });
67
55
  const HighlightGroup = observer(function HighlightGroup({ model, }) {
68
- return getSession(model).highlightsVisible && model.highlight.length ? (_jsx(Suspense, { fallback: null, children: model.highlight.map((highlight, idx) => (_jsx(Highlight, { model: model, highlight: highlight }, highlightKey(highlight, idx)))) })) : null;
56
+ return getSession(model).highlightsVisible && model.highlights.length ? (_jsx(Suspense, { fallback: null, children: model.highlights.map((highlight, idx) => (_jsx(Highlight, { model: model, highlight: highlight }, highlightKey(highlight, idx)))) })) : null;
69
57
  });
70
58
  const ScalebarHighlightGroup = observer(function ScalebarHighlightGroup({ model, }) {
71
- const theme = useTheme();
59
+ const theme = useStyleTheme();
72
60
  const { pluginManager } = getEnv(model);
73
61
  const { classes } = useStyles();
74
62
  const viewBands = getSession(model).highlightsVisible
75
- ? model.highlight.map((h, idx) => {
63
+ ? model.highlights.map((h, idx) => {
76
64
  const coords = model.getHighlightCoords(h);
77
65
  return coords ? (_jsx(OverviewHighlightBand, { coords: coords, background: getHighlightColor(h, theme).toRgbString() }, highlightKey(h, idx))) : null;
78
66
  })
@@ -1,7 +1,6 @@
1
1
  import type { LinearGenomeViewModel } from '../index.ts';
2
- type LGV = LinearGenomeViewModel;
3
2
  declare const VerticalGuide: ({ model, coordX, }: {
4
- model: LGV;
3
+ model: LinearGenomeViewModel;
5
4
  coordX: number;
6
5
  }) => import("react").JSX.Element;
7
6
  export default VerticalGuide;
@@ -1,24 +1,11 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { stringify } from '@jbrowse/core/util';
3
- import { makeStyles } from '@jbrowse/core/util/tss-react';
4
3
  import { observer } from 'mobx-react';
5
- import { GuideLabel } from '../../shared/coordLabels.js';
4
+ import { VerticalGuideLine } from '../../shared/coordLabels.js';
6
5
  import { stickyChromeTops } from '../stickyChrome.js';
7
- const useStyles = makeStyles()({
8
- guide: {
9
- pointerEvents: 'none',
10
- height: '100%',
11
- width: 1,
12
- position: 'absolute',
13
- left: 0,
14
- background: 'red',
15
- zIndex: 1001,
16
- },
17
- });
18
6
  const VerticalGuide = observer(function VerticalGuide({ model, coordX, }) {
19
- const { classes } = useStyles();
20
7
  const { width, stickyViewHeaders, headerHeight } = model;
21
8
  const { scalebar } = stickyChromeTops({ stickyViewHeaders, headerHeight });
22
- return (_jsxs(_Fragment, { children: [_jsx(GuideLabel, { coordX: coordX, viewWidth: width, stickyTop: scalebar, children: stringify(model.pxToBp(coordX)) }), _jsx("div", { className: classes.guide, style: { transform: `translateX(${coordX}px)` } })] }));
9
+ return (_jsx(VerticalGuideLine, { coordX: coordX, viewWidth: width, stickyTop: scalebar, children: stringify(model.pxToBp(coordX)) }));
23
10
  });
24
11
  export default VerticalGuide;
@@ -1,8 +1,7 @@
1
1
  import type { StatusCallback } from '@jbrowse/core/util';
2
- import type { StopToken } from '@jbrowse/core/util/stopToken';
3
2
  import type { Region } from '@jbrowse/core/util/types';
4
3
  import type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree';
5
4
  export declare function fetchSequence(model: IAnyStateTreeNode, regions: Region[], opts?: {
6
- stopToken?: StopToken;
5
+ signal?: AbortSignal;
7
6
  statusCallback?: StatusCallback;
8
7
  }): Promise<import("@jbrowse/core/util").Feature[]>;
@@ -1,5 +1,5 @@
1
1
  import { getSequenceAdapterConfig } from '@jbrowse/core/assemblyManager/assembly';
2
- import { getSession } from '@jbrowse/core/util';
2
+ import { assembleLocString, getSession } from '@jbrowse/core/util';
3
3
  export async function fetchSequence(model, regions, opts = {}) {
4
4
  const session = getSession(model);
5
5
  const assemblyNames = new Set(regions.map(r => r.assemblyName));
@@ -25,10 +25,18 @@ export async function fetchSequence(model, regions, opts = {}) {
25
25
  if (!adapterConfig) {
26
26
  throw new Error(`assembly ${assemblyName} has no resolved configuration, so its sequence adapter cannot be read`);
27
27
  }
28
- const sessionId = 'getSequence';
29
- return rpcManager.call(sessionId, 'CoreGetFeatures', {
30
- adapterConfig,
31
- regions,
32
- ...opts,
33
- });
28
+ // one call per region: a multi-region fetch merges its regions' streams in
29
+ // the order they finish, and a region the sequence lacks yields nothing,
30
+ // where the reader wants one entry per selected region, in selection order
31
+ return Promise.all(regions.map(async (region) => {
32
+ const [feature] = await rpcManager.call('getSequence', 'CoreGetFeatures', {
33
+ adapterConfig,
34
+ regions: [region],
35
+ ...opts,
36
+ });
37
+ if (!feature) {
38
+ throw new Error(`no sequence found for ${assembleLocString(region)} in assembly ${assemblyName}`);
39
+ }
40
+ return feature;
41
+ }));
34
42
  }
@@ -19,6 +19,16 @@ export function recentLocationsMenu({ recentLocations, onNavigate, onClear, }) {
19
19
  label: 'Recent',
20
20
  subMenu: [
21
21
  ...recentLocations.map(({ label, loc }) => ({
22
+ // the list dedupes on the location, so two rows can share a
23
+ // display string — two features of the same name at different
24
+ // loci, or two snippets ellipsized to the same text. `id` is what
25
+ // keeps them separate rows to React, which otherwise keys both on
26
+ // that one label.
27
+ //
28
+ // Prefixed, because a freehand row has no location and falls back
29
+ // to its label, which may itself be a locstring — unprefixed, that
30
+ // row and a recorded one at the same locus share an id.
31
+ id: loc ? `loc:${loc}` : `query:${label}`,
22
32
  label,
23
33
  onClick: () => {
24
34
  // a row that recorded a location navigates straight to it; one
@@ -7,11 +7,8 @@ interface AnchorPosition {
7
7
  isClick: boolean;
8
8
  }
9
9
  export declare function useRangeSelect(ref: React.RefObject<HTMLDivElement | null>, model: LinearGenomeViewModel, shiftOnly?: boolean): {
10
- open: boolean;
11
10
  isClick: boolean | undefined;
12
- clickBpOffset: import("@jbrowse/core/util/Base1DUtils").PxToBpResult | undefined;
13
11
  guideX: number | undefined;
14
- rubberbandOn: boolean;
15
12
  mouseDown: (event: React.MouseEvent<HTMLDivElement>) => void;
16
13
  mouseMove: (event: React.MouseEvent<HTMLDivElement>) => void;
17
14
  mouseOut: () => void;
@@ -1,8 +1,12 @@
1
- import { useCallback, useEffect, useState } from 'react';
1
+ import { useCallback, useState } from 'react';
2
2
  import { getRelativeX } from '@jbrowse/core/util/getRelativeX';
3
+ import { isClaimedPress, isFromPortal } from '@jbrowse/core/util/pressOwner';
4
+ import { useWindowDrag } from '../../shared/useWindowDrag.js';
5
+ import { isOnScalebarRefLabel } from './util.js';
3
6
  export function useRangeSelect(ref, model, shiftOnly) {
4
7
  const [startX, setStartX] = useState();
5
8
  const [currentX, setCurrentX] = useState();
9
+ const [startedOnRefLabel, setStartedOnRefLabel] = useState(false);
6
10
  // clientX and clientY used for anchorPosition for menu
7
11
  // offsetX used for calculations about width of selection
8
12
  const [anchorPosition, setAnchorPosition] = useState();
@@ -14,69 +18,37 @@ export function useRangeSelect(ref, model, shiftOnly) {
14
18
  setCurrentX(undefined);
15
19
  setGuideX(undefined);
16
20
  }, []);
17
- useEffect(() => {
18
- const el = ref.current;
19
- if (!mouseDragging || !el) {
20
- return;
21
- }
22
- // the container's left edge is fixed for the duration of a drag, so measure
23
- // it once here rather than calling getBoundingClientRect on every mousemove
24
- const { left } = el.getBoundingClientRect();
25
- function globalMouseMove(event) {
26
- setCurrentX(event.clientX - left);
27
- }
28
- function globalMouseUp(event) {
29
- if (startX === undefined) {
30
- return;
31
- }
32
- const { clientX, clientY } = event;
33
- const offsetX = clientX - left;
34
- const isClick = Math.abs(offsetX - startX) <= 3;
35
- // Clear the flag unconditionally once consumed: the label's own onClick
36
- // also clears it, but that only fires if mouseup lands on the label, so
37
- // relying on it alone can leave the flag stuck (swallowing the next
38
- // scalebar click) when mouseup drifts a few px off the label edge.
39
- const startedOnRefLabel = model.scalebarRefNameClickPending;
40
- if (startedOnRefLabel) {
41
- model.setScalebarRefNameClickPending(false);
42
- }
43
- // A click that began on a scalebar refname label is handled by that
44
- // label's onClick (opens its menu), not by the rubberband menu here.
45
- // Drop the hover guide too: the label's menu covers it while it is open,
46
- // and nothing else clears it, so picking an item like "Focus on X" left a
47
- // red line stranded on the scalebar with the pointer nowhere near it
21
+ useWindowDrag(ref, mouseDragging ? startX : undefined, {
22
+ onMove: setCurrentX,
23
+ onEnd: ({ startX, endX, isClick, clientX, clientY }) => {
24
+ // A click on a scalebar refName label belongs to the label's own menu.
25
+ // Drop the hover guide too: that menu covers it, and nothing else clears
26
+ // it once the menu closes
48
27
  if (isClick && startedOnRefLabel) {
49
28
  setStartX(undefined);
50
29
  setCurrentX(undefined);
51
30
  setGuideX(undefined);
52
31
  return;
53
32
  }
54
- setAnchorPosition({ offsetX, clientX, clientY, isClick });
33
+ setAnchorPosition({ offsetX: endX, clientX, clientY, isClick });
55
34
  if (isClick) {
56
- setGuideX(offsetX);
35
+ setGuideX(endX);
57
36
  }
58
37
  else {
59
- model.setOffsets(model.pxToBp(Math.min(startX, offsetX)), model.pxToBp(Math.max(startX, offsetX)));
38
+ model.setOffsets(model.pxToBp(Math.min(startX, endX)), model.pxToBp(Math.max(startX, endX)));
60
39
  setGuideX(undefined);
61
40
  }
62
- }
63
- function globalKeyDown(event) {
64
- if (event.key === 'Escape') {
65
- setStartX(undefined);
66
- setCurrentX(undefined);
67
- }
68
- }
69
- window.addEventListener('mousemove', globalMouseMove);
70
- window.addEventListener('mouseup', globalMouseUp);
71
- window.addEventListener('keydown', globalKeyDown);
72
- return () => {
73
- window.removeEventListener('mousemove', globalMouseMove);
74
- window.removeEventListener('mouseup', globalMouseUp);
75
- window.removeEventListener('keydown', globalKeyDown);
76
- };
77
- }, [startX, mouseDragging, model, ref]);
41
+ },
42
+ onCancel: () => {
43
+ setStartX(undefined);
44
+ setCurrentX(undefined);
45
+ },
46
+ });
78
47
  function mouseDown(event) {
79
- if (shiftOnly && !event.shiftKey) {
48
+ if (event.button !== 0 ||
49
+ (shiftOnly
50
+ ? !event.shiftKey || isClaimedPress(event)
51
+ : isFromPortal(event))) {
80
52
  return;
81
53
  }
82
54
  // a press with the refName menu already open reopens it on the label under
@@ -90,13 +62,14 @@ export function useRangeSelect(ref, model, shiftOnly) {
90
62
  // clear any leftover menu/selection so a fresh drag isn't blocked by a
91
63
  // stale anchorPosition keeping mouseDragging false
92
64
  setAnchorPosition(undefined);
65
+ setStartedOnRefLabel(isOnScalebarRefLabel(event.target));
93
66
  const relativeX = getRelativeX(event, ref.current);
94
67
  setStartX(relativeX);
95
68
  setCurrentX(relativeX);
96
69
  }
97
70
  function mouseMove(event) {
98
71
  // Keep the rubberband visible while a drag-selection menu is open
99
- if (anchorPosition?.isClick === false) {
72
+ if (anchorPosition?.isClick === false || isFromPortal(event)) {
100
73
  return;
101
74
  }
102
75
  const wantsGuide = !mouseDragging && (!shiftOnly || event.shiftKey);
@@ -111,11 +84,7 @@ export function useRangeSelect(ref, model, shiftOnly) {
111
84
  callback();
112
85
  handleClose();
113
86
  }
114
- const open = Boolean(anchorPosition);
115
87
  const isClick = anchorPosition?.isClick;
116
- const clickBpOffset = isClick
117
- ? model.pxToBp(anchorPosition.offsetX)
118
- : undefined;
119
88
  // rubberband geometry only exists while a drag is in progress (startX set);
120
89
  // grouped so a single truthiness check narrows all fields for RubberbandSpan
121
90
  let rubberband;
@@ -132,12 +101,8 @@ export function useRangeSelect(ref, model, shiftOnly) {
132
101
  };
133
102
  }
134
103
  return {
135
- open,
136
104
  isClick,
137
- clickBpOffset,
138
105
  guideX,
139
- // true only mid-drag and not a click — drives RubberbandSpan vs guide
140
- rubberbandOn: rubberband !== undefined && !isClick,
141
106
  mouseDown,
142
107
  mouseMove,
143
108
  mouseOut,
@@ -22,5 +22,7 @@ export type SearchBoxPrefs = ReturnType<typeof useSearchBoxPrefs>;
22
22
  /**
23
23
  * The menu rows that drive those prefs. "Stacked" rather than "Vertical": the
24
24
  * two headers name the same state and had drifted apart on it once already.
25
+ * A caller spreading the rows into a "Show" submenu passes `'Search boxes'`
26
+ * as the toggle's label.
25
27
  */
26
- export declare function searchBoxMenuItems({ showSearchBoxes, setShowSearchBoxes, sideBySide, setSideBySide, }: SearchBoxPrefs): MenuItem[];
28
+ export declare function searchBoxMenuItems({ showSearchBoxes, setShowSearchBoxes, sideBySide, setSideBySide, }: SearchBoxPrefs, toggleLabel?: string): MenuItem[];
@@ -22,11 +22,13 @@ export function useSearchBoxPrefs(prefix, numViews) {
22
22
  /**
23
23
  * The menu rows that drive those prefs. "Stacked" rather than "Vertical": the
24
24
  * two headers name the same state and had drifted apart on it once already.
25
+ * A caller spreading the rows into a "Show" submenu passes `'Search boxes'`
26
+ * as the toggle's label.
25
27
  */
26
- export function searchBoxMenuItems({ showSearchBoxes, setShowSearchBoxes, sideBySide, setSideBySide, }) {
28
+ export function searchBoxMenuItems({ showSearchBoxes, setShowSearchBoxes, sideBySide, setSideBySide, }, toggleLabel = 'Show search boxes') {
27
29
  return [
28
30
  {
29
- label: 'Show search boxes',
31
+ label: toggleLabel,
30
32
  type: 'checkbox',
31
33
  checked: showSearchBoxes,
32
34
  onClick: () => {