@jbrowse/core 5.0.0-beta.1 → 5.0.0-beta.3

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 (199) hide show
  1. package/README.md +112 -43
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -3
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +4 -3
  6. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
  7. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +2 -2
  8. package/esm/BaseFeatureWidget/index.d.ts +1 -1
  9. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
  10. package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
  11. package/esm/BaseFeatureWidget/types.d.ts +10 -2
  12. package/esm/PluginLoader.d.ts +1 -0
  13. package/esm/PluginLoader.js +52 -8
  14. package/esm/PluginManager.d.ts +99 -17
  15. package/esm/PluginManager.js +194 -26
  16. package/esm/ReExports/BaseFeatureDetails.js +1 -1
  17. package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
  18. package/esm/ReExports/MuiDataGridReExports.js +2 -2
  19. package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
  20. package/esm/ReExports/barrelOnlyNames.js +63 -0
  21. package/esm/ReExports/modules.js +31 -109
  22. package/esm/ReExports/publicTracks.d.ts +1 -0
  23. package/esm/ReExports/publicTracks.js +14 -0
  24. package/esm/ReExports/publicUi.d.ts +4 -0
  25. package/esm/ReExports/publicUi.js +33 -0
  26. package/esm/ReExports/publicUtil.d.ts +1 -1
  27. package/esm/ReExports/publicUtil.js +8 -4
  28. package/esm/ReExports/sharedModules.d.ts +96 -0
  29. package/esm/ReExports/sharedModules.js +66 -0
  30. package/esm/ReExports/uiStub.d.ts +2 -0
  31. package/esm/ReExports/uiStub.js +11 -0
  32. package/esm/ReExports/workerModules.d.ts +2 -0
  33. package/esm/ReExports/workerModules.js +15 -0
  34. package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
  35. package/esm/ReExports/workerNamespaceNames.js +281 -0
  36. package/esm/configuration/configurationSchema.d.ts +5 -38
  37. package/esm/configuration/configurationSchema.js +64 -40
  38. package/esm/configuration/index.d.ts +2 -2
  39. package/esm/configuration/index.js +1 -1
  40. package/esm/configuration/promotableDefaults.d.ts +54 -19
  41. package/esm/configuration/promotableDefaults.js +117 -48
  42. package/esm/configuration/promotablePin.d.ts +50 -40
  43. package/esm/configuration/promotableResolve.d.ts +1 -1
  44. package/esm/configuration/promotableResolve.js +1 -1
  45. package/esm/configuration/tabixIndexFields.d.ts +2 -2
  46. package/esm/configuration/tabixIndexFields.js +2 -2
  47. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +12 -0
  48. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +35 -4
  49. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +41 -0
  50. package/esm/data_adapters/BaseAdapter/featureDensity.js +32 -0
  51. package/esm/data_adapters/BaseAdapter/index.d.ts +2 -1
  52. package/esm/data_adapters/BaseAdapter/index.js +1 -0
  53. package/esm/data_adapters/BaseAdapter/stats.d.ts +33 -1
  54. package/esm/data_adapters/BaseAdapter/stats.js +52 -13
  55. package/esm/data_adapters/BaseAdapter/types.d.ts +3 -8
  56. package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
  57. package/esm/pluggableElementTypes/AdapterType.js +1 -1
  58. package/esm/pluggableElementTypes/DisplayType.d.ts +4 -12
  59. package/esm/pluggableElementTypes/DisplayType.js +3 -10
  60. package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
  61. package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
  62. package/esm/pluggableElementTypes/ViewType.d.ts +20 -4
  63. package/esm/pluggableElementTypes/ViewType.js +32 -4
  64. package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
  65. package/esm/pluggableElementTypes/extendElementType.js +9 -5
  66. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +44 -3
  67. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +75 -2
  68. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +21 -0
  69. package/esm/pluggableElementTypes/models/BaseTrackModel.js +34 -2
  70. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +49 -0
  71. package/esm/pluggableElementTypes/models/BaseViewModel.js +28 -0
  72. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +14 -10
  73. package/esm/pluggableElementTypes/models/assertDisplayContract.js +25 -32
  74. package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
  75. package/esm/rpc/RpcRegistry.d.ts +10 -0
  76. package/esm/rpc/byteBudget.d.ts +9 -0
  77. package/esm/rpc/coreRpcMethods.d.ts +1 -0
  78. package/esm/rpc/coreRpcMethods.js +1 -0
  79. package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +11 -0
  80. package/esm/rpc/methods/CoreGetFeatureDensity.js +22 -0
  81. package/esm/svg/svgReady.d.ts +1 -0
  82. package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
  83. package/esm/ui/CascadingMenu.js +30 -8
  84. package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
  85. package/esm/ui/ExportSvgDialog.d.ts +1 -1
  86. package/esm/ui/LoadingOverlay.d.ts +14 -0
  87. package/esm/ui/LoadingOverlay.js +1 -1
  88. package/esm/ui/MenuTypes.d.ts +14 -5
  89. package/esm/ui/MenuTypes.js +3 -0
  90. package/esm/ui/PaletteContext.d.ts +11 -4
  91. package/esm/ui/PaletteContext.js +34 -5
  92. package/esm/ui/PinAdornment.js +31 -43
  93. package/esm/ui/ScrollChrome.d.ts +16 -0
  94. package/esm/ui/ScrollChrome.js +12 -0
  95. package/esm/ui/ScrollZoomToggle.d.ts +4 -3
  96. package/esm/ui/ScrollZoomToggle.js +4 -3
  97. package/esm/ui/SizeSliderRow.js +1 -1
  98. package/esm/ui/index.d.ts +3 -3
  99. package/esm/ui/index.js +4 -4
  100. package/esm/ui/launchViewMenu.js +7 -1
  101. package/esm/ui/legendMenuItem.d.ts +10 -16
  102. package/esm/ui/legendMenuItem.js +9 -20
  103. package/esm/ui/makeSizeMenu.js +1 -1
  104. package/esm/ui/menuItemAdornment.d.ts +2 -3
  105. package/esm/ui/menuItemAdornment.js +2 -3
  106. package/esm/ui/menuItems.d.ts +2 -3
  107. package/esm/ui/menuItems.js +1 -2
  108. package/esm/ui/palette.d.ts +11 -11
  109. package/esm/ui/palette.js +11 -11
  110. package/esm/ui/promotablePinCoverage.d.ts +16 -2
  111. package/esm/ui/promotablePinCoverage.js +40 -3
  112. package/esm/ui/theme.js +5 -0
  113. package/esm/ui/toggleMenuItems.d.ts +14 -9
  114. package/esm/ui/toggleMenuItems.js +32 -15
  115. package/esm/util/Base1DUtils.d.ts +4 -2
  116. package/esm/util/Base1DUtils.js +12 -4
  117. package/esm/util/SvgCanvas.js +4 -3
  118. package/esm/util/adapterConfigKey.d.ts +12 -0
  119. package/esm/util/adapterConfigKey.js +14 -0
  120. package/esm/util/adapterMetadata.js +2 -1
  121. package/esm/util/addAndShowTrack.d.ts +1 -1
  122. package/esm/util/addAndShowTrack.js +5 -1
  123. package/esm/util/addTrackFromWidget.js +2 -2
  124. package/esm/util/analytics.js +4 -5
  125. package/esm/util/cacheBudgets.d.ts +22 -19
  126. package/esm/util/cacheBudgets.js +22 -19
  127. package/esm/util/clampToContig.d.ts +17 -0
  128. package/esm/util/clampToContig.js +19 -0
  129. package/esm/util/colorBits.d.ts +2 -1
  130. package/esm/util/colorBits.js +2 -5
  131. package/esm/util/createStopTokenRotation.d.ts +9 -7
  132. package/esm/util/createStopTokenRotation.js +7 -27
  133. package/esm/util/featureTypes.d.ts +24 -0
  134. package/esm/util/featureTypes.js +35 -0
  135. package/esm/util/fetchContext.d.ts +2 -2
  136. package/esm/util/fetchContext.js +2 -2
  137. package/esm/util/fetchPhases.d.ts +10 -10
  138. package/esm/util/hooks.d.ts +8 -0
  139. package/esm/util/hooks.js +27 -0
  140. package/esm/util/index.d.ts +6 -5
  141. package/esm/util/index.js +5 -4
  142. package/esm/util/installFetch.d.ts +71 -34
  143. package/esm/util/installFetch.js +57 -29
  144. package/esm/util/installInitAutorun.d.ts +14 -13
  145. package/esm/util/installInitAutorun.js +17 -17
  146. package/esm/util/installPrerequisiteFetch.d.ts +86 -0
  147. package/esm/util/installPrerequisiteFetch.js +73 -0
  148. package/esm/util/lazyAfterAttach.d.ts +13 -0
  149. package/esm/util/lazyAfterAttach.js +31 -0
  150. package/esm/util/legendCandidates.d.ts +50 -0
  151. package/esm/util/legendCandidates.js +87 -0
  152. package/esm/util/mstUtils.d.ts +12 -1
  153. package/esm/util/mstUtils.js +20 -2
  154. package/esm/util/openFeatureWidget.d.ts +5 -0
  155. package/esm/util/openFeatureWidget.js +1 -0
  156. package/esm/util/openViews.d.ts +16 -0
  157. package/esm/util/openViews.js +22 -0
  158. package/esm/util/parentWalk.d.ts +1 -1
  159. package/esm/util/parentWalk.js +1 -1
  160. package/esm/util/pluginStore.d.ts +1 -0
  161. package/esm/util/pluginStore.js +8 -1
  162. package/esm/util/range.d.ts +13 -9
  163. package/esm/util/range.js +17 -8
  164. package/esm/util/renderToStaticMarkup.js +10 -0
  165. package/esm/util/rxjs.d.ts +16 -0
  166. package/esm/util/rxjs.js +49 -0
  167. package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
  168. package/esm/util/scheduleDetachedDestroy.js +24 -0
  169. package/esm/util/scrollLatch.d.ts +1 -0
  170. package/esm/util/scrollLatch.js +8 -0
  171. package/esm/util/stopToken.d.ts +6 -5
  172. package/esm/util/tabix.d.ts +10 -4
  173. package/esm/util/tabix.js +11 -5
  174. package/esm/util/trackConfigDelta.d.ts +6 -6
  175. package/esm/util/trackConfigDelta.js +3 -3
  176. package/esm/util/tracks.d.ts +48 -0
  177. package/esm/util/tracks.js +192 -66
  178. package/esm/util/types/index.d.ts +58 -10
  179. package/esm/util/types/index.js +3 -0
  180. package/esm/util/unknownSnapshotKeys.d.ts +36 -0
  181. package/esm/util/unknownSnapshotKeys.js +69 -0
  182. package/esm/util/usePanelVirtualScroll.d.ts +6 -2
  183. package/esm/util/usePanelVirtualScroll.js +6 -2
  184. package/esm/util/useRowVirtualScroll.d.ts +1 -1
  185. package/esm/util/useRowVirtualScroll.js +1 -1
  186. package/esm/util/useVirtualScrollWheel.js +11 -1
  187. package/esm/util/viewStatus.d.ts +23 -0
  188. package/esm/util/viewStatus.js +17 -0
  189. package/esm/util/wheelZoom.d.ts +3 -1
  190. package/esm/util/wheelZoom.js +39 -14
  191. package/esm/util/whenViewSettled.d.ts +17 -4
  192. package/esm/util/whenViewSettled.js +19 -6
  193. package/esm/util/withLaunchInput.d.ts +168 -0
  194. package/esm/util/withLaunchInput.js +273 -0
  195. package/package.json +19 -11
  196. package/esm/ui/promotableMenuItems.d.ts +0 -19
  197. package/esm/ui/promotableMenuItems.js +0 -89
  198. package/esm/util/applyInitSettings.d.ts +0 -79
  199. package/esm/util/applyInitSettings.js +0 -91
