@jbrowse/display-ui 5.0.0-beta.11 → 5.0.0-beta.14
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/README.md +70 -76
- package/esm/AxisCaption.d.ts +2 -2
- package/esm/AxisCaption.js +6 -4
- package/esm/AxisGutter.d.ts +2 -2
- package/esm/AxisGutter.js +5 -4
- package/esm/CrossHatches.d.ts +3 -2
- package/esm/CrossHatches.js +5 -2
- package/esm/DisplayUIProvider.d.ts +3 -2
- package/esm/DisplayUIProvider.js +4 -2
- package/esm/FloatingLegend.js +7 -3
- package/esm/FloatingText.d.ts +9 -8
- package/esm/FloatingText.js +9 -7
- package/esm/ScoreDomainCaption.d.ts +2 -2
- package/esm/ScoreDomainCaption.js +3 -2
- package/esm/ScoreRules.d.ts +3 -2
- package/esm/ScoreRules.js +5 -2
- package/esm/YScaleBar.js +1 -8
- package/esm/YScaleBarOverlay.d.ts +3 -2
- package/esm/YScaleBarOverlay.js +4 -2
- package/esm/axisPlacement.d.ts +16 -9
- package/esm/axisPlacement.js +22 -14
- package/esm/bottomRightCorner.d.ts +19 -47
- package/esm/bottomRightCorner.js +19 -47
- package/esm/chromeOverlayContext.js +10 -25
- package/esm/chromeOverlays.d.ts +73 -67
- package/esm/embed/engineBoundary.d.ts +34 -0
- package/esm/embed/engineBoundary.js +29 -0
- package/esm/embed/index.d.ts +6 -0
- package/esm/embed/index.js +18 -3
- package/esm/embed/legend.js +2 -2
- package/esm/embed/location.d.ts +2 -1
- package/esm/embed/location.js +18 -17
- package/esm/embed/notifications.d.ts +29 -0
- package/esm/embed/notifications.js +38 -0
- package/esm/embed/provider.d.ts +5 -3
- package/esm/embed/provider.js +6 -4
- package/esm/embed/regions.d.ts +3 -2
- package/esm/embed/regions.js +9 -7
- package/esm/embed/searchPicker.d.ts +24 -0
- package/esm/embed/searchPicker.js +14 -0
- package/esm/embed/toolbar.d.ts +16 -0
- package/esm/embed/toolbar.js +22 -0
- package/esm/index.d.ts +1 -1
- package/esm/isLiveModel.d.ts +10 -15
- package/esm/isLiveModel.js +10 -15
- package/esm/plainChromeOverlays.d.ts +2 -2
- package/esm/plainChromeOverlays.js +17 -39
- package/esm/tooltip/Tooltip.d.ts +3 -3
- package/esm/tooltip/Tooltip.js +4 -2
- package/esm/trackControl/plainTrackControl.d.ts +2 -1
- package/esm/trackControl/plainTrackControl.js +8 -6
- package/esm/trackOverlay/TrackOverlaySlot.d.ts +3 -3
- package/esm/trackOverlay/TrackOverlaySlot.js +4 -3
- package/esm/valueScale.d.ts +5 -5
- package/package.json +4 -4
package/esm/YScaleBar.js
CHANGED
|
@@ -2,18 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { usePalette } from '@jbrowse/core/ui/PaletteContext';
|
|
3
3
|
import { AXIS_FONT_PX, TICK_LABEL_X_PX } from './yAxisConstants.js';
|
|
4
4
|
import { clampStrokeInsideAxis } from './yScaleTicks.js';
|
|
5
|
-
// Not an `observer`, and deliberately: there is nothing here to observe. Every
|
|
6
|
-
// caller already reads `model.ticks` inside its own observer and hands the
|
|
7
|
-
// resolved plain object down, and `usePalette` is a React context, not MobX.
|
|
8
|
-
// Wrapping it anyway allocated a Reaction per instance — multi-wiggle renders
|
|
9
|
-
// one per sample row, on screen as well as in export — and, per CLAUDE.md, put
|
|
10
|
-
// the component out of `babel-plugin-react-compiler`'s reach, so it got neither
|
|
11
|
-
// the MobX tracking it doesn't need nor the memoization it does. Its sibling
|
|
12
|
-
// `CrossHatchLines`, consuming the same ticks, is already plain.
|
|
13
5
|
// Half the vertical space a 10px label needs, halo included: digits reach about
|
|
14
6
|
// 3.6px above the centered baseline and the 2.5px-wide background stroke another
|
|
15
7
|
// 1.25px past that.
|
|
16
8
|
const LABEL_HALF_HEIGHT_PX = 5;
|
|
9
|
+
// eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
|
|
17
10
|
export default function YScaleBar({ ticks, orientation, bandHeight, }) {
|
|
18
11
|
const palette = usePalette();
|
|
19
12
|
if (!ticks) {
|
|
@@ -4,8 +4,9 @@ import type { YAxis } from './valueScale.ts';
|
|
|
4
4
|
* positioned absolutely over the band at `top`, with `AxisGutter` inside. A
|
|
5
5
|
* right-side gutter clears the vertical scrollbar a display may mount.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
declare const YScaleBarOverlay: ({ axis, top, width, }: {
|
|
8
8
|
axis: YAxis;
|
|
9
9
|
top: number;
|
|
10
10
|
width: number;
|
|
11
|
-
})
|
|
11
|
+
}) => import("react").JSX.Element;
|
|
12
|
+
export default YScaleBarOverlay;
|
package/esm/YScaleBarOverlay.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { VERTICAL_SCROLLBAR_CLEARANCE } from '@jbrowse/core/ui/VerticalScrollbar';
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
3
4
|
import AxisGutter from './AxisGutter.js';
|
|
4
5
|
import { axisGutterLeft, axisGutterWidth } from './axisPlacement.js';
|
|
5
6
|
/**
|
|
@@ -7,7 +8,7 @@ import { axisGutterLeft, axisGutterWidth } from './axisPlacement.js';
|
|
|
7
8
|
* positioned absolutely over the band at `top`, with `AxisGutter` inside. A
|
|
8
9
|
* right-side gutter clears the vertical scrollbar a display may mount.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
const YScaleBarOverlay = observer(function YScaleBarOverlay({ axis, top, width, }) {
|
|
11
12
|
return (_jsx("svg", { style: {
|
|
12
13
|
position: 'absolute',
|
|
13
14
|
top,
|
|
@@ -17,4 +18,5 @@ export default function YScaleBarOverlay({ axis, top, width, }) {
|
|
|
17
18
|
width: axisGutterWidth(axis),
|
|
18
19
|
overflow: 'visible',
|
|
19
20
|
}, children: _jsx(AxisGutter, { axis: axis }) }));
|
|
20
|
-
}
|
|
21
|
+
});
|
|
22
|
+
export default YScaleBarOverlay;
|
package/esm/axisPlacement.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { ValueScale, YAxis } from './valueScale.ts';
|
|
|
8
8
|
export declare const COMPACT_AXIS_HEIGHT = 30;
|
|
9
9
|
/**
|
|
10
10
|
* Whether a scale places anything by y, which is whether its rules draw: it
|
|
11
|
-
* rules at least one band, where `[]` is a scale mapped to
|
|
11
|
+
* rules at least one band, where `[]` is a scale mapped to color instead.
|
|
12
12
|
*/
|
|
13
13
|
export declare function rulesABand(scale: Pick<ValueScale, 'bandTops'>): boolean;
|
|
14
14
|
/**
|
|
@@ -30,11 +30,19 @@ export declare function axisCaptionY(axis: Pick<YAxis, 'ticks'>, bandTops: numbe
|
|
|
30
30
|
*/
|
|
31
31
|
export declare function axisGutterWidth(axis: Pick<YAxis, 'ticks' | 'caption'>): number;
|
|
32
32
|
/**
|
|
33
|
-
* Px the export's left margin holds for these axes
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* Px the export's left margin holds for these axes, 0 when no left-side axis
|
|
34
|
+
* draws. `axisGutterLeft` puts every left axis's outer edge this far out, a
|
|
35
|
+
* wider gutter growing inward over the plot, so a sidebar the export parks left
|
|
36
|
+
* of the figure sits past this strip.
|
|
36
37
|
*/
|
|
37
|
-
export declare function leftAxisGutterWidth(axes: readonly Pick<YAxis, 'side' | '
|
|
38
|
+
export declare function leftAxisGutterWidth(axes: readonly Pick<YAxis, 'side' | 'height' | 'bandTops'>[]): 0 | 50;
|
|
39
|
+
/**
|
|
40
|
+
* Whether an axis's numbers grow rightward from its spine: a right-side axis
|
|
41
|
+
* keeps them inside the plot's right edge, and a left-side axis set past a
|
|
42
|
+
* panel keeps its spine against the panel. Only a left-side axis at the
|
|
43
|
+
* display's own edge grows them leftward, toward that edge.
|
|
44
|
+
*/
|
|
45
|
+
export declare function numbersGrowRight(axis: Pick<YAxis, 'side' | 'left'>): boolean;
|
|
38
46
|
/** How far in from the plot's right edge a right-side gutter ends in an export. */
|
|
39
47
|
export declare const AXIS_RIGHT_INSET_PX = 4;
|
|
40
48
|
/**
|
|
@@ -42,9 +50,8 @@ export declare const AXIS_RIGHT_INSET_PX = 4;
|
|
|
42
50
|
* gutter inside the plot's right edge, less `rightInset` (the vertical
|
|
43
51
|
* scrollbar a display may mount on screen; a margin in an export). A left-side
|
|
44
52
|
* axis takes the gutter at the display's left edge, past whatever panel the
|
|
45
|
-
* scale's `left` reserves — except in an export, whose margin is the gutter
|
|
46
|
-
*
|
|
47
|
-
* the
|
|
48
|
-
* `axisGutterWidth` grew.
|
|
53
|
+
* scale's `left` reserves — except in an export, whose margin is the gutter:
|
|
54
|
+
* the export parks that panel left of the margin, so the axis sits between
|
|
55
|
+
* the two with its numbers outside the plot.
|
|
49
56
|
*/
|
|
50
57
|
export declare function axisGutterLeft(axis: Pick<YAxis, 'side' | 'left' | 'ticks' | 'caption'>, width: number, rightInset: number, exportContentLeft?: number): number;
|
package/esm/axisPlacement.js
CHANGED
|
@@ -10,7 +10,7 @@ import { AXIS_GUTTER_WIDTH_PX } from './yScaleTicks.js';
|
|
|
10
10
|
export const COMPACT_AXIS_HEIGHT = 30;
|
|
11
11
|
/**
|
|
12
12
|
* Whether a scale places anything by y, which is whether its rules draw: it
|
|
13
|
-
* rules at least one band, where `[]` is a scale mapped to
|
|
13
|
+
* rules at least one band, where `[]` is a scale mapped to color instead.
|
|
14
14
|
*/
|
|
15
15
|
export function rulesABand(scale) {
|
|
16
16
|
return (scale.bandTops?.length ?? 1) > 0;
|
|
@@ -48,14 +48,24 @@ export function axisGutterWidth(axis) {
|
|
|
48
48
|
return Math.max(AXIS_GUTTER_WIDTH_PX, Math.ceil(CAPTION_BAND_PX + widest + TICK_LABEL_X_PX));
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
|
-
* Px the export's left margin holds for these axes
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* Px the export's left margin holds for these axes, 0 when no left-side axis
|
|
52
|
+
* draws. `axisGutterLeft` puts every left axis's outer edge this far out, a
|
|
53
|
+
* wider gutter growing inward over the plot, so a sidebar the export parks left
|
|
54
|
+
* of the figure sits past this strip.
|
|
54
55
|
*/
|
|
55
56
|
export function leftAxisGutterWidth(axes) {
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
return axes.some(axis => axis.side !== 'right' && axisDrawn(axis))
|
|
58
|
+
? AXIS_GUTTER_WIDTH_PX
|
|
59
|
+
: 0;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Whether an axis's numbers grow rightward from its spine: a right-side axis
|
|
63
|
+
* keeps them inside the plot's right edge, and a left-side axis set past a
|
|
64
|
+
* panel keeps its spine against the panel. Only a left-side axis at the
|
|
65
|
+
* display's own edge grows them leftward, toward that edge.
|
|
66
|
+
*/
|
|
67
|
+
export function numbersGrowRight(axis) {
|
|
68
|
+
return axis.side === 'right' || (axis.left ?? 0) > 0;
|
|
59
69
|
}
|
|
60
70
|
/** How far in from the plot's right edge a right-side gutter ends in an export. */
|
|
61
71
|
export const AXIS_RIGHT_INSET_PX = 4;
|
|
@@ -64,17 +74,15 @@ export const AXIS_RIGHT_INSET_PX = 4;
|
|
|
64
74
|
* gutter inside the plot's right edge, less `rightInset` (the vertical
|
|
65
75
|
* scrollbar a display may mount on screen; a margin in an export). A left-side
|
|
66
76
|
* axis takes the gutter at the display's left edge, past whatever panel the
|
|
67
|
-
* scale's `left` reserves — except in an export, whose margin is the gutter
|
|
68
|
-
*
|
|
69
|
-
* the
|
|
70
|
-
* `axisGutterWidth` grew.
|
|
77
|
+
* scale's `left` reserves — except in an export, whose margin is the gutter:
|
|
78
|
+
* the export parks that panel left of the margin, so the axis sits between
|
|
79
|
+
* the two with its numbers outside the plot.
|
|
71
80
|
*/
|
|
72
81
|
export function axisGutterLeft(axis, width, rightInset, exportContentLeft) {
|
|
73
82
|
if (axis.side === 'right') {
|
|
74
83
|
return width - rightInset - axisGutterWidth(axis);
|
|
75
84
|
}
|
|
76
|
-
|
|
77
|
-
return exportContentLeft !== undefined && left === 0
|
|
85
|
+
return exportContentLeft !== undefined
|
|
78
86
|
? exportContentLeft - AXIS_GUTTER_WIDTH_PX
|
|
79
|
-
: left;
|
|
87
|
+
: (axis.left ?? 0);
|
|
80
88
|
}
|
|
@@ -2,56 +2,28 @@
|
|
|
2
2
|
* #api
|
|
3
3
|
* The one box per display that owns the bottom-right corner.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `DisplayChromeOverlays.BackgroundProgress`
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* Two members share it: the display's own control row
|
|
6
|
+
* (`BottomRightIndicators`) and the chrome's background-progress chip
|
|
7
|
+
* (`DisplayChromeOverlays.BackgroundProgress`). Both portal into the same
|
|
8
|
+
* per-track overlay node, so each claiming the corner with its own
|
|
9
|
+
* `position: absolute` box draws one over the other. The chrome renders this
|
|
10
|
+
* box, lays its chip out in it, and publishes the node here so the control row,
|
|
11
|
+
* rendered inside the chrome's body, lands in the same flex column.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* the
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* both used to claim `bottom: 2; right: 2` there with their own
|
|
19
|
-
* `position: absolute` box — so they simply drew on top of each other, the
|
|
20
|
-
* controls winning on z-index and the status text disappearing under them.
|
|
21
|
-
*
|
|
22
|
-
* It has never been reachable: the two displays that render the control row
|
|
23
|
-
* (alignments, canvas) are not among the four that report a `ready`-phase
|
|
24
|
-
* status (clustering, on multi-wiggle / multi-row features / maf / the
|
|
25
|
-
* multi-sample variant pair). The layout is structural anyway, because neither
|
|
26
|
-
* side checks for the constraint, so the first display to want both would hit
|
|
27
|
-
* the bug as a status message that never appears.
|
|
28
|
-
*
|
|
29
|
-
* `BottomRightIndicators` already described itself as "the single anchor point
|
|
30
|
-
* for every bottom-right overlay ... so they lay out as one row instead of each
|
|
31
|
-
* picking their own position and colliding". This makes that true of the chip
|
|
32
|
-
* too: the chrome renders the anchor, puts its chip in it, and publishes the
|
|
33
|
-
* node here so the display's row — rendered several components away, inside the
|
|
34
|
-
* chrome's body — lands in the same flex box instead of over it.
|
|
35
|
-
*
|
|
36
|
-
* `null` outside a chrome (a display an embedder mounts standalone, a unit
|
|
37
|
-
* test, the SVG export), where `BottomRightIndicators` keeps its own anchored
|
|
38
|
-
* box. That fallback is why this can be added without every consumer changing.
|
|
13
|
+
* - A host writing their own display over `DisplayChromeBase` builds the corner
|
|
14
|
+
* from this; the chip is told to render in-flow, with no `position` and no
|
|
15
|
+
* corner offsets.
|
|
16
|
+
* - `null` outside a chrome (a standalone mount, a unit test, the SVG export),
|
|
17
|
+
* where `BottomRightIndicators` anchors its own box.
|
|
39
18
|
*/
|
|
40
19
|
export declare const BottomRightCornerContext: import("react").Context<HTMLElement | null>;
|
|
41
20
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Ordered by `order` rather than by DOM position because one member arrives as
|
|
50
|
-
* a portal and the other as an ordinary child, and the relative order of those
|
|
51
|
-
* two inside the container is not something React documents. Only the control
|
|
52
|
-
* row needs a value: the status chip takes CSS's default 0, so anything the
|
|
53
|
-
* chrome adds to the corner later sorts above the controls unless it says
|
|
54
|
-
* otherwise — which is the right default, the controls being the thing whose
|
|
55
|
-
* position in the corner users learn.
|
|
21
|
+
* The control row's flex `order` in the corner column. The members stack
|
|
22
|
+
* rather than sit side by side, so a wide status chip starting or finishing
|
|
23
|
+
* never shoves the controls sideways. `order` sets the sequence because one
|
|
24
|
+
* member arrives as a portal and the other as a child, and React does not
|
|
25
|
+
* document their relative DOM order. The chip takes CSS's default 0, so
|
|
26
|
+
* anything the chrome adds later sorts above the controls, whose position users
|
|
27
|
+
* learn.
|
|
56
28
|
*/
|
|
57
29
|
export declare const BOTTOM_RIGHT_CONTROLS_ORDER = 1;
|
package/esm/bottomRightCorner.js
CHANGED
|
@@ -3,56 +3,28 @@ import { createContext } from 'react';
|
|
|
3
3
|
* #api
|
|
4
4
|
* The one box per display that owns the bottom-right corner.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `DisplayChromeOverlays.BackgroundProgress`
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* Two members share it: the display's own control row
|
|
7
|
+
* (`BottomRightIndicators`) and the chrome's background-progress chip
|
|
8
|
+
* (`DisplayChromeOverlays.BackgroundProgress`). Both portal into the same
|
|
9
|
+
* per-track overlay node, so each claiming the corner with its own
|
|
10
|
+
* `position: absolute` box draws one over the other. The chrome renders this
|
|
11
|
+
* box, lays its chip out in it, and publishes the node here so the control row,
|
|
12
|
+
* rendered inside the chrome's body, lands in the same flex column.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* the
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* both used to claim `bottom: 2; right: 2` there with their own
|
|
20
|
-
* `position: absolute` box — so they simply drew on top of each other, the
|
|
21
|
-
* controls winning on z-index and the status text disappearing under them.
|
|
22
|
-
*
|
|
23
|
-
* It has never been reachable: the two displays that render the control row
|
|
24
|
-
* (alignments, canvas) are not among the four that report a `ready`-phase
|
|
25
|
-
* status (clustering, on multi-wiggle / multi-row features / maf / the
|
|
26
|
-
* multi-sample variant pair). The layout is structural anyway, because neither
|
|
27
|
-
* side checks for the constraint, so the first display to want both would hit
|
|
28
|
-
* the bug as a status message that never appears.
|
|
29
|
-
*
|
|
30
|
-
* `BottomRightIndicators` already described itself as "the single anchor point
|
|
31
|
-
* for every bottom-right overlay ... so they lay out as one row instead of each
|
|
32
|
-
* picking their own position and colliding". This makes that true of the chip
|
|
33
|
-
* too: the chrome renders the anchor, puts its chip in it, and publishes the
|
|
34
|
-
* node here so the display's row — rendered several components away, inside the
|
|
35
|
-
* chrome's body — lands in the same flex box instead of over it.
|
|
36
|
-
*
|
|
37
|
-
* `null` outside a chrome (a display an embedder mounts standalone, a unit
|
|
38
|
-
* test, the SVG export), where `BottomRightIndicators` keeps its own anchored
|
|
39
|
-
* box. That fallback is why this can be added without every consumer changing.
|
|
14
|
+
* - A host writing their own display over `DisplayChromeBase` builds the corner
|
|
15
|
+
* from this; the chip is told to render in-flow, with no `position` and no
|
|
16
|
+
* corner offsets.
|
|
17
|
+
* - `null` outside a chrome (a standalone mount, a unit test, the SVG export),
|
|
18
|
+
* where `BottomRightIndicators` anchors its own box.
|
|
40
19
|
*/
|
|
41
20
|
export const BottomRightCornerContext = createContext(null);
|
|
42
21
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* Ordered by `order` rather than by DOM position because one member arrives as
|
|
51
|
-
* a portal and the other as an ordinary child, and the relative order of those
|
|
52
|
-
* two inside the container is not something React documents. Only the control
|
|
53
|
-
* row needs a value: the status chip takes CSS's default 0, so anything the
|
|
54
|
-
* chrome adds to the corner later sorts above the controls unless it says
|
|
55
|
-
* otherwise — which is the right default, the controls being the thing whose
|
|
56
|
-
* position in the corner users learn.
|
|
22
|
+
* The control row's flex `order` in the corner column. The members stack
|
|
23
|
+
* rather than sit side by side, so a wide status chip starting or finishing
|
|
24
|
+
* never shoves the controls sideways. `order` sets the sequence because one
|
|
25
|
+
* member arrives as a portal and the other as a child, and React does not
|
|
26
|
+
* document their relative DOM order. The chip takes CSS's default 0, so
|
|
27
|
+
* anything the chrome adds later sorts above the controls, whose position users
|
|
28
|
+
* learn.
|
|
57
29
|
*/
|
|
58
30
|
export const BOTTOM_RIGHT_CONTROLS_ORDER = 1;
|
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import { createContext, use } from 'react';
|
|
2
|
-
// The context alone, in a module of its own
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// `DisplayUIProvider` — the component whose whole purpose is "I do not want
|
|
8
|
-
// Material UI in my app" — and the build agreed: the build-your-own site's
|
|
9
|
-
// "Removing Material UI" page carried 34 first-party eager modules importing
|
|
10
|
-
// `@mui/material` against 16 on the page that deliberately leaves the Material
|
|
11
|
-
// chrome on screen, and 53 KB gzip more. Nothing rendered them. A DOM census
|
|
12
|
-
// cannot see a module graph, so nothing said so.
|
|
13
|
-
//
|
|
14
|
-
// The rule that falls out, and it applies to any seam: **the override channel
|
|
15
|
-
// must not live in the module that binds the default.** Everything toolkit-free
|
|
16
|
-
// (`plainChromeOverlays`, `plainTrackControl`, `DisplayChromeBase`,
|
|
17
|
-
// `DisplayUIProvider`) reaches zero `@mui/*` modules, and
|
|
18
|
-
// `muiFreeSeam.test.ts` fails naming the import trail if that stops being true.
|
|
2
|
+
// The context alone, in a module of its own: the override channel must not live
|
|
3
|
+
// in the module that binds the default. `DisplayChrome.tsx` binds the Material
|
|
4
|
+
// set, so a provider imported from there put Material UI in the graph of the
|
|
5
|
+
// apps asking to leave it out. `muiFree.test.ts` fails naming the import trail
|
|
6
|
+
// if a toolkit-free module reaches `@mui/*` again.
|
|
19
7
|
/**
|
|
20
8
|
* Runtime override for the overlay set. **Defaults to undefined, not to a
|
|
21
|
-
* component set
|
|
22
|
-
* outside a provider (unit tests, SVG export
|
|
23
|
-
* overlayUtils): the display would still work, but stop looking like JBrowse. Undefined means
|
|
24
|
-
* "nobody asked", so `DisplayChrome` keeps its MUI set and nothing changes.
|
|
9
|
+
* component set**: undefined means "nobody asked", so a display rendered
|
|
10
|
+
* outside a provider (unit tests, SVG export) keeps JBrowse's own look.
|
|
25
11
|
*
|
|
26
|
-
* This is
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* no MUI rendered, no ThemeProvider needed, no emotion in their page.
|
|
12
|
+
* This is how an embedder makes JBrowse's own displays, which import
|
|
13
|
+
* `DisplayChrome` directly, draw with their overlays: no MUI rendered, no
|
|
14
|
+
* ThemeProvider needed, no emotion in their page.
|
|
30
15
|
*
|
|
31
16
|
* Prefer `DisplayUIProvider`, which mounts this and the track-control context
|
|
32
17
|
* together and accepts a partial set. Reach for this one only to override
|
package/esm/chromeOverlays.d.ts
CHANGED
|
@@ -1,90 +1,96 @@
|
|
|
1
1
|
import type { ComponentType } from 'react';
|
|
2
|
-
/** What `
|
|
3
|
-
export interface
|
|
2
|
+
/** What `RenderError` draws: a render-backend failure and the re-init. */
|
|
3
|
+
export interface RenderErrorProps {
|
|
4
4
|
error: unknown;
|
|
5
|
-
|
|
5
|
+
onRetry: () => void;
|
|
6
|
+
height: number;
|
|
6
7
|
}
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
/**
|
|
9
|
+
* What `TooLarge` draws: the byte gate's banner text and the way past it.
|
|
10
|
+
* `onForceLoad` is the whole point of the state; without it the region is
|
|
11
|
+
* unreachable for the rest of the session.
|
|
12
|
+
*/
|
|
13
|
+
export interface TooLargeProps {
|
|
14
|
+
message: string;
|
|
15
|
+
onForceLoad: () => void;
|
|
15
16
|
}
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
/**
|
|
18
|
+
* What `ErrorBar` draws: a failed fetch. No `onRetry` means a Retry cannot
|
|
19
|
+
* clear it (the byte gate tripped inside the fetch), so draw the message as
|
|
20
|
+
* information.
|
|
21
|
+
*/
|
|
22
|
+
export interface ErrorBarProps {
|
|
23
|
+
error: unknown;
|
|
24
|
+
onRetry?: () => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* What `Loading` draws. A display that reports no progress and offers no cancel
|
|
28
|
+
* passes neither, and still gets a scrim. `canceled` swaps Cancel for Retry.
|
|
29
|
+
*/
|
|
30
|
+
export interface LoadingProps {
|
|
31
|
+
visible: boolean;
|
|
32
|
+
immediate?: boolean;
|
|
33
|
+
message?: string;
|
|
34
|
+
progress?: number;
|
|
35
|
+
canceled?: boolean;
|
|
36
|
+
onCancel?: () => void;
|
|
37
|
+
onRetry?: () => void;
|
|
21
38
|
}
|
|
22
|
-
/** What `
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
zoomCanReleaseGate: boolean;
|
|
27
|
-
forceLoad: () => void;
|
|
39
|
+
/** What `BackgroundProgress` draws: work with no fetch behind it. */
|
|
40
|
+
export interface BackgroundProgressProps {
|
|
41
|
+
message?: string;
|
|
42
|
+
progress?: number;
|
|
28
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* The five components that draw `displayPhase`'s terminal and overlay states.
|
|
46
|
+
* `DisplayChromeBase` decides which renders, reads the display model, and hands
|
|
47
|
+
* each plain values and callbacks, so a set needs no model, no MobX and no UI
|
|
48
|
+
* toolkit: an embedder with their own design system supplies plain markup and
|
|
49
|
+
* ships no ThemeProvider. Every import above is type-only, so this module pulls
|
|
50
|
+
* no runtime dependency.
|
|
51
|
+
*
|
|
52
|
+
* A replacement set must render something for each state; four test systems
|
|
53
|
+
* key on the testids in `plainChromeOverlays.tsx`.
|
|
54
|
+
*
|
|
55
|
+
* `ErrorBar`, `Loading` and `BackgroundProgress` are portalled as a group into
|
|
56
|
+
* the LGV's per-track overlay layer, which is `pointer-events: none`, so
|
|
57
|
+
* anything of yours the user clicks sets `pointer-events: auto` on its own
|
|
58
|
+
* positioned box. `BackgroundProgress` alone does not own its box; see its
|
|
59
|
+
* entry.
|
|
60
|
+
*/
|
|
29
61
|
export interface DisplayChromeOverlays {
|
|
30
62
|
/**
|
|
31
63
|
* GPU/render-backend failure. A subtree-replacing terminal state: the canvas
|
|
32
64
|
* unmounts and the backend disposes, so this owns the full display area.
|
|
33
65
|
*/
|
|
34
|
-
RenderError: ComponentType<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
height: number;
|
|
38
|
-
}>;
|
|
39
|
-
/**
|
|
40
|
-
* The byte gate tripped. Also subtree-replacing. Must offer `model.forceLoad`
|
|
41
|
-
* or the region becomes unreachable for the rest of the session.
|
|
42
|
-
*/
|
|
43
|
-
TooLarge: ComponentType<{
|
|
44
|
-
model: TooLargeMessageModel;
|
|
45
|
-
}>;
|
|
66
|
+
RenderError: ComponentType<RenderErrorProps>;
|
|
67
|
+
/** The byte gate tripped. Also subtree-replacing. */
|
|
68
|
+
TooLarge: ComponentType<TooLargeProps>;
|
|
46
69
|
/**
|
|
47
70
|
* Fetch error, drawn *over* a live canvas rather than replacing it. Mounted
|
|
48
|
-
*
|
|
49
|
-
* 'error'`) is the gate -- don't re-derive it from `model.error`, which is
|
|
50
|
-
* the same subtraction `displayPhase` exists to retire.
|
|
71
|
+
* only while the phase is `error`.
|
|
51
72
|
*/
|
|
52
|
-
ErrorBar: ComponentType<
|
|
53
|
-
model: DisplayErrorBarModel;
|
|
54
|
-
visible: boolean;
|
|
55
|
-
}>;
|
|
73
|
+
ErrorBar: ComponentType<ErrorBarProps>;
|
|
56
74
|
/**
|
|
57
|
-
* The loading scrim
|
|
58
|
-
*
|
|
59
|
-
* `immediate` asks it to skip its anti-flash delay because nothing is painted
|
|
75
|
+
* The loading scrim, `visible` in the `loading` and `canceled` phases;
|
|
76
|
+
* `immediate` asks it to skip any anti-flash delay because nothing is painted
|
|
60
77
|
* yet.
|
|
61
78
|
*
|
|
62
|
-
* Mounted unconditionally, so it
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* replacement mountable-while-hidden for the same reason.
|
|
79
|
+
* Mounted unconditionally, so it handles `visible === false` itself. An
|
|
80
|
+
* anti-flash delay is component state, so a chrome that mounted this only
|
|
81
|
+
* while loading would restart the timer on every activation and never reach
|
|
82
|
+
* it. Keep any replacement mountable-while-hidden for the same reason.
|
|
67
83
|
*/
|
|
68
|
-
Loading: ComponentType<
|
|
69
|
-
model: DisplayLoadingOverlayModel;
|
|
70
|
-
visible: boolean;
|
|
71
|
-
immediate?: boolean;
|
|
72
|
-
}>;
|
|
84
|
+
Loading: ComponentType<LoadingProps>;
|
|
73
85
|
/**
|
|
74
|
-
* Status for work with no fetch behind it,
|
|
75
|
-
*
|
|
86
|
+
* Status for work with no fetch behind it, mounted only while that work
|
|
87
|
+
* runs: in the LGV chrome, a status message set while the phase is `ready`.
|
|
76
88
|
*
|
|
77
89
|
* **The one state that does not own its own box.** The chrome anchors the
|
|
78
|
-
* bottom-right corner and lays this out there,
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* winning on z-index and the status text vanishing underneath. So render an
|
|
83
|
-
* **in-flow** chip: no `position`, no `inset`, no corner offsets. Sizing and
|
|
84
|
-
* colours are yours; placement is not. See `bottomRightCorner.ts`.
|
|
90
|
+
* bottom-right corner and lays this out there, sharing it with the display's
|
|
91
|
+
* own control row (`BottomRightIndicators`). So render an **in-flow** chip:
|
|
92
|
+
* no `position`, no `inset`, no corner offsets. Sizing and colors are yours;
|
|
93
|
+
* placement is not. See `bottomRightCorner.ts`.
|
|
85
94
|
*/
|
|
86
|
-
BackgroundProgress: ComponentType<
|
|
87
|
-
model: DisplayBackgroundProgressModel;
|
|
88
|
-
visible: boolean;
|
|
89
|
-
}>;
|
|
95
|
+
BackgroundProgress: ComponentType<BackgroundProgressProps>;
|
|
90
96
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Component } from 'react';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
export interface EngineFallbackProps {
|
|
4
|
+
error: unknown;
|
|
5
|
+
retry: () => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Catches what `useCreateViewState` rethrows from render when the engine
|
|
9
|
+
* itself cannot be built (a hub genome that does not exist, a plugin that
|
|
10
|
+
* fails to load), where there is no view yet for `ViewStatus` to draw. Wrap
|
|
11
|
+
* the component that calls the hook. `retry` remounts it, which builds again.
|
|
12
|
+
*
|
|
13
|
+
* Its own class rather than `@jbrowse/core/ui/ErrorBoundary`: a bundler groups
|
|
14
|
+
* that module with core's Material error UI, and importing it eagerly ships
|
|
15
|
+
* ~40 KB gzip of Material with the page.
|
|
16
|
+
*/
|
|
17
|
+
export declare class EngineBoundary extends Component<{
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
fallback?: React.ComponentType<EngineFallbackProps>;
|
|
20
|
+
}, {
|
|
21
|
+
error: unknown;
|
|
22
|
+
failed: boolean;
|
|
23
|
+
}> {
|
|
24
|
+
state: {
|
|
25
|
+
error: unknown;
|
|
26
|
+
failed: boolean;
|
|
27
|
+
};
|
|
28
|
+
static getDerivedStateFromError(error: unknown): {
|
|
29
|
+
error: unknown;
|
|
30
|
+
failed: boolean;
|
|
31
|
+
};
|
|
32
|
+
retry: () => void;
|
|
33
|
+
render(): string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | Iterable<React.ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | null | undefined;
|
|
34
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
4
|
+
const DefaultFallback = observer(function DefaultFallback({ error, retry, }) {
|
|
5
|
+
return (_jsxs("div", { role: "alert", style: { padding: '10px 12px', fontSize: '0.85rem' }, children: ["Could not build the view:", ' ', error instanceof Error ? error.message : String(error), ' ', _jsx("button", { type: "button", onClick: retry, children: "Retry" })] }));
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* Catches what `useCreateViewState` rethrows from render when the engine
|
|
9
|
+
* itself cannot be built (a hub genome that does not exist, a plugin that
|
|
10
|
+
* fails to load), where there is no view yet for `ViewStatus` to draw. Wrap
|
|
11
|
+
* the component that calls the hook. `retry` remounts it, which builds again.
|
|
12
|
+
*
|
|
13
|
+
* Its own class rather than `@jbrowse/core/ui/ErrorBoundary`: a bundler groups
|
|
14
|
+
* that module with core's Material error UI, and importing it eagerly ships
|
|
15
|
+
* ~40 KB gzip of Material with the page.
|
|
16
|
+
*/
|
|
17
|
+
export class EngineBoundary extends Component {
|
|
18
|
+
state = { error: undefined, failed: false };
|
|
19
|
+
static getDerivedStateFromError(error) {
|
|
20
|
+
return { error, failed: true };
|
|
21
|
+
}
|
|
22
|
+
retry = () => {
|
|
23
|
+
this.setState({ error: undefined, failed: false });
|
|
24
|
+
};
|
|
25
|
+
render() {
|
|
26
|
+
const Fallback = this.props.fallback ?? DefaultFallback;
|
|
27
|
+
return this.state.failed ? (_jsx(Fallback, { error: this.state.error, retry: this.retry })) : (this.props.children);
|
|
28
|
+
}
|
|
29
|
+
}
|