@jbrowse/core 5.0.0-beta.2 → 5.0.0-beta.4

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 (142) hide show
  1. package/README.md +70 -40
  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/index.d.ts +1 -1
  8. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
  9. package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
  10. package/esm/BaseFeatureWidget/types.d.ts +10 -2
  11. package/esm/PluginManager.d.ts +30 -1
  12. package/esm/PluginManager.js +107 -70
  13. package/esm/ReExports/BaseFeatureDetails.js +1 -1
  14. package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
  15. package/esm/ReExports/MuiDataGridReExports.js +2 -2
  16. package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
  17. package/esm/ReExports/barrelOnlyNames.js +63 -0
  18. package/esm/ReExports/modules.js +28 -56
  19. package/esm/ReExports/publicTracks.d.ts +1 -0
  20. package/esm/ReExports/publicTracks.js +14 -0
  21. package/esm/ReExports/publicUi.d.ts +4 -0
  22. package/esm/ReExports/publicUi.js +33 -0
  23. package/esm/ReExports/publicUtil.d.ts +1 -1
  24. package/esm/ReExports/publicUtil.js +8 -4
  25. package/esm/ReExports/sharedModules.d.ts +1 -1
  26. package/esm/ReExports/sharedModules.js +8 -1
  27. package/esm/ReExports/uiStub.d.ts +1 -0
  28. package/esm/ReExports/uiStub.js +6 -8
  29. package/esm/ReExports/workerModules.js +9 -4
  30. package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
  31. package/esm/ReExports/workerNamespaceNames.js +281 -0
  32. package/esm/configuration/configurationSchema.js +11 -0
  33. package/esm/configuration/index.d.ts +2 -2
  34. package/esm/configuration/index.js +1 -1
  35. package/esm/configuration/promotableDefaults.d.ts +54 -19
  36. package/esm/configuration/promotableDefaults.js +108 -45
  37. package/esm/configuration/promotablePin.d.ts +50 -40
  38. package/esm/configuration/promotableResolve.d.ts +1 -1
  39. package/esm/configuration/promotableResolve.js +1 -1
  40. package/esm/configuration/tabixIndexFields.d.ts +2 -2
  41. package/esm/configuration/tabixIndexFields.js +2 -2
  42. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +4 -12
  43. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +12 -0
  44. package/esm/data_adapters/BaseAdapter/featureDensity.js +15 -0
  45. package/esm/data_adapters/BaseAdapter/index.d.ts +2 -2
  46. package/esm/data_adapters/BaseAdapter/index.js +1 -1
  47. package/esm/data_adapters/BaseAdapter/types.d.ts +2 -8
  48. package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
  49. package/esm/pluggableElementTypes/AdapterType.js +1 -1
  50. package/esm/pluggableElementTypes/DisplayType.d.ts +3 -10
  51. package/esm/pluggableElementTypes/DisplayType.js +3 -45
  52. package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
  53. package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
  54. package/esm/pluggableElementTypes/ViewType.d.ts +3 -10
  55. package/esm/pluggableElementTypes/ViewType.js +6 -51
  56. package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
  57. package/esm/pluggableElementTypes/extendElementType.js +1 -2
  58. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +3 -3
  59. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +1 -1
  60. package/esm/pluggableElementTypes/models/BaseTrackModel.js +1 -4
  61. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +34 -34
  62. package/esm/pluggableElementTypes/models/BaseViewModel.js +19 -30
  63. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +4 -3
  64. package/esm/pluggableElementTypes/models/assertDisplayContract.js +2 -2
  65. package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
  66. package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
  67. package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
  68. package/esm/ui/ExportSvgDialog.d.ts +1 -1
  69. package/esm/ui/MenuTypes.d.ts +3 -3
  70. package/esm/ui/PinAdornment.js +22 -40
  71. package/esm/ui/ScrollChrome.d.ts +16 -0
  72. package/esm/ui/ScrollChrome.js +12 -0
  73. package/esm/ui/ScrollZoomToggle.d.ts +4 -3
  74. package/esm/ui/ScrollZoomToggle.js +4 -3
  75. package/esm/ui/SizeSliderRow.js +1 -1
  76. package/esm/ui/index.d.ts +2 -2
  77. package/esm/ui/index.js +3 -3
  78. package/esm/ui/legendMenuItem.d.ts +9 -15
  79. package/esm/ui/legendMenuItem.js +8 -19
  80. package/esm/ui/menuItemAdornment.d.ts +2 -3
  81. package/esm/ui/menuItemAdornment.js +2 -3
  82. package/esm/ui/menuItems.d.ts +1 -2
  83. package/esm/ui/menuItems.js +0 -1
  84. package/esm/ui/palette.d.ts +11 -11
  85. package/esm/ui/palette.js +11 -11
  86. package/esm/ui/promotablePinCoverage.d.ts +16 -2
  87. package/esm/ui/promotablePinCoverage.js +38 -2
  88. package/esm/ui/theme.js +5 -0
  89. package/esm/ui/toggleMenuItems.d.ts +13 -6
  90. package/esm/ui/toggleMenuItems.js +32 -15
  91. package/esm/util/Base1DUtils.d.ts +4 -2
  92. package/esm/util/Base1DUtils.js +12 -4
  93. package/esm/util/SvgCanvas.js +4 -3
  94. package/esm/util/adapterConfigKey.d.ts +12 -0
  95. package/esm/util/adapterConfigKey.js +14 -0
  96. package/esm/util/adapterMetadata.js +2 -1
  97. package/esm/util/analytics.js +4 -5
  98. package/esm/util/clampToContig.d.ts +17 -0
  99. package/esm/util/clampToContig.js +19 -0
  100. package/esm/util/colorBits.d.ts +2 -1
  101. package/esm/util/colorBits.js +2 -5
  102. package/esm/util/createStopTokenRotation.d.ts +8 -7
  103. package/esm/util/featureTypes.d.ts +24 -0
  104. package/esm/util/featureTypes.js +35 -0
  105. package/esm/util/fetchPhases.d.ts +1 -1
  106. package/esm/util/index.d.ts +4 -2
  107. package/esm/util/index.js +3 -1
  108. package/esm/util/installFetch.d.ts +29 -18
  109. package/esm/util/installFetch.js +17 -17
  110. package/esm/util/installInitAutorun.d.ts +6 -5
  111. package/esm/util/installInitAutorun.js +2 -2
  112. package/esm/util/installPrerequisiteFetch.d.ts +86 -0
  113. package/esm/util/installPrerequisiteFetch.js +73 -0
  114. package/esm/util/openFeatureWidget.d.ts +5 -0
  115. package/esm/util/openFeatureWidget.js +1 -0
  116. package/esm/util/openViews.d.ts +16 -0
  117. package/esm/util/openViews.js +22 -0
  118. package/esm/util/parentWalk.d.ts +1 -1
  119. package/esm/util/parentWalk.js +1 -1
  120. package/esm/util/renderToStaticMarkup.js +10 -0
  121. package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
  122. package/esm/util/scheduleDetachedDestroy.js +24 -0
  123. package/esm/util/scrollLatch.d.ts +1 -0
  124. package/esm/util/scrollLatch.js +8 -0
  125. package/esm/util/stopToken.d.ts +6 -5
  126. package/esm/util/trackConfigDelta.d.ts +6 -6
  127. package/esm/util/trackConfigDelta.js +3 -3
  128. package/esm/util/types/index.d.ts +25 -20
  129. package/esm/util/usePanelVirtualScroll.d.ts +6 -2
  130. package/esm/util/usePanelVirtualScroll.js +6 -2
  131. package/esm/util/useRowVirtualScroll.d.ts +1 -1
  132. package/esm/util/useRowVirtualScroll.js +1 -1
  133. package/esm/util/useVirtualScrollWheel.js +11 -1
  134. package/esm/util/wheelZoom.d.ts +3 -1
  135. package/esm/util/wheelZoom.js +39 -14
  136. package/esm/util/whenViewSettled.d.ts +31 -6
  137. package/esm/util/whenViewSettled.js +33 -5
  138. package/esm/util/withLaunchInput.d.ts +47 -2
  139. package/esm/util/withLaunchInput.js +56 -11
  140. package/package.json +10 -5
  141. package/esm/ui/promotableMenuItems.d.ts +0 -19
  142. package/esm/ui/promotableMenuItems.js +0 -91