package/README.md CHANGED
@@ -149,12 +149,11 @@ default" action, which passes the slots it actually listed
149
149
 
150
150
  **`slots` is required, and an all-slots default is not the convenience it looks
151
151
  like.** It reaches further than any list a dialog can have shown: a promoted
152
- default the track _customized_ over, or one promoted to a value equal to
153
- `promotedBase`, is `inherited: false` and so appears in no row, yet still
154
- governs sibling tracks — so clearing it from a dialog that never showed it moves
155
- tracks other than the one whose badge was clicked. Clearing every promoted
156
- default at once is a preferences-scope action, and Preferences → "Reset to
157
- defaults" is where it lives (`clearPreferenceOverrides`).
152
+ default the track _customized_ over is `inherited: false` and so appears in no
153
+ row, yet still governs sibling tracks — so clearing it from a dialog that never
154
+ showed it moves tracks other than the one whose badge was clicked. Clearing
155
+ every promoted default at once is a preferences-scope action, and Preferences →
156
+ "Reset to defaults" is where it lives (`clearPreferenceOverrides`).
158
157
 
159
158
  ```js
160
159
  // type signature
@@ -402,8 +401,11 @@ not be the thing that discovers this. Callers fall back to treating it as the
402
401
  plain object it is.
403
402
 
404
403
  Shares `TrackConfigurationReference`'s per-PluginManager cache, so hydrating the
405
- same entry twice returns the same node and a track that gets opened later reuses
406
- it.
404
+ same entry twice returns the same node — and in admin/embedded sessions a track
405
+ opened later resolves to that same node. A non-admin's open track does not: it
406
+ resolves to the session's private working copy (ADR-032) and this is the
407
+ pristine mirror beside it. The two agree in content, which is what the caller
408
+ needs; `CopyConfigEntryPoints.test.ts` pins both halves.
407
409
 
408
410
  ```js
