@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.
Files changed (55) hide show
  1. package/README.md +70 -76
  2. package/esm/AxisCaption.d.ts +2 -2
  3. package/esm/AxisCaption.js +6 -4
  4. package/esm/AxisGutter.d.ts +2 -2
  5. package/esm/AxisGutter.js +5 -4
  6. package/esm/CrossHatches.d.ts +3 -2
  7. package/esm/CrossHatches.js +5 -2
  8. package/esm/DisplayUIProvider.d.ts +3 -2
  9. package/esm/DisplayUIProvider.js +4 -2
  10. package/esm/FloatingLegend.js +7 -3
  11. package/esm/FloatingText.d.ts +9 -8
  12. package/esm/FloatingText.js +9 -7
  13. package/esm/ScoreDomainCaption.d.ts +2 -2
  14. package/esm/ScoreDomainCaption.js +3 -2
  15. package/esm/ScoreRules.d.ts +3 -2
  16. package/esm/ScoreRules.js +5 -2
  17. package/esm/YScaleBar.js +1 -8
  18. package/esm/YScaleBarOverlay.d.ts +3 -2
  19. package/esm/YScaleBarOverlay.js +4 -2
  20. package/esm/axisPlacement.d.ts +16 -9
  21. package/esm/axisPlacement.js +22 -14
  22. package/esm/bottomRightCorner.d.ts +19 -47
  23. package/esm/bottomRightCorner.js +19 -47
  24. package/esm/chromeOverlayContext.js +10 -25
  25. package/esm/chromeOverlays.d.ts +73 -67
  26. package/esm/embed/engineBoundary.d.ts +34 -0
  27. package/esm/embed/engineBoundary.js +29 -0
  28. package/esm/embed/index.d.ts +6 -0
  29. package/esm/embed/index.js +18 -3
  30. package/esm/embed/legend.js +2 -2
  31. package/esm/embed/location.d.ts +2 -1
  32. package/esm/embed/location.js +18 -17
  33. package/esm/embed/notifications.d.ts +29 -0
  34. package/esm/embed/notifications.js +38 -0
  35. package/esm/embed/provider.d.ts +5 -3
  36. package/esm/embed/provider.js +6 -4
  37. package/esm/embed/regions.d.ts +3 -2
  38. package/esm/embed/regions.js +9 -7
  39. package/esm/embed/searchPicker.d.ts +24 -0
  40. package/esm/embed/searchPicker.js +14 -0
  41. package/esm/embed/toolbar.d.ts +16 -0
  42. package/esm/embed/toolbar.js +22 -0
  43. package/esm/index.d.ts +1 -1
  44. package/esm/isLiveModel.d.ts +10 -15
  45. package/esm/isLiveModel.js +10 -15
  46. package/esm/plainChromeOverlays.d.ts +2 -2
  47. package/esm/plainChromeOverlays.js +17 -39
  48. package/esm/tooltip/Tooltip.d.ts +3 -3
  49. package/esm/tooltip/Tooltip.js +4 -2
  50. package/esm/trackControl/plainTrackControl.d.ts +2 -1
  51. package/esm/trackControl/plainTrackControl.js +8 -6
  52. package/esm/trackOverlay/TrackOverlaySlot.d.ts +3 -3
  53. package/esm/trackOverlay/TrackOverlaySlot.js +4 -3
  54. package/esm/valueScale.d.ts +5 -5
  55. package/package.json +4 -4
package/README.md CHANGED
@@ -34,19 +34,19 @@ above them.
34
34
 
35
35
  ## What is here
36
36
 
37
- | | |
38
- | ------------------------------------------- | --------------------------------------------------------------------------------------- |
39
- | `DisplayChromeOverlays` | the `displayPhase` states, as a five-component set, with the model shape each is handed |
40
- | `DisplayChromeOverlayProvider` | redirects those states for JBrowse's own displays |
41
- | `TrackControlComponent` | one shape for every ambient bottom-right control, icons named rather than passed |
42
- | `TrackControlProvider` | redirects those |
43
- | `DisplayUIProvider` | both at once, defaulting to the plain sets — what an embedder mounts |
44
- | `plainChromeOverlays` / `plainTrackControl` | the toolkit-free sets, CSS system colours, no theme object |
45
- | `TrackOverlaySlot` / `TrackOverlayPortal` | the per-track overlay layer, and the host's half of it |
46
- | `FloatingLegend` | the one legend box every display with colours to explain draws |
47
- | `BottomRightCornerContext` | the corner `BackgroundProgress` is laid out in, which its prop types cannot express |
48
- | `tooLargeBannerText` | what the byte gate says, shared by every set that renders it |
49
- | `isLiveModel` | the liveness guard an overlay's one button needs, for an MST node or a plain object |
37
+ | | |
38
+ | ------------------------------------------- | ----------------------------------------------------------------------------------- |
39
+ | `DisplayChromeOverlays` | the `displayPhase` states, as a five-component set taking plain props |
40
+ | `DisplayChromeOverlayProvider` | redirects those states for JBrowse's own displays |
41
+ | `TrackControlComponent` | one shape for every ambient bottom-right control, icons named rather than passed |
42
+ | `TrackControlProvider` | redirects those |
43
+ | `DisplayUIProvider` | both at once, defaulting to the plain sets — what an embedder mounts |
44
+ | `plainChromeOverlays` / `plainTrackControl` | the toolkit-free sets, CSS system colors, no theme object |
45
+ | `TrackOverlaySlot` / `TrackOverlayPortal` | the per-track overlay layer, and the host's half of it |
46
+ | `FloatingLegend` | the one legend box every display with colors to explain draws |
47
+ | `BottomRightCornerContext` | the corner `BackgroundProgress` is laid out in, which its prop types cannot express |
48
+ | `tooLargeBannerText` | what the byte gate says, shared by every set that renders it |
49
+ | `isLiveModel` | the liveness guard an overlay's one button needs, for an MST node or a plain object |
50
50
 
