@jbrowse/display-ui 4.3.0

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 (41) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +433 -0
  3. package/esm/DisplayUIProvider.d.ts +70 -0
  4. package/esm/DisplayUIProvider.js +96 -0
  5. package/esm/FloatingLegend.d.ts +16 -0
  6. package/esm/FloatingLegend.js +213 -0
  7. package/esm/PointerLayer.d.ts +26 -0
  8. package/esm/PointerLayer.js +27 -0
  9. package/esm/bottomRightCorner.d.ts +58 -0
  10. package/esm/bottomRightCorner.js +59 -0
  11. package/esm/chromeOverlayContext.d.ts +7 -0
  12. package/esm/chromeOverlayContext.js +44 -0
  13. package/esm/chromeOverlays.d.ts +88 -0
  14. package/esm/chromeOverlays.js +1 -0
  15. package/esm/index.d.ts +22 -0
  16. package/esm/index.js +51 -0
  17. package/esm/isLiveModel.d.ts +21 -0
  18. package/esm/isLiveModel.js +24 -0
  19. package/esm/plainChromeOverlays.d.ts +18 -0
  20. package/esm/plainChromeOverlays.js +189 -0
  21. package/esm/tooLargeBannerText.d.ts +18 -0
  22. package/esm/tooLargeBannerText.js +34 -0
  23. package/esm/tooltip/Tooltip.d.ts +52 -0
  24. package/esm/tooltip/Tooltip.js +67 -0
  25. package/esm/tooltip/useTooltip.d.ts +50 -0
  26. package/esm/tooltip/useTooltip.js +116 -0
  27. package/esm/trackControl/plainTrackControl.d.ts +17 -0
  28. package/esm/trackControl/plainTrackControl.js +133 -0
  29. package/esm/trackControl/trackControlContext.d.ts +7 -0
  30. package/esm/trackControl/trackControlContext.js +30 -0
  31. package/esm/trackControl/types.d.ts +58 -0
  32. package/esm/trackControl/types.js +1 -0
  33. package/esm/trackControl/useTrackControlMenu.d.ts +51 -0
  34. package/esm/trackControl/useTrackControlMenu.js +163 -0
  35. package/esm/trackOverlay/TrackOverlayContext.d.ts +1 -0
  36. package/esm/trackOverlay/TrackOverlayContext.js +18 -0
  37. package/esm/trackOverlay/TrackOverlayPortal.d.ts +18 -0
  38. package/esm/trackOverlay/TrackOverlayPortal.js +66 -0
  39. package/esm/trackOverlay/TrackOverlaySlot.d.ts +54 -0
  40. package/esm/trackOverlay/TrackOverlaySlot.js +60 -0
  41. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [2020] [Evolutionary Software Foundation]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,433 @@