409
411
  // type signature
@@ -420,10 +422,10 @@ default" predicate for a promotable slot: comparing the resolved value to the
420
422
  base instead reads as at-default for a track merely _following_ a non-base
421
423
  promoted default, so the reset control lights up on a no-op.
422
424
 
423
- `SLOT` is constrained the way `getConf`'s is. A pin or a reset over a slot name
424
- the schema does not declare is inert and silent — `resolveSlot` answers about
425
- nothing, so the control draws outline forever — and a widened `self` switches
426
- the check off (`HostChecksSlotNames`).
425
+ `SLOT` is constrained the way `getConf`'s is, and a widened `self` switches the
426
+ check off (`HostChecksSlotNames`). A slot name the schema does not declare
427
+ throws at the first read (`getSlotDefinition`), and a declared but
428
+ non-promotable one throws in `resolveSlotIn`.
427
429
 
428
430
  ```js
429
431
  // type signature
@@ -432,22 +434,36 @@ the check off (`HostChecksSlotNames`).
432
434
 
433
435
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
434
436
 
437
+ ### launchOrReplaceView
438
+
439
+ `addOrReplaceView` for view types whose state model may be lazily loaded; the
440
+ synchronous `addOrReplaceView` requires it loaded already.
441
+
442
+ ```js
443
+ // type signature
444
+ (args: { session: AbstractViewContainer; typeName: string; initialState?: Record<string, unknown> | undefined; replacing?: AbstractViewModel | undefined; }) => Promise<...>
445
+ ```
446
+
447
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/util/mstUtils.ts)
448
+
435
449
  ### makePin
436
450
 
437
- The pin for one promotable slot: "apply this value to every open track of this
451
+ The pin on a radio or slider row: "apply this value to every open track of this
438
452
  display type", and — via the snackbar it raises — "keep it as the default for
439
453
  the ones opened later".
440
454
 
441
455
  `value` chooses between the subsystem's two meanings, which are otherwise
442
456
  identical:
443
457
 
444
- - **Give it** for a per-value pin — "make _arcs_ the default" — independent of
445
- what the track currently shows. Use on an always-visible pin so it can never
446
- promote a meaningless value, and so two rows sharing one slot (arcs `'arc'` vs
447
- read cloud `'cloud'`; sashimi `'down'` vs `'auto'`) stay independent.
458
+ - **Give it** for a per-value pin — "make _compact_ the default" — independent
459
+ of what the track currently shows. Use on an always-visible pin so it can
460
+ never promote a meaningless value, and so two rows sharing one slot (sashimi
461
+ `'down'` vs `'auto'`) stay independent.
448
462
  - **Omit it** for "whatever I'm showing", resolved through the cascade. Use for
449
- a symmetric or continuous setting where no fixed on-value makes sense (wiggle
450
- point size, arc line width, `mismatchAlpha`).
463
+ a continuous setting where no fixed on-value makes sense (wiggle point size,
464
+ arc line width).
465
+
466
+ A checkbox row takes neither: makeTogglePin.
451
467
 
452
468
  One function with an optional argument, rather than the two exported builders it
453
469
  replaces — a per-value one and a `…CurrentValue…` one, the second of which was
@@ -457,7 +473,32 @@ argument now says what the longer name said.
457
473
 
458
474
  ```js
