@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.
- package/esm/LinearGenomeView/afterAttach.d.ts +22 -5
- package/esm/LinearGenomeView/afterAttach.js +129 -106
- package/esm/LinearGenomeView/axisConfigSchema.d.ts +18 -0
- package/esm/LinearGenomeView/axisConfigSchema.js +22 -0
- package/esm/LinearGenomeView/components/CenterLine.js +10 -5
- package/esm/LinearGenomeView/components/ConnectedHoverHighlight.js +2 -3
- package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +9 -4
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +45 -8
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
- package/esm/LinearGenomeView/components/Header.js +11 -1
- package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
- package/esm/LinearGenomeView/components/HeaderPanControls.d.ts +3 -3
- package/esm/LinearGenomeView/components/HeaderPanControls.js +6 -3
- package/esm/LinearGenomeView/components/HeaderSearchBoxes.js +4 -1
- package/esm/LinearGenomeView/components/HeaderZoomControls.js +6 -35
- package/esm/LinearGenomeView/components/Highlight.js +27 -11
- package/esm/LinearGenomeView/components/HighlightBand.d.ts +11 -2
- package/esm/LinearGenomeView/components/HighlightBand.js +32 -13
- package/esm/LinearGenomeView/components/HighlightChip.d.ts +3 -3
- package/esm/LinearGenomeView/components/HighlightChip.js +13 -8
- package/esm/LinearGenomeView/components/HighlightLabelDialog.d.ts +6 -0
- package/esm/LinearGenomeView/components/HighlightLabelDialog.js +18 -0
- package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
- package/esm/LinearGenomeView/components/ImportForm.js +7 -9
- package/esm/LinearGenomeView/components/LinearGenomeView.js +5 -12
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +13 -14
- package/esm/LinearGenomeView/components/MiniControls.js +11 -5
- package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
- package/esm/LinearGenomeView/components/OverviewHighlightBand.d.ts +3 -2
- package/esm/LinearGenomeView/components/OverviewHighlightBand.js +6 -5
- package/esm/LinearGenomeView/components/OverviewRubberband.js +25 -48
- package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
- package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
- package/esm/LinearGenomeView/components/PaddingBlocks.js +3 -8
- package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.d.ts +3 -2
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.js +4 -4
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +74 -0
- package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
- package/esm/LinearGenomeView/components/Rubberband.js +3 -2
- package/esm/LinearGenomeView/components/SVGHighlightBand.d.ts +10 -1
- package/esm/LinearGenomeView/components/SVGHighlightBand.js +16 -5
- package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
- package/esm/LinearGenomeView/components/Scalebar.js +8 -5
- package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +51 -36
- package/esm/LinearGenomeView/components/SearchBox.js +10 -16
- 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 -8
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -4
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +4 -7
- package/esm/LinearGenomeView/components/SearchResultsTable.js +25 -53
- package/esm/LinearGenomeView/components/SequenceFeatureHoverHighlight.js +2 -3
- package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
- package/esm/LinearGenomeView/components/StrandCheckboxes.d.ts +3 -2
- package/esm/LinearGenomeView/components/StrandCheckboxes.js +4 -2
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +2 -3
- package/esm/LinearGenomeView/components/TrackContainer.js +63 -10
- package/esm/LinearGenomeView/components/TrackLabel.js +14 -4
- package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +4 -5
- package/esm/LinearGenomeView/components/TrackLabelMenu.js +11 -14
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.d.ts +3 -4
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.js +23 -10
- package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +6 -4
- package/esm/LinearGenomeView/components/TrackRenderingContainer.js +12 -24
- package/esm/LinearGenomeView/components/TracksContainer.js +11 -23
- package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
- package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
- package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
- package/esm/LinearGenomeView/components/fetchSequence.js +15 -7
- package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
- package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
- package/esm/LinearGenomeView/components/useRangeSelect.js +26 -61
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.d.ts +3 -1
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.js +4 -2
- package/esm/LinearGenomeView/components/useSideScroll.d.ts +17 -2
- package/esm/LinearGenomeView/components/useSideScroll.js +156 -102
- package/esm/LinearGenomeView/components/util.d.ts +4 -0
- package/esm/LinearGenomeView/components/util.js +4 -2
- package/esm/LinearGenomeView/consts.d.ts +2 -0
- package/esm/LinearGenomeView/consts.js +3 -1
- package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
- package/esm/LinearGenomeView/containingLgv.js +23 -0
- package/esm/LinearGenomeView/headerFit.d.ts +4 -2
- package/esm/LinearGenomeView/headerFit.js +20 -7
- package/esm/LinearGenomeView/index.d.ts +2 -7
- package/esm/LinearGenomeView/index.js +5 -7
- package/esm/LinearGenomeView/keyboardHandler.d.ts +8 -7
- package/esm/LinearGenomeView/keyboardHandler.js +61 -23
- package/esm/LinearGenomeView/launchKeys.d.ts +1 -1
- package/esm/LinearGenomeView/launchKeys.js +11 -6
- package/esm/LinearGenomeView/lazyDialogs.d.ts +16 -3
- package/esm/LinearGenomeView/lazyDialogs.js +1 -0
- package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
- package/esm/LinearGenomeView/linkedViewSync.js +27 -49
- package/esm/LinearGenomeView/menuItems.d.ts +16 -18
- package/esm/LinearGenomeView/menuItems.js +264 -164
- package/esm/LinearGenomeView/model.d.ts +1192 -560
- package/esm/LinearGenomeView/model.js +805 -590
- package/esm/LinearGenomeView/rExport/exportLinearView.d.ts +17 -0
- package/esm/LinearGenomeView/rExport/exportLinearView.js +117 -0
- package/esm/LinearGenomeView/rExport/rScript.d.ts +110 -0
- package/esm/LinearGenomeView/rExport/rScript.js +524 -0
- package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
- package/esm/LinearGenomeView/sharedScaleContainer.js +2 -12
- package/esm/LinearGenomeView/showFiles.d.ts +2 -0
- package/esm/LinearGenomeView/showFiles.js +19 -0
- package/esm/LinearGenomeView/showRegionsWithUndo.d.ts +1 -1
- package/esm/LinearGenomeView/showRegionsWithUndo.js +13 -5
- package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
- package/esm/LinearGenomeView/stickyChrome.js +5 -9
- package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
- package/esm/LinearGenomeView/svgcomponents/SVGHighlights.d.ts +3 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +9 -9
- package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.d.ts +3 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +5 -5
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +13 -18
- package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
- package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
- package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
- package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +26 -0
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +21 -13
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -5
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +7 -6
- package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +2 -3
- package/esm/LinearGenomeView/svgcomponents/SVGView.js +17 -3
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +24 -20
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +42 -29
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +74 -77
- package/esm/LinearGenomeView/svgcomponents/util.d.ts +28 -12
- package/esm/LinearGenomeView/svgcomponents/util.js +41 -29
- package/esm/LinearGenomeView/types.d.ts +13 -10
- package/esm/LinearGenomeView/types.js +0 -1
- package/esm/LinearGenomeView/util.d.ts +103 -46
- package/esm/LinearGenomeView/util.js +222 -170
- package/esm/MultiLevelRubberband/MultiLevelRubberband.js +9 -6
- package/esm/MultiLevelRubberband/index.d.ts +2 -0
- package/esm/MultiLevelRubberband/index.js +2 -0
- package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
- package/esm/MultiLevelRubberband/menuItems.js +52 -0
- package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
- package/esm/MultiLevelRubberband/rowLabel.js +27 -0
- package/esm/MultiLevelRubberband/types.d.ts +1 -0
- package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
- package/esm/MultiLevelRubberband/useRangeSelect.js +45 -59
- package/esm/TrackModifiers/index.d.ts +83 -0
- package/esm/TrackModifiers/index.js +231 -0
- package/esm/displayKitTests/perRegionTestEnv.d.ts +244 -68
- package/esm/displayKitTests/perRegionTestEnv.js +30 -26
- package/esm/index.d.ts +21 -99
- package/esm/index.js +17 -38
- package/esm/searchUtils.d.ts +26 -10
- package/esm/searchUtils.js +137 -137
- package/esm/shared/RubberbandSpan.d.ts +3 -2
- package/esm/shared/RubberbandSpan.js +6 -3
- package/esm/shared/coordLabels.d.ts +11 -4
- package/esm/shared/coordLabels.js +20 -5
- package/esm/shared/useWindowDrag.d.ts +18 -0
- package/esm/shared/useWindowDrag.js +47 -0
- package/package.json +12 -11
- package/esm/FeatureTrack/configSchema.d.ts +0 -124
- package/esm/FeatureTrack/configSchema.js +0 -54
- package/esm/FeatureTrack/index.d.ts +0 -2
- package/esm/FeatureTrack/index.js +0 -13
- package/esm/LinearGenomeView/initKeys.d.ts +0 -12
- package/esm/LinearGenomeView/initKeys.js +0 -68
- package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
- package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
- package/esm/lazyPluginExports.d.ts +0 -23
- package/esm/lazyPluginExports.js +0 -36
|
@@ -5,7 +5,8 @@ import { assembleLocString, assembleLocStrings } from '@jbrowse/core/util';
|
|
|
5
5
|
import { copyText } from '@jbrowse/core/util/copyText';
|
|
6
6
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
7
7
|
import { observer } from 'mobx-react';
|
|
8
|
-
import { REF_NAME_LABEL_FONT_SIZE, regionMoveActions, withRegionMoved, withRegionRemoved, withRegionReversed, } from '../util.js';
|
|
8
|
+
import { REF_NAME_LABEL_FONT_SIZE, regionMoveActions, regionRunBounds, withRegionMoved, withRegionRemoved, withRegionReversed, withRegionsKept, } from '../util.js';
|
|
9
|
+
import { scalebarRefLabelProps } from './util.js';
|
|
9
10
|
const useStyles = makeStyles()(theme => ({
|
|
10
11
|
refLabel: {
|
|
11
12
|
// the width the fit test in getScalebarRefNameLabels measures against
|
|
@@ -31,65 +32,45 @@ const useStyles = makeStyles()(theme => ({
|
|
|
31
32
|
overflow: 'clip',
|
|
32
33
|
whiteSpace: 'nowrap',
|
|
33
34
|
},
|
|
34
|
-
//
|
|
35
|
-
// caption, and wearing the pointer and the hover tint made it look like the
|
|
36
|
-
// one thing on the row that does nothing when clicked
|
|
35
|
+
// refName labels only: the caption chip opens no menu
|
|
37
36
|
clickable: {
|
|
38
37
|
cursor: 'pointer',
|
|
39
38
|
'&:hover': {
|
|
40
|
-
// action.hover is a mode-aware translucent overlay; the old hardcoded
|
|
41
|
-
// grey[300] stayed light in dark mode, washing out the light label text
|
|
42
39
|
background: theme.palette.action.hover,
|
|
43
40
|
},
|
|
44
41
|
},
|
|
45
|
-
|
|
42
|
+
caption: {
|
|
46
43
|
zIndex: 100,
|
|
47
44
|
},
|
|
48
45
|
}));
|
|
49
46
|
const ScalebarRefNameLabels = observer(function ScalebarRefNameLabels({ model, }) {
|
|
50
47
|
const { classes, cx } = useStyles();
|
|
51
48
|
const [menuState, setMenuState] = useState();
|
|
52
|
-
// `model.scalebarRefNameLabels`, not a getScalebarRefNameLabels call of its
|
|
53
|
-
// own: a host drawing its own region names reads the same getter, so the
|
|
54
|
-
// sticky/dedup/fit rules can't be one thing here and another there. The SVG
|
|
55
|
-
// export still calls the helper directly, deliberately and with no prefix.
|
|
56
49
|
const { labels, caption } = model.scalebarRefNameLabels;
|
|
57
50
|
return (_jsxs(_Fragment, { children: [labels.map((label, i) => (_jsx(RefLabel
|
|
58
51
|
// eslint-disable-next-line @eslint-react/no-array-index-key -- position IS the identity here; keying by the run makes the list churn on zoom
|
|
59
|
-
, { model: model, label: label, onOpenMenu:
|
|
60
|
-
setMenuState(state);
|
|
61
|
-
} }, i))), caption === undefined ? null : (_jsx("span", { className: cx(classes.prefixLabel, classes.refLabel), "data-testid": "refLabel-prefix", children: caption })), menuState ? (_jsx(RefNameMenu, { model: model, menuState: menuState, onClose: () => {
|
|
52
|
+
, { model: model, label: label, onOpenMenu: setMenuState }, i))), caption === undefined ? null : (_jsx("span", { className: cx(classes.caption, classes.refLabel), "data-testid": "refLabel-prefix", children: caption })), menuState ? (_jsx(RefNameMenu, { model: model, menuState: menuState, onClose: () => {
|
|
62
53
|
model.setIsScalebarRefNameMenuOpen(false);
|
|
63
54
|
setMenuState(undefined);
|
|
64
55
|
} })) : null] }));
|
|
65
56
|
});
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
// this label's own onClick instead of opening the range menu.
|
|
70
|
-
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, }) {
|
|
71
60
|
const { classes, cx } = useStyles();
|
|
72
|
-
const { refName,
|
|
61
|
+
const { refName, transform, maxWidth, paddingLeft, text } = label;
|
|
73
62
|
return (_jsx("span", { className: cx(classes.refLabel, classes.clickable), style: {
|
|
74
63
|
transform: `translateX(${transform}px)`,
|
|
75
64
|
paddingLeft,
|
|
76
65
|
maxWidth,
|
|
77
|
-
}, "data-testid": `refLabel-${refName}`,
|
|
78
|
-
model.setScalebarRefNameClickPending(true);
|
|
79
|
-
}, onClick: e => {
|
|
80
|
-
model.setScalebarRefNameClickPending(false);
|
|
66
|
+
}, "data-testid": `refLabel-${refName}`, ...scalebarRefLabelProps, onClick: e => {
|
|
81
67
|
model.setIsScalebarRefNameMenuOpen(true);
|
|
82
|
-
onOpenMenu({
|
|
83
|
-
anchorEl: e.currentTarget,
|
|
84
|
-
refName,
|
|
85
|
-
displayedRegionIndex,
|
|
86
|
-
lastDisplayedRegionIndex,
|
|
87
|
-
});
|
|
68
|
+
onOpenMenu({ anchorEl: e.currentTarget, label });
|
|
88
69
|
}, children: text }));
|
|
89
|
-
}
|
|
70
|
+
});
|
|
90
71
|
const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }) {
|
|
91
72
|
const { displayedRegions } = model;
|
|
92
|
-
const { refName, displayedRegionIndex: idx, lastDisplayedRegionIndex: lastIdx, } = menuState;
|
|
73
|
+
const { refName, displayedRegionIndex: idx, lastDisplayedRegionIndex: lastIdx, } = menuState.label;
|
|
93
74
|
const numRegions = displayedRegions.length;
|
|
94
75
|
const labeled = displayedRegions.slice(idx, lastIdx + 1);
|
|
95
76
|
// A label naming several regions is the collapsed-intron case: adjacent
|
|
@@ -104,6 +85,16 @@ const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }
|
|
|
104
85
|
const locString = oneRegion
|
|
105
86
|
? assembleLocString(displayedRegions[idx])
|
|
106
87
|
: assembleLocStrings(labeled);
|
|
88
|
+
// The region this label's blocks were cut out of. Taken over the WHOLE run
|
|
89
|
+
// rather than `labeled`, which the viewport clips: a collapsed-introns view
|
|
90
|
+
// zoomed into two exons would otherwise offer a span that is not the gene's.
|
|
91
|
+
const { first: runFirst, last: runLast } = regionRunBounds(displayedRegions, idx, lastIdx);
|
|
92
|
+
const run = displayedRegions.slice(runFirst, runLast + 1);
|
|
93
|
+
const wholeSpan = {
|
|
94
|
+
...run[0],
|
|
95
|
+
start: Math.min(...run.map(r => r.start)),
|
|
96
|
+
end: Math.max(...run.map(r => r.end)),
|
|
97
|
+
};
|
|
107
98
|
return (_jsx(Menu, { anchorEl: menuState.anchorEl, open: true, onClose: onClose, onMenuItemClick: callback => {
|
|
108
99
|
callback();
|
|
109
100
|
onClose();
|
|
@@ -126,7 +117,31 @@ const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }
|
|
|
126
117
|
? 'Show only this region'
|
|
127
118
|
: `Show only ${refName}`,
|
|
128
119
|
onClick: () => {
|
|
129
|
-
model.
|
|
120
|
+
model.editDisplayedRegions(withRegionsKept(displayedRegions, idx, lastIdx));
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
: []),
|
|
125
|
+
...(runLast > runFirst
|
|
126
|
+
? [
|
|
127
|
+
{
|
|
128
|
+
// Names its subject the way the two rows above it do; the span
|
|
129
|
+
// it lands on is not spelled into the label, which would move
|
|
130
|
+
// under the reader as they navigate.
|
|
131
|
+
label: `Show the whole span of ${refName}`,
|
|
132
|
+
// Focused rather than centre-kept: the rejoined region is one
|
|
133
|
+
// the old viewport never saw, so there is no centre to hold,
|
|
134
|
+
// and showing the span is the whole point of the row.
|
|
135
|
+
onClick: () => {
|
|
136
|
+
model.setDisplayedRegions([
|
|
137
|
+
...displayedRegions.slice(0, runFirst),
|
|
138
|
+
wholeSpan,
|
|
139
|
+
...displayedRegions.slice(runLast + 1),
|
|
140
|
+
]);
|
|
141
|
+
model.moveTo({ index: runFirst, offset: 0 }, {
|
|
142
|
+
index: runFirst,
|
|
143
|
+
offset: wholeSpan.end - wholeSpan.start,
|
|
144
|
+
});
|
|
130
145
|
},
|
|
131
146
|
},
|
|
132
147
|
]
|
|
@@ -156,13 +171,13 @@ const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }
|
|
|
156
171
|
{
|
|
157
172
|
label: 'Reverse region',
|
|
158
173
|
onClick: () => {
|
|
159
|
-
model.
|
|
174
|
+
model.editDisplayedRegions(withRegionReversed(displayedRegions, idx));
|
|
160
175
|
},
|
|
161
176
|
},
|
|
162
177
|
...regionMoveActions(idx, numRegions).map(({ label, to }) => ({
|
|
163
178
|
label,
|
|
164
179
|
onClick: () => {
|
|
165
|
-
model.
|
|
180
|
+
model.editDisplayedRegions(withRegionMoved(displayedRegions, idx, to));
|
|
166
181
|
},
|
|
167
182
|
})),
|
|
168
183
|
...(numRegions > 1
|
|
@@ -170,7 +185,7 @@ const RefNameMenu = observer(function RefNameMenu({ model, menuState, onClose, }
|
|
|
170
185
|
{
|
|
171
186
|
label: 'Remove this region from view',
|
|
172
187
|
onClick: () => {
|
|
173
|
-
model.
|
|
188
|
+
model.editDisplayedRegions(withRegionRemoved(displayedRegions, idx));
|
|
174
189
|
},
|
|
175
190
|
},
|
|
176
191
|
]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { RefNameAutocomplete, RefNameAutocompleteEndAdornment, adornmentReservePx, getInputWidth, useRecentLocations, } from '@jbrowse/core/ui';
|
|
3
|
+
import { usePalette } from '@jbrowse/core/ui/PaletteContext';
|
|
4
|
+
import { alpha } from '@jbrowse/core/ui/palette';
|
|
3
5
|
import { getSession } from '@jbrowse/core/util';
|
|
4
|
-
import { alpha, useTheme } from '@mui/material';
|
|
5
6
|
import { observer } from 'mobx-react';
|
|
6
7
|
import { fetchResults, navigateToSelectedOption, notifySearchFailure, } from '../../searchUtils.js';
|
|
7
8
|
import { SPACING, WIDGET_HEIGHT } from '../consts.js';
|
|
@@ -31,17 +32,16 @@ export function searchBoxWidth(value) {
|
|
|
31
32
|
2 * SPACING);
|
|
32
33
|
}
|
|
33
34
|
const SearchBox = observer(function SearchBox({ model, showHelp = true, minWidth = MIN_WIDTH, maxWidth = MAX_WIDTH, style = defaultStyle, }) {
|
|
34
|
-
const
|
|
35
|
+
const palette = usePalette();
|
|
35
36
|
const session = getSession(model);
|
|
36
|
-
const { textSearchManager, assemblyManager } = session;
|
|
37
37
|
const { assemblyNames } = model;
|
|
38
38
|
const assemblyName = assemblyNames[0];
|
|
39
|
-
const assembly = assemblyManager.get(assemblyName);
|
|
40
39
|
const { recentLocations, addRecentLocation, clearRecentLocations } = useRecentLocations(assemblyName);
|
|
41
40
|
async function navigate(option) {
|
|
42
41
|
try {
|
|
43
|
-
await navigateToSelectedOption({ model, assemblyName, option })
|
|
44
|
-
|
|
42
|
+
if (await navigateToSelectedOption({ model, assemblyName, option })) {
|
|
43
|
+
addRecentLocation(recentLocationOf(option));
|
|
44
|
+
}
|
|
45
45
|
}
|
|
46
46
|
catch (e) {
|
|
47
47
|
notifySearchFailure(session, e);
|
|
@@ -50,25 +50,19 @@ const SearchBox = observer(function SearchBox({ model, showHelp = true, minWidth
|
|
|
50
50
|
const recentMenuItems = recentLocationsMenu({
|
|
51
51
|
recentLocations,
|
|
52
52
|
onNavigate: option => {
|
|
53
|
-
navigate(option)
|
|
53
|
+
void navigate(option);
|
|
54
54
|
},
|
|
55
55
|
onClear: clearRecentLocations,
|
|
56
56
|
});
|
|
57
57
|
return (_jsx(RefNameAutocomplete, { onSelect: option => {
|
|
58
|
-
navigate(option)
|
|
59
|
-
}, assemblyName: assemblyName, fetchResults: (queryString,
|
|
60
|
-
queryString,
|
|
61
|
-
assemblyName,
|
|
62
|
-
textSearchManager,
|
|
63
|
-
assembly,
|
|
64
|
-
stopToken,
|
|
65
|
-
}), session: session, value: model.coarseVisibleLocStrings, minWidth: minWidth, maxWidth: maxWidth, adornmentWidth: adornmentReservePx({
|
|
58
|
+
void navigate(option);
|
|
59
|
+
}, assemblyName: assemblyName, fetchResults: (queryString, signal) => fetchResults({ session, queryString, assemblyName, signal }), session: session, value: model.coarseVisibleLocStrings, minWidth: minWidth, maxWidth: maxWidth, adornmentWidth: adornmentReservePx({
|
|
66
60
|
showHelp,
|
|
67
61
|
menuItemCount: recentMenuItems.length,
|
|
68
62
|
}), style: style, endAdornment: _jsx(RefNameAutocompleteEndAdornment, { showHelp: showHelp, menuItems: recentMenuItems }), inputStyle: {
|
|
69
63
|
padding: 0,
|
|
70
64
|
height: WIDGET_HEIGHT,
|
|
71
|
-
background: alpha(
|
|
65
|
+
background: alpha(palette.background.paper, 0.8),
|
|
72
66
|
} }));
|
|
73
67
|
});
|
|
74
68
|
export default SearchBox;
|
|
@@ -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,9 +1,5 @@
|
|
|
1
|
-
import type { LinearGenomeViewModel } from '
|
|
2
|
-
|
|
3
|
-
export default function SearchResultsDialog({ model, assemblyName, searchQuery, searchResults, handleClose, }: {
|
|
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
|
-
}): 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: [searchPicker.rows.length, " matches for ", _jsx("b", { children: searchPicker.query })] }), _jsx(SearchResultsTable, { picker: searchPicker })] })) : null;
|
|
9
|
+
});
|
|
10
|
+
export default SearchResultsDialog;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
declare const SearchResultsTable: ({
|
|
4
|
-
|
|
5
|
-
assemblyName: string;
|
|
6
|
-
model: LinearGenomeViewModel;
|
|
7
|
-
handleClose: () => void;
|
|
1
|
+
import type { SearchPickerRow, SearchPickerState } from '../model.ts';
|
|
2
|
+
export declare function filterRows(rows: SearchPickerRow[], text: string): SearchPickerRow[];
|
|
3
|
+
declare const SearchResultsTable: ({ picker, }: {
|
|
4
|
+
picker: SearchPickerState;
|
|
8
5
|
}) => import("react").JSX.Element;
|
|
9
6
|
export default SearchResultsTable;
|
|
@@ -1,56 +1,28 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, } from '@mui/material';
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { SanitizedHTML } from '@jbrowse/core/ui';
|
|
4
|
+
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, } from '@mui/material';
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
console.warn('failed to parse location string', locString, e);
|
|
30
|
-
return locString;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
return locString;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// A hit in a track that is already on screen is usually the one meant, so it
|
|
38
|
-
// is listed first rather than given a control that says so. sort is stable,
|
|
39
|
-
// so everything else keeps the ranked order it arrived in.
|
|
40
|
-
const ordered = [...searchResults].sort((a, b) => Number(isOpenInView(b, model)) - Number(isOpenInView(a, model)));
|
|
41
|
-
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: getTrackName(result.getTrackId()) || 'N/A' }), _jsx(TableCell, { align: "right", children: _jsx(Button, { onClick: async () => {
|
|
42
|
-
try {
|
|
43
|
-
await navToOption({
|
|
44
|
-
option: result,
|
|
45
|
-
model,
|
|
46
|
-
assemblyName,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
catch (e) {
|
|
50
|
-
console.error(e);
|
|
51
|
-
session.notifyError(`${e}`, e);
|
|
52
|
-
}
|
|
53
|
-
handleClose();
|
|
54
|
-
}, color: "primary", variant: "contained", children: "Go" }) })] }, result.getId()))) })] }) }));
|
|
6
|
+
// past this many rows a list is easier to narrow than to read; gene names
|
|
7
|
+
// sort too irregularly (scn1ab, HOXA10-AS) for an order to stand in for it
|
|
8
|
+
const FILTER_AT = 8;
|
|
9
|
+
export function filterRows(rows, text) {
|
|
10
|
+
const needle = text.trim().toLowerCase();
|
|
11
|
+
return needle
|
|
12
|
+
? rows.filter(row => [row.label, row.location, row.trackName].some(field => field.toLowerCase().includes(needle)))
|
|
13
|
+
: rows;
|
|
14
|
+
}
|
|
15
|
+
const SearchResultsTable = observer(function SearchResultsTable({ picker, }) {
|
|
16
|
+
const [filter, setFilter] = useState('');
|
|
17
|
+
const rows = filterRows(picker.rows, filter);
|
|
18
|
+
return (_jsxs(_Fragment, { children: [picker.rows.length > FILTER_AT ? (_jsx(TextField, { autoFocus: true, fullWidth: true, size: "small", margin: "dense", placeholder: "Filter by name, location or track", slotProps: { htmlInput: { 'aria-label': 'Filter search results' } }, value: filter, onChange: event => {
|
|
19
|
+
setFilter(event.target.value);
|
|
20
|
+
}, onKeyDown: event => {
|
|
21
|
+
if (event.key === 'Enter' && rows.length === 1) {
|
|
22
|
+
void picker.pick(rows[0].id);
|
|
23
|
+
}
|
|
24
|
+
}, helperText: filter ? `${rows.length} of ${picker.rows.length}` : undefined })) : null, _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: 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: () => {
|
|
25
|
+
void picker.pick(row.id);
|
|
26
|
+
}, color: "primary", variant: "contained", "aria-label": `Go to ${row.label} at ${row.location}`, children: "Go" }) })] }, row.id))) })] }) })] }));
|
|
55
27
|
});
|
|
56
28
|
export default SearchResultsTable;
|
|
@@ -15,8 +15,7 @@ function isFeatureWidgetForView(w, viewId) {
|
|
|
15
15
|
// is owned by the display rather than by a widget — so the view's own displays
|
|
16
16
|
// publish hover positions too.
|
|
17
17
|
function displayHoverPosition(display) {
|
|
18
|
-
|
|
19
|
-
return candidate?.sequenceHoverPosition;
|
|
18
|
+
return display.sequenceHoverPosition;
|
|
20
19
|
}
|
|
21
20
|
// Draws a crosshair on the LGV at the base a connected feature-detail sequence
|
|
22
21
|
// panel is hovering, so mousing over the sequence readout points at the genome.
|
|
@@ -24,7 +23,7 @@ const SequenceFeatureHoverHighlight = observer(function SequenceFeatureHoverHigh
|
|
|
24
23
|
return (_jsxs(_Fragment, { children: [_jsx(ConnectedHoverHighlight, { model: model, getPosition: (widget, viewId) => isFeatureWidgetForView(widget, viewId)
|
|
25
24
|
? widget.sequenceHoverPosition
|
|
26
25
|
: undefined }), model.tracks
|
|
27
|
-
.flatMap(track => track.displays)
|
|
26
|
+
.flatMap((track) => track.displays)
|
|
28
27
|
.flatMap(display => {
|
|
29
28
|
const position = displayHoverPosition(display);
|
|
30
29
|
return position
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import type { SequenceSearchModel } from './searchModes.ts';
|
|
1
2
|
declare const SequenceSearchDialog: ({ model, handleClose, }: {
|
|
2
|
-
model:
|
|
3
|
-
assemblyNames: string[];
|
|
4
|
-
launchTrack: (trackId: string) => Promise<unknown>;
|
|
5
|
-
};
|
|
3
|
+
model: SequenceSearchModel;
|
|
6
4
|
handleClose: () => void;
|
|
7
5
|
}) => import("react").JSX.Element;
|
|
8
6
|
export default SequenceSearchDialog;
|
|
@@ -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;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { LinearGenomeViewModel } from '../index.ts';
|
|
2
|
-
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
|
|
1
|
+
import type { LinearGenomeViewModel, LinearGenomeViewTrack } from '../index.ts';
|
|
3
2
|
type LGV = LinearGenomeViewModel;
|
|
4
3
|
declare const TrackContainer: ({ model, track, }: {
|
|
5
4
|
model: LGV;
|
|
6
|
-
track:
|
|
5
|
+
track: LinearGenomeViewTrack;
|
|
7
6
|
}) => import("react").JSX.Element;
|
|
8
7
|
export default TrackContainer;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
2
3
|
import { ErrorBanner, ResizeHandle } from '@jbrowse/core/ui';
|
|
3
4
|
import { ErrorBoundary } from '@jbrowse/core/ui/ErrorBoundary';
|
|
4
5
|
import { cx, makeStyles } from '@jbrowse/core/util/tss-react';
|
|
5
6
|
import { TrackOverlaySlot } from '@jbrowse/display-ui';
|
|
7
|
+
import { isAlive } from '@jbrowse/mobx-state-tree';
|
|
6
8
|
import { Paper } from '@mui/material';
|
|
7
9
|
import { observer } from 'mobx-react';
|
|
8
10
|
import { RESIZE_HANDLE_HEIGHT, TRACK_OUTLINE_BORDER, TRACK_TOP_GAP, } from '../consts.js';
|
|
@@ -16,8 +18,8 @@ const useStyles = makeStyles()({
|
|
|
16
18
|
// described in TrackRenderingContainer. flow-root keeps the block formatting
|
|
17
19
|
// context that `overflow: hidden` used to establish as a side effect (neither
|
|
18
20
|
// `clip` nor no overflow does), so child margins still can't collapse through
|
|
19
|
-
// and shift the track — which
|
|
20
|
-
//
|
|
21
|
+
// and shift the track — which would put the pixels off the model's offset
|
|
22
|
+
// arithmetic, which the breakpoint split view draws its connectors from.
|
|
21
23
|
root: {
|
|
22
24
|
marginTop: TRACK_TOP_GAP,
|
|
23
25
|
position: 'relative',
|
|
@@ -56,17 +58,61 @@ const useStyles = makeStyles()({
|
|
|
56
58
|
// spends the other 4 on clearance.
|
|
57
59
|
trackLabelOffset: {
|
|
58
60
|
position: 'relative',
|
|
59
|
-
display: 'inline-block',
|
|
60
61
|
marginBottom: 8,
|
|
61
62
|
},
|
|
62
63
|
trackLabelOverlap: {
|
|
63
64
|
position: 'absolute',
|
|
64
65
|
},
|
|
66
|
+
// in flow, so the track keeps the banner's height, and raised over the
|
|
67
|
+
// `PaddingBlocks` painted after it
|
|
68
|
+
crashBanner: {
|
|
69
|
+
position: 'relative',
|
|
70
|
+
zIndex: 1,
|
|
71
|
+
},
|
|
65
72
|
});
|
|
73
|
+
// Measures the in-flow label band, the distance from the Paper's content top to
|
|
74
|
+
// the rendering container, into the model. Observes the Paper: it grows and
|
|
75
|
+
// shrinks with the label, the label setting, and the display, and each of those
|
|
76
|
+
// can move the container. Published after a requestAnimationFrame like
|
|
77
|
+
// useWidthSetter, and cleared on unmount so a removed track leaves no band.
|
|
78
|
+
function useTrackLabelBand(model, trackId) {
|
|
79
|
+
const [paper, setPaper] = useState(null);
|
|
80
|
+
const [container, setContainer] = useState(null);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (paper && container && 'ResizeObserver' in window) {
|
|
83
|
+
let token;
|
|
84
|
+
const publish = () => {
|
|
85
|
+
token = requestAnimationFrame(() => {
|
|
86
|
+
if (isAlive(model)) {
|
|
87
|
+
const paperRect = paper.getBoundingClientRect();
|
|
88
|
+
const band = container.getBoundingClientRect().top -
|
|
89
|
+
paperRect.top -
|
|
90
|
+
paper.clientTop;
|
|
91
|
+
model.setTrackLabelBand(trackId, band);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
publish();
|
|
96
|
+
const observer = new ResizeObserver(publish);
|
|
97
|
+
observer.observe(paper);
|
|
98
|
+
return () => {
|
|
99
|
+
observer.disconnect();
|
|
100
|
+
if (token !== undefined) {
|
|
101
|
+
cancelAnimationFrame(token);
|
|
102
|
+
}
|
|
103
|
+
if (isAlive(model)) {
|
|
104
|
+
model.setTrackLabelBand(trackId, 0);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}, [paper, container, model, trackId]);
|
|
110
|
+
return { setPaper, setContainer };
|
|
111
|
+
}
|
|
66
112
|
const TrackContainer = observer(function TrackContainer({ model, track, }) {
|
|
67
113
|
const { classes } = useStyles();
|
|
68
|
-
//
|
|
69
|
-
// displays
|
|
114
|
+
// read once and handed down, so a track's chrome and its body can't read two
|
|
115
|
+
// displays
|
|
70
116
|
const display = track.activeDisplay;
|
|
71
117
|
const { showTrackOutlines } = model;
|
|
72
118
|
// The Paper's 1px border, present iff outlines are on. Everything laid out in
|
|
@@ -76,12 +122,19 @@ const TrackContainer = observer(function TrackContainer({ model, track, }) {
|
|
|
76
122
|
// the data. One binding rather than three copies of the ternary, because the
|
|
77
123
|
// three agreeing is the whole point.
|
|
78
124
|
const outlineOffset = showTrackOutlines ? TRACK_OUTLINE_BORDER : 0;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
125
|
+
// A label in flow is a row of track height, which is most of what minimizing
|
|
126
|
+
// buys back — so a minimized track overlaps its label whatever the setting
|
|
127
|
+
// says, and there is nothing under it to print over. `prefersOffset` is the
|
|
128
|
+
// display asking for the offset row in 'overlapping' mode, because its left
|
|
129
|
+
// edge carries an axis or a sidebar the label would cover.
|
|
130
|
+
const trackLabelStyle = track.minimized ||
|
|
131
|
+
(model.effectiveTrackLabels === 'overlapping' && !display.prefersOffset)
|
|
132
|
+
? classes.trackLabelOverlap
|
|
133
|
+
: classes.trackLabelOffset;
|
|
134
|
+
const { setPaper, setContainer } = useTrackLabelBand(model, track.trackId);
|
|
135
|
+
return (_jsxs(Paper, { ref: setPaper, className: cx(classes.root, track.pinned ? null : classes.unpinnedTrack), variant: showTrackOutlines ? 'outlined' : undefined, elevation: showTrackOutlines ? undefined : 0, onDragOver: event => {
|
|
83
136
|
model.onTrackDragOver(track.id, event.clientY);
|
|
84
|
-
}, 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, {
|
|
137
|
+
}, 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 }, labelBand: model.trackLabelBand(track), 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 }, value: display.height, onChange: height => display.resizeHeight(height - display.height),
|
|
85
138
|
// the drag's shortcut: grow the track by whatever it is scrolled over,
|
|
86
139
|
// so a pileup showing three rows of forty opens to all forty
|
|
87
140
|
// Optional: only a display that scrolls its own content has anything
|
|
@@ -13,17 +13,27 @@ const useStyles = makeStyles()(theme => ({
|
|
|
13
13
|
root: {
|
|
14
14
|
// above breakpoint split view
|
|
15
15
|
zIndex: 200,
|
|
16
|
-
|
|
16
|
+
...(theme.palette.mode === 'dark' && {
|
|
17
|
+
outline: `1px solid ${theme.palette.divider}`,
|
|
18
|
+
outlineOffset: -1,
|
|
19
|
+
}),
|
|
20
|
+
display: 'inline-flex',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
maxWidth: 'calc(100% - 16px)',
|
|
17
23
|
},
|
|
24
|
+
// one line: a long name wrapping over a narrow view covered the data below
|
|
18
25
|
trackName: {
|
|
19
|
-
margin:
|
|
20
|
-
|
|
26
|
+
margin: theme.spacing(0, 0.5),
|
|
27
|
+
minWidth: 0,
|
|
28
|
+
overflow: 'hidden',
|
|
29
|
+
textOverflow: 'ellipsis',
|
|
30
|
+
whiteSpace: 'nowrap',
|
|
21
31
|
pointerEvents: 'none',
|
|
22
32
|
},
|
|
23
33
|
}));
|
|
24
34
|
const TrackLabel = observer(function TrackLabel({ track, className, }) {
|
|
25
35
|
const { classes } = useStyles();
|
|
26
36
|
const trackName = getTrackName(track.configuration, getSession(track));
|
|
27
|
-
return (_jsxs(Paper, { className: cx(className, classes.root), children: [_jsx(TrackLabelDragHandle, { track: track }), _jsx(TrackLabelCloseButton, { track: track }), _jsx(TrackLabelMinimizeButton, { track: track }), _jsx(Typography, { variant: "body2", component: "span", className: classes.trackName, children: _jsx(SanitizedHTML, { html: trackName }) }), _jsx(TrackLabelRefNameWarning, { track: track }), _jsx(TrackLabelMenu, { track: track })] }));
|
|
37
|
+
return (_jsxs(Paper, { className: cx(className, classes.root), "data-testid": `trackLabel-${track.trackId}`, children: [_jsx(TrackLabelDragHandle, { track: track }), _jsx(TrackLabelCloseButton, { track: track }), _jsx(TrackLabelMinimizeButton, { track: track }), _jsx(Typography, { variant: "body2", component: "span", className: classes.trackName, children: _jsx(SanitizedHTML, { html: trackName }) }), _jsx(TrackLabelRefNameWarning, { track: track }), _jsx(TrackLabelMenu, { track: track })] }));
|
|
28
38
|
});
|
|
29
39
|
export default TrackLabel;
|