@jbrowse/plugin-linear-genome-view 5.0.0-beta.13 → 5.0.0-beta.16
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.
- package/esm/FeatureTrack/configSchema.d.ts +2 -1
- package/esm/FeatureTrack/configSchema.js +2 -1
- package/esm/LinearGenomeView/afterAttach.js +1 -23
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +6 -2
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +31 -7
- package/esm/LinearGenomeView/components/HeaderPanControls.d.ts +3 -3
- package/esm/LinearGenomeView/components/HeaderPanControls.js +4 -2
- package/esm/LinearGenomeView/components/HighlightBand.d.ts +3 -2
- package/esm/LinearGenomeView/components/HighlightBand.js +4 -2
- package/esm/LinearGenomeView/components/HighlightChip.d.ts +3 -2
- package/esm/LinearGenomeView/components/HighlightChip.js +4 -2
- package/esm/LinearGenomeView/components/LinearGenomeView.js +5 -12
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +4 -5
- package/esm/LinearGenomeView/components/OverviewHighlightBand.d.ts +3 -2
- package/esm/LinearGenomeView/components/OverviewHighlightBand.js +4 -2
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.d.ts +3 -2
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.js +4 -4
- package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +4 -4
- package/esm/LinearGenomeView/components/SearchPanelForm.d.ts +3 -2
- package/esm/LinearGenomeView/components/SearchPanelForm.js +4 -2
- package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +4 -9
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -4
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +3 -8
- package/esm/LinearGenomeView/components/SearchResultsTable.js +4 -32
- package/esm/LinearGenomeView/components/StrandCheckboxes.d.ts +3 -2
- package/esm/LinearGenomeView/components/StrandCheckboxes.js +4 -2
- package/esm/LinearGenomeView/components/TrackContainer.js +1 -1
- package/esm/LinearGenomeView/components/TrackLabelMenu.js +8 -12
- package/esm/LinearGenomeView/components/useRangeSelect.js +3 -2
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.d.ts +3 -1
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.js +4 -2
- package/esm/LinearGenomeView/components/useSideScroll.js +11 -12
- package/esm/LinearGenomeView/lazyDialogs.d.ts +17 -2
- package/esm/LinearGenomeView/menuItems.js +32 -24
- package/esm/LinearGenomeView/model.d.ts +197 -151
- package/esm/LinearGenomeView/model.js +203 -201
- package/esm/LinearGenomeView/rExport/exportLinearView.d.ts +13 -0
- package/esm/LinearGenomeView/rExport/exportLinearView.js +98 -0
- package/esm/LinearGenomeView/rExport/rScript.d.ts +75 -0
- package/esm/LinearGenomeView/rExport/rScript.js +465 -0
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +3 -6
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +1 -2
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +2 -2
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +1 -2
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +4 -4
- package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +1 -2
- package/esm/LinearGenomeView/svgcomponents/SVGView.js +3 -3
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +22 -20
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +42 -29
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +6 -11
- package/esm/LinearGenomeView/svgcomponents/util.d.ts +2 -1
- package/esm/LinearGenomeView/util.d.ts +42 -0
- package/esm/LinearGenomeView/util.js +81 -0
- package/esm/MultiLevelRubberband/MultiLevelRubberband.js +2 -2
- package/esm/displayKitTests/perRegionTestEnv.d.ts +45 -12
- package/esm/index.d.ts +4 -2
- package/esm/index.js +3 -1
- package/esm/searchUtils.js +1 -0
- package/esm/shared/RubberbandSpan.d.ts +3 -2
- package/esm/shared/RubberbandSpan.js +4 -2
- package/esm/shared/coordLabels.d.ts +6 -6
- package/esm/shared/coordLabels.js +7 -6
- package/package.json +9 -9
|
@@ -2,7 +2,8 @@ import type PluginManager from '@jbrowse/core/PluginManager';
|
|
|
2
2
|
/**
|
|
3
3
|
* #config FeatureTrack
|
|
4
4
|
* #category track
|
|
5
|
-
*
|
|
5
|
+
* Holds gene and other feature annotations, such as a GFF3 or BED file, which
|
|
6
|
+
* `LinearBasicDisplay` usually draws.
|
|
6
7
|
*
|
|
7
8
|
* #example
|
|
8
9
|
* A minimal hand-authored entry in the top-level `tracks` array — `adapter`
|
|
@@ -3,7 +3,8 @@ import { createBaseTrackConfig } from '@jbrowse/core/pluggableElementTypes';
|
|
|
3
3
|
/**
|
|
4
4
|
* #config FeatureTrack
|
|
5
5
|
* #category track
|
|
6
|
-
*
|
|
6
|
+
* Holds gene and other feature annotations, such as a GFF3 or BED file, which
|
|
7
|
+
* `LinearBasicDisplay` usually draws.
|
|
7
8
|
*
|
|
8
9
|
* #example
|
|
9
10
|
* A minimal hand-authored entry in the top-level `tracks` array — `adapter`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getSession, isSessionModelWithWidgets,
|
|
1
|
+
import { getSession, isSessionModelWithWidgets, resolveNamedRegions, } from '@jbrowse/core/util';
|
|
2
2
|
import { coerceHighlight } from '@jbrowse/core/util/highlights';
|
|
3
3
|
import { installInitAutorun } from '@jbrowse/core/util/installInitAutorun';
|
|
4
4
|
import { normalizeTrackInit, warmTrackDisplayGeneric, } from '@jbrowse/core/util/tracks';
|
|
@@ -258,27 +258,6 @@ function setupCoarseDynamicBlocksAutorun(self) {
|
|
|
258
258
|
name: 'LGVCoarseDynamicBlocks',
|
|
259
259
|
}));
|
|
260
260
|
}
|
|
261
|
-
/**
|
|
262
|
-
* Autorun that syncs view settings to localStorage
|
|
263
|
-
*/
|
|
264
|
-
function setupLocalStorageAutorun(self) {
|
|
265
|
-
addDisposer(self, autorun(function localStorageAutorun() {
|
|
266
|
-
const s = (s) => JSON.stringify(s);
|
|
267
|
-
const { showCytobands, showCenterLine, colorByCDS, showAminoAcids, showTrackOutlines, trackLabels, } = self;
|
|
268
|
-
localStorageSetItem('lgv-showCytobands', s(showCytobands));
|
|
269
|
-
localStorageSetItem('lgv-showCenterLine', s(showCenterLine));
|
|
270
|
-
localStorageSetItem('lgv-colorByCDS', s(colorByCDS));
|
|
271
|
-
localStorageSetItem('lgv-showAminoAcids', s(showAminoAcids));
|
|
272
|
-
localStorageSetItem('lgv-showTrackOutlines', s(showTrackOutlines));
|
|
273
|
-
// skip writing the empty default — otherwise reads later round-trip to
|
|
274
|
-
// '' instead of null, hiding the config-fallback path
|
|
275
|
-
if (trackLabels) {
|
|
276
|
-
localStorageSetItem('lgv-trackLabels', trackLabels);
|
|
277
|
-
}
|
|
278
|
-
}, {
|
|
279
|
-
name: 'LGVLocalStorage',
|
|
280
|
-
}));
|
|
281
|
-
}
|
|
282
261
|
/**
|
|
283
262
|
* Sets up all afterAttach autoruns for the LinearGenomeView
|
|
284
263
|
*/
|
|
@@ -286,5 +265,4 @@ export function doAfterAttach(self) {
|
|
|
286
265
|
setupInitWarmup(self);
|
|
287
266
|
setupInitAutorun(self);
|
|
288
267
|
setupCoarseDynamicBlocksAutorun(self);
|
|
289
|
-
setupLocalStorageAutorun(self);
|
|
290
268
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { TrackLabelMode, ViewTrackLabelMode } from '../types.ts';
|
|
2
2
|
import type { BaseExportSvgOptions } from '@jbrowse/core/ui';
|
|
3
|
-
|
|
3
|
+
declare const ExportSvgDialog: ({ model, handleClose, chooseWidth, }: {
|
|
4
4
|
model: {
|
|
5
|
+
width?: number;
|
|
5
6
|
effectiveTrackLabels?: ViewTrackLabelMode;
|
|
6
7
|
exportSvg(opts: BaseExportSvgOptions & {
|
|
7
8
|
trackLabels: TrackLabelMode;
|
|
8
9
|
showGridlines: boolean;
|
|
10
|
+
viewWidth?: number;
|
|
9
11
|
}): Promise<unknown>;
|
|
10
12
|
};
|
|
11
13
|
handleClose: () => void;
|
|
12
|
-
|
|
14
|
+
chooseWidth?: boolean;
|
|
15
|
+
}) => import("react").JSX.Element;
|
|
16
|
+
export default ExportSvgDialog;
|
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { BaseExportSvgDialog, LabeledCheckbox, useExportSvgPreference, } from '@jbrowse/core/ui';
|
|
3
4
|
import { MenuItem, TextField } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
const MIN_WIDTH = 100;
|
|
7
|
+
const MAX_WIDTH = 10000;
|
|
4
8
|
// Shared track-label + gridlines export dialog. Used by LGV, linear-synteny and
|
|
5
|
-
// breakpoint-split views (their lazyDialogs re-export this).
|
|
6
|
-
|
|
9
|
+
// breakpoint-split views (their lazyDialogs re-export this). Only a caller
|
|
10
|
+
// passing `chooseWidth` offers the width field, whose model lays itself out at
|
|
11
|
+
// `viewWidth`.
|
|
12
|
+
const ExportSvgDialog = observer(function ExportSvgDialog({ model, handleClose, chooseWidth, }) {
|
|
7
13
|
// The view's own setting is already an export mode, so a user who has not
|
|
8
14
|
// picked one here gets the figure their screen shows. The key is `-mode`
|
|
9
15
|
// because the modes were once spelled `overlay`/`none`, and a stored one of
|
|
10
16
|
// those would select nothing in the dropdown.
|
|
11
17
|
const [trackLabels, setTrackLabels] = useExportSvgPreference('tracklabels-mode', model.effectiveTrackLabels ?? 'offset');
|
|
12
18
|
const [showGridlines, setShowGridlines] = useExportSvgPreference('gridlines', false);
|
|
13
|
-
|
|
19
|
+
// not a stored preference: a remembered width would drift from the screen's
|
|
20
|
+
const [widthText, setWidthText] = useState(() => String(Math.round(model.width ?? 0)));
|
|
21
|
+
const typedWidth = Number(widthText);
|
|
22
|
+
const widthValid = Number.isInteger(typedWidth) &&
|
|
23
|
+
typedWidth >= MIN_WIDTH &&
|
|
24
|
+
typedWidth <= MAX_WIDTH;
|
|
25
|
+
return (_jsxs(BaseExportSvgDialog, { model: model, handleClose: handleClose, exportSvg: opts => model.exportSvg({
|
|
26
|
+
...opts,
|
|
27
|
+
trackLabels,
|
|
28
|
+
showGridlines,
|
|
29
|
+
viewWidth: chooseWidth && widthValid ? typedWidth : undefined,
|
|
30
|
+
}), checkboxes: _jsx(LabeledCheckbox, { checked: showGridlines, onChange: val => {
|
|
14
31
|
setShowGridlines(val);
|
|
15
|
-
}, label: "Show gridlines" }), children: _jsxs(TextField, { select: true, label: "Track label positioning", variant: "outlined", style: { minWidth: 200 }, value: trackLabels, onChange: event => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
}, label: "Show gridlines" }), children: [_jsxs(TextField, { select: true, label: "Track label positioning", variant: "outlined", style: { minWidth: 200 }, value: trackLabels, onChange: event => {
|
|
33
|
+
setTrackLabels(event.target.value);
|
|
34
|
+
}, children: [_jsx(MenuItem, { value: "offset", children: "Offset" }), _jsx(MenuItem, { value: "overlapping", children: "Overlapping" }), _jsx(MenuItem, { value: "left", children: "Left" }), _jsx(MenuItem, { value: "hidden", children: "Hidden" })] }), chooseWidth ? (_jsx(TextField, { label: "Width (px)", variant: "outlined", type: "number", value: widthText, error: !widthValid, helperText: widthValid
|
|
35
|
+
? 'Lays the tracks out as a window this wide would; text keeps its size'
|
|
36
|
+
: `A whole number from ${MIN_WIDTH} to ${MAX_WIDTH}`, slotProps: {
|
|
37
|
+
htmlInput: { min: MIN_WIDTH, max: MAX_WIDTH, step: 1 },
|
|
38
|
+
}, onChange: event => {
|
|
39
|
+
setWidthText(event.target.value);
|
|
40
|
+
} })) : null] }));
|
|
41
|
+
});
|
|
42
|
+
export default ExportSvgDialog;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
2
|
type LGV = LinearGenomeViewModel;
|
|
3
|
-
|
|
3
|
+
declare const HeaderPanControls: ({ model, compact, }: {
|
|
4
4
|
model: LGV;
|
|
5
5
|
compact?: boolean;
|
|
6
|
-
})
|
|
7
|
-
export
|
|
6
|
+
}) => import("react").JSX.Element;
|
|
7
|
+
export default HeaderPanControls;
|
|
@@ -4,6 +4,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
|
4
4
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|
5
5
|
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
|
6
6
|
import { Button } from '@mui/material';
|
|
7
|
+
import { observer } from 'mobx-react';
|
|
7
8
|
import { SPACING, WIDGET_HEIGHT } from '../consts.js';
|
|
8
9
|
const useStyles = makeStyles()(theme => ({
|
|
9
10
|
panButton: {
|
|
@@ -20,7 +21,7 @@ const useStyles = makeStyles()(theme => ({
|
|
|
20
21
|
padding: theme.spacing(0, 0.5),
|
|
21
22
|
},
|
|
22
23
|
}));
|
|
23
|
-
|
|
24
|
+
const HeaderPanControls = observer(function HeaderPanControls({ model, compact, }) {
|
|
24
25
|
const { classes, cx } = useStyles();
|
|
25
26
|
const className = cx(classes.panButton, compact && classes.compact);
|
|
26
27
|
return (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outlined", "aria-label": "Pan left", className: className, onClick: () => {
|
|
@@ -28,4 +29,5 @@ export default function HeaderPanControls({ model, compact, }) {
|
|
|
28
29
|
}, children: _jsx(ArrowBackIcon, {}) }), _jsx(Button, { variant: "outlined", "aria-label": "Pan right", className: className, onClick: () => {
|
|
29
30
|
model.slide(0.9);
|
|
30
31
|
}, children: _jsx(ArrowForwardIcon, {}) })] }));
|
|
31
|
-
}
|
|
32
|
+
});
|
|
33
|
+
export default HeaderPanControls;
|
|
@@ -2,7 +2,7 @@ export declare function gapMask(gaps: {
|
|
|
2
2
|
top: number;
|
|
3
3
|
height: number;
|
|
4
4
|
}[]): string;
|
|
5
|
-
|
|
5
|
+
declare const HighlightBand: ({ coords, background, label, gaps, children, }: {
|
|
6
6
|
coords: {
|
|
7
7
|
left: number;
|
|
8
8
|
width: number;
|
|
@@ -14,4 +14,5 @@ export default function HighlightBand({ coords, background, label, gaps, childre
|
|
|
14
14
|
height: number;
|
|
15
15
|
}[];
|
|
16
16
|
children?: React.ReactNode;
|
|
17
|
-
})
|
|
17
|
+
}) => import("react").JSX.Element;
|
|
18
|
+
export default HighlightBand;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
4
5
|
const useStyles = makeStyles()(theme => ({
|
|
5
6
|
highlight: {
|
|
6
7
|
height: '100%',
|
|
@@ -37,7 +38,7 @@ export function gapMask(gaps) {
|
|
|
37
38
|
// colored band with an
|
|
38
39
|
// optional top label; when `children` (the highlight chip) is passed it renders
|
|
39
40
|
// that instead of the plain label. Visibility is toggled from the view menu
|
|
40
|
-
|
|
41
|
+
const HighlightBand = observer(function HighlightBand({ coords, background, label, gaps, children, }) {
|
|
41
42
|
const { classes } = useStyles();
|
|
42
43
|
const content = children ??
|
|
43
44
|
(label ? (_jsx(Typography, { variant: "caption", className: classes.label, noWrap: true, children: label })) : null);
|
|
@@ -49,4 +50,5 @@ export default function HighlightBand({ coords, background, label, gaps, childre
|
|
|
49
50
|
? { maskImage: gapMask(gaps), WebkitMaskImage: gapMask(gaps) }
|
|
50
51
|
: undefined),
|
|
51
52
|
}, children: coords.width > 3 && content ? (_jsx("div", { className: classes.overlay, children: content })) : null }));
|
|
52
|
-
}
|
|
53
|
+
});
|
|
54
|
+
export default HighlightBand;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { MenuItem } from '@jbrowse/core/ui';
|
|
2
2
|
import type { Colord } from '@jbrowse/core/util/colord';
|
|
3
|
-
|
|
3
|
+
declare const HighlightChip: ({ color, label, tooltip, menuItems, }: {
|
|
4
4
|
color: Colord;
|
|
5
5
|
label?: string;
|
|
6
6
|
tooltip?: string;
|
|
7
7
|
menuItems: MenuItem[];
|
|
8
|
-
})
|
|
8
|
+
}) => import("react").JSX.Element;
|
|
9
|
+
export default HighlightChip;
|
|
@@ -2,12 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
3
3
|
import LinkIcon from '@mui/icons-material/Link';
|
|
4
4
|
import { Box, Tooltip, Typography } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
5
6
|
// Interactive chip drawn inside a highlight band: a link icon tinted to the
|
|
6
7
|
// band color plus an optional inline label, wrapped in a context menu. Sets its
|
|
7
8
|
// own pointer-events since the band is click-through.
|
|
8
|
-
|
|
9
|
+
const HighlightChip = observer(function HighlightChip({ color, label, tooltip, menuItems, }) {
|
|
9
10
|
// hide the icon color when the band is fully transparent ("label-only"
|
|
10
11
|
// highlight); otherwise bump to 0.8 alpha so the chip stays legible
|
|
11
12
|
const chipAlpha = color.alpha() === 0 ? 0 : 0.8;
|
|
12
13
|
return (_jsx(Box, { sx: { pointerEvents: 'auto' }, children: _jsx(CascadingMenuButton, { "data-testid": "highlight-chip", menuItems: menuItems, children: _jsx(Tooltip, { title: tooltip, arrow: true, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [_jsx(LinkIcon, { fontSize: "small", sx: { color: color.alpha(chipAlpha).toRgbString() } }), label ? (_jsx(Typography, { variant: "caption", noWrap: true, children: label })) : null] }) }) }) }));
|
|
13
|
-
}
|
|
14
|
+
});
|
|
15
|
+
export default HighlightChip;
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { lazy } from 'react';
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense, lazy } from 'react';
|
|
3
3
|
import { ViewLoadingScreen } from '@jbrowse/core/ui';
|
|
4
4
|
import { observer } from 'mobx-react';
|
|
5
5
|
import LinearGenomeViewContainer from './LinearGenomeViewContainer.js';
|
|
6
6
|
// lazies
|
|
7
7
|
const ImportForm = lazy(() => import('./ImportForm.js'));
|
|
8
|
+
const SearchResultsDialog = lazy(() => import('./SearchResultsDialog.js'));
|
|
8
9
|
const LinearGenomeView = observer(function LinearGenomeView({ model, }) {
|
|
9
|
-
const { loading, showImportForm } = model;
|
|
10
|
-
|
|
11
|
-
return _jsx(ViewLoadingScreen, { ...loading });
|
|
12
|
-
}
|
|
13
|
-
else if (showImportForm) {
|
|
14
|
-
return _jsx(ImportForm, { model: model });
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
return _jsx(LinearGenomeViewContainer, { model: model });
|
|
18
|
-
}
|
|
10
|
+
const { loading, showImportForm, searchPicker } = model;
|
|
11
|
+
return (_jsxs(_Fragment, { children: [loading ? (_jsx(ViewLoadingScreen, { ...loading })) : showImportForm ? (_jsx(ImportForm, { model: model })) : (_jsx(LinearGenomeViewContainer, { model: model })), searchPicker ? (_jsx(Suspense, { fallback: null, children: _jsx(SearchResultsDialog, { model: model }) })) : null] }));
|
|
19
12
|
});
|
|
20
13
|
export default LinearGenomeView;
|
|
@@ -105,11 +105,10 @@ const LinearGenomeViewContainer = observer(function LinearGenomeViewContainer({
|
|
|
105
105
|
session.setHovered({ hoverPosition, hoverFeature });
|
|
106
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: {
|
|
107
107
|
top: stickyTops.pinnedTracks,
|
|
108
|
-
// the scroll port this sticks in, not the window:
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
// the page itself is the scroller
|
|
108
|
+
// the scroll port this sticks in, not the window: a
|
|
109
|
+
// workspace cell, or the host's box when embedded. The
|
|
110
|
+
// fallback is what an unbounded embed gets, where the
|
|
111
|
+
// page itself is the scroller
|
|
113
112
|
maxHeight: `calc(var(${SCROLL_PORT_HEIGHT_VAR}, 100vh) - ${stickyTops.pinnedTracks})`,
|
|
114
113
|
}, children: pinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id))) })) : null, unpinnedTracks.map(track => (_jsx(TrackContainer, { model: model, track: track }, track.id))), _jsx(ResizeAllTracksHandle, { model: model })] })) })) })] }) }));
|
|
115
114
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
declare const OverviewHighlightBand: ({ coords, background, borderColor, tooltip, }: {
|
|
2
2
|
coords: {
|
|
3
3
|
left: number;
|
|
4
4
|
width: number;
|
|
@@ -6,4 +6,5 @@ export default function OverviewHighlightBand({ coords, background, borderColor,
|
|
|
6
6
|
background: string;
|
|
7
7
|
borderColor?: string;
|
|
8
8
|
tooltip?: string;
|
|
9
|
-
})
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export default OverviewHighlightBand;
|
|
@@ -1,6 +1,7 @@
|
|
|
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
|
+
import { observer } from 'mobx-react';
|
|
4
5
|
// A single absolute-positioned band over the overview scalebar. The 1px border
|
|
5
6
|
// keeps very narrow bands visible.
|
|
6
7
|
const useStyles = makeStyles()({
|
|
@@ -10,7 +11,7 @@ const useStyles = makeStyles()({
|
|
|
10
11
|
left: 0,
|
|
11
12
|
},
|
|
12
13
|
});
|
|
13
|
-
|
|
14
|
+
const OverviewHighlightBand = observer(function OverviewHighlightBand({ coords, background, borderColor, tooltip, }) {
|
|
14
15
|
const { classes } = useStyles();
|
|
15
16
|
const band = (_jsx("div", { className: classes.highlight, style: {
|
|
16
17
|
transform: `translateX(${coords.left}px)`,
|
|
@@ -22,4 +23,5 @@ export default function OverviewHighlightBand({ coords, background, borderColor,
|
|
|
22
23
|
}),
|
|
23
24
|
} }));
|
|
24
25
|
return tooltip ? (_jsx(Tooltip, { title: tooltip, arrow: true, children: band })) : (band);
|
|
25
|
-
}
|
|
26
|
+
});
|
|
27
|
+
export default OverviewHighlightBand;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LinearGenomeViewModel } from '../model.ts';
|
|
2
|
-
|
|
2
|
+
declare const RegionWidthEditorDialog: ({ model, handleClose, }: {
|
|
3
3
|
model: LinearGenomeViewModel;
|
|
4
4
|
handleClose: () => void;
|
|
5
|
-
})
|
|
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
|
-
|
|
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;
|
|
@@ -54,9 +54,9 @@ const ScalebarRefNameLabels = observer(function ScalebarRefNameLabels({ model, }
|
|
|
54
54
|
setMenuState(undefined);
|
|
55
55
|
} })) : null] }));
|
|
56
56
|
});
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
function RefLabel({ model, label, onOpenMenu, }) {
|
|
57
|
+
// The attribute tells the scalebar's rubberband to leave a click here to this
|
|
58
|
+
// label's onClick.
|
|
59
|
+
const RefLabel = observer(function RefLabel({ model, label, onOpenMenu, }) {
|
|
60
60
|
const { classes, cx } = useStyles();
|
|
61
61
|
const { refName, transform, maxWidth, paddingLeft, text } = label;
|
|
62
62
|
return (_jsx("span", { className: cx(classes.refLabel, classes.clickable), style: {
|
|
@@ -67,7 +67,7 @@ function RefLabel({ model, label, onOpenMenu, }) {
|
|
|
67
67
|
model.setIsScalebarRefNameMenuOpen(true);
|
|
68
68
|
onOpenMenu({ anchorEl: e.currentTarget, label });
|
|
69
69
|
}, children: text }));
|
|
70
|
-
}
|
|
70
|
+
});
|
|
71
71
|
const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }) {
|
|
72
72
|
const { displayedRegions } = model;
|
|
73
73
|
const { refName, displayedRegionIndex: idx, lastDisplayedRegionIndex: lastIdx, } = menuState.label;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
2
|
+
declare const SearchPanelForm: ({ onSubmit, handleClose, submitDisabled, submitText, actions, children, }: {
|
|
3
3
|
onSubmit: () => void;
|
|
4
4
|
handleClose: () => void;
|
|
5
5
|
submitDisabled: boolean;
|
|
6
6
|
submitText?: string;
|
|
7
7
|
actions?: ReactNode;
|
|
8
8
|
children: ReactNode;
|
|
9
|
-
})
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export default SearchPanelForm;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { SubmitForm } from '@jbrowse/core/ui';
|
|
3
3
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
4
5
|
const useStyles = makeStyles()({
|
|
5
6
|
dialogContent: {
|
|
6
7
|
width: '34em',
|
|
@@ -12,7 +13,8 @@ const useStyles = makeStyles()({
|
|
|
12
13
|
// The chrome shared by the sequence-search mode panels: the fixed-width column
|
|
13
14
|
// their fields lay out in, plus SubmitForm's Cancel/Submit footer. Each panel
|
|
14
15
|
// still owns its own fields and its own submit, so this is only the frame.
|
|
15
|
-
|
|
16
|
+
const SearchPanelForm = observer(function SearchPanelForm({ onSubmit, handleClose, submitDisabled, submitText, actions, children, }) {
|
|
16
17
|
const { classes } = useStyles();
|
|
17
18
|
return (_jsx(SubmitForm, { contentClassName: classes.dialogContent, onSubmit: onSubmit, onCancel: handleClose, submitDisabled: submitDisabled, submitText: submitText, actions: actions, children: children }));
|
|
18
|
-
}
|
|
19
|
+
});
|
|
20
|
+
export default SearchPanelForm;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import type { LinearGenomeViewModel } from '
|
|
2
|
-
|
|
3
|
-
export default function SearchResultsDialog({ model, assemblyName, searchQuery, searchResults, handleClose, onPick, }: {
|
|
1
|
+
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
|
+
declare const SearchResultsDialog: ({ model, }: {
|
|
4
3
|
model: LinearGenomeViewModel;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
searchResults: BaseResult[];
|
|
8
|
-
handleClose: () => void;
|
|
9
|
-
onPick: (result: BaseResult) => Promise<unknown>;
|
|
10
|
-
}): import("react").JSX.Element;
|
|
4
|
+
}) => import("react").JSX.Element | null;
|
|
5
|
+
export default SearchResultsDialog;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { InfoDialog } from '@jbrowse/core/ui';
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
4
5
|
import SearchResultsTable from './SearchResultsTable.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
6
|
+
const SearchResultsDialog = observer(function SearchResultsDialog({ model, }) {
|
|
7
|
+
const { searchPicker } = model;
|
|
8
|
+
return searchPicker ? (_jsxs(InfoDialog, { open: true, maxWidth: "xl", onClose: model.closeSearchPicker, title: "Search results", children: [_jsxs(Typography, { children: ["Showing results for ", _jsx("b", { children: searchPicker.query })] }), _jsx(SearchResultsTable, { picker: searchPicker })] })) : null;
|
|
9
|
+
});
|
|
10
|
+
export default SearchResultsDialog;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
searchResults: BaseResult[];
|
|
5
|
-
assemblyName: string;
|
|
6
|
-
model: LinearGenomeViewModel;
|
|
7
|
-
handleClose: () => void;
|
|
8
|
-
onPick: (result: BaseResult) => Promise<unknown>;
|
|
1
|
+
import type { SearchPickerState } from '../model.ts';
|
|
2
|
+
declare const SearchResultsTable: ({ picker, }: {
|
|
3
|
+
picker: SearchPickerState;
|
|
9
4
|
}) => import("react").JSX.Element;
|
|
10
5
|
export default SearchResultsTable;
|
|
@@ -1,38 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { canonicalLocString } from '@jbrowse/core/TextSearch/places';
|
|
3
2
|
import { SanitizedHTML } from '@jbrowse/core/ui';
|
|
4
|
-
import { getSession } from '@jbrowse/core/util';
|
|
5
3
|
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, } from '@mui/material';
|
|
6
4
|
import { observer } from 'mobx-react';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const assembly = assemblyManager.get(assemblyName);
|
|
12
|
-
function getTrackName(trackId) {
|
|
13
|
-
const conf = trackId !== undefined ? session.getTrackById(trackId) : undefined;
|
|
14
|
-
return conf?.name ?? '';
|
|
15
|
-
}
|
|
16
|
-
// A location the assembly can't resolve is listed as-is: Go navigates
|
|
17
|
-
// through navToOption, which reports its own failure
|
|
18
|
-
function formatLocation(locString) {
|
|
19
|
-
return assembly && locString
|
|
20
|
-
? canonicalLocString(locString, assembly)
|
|
21
|
-
: locString;
|
|
22
|
-
}
|
|
23
|
-
// A hit in a track that is already on screen is usually the one meant, so it
|
|
24
|
-
// is listed first rather than given a control that says so. sort is stable,
|
|
25
|
-
// so everything else keeps the ranked order it arrived in.
|
|
26
|
-
const ordered = [...searchResults].sort((a, b) => Number(isOpenInView(b, model)) - Number(isOpenInView(a, model)));
|
|
27
|
-
return (_jsx(TableContainer, { component: Paper, children: _jsxs(Table, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Name" }), _jsx(TableCell, { align: "right", children: "Location" }), _jsx(TableCell, { align: "right", children: "Track" }), _jsx(TableCell, { align: "right" })] }) }), _jsx(TableBody, { children: ordered.map(result => (_jsxs(TableRow, { children: [_jsx(TableCell, { component: "th", scope: "row", children: result.getLabel() }), _jsx(TableCell, { align: "right", children: formatLocation(result.getLocation()) }), _jsx(TableCell, { align: "right", children: _jsx(SanitizedHTML, { html: getTrackName(result.getTrackId()) || 'N/A' }) }), _jsx(TableCell, { align: "right", children: _jsx(Button, { onClick: async () => {
|
|
28
|
-
try {
|
|
29
|
-
await onPick(result);
|
|
30
|
-
}
|
|
31
|
-
catch (e) {
|
|
32
|
-
console.error(e);
|
|
33
|
-
session.notifyError(`${e}`, e);
|
|
34
|
-
}
|
|
35
|
-
handleClose();
|
|
36
|
-
}, color: "primary", variant: "contained", children: "Go" }) })] }, result.getId()))) })] }) }));
|
|
5
|
+
const SearchResultsTable = observer(function SearchResultsTable({ picker, }) {
|
|
6
|
+
return (_jsx(TableContainer, { component: Paper, children: _jsxs(Table, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Name" }), _jsx(TableCell, { align: "right", children: "Location" }), _jsx(TableCell, { align: "right", children: "Track" }), _jsx(TableCell, { align: "right" })] }) }), _jsx(TableBody, { children: picker.rows.map(row => (_jsxs(TableRow, { children: [_jsx(TableCell, { component: "th", scope: "row", children: row.label }), _jsx(TableCell, { align: "right", children: row.location }), _jsx(TableCell, { align: "right", children: _jsx(SanitizedHTML, { html: row.trackName || 'N/A' }) }), _jsx(TableCell, { align: "right", children: _jsx(Button, { onClick: () => {
|
|
7
|
+
void picker.pick(row.id);
|
|
8
|
+
}, color: "primary", variant: "contained", children: "Go" }) })] }, row.id))) })] }) }));
|
|
37
9
|
});
|
|
38
10
|
export default SearchResultsTable;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
2
|
+
declare const StrandCheckboxes: ({ searchForward, searchReverse, setSearchForward, setSearchReverse, children, }: {
|
|
3
3
|
searchForward: boolean;
|
|
4
4
|
searchReverse: boolean;
|
|
5
5
|
setSearchForward: (arg: boolean) => void;
|
|
6
6
|
setSearchReverse: (arg: boolean) => void;
|
|
7
7
|
children?: ReactNode;
|
|
8
|
-
})
|
|
8
|
+
}) => import("react").JSX.Element;
|
|
9
|
+
export default StrandCheckboxes;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { LabeledCheckbox } from '@jbrowse/core/ui';
|
|
3
3
|
import { FormGroup, Typography } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
4
5
|
// Forward/reverse strand checkboxes plus the "select at least one" guard, shared
|
|
5
6
|
// by the sequence-search mode panels. Extra checkboxes for a specific panel (e.g.
|
|
6
7
|
// "Case insensitive") slot in alongside via `children`.
|
|
7
|
-
|
|
8
|
+
const StrandCheckboxes = observer(function StrandCheckboxes({ searchForward, searchReverse, setSearchForward, setSearchReverse, children, }) {
|
|
8
9
|
return (_jsxs(_Fragment, { children: [_jsxs(FormGroup, { row: true, children: [_jsx(LabeledCheckbox, { size: "small", checked: searchForward, onChange: val => {
|
|
9
10
|
setSearchForward(val);
|
|
10
11
|
}, label: "Forward strand" }), _jsx(LabeledCheckbox, { size: "small", checked: searchReverse, onChange: val => {
|
|
11
12
|
setSearchReverse(val);
|
|
12
13
|
}, label: "Reverse strand" }), children] }), !searchForward && !searchReverse ? (_jsx(Typography, { color: "error", variant: "body2", children: "Select at least one strand" })) : null] }));
|
|
13
|
-
}
|
|
14
|
+
});
|
|
15
|
+
export default StrandCheckboxes;
|
|
@@ -135,7 +135,7 @@ const TrackContainer = observer(function TrackContainer({ model, track, }) {
|
|
|
135
135
|
const { setPaper, setContainer } = useTrackLabelBand(model, track.trackId);
|
|
136
136
|
return (_jsxs(Paper, { ref: setPaper, className: cx(classes.root, track.pinned ? null : classes.unpinnedTrack), variant: showTrackOutlines ? 'outlined' : undefined, elevation: showTrackOutlines ? undefined : 0, onDragOver: event => {
|
|
137
137
|
model.onTrackDragOver(track.id, event.clientY);
|
|
138
|
-
}, children: [track.pinned ? _jsx(Gridlines, { model: model, offset: outlineOffset }) : null, model.effectiveTrackLabels !== 'hidden' ? (_jsx(TrackLabel, { track: track, className: trackLabelStyle })) : null, _jsx(TrackOverlaySlot, { zIndex: 100, overlayStyle: { left: -outlineOffset }, children: _jsx(ErrorBoundary, { FallbackComponent: e => (_jsx("div", { className: classes.crashBanner, children: _jsx(ErrorBanner, { error: e.error, onReset: e.resetErrorBoundary }) })), children: _jsx(TrackRenderingContainer, { model: model, track: track, display: display, ref: setContainer }) }, display.id) }), _jsx(PaddingBlocks, { model: model, offset: outlineOffset }), _jsx(ResizeHandle, { style: { height: RESIZE_HANDLE_HEIGHT }, onDrag: distance => display.resizeHeight(distance),
|
|
138
|
+
}, children: [track.pinned ? _jsx(Gridlines, { model: model, offset: outlineOffset }) : null, model.effectiveTrackLabels !== 'hidden' ? (_jsx(TrackLabel, { track: track, className: trackLabelStyle })) : null, _jsx(TrackOverlaySlot, { zIndex: 100, overlayStyle: { left: -outlineOffset }, children: _jsx(ErrorBoundary, { FallbackComponent: e => (_jsx("div", { className: classes.crashBanner, "data-gesture-owner": "true", children: _jsx(ErrorBanner, { error: e.error, onReset: e.resetErrorBoundary }) })), children: _jsx(TrackRenderingContainer, { model: model, track: track, display: display, ref: setContainer }) }, display.id) }), _jsx(PaddingBlocks, { model: model, offset: outlineOffset }), _jsx(ResizeHandle, { style: { height: RESIZE_HANDLE_HEIGHT }, onDrag: distance => display.resizeHeight(distance),
|
|
139
139
|
// the drag's shortcut: grow the track by whatever it is scrolled over,
|
|
140
140
|
// so a pileup showing three rows of forty opens to all forty
|
|
141
141
|
// Optional: only a display that scrolls its own content has anything
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
3
|
+
import { TRACK_MENU_PRIORITY, subMenuIfAny } from '@jbrowse/core/ui/menuItems';
|
|
3
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';
|
|
@@ -27,21 +28,16 @@ const TrackLabelMenu = observer(function TrackLabelMenu({ track, }) {
|
|
|
27
28
|
view,
|
|
28
29
|
}) ?? [];
|
|
29
30
|
return [
|
|
30
|
-
...(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
priority: 1000,
|
|
37
|
-
subMenu: orderSubMenu,
|
|
38
|
-
},
|
|
39
|
-
]
|
|
40
|
-
: []),
|
|
31
|
+
...subMenuIfAny({
|
|
32
|
+
label: 'Track order',
|
|
33
|
+
icon: LowPriorityIcon,
|
|
34
|
+
priority: TRACK_MENU_PRIORITY.trackOrder,
|
|
35
|
+
subMenu: orderSubMenu,
|
|
36
|
+
}),
|
|
41
37
|
...sessionItems,
|
|
42
38
|
track.saveTrackDataMenuItem,
|
|
43
39
|
...track.trackMenuItems(),
|
|
44
|
-
]
|
|
40
|
+
];
|
|
45
41
|
}
|
|
46
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" }) }));
|
|
47
43
|
});
|