@@ -1,4 +1,3 @@
1
- import { promotableToggleItem } from './promotableMenuItems.js';
2
1
  import { checkboxItem } from './toggleMenuItems.js';
3
2
  /**
4
3
  * The "Show legend" checkbox, which seven displays build by hand — Hi-C, LD,
@@ -14,31 +13,21 @@ import { checkboxItem } from './toggleMenuItems.js';
14
13
  * values legitimately differ (a Hi-C color scale is off by default, a variant
15
14
  * genotype key on), and their descriptions describe genuinely different legends.
16
15
  * What they now share is being *promotable* — pass `opts.pin` and the row gains
17
- * the pin that applies the current state to every open track of this display
18
- * type, offering the display-type default as its snackbar's one action. Every
16
+ * the pin that toggles the legend on every open track of this display type,
17
+ * offering the new state as the display-type default in its snackbar. Every
19
18
  * display whose legend is backed by a config slot passes one, and gets it from
20
- * `LegendMixin`'s `showLegendDisplayTypeDefault` rather than calling `makePin`
21
- * itself: the slot is the per-display half, the accessors over it are not.
19
+ * `LegendMixin`'s `showLegendDisplayTypeDefault` rather than calling
20
+ * `makeTogglePin` itself: the slot is the per-display half, the accessors over
21
+ * it are not.
22
22
  *
23
23
  * `pin` is optional because two callers have no slot to promote: the Manhattan
24
24
  * plot's LD legend and `LinearBasicDisplay`'s color key are a volatile and a
25
25
  * per-legend `dismissed` flag respectively, neither of which is config at all.
26
- * They get the plain row, which is what `checkboxItem` builds either way — the
27
- * promotable form is that same row plus the pin, per `promotableToggleItem`.
28
26
  *
29
- * Deliberately not used by `synteny-core`'s "Show color legend", which sits
30
- * inside a "Color by..." submenu where the bare word would not say which legend.
27
+ * `synteny-core`'s color-by legend has no toggle at all: it comes up with the
28
+ * modes that have a key and is dismissed from its own close button.
31
29
  */
32
30
  /** #menuBuilder showLegendCheckboxItem | the shared "Show legend" checkbox */
33
31
  export function showLegendCheckboxItem(checked, onToggle, opts) {
34
- const { pin, ...rest } = opts ?? {};
35
- return pin
36
- ? promotableToggleItem({
37
- label: 'Show legend',
38
- checked,
39
- onToggle,
40
- pin,
41
- ...rest,
42
- })
43
- : checkboxItem('Show legend', checked, onToggle, rest);
32
+ return checkboxItem('Show legend', checked, onToggle, opts);
44
33
  }
@@ -6,9 +6,8 @@ import type { MenuItem } from './MenuTypes.ts';
6
6
  * the builder already made — the escape hatch, for content nothing else can
7
7
  * describe. `pin` is a *description* of the "default for all tracks of
8
8
  * this type" pin, and turning it into `PinAdornment` here is the whole