51
51
  ## What is _not_ here, and cannot be
52
52
 
@@ -69,42 +69,23 @@ Auto-generated from `#api` JSDoc tags in this package. Do not edit by hand.
69
69
 
70
70
  The one box per display that owns the bottom-right corner.
71
71
 
72
- It lives beside the overlay contract rather than with the chrome that mounts it,
73
- because it is the half of that contract the types cannot carry:
74
- `DisplayChromeOverlays.BackgroundProgress` is the one state told to render an
75
- in-flow chip with no `position` and no corner offsets, and this is the box it is
76
- laid out in. A host writing their own display over `DisplayChromeBase` needs to
77
- be able to build that corner; while this sat one layer up in the LGV plugin, the
78
- rule was a paragraph they could only obey by hand.
79
-
80
- Two independent things want that corner and neither could see the other: the
81
- display's own control row (`BottomRightIndicators` — track sizing, the isoform
82
- notice, the solo chip) and the chrome's background-progress chip
83
- (`DisplayChromeOverlays.BackgroundProgress`, the status channel for work with no
84
- fetch behind it). Both portal into the _same_ per-track overlay node, and both
85
- used to claim `bottom: 2; right: 2` there with their own `position: absolute`
86
- box — so they simply drew on top of each other, the controls winning on z-index
87
- and the status text disappearing under them.
88
-
89
- It has never been reachable: the two displays that render the control row
90
- (alignments, canvas) are not among the four that report a `ready`-phase status
91
- (clustering, on multi-wiggle / multi-row features / maf / the multi-sample
92
- variant pair). The layout is structural anyway, because neither side checks for
93
- the constraint, so the first display to want both would hit the bug as a status
94
- message that never appears.
95
-
96
- `BottomRightIndicators` already described itself as "the single anchor point for
97
- every bottom-right overlay ... so they lay out as one row instead of each
98
- picking their own position and colliding". This makes that true of the chip too:
99
- the chrome renders the anchor, puts its chip in it, and publishes the node here
100
- so the display's row — rendered several components away, inside the chrome's
101
- body — lands in the same flex box instead of over it.
102
-
103
- `null` outside a chrome (a display an embedder mounts standalone, a unit test,
104
- the SVG export), where `BottomRightIndicators` keeps its own anchored box. That
105
- fallback is why this can be added without every consumer changing.
72
+ Two members share it: the display's own control row (`BottomRightIndicators`)
73
+ and the chrome's background-progress chip
74
+ (`DisplayChromeOverlays.BackgroundProgress`). Both portal into the same
75
+ per-track overlay node, so each claiming the corner with its own
76
+ `position: absolute` box draws one over the other. The chrome renders this box,
77
+ lays its chip out in it, and publishes the node here so the control row,
78
+ rendered inside the chrome's body, lands in the same flex column.
79
+
80
+ - A host writing their own display over `DisplayChromeBase` builds the corner
81
+ from this; the chip is told to render in-flow, with no `position` and no
82
+ corner offsets.
83
+ - `null` outside a chrome (a standalone mount, a unit test, the SVG export),
84
+ where `BottomRightIndicators` anchors its own box.
106
85
 
107
86
  ```js
87
+ import { BottomRightCornerContext } from '@jbrowse/display-ui'
88
+
108
89
  // type signature
109
90
  Context<HTMLElement | null>
110
91
  ```
@@ -172,33 +153,32 @@ no toolkit. See
172
153
  [DISPLAYCHROME.md](https://github.com/GMOD/jbrowse-components/blob/main/agent-docs/reference/DISPLAYCHROME.md).
173
154
 
174
155
  ```js
156
+ import { DisplayUIProvider } from '@jbrowse/display-ui'
157
+
175
158
  // type signature
176
- ({ overlays, trackControl, children, }: { overlays?: Partial<…> | undefined; trackControl?: TrackControlComponent | undefined; children: ReactNode; }) => Element
159
+ ({ overlays, trackControl, children, }: { overlays?: Partial<DisplayChromeOverlays> | undefined; trackControl?: TrackControlComponent | undefined; children: ReactNode; }) => Element
177
160
  ```
178
161
 
179
162
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/DisplayUIProvider.tsx)
180
163
 
181
164
  ### isLiveModel
182
165
 
183
- Whether an overlay's model can still be called into.
166
+ Whether a display model can still be called into.
184
167
 