459
475
  // type signature
460
- <CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<…>>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...value: [] | [...]) => Pin
476
+ <CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<…>>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...value: [] | [...]) => ValuePin
477
+ ```
478
+
479
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
480
+
481
+ ### makeTogglePin
482
+
483
+ The pin on a checkbox row: the row's own checkbox, acting on every open track of
484
+ the display type. `active` mirrors the row, so the pin draws filled exactly when
485
+ the box is ticked; a click flips the row's state on every open track and offers
486
+ the new state as the display type's default. It never clears a default the way
487
+ makePin's filled pin does — flipping back and taking the offer promotes the
488
+ other value, and promoting the base value clears the default
489
+ (`applyAndOfferDefault`).
490
+
491
+ Replaces a symmetric `makePin(self, slot)` on these rows, which carried the
492
+ row's current state: beside an unchecked box that applied _off_ everywhere and
493
+ visibly did nothing. It also replaces the per-value `makePin` a checkbox row
494
+ over a shared enum slot used to carry, which gave two checkbox rows in one
495
+ submenu two different pins: one filled when its value was promoted and clearing
496
+ on a second click, the other filled when the box was ticked and flipping. With
497
+ `states`, a checkbox row is always the toggle kind.
498
+
499
+ ```js
500
+ // type signature
501
+ <…>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...states: ConfigurationSlotValueResolved<...> extends boolean ? [] | [...] : [...]) => TogglePin
461
502
  ```
462
503
 
463
504
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
@@ -490,28 +531,12 @@ each display whether it has anything to promote.
490
531
  ### Pin
491
532
 
492
533
  The "apply this to every open track of this type" affordance on a menu row — the
493
- trailing `PushPin`, bundled so the row consumes it as one prop. Built by
494
- makePin.
495
-
496
- `active` = this value is currently the session default (a filled pin), which is
497
- the state, not the click. `toggle` **applies the value to every open track of
498
- the display type** and raises a snackbar whose one action promotes it to the
499
- display type's default; on an already-promoted value it clears that default
500
- instead, touching no track (see `applyPinClick`).
501
-
502
- **`toggle` rather than an `apply`/`clear` pair**, which was tried and dropped:
503
- the sole renderer is a MUI `ToggleButton` whose `onChange` means exactly "flip",
504
- so splitting it adds a member _and_ a branch at the one call site that never
505
- needed one. `active` is already public for a caller that wants to state a
506
- direction. (The house preference for explicit setters over toggles is about MST
507
- actions, where a toggle destroys the ability to set a known state; nothing here
508
- stores a value.)
509
-
510
- Lives here, alone and with no imports, rather than beside `makePin` in
511
- `promotableDefaults.ts`: the menu types describe a pin without building one, and
512
- `MenuTypes.ts` taking this one interface from that module gave a React-free type
513
- file a type closure of 374 files. See
514
- `agent-docs/ideas/barrels-block-extraction.md` and `scripts/moduleClosure.ts`.
534
+ trailing `PushPin`, bundled so the row consumes it as one prop.
535
+
536
+ `kind` is what the adornment words itself from and what the row builders check:
537
+ a checkbox row takes a TogglePin, a radio or slider row a ValuePin. The two used
538
+ to be told apart by `typeof onValue === 'boolean'`, which let a value pin over a
539
+ boolean slot compile and read as a toggle while clearing on its second click.
515
540
 
516
541
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
517
542
 
@@ -648,6 +673,24 @@ at the point where the connection is cut.
648
673
 
649
674
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
650
675
 
676
+ ### runLazyAfterAttach
677
+
678
+ Run a display's `afterAttach` body from a module loaded on demand, so the
679
+ autorun installers stay out of the display's eager bundle.
680
+
681
+ One policy for the gap the `await` opens: a node torn down before the module
682
+ lands installs nothing, and a module that fails to load is reported where the
683
+ user can see it rather than onto the display's own error slot — that slot is
684
+ what `reload()` clears, and nothing would re-run the install behind it. Three
685
+ displays hand-rolled this IIFE and each drew the lines differently.
686
+
687
+ ```js
688
+ // type signature
689
+ <Self extends IStateTreeNode>(self: Self, load: () => Promise<(self: Self) => void>) => void
690
+ ```
691
+
692
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/util/lazyAfterAttach.ts)
693
+
651
694
  ### sampleColorRamp
652
695
 
653
696
  The color at `t` in `[0, 1]` across a list of EVENLY SPACED stops, linearly
@@ -671,6 +714,12 @@ Make JBrowse follow the host's light/dark state — the whole of it, in one moun
671
714
  </SessionPaletteProvider>
672
715
  ```