9
- * point: the builders that set it (`promotableToggleItem`,
10
- * `promotableRadioItem`) are called from state models and menu modules, which
11
- * are eager, so a module that constructs the element instead puts MUI's
9
+ * point: the row builders that set it (`toggleMenuItems.ts`) are called from
10
+ * state models and menu modules, which are eager, so a module that constructs the element instead puts MUI's
12
11
  * `ToggleButton`, `Tooltip` and two icons into every host's first paint.
13
12
  *
14
13
  * Live in one place rather than at each of the four render sites, because the
@@ -7,9 +7,8 @@ import { PinAdornment } from './PinAdornment.js';
7
7
  * the builder already made — the escape hatch, for content nothing else can
8
8
  * describe. `pin` is a *description* of the "default for all tracks of
9
9
  * this type" pin, and turning it into `PinAdornment` here is the whole
10
- * point: the builders that set it (`promotableToggleItem`,
11
- * `promotableRadioItem`) are called from state models and menu modules, which
12
- * are eager, so a module that constructs the element instead puts MUI's
10
+ * point: the row builders that set it (`toggleMenuItems.ts`) are called from
11
+ * state models and menu modules, which are eager, so a module that constructs the element instead puts MUI's
13
12
  * `ToggleButton`, `Tooltip` and two icons into every host's first paint.
14
13
  *
15
14
  * Live in one place rather than at each of the four render sites, because the
@@ -22,7 +22,6 @@ export { checkboxItem, radioItem, radioItems, toggleItem, withSubHeader, } from
22
22
  export { withHint } from './menuLabels.ts';
23
23
  export { makeRadioSubMenu } from './radioSubMenu.ts';
24
24
  export { showLegendCheckboxItem } from './legendMenuItem.ts';
25
- export { promotableRadioItem, promotableRadioItems, promotableToggleItem, } from './promotableMenuItems.ts';
26
- export type { RadioOption, SettingRowOptions } from './toggleMenuItems.ts';
25
+ export type { CheckboxRowOptions, RadioOption, RadioRowOptions, SettingRowOptions, } from './toggleMenuItems.ts';
27
26
  export { resolveSubMenu, staysOpenOnClick } from './MenuTypes.ts';
28
27
  export type { BaseMenuItem, CheckboxMenuItem, ClickableMenuItem, CustomMenuItem, MenuDivider, MenuItem, MenuItemClickHandler, MenuItemPin, MenuItemsGetter, MenuSubHeader, NormalMenuItem, RadioMenuItem, SubMenuItem, } from './MenuTypes.ts';
@@ -22,5 +22,4 @@ export { checkboxItem, radioItem, radioItems, toggleItem, withSubHeader, } from
22
22
  export { withHint } from './menuLabels.js';
23
23
  export { makeRadioSubMenu } from './radioSubMenu.js';
24
24
  export { showLegendCheckboxItem } from './legendMenuItem.js';
25
- export { promotableRadioItem, promotableRadioItems, promotableToggleItem, } from './promotableMenuItems.js';
26
25
  export { resolveSubMenu, staysOpenOnClick } from './MenuTypes.js';
