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

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.
@@ -13,8 +13,11 @@ const useStyles = makeStyles()(theme => ({
13
13
  display: 'flex',
14
14
  alignItems: 'center',
15
15
  gap: theme.spacing(0.5),
16
+ minWidth: 0,
16
17
  },
17
18
  }));
19
+ const MIN_BOX_WIDTH = 100;
20
+ const boxStyle = { margin: 0, minWidth: MIN_BOX_WIDTH };
18
21
  // One row's locate control in a header that stacks several linear genome views:
19
22
  // the compact search box, then the assembly name and the span on screen. The
20
23
  // comparative view and the breakpoint split view each draw one per row, and each
@@ -23,6 +26,6 @@ const useStyles = makeStyles()(theme => ({
23
26
  const HeaderSearchBoxes = observer(function HeaderSearchBoxes({ view, }) {
24
27
  const { classes } = useStyles();
25
28
  const { assemblyDisplayNames, coarseTotalBp } = view;
26
- return (_jsxs("span", { className: classes.searchBox, children: [_jsx(SearchBox, { model: view, showHelp: false, maxWidth: 250, minWidth: 100, style: { margin: 0 } }), _jsxs(Typography, { variant: "body2", color: "text.secondary", className: classes.bp, children: [assemblyDisplayNames.join(','), " ", getBpDisplayStr(coarseTotalBp)] })] }));
29
+ return (_jsxs("span", { className: classes.searchBox, children: [_jsx(SearchBox, { model: view, showHelp: false, maxWidth: 250, minWidth: MIN_BOX_WIDTH, style: boxStyle }), _jsxs(Typography, { variant: "body2", color: "text.secondary", className: classes.bp, children: [assemblyDisplayNames.join(','), " ", getBpDisplayStr(coarseTotalBp)] })] }));
27
30
  });
28
31
  export default HeaderSearchBoxes;
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, lazy, useEffect, useRef } from 'react';
2
+ import { useEffect, useRef } from 'react';
3
3
  import { VIEW_HEADER_HEIGHT } from '@jbrowse/core/ui';
4
4
  import { getSession } from '@jbrowse/core/util';
5
5
  import { LGV_HEADER_HEIGHT_VAR, SCROLL_PORT_HEIGHT_VAR, VIEW_HEADER_HEIGHT_VAR, useChromeHeightVar, useFocusOnInteraction, } from '@jbrowse/core/util/hooks';
@@ -11,12 +11,11 @@ import { stickyChromeTops } from '../stickyChrome.js';
11
11
  import Header from './Header.js';
12
12
  import MiniControls from './MiniControls.js';
13
13
  import NavigationAnnouncer from './NavigationAnnouncer.js';
14
+ import NoTracksActiveButton from './NoTracksActiveButton.js';
14
15
  import ResizeAllTracksHandle from './ResizeAllTracksHandle.js';
15
16
  import Rubberband from './Rubberband.js';
16
17
  import TrackContainer from './TrackContainer.js';
17
18
  import TracksContainer from './TracksContainer.js';
18
- // lazies
19
- const NoTracksActiveButton = lazy(() => import('./NoTracksActiveButton.js'));
20
19
  const useStyles = makeStyles()(theme => ({
21
20
  header: {
22
21
  background: theme.palette.background.paper,
@@ -104,7 +103,7 @@ const LinearGenomeViewContainer = observer(function LinearGenomeViewContainer({
104
103
  .map(d => d.hoveredFeature)
105
104
  .find(Boolean);
106
105
  session.setHovered({ hoverPosition, hoverFeature });
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: {
106
+ }, 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(NoTracksActiveButton, { model: model })) : (_jsxs(_Fragment, { children: [pinnedTracks.length ? (_jsx(Paper, { elevation: 2, "data-testid": "pinned-tracks", className: classes.pinnedTracks, style: {
108
107
  top: stickyTops.pinnedTracks,
109
108
  // the scroll port this sticks in, not the window: it is
110
109
  // under the app bar in the classic stack, a dockview
@@ -14,19 +14,24 @@ const useStyles = makeStyles()(theme => ({
14
14
  background: {
15
15
  position: 'absolute',
16
16
  right: 0,
17
- background: theme.palette.background.paper,
18
17
  // needed when sticky header is off in lgv, e.g. in breakpoint split view
19
18
  zIndex: 2,
20
19
  },
21
20
  focusedBackground: {
22
- background: alpha(theme.palette.secondary.light, 0.2),
21
+ backgroundColor: alpha(theme.palette.secondary.light, 0.2),
23
22
  },
24
23
  }));
25
24
  const MiniControls = observer(function MiniControls({ model, }) {
26
25
  const { classes } = useStyles();
27
26
  const { id, scalebarOnly } = model;
28
27
  const { focusedViewId } = getSession(model);
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: () => {
28
+ // A ruler-only row is shorter than these controls, so they rise from the
29
+ // ruler's bottom edge rather than hang from its top: a nested row always has
30
+ // chrome above it, while the last row of a stack has only the view's frame
31
+ // below.
32
+ return (_jsx(Paper, { "data-testid": "lgv-mini-controls", className: classes.background, style: scalebarOnly
33
+ ? { top: model.scalebarHeight, transform: 'translateY(-100%)' }
34
+ : undefined, children: _jsxs(Paper, { className: focusedViewId === id ? classes.focusedBackground : undefined, children: [_jsx(Tooltip, { title: "Open track selector", children: _jsx(IconButton, { size: "small", onClick: () => {
30
35
  model.activateTrackSelector();
31
36
  }, 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: () => {
32
37
  model.setScalebarOnly(!scalebarOnly);
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { canonicalLocString } from '@jbrowse/core/TextSearch/places';
3
- import { readConfObject } from '@jbrowse/core/configuration';
4
3
  import { SanitizedHTML } from '@jbrowse/core/ui';
5
4
  import { getSession } from '@jbrowse/core/util';
6
5
  import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, } from '@mui/material';
@@ -12,7 +11,7 @@ const SearchResultsTable = observer(function SearchResultsTable({ searchResults,
12
11
  const assembly = assemblyManager.get(assemblyName);
13
12
  function getTrackName(trackId) {
14
13
  const conf = trackId !== undefined ? session.getTrackById(trackId) : undefined;
15
- return conf ? readConfObject(conf, 'name') : '';
14
+ return conf?.name ?? '';
16
15
  }
17
16
  // A location the assembly can't resolve is listed as-is: Go navigates
18
17
  // through navToOption, which reports its own failure
@@ -13,7 +13,10 @@ const useStyles = makeStyles()(theme => ({
13
13
  root: {
14
14
  // above breakpoint split view
15
15
  zIndex: 200,
16
- background: theme.palette.background.paper,
16
+ ...(theme.palette.mode === 'dark' && {
17
+ outline: `1px solid ${theme.palette.divider}`,
18
+ outlineOffset: -1,
19
+ }),
17
20
  display: 'inline-flex',
18
21
  alignItems: 'center',
19
22
  maxWidth: 'calc(100% - 16px)',
@@ -34,7 +34,7 @@ export async function renderToSvg(model, opts) {
34
34
  // itself.
35
35
  const { tracks, displayResults, tracksHeight, legendWidth, skippedTracks } = await renderViewTracks({
36
36
  view: model,
37
- opts,
37
+ opts: { ...opts, fontSize },
38
38
  theme,
39
39
  textHeight,
40
40
  trackLabels,
@@ -1,10 +1,9 @@
1
1
  import type { TrackLabelMode } from '../types.ts';
2
- export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, raised, }: {
2
+ export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, }: {
3
3
  trackName: string;
4
4
  trackLabels: TrackLabelMode;
5
5
  fontSize: number;
6
6
  textHeight: number;
7
7
  trackLabelOffset: number;
8
8
  x: number;
9
- raised?: boolean;
10
9
  }): import("react").JSX.Element | null;
@@ -4,24 +4,20 @@ import { stripAlpha } from '@jbrowse/core/util';
4
4
  import { TRACK_LABEL_GAP, insetLabelBaselineY, offsetLabelBaselineY, } from './util.js';
5
5
  // Where the label sits, per mode. 'left' right-aligns in the gutter
6
6
  // trackLabelLeftOffset reserved (hence the shared TRACK_LABEL_GAP), beside the
7
- // first row or, `raised`, in the band above a track whose sidebar holds the
8
- // gutter beside its rows. The other modes hang off the leftmost visible content
7
+ // first row. The other modes hang off the leftmost visible content
9
8
  // at `x`, either just above the track body ('offset') or inset over it
10
9
  // ('overlapping').
11
10
  //
12
11
  // Every mode is placed on its alphabetic baseline (the SVG default, so no
13
- // dominantBaseline is emitted at all): 'offset' and a raised 'left' so their
14
- // descenders land a known distance above the track body — the band is
12
+ // dominantBaseline is emitted at all): 'offset' so its descenders land a known distance above the track body — the band is
15
13
  // `textHeight` tall, and offsetLabelBaselineY owns that arithmetic — and
16
14
  // 'left'/'overlapping' so their ascenders stay inside the track box they align
17
15
  // with.
18
- function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x, raised, }) {
16
+ function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x, }) {
19
17
  if (trackLabels === 'left') {
20
18
  return {
21
19
  x: trackLabelOffset - TRACK_LABEL_GAP,
22
- y: raised
23
- ? offsetLabelBaselineY(textHeight, fontSize)
24
- : insetLabelBaselineY(fontSize),
20
+ y: insetLabelBaselineY(fontSize),
25
21
  textAnchor: 'end',
26
22
  };
27
23
  }
@@ -34,7 +30,7 @@ function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x,
34
30
  // stay inside it (at y=0 they rose into the track above)
35
31
  return { x: x + 5, y: insetLabelBaselineY(fontSize) };
36
32
  }
37
- export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, raised = false, }) {
33
+ export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, }) {
38
34
  const palette = usePalette();
39
35
  if (trackLabels === 'hidden') {
40
36
  return null;
@@ -45,7 +41,6 @@ export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHe
45
41
  textHeight,
46
42
  fontSize,
47
43
  x,
48
- raised,
49
44
  });
50
45
  // 'overlapping' prints over the track's own data, which the on-screen label
51
46
  // clears with a paper box, so it carries the halo text over a plot needs
@@ -6,7 +6,7 @@ import { getSession } from '@jbrowse/core/util';
6
6
  import { exportsTooLargeNote } from '@jbrowse/display-kit/renderDisplaySvg';
7
7
  import SVGRegionSeparators from './SVGRegionSeparators.js';
8
8
  import SVGTrackLabel from './SVGTrackLabel.js';
9
- import { labelOffset, leftLabelRaised, trackBoxOffsets, trackLabelMode, } from './util.js';
9
+ import { labelOffset, trackBoxOffsets, trackLabelMode } from './util.js';
10
10
  export default function SVGTracks({ displayResults, model, textHeight, fontSize, trackLabels, trackLabelOffset, leftBuffer, legendWidth, }) {
11
11
  const session = getSession(model);
12
12
  const x = Math.max(-model.offsetPx, 0);
@@ -17,6 +17,6 @@ export default function SVGTracks({ displayResults, model, textHeight, fontSize,
17
17
  const display = track.displays[0];
18
18
  const currentOffset = offsets[i];
19
19
  const textOffset = labelOffset(track, trackLabels, textHeight);
20
- return (_jsxs("g", { transform: `translate(0 ${currentOffset})`, children: [_jsx(SvgClipRect, { id: `track-clip-${svgNodeId(model)}-${conf.trackId}`, x: -leftBuffer, y: textOffset, width: model.width + trackLabelOffset + leftBuffer + legendWidth, height: display.height, children: _jsxs("g", { transform: `translate(${trackLabelOffset} ${textOffset})`, children: [result, exportsTooLargeNote(display) ? null : (_jsx(SVGRegionSeparators, { model: model, height: display.height }))] }) }), _jsx(SVGTrackLabel, { trackName: trackName, fontSize: fontSize, textHeight: textHeight, trackLabels: trackLabelMode(track, trackLabels), trackLabelOffset: trackLabelOffset, raised: leftLabelRaised(track, trackLabels), x: x + trackLabelOffset })] }, conf.trackId));
20
+ return (_jsxs("g", { transform: `translate(0 ${currentOffset})`, children: [_jsx(SvgClipRect, { id: `track-clip-${svgNodeId(model)}-${conf.trackId}`, x: -leftBuffer, y: textOffset, width: model.width + trackLabelOffset + leftBuffer + legendWidth, height: display.height, children: _jsxs("g", { transform: `translate(${trackLabelOffset} ${textOffset})`, children: [result, exportsTooLargeNote(display) ? null : (_jsx(SVGRegionSeparators, { model: model, height: display.height }))] }) }), _jsx(SVGTrackLabel, { trackName: trackName, fontSize: fontSize, textHeight: textHeight, trackLabels: trackLabelMode(track, trackLabels), trackLabelOffset: trackLabelOffset, x: x + trackLabelOffset })] }, conf.trackId));
21
21
  }) }));
22
22
  }
@@ -1,4 +1,5 @@
1
1
  import type { ExportSvgOptions, TrackLabelMode } from '../types.ts';
2
+ import type { LgvSvgExportable } from '@jbrowse/display-kit/renderDisplaySvg';
2
3
  import type { ExportSvgDisplayOptions } from '@jbrowse/display-kit/types';
3
4
  import type { ThemeOptions } from '@mui/material';
4
5
  import type { ReactNode } from 'react';
@@ -7,7 +8,7 @@ export interface SvgExportTrack {
7
8
  displays: {
8
9
  height: number;
9
10
  svgLegendWidth?: () => number;
10
- svgSidebarWidth?: () => number;
11
+ svgSidebarWidth?: LgvSvgExportable['svgSidebarWidth'];
11
12
  /**
12
13
  * Optional, and the option is the point: SVG export is a substantial extra
13
14
  * implementation for a display type, and a third-party plugin that has not
@@ -125,7 +125,15 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
125
125
  * question about regions and is true before a track is instantiated (the first
126
126
  * figure then draws a header over nothing, and nothing else ever changes to
127
127
  * correct it); **their heights and minimized flags**, since the geometry is
128
- * derived from them; **the width**, since a resize can widen the canvas without
128
+ * derived from them; **their configs**, since a display's settings are slots on
129
+ * the track config and a shown track's snapshot spells that config as its id;
130
+ * **the legend sections a reader dismissed** and **the per-group state**
131
+ * (hidden sections, collapses, height overrides: `groupStateKey`), which are
132
+ * volatile and in no snapshot; **the reload counter**, since a Retry or a Force
133
+ * load leaves every snapshot as it was while the figure has an error or a
134
+ * too-large note to replace; **the view's coloring toggles** (`colorByCDS`,
135
+ * `showAminoAcids`), named one by one because the view's own snapshot moves
136
+ * every pan frame; **the width**, since a resize can widen the canvas without
129
137
  * moving the locus; **the theme**, since each display bakes colors into its own
130
138
  * bodies, so a figure from the other mode is not stale but unreadable; and **the
131
139
  * highlight bands**, which are drawn in the figure and are the one thing in it a
@@ -133,8 +141,10 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
133
141
  *
134
142
  * A plugin's own overlay, through `LinearGenomeView-HighlightSVGComponent`, is
135
143
  * state this cannot see, so a change to it shows up at the figure's next
136
- * redraw rather than at once. Subscribing from inside the figure is the thing
137
- * that must not happen — see the note at the top of the file.
144
+ * redraw rather than at once. So does a track's vertical scroll, which moves
145
+ * every wheel frame and has no settled copy to key on. Subscribing from inside
146
+ * the figure is the thing that must not happen — see the note at the top of
147
+ * the file.
138
148
  */
139
149
  function figureKey(view, themeName) {
140
150
  // A closed view is not an error, it is a host doing an ordinary thing in an
@@ -156,9 +166,19 @@ function figureKey(view, themeName) {
156
166
  view.coarseVisibleLocStrings,
157
167
  view.coarseBpPerPx,
158
168
  view.width,
159
- // the snapshot carries pinned, minimized and the display settings a body
160
- // bakes in; the effective height is a getter, so it is read beside it
161
- view.tracks.map(track => [getSnapshot(track), track.displays[0]?.height]),
169
+ view.tracks.map(track => {
170
+ const display = track.displays[0];
171
+ return [
172
+ getSnapshot(track),
173
+ getSnapshot(track.configuration),
174
+ display?.height,
175
+ display?.dismissedLegendSections,
176
+ display?.groupStateKey,
177
+ display?.reloadCounter,
178
+ ];
179
+ }),
180
+ view.colorByCDS,
181
+ view.showAminoAcids,
162
182
  session.getActiveThemeOptions?.(themeName),
163
183
  session.highlightsVisible ? view.highlights : false,
164
184
  session.highlightLabelsVisible,
@@ -1,23 +1,24 @@
1
1
  import type { TrackLabelMode } from '../types.ts';
2
2
  import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
3
3
  import type { TrackCatalog } from '@jbrowse/core/util';
4
+ import type { LgvSvgExportable } from '@jbrowse/display-kit/renderDisplaySvg';
5
+ import type { ExportTextStyle } from '@jbrowse/display-kit/types';
4
6
  import type { ReactNode } from 'react';
7
+ type SidebarDisplay = Pick<LgvSvgExportable, 'svgSidebarWidth'>;
5
8
  interface TrackHeights {
6
- displays: {
9
+ displays: ({
7
10
  height: number;
8
11
  prefersOffset?: boolean;
9
- svgSidebarWidth?: () => number;
10
- }[];
12
+ } & SidebarDisplay)[];
11
13
  }
12
14
  export interface SvgDisplayResult {
13
15
  track: {
14
16
  configuration: AnyConfigurationModel;
15
- displays: {
17
+ displays: ({
16
18
  height: number;
17
19
  regionTooLarge?: boolean;
18
20
  drawsWhenTooLarge?: boolean;
19
- svgSidebarWidth?: () => number;
20
- }[];
21
+ } & SidebarDisplay)[];
21
22
  };
22
23
  result: ReactNode;
23
24
  }
@@ -83,14 +84,15 @@ export declare function getRulerLayout(rulerHeight: number): {
83
84
  };
84
85
  export declare const refNameLabelBoxHeight: number;
85
86
  export declare const refNameLabelBaselineY: number;
86
- export declare function trackLabelMode(track: TrackHeights, trackLabels: TrackLabelMode): TrackLabelMode;
87
- export declare function leftLabelRaised(track: Pick<TrackHeights, 'displays'>, trackLabels: TrackLabelMode): boolean;
87
+ export declare function trackLabelMode(track: {
88
+ displays: ({
89
+ prefersOffset?: boolean;
90
+ } & SidebarDisplay)[];
91
+ }, trackLabels: TrackLabelMode): TrackLabelMode;
88
92
  export declare function labelOffset(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
89
93
  interface SidebarTrack {
90
94
  configuration: AnyConfigurationModel;
91
- displays: {
92
- svgSidebarWidth?: () => number;
93
- }[];
95
+ displays: SidebarDisplay[];
94
96
  }
95
97
  export declare const TRACK_LABEL_GAP = 40;
96
98
  export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }: {
@@ -100,7 +102,7 @@ export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fo
100
102
  fontFamily?: string;
101
103
  session: TrackCatalog;
102
104
  }): number;
103
- export declare function trackSidebarWidth(track: Pick<SidebarTrack, 'displays'>): number;
105
+ export declare function trackSidebarWidth(track: Pick<SidebarTrack, 'displays'>, text?: ExportTextStyle): number;
104
106
  export declare function trackBoxHeight(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
105
107
  export declare function trackBoxOffsets(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number[];
106
108
  export declare function totalHeight(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number;
@@ -179,24 +179,17 @@ export const refNameLabelBaselineY = labelBaselineFromTop(0, REF_NAME_LABEL_FONT
179
179
  // The mode one track's label is drawn in. 'overlapping' yields to 'offset' for a
180
180
  // display that `prefersOffset`, as TrackContainer does on screen: its left edge
181
181
  // carries content — an axis, a sample's genotypes — the label would print over.
182
+ // 'left' yields to 'offset' for a track whose sidebar holds the gutter beside
183
+ // its rows.
182
184
  export function trackLabelMode(track, trackLabels) {
183
- return trackLabels === 'overlapping' && track.displays[0]?.prefersOffset
185
+ return (trackLabels === 'overlapping' && track.displays[0]?.prefersOffset) ||
186
+ (trackLabels === 'left' && trackSidebarWidth(track) > 0)
184
187
  ? 'offset'
185
188
  : trackLabels;
186
189
  }
187
- // Whether a 'left' name sits in a band above its track's rows rather than
188
- // beside the first of them: the gutter beside the rows holds the track's own
189
- // sidebar, so the name heads it instead of standing off to its left.
190
- export function leftLabelRaised(track, trackLabels) {
191
- return trackLabels === 'left' && trackSidebarWidth(track) > 0;
192
- }
193
- // space the label pushes a track's body down by: an 'offset' label, or a raised
194
- // 'left' one
190
+ // space an 'offset' label pushes a track's body down by
195
191
  export function labelOffset(track, trackLabels, textHeight) {
196
- return trackLabelMode(track, trackLabels) === 'offset' ||
197
- leftLabelRaised(track, trackLabels)
198
- ? textHeight
199
- : 0;
192
+ return trackLabelMode(track, trackLabels) === 'offset' ? textHeight : 0;
200
193
  }
201
194
  // Gap between a 'left' track label's right edge and the track body.
202
195
  // SVGTrackLabel right-aligns its text at `trackLabelOffset - TRACK_LABEL_GAP`,
@@ -204,9 +197,7 @@ export function labelOffset(track, trackLabels, textHeight) {
204
197
  // gutter it was measured for.
205
198
  export const TRACK_LABEL_GAP = 40;
206
199
  // Horizontal gutter left of the track bodies: the widest of each track's
207
- // sidebar and, in 'left' mode, its name plus TRACK_LABEL_GAP. A sidebar and a
208
- // name share the column because the name rises above the sidebar
209
- // (leftLabelRaised). Takes an
200
+ // sidebar and of each name drawn 'left', plus TRACK_LABEL_GAP. Takes an
210
201
  // already-minimized-filtered track list, so the reserved width matches the
211
202
  // labels that actually get drawn.
212
203
  //
@@ -225,14 +216,14 @@ export const TRACK_LABEL_GAP = 40;
225
216
  // `getScalebarRefNameLabels`, an on-screen model getter, so making them
226
217
  // family-aware means threading an export option through screen state.
227
218
  export function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }) {
228
- return max(tracks.map(t => Math.max(trackSidebarWidth(t), trackLabels === 'left'
219
+ return max(tracks.map(t => Math.max(trackSidebarWidth(t, { fontSize, fontFamily }), trackLabelMode(t, trackLabels) === 'left'
229
220
  ? measureText(svgTrackName(t, session), fontSize, fontFamily) +
230
221
  TRACK_LABEL_GAP
231
222
  : 0)), 0);
232
223
  }
233
224
  // Px of tree and row labels a track's display draws left of its body.
234
- export function trackSidebarWidth(track) {
235
- return track.displays[0]?.svgSidebarWidth?.() ?? 0;
225
+ export function trackSidebarWidth(track, text) {
226
+ return track.displays[0]?.svgSidebarWidth?.(text) ?? 0;
236
227
  }
237
228
  // vertical box a single track occupies. Shared by totalHeight (sum) and
238
229
  // trackBoxOffsets (prefix-sum) so the two can't drift.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-linear-genome-view",
3
- "version": "5.0.0-beta.11",
3
+ "version": "5.0.0-beta.13",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 linear genome view",
6
6
  "keywords": [
@@ -24,12 +24,12 @@
24
24
  "@jbrowse/mobx-state-tree": "^6.7.0",
25
25
  "@mui/icons-material": "^9.4.0",
26
26
  "@mui/material": "^9.4.0",
27
- "mobx": "^7.0.5",
27
+ "mobx": "^7.0.6",
28
28
  "mobx-react": "^10.0.2",
29
- "@jbrowse/display-kit": "^5.0.0-beta.11",
30
- "@jbrowse/core": "^5.0.0-beta.11",
31
- "@jbrowse/render-core": "^5.0.0-beta.11",
32
- "@jbrowse/display-ui": "^5.0.0-beta.11"
29
+ "@jbrowse/core": "^5.0.0-beta.13",
30
+ "@jbrowse/render-core": "^5.0.0-beta.13",
31
+ "@jbrowse/display-kit": "^5.0.0-beta.13",
32
+ "@jbrowse/display-ui": "^5.0.0-beta.13"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": ">=19.0.0",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "sideEffects": false,
42
42
  "devDependencies": {
43
- "@jbrowse/display-test-utils": "^5.0.0-beta.11"
43
+ "@jbrowse/display-test-utils": "^5.0.0-beta.13"
44
44
  },
45
45
  "scripts": {
46
46
  "prebuild": "pnpm clean",