1
+ # @jbrowse/display-ui
2
+
3
+ The UI a display draws that is **not data** — loading scrims, error bars, the
4
+ too-large gate, the controls in a track's corner, and the overlay layer floating
5
+ chrome escapes into. The contract, and implementations of it that reach no UI
6
+ toolkit.
7
+
8
+ ```tsx
9
+ import { DisplayUIProvider } from '@jbrowse/display-ui'
10
+
11
+ ;<DisplayUIProvider>{tracks}</DisplayUIProvider>
12
+ ```
13
+
14
+ That is the whole common case: JBrowse's own stock displays render no Material
15
+ UI beneath it, with no `ThemeProvider` to mount and no emotion in your page.
16
+ Supply `overlays` (a partial set, merged over the plain one) or `trackControl`
17
+ to bring your own.
18
+
19
+ ## Why it is a package
20
+
21
+ **This package has no UI-toolkit dependency, and that is the feature.** The
22
+ contract used to live beside the Material implementations it exists to replace,
23
+ so importing the seam pulled 45 `@mui/*` modules in behind it — the whole
24
+ Material overlay set, and (through one barrel import) `FileSelector`,
25
+ `FatalErrorDialog` and `PluginManager`. Every check in the repo counted
26
+ _rendered_ elements and stayed green. Here, npm decides instead of a test: the
27
+ Material bindings live in `@jbrowse/plugin-linear-genome-view`, which depends on
28
+ this, never the other way round.
29
+
30
+ It also puts the contract somewhere `packages/*` can reach. `tree-sidebar`
31
+ depended on the LGV **plugin** for `TrackOverlayPortal` alone; the comparative
32
+ displays could not read the overlay contract at all, because it sat one layer
33
+ above them.
34
+
35
+ ## What is here
36
+
37
+ | | |
38
+ | ------------------------------------------- | --------------------------------------------------------------------------------------- |
39
+ | `DisplayChromeOverlays` | the five `displayPhase` states, as a 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 |
50
+
51
+ ## What is _not_ here, and cannot be
52
+
53
+ Redirecting what a stock display **renders** is not the same as keeping a
54
+ toolkit out of its **bundle**. `DisplayChrome` and `TrackControl` live in the
55
+ LGV plugin and import Material UI; a provider only stops them rendering it.
56
+ Dropping the weight means writing your own display component over
57
+ `DisplayChromeBase`, which takes `overlays` as a prop.
58
+
59
+ See `agent-docs/reference/DISPLAYCHROME.md` for the seams in full, and
60
+ `products/jbrowse-build-your-own` for a site built on them.
61
+
62
+ <!-- API_DOCS_START -->
63
+
64
+ ## API
65
+
66
+ Auto-generated from `#api` JSDoc tags in this package. Do not edit by hand.
67
+
68
+ ### BottomRightCornerContext
69
+
70
+ The one box per display that owns the bottom-right corner.
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). That is the _reason_ to make it structural rather than to leave
93
+ it — nothing on either side is aware of the constraint, so the first display to
94
+ want both would find the bug, and it presents as a status message that silently
95
+ never appears.
96
+
97
+ `BottomRightIndicators` already described itself as "the single anchor point for
98
+ every bottom-right overlay ... so they lay out as one row instead of each
99
+ picking their own position and colliding". This makes that true of the chip too:
100
+ the chrome renders the anchor, puts its chip in it, and publishes the node here
101
+ so the display's row — rendered several components away, inside the chrome's
102
+ body — lands in the same flex box instead of over it.
103
+
104
+ `null` outside a chrome (a display an embedder mounts standalone, a unit test,
105
+ the SVG export), where `BottomRightIndicators` keeps its own anchored box. That
106
+ fallback is why this can be added without every consumer changing.
107
+
108
+ ```js
109
+ // type signature
110
+ Context<HTMLElement | null>
111
+ ```
112
+
113
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/bottomRightCorner.ts)
114
+
115
+ ### DisplayUIProvider
116
+
117
+ Both bring-your-own seams at once: what a display draws that is not data.
118
+
119
+ There are two contexts underneath because two different things render them — the
120
+ chrome around a display draws the status states, the display itself draws its
121
+ bottom-right controls — and that split is real at the implementation level,
122
+ since `DisplayChromeBase` takes its overlay set as a _prop_ and never renders a
123
+ track control. It is not real for an embedder: nobody wants stock Material
124
+ loading scrims with plain corner controls, or the reverse. Every consumer in
125
+ this repo mounts the two together.
126
+
127
+ ```tsx
128
+ <DisplayUIProvider>{tracks}</DisplayUIProvider>
129
+ ```
130
+
131
+ Both props default to the plain, toolkit-free sets, so the common case — "I do
132
+ not want Material UI in my app" — needs no arguments and no second import.
133
+
134
+ **`overlays` is a partial set**, merged over the plain one, so replacing a
135
+ single state is one entry rather than five:
136
+
137
+ ```tsx
138
+ <DisplayUIProvider overlays={{ ErrorBar: MyErrorBar }}>
139
+ ```
140
+
141
+ Partial rather than whole for two reasons. A host writing four of the five
142
+ states by hand only ever wanted one of them, and every example of this had
143
+ spread `plainChromeOverlays` in to say so. And a _sixth_ state is a thing
144
+ JBrowse can add: with a whole set the host's object goes stale on upgrade — a
145
+ compile error if they typecheck, a missing component if they ship JS — while a
146
+ partial one keeps working and picks up the new plain default.
147
+
148
+ Declare that object at module scope if you can. The merge is stable per object
149
+ (`resolveOverlays`), so a constant costs one merge for the life of the app; a
150
+ literal written inline in JSX is a new object every render, and this value goes
151
+ into a context, so every display beneath re-renders with it.
152
+
153
+ **The contexts themselves still default to `undefined`, and that stays true.** A
154
+ display rendering outside any provider — a unit test, the SVG export,
155
+ breakpoint-split-view's `overlayUtils` — keeps JBrowse's own Material look,
156
+ because a plain ambient default would degrade those invisibly. Defaulting _this
157
+ component's props_ is a different thing: mounting it is a deliberate act, and
158
+ the act means "not the Material default". Nothing gets a plain set without
159
+ someone having asked.
160
+
161
+ Colors are not a seam and are not here. A display reads `usePalette()` for its
162
+ own content colors, which is a palette of strings rather than a UI toolkit, so
163
+ it arrives through `SessionPaletteProvider` (`@jbrowse/core/ui/PaletteContext`)
164
+ whatever these are set to. A feature track needs it even with plain chrome.
165
+
166
+ This module reaches no `@mui/*` module, and `muiFree.test.ts` keeps it that way
167
+ — asking for less Material UI must not download more of it. What it cannot do is
168
+ unship the Material components a _stock display_ imports: `DisplayChrome` and
169
+ `TrackControl` are in that display's chunk either way, and merely stop
170
+ rendering. Keeping them out of the graph means writing your own display
171
+ component over `DisplayChromeBase`, which takes `overlays` as a prop and imports
172
+ no toolkit. See
173
+ [DISPLAYCHROME.md](https://github.com/GMOD/jbrowse-components/blob/main/agent-docs/reference/DISPLAYCHROME.md).
174
+
175
+ ```js
176
+ // type signature
177
+ ({ overlays, trackControl, children, }: { overlays?: Partial<…> | undefined; trackControl?: TrackControlComponent | undefined; children: ReactNode; }) => Element
178
+ ```
179
+
180
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/DisplayUIProvider.tsx)
181
+
182
+ ### isLiveModel
183
+
184
+ Whether an overlay's model can still be called into.
185
+
186
+ The terminal states unmount the canvas, so a click landing after the track was
187
+ closed would otherwise run an action on a destroyed node — which is why both
188
+ overlay sets guard their one button with `isAlive`.
189
+
190
+ **`isAlive` alone is wrong here, and it throws rather than answering.** The four
191
+ model shapes in `chromeOverlays.ts` are structural on purpose ("A display
192
+ satisfies one by having the fields; no mixin has to be composed"), so a host
193
+ writing their own display over `DisplayChromeBase` may hand these components a
194
+ plain object. `isAlive` runs `assertIsStateTreeNode` and throws on one, inside
195
+ an event handler, where React logs it and moves on — leaving the Force load
196
+ button looking live and doing nothing, which is the exact state
197
+ `DisplayChromeOverlays.TooLarge` documents itself as existing to prevent.
198
+
199
+ A plain object is never destroyed, so it is always callable. The liveness
200
+ question only exists for an MST node.
201
+
202
+ ```js
203
+ // type signature
204
+ (model: unknown) => boolean
205
+ ```
206
+
207
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/isLiveModel.ts)
208
+
209
+ ### plainChromeOverlays
210
+
211
+ The five `displayPhase` states drawn with no UI toolkit: no theme provider to
212
+ mount, no emotion in the host page, and nothing that reads as a stray Material
213
+ widget inside someone else's design system.
214
+
215
+ `DisplayUIProvider` installs this by default, so mount that rather than naming
216
+ this — reach for it directly only to wrap a state or to build a context value by
217
+ hand. Colours come from `currentColor` and the CSS system colours, so the host's
218
+ own cascade drives them in both light and dark.
219
+
220
+ The `data-testid` values it renders are a contract four of JBrowse's test
221
+ systems key on, so a replacement set that keeps them can be driven by those
222
+ suites too.
223
+
224
+ ```js
225
+ // type signature
226
+ DisplayChromeOverlays
227
+ ```
228
+
229
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/plainChromeOverlays.tsx)
230
+
231
+ ### PlainTrackControl
232
+
233
+ A display's ambient bottom-right control — track sizing, the isoform notice, the
234
+ show-only badge — drawn with no UI toolkit, the corner-control counterpart of
235
+ `plainChromeOverlays`.
236
+
237
+ `DisplayUIProvider` installs this by default. The behaviour is not in here:
238
+ dismissal, the keyboard, focus, the top layer and the anchoring are
239
+ `useTrackControlMenu`, so writing your own control means writing markup rather
240
+ than re-deriving why the menu opens upward.
241
+
242
+ The package exports it as `plainTrackControl`, lower-cased to match
243
+ `plainChromeOverlays` — the two are a pair, and both are things you hand to a
244
+ provider rather than render yourself.
245
+
246
+ ```js
247
+ // type signature
248
+ ({ icon, tooltip, label, options, onClick, onMenuClose, onDelete, warning, }: TrackControlProps) => Element
249
+ ```
250
+
251
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/trackControl/plainTrackControl.tsx)
252
+
253
+ ### tooLargeBannerText
254
+
255
+ Which axis tripped (empty when the display gates without a reason), then the way
256
+ out.
257
+
258
+ `zoomCanRelease` decides whether "zoom in" is offered, and it has to be asked
259
+ because the advice is not always true. It was, once: the `AUTO_FORCE_LOAD_BP`
260
+ floor turned the byte gate off below 20kb, so zooming far enough always worked.
261
+ The byte gate no longer stops at any floor, and an index quotes whole blocks —
262
+ so for a file whose blocks are large the same bytes come down however far the
263
+ user goes, and telling them to keep zooming into a fetch whose cost cannot fall
264
+ is the one thing the banner must not do. `zoomCanReleaseGate` answers it from
265
+ two consecutive measurements rather than from a threshold; see
266
+ `ByteEstimate.zoomIneffective`.
267
+
268
+ ```js
269
+ // type signature
270
+ (regionTooLargeReason: string, { zoomCanRelease }?: { zoomCanRelease?: boolean | undefined; }) => string
271
+ ```
272
+
273
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/tooLargeBannerText.ts)
274
+
275
+ ### Tooltip
276
+
277
+ A hover/focus label for a control, drawn rather than delegated to the browser's
278
+ `title` attribute — positioned so it clears the display's `contain: strict` box
279
+ and the window edge, dismissed by Escape, and drawn like every other JBrowse
280
+ tooltip instead of like whatever the host OS renders.
281
+
282
+ `title` is what this chrome used to use, and it was the wrong tool three ways:
283
+ it can be neither styled nor positioned, it waits about a second and then
284
+ disappears on a timer of its own, and on a control that already carries an
285
+ `aria-label` some screen readers announce both strings. This reaches no UI
286
+ toolkit, so the package's no-Material-UI guarantee holds.
287
+
288
+ Takes a single element child and clones it rather than wrapping it: the controls
289
+ that want a tooltip are absolutely positioned inside a legend or sit in a flex
290
+ row, where an extra `<span>` moves them. The child keeps its own handlers —
291
+ these compose on top of them. This is the same trigger pattern MUI's own
292
+ `Tooltip` uses, which is what the rest of JBrowse's chrome is built on; the
293
+ toolkit is what differs here, not the shape.
294
+
295
+ ```tsx
296
+ <Tooltip title="Hide legend">
297
+ <button type="button" aria-label="Hide legend" onClick={onDismiss}>
298
+ ×
299
+ </button>
300
+ </Tooltip>
301
+ ```
302
+
303
+ **The child still needs its own accessible name**, because this sets
304
+ `aria-describedby` and never `aria-label` — see useTooltip, which is this
305
+ without the cloning, for a host writing its own markup.
306
+
307
+ ```js
308
+ // type signature
309
+ ({ title, placement, children, }: { title: ReactNode; placement?: TooltipPlacement | undefined; children: ReactElement<…>; }) => Element
310
+ ```
311
+
312
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/tooltip/Tooltip.tsx)
313
+
314
+ ### TrackOverlayPortal
315
+
316
+ Lift floating track chrome out of the display's `contain: strict` sandbox and
317
+ into the host's overlay node, so the LGV's inter-region masks cannot bury it at
318
+ multi-region scale. `TrackOverlaySlot` is the other end.
319
+
320
+ The overlay node takes no pointer events, so anything of yours the user hovers
321
+ or clicks sets `pointer-events: auto` on its own positioned box.
322
+
323
+ With no slot above it this renders the children in place (`fallbackInline`, the
324
+ default), which preserves chrome that is still meaningful unescaped. Pass
325
+ `fallbackInline={false}` for chrome that only makes sense above the masks and
326
+ draws itself some other way elsewhere.
327
+
328
+ ```js
329
+ // type signature
330
+ ({ children, fallbackInline, }: { children: ReactNode; fallbackInline?: boolean | undefined; }) => ReactNode
331
+ ```
332
+
333
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/trackOverlay/TrackOverlayPortal.tsx)
334
+
335
+ ### TrackOverlaySlot
336
+
337
+ The box a display is mounted in, plus the overlay node its floating chrome
338
+ escapes into. Pair to `TrackOverlayPortal`, which is the other end.
339
+
340
+ A display's React tree is sealed in a `contain: strict` sandbox — that is what
341
+ isolates its paint, and dropping it is measured and rejected (ADR-058). A
342
+ stacking context comes with the isolation, so floating chrome a display draws (a
343
+ colour key, hi-c's overlay panel, maf's row labels) cannot out-z-index anything
344
+ painted over the track stack from outside. The escape is a node mounted _beside_
345
+ the sandbox rather than inside it, published through `TrackOverlayContext`; this
346
+ component is that node, its context and the paint order between them, in the one
347
+ place they have to agree.
348
+
349
+ `TrackContainer` uses it, so JBrowse's own layout and an embedder's go through
350
+ the same code rather than two copies of one rule. **An embedder mounting
351
+ `RenderingComponent` directly needs it too**, and that is the case it was added
352
+ for: with no provider the context is null, the portal falls back to rendering
353
+ inline, and a host that paints region seams over its column buries the chrome
354
+ under them with nothing to say so.
355
+
356
+ ```tsx
357
+ <TrackOverlaySlot zIndex={3} style={{ height: display.height }}>
358
+ <div style={{ position: 'absolute', inset: 0, contain: 'strict' }}>
359
+ <RenderingComponent model={display} />
360
+ </div>
361
+ </TrackOverlaySlot>
362
+ ```
363
+
364
+ **`zIndex` is required, and deliberately has no default.** It is the answer to
365
+ "above what?", and that is a fact about the caller's layout rather than about
366
+ this component: JBrowse's own track container passes 100, which is positioned
367
+ above `PaddingBlocks` and below `TrackLabel` at 200, and means nothing to a host
368
+ whose masks sit at 2. A default would be a number that is right in one layout
369
+ and silently wrong in every other, and the failure — chrome painted under a mask
370
+ — is invisible until someone looks at the right zoom.
371
+
372
+ The node takes no pointer events, so it does not eat the canvas's. Chrome that
373
+ wants them takes them back on its own positioned box; it also carries
374
+ `data-gesture-owner`, so anything that does is already exempt from the LGV's
375
+ click-drag pan.
376
+
377
+ ```js
378
+ // type signature
379
+ ({ children, zIndex, style, overlayStyle, }: { children: ReactNode; zIndex: number; style?: CSSProperties | undefined; overlayStyle?: CSSProperties | undefined; }) => Element
380
+ ```
381
+
382
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/trackOverlay/TrackOverlaySlot.tsx)
383
+
384
+ ### useTooltip
385
+
386
+ A hover/focus label for one control, as props to spread — the headless half of
387
+ Tooltip, for a host writing its own chrome rather than restyling ours. Same
388
+ relationship `useTrackControlMenu` has to `plainTrackControl`.
389
+
390
+ ```tsx
391
+ const { triggerProps, tooltip } = useTooltip('Hide legend')
392
+ return (
393
+ <>
394
+ <button {...triggerProps} aria-label="Hide legend" onClick={onDismiss}>
395
+ ×
396
+ </button>
397
+ {tooltip}
398
+ </>
399
+ )
400
+ ```
401
+
402
+ `triggerProps` carries no `onClick`, so a control's own handler does not collide
403
+ with it. Any other handler on this list has to compose rather than replace —
404
+ spread first, then call `triggerProps.onFocus` from yours.
405
+
406
+ ```js
407
+ // type signature
408
+ (title: ReactNode, { placement }?: { placement?: TooltipPlacement | undefined; }) => TooltipTrigger
409
+ ```
410
+
411
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/tooltip/useTooltip.tsx)
412
+
413
+ ### useTrackControlMenu
414
+
415
+ The behaviour behind a bottom-right track control's menu, as prop getters to
416
+ spread — dismissal (Escape, an outside press, an ancestor scrolling), the
417
+ keyboard (arrows, Home/End), focus, and the anchoring that clears both the
418
+ display's `contain: strict` box and the window edge.
419
+
420
+ For writing your own control rather than restyling `plainTrackControl`: each of
421
+ those rules is a bug when missed and none of them shows up in a screenshot.
422
+ Render `menuProps` only while `open`, and portal it to `document.body` —
423
+ `createPortal` is the caller's to aim, the maths is here. `menuProps.style`
424
+ carries position only.
425
+
426
+ ```js
427
+ // type signature
428
+ (onClose?: (() => void) | undefined) => TrackControlMenu
429
+ ```
430
+
431
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/display-ui/src/trackControl/useTrackControlMenu.tsx)
432
+
433
+ <!-- API_DOCS_END -->