@@ -117,33 +117,33 @@ export interface SemanticColors {
117
117
  export declare const colorFwdStrand = "#EC8B8B";
118
118
  /** #color alignments-strand | Reverse strand | Read maps to the reverse strand */
119
119
  export declare const colorRevStrand = "#8F8FD8";
120
- /** #color alignments-pair-orientation | LR (→ ←, normal proper pair) | Concordant */
120
+ /** #color alignments-pair-orientation | LR (→ ←) | Normal proper pair */
121
121
  export declare const colorPairLR = "#d3d3d3";
122
122
  export declare const colorPairLRDark = "#8a8a8a";
123
- /** #color alignments-pair-orientation | RL (← →, mates point away from each other) | Abnormal orientation */
123
+ /** #color alignments-pair-orientation | RL (← →) | Mates point away from each other */
124
124
  export declare const colorPairRL = "#0099bb";
125
- /** #color alignments-pair-orientation | LL (→ →, both mates forward strand) | Abnormal orientation */
125
+ /** #color alignments-pair-orientation | LL (→ →) | Both mates on the forward strand */
126
126
  export declare const colorPairLL = "#4d9a4d";
127
- /** #color alignments-pair-orientation | RR (← ←, both mates reverse strand) | Abnormal orientation */
127
+ /** #color alignments-pair-orientation | RR (← ←) | Both mates on the reverse strand */
128
128
  export declare const colorPairRR = "#5555bb";
129
129
  export declare const colorNeutralRead = "#c8c8c8";
130
130
  /**
131
- * #color alignments-pair-orientation | Inter-chromosomal | Mate maps to a different chromosome; colored distinctly rather than by orientation
132
- * #color alignments-insert-size | Mate on a different chromosome | Suggests an inter-chromosomal event
131
+ * #color alignments-pair-orientation | Inter-chromosomal | Mate on another chromosome
132
+ * #color alignments-insert-size | Inter-chromosomal | Mate on another chromosome
133
133
  */
134
134
  export declare const colorInterchrom = "#af4d19";
135
- /** #color alignments-insert-size | Insert larger than expected | Suggests a deletion spanning the pair */
135
+ /** #color alignments-insert-size | Insert larger than expected | Deletion between the mates */
136
136
  export declare const colorLongInsert = "#ff0000";
137
- /** #color alignments-insert-size | Insert smaller than expected | Suggests an insertion between the pair */
137
+ /** #color alignments-insert-size | Insert smaller than expected | Insertion between the mates */
138
138
  export declare const colorShortInsert = "#f582c0";
139
139
  /**
140
- * #color alignments-pair-orientation | Mate unmapped | The other end of the pair aligned nowhere, so orientation and insert size say nothing
141
- * #color alignments-insert-size | Mate unmapped | The other end of the pair aligned nowhere, so insert size says nothing
140
+ * #color alignments-pair-orientation | Mate unmapped | Mate aligned nowhere
141
+ * #color alignments-insert-size | Mate unmapped | Mate aligned nowhere
142
142
  */
143
143
  export declare const colorUnmappedMate = "#000000";
144
144
  export declare const colorUnmappedMateDark = "#4a4a4a";
145
145
  export declare const colorLongreadInv = "#7755bb";
146
- /** #color alignments-pair-orientation | Split paired-end read (inverted) | A paired read's supplementary segment maps opposite-strand to its primary, so the junction is inverted — an inversion or an inverted duplication */
146
+ /** #color alignments-pair-orientation | Split read (inverted) | Supplementary segment on the opposite strand to its primary */
147
147
  export declare const colorSplitReadInversion = "#9b30b0";
148
148
  export declare const colorSupplementary = "#f0b878";
149
149
  export declare const tagColorPalette: string[];
package/esm/ui/palette.js CHANGED
@@ -231,16 +231,16 @@ const darkNeutrals = {
231
231
  export const colorFwdStrand = '#EC8B8B';
232
232
  /** #color alignments-strand | Reverse strand | Read maps to the reverse strand */
233
233
  export const colorRevStrand = '#8F8FD8';
234
- /** #color alignments-pair-orientation | LR (→ ←, normal proper pair) | Concordant */
234
+ /** #color alignments-pair-orientation | LR (→ ←) | Normal proper pair */
235
235
  export const colorPairLR = '#d3d3d3';
236
236
  // Dimmer grey for dark mode: the light #d3d3d3 reads as near-white glaring
237
237
  // blocks against a dark track background. Wired into the dark alignmentFill.
238
238
  export const colorPairLRDark = '#8a8a8a';
239
- /** #color alignments-pair-orientation | RL (← →, mates point away from each other) | Abnormal orientation */
239
+ /** #color alignments-pair-orientation | RL (← →) | Mates point away from each other */
240
240
  export const colorPairRL = '#0099bb';
241
- /** #color alignments-pair-orientation | LL (→ →, both mates forward strand) | Abnormal orientation */
241
+ /** #color alignments-pair-orientation | LL (→ →) | Both mates on the forward strand */
242
242
  export const colorPairLL = '#4d9a4d';
243
- /** #color alignments-pair-orientation | RR (← ←, both mates reverse strand) | Abnormal orientation */
243
+ /** #color alignments-pair-orientation | RR (← ←) | Both mates on the reverse strand */
244
244
  export const colorPairRR = '#5555bb';
245
245
  // Was `colorNostrand`, which named the one thing it essentially never paints. A
246
246
  // SAM record's strand is DEFINED from the reverse flag inside the adapter's
@@ -266,8 +266,8 @@ export const colorPairRR = '#5555bb';
266
266
  // settle it, and the dark-mode half is `agent-docs/TODO.md`.
267
267
  export const colorNeutralRead = '#c8c8c8';
268
268
  /**
269
- * #color alignments-pair-orientation | Inter-chromosomal | Mate maps to a different chromosome; colored distinctly rather than by orientation
270
- * #color alignments-insert-size | Mate on a different chromosome | Suggests an inter-chromosomal event
269
+ * #color alignments-pair-orientation | Inter-chromosomal | Mate on another chromosome
270
+ * #color alignments-insert-size | Inter-chromosomal | Mate on another chromosome
271
271
  */
272
272
  // THIS SLOT AND `colorUnmappedMate` WERE CHOSEN TOGETHER, and reading either one
273
273
  // alone is how the previous pair got stuck. Both are warm, both belong to all
@@ -299,9 +299,9 @@ export const colorNeutralRead = '#c8c8c8';
299
299
  // neighbour that must not be confusable: red means "insert too long", and a
300
300
  // second red would read as a second statement about insert size.
301
301
  export const colorInterchrom = '#af4d19';
302
- /** #color alignments-insert-size | Insert larger than expected | Suggests a deletion spanning the pair */
302
+ /** #color alignments-insert-size | Insert larger than expected | Deletion between the mates */
303
303
  export const colorLongInsert = '#ff0000';
304
- /** #color alignments-insert-size | Insert smaller than expected | Suggests an insertion between the pair */
304
+ /** #color alignments-insert-size | Insert smaller than expected | Insertion between the mates */
305
305
  // This slot has TWO neighbours it must stay clear of, and every past value has
306
306
  // solved one by walking into the other. They sit at opposite ends of the
307
307
  // lightness axis, which is what makes it a balance rather than a direction:
@@ -349,8 +349,8 @@ export const colorLongInsert = '#ff0000';
349
349
  // them.
350
350
  export const colorShortInsert = '#f582c0';
351
351
  /**
352
- * #color alignments-pair-orientation | Mate unmapped | The other end of the pair aligned nowhere, so orientation and insert size say nothing
353
- * #color alignments-insert-size | Mate unmapped | The other end of the pair aligned nowhere, so insert size says nothing
352
+ * #color alignments-pair-orientation | Mate unmapped | Mate aligned nowhere
353
+ * #color alignments-insert-size | Mate unmapped | Mate aligned nowhere
354
354
  */
355
355
  // A NON-COLOUR, at the dark end of the neutral scale on BOTH themes. It takes
356
356
  // the first half of the `readOverlap` pattern and not the second, and that split
@@ -421,7 +421,7 @@ export const colorUnmappedMate = '#000000';
421
421
  // the least that still reads as a read rather than as a hole.
422
422
  export const colorUnmappedMateDark = '#4a4a4a';
423
423
  export const colorLongreadInv = '#7755bb';
424
- /** #color alignments-pair-orientation | Split paired-end read (inverted) | A paired read's supplementary segment maps opposite-strand to its primary, so the junction is inverted — an inversion or an inverted duplication */
424
+ /** #color alignments-pair-orientation | Split read (inverted) | Supplementary segment on the opposite strand to its primary */
425
425
  export const colorSplitReadInversion = '#9b30b0';
426
426
  export const colorSupplementary = '#f0b878';
427
427
  // Qualitative palette for coloring reads by an arbitrary tag value (e.g. the HP
@@ -26,10 +26,24 @@ export declare function displayTypesWithPromotableSlots(displayTypes: readonly {
26
26
  * Reads `pin.control.slot` and nothing else. A raw `endAdornment` is
27
27
  * deliberately not counted: it is an arbitrary element (synteny's colour
28
28
  * swatch), so it cannot say which slot it promotes, and a pin built by hand
29
- * rather than through `promotableToggleItem`/`promotableRadioItem` is a thing to
30
- * find, not to accept.
29
+ * rather than through `makePin`/`makeTogglePin` is a thing to find, not to
30
+ * accept.
31
31
  */
32
32
  export declare function pinnedSlots(items: MenuItem[]): Set<string>;
33
+ /**
34
+ * Rows whose pin is the wrong kind for the row, submenus included: a checkbox
35
+ * row carrying a value pin, or a radio row carrying a toggle pin. Empty is the
36
+ * healthy answer.
37
+ *
38
+ * The row builders type the option so this cannot happen through them; this
39
+ * is for a `pin` written by hand as a literal, which the type system lets
40
+ * through as the union. A checkbox row's pin has to be the toggle kind because
41
+ * that is what a click beside a checkbox is read as — "turn this on for all" —
42
+ * and a value pin there applies the row's *current* state instead, which
43
+ * beside an unchecked box is a visible no-op. That shipped once (2026-09-07)
44
+ * and was caught in a live session, not by a test; this is the test.
45
+ */
46
+ export declare function misKindedPins(items: MenuItem[]): string[];
33
47
  /**
34
48
  * A display's promotable slots that its own track menu offers no pin for,
35
49
  * sorted. Empty is the healthy answer.
@@ -51,8 +51,8 @@ export function displayTypesWithPromotableSlots(displayTypes) {
51
51
  * Reads `pin.control.slot` and nothing else. A raw `endAdornment` is
52
52
  * deliberately not counted: it is an arbitrary element (synteny's colour
53
53
  * swatch), so it cannot say which slot it promotes, and a pin built by hand
54
- * rather than through `promotableToggleItem`/`promotableRadioItem` is a thing to
55
- * find, not to accept.
54
+ * rather than through `makePin`/`makeTogglePin` is a thing to find, not to
55
+ * accept.
56
56
  */
57
57
  export function pinnedSlots(items) {
58
58
  const found = new Set();
@@ -69,6 +69,42 @@ export function pinnedSlots(items) {
69
69
  walk(items);
70
70
  return found;
71
71
  }
72
+ /**
73
+ * Rows whose pin is the wrong kind for the row, submenus included: a checkbox
74
+ * row carrying a value pin, or a radio row carrying a toggle pin. Empty is the
75
+ * healthy answer.
76
+ *
77
+ * The row builders type the option so this cannot happen through them; this
78
+ * is for a `pin` written by hand as a literal, which the type system lets
79
+ * through as the union. A checkbox row's pin has to be the toggle kind because
80
+ * that is what a click beside a checkbox is read as — "turn this on for all" —
81
+ * and a value pin there applies the row's *current* state instead, which
82
+ * beside an unchecked box is a visible no-op. That shipped once (2026-09-07)
83
+ * and was caught in a live session, not by a test; this is the test.
84
+ */
85
+ export function misKindedPins(items) {
86
+ const found = [];
87
+ const walk = (list) => {
88
+ for (const item of list) {
89
+ if ('pin' in item && item.pin && 'type' in item) {
90
+ const { kind } = item.pin.control;
91
+ const wanted = item.type === 'checkbox'
92
+ ? 'toggle'
93
+ : item.type === 'radio'
94
+ ? 'value'
95
+ : undefined;
96
+ if (wanted && kind !== wanted) {
97
+ found.push(`${item.pin.label}: ${kind} pin on a ${item.type} row`);
98
+ }
99
+ }
100
+ if ('subMenu' in item) {
101
+ walk(resolveSubMenu(item));
102
+ }
103
+ }
104
+ };
105
+ walk(items);
106
+ return found;
107
+ }
72
108
  /**
73
109
  * A display's promotable slots that its own track menu offers no pin for,
74
110
  * sorted. Empty is the healthy answer.
package/esm/ui/theme.js CHANGED
@@ -209,6 +209,11 @@ const baseThemeOptions = {
209
209
  MuiFormLabel: {
210
210
  styleOverrides: darkModeContrastOverride(['&.Mui-focused']),
211
211
  },
212
+ // the rail, track and thumb are all `currentColor` off the root, so a
213
+ // midnight root paints the whole control dark-on-dark
214
+ MuiSlider: {
215
+ styleOverrides: darkModeContrastOverride(),
216
+ },
212
217
  MuiAccordionSummary: {
213
218
  styleOverrides: {
214
219
  root: ({ theme: t }) => ({
@@ -1,3 +1,4 @@
1
+ import type { TogglePin, ValuePin } from '../configuration/promotablePin.ts';
1
2
  import type { CheckboxMenuItem, MenuItem, RadioMenuItem } from './MenuTypes.ts';
2
3
  export interface SettingRowOptions {
3
4
  helpText?: string;
@@ -5,8 +6,14 @@ export interface SettingRowOptions {
5
6
  disabledHelpText?: string;
6
7
  keepMenuOpen?: boolean;
7
8
  }
8
- /** #menuBuilder checkboxItem | one checkbox setting row */
9
- export declare function checkboxItem(label: string, checked: boolean, onToggle: () => void, opts?: SettingRowOptions): CheckboxMenuItem;
9
+ export interface CheckboxRowOptions extends SettingRowOptions {
10
+ pin?: TogglePin;
11
+ }
12
+ export interface RadioRowOptions extends SettingRowOptions {
13
+ pin?: ValuePin;
14
+ }
15
+ /** #menuBuilder checkboxItem | one checkbox setting row, with a toggle pin when the setting is promotable */
16
+ export declare function checkboxItem(label: string, checked: boolean, onToggle: () => void, opts?: CheckboxRowOptions): CheckboxMenuItem;
10
17
  /**
11
18
  * #menuBuilder toggleItem | a checkbox row whose setter takes the new value
12
19
  *
@@ -23,15 +30,15 @@ export declare function checkboxItem(label: string, checked: boolean, onToggle:
23
30
  * `SettingRowOptions` to a hand-narrowed one-field bag — the exact drift the
24
31
  * comment on that interface warns about.
25
32
  */
26
- export declare function toggleItem(label: string, value: boolean, setValue: (value: boolean) => void, opts?: SettingRowOptions): CheckboxMenuItem;
33
+ export declare function toggleItem(label: string, value: boolean, setValue: (value: boolean) => void, opts?: CheckboxRowOptions): CheckboxMenuItem;
27
34
  /** #menuBuilder radioItem | one radio setting row; the singular of `radioItems` */
28
- export declare function radioItem(label: string, checked: boolean, onClick: () => void, opts?: SettingRowOptions): RadioMenuItem;
35
+ export declare function radioItem(label: string, checked: boolean, onClick: () => void, opts?: RadioRowOptions): RadioMenuItem;
29
36
  export interface RadioOption<T extends string> extends SettingRowOptions {
30
37
  value: T;
31
38
  label: string;
32
39
  }
33
- /** #menuBuilder radioItems | a radio group, one row per option */
34
- export declare function radioItems<T extends string>(options: readonly RadioOption<T>[], current: T | undefined, setMode: (m: T) => void): RadioMenuItem[];
40
+ /** #menuBuilder radioItems | a radio group, one row per option, with a value pin per option when the setting is promotable */
41
+ export declare function radioItems<T extends string>(options: readonly RadioOption<T>[], current: T | undefined, setMode: (m: T) => void, pin?: (value: T) => ValuePin): RadioMenuItem[];
35
42
  /**
36
43
  * #menuBuilder withSubHeader | a section heading, present only if the section is
37
44
  *
@@ -1,12 +1,16 @@
1
- /** #menuBuilder checkboxItem | one checkbox setting row */
2
- export function checkboxItem(label, checked, onToggle, opts) {
3
- return {
1
+ function withPin(row, pin) {
2
+ return pin ? { ...row, pin: { control: pin, label: row.label } } : row;
3
+ }
4
+ /** #menuBuilder checkboxItem | one checkbox setting row, with a toggle pin when the setting is promotable */
5
+ export function checkboxItem(label, checked, onToggle, opts = {}) {
6
+ const { pin, ...rest } = opts;
7
+ return withPin({
4
8
  label,
5
9
  type: 'checkbox',
6
10
  checked,
7
11
  onClick: onToggle,
8
- ...opts,
9
- };
12
+ ...rest,
13
+ }, pin);
10
14
  }
11
15
  /**
12
16
  * #menuBuilder toggleItem | a checkbox row whose setter takes the new value
@@ -29,24 +33,37 @@ export function toggleItem(label, value, setValue, opts) {
29
33
  setValue(!value);
30
34
  }, opts);
31
35
  }
32
- // One radio row. The singular of `radioItems`, and what
33
- // `promotableRadioItem` builds through, so a lone radio row and a member of a
34
- // group are the same object plus or minus its pin.
36
+ // One radio row. The singular of `radioItems`, for a group the plural form
37
+ // can't express: a row with no single value to promote yet (the colorBy
38
+ // "Tag..." row before a tag is picked), a display whose slot isn't promotable
39
+ // at all (the shared colorBy menu on gwas/variants), or a group gated row by
40
+ // row and mixing in a non-promotable peer (the alignments size presets and
41
+ // their "Custom..." row). **Reach for `radioItems` first**: every option in a
42
+ // group has to get a pin, and hand-naming the rows is what leaves one without.
35
43
  /** #menuBuilder radioItem | one radio setting row; the singular of `radioItems` */
36
- export function radioItem(label, checked, onClick, opts) {
37
- return {
44
+ export function radioItem(label, checked, onClick, opts = {}) {
45
+ const { pin, ...rest } = opts;
46
+ return withPin({
38
47
  label,
39
48
  type: 'radio',
40
49
  checked,
41
50
  onClick,
42
- ...opts,
43
- };
51
+ ...rest,
52
+ }, pin);
44
53
  }
45
- /** #menuBuilder radioItems | a radio group, one row per option */
46
- export function radioItems(options, current, setMode) {
54
+ // `pin` is a factory rather than a per-option field so a promotable group can't
55
+ // be a row short. **Every option in a group gets a pin, the `promotedBase`
56
+ // value included**: once a non-base value is promoted, taking the base row's
57
+ // offer is the per-value way to undo it, and a radio group with one row silently
58
+ // missing its trailing control reads as a bug. `sashimiArcsMode`'s base looked
59
+ // unpinnable precisely because each row had been named by hand. Pass
60
+ // `value => makePin(self, slot, value)`, or a model member of that shape where
61
+ // the menu module is handed a duck-typed model (alignments).
62
+ /** #menuBuilder radioItems | a radio group, one row per option, with a value pin per option when the setting is promotable */
63
+ export function radioItems(options, current, setMode, pin) {
47
64
  return options.map(({ value, label, ...opts }) => radioItem(label, current === value, () => {
48
65
  setMode(value);
49
- }, opts));
66
+ }, { ...opts, pin: pin?.(value) }));
50
67
  }
51
68
  /**
52
69
  * #menuBuilder withSubHeader | a section heading, present only if the section is
@@ -121,7 +121,7 @@ export declare function bpToPx({ refName, coord, displayedRegionIndex, self, }:
121
121
  * Undefined when no displayed region holds the coord, same as `bpToPx`; a
122
122
  * caller that means "as far as the region goes" clamps before asking.
123
123
  */
124
- export declare function bpToOffset({ refName, coord, displayedRegions, }: {
124
+ export declare function bpToOffset({ refName, coord, displayedRegions, displayedRegionIndex, }: {
125
125
  refName: string;
126
126
  coord: number;
127
127
  displayedRegions: {
@@ -130,6 +130,7 @@ export declare function bpToOffset({ refName, coord, displayedRegions, }: {
130
130
  end: number;
131
131
  reversed?: boolean;
132
132
  }[];
133
+ displayedRegionIndex?: number;
133
134
  }): BpOffset | undefined;
134
135
  /**
135
136
  * Where a 0-based genomic coord sits in the LINEARIZED bp space — the
@@ -145,7 +146,7 @@ export declare function bpToOffset({ refName, coord, displayedRegions, }: {
145
146
  * `undefined` when no displayed region holds the coord, exactly as `bpToPx`
146
147
  * answers: a refName the view is not showing has no place on its screen.
147
148
  */
148
- export declare function bpToLinearBp({ refName, coord, displayedRegions, }: {
149
+ export declare function bpToLinearBp({ refName, coord, displayedRegions, displayedRegionIndex, }: {
149
150
  refName: string;
150
151
  coord: number;
151
152
  displayedRegions: {
@@ -154,6 +155,7 @@ export declare function bpToLinearBp({ refName, coord, displayedRegions, }: {
154
155
  end: number;
155
156
  reversed?: boolean;
156
157
  }[];
158
+ displayedRegionIndex?: number;
157
159
  }): number | undefined;
158
160
  /**
159
161
  * Screen order of two {@link BpOffset}s: negative when `a` is to the left of
@@ -187,9 +187,12 @@ export function bpToPx({ refName, coord, displayedRegionIndex, self, }) {
187
187
  * Undefined when no displayed region holds the coord, same as `bpToPx`; a
188
188
  * caller that means "as far as the region goes" clamps before asking.
189
189
  */
190
- export function bpToOffset({ refName, coord, displayedRegions, }) {
190
+ export function bpToOffset({ refName, coord, displayedRegions, displayedRegionIndex, }) {
191
191
  for (const [index, r] of displayedRegions.entries()) {
192
- if (refName === r.refName && coord >= r.start && coord <= r.end) {
192
+ if (refName === r.refName &&
193
+ coord >= r.start &&
194
+ coord <= r.end &&
195
+ (displayedRegionIndex === undefined || displayedRegionIndex === index)) {
193
196
  return { refName, index, offset: bpOffsetInRegion(r, coord) };
194
197
  }
195
198
  }
@@ -209,8 +212,13 @@ export function bpToOffset({ refName, coord, displayedRegions, }) {
209
212
  * `undefined` when no displayed region holds the coord, exactly as `bpToPx`
210
213
  * answers: a refName the view is not showing has no place on its screen.
211
214
  */
212
- export function bpToLinearBp({ refName, coord, displayedRegions, }) {
213
- const at = bpToOffset({ refName, coord, displayedRegions });
215
+ export function bpToLinearBp({ refName, coord, displayedRegions, displayedRegionIndex, }) {
216
+ const at = bpToOffset({
217
+ refName,
218
+ coord,
219
+ displayedRegions,
220
+ displayedRegionIndex,
221
+ });
214
222
  return at ? cumulativeBp(displayedRegions, at.index, at.offset) : undefined;
215
223
  }
216
224
  /**
@@ -479,9 +479,10 @@ export class SvgCanvas {
479
479
  // The family goes through, not just the size: `measureText` switches to the
480
480
  // fixed monospace advance on seeing one, so dropping it measured a monospace
481
481
  // string against the proportional table — the same string, laid out one way on
482
- // a real canvas and another in the export, with nothing to show which. No draw
483
- // function calls ctx.measureText today; this is here so the first one to do it
484
- // doesn't inherit a silent discrepancy.
482
+ // a real canvas and another in the export, with nothing to show which. An
483
+ // estimate all the same: a draw whose layout turns on a width (synteny's
484
+ // off-screen mate labels) measures through a real canvas and passes the
485
+ // result in, so the figure names what the screen named.
485
486
  measureText(text) {
486
487
  const { size, family } = parseFont(this.font);
487
488
  return { width: measureTextWidth(text, Number(size), family) };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The adapter-config axis of a fetch key: the config a fetch was issued
3
+ * against, as one string. Every fetch that refetches on an adapter edit folds
4
+ * this in — the comparative displays, the prerequisite reads, the density
5
+ * tier, the global family's signature — so the axis is spelled once and cannot
6
+ * drift between them.
7
+ *
8
+ * Not `adapterConfigCacheKey`: that one short-circuits on `adapterId`, which is
9
+ * right for sharing one adapter instance and wrong for freshness, where an
10
+ * edit to a config carrying an id still has to read as a different fetch.
11
+ */
12
+ export declare function adapterConfigKey(adapterConfig: Record<string, unknown>): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The adapter-config axis of a fetch key: the config a fetch was issued
3
+ * against, as one string. Every fetch that refetches on an adapter edit folds
4
+ * this in — the comparative displays, the prerequisite reads, the density
5
+ * tier, the global family's signature — so the axis is spelled once and cannot
6
+ * drift between them.
7
+ *
8
+ * Not `adapterConfigCacheKey`: that one short-circuits on `adapterId`, which is
9
+ * right for sharing one adapter instance and wrong for freshness, where an
10
+ * edit to a config carrying an id still has to read as a different fetch.
11
+ */
12
+ export function adapterConfigKey(adapterConfig) {
13
+ return JSON.stringify(adapterConfig);
14
+ }
@@ -1,3 +1,4 @@
1
+ import { adapterConfigKey } from './adapterConfigKey.js';
1
2
  import { getRpcSessionId } from './parentWalk.js';
2
3
  import { getRpcHost } from './sessionServices.js';
3
4
  /**
@@ -19,7 +20,7 @@ import { getRpcHost } from './sessionServices.js';
19
20
  export function createAdapterMetadataFetch(self) {
20
21
  let cached;
21
22
  return () => {
22
- const key = JSON.stringify(self.adapterConfig);
23
+ const key = adapterConfigKey(self.adapterConfig);
23
24
  if (cached?.key !== key) {
24
25
  const promise = getRpcHost(self)
25
26
  // eslint-disable-next-line no-restricted-syntax -- nothing to narrate, nothing a cancel could save
@@ -9,11 +9,10 @@ export async function writeAWSAnalytics(rootModel, initialTimestamp, sessionQuer
9
9
  try {
10
10
  const url = 'https://analytics.jbrowse.org/api/v1';
11
11
  const multiAssemblyTracks = rootModel.jbrowse.tracks.filter(track => readConfObject(track, 'assemblyNames').length > 1).length;
12
- // which rendering backend is actually drawing (WebGPU/WebGL2/Canvas2D) —
13
- // capabilities *and* any page-wide pin, so a session that fell back to
14
- // Canvas2D is counted as Canvas2D rather than as what the hardware could
15
- // have done. Reporting the capability answer here is what made "how many
16
- // users end up on Canvas2D" unanswerable.
12
+ // The rung createGpuHal built where a display has built one by idle time,
13
+ // else the ladder's prediction with any page-wide pin applied — so a
14
+ // session that fell back to Canvas2D is counted as Canvas2D rather than as
15
+ // what the hardware could have done.
17
16
  const capabilities = await getGraphicsCapabilities();
18
17
  const renderer = effectiveRenderer(capabilities);
19
18
  // The coarse bit only. `glRenderer` names the exact driver and stays local
@@ -24,3 +24,20 @@ export declare function clampToContig(assembly: Assembly, region: {
24
24
  start: number;
25
25
  end: number;
26
26
  }): Region | undefined;
27
+ /**
28
+ * `clampToContig` for a refName that may not be on the assembly at all, which
29
+ * is the shape a location nobody requested arrives in — a BAM's `nextRef`, an
30
+ * SA record's contig (REFNAME_NAMESPACES.md). `clampToContig` alone passes an
31
+ * unknown name through with nothing to clamp against, so it cannot tell "past
32
+ * the end of a contig we have" from "a contig we do not have", and both callers
33
+ * need that apart to say which happened.
34
+ */
35
+ export declare function clampToListedContig(assembly: Assembly, region: {
36
+ refName: string;
37
+ start: number;
38
+ end: number;
39
+ }): {
40
+ refName: string;
41
+ onAssembly: boolean;
42
+ region: Region | undefined;
43
+ };
@@ -26,3 +26,22 @@ export function clampToContig(assembly, region) {
26
26
  ? { ...region, assemblyName: assembly.name, refName, start, end }
27
27
  : undefined;
28
28
  }
29
+ /**
30
+ * `clampToContig` for a refName that may not be on the assembly at all, which
31
+ * is the shape a location nobody requested arrives in — a BAM's `nextRef`, an
32
+ * SA record's contig (REFNAME_NAMESPACES.md). `clampToContig` alone passes an
33
+ * unknown name through with nothing to clamp against, so it cannot tell "past
34
+ * the end of a contig we have" from "a contig we do not have", and both callers
35
+ * need that apart to say which happened.
36
+ */
37
+ export function clampToListedContig(assembly, region) {
38
+ const refName = assembly.getCanonicalRefName2(region.refName);
39
+ const onAssembly = assembly.getRegionForRefName(refName) !== undefined;
40
+ return {
41
+ refName,
42
+ onAssembly,
43
+ region: onAssembly
44
+ ? clampToContig(assembly, { ...region, refName })
45
+ : undefined,
46
+ };
47
+ }
@@ -1,5 +1,7 @@
1
+ import { abgrToCssRgba } from '@jbrowse/render-core/marks/colorFill';
1
2
  import type { Color } from './color-bits/index.ts';
2
3
  import type { Feature } from './simpleFeature.ts';
4
+ export { abgrToCssRgba };
3
5
  export { alpha, blend, darken, formatHEX, formatHEXA, formatRGBA, getAlpha, getBlue, getGreen, getLuminance, getRed, lighten, newColor, parse, toHSLA, toRGBA, } from './color-bits/index.ts';
4
6
  export type { Color } from './color-bits/index.ts';
5
7
  /**
@@ -35,5 +37,4 @@ export declare function abgrRed(c: number): number;
35
37
  export declare function abgrGreen(c: number): number;
36
38
  export declare function abgrBlue(c: number): number;
37
39
  export declare function abgrAlpha(c: number): number;
38
- export declare function abgrToCssRgba(c: number): string;
39
40
  export declare function cssColorToNormalizedRgba(color: string): [number, number, number, number];