185
- The terminal states unmount the canvas, so a click landing after the track was
186
- closed would otherwise run an action on a destroyed node — which is why both
187
- overlay sets guard their one button with `isAlive`.
168
+ The chrome's overlay slots guard every button with it: the terminal states
169
+ unmount the canvas, so a click landing after the track was closed would
170
+ otherwise run an action on a destroyed node.
188
171
 
189
- **`isAlive` alone is wrong here, and it throws rather than answering.** The four
190
- model shapes in `chromeOverlays.ts` are structural on purpose ("A display
191
- satisfies one by having the fields; no mixin has to be composed"), so a host
192
- writing their own display over `DisplayChromeBase` may hand these components a
193
- plain object. `isAlive` runs `assertIsStateTreeNode` and throws on one, inside
194
- an event handler, where React logs it and moves on — leaving the Force load
195
- button looking live and doing nothing, which is the exact state
196
- `DisplayChromeOverlays.TooLarge` documents itself as existing to prevent.
197
-
198
- A plain object is never destroyed, so it is always callable. The liveness
199
- question only exists for an MST node.
172
+ **`isAlive` alone is wrong here, and it throws rather than answering.** A host
173
+ writing their own display over `DisplayChromeBase` may hand the chrome a plain
174
+ object, and `isAlive` runs `assertIsStateTreeNode`, which throws inside the
175
+ click handler, where React logs it and moves on: a Force load button that looks
176
+ live and does nothing. A plain object is never destroyed, so it is always
177
+ callable.
200
178
 
201
179
  ```js
180
+ import { isLiveModel } from '@jbrowse/display-ui'
181
+
202
182
  // type signature
203
183
  (model: unknown) => boolean
204
184
  ```
@@ -213,7 +193,7 @@ inside someone else's design system.
213
193
 
214
194
  `DisplayUIProvider` installs this by default, so mount that rather than naming
215
195
  this — reach for it directly only to wrap a state or to build a context value by
216
- hand. Colours come from `currentColor` and the CSS system colours, so the host's
196
+ hand. Colors come from `currentColor` and the CSS system colors, so the host's
217
197
  own cascade drives them in both light and dark.
218
198
 
219
199
  The `data-testid` values it renders are a contract four of JBrowse's test
@@ -221,6 +201,8 @@ systems key on, so a replacement set that keeps them can be driven by those
221
201
  suites too.
222
202
 
223
203
  ```js
204
+ import { plainChromeOverlays } from '@jbrowse/display-ui'
205
+
224
206
  // type signature
225
207
  DisplayChromeOverlays
226
208
  ```
@@ -265,6 +247,8 @@ two consecutive measurements rather than from a threshold; see
265
247
  `ByteEstimate.zoomIneffective`.
266
248
 
267
249
  ```js
250
+ import { tooLargeBannerText } from '@jbrowse/display-ui'
251
+
268
252
  // type signature
269
253
  (regionTooLargeReason: string, { zoomCanRelease }?: { zoomCanRelease?: boolean | undefined; }) => string
270
254
  ```
@@ -303,8 +287,10 @@ chrome is built on, uses the same trigger pattern; only the toolkit differs.
303
287
  without the cloning, for a host writing its own markup.
304
288
 
305
289
  ```js
290
+ import { Tooltip } from '@jbrowse/display-ui'
291
+
306
292
  // type signature
307
- ({ title, placement, children, }: { title: ReactNode; placement?: TooltipPlacement | undefined; children: ReactElement<…>; }) => Element
293
+ ({ title, placement, children, }: { title: ReactNode; placement?: TooltipPlacement | undefined; children: ReactElement<TriggerProps, string | JSXElementConstructor<any>>; }) => Element
308
294
  ```
309
295
 
310
296
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/tooltip/Tooltip.tsx)
@@ -324,6 +310,8 @@ default), which preserves chrome that is still meaningful unescaped. Pass
324
310
  draws itself some other way elsewhere.
325
311
 
326
312
  ```js
313
+ import { TrackOverlayPortal } from '@jbrowse/display-ui'
314
+
327
315
  // type signature
328
316
  ({ children, fallbackInline, }: { children: ReactNode; fallbackInline?: boolean | undefined; }) => ReactNode
329
317
  ```
@@ -338,7 +326,7 @@ escapes into. Pair to `TrackOverlayPortal`, which is the other end.
338
326
  A display's React tree is sealed in a `contain: strict` sandbox — that is what
339
327
  isolates its paint, and dropping it is measured and rejected (ADR-058). A
340
328
  stacking context comes with the isolation, so floating chrome a display draws (a
341
- colour key, hi-c's overlay panel, maf's row labels) cannot out-z-index anything
329
+ color key, hi-c's overlay panel, maf's row labels) cannot out-z-index anything
342
330
  painted over the track stack from outside. The escape is a node mounted _beside_
343
331
  the sandbox rather than inside it, published through `TrackOverlayContext`; this
344
332
  component is that node, its context and the paint order between them, in the one
@@ -373,6 +361,8 @@ wants them takes them back on its own positioned box; it also carries
373
361
  click-drag pan.
374
362
 
375
363
  ```js
364
+ import { TrackOverlaySlot } from '@jbrowse/display-ui'
365
+
376
366
  // type signature
377
367
  ({ children, zIndex, style, overlayStyle, }: { children: ReactNode; zIndex: number; style?: CSSProperties | undefined; overlayStyle?: CSSProperties | undefined; }) => Element
378
368
  ```
@@ -402,6 +392,8 @@ with it. Any other handler on this list has to compose rather than replace —
402
392
  spread first, then call `triggerProps.onFocus` from yours.
403
393
 
404
394
  ```js
395
+ import { useTooltip } from '@jbrowse/display-ui'
396
+
405
397
  // type signature
406
398
  (title: ReactNode, { placement }?: { placement?: TooltipPlacement | undefined; }) => TooltipTrigger
407
399
  ```
@@ -422,6 +414,8 @@ Render `menuProps` only while `open`, and portal it to `document.body` —
422
414
  carries position only.
423
415
 
424
416
  ```js
417
+ import { useTrackControlMenu } from '@jbrowse/display-ui'
418
+
425
419
  // type signature
426
420
  (onClose?: (() => void) | undefined) => TrackControlMenu
427
421
  ```
@@ -431,7 +425,7 @@ carries position only.
431
425
  ### ValueScale
432
426
 
433
427
  A value scale a display places its y through, declared so the chrome can derive
434
- the axis from it — the score axis's counterpart to a colour scale.
428
+ the axis from it — the score axis's counterpart to a color scale.
435
429
 
436
430
  `domain` is the resolved `[min, max]`; `height` the band it rules and `offset`
437
431
  the inset of the plot box inside that band (`axisPlotBox(height, offset)`);
@@ -444,15 +438,15 @@ geometry); `ScoreScaleMixin` derives one through `computeYTicks` otherwise.
444
438
  display stacks the same plot: the multi-wiggle's rows, a grouped alignments
445
439
  track's coverage band per group, each projected through the display's own
446
440
  scroll; the chrome drops the ones off screen. `[]` is a scale the display maps
447
- to colour rather than to y (density rows each in their own colour), which gets
448
- the `[min, max]` caption and no axis, as a scale whose bands are too short for
449
- one does. `side` and `left` are which of the band's edges the display's own
450
- panels leave clear for a gutter: `right` where a group label chip takes the
451
- left, `left: n` where a dendrogram takes the first `n` px. `caption` is what the
452
- scale measures (`TLEN`), as a colour scale's `field` is; the chrome draws it
453
- once for the scale, beside the bands on screen, however many it rules. `rules`
454
- are the reference lines the scale declares and `grid` a line at every tick, both
455
- drawn across every band.
441
+ to color rather than to y (density rows each in their own color), which gets the
442
+ `[min, max]` caption and no axis, as a scale whose bands are too short for one
443
+ does. `side` and `left` are which of the band's edges the display's own panels
444
+ leave clear for a gutter: `right` where a group label chip takes the left,
445
+ `left: n` where a dendrogram and row labels take the first `n` px. `caption` is
446
+ what the scale measures (`TLEN`), as a color scale's `field` is; the chrome
447
+ draws it once for the scale, beside the bands on screen, however many it rules.
448
+ `rules` are the reference lines the scale declares and `grid` a line at every
449
+ tick, both drawn across every band.
456
450
 
457
451
  A member describes the scale or the band it rules, never the axis — not an
458
452
  orientation, a form, a gutter width or a font. The chrome reads a member to keep