673
716
 
717
+ `mode` is optional. Left out, JBrowse follows `prefers-color-scheme` and
718
+ re-themes when the OS preference changes, through the same session write an
719
+ explicit mode takes — so a host whose dark mode _is_ the OS preference mounts
720
+ this with a session and nothing else. Pass a mode as soon as the host has a
721
+ toggle of its own, since the media query cannot see it.
722
+
674
723
  A component rather than a documented pair of calls because the pair has a half
675
724
  that can be left out with nothing to show for it. `PaletteProvider` is the name
676
725
  a host reaches for, and it colors the React side alone; the session write is
@@ -684,7 +733,7 @@ colors of its own mounts `PaletteProvider` directly instead.
684
733
 
685
734
  ```js
686
735
  // type signature
687
- ({ session, mode, children, }: { session: ThemeModeSession; mode: "dark" | "light"; children: ReactNode; }) => Element
736
+ ({ session, mode, children, }: { session: ThemeModeSession; mode?: "dark" | "light" | undefined; children: ReactNode; }) => Element
688
737
  ```
689
738
 
690
739
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/ui/PaletteContext.tsx)
@@ -757,6 +806,16 @@ never baked into the color string.
757
806
 
758
807
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/util/colorRamp.ts)
759
808
 
809
+ ### TogglePin
810
+
811
+ The pin on a checkbox row, built by makeTogglePin: the row's own checkbox over
812
+ every open track of the display type. `active` mirrors the row, `onValue` is the
813
+ state a click applies (the row's opposite), and `toggle` applies it everywhere
814
+ and offers it as the default. It never clears a default on its own — promoting
815
+ the slot's base value is what clears one.
816
+
817
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
818
+
760
819
  ### TrackConfigWithPromotables
761
820
 
762
821
  A track config snapshot with every display's `promotable` slots resolved, plus
@@ -788,6 +847,16 @@ reader has promoted in their own browser. Pinned by
788
847
 
789
848
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
790
849
 
850
+ ### ValuePin
851
+
852
+ The pin on a radio or slider row, built by makePin: `onValue` is the row's own
853
+ value, `active` means that value is the display type's promoted default, and
854
+ `toggle` on an outline pin applies the value to every open track and offers it
855
+ as the default, while on a filled pin it clears that default and touches no
856
+ track (`applyAndOfferDefault` / `clearDefault`).
857
+
858
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
859
+
791
860
  ### VIRIDIS_STOPS
792
861
 
793
862
  The 256 viridis stops, fully opaque. Feed them to buildColorRampLut for the
@@ -1,8 +1,7 @@
1
1
  import type { SimpleFeatureSerialized } from '../../util/index.ts';
2
- import type { Descriptors, FeatureFormatter } from '../types.tsx';
3
- import type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree';
2
+ import type { Descriptors, FeatureDetailsModel, FeatureFormatter } from '../types.tsx';
4
3
  interface FeatureDetailsProps {
5
- model: IAnyStateTreeNode;
4
+ model: FeatureDetailsModel;
6
5
  feature: SimpleFeatureSerialized;
7
6
  depth?: number;
8
7
  omit?: string[];
@@ -0,0 +1,4 @@
1
+ import type { ParentFeatureSummary } from '../../util/index.ts';
2
+ export default function ParentFeatureLine({ parentFeature, }: {
3
+ parentFeature: ParentFeatureSummary;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Typography } from '@mui/material';
3
+ import { makeStyles } from '../../util/tss-react/index.js';
4
+ const useStyles = makeStyles()(theme => ({
5
+ line: {
6
+ padding: theme.spacing(0.5, 1, 0),
7
+ },
8
+ }));
9
+ // Which gene a transcript came out of, above the card naming the transcript.
10
+ // The panel is opened on the exact isoform the click resolved to, and that
11
+ // isoform's own record is regularly the only place its accession appears --
12
+ // nothing in `NM_004006.2 - mRNA` says DMD.
13
+ export default function ParentFeatureLine({ parentFeature, }) {
14
+ const { classes } = useStyles();
15
+ const { name, type } = parentFeature;
16
+ return (_jsxs(Typography, { variant: "body2", color: "textSecondary", className: classes.line, "data-testid": "parent-feature-line", children: ["in ", type ? `${type} ` : '', name] }));
17
+ }
@@ -1,11 +1,12 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { observer } from 'mobx-react';
3
3
  import { ErrorBanner } from '../../ui/index.js';
4
4
  import FeatureDetails from './FeatureDetails.js';
5
5
  import FeatureWash from './FeatureWash.js';
6
+ import ParentFeatureLine from './ParentFeatureLine.js';
6
7
  import { isEmpty } from './util.js';
7
8
  const BaseFeatureDetail = observer(function BaseFeatureDetail({ model, }) {
8
- const { error, featureData } = model;
9
+ const { error, featureData, parentFeature } = model;
9
10
  // annotated to shed the MST node brand types.frozen() carries on the instance
10
11
  const descriptions = model.descriptions;
11
12
  // A field is hidden by a formatDetails callback returning undefined (jexl
@@ -19,7 +20,7 @@ const BaseFeatureDetail = observer(function BaseFeatureDetail({ model, }) {
19
20
  return null;
20
21
  }
21
22
  else {
22
- return (_jsx(FeatureWash, { uniqueId: featureData.uniqueId, children: _jsx(FeatureDetails, { model: model, feature: featureData, descriptions: descriptions }) }));
23
+ return (_jsxs(FeatureWash, { uniqueId: featureData.uniqueId, children: [parentFeature ? (_jsx(ParentFeatureLine, { parentFeature: parentFeature })) : null, _jsx(FeatureDetails, { model: model, feature: featureData, descriptions: descriptions })] }));
23
24
  }
24
25
  });
25
26
  export default BaseFeatureDetail;
@@ -1,7 +1,7 @@
1
1
  import type { SimpleFeatureSerialized } from '../../util/index.ts';
2
- import type { BaseFeatureWidgetModel } from '../stateModelFactory.ts';
2
+ import type { FeatureDetailsModel } from '../types.tsx';
3
3
  declare const SequenceFeaturePanel: ({ model, feature, }: {
4
- model: BaseFeatureWidgetModel;
4
+ model: FeatureDetailsModel;
5
5
  feature: SimpleFeatureSerialized;
6
6
  }) => import("react").JSX.Element;
7
7
  export default SequenceFeaturePanel;
@@ -48,9 +48,9 @@ declare const _default: {
48
48
  uniqueId: string;
49
49
  parentId: string;
50
50
  id?: undefined;
51
+ name?: undefined;
51
52
  note?: undefined;
52
53
  protein_id?: undefined;
53
- name?: undefined;
54
54
  } | {
55
55
  transcript_id?: undefined;
56
56
  source: string;
@@ -94,6 +94,7 @@ declare const _default: {
94
94
  transcript_id: string;
95
95
  subfeatures: ({
96
96
  id?: undefined;
97
+ name?: undefined;
97
98
  note?: undefined;
98
99
  protein_id?: undefined;
99
100
  source: string;
@@ -111,7 +112,6 @@ declare const _default: {
111
112
  transcript_id: string;
112
113
  uniqueId: string;
113
114
  parentId: string;
114
- name?: undefined;
115
115
  } | {
116
116
  transcript_id?: undefined;
117
117
  source: string;
@@ -1,5 +1,5 @@
1
1
  export { configSchema } from './configSchema.ts';
2
- export type { Descriptors, MaybeSerializedFeat } from './types.tsx';
2
+ export type { Descriptors, FeatureDetailsModel, MaybeSerializedFeat, } from './types.tsx';
3
3
  export type { SequenceHoverPosition, ShowCoordinatesMode, } from './SequenceFeatureDetails/model.ts';
4
4
  export { stateModelFactory } from './stateModelFactory.ts';
5
5
  export type { BaseFeatureWidgetModel, BaseFeatureWidgetStateModel, } from './stateModelFactory.ts';
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '../PluginManager.ts';
2
- import type { SimpleFeatureSerialized } from '../util/index.ts';
2
+ import type { ParentFeatureSummary, SimpleFeatureSerialized } from '../util/index.ts';
3
3
  import type { SequenceHoverPosition } from './SequenceFeatureDetails/model.ts';
4
4
  import type { Descriptors, MaybeSerializedFeat } from './types.tsx';
5
5
  import type { Instance } from '@jbrowse/mobx-state-tree';
@@ -69,6 +69,12 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
69
69
  * #property
70
70
  */
71
71
  descriptions: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<Descriptors | undefined, Descriptors | undefined, Descriptors | undefined>, [undefined]>;
72
+ /**
73
+ * #property
74
+ * names the feature this one was reached through, when it was reached
75
+ * through one -- a transcript clicked inside its gene
76
+ */
77
+ parentFeature: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<ParentFeatureSummary | undefined, ParentFeatureSummary | undefined, ParentFeatureSummary | undefined>, [undefined]>;
72
78
  }, {
73
79
  error: unknown;
74
80
  sequenceHoverPosition: SequenceHoverPosition | undefined;
@@ -113,6 +119,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
113
119
  maxDepth: number | undefined;
114
120
  sequenceFeatureDetails: import("@jbrowse/mobx-state-tree").ModelSnapshotType<{}>;
115
121
  descriptions: Descriptors | undefined;
122
+ parentFeature: ParentFeatureSummary | undefined;
116
123
  finalizedFeatureData: any;
117
124
  }>;
118
125
  export type BaseFeatureWidgetStateModel = ReturnType<typeof stateModelFactory>;
@@ -59,6 +59,12 @@ export function stateModelFactory(pluginManager) {
59
59
  * #property
60
60
  */
61
61
  descriptions: types.optional(types.frozen(), undefined),
62
+ /**
63
+ * #property
64
+ * names the feature this one was reached through, when it was reached
65
+ * through one -- a transcript clicked inside its gene
66
+ */
67
+ parentFeature: types.optional(types.frozen(), undefined),
62
68
  })
63
69
  .volatile(() => ({
64
70
  /**
@@ -1,6 +1,14 @@
1
1
  import type { SimpleFeatureSerialized } from '../util/simpleFeature.ts';
2
- import type { BaseFeatureWidgetModel } from './stateModelFactory.ts';
2
+ import type { SequenceFeatureDetailsModel, SequenceHoverTarget } from './SequenceFeatureDetails/model.ts';
3
+ import type { IStateTreeNode } from '@jbrowse/mobx-state-tree';
3
4
  import type React from 'react';
5
+ export interface FeatureDetailsModel extends IStateTreeNode, SequenceHoverTarget {
6
+ maxDepth: number | undefined;
7
+ sequenceFeatureDetails: SequenceFeatureDetailsModel;
8
+ view: {
9
+ assemblyNames: string[];
10
+ } | undefined;
11
+ }
4
12
  export interface Descriptors {
5
13
  [key: string]: React.ReactNode | Descriptors;
6
14
  }
@@ -9,7 +17,7 @@ export interface BaseProps extends BaseCardProps {
9
17
  feature: SimpleFeatureSerialized;
10
18
  formatter?: FeatureFormatter;
11
19
  descriptions?: Descriptors;
12
- model?: BaseFeatureWidgetModel;
20
+ model?: FeatureDetailsModel;
13
21
  }
14
22
  export interface BaseCardProps {
15
23
  title?: string;
@@ -12,6 +12,7 @@ export interface PluginLoadFailure {
12
12
  definition: PluginDefinition;
13
13
  error: unknown;
14
14
  }
15
+ export declare function workerScriptLoadMessage(scriptUrl: string, error: unknown): string;
15
16
  export default class PluginLoader {
16
17
  definitions: PluginDefinition[];
17
18
  fetchESM?: (url: string) => Promise<LoadedPlugin>;
@@ -1,5 +1,6 @@
1
+ import { enableContractReports } from '@jbrowse/render-core/contractReports';
1
2
  import { setReExportRegistry } from './ReExports/registry.js';
2
- import { isCJSPluginDefinition, isESMPluginDefinition, isUMDPluginDefinition, pluginDescriptionString, } from './pluginDefinitions.js';
3
+ import { isCJSPluginDefinition, isESMPluginDefinition, isUMDPluginDefinition, maybePluginUrl, pluginDescriptionString, } from './pluginDefinitions.js';
3
4
  import { isElectron } from './util/index.js';
4
5
  import { isWebWorker } from './util/isWebWorker.js';
5
6
  /**
@@ -45,6 +46,19 @@ function promisifiedLoadScript(src, integrity) {
45
46
  function hasImportScripts(scope) {
46
47
  return 'importScripts' in scope;
47
48
  }
49
+ // A *module* worker has importScripts on its global but throws from it — the
50
+ // spec forbids it there, and the browser says so ("Module scripts don't support
51
+ // importScripts"). That is the whole failure for a UMD plugin in a bundler
52
+ // configured for module workers (Vite's `worker.format: 'es'`), and it reads as
53
+ // a broken plugin unless named. Every other throw is the script's own — a 404,
54
+ // or a bundle that dereferences `window` in a realm that has none — and the
55
+ // script's words are the diagnosis, so they are kept rather than replaced.
56
+ export function workerScriptLoadMessage(scriptUrl, error) {
57
+ const detail = error instanceof Error ? error.message : String(error);
58
+ return /module script/i.test(detail)
59
+ ? `Failed to load ${scriptUrl} in the worker. A UMD plugin is loaded there via importScripts, which module workers do not support — either build the worker as a classic worker, or use a plugin published as ESM.`
60
+ : `Failed to load ${scriptUrl} in the worker: ${detail}`;
61
+ }
48
62
  async function loadScript(scriptUrl, integrity) {
49
63
  const scope = globalThis;
50
64
  if (!isWebWorker()) {
@@ -55,12 +69,9 @@ async function loadScript(scriptUrl, integrity) {
55
69
  scope.importScripts(scriptUrl);
56
70
  }
57
71
  catch (error) {
58
- // A *module* worker has importScripts on its global but throws from it —
59
- // the spec forbids it there. That is the whole failure for a UMD plugin
60
- // in a bundler configured for module workers (Vite's `worker.format:
61
- // 'es'`), and the raw TypeError names none of it, so it reads as a broken
62
- // plugin rather than an incompatible pairing.
63
- throw new Error(`Failed to load ${scriptUrl} in the worker. A UMD plugin is loaded there via importScripts, which module workers do not support — either build the worker as a classic worker, or use a plugin published as ESM.`, { cause: error });
72
+ throw new Error(workerScriptLoadMessage(scriptUrl, error), {
73
+ cause: error,
74
+ });
64
75
  }
65
76
  return;
66
77
  }
@@ -97,6 +108,34 @@ function resolvePluginUrl(spec, base) {
97
108
  }
98
109
  return url;
99
110
  }
111
+ // A plugin served from the developer's own machine into an app built for
112
+ // production is the one arrangement that can only be a plugin under
113
+ // development: a shipped site serves its plugins from its own origin, and a
114
+ // developer running the app itself from source already has a development build.
115
+ // So it is the evidence that arms the contract channel without anything for the
116
+ // author to know about first — which is the whole difficulty the channel had,
117
+ // since the population it is written for is the one with nobody to ask. See
118
+ // `@jbrowse/render-core/contractReports`.
119
+ function armIfUnderDevelopment(def) {
120
+ const url = maybePluginUrl(def);
121
+ if (url !== undefined && servedFromThisMachine(url)) {
122
+ enableContractReports(`the plugin at ${url} is served from this machine`);
123
+ }
124
+ }
125
+ function servedFromThisMachine(url) {
126
+ try {
127
+ const { hostname, protocol } = new URL(url);
128
+ return ((protocol === 'http:' || protocol === 'https:') &&
129
+ (hostname === 'localhost' ||
130
+ hostname === '127.0.0.1' ||
131
+ hostname === '[::1]'));
132
+ }
133
+ catch {
134
+ // a relative url is a plugin shipped beside this index.html, which is the
135
+ // site's own rather than one under development
136
+ return false;
137
+ }
138
+ }
100
139
  function addCacheBuster(url) {
101
140
  if (!('__jbrowseCacheBuster' in globalThis)) {
102
141
  return url;
@@ -155,6 +194,7 @@ export default class PluginLoader {
155
194
  }
156
195
  async loadPlugin(def, baseUri) {
157
196
  assertSingleKind(def);
197
+ armIfUnderDevelopment(def);
158
198
  let plugin;
159
199
  if (isCJSPluginDefinition(def)) {
160
200
  if (!isElectron) {
@@ -198,7 +238,11 @@ export default class PluginLoader {
198
238
  if (!target) {
199
239
  return;
200
240
  }
201
- const { default: ReExports } = await import('./ReExports/index.js');
241
+ // a worker never renders: the same keys, with the UI ones stubbed, so a
242
+ // plugin bundle evaluates there without fetching react-dom and Material UI
243
+ const { default: ReExports } = isWebWorker()
244
+ ? await import('./ReExports/workerModules.js')
245
+ : await import('./ReExports/index.js');
202
246
  target.JBrowseExports = {
203
247
  ...ReExports,
204
248
  };