@@ -16,9 +16,9 @@ export default function AxisCaption({ axis, bandTops, height, }: {
16
16
  * The on-screen caption of one scale: an `<svg>` over the gutter column, the
17
17
  * height of the display, with `AxisCaption` inside.
18
18
  */
19
- export declare function AxisCaptionOverlay({ axis, bandTops, width, height, }: {
19
+ export declare const AxisCaptionOverlay: ({ axis, bandTops, width, height, }: {
20
20
  axis: YAxis;
21
21
  bandTops: number[];
22
22
  width: number;
23
23
  height: number;
24
- }): import("react").JSX.Element;
24
+ }) => import("react").JSX.Element;
@@ -2,7 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { usePalette } from '@jbrowse/core/ui/PaletteContext';
3
3
  import { VERTICAL_SCROLLBAR_CLEARANCE } from '@jbrowse/core/ui/VerticalScrollbar';
4
4
  import { measureText } from '@jbrowse/core/util/measureText';
5
- import { axisCaptionY, axisGutterLeft, axisGutterWidth, } from './axisPlacement.js';
5
+ import { observer } from 'mobx-react';
6
+ import { axisCaptionY, axisGutterLeft, axisGutterWidth, numbersGrowRight, } from './axisPlacement.js';
6
7
  import { AXIS_FONT_PX, CAPTION_INSET_PX } from './yAxisConstants.js';
7
8
  // The caption and its length, cut to an ellipsis where it is longer than
8
9
  // `room`, as a Vega-Lite axis title is cut at its `titleLimit`. The ellipsis
@@ -28,9 +29,10 @@ function fitCaption(caption, room) {
28
29
  * and the export both draw through this, so the two cannot place a caption
29
30
  * differently.
30
31
  */
32
+ // eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
31
33
  export default function AxisCaption({ axis, bandTops, height, }) {
32
34
  const palette = usePalette();
33
- const x = axis.side === 'right'
35
+ const x = numbersGrowRight(axis)
34
36
  ? axisGutterWidth(axis) - CAPTION_INSET_PX
35
37
  : CAPTION_INSET_PX;
36
38
  const caption = fitCaption(axis.caption ?? '', height);
@@ -45,7 +47,7 @@ export default function AxisCaption({ axis, bandTops, height, }) {
45
47
  * The on-screen caption of one scale: an `<svg>` over the gutter column, the
46
48
  * height of the display, with `AxisCaption` inside.
47
49
  */
48
- export function AxisCaptionOverlay({ axis, bandTops, width, height, }) {
50
+ export const AxisCaptionOverlay = observer(function AxisCaptionOverlay({ axis, bandTops, width, height, }) {
49
51
  return (_jsx("svg", { style: {
50
52
  position: 'absolute',
51
53
  top: 0,
@@ -54,4 +56,4 @@ export function AxisCaptionOverlay({ axis, bandTops, width, height, }) {
54
56
  height,
55
57
  width: axisGutterWidth(axis),
56
58
  }, children: _jsx(AxisCaption, { axis: axis, bandTops: bandTops, height: height }) }));
57
- }
59
+ });
@@ -1,8 +1,8 @@
1
1
  import type { YAxis } from './valueScale.ts';
2
2
  /**
3
3
  * One band's axis drawn inside its gutter, the origin at the gutter's left
4
- * edge: the spine on the gutter's inner edge — its right for a left-side
5
- * axis, its left for a right-side one — with the numbers growing outward. The
4
+ * edge: the spine on the gutter's left edge with the numbers growing right
5
+ * where `numbersGrowRight` says so, and on its right edge otherwise. The
6
6
  * on-screen overlay and the export both draw through this, so the two cannot
7
7
  * place a spine differently. The scale's caption is `AxisCaption`'s, drawn once
8
8
  * for the scale and not per band.
package/esm/AxisGutter.js CHANGED
@@ -1,15 +1,16 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import YScaleBar from './YScaleBar.js';
3
- import { axisGutterWidth } from './axisPlacement.js';
3
+ import { axisGutterWidth, numbersGrowRight } from './axisPlacement.js';
4
4
  /**
5
5
  * One band's axis drawn inside its gutter, the origin at the gutter's left
6
- * edge: the spine on the gutter's inner edge — its right for a left-side
7
- * axis, its left for a right-side one — with the numbers growing outward. The
6
+ * edge: the spine on the gutter's left edge with the numbers growing right
7
+ * where `numbersGrowRight` says so, and on its right edge otherwise. The
8
8
  * on-screen overlay and the export both draw through this, so the two cannot
9
9
  * place a spine differently. The scale's caption is `AxisCaption`'s, drawn once
10
10
  * for the scale and not per band.
11
11
  */
12
+ // eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
12
13
  export default function AxisGutter({ axis }) {
13
- const right = axis.side === 'right';
14
+ const right = numbersGrowRight(axis);
14
15
  return (_jsx("g", { transform: `translate(${right ? 0 : axisGutterWidth(axis)} 0)`, children: _jsx(YScaleBar, { ticks: axis.ticks, orientation: right ? 'right' : 'left', bandHeight: axis.height }) }));
15
16
  }
@@ -4,9 +4,10 @@ export declare function CrossHatchLines({ ticks, width, offsetY, }: {
4
4
  width: number;
5
5
  offsetY?: number;
6
6
  }): import("react").JSX.Element;
7
- export default function CrossHatches({ ticks, width, height, bandTops, }: {
7
+ declare const CrossHatches: ({ ticks, width, height, bandTops, }: {
8
8
  ticks: YScaleTicks;
9
9
  width: number;
10
10
  height: number;
11
11
  bandTops: number[];
12
- }): import("react").JSX.Element;
12
+ }) => import("react").JSX.Element;
13
+ export default CrossHatches;
@@ -1,8 +1,10 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { observer } from 'mobx-react';
2
3
  import { clampStrokeInsideAxis } from './yScaleTicks.js';
3
4
  // Bare <line> set for the Y-scale tick guide lines, no wrapping <svg>. Shared by
4
5
  // the absolutely-positioned on-screen CrossHatches overlay and the flat SVG
5
6
  // export, so the two can't drift. `offsetY` is the band's top.
7
+ // eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
6
8
  export function CrossHatchLines({ ticks, width, offsetY = 0, }) {
7
9
  return (_jsx(_Fragment, { children: ticks.items.map(({ value, y }) => {
8
10
  // Same clamp the axis ticks take, so a guide line and the tick it
@@ -19,7 +21,7 @@ export function CrossHatchLines({ ticks, width, offsetY = 0, }) {
19
21
  }
20
22
  // Horizontal guide lines at each Y-scale tick, once per band the scale rules.
21
23
  // Pointer-events disabled so the underlying canvas still receives mouse events.
22
- export default function CrossHatches({ ticks, width, height, bandTops, }) {
24
+ const CrossHatches = observer(function CrossHatches({ ticks, width, height, bandTops, }) {
23
25
  return (_jsx("svg", { style: {
24
26
  position: 'absolute',
25
27
  top: 0,
@@ -28,4 +30,5 @@ export default function CrossHatches({ ticks, width, height, bandTops, }) {
28
30
  height,
29
31
  width,
30
32
  }, children: bandTops.map(top => (_jsx(CrossHatchLines, { ticks: ticks, width: width, offsetY: top }, top))) }));
31
- }
33
+ });
34
+ export default CrossHatches;
@@ -63,8 +63,9 @@ export declare function resolveOverlays(overlays?: Partial<DisplayChromeOverlays
63
63
  * prop and imports no toolkit. See
64
64
  * [DISPLAYCHROME.md](https://github.com/GMOD/jbrowse-components/blob/main/agent-docs/reference/DISPLAYCHROME.md).
65
65
  */
66
- export default function DisplayUIProvider({ overlays, trackControl, children, }: {
66
+ declare const DisplayUIProvider: ({ overlays, trackControl, children, }: {
67
67
  overlays?: Partial<DisplayChromeOverlays>;
68
68
  trackControl?: TrackControlComponent;
69
69
  children: ReactNode;
70
- }): import("react").JSX.Element;
70
+ }) => import("react").JSX.Element;
71
+ export default DisplayUIProvider;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { observer } from 'mobx-react';
2
3
  import { DisplayChromeOverlayProvider } from './chromeOverlayContext.js';
3
4
  import plainChromeOverlays from './plainChromeOverlays.js';
4
5
  import plainTrackControl from './trackControl/plainTrackControl.js';
@@ -91,6 +92,7 @@ export function resolveOverlays(overlays) {
91
92
  * prop and imports no toolkit. See
92
93
  * [DISPLAYCHROME.md](https://github.com/GMOD/jbrowse-components/blob/main/agent-docs/reference/DISPLAYCHROME.md).
93
94
  */
94
- export default function DisplayUIProvider({ overlays, trackControl = plainTrackControl, children, }) {
95
+ const DisplayUIProvider = observer(function DisplayUIProvider({ overlays, trackControl = plainTrackControl, children, }) {
95
96
  return (_jsx(DisplayChromeOverlayProvider, { value: resolveOverlays(overlays), children: _jsx(TrackControlProvider, { value: trackControl, children: children }) }));
96
- }
97
+ });
98
+ export default DisplayUIProvider;
@@ -193,7 +193,7 @@ function gradientCss({ stops }, paper) {
193
193
  });
194
194
  return `linear-gradient(to right, ${list.join(', ')})`;
195
195
  }
196
- function GradientRow({ label, gradient, }) {
196
+ const GradientRow = observer(function GradientRow({ label, gradient, }) {
197
197
  const { classes, theme } = useStyles();
198
198
  return (_jsxs("div", { className: classes.gradientRow, children: [label ? _jsx("div", { className: classes.label, children: label }) : null, _jsx("div", { className: classes.gradientBar,
199
199
  // backgroundImage (longhand), not the `background` shorthand: the
@@ -202,7 +202,7 @@ function GradientRow({ label, gradient, }) {
202
202
  style: {
203
203
  backgroundImage: gradientCss(gradient, theme.palette.background.paper),
204
204
  } }), _jsxs("div", { className: classes.gradientLabels, children: [_jsx("span", { children: gradient.minLabel }), _jsx("span", { children: gradient.maxLabel })] })] }));
205
- }
205
+ });
206
206
  // One list of swatches with its own independent collapse state, so each section
207
207
  // in a multi-section legend expands/collapses on its own.
208
208
  const LegendItemList = observer(function LegendItemList({ items, maxItems, onItemClick, }) {
@@ -223,7 +223,7 @@ const LegendItemList = observer(function LegendItemList({ items, maxItems, onIte
223
223
  }
224
224
  const row = (_jsxs(_Fragment, { children: [_jsx("div", { className: classes.swatches, style: { minWidth: columns * SWATCH + (columns - 1) * 2 }, children: legendSwatches(item).map(swatch => (_jsx("svg", { width: SWATCH, height: SWATCH, children: _jsx(LegendSwatchGlyph, { swatch: swatch, size: SWATCH }) }, `${swatch.shape}-${swatch.color}`))) }), _jsx("span", { className: classes.label, children: item.label })] }));
225
225
  const itemClass = cx(classes.item, item.hidden && classes.hiddenItem);
226
- return onItemClick ? (_jsx("button", { type: "button", className: cx(itemClass, classes.itemButton), title: "Show only these rows", onClick: () => {
226
+ return onItemClick && legendSwatches(item).length > 0 ? (_jsx("button", { type: "button", className: cx(itemClass, classes.itemButton), title: "Show only these rows", onClick: () => {
227
227
  onItemClick(item);
228
228
  }, children: row }, `${item.label}-${i}`)) : (_jsx("div", { className: itemClass, children: row }, `${item.label}-${i}`));
229
229
  }), collapsible ? (_jsx("button", { type: "button", className: classes.toggle, onClick: () => {
@@ -239,6 +239,10 @@ const LegendItemList = observer(function LegendItemList({ items, maxItems, onIte
239
239
  // `onItemClick` makes the rows of a section declaring `focusesRows` act —
240
240
  // clicking an entry focuses the rows it names. A section coloring features or
241
241
  // cells stays inert text beside it.
242
+ //
243
+ // The key covers data at the lane's top right, an overlap Colin accepted on
244
+ // 2026-09-30. A lane shorter than the key scrolls it rather than clipping it,
245
+ // which a still cannot show, so a figure gives that lane more height.
242
246
  const FloatingLegend = observer(function FloatingLegend({ sections, title, onDismiss, onDismissSection, onItemClick, maxItems = DEFAULT_MAX_ITEMS, maxWidth = DEFAULT_MAX_WIDTH, top = FLOATING_LEGEND_TOP_PX, right = FLOATING_LEGEND_RIGHT_PX, }) {
243
247
  const { classes } = useStyles();
244
248
  const nonEmpty = nonEmptyLegendSections(sections);
@@ -1,6 +1,6 @@
1
1
  import type { CSSProperties, ComponentPropsWithoutRef, ReactNode } from 'react';
2
2
  /**
3
- * Four offset shadows in the surface colour: a halo under a line of DOM text
3
+ * Four offset shadows in the surface color: a halo under a line of DOM text
4
4
  * that needs no measured stroke and reads the same over a mark and over the
5
5
  * background.
6
6
  */
@@ -17,11 +17,11 @@ export declare const TEXT_BASELINE_RATIO = 0.84;
17
17
  * The canvas feature labels and the mark display's text marks emit through
18
18
  * this, so the typography of a floated label is one declaration; what places
19
19
  * each label is its display's own rule. `halo` draws {@link textHalo} under
20
- * the glyphs in that colour. Everything else a caller passes reaches the div:
20
+ * the glyphs in that color. Everything else a caller passes reaches the div:
21
21
  * a class for the pointer and the cursor, the data attributes a delegated
22
22
  * handler reads, a `title`.
23
23
  */
24
- export declare function FloatingText({ x, y, color, fontSize, halo, style, children, ...rest }: {
24
+ export declare const FloatingText: ({ x, y, color, fontSize, halo, style, children, ...rest }: {
25
25
  x: number;
26
26
  y: number;
27
27
  color: string;
@@ -29,13 +29,14 @@ export declare function FloatingText({ x, y, color, fontSize, halo, style, child
29
29
  halo?: string;
30
30
  style?: CSSProperties;
31
31
  children: ReactNode;
32
- } & Omit<ComponentPropsWithoutRef<'div'>, 'style' | 'color' | 'children'>): import("react").JSX.Element;
32
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'style' | 'color' | 'children'>) => import("react").JSX.Element;
33
33
  /**
34
34
  * The same line in an SVG export: two `<text>`s at the baseline `y`, a stroke
35
- * in the surface colour under the glyphs, since SVG paints stroke over fill
35
+ * in the surface color under the glyphs, since SVG paints stroke over fill
36
36
  * and a thick stroke beneath a second copy is how a halo is drawn there. Both
37
- * carry the size and family explicitly, because a `<text>` with neither takes
38
- * SVG's 16px default in a saved file.
37
+ * carry the size, because a `<text>` without one takes SVG's 16px default in a
38
+ * saved file. An export leaves `fontFamily` out, so the label inherits the
39
+ * family the export dialog put on the root.
39
40
  */
40
41
  export declare function SvgHaloText({ x, y, fill, halo, haloWidth, fontSize, fontFamily, anchor, children, }: {
41
42
  x: number;
@@ -44,7 +45,7 @@ export declare function SvgHaloText({ x, y, fill, halo, haloWidth, fontSize, fon
44
45
  halo: string;
45
46
  haloWidth: number | string;
46
47
  fontSize: number;
47
- fontFamily: string;
48
+ fontFamily?: string;
48
49
  anchor?: 'start' | 'middle' | 'end';
49
50
  children: ReactNode;
50
51
  }): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { observer } from 'mobx-react';
2
3
  /**
3
- * Four offset shadows in the surface colour: a halo under a line of DOM text
4
+ * Four offset shadows in the surface color: a halo under a line of DOM text
4
5
  * that needs no measured stroke and reads the same over a mark and over the
5
6
  * background.
6
7
  */
@@ -19,11 +20,11 @@ export const TEXT_BASELINE_RATIO = 0.84;
19
20
  * The canvas feature labels and the mark display's text marks emit through
20
21
  * this, so the typography of a floated label is one declaration; what places
21
22
  * each label is its display's own rule. `halo` draws {@link textHalo} under
22
- * the glyphs in that colour. Everything else a caller passes reaches the div:
23
+ * the glyphs in that color. Everything else a caller passes reaches the div:
23
24
  * a class for the pointer and the cursor, the data attributes a delegated
24
25
  * handler reads, a `title`.
25
26
  */
26
- export function FloatingText({ x, y, color, fontSize, halo, style, children, ...rest }) {
27
+ export const FloatingText = observer(function FloatingText({ x, y, color, fontSize, halo, style, children, ...rest }) {
27
28
  return (_jsx("div", { ...rest, style: {
28
29
  position: 'absolute',
29
30
  lineHeight: 1,
@@ -34,13 +35,14 @@ export function FloatingText({ x, y, color, fontSize, halo, style, children, ...
34
35
  ...(halo ? { textShadow: textHalo(halo) } : {}),
35
36
  ...style,
36
37
  }, children: children }));
37
- }
38
+ });
38
39
  /**
39
40
  * The same line in an SVG export: two `<text>`s at the baseline `y`, a stroke
40
- * in the surface colour under the glyphs, since SVG paints stroke over fill
41
+ * in the surface color under the glyphs, since SVG paints stroke over fill
41
42
  * and a thick stroke beneath a second copy is how a halo is drawn there. Both
42
- * carry the size and family explicitly, because a `<text>` with neither takes
43
- * SVG's 16px default in a saved file.
43
+ * carry the size, because a `<text>` without one takes SVG's 16px default in a
44
+ * saved file. An export leaves `fontFamily` out, so the label inherits the
45
+ * family the export dialog put on the root.
44
46
  */
45
47
  export function SvgHaloText({ x, y, fill, halo, haloWidth, fontSize, fontFamily, anchor = 'start', children, }) {
46
48
  const attrs = { x, y, fontSize, fontFamily, textAnchor: anchor };
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The one-line `[min, max]` caption that stands in for a y axis where none can
3
3
  * be drawn — a scale whose bands are too short for tick labels, and a density
4
- * track whose rows each carry their own colour, so no single ramp describes
5
- * them. An axis stand-in rather than a key, which is why it is not a colour
4
+ * track whose rows each carry their own color, so no single ramp describes
5
+ * them. An axis stand-in rather than a key, which is why it is not a color
6
6
  * scale and draws whether or not the legend does. Right-aligned to
7
7
  * `canvasWidth` at the top of the display, led by the scale's `caption` where
8
8
  * it has one, which has no gutter to sit in here.
@@ -7,12 +7,13 @@ import { SCORE_CAPTION_HEIGHT } from './yAxisConstants.js';
7
7
  /**
8
8
  * The one-line `[min, max]` caption that stands in for a y axis where none can
9
9
  * be drawn — a scale whose bands are too short for tick labels, and a density
10
- * track whose rows each carry their own colour, so no single ramp describes
11
- * them. An axis stand-in rather than a key, which is why it is not a colour
10
+ * track whose rows each carry their own color, so no single ramp describes
11
+ * them. An axis stand-in rather than a key, which is why it is not a color
12
12
  * scale and draws whether or not the legend does. Right-aligned to
13
13
  * `canvasWidth` at the top of the display, led by the scale's `caption` where
14
14
  * it has one, which has no gutter to sit in here.
15
15
  */
16
+ // eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
16
17
  export default function ScoreDomainCaption({ domain, scaleType, canvasWidth, caption, }) {
17
18
  const palette = usePalette();
18
19
  const suffix = scaleType === 'log' ? ' (log)' : scaleType === 'symlog' ? ' (symlog)' : '';
@@ -13,9 +13,10 @@ export declare function ScoreRuleLines({ marks, width, offsetY, }: {
13
13
  width: number;
14
14
  offsetY?: number;
15
15
  }): import("react").JSX.Element;
16
- export default function ScoreRules({ marks, width, height, bandTops, }: {
16
+ declare const ScoreRules: ({ marks, width, height, bandTops, }: {
17
17
  marks: ScoreRuleMark[];
18
18
  width: number;
19
19
  height: number;
20
20
  bandTops: number[];
21
- }): import("react").JSX.Element;
21
+ }) => import("react").JSX.Element;
22
+ export default ScoreRules;
package/esm/ScoreRules.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { usePalette } from '@jbrowse/core/ui/PaletteContext';
3
+ import { observer } from 'mobx-react';
3
4
  import { DEFAULT_RULE_COLOR } from './yAxisConstants.js';
4
5
  const LABEL_FONT_SIZE = 10;
5
6
  const LABEL_GAP = 2;
@@ -12,6 +13,7 @@ function labelY(y, offsetY) {
12
13
  }
13
14
  // Bare marks, no wrapping <svg>, so the on-screen overlay and the SVG export
14
15
  // draw the same elements from the same y. Same split as CrossHatchLines.
16
+ // eslint-disable-next-line no-restricted-syntax -- drawn inside a frozen SVG figure
15
17
  export function ScoreRuleLines({ marks, width, offsetY = 0, }) {
16
18
  // A caption sits over the plot, not beside it, so it needs the halo the tick
17
19
  // labels next to it already draw (YScaleBar) — without one a rule crossing
@@ -34,7 +36,7 @@ export function ScoreRuleLines({ marks, width, offsetY = 0, }) {
34
36
  }
35
37
  // Once per band the scale rules, like CrossHatches; pointer-events disabled so
36
38
  // the canvas underneath still gets mouse events.
37
- export default function ScoreRules({ marks, width, height, bandTops, }) {
39
+ const ScoreRules = observer(function ScoreRules({ marks, width, height, bandTops, }) {
38
40
  return (_jsx("svg", { style: {
39
41
  position: 'absolute',
40
42
  top: 0,
@@ -43,4 +45,5 @@ export default function ScoreRules({ marks, width, height, bandTops, }) {
43
45
  height,
44
46
  width,
45
47
  }, children: bandTops.map(top => (_jsx(ScoreRuleLines, { marks: marks, width: width, offsetY: top }, top))) }));
46
- }
48
+ });
49
+ export default ScoreRules;