@jbrowse/core 5.0.0-beta.13 → 5.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/README.md +365 -69
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.d.ts +3 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +4 -2
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -2
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +4 -2
  6. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseAttributes.d.ts +2 -1
  7. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseAttributes.js +4 -2
  8. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCard.d.ts +2 -1
  9. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCard.js +4 -2
  10. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCoreDetails.d.ts +2 -1
  11. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCoreDetails.js +4 -2
  12. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.d.ts +5 -4
  13. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +6 -4
  14. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.d.ts +2 -1
  15. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.js +4 -2
  16. package/esm/BaseFeatureWidget/BaseFeatureDetail/DataGridDetails.d.ts +3 -2
  17. package/esm/BaseFeatureWidget/BaseFeatureDetail/DataGridDetails.js +4 -2
  18. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.js +2 -2
  19. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureWash.d.ts +3 -2
  20. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureWash.js +4 -2
  21. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.d.ts +3 -2
  22. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.js +4 -2
  23. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldName.d.ts +3 -2
  24. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldName.js +4 -2
  25. package/esm/BaseFeatureWidget/BaseFeatureDetail/Formatter.d.ts +3 -2
  26. package/esm/BaseFeatureWidget/BaseFeatureDetail/Formatter.js +4 -2
  27. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +3 -2
  28. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +4 -2
  29. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts +3 -2
  30. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.js +4 -2
  31. package/esm/BaseFeatureWidget/BaseFeatureDetail/UriField.d.ts +3 -2
  32. package/esm/BaseFeatureWidget/BaseFeatureDetail/UriField.js +4 -2
  33. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceBody.d.ts +3 -2
  34. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceBody.js +4 -2
  35. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.d.ts +1 -1
  36. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.js +10 -19
  37. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceLegend.d.ts +3 -2
  38. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceLegend.js +4 -2
  39. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequencePanel.js +4 -4
  40. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/HelpDialog.d.ts +3 -2
  41. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/HelpDialog.js +4 -2
  42. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.d.ts +1 -2
  43. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.js +2 -2
  44. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.d.ts +1 -2
  45. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.js +15 -36
  46. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/TranscriptSelector.d.ts +3 -2
  47. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/TranscriptSelector.js +4 -2
  48. package/esm/BaseFeatureWidget/SequenceFeatureDetails/featureTypeUtil.d.ts +2 -1
  49. package/esm/BaseFeatureWidget/SequenceFeatureDetails/featureTypeUtil.js +22 -6
  50. package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.d.ts +13 -1
  51. package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.js +28 -1
  52. package/esm/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/SequenceDisplay.js +2 -2
  53. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +2 -0
  54. package/esm/PluginManager.d.ts +1 -0
  55. package/esm/PluginManager.js +6 -0
  56. package/esm/ReExports/coreModules.generated.js +538 -524
  57. package/esm/ReExports/coreWorkerModules.generated.js +454 -441
  58. package/esm/ReExports/lazify.js +3 -2
  59. package/esm/ReExports/list.js +15 -6
  60. package/esm/ReExports/names.d.ts +1 -0
  61. package/esm/ReExports/names.generated.d.ts +2 -0
  62. package/esm/ReExports/names.generated.js +566 -0
  63. package/esm/ReExports/names.js +3 -0
  64. package/esm/assemblyManager/assembly.d.ts +9 -0
  65. package/esm/assemblyManager/assembly.js +13 -0
  66. package/esm/assemblyManager/assemblyConfigSchema.d.ts +6 -1
  67. package/esm/assemblyManager/assemblyConfigSchema.js +23 -22
  68. package/esm/assemblyManager/assemblyManager.d.ts +11 -0
  69. package/esm/assemblyManager/assemblyManager.js +2 -0
  70. package/esm/assemblyManager/expandAssemblyConfigShorthand.d.ts +9 -0
  71. package/esm/assemblyManager/expandAssemblyConfigShorthand.js +23 -0
  72. package/esm/checkPlugins.js +10 -4
  73. package/esm/configuration/configurationSchema.d.ts +18 -5
  74. package/esm/configuration/configurationSchema.js +9 -7
  75. package/esm/configuration/configurationSchemaUnion.d.ts +2 -1
  76. package/esm/configuration/configurationSchemaUnion.js +2 -1
  77. package/esm/configuration/configurationSlot.js +4 -4
  78. package/esm/configuration/fillLocations.d.ts +4 -2
  79. package/esm/configuration/fillLocations.js +9 -3
  80. package/esm/configuration/formatAboutConfigSchema.d.ts +2 -2
  81. package/esm/configuration/formatAboutConfigSchema.js +2 -2
  82. package/esm/configuration/formatDetailsConfigSchema.d.ts +2 -2
  83. package/esm/configuration/formatDetailsConfigSchema.js +5 -5
  84. package/esm/configuration/getConf.js +13 -4
  85. package/esm/configuration/index.d.ts +1 -1
  86. package/esm/configuration/index.js +1 -1
  87. package/esm/configuration/plot.d.ts +2 -2
  88. package/esm/configuration/plot.js +32 -18
  89. package/esm/configuration/schemaRegistry.d.ts +0 -2
  90. package/esm/configuration/slotFacade.js +2 -2
  91. package/esm/configuration/snapshotPreprocess.d.ts +42 -18
  92. package/esm/configuration/snapshotPreprocess.js +94 -34
  93. package/esm/configuration/tabixShorthand.js +1 -3
  94. package/esm/data_adapters/BaseAdapter/BaseAdapter.d.ts +7 -0
  95. package/esm/data_adapters/BaseAdapter/BaseAdapter.js +7 -0
  96. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +0 -22
  97. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +0 -55
  98. package/esm/data_adapters/BaseAdapter/index.d.ts +0 -1
  99. package/esm/data_adapters/BaseAdapter/index.js +0 -1
  100. package/esm/data_adapters/BaseAdapter/rowSources.d.ts +2 -2
  101. package/esm/data_adapters/BaseAdapter/types.d.ts +1 -0
  102. package/esm/data_adapters/CytobandAdapter/configSchema.d.ts +2 -0
  103. package/esm/data_adapters/CytobandAdapter/configSchema.js +5 -0
  104. package/esm/data_adapters/dataAdapterCache.d.ts +25 -13
  105. package/esm/data_adapters/dataAdapterCache.js +68 -24
  106. package/esm/data_adapters/getFeatureAdapter.d.ts +9 -0
  107. package/esm/data_adapters/getFeatureAdapter.js +17 -0
  108. package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +2 -0
  109. package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.js +2 -0
  110. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +40 -6
  111. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +56 -8
  112. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +3 -3
  113. package/esm/pluggableElementTypes/models/BaseTrackModel.js +7 -6
  114. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +2 -0
  115. package/esm/pluggableElementTypes/models/BaseViewModel.js +2 -0
  116. package/esm/pluggableElementTypes/models/InternetAccountModel.d.ts +3 -0
  117. package/esm/pluggableElementTypes/models/InternetAccountModel.js +3 -0
  118. package/esm/pluggableElementTypes/models/baseConnectionConfig.d.ts +3 -0
  119. package/esm/pluggableElementTypes/models/baseConnectionConfig.js +3 -0
  120. package/esm/pluggableElementTypes/models/baseInternetAccountConfig.d.ts +3 -1
  121. package/esm/pluggableElementTypes/models/baseInternetAccountConfig.js +3 -1
  122. package/esm/pluggableElementTypes/models/baseTrackConfig.js +9 -1
  123. package/esm/pluggableElementTypes/models/components/SaveTrackData.js +2 -2
  124. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.d.ts +1 -1
  125. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.js +1 -1
  126. package/esm/pluginDefinitions.d.ts +7 -0
  127. package/esm/pluginDefinitions.js +20 -0
  128. package/esm/rpc/RpcRegistry.d.ts +0 -10
  129. package/esm/rpc/byteBudget.d.ts +8 -0
  130. package/esm/rpc/byteBudget.js +13 -0
  131. package/esm/rpc/configSchema.d.ts +2 -0
  132. package/esm/rpc/configSchema.js +3 -1
  133. package/esm/rpc/coreRpcMethods.d.ts +0 -1
  134. package/esm/rpc/coreRpcMethods.js +0 -1
  135. package/esm/rpc/methods/CoreGetEncodedLayers.d.ts +2 -2
  136. package/esm/rpc/methods/CoreGetEncodedLayers.js +7 -5
  137. package/esm/rpc/methods/layerFeatures.d.ts +9 -6
  138. package/esm/rpc/methods/layerFeatures.js +21 -5
  139. package/esm/ui/ActionLink.d.ts +3 -2
  140. package/esm/ui/ActionLink.js +4 -2
  141. package/esm/ui/AddCustomPluginDialog.d.ts +3 -2
  142. package/esm/ui/AddCustomPluginDialog.js +6 -4
  143. package/esm/ui/BaseTooltip.d.ts +3 -2
  144. package/esm/ui/BaseTooltip.js +4 -2
  145. package/esm/ui/CascadingMenu.js +14 -12
  146. package/esm/ui/CascadingMenuButton.d.ts +2 -2
  147. package/esm/ui/CascadingMenuButton.js +5 -4
  148. package/esm/ui/CascadingMenuHelpDialog.d.ts +3 -2
  149. package/esm/ui/CascadingMenuHelpDialog.js +4 -2
  150. package/esm/ui/CascadingMenuHelpIconButton.d.ts +4 -3
  151. package/esm/ui/CascadingMenuHelpIconButton.js +9 -5
  152. package/esm/ui/ColorPicker.d.ts +5 -4
  153. package/esm/ui/ColorPicker.js +6 -4
  154. package/esm/ui/ContextMenu.d.ts +1 -1
  155. package/esm/ui/ContextMenu.js +1 -1
  156. package/esm/ui/CopyToClipboardButton.d.ts +3 -2
  157. package/esm/ui/CopyToClipboardButton.js +4 -2
  158. package/esm/ui/Crosshairs.js +13 -10
  159. package/esm/ui/DOMPurifySanitizedHTML.d.ts +3 -2
  160. package/esm/ui/DOMPurifySanitizedHTML.js +4 -2
  161. package/esm/ui/DataGridFlexContainer.d.ts +3 -2
  162. package/esm/ui/DataGridFlexContainer.js +4 -2
  163. package/esm/ui/Dialog.d.ts +1 -1
  164. package/esm/ui/Dialog.js +5 -4
  165. package/esm/ui/DropDownMenu.js +2 -2
  166. package/esm/ui/EditableTypography.d.ts +1 -1
  167. package/esm/ui/EditableTypography.js +3 -2
  168. package/esm/ui/ErrorActions.d.ts +3 -2
  169. package/esm/ui/ErrorActions.js +4 -2
  170. package/esm/ui/ErrorBanner.d.ts +2 -2
  171. package/esm/ui/ErrorBanner.js +3 -2
  172. package/esm/ui/ErrorBar.d.ts +3 -2
  173. package/esm/ui/ErrorBar.js +4 -2
  174. package/esm/ui/ErrorMessage.d.ts +3 -2
  175. package/esm/ui/ErrorMessage.js +4 -2
  176. package/esm/ui/ErrorMessageStackTraceContents.d.ts +3 -2
  177. package/esm/ui/ErrorMessageStackTraceContents.js +4 -2
  178. package/esm/ui/ErrorMessageStackTraceDialog.d.ts +3 -2
  179. package/esm/ui/ErrorMessageStackTraceDialog.js +4 -2
  180. package/esm/ui/ErrorOverlay.d.ts +3 -2
  181. package/esm/ui/ErrorOverlay.js +4 -2
  182. package/esm/ui/ExportSvgDialog.d.ts +3 -2
  183. package/esm/ui/ExportSvgDialog.js +4 -2
  184. package/esm/ui/ExternalLink.d.ts +2 -1
  185. package/esm/ui/ExternalLink.js +4 -2
  186. package/esm/ui/FactoryResetDialog.d.ts +3 -2
  187. package/esm/ui/FactoryResetDialog.js +4 -2
  188. package/esm/ui/FatalErrorDialog.d.ts +3 -2
  189. package/esm/ui/FatalErrorDialog.js +6 -4
  190. package/esm/ui/FileDropZone.d.ts +3 -2
  191. package/esm/ui/FileDropZone.js +4 -2
  192. package/esm/ui/FileSelector/LocalFileChooser.js +4 -4
  193. package/esm/ui/FileSelector/LocationInput.d.ts +3 -2
  194. package/esm/ui/FileSelector/LocationInput.js +4 -2
  195. package/esm/ui/FileSelector/SourceTypeSelector.d.ts +3 -2
  196. package/esm/ui/FileSelector/SourceTypeSelector.js +8 -6
  197. package/esm/ui/GpuFallbackButton.d.ts +3 -2
  198. package/esm/ui/GpuFallbackButton.js +4 -2
  199. package/esm/ui/HoverMenu.d.ts +2 -2
  200. package/esm/ui/HoverMenu.js +7 -3
  201. package/esm/ui/HoverTooltip.d.ts +3 -2
  202. package/esm/ui/HoverTooltip.js +4 -2
  203. package/esm/ui/Icons.d.ts +5 -5
  204. package/esm/ui/Icons.js +11 -10
  205. package/esm/ui/InlineMenuControls.d.ts +2 -2
  206. package/esm/ui/InlineMenuControls.js +4 -3
  207. package/esm/ui/JexlFilterRowEditors.d.ts +4 -4
  208. package/esm/ui/JexlFilterRowEditors.js +9 -8
  209. package/esm/ui/LabeledCheckbox.d.ts +3 -2
  210. package/esm/ui/LabeledCheckbox.js +4 -2
  211. package/esm/ui/LazyBaseTooltip.d.ts +12 -3
  212. package/esm/ui/LazyBaseTooltip.js +4 -2
  213. package/esm/ui/LegendSwatchGlyph.js +1 -0
  214. package/esm/ui/LoadingDots.d.ts +2 -1
  215. package/esm/ui/LoadingDots.js +4 -2
  216. package/esm/ui/LoadingEllipses.d.ts +5 -2
  217. package/esm/ui/LoadingEllipses.js +5 -3
  218. package/esm/ui/LoadingOverlay.d.ts +3 -2
  219. package/esm/ui/LoadingOverlay.js +4 -2
  220. package/esm/ui/LoadingProgress.d.ts +3 -2
  221. package/esm/ui/LoadingProgress.js +4 -2
  222. package/esm/ui/Logo.d.ts +2 -2
  223. package/esm/ui/Logo.js +9 -8
  224. package/esm/ui/MenuItemChevron.d.ts +2 -2
  225. package/esm/ui/MenuItemChevron.js +3 -2
  226. package/esm/ui/MenuItemEndDecoration.d.ts +2 -2
  227. package/esm/ui/MenuItemEndDecoration.js +3 -2
  228. package/esm/ui/MenuItemTrailing.d.ts +2 -2
  229. package/esm/ui/MenuItemTrailing.js +7 -6
  230. package/esm/ui/MenuTypes.d.ts +21 -1
  231. package/esm/ui/MenuTypes.js +20 -0
  232. package/esm/ui/MonospaceTextField.d.ts +3 -2
  233. package/esm/ui/MonospaceTextField.js +4 -2
  234. package/esm/ui/NumberTextField.d.ts +2 -2
  235. package/esm/ui/NumberTextField.js +4 -2
  236. package/esm/ui/PaletteContext.d.ts +11 -9
  237. package/esm/ui/PaletteContext.js +33 -18
  238. package/esm/ui/PluginStoreCard.d.ts +3 -2
  239. package/esm/ui/PluginStoreCard.js +4 -2
  240. package/esm/ui/PopoverPicker.d.ts +3 -2
  241. package/esm/ui/PopoverPicker.js +4 -2
  242. package/esm/ui/PrerenderedCanvas.d.ts +2 -2
  243. package/esm/ui/PrerenderedCanvas.js +3 -2
  244. package/esm/ui/RedErrorMessageBox.d.ts +3 -2
  245. package/esm/ui/RedErrorMessageBox.js +4 -2
  246. package/esm/ui/RefNameAutocomplete/EndAdornment.d.ts +3 -2
  247. package/esm/ui/RefNameAutocomplete/EndAdornment.js +4 -2
  248. package/esm/ui/RefNameAutocomplete/HelpDialog.d.ts +3 -2
  249. package/esm/ui/RefNameAutocomplete/HelpDialog.js +4 -2
  250. package/esm/ui/ReplaceCurrentViewButton.d.ts +3 -2
  251. package/esm/ui/ReplaceCurrentViewButton.js +4 -2
  252. package/esm/ui/ResizeHandle.d.ts +2 -2
  253. package/esm/ui/ResizeHandle.js +3 -2
  254. package/esm/ui/SanitizedHTML.d.ts +3 -2
  255. package/esm/ui/SanitizedHTML.js +6 -4
  256. package/esm/ui/ScrollChrome.d.ts +3 -2
  257. package/esm/ui/ScrollChrome.js +4 -2
  258. package/esm/ui/ScrollEdgeShadow.d.ts +2 -2
  259. package/esm/ui/ScrollEdgeShadow.js +2 -2
  260. package/esm/ui/SessionJsonPanel.d.ts +3 -2
  261. package/esm/ui/SessionJsonPanel.js +4 -2
  262. package/esm/ui/ShareLinkField.d.ts +3 -2
  263. package/esm/ui/ShareLinkField.js +4 -2
  264. package/esm/ui/SingleSlider.d.ts +2 -2
  265. package/esm/ui/SingleSlider.js +4 -2
  266. package/esm/ui/SliderTooltip.d.ts +2 -1
  267. package/esm/ui/SliderTooltip.js +4 -2
  268. package/esm/ui/SnackbarContents.d.ts +3 -2
  269. package/esm/ui/SnackbarContents.js +4 -2
  270. package/esm/ui/SnackbarModel.d.ts +2 -0
  271. package/esm/ui/SnackbarModel.js +2 -0
  272. package/esm/ui/StackTraceButton.d.ts +3 -2
  273. package/esm/ui/StackTraceButton.js +4 -2
  274. package/esm/ui/StatusProgressBar.d.ts +3 -2
  275. package/esm/ui/StatusProgressBar.js +4 -2
  276. package/esm/ui/SubmitForm.d.ts +2 -1
  277. package/esm/ui/SubmitForm.js +4 -2
  278. package/esm/ui/SvgColorLegend.d.ts +3 -4
  279. package/esm/ui/SvgColorLegend.js +27 -18
  280. package/esm/ui/TagTextField.d.ts +2 -2
  281. package/esm/ui/TagTextField.js +4 -2
  282. package/esm/ui/ViewLoadingScreen.d.ts +3 -2
  283. package/esm/ui/ViewLoadingScreen.js +4 -2
  284. package/esm/ui/colorScale.d.ts +5 -1
  285. package/esm/ui/colorScale.js +12 -10
  286. package/esm/ui/colors.d.ts +3 -3
  287. package/esm/ui/colors.js +7 -7
  288. package/esm/ui/filterMenuItems.d.ts +10 -31
  289. package/esm/ui/filterMenuItems.js +13 -14
  290. package/esm/ui/index.d.ts +1 -1
  291. package/esm/ui/index.js +1 -1
  292. package/esm/ui/launchTargetsMenuItem.js +9 -13
  293. package/esm/ui/legendMenuItem.d.ts +4 -4
  294. package/esm/ui/legendMenuItem.js +4 -4
  295. package/esm/ui/menuItemAdornment.d.ts +1 -1
  296. package/esm/ui/menuItemAdornment.js +1 -1
  297. package/esm/ui/menuItems.d.ts +1 -1
  298. package/esm/ui/menuItems.js +1 -1
  299. package/esm/ui/menuLabels.d.ts +2 -2
  300. package/esm/ui/menuLabels.js +2 -2
  301. package/esm/ui/palette.d.ts +2 -2
  302. package/esm/ui/palette.js +10 -10
  303. package/esm/ui/radioSubMenu.d.ts +5 -3
  304. package/esm/ui/radioSubMenu.js +2 -2
  305. package/esm/ui/rampKey.d.ts +15 -0
  306. package/esm/ui/rampKey.js +17 -0
  307. package/esm/ui/showSubMenu.d.ts +0 -5
  308. package/esm/ui/showSubMenu.js +6 -15
  309. package/esm/ui/theme.d.ts +2 -2
  310. package/esm/ui/theme.js +1 -1
  311. package/esm/ui/useAssemblySelection.d.ts +2 -0
  312. package/esm/ui/useMouseTracking.d.ts +8 -20
  313. package/esm/ui/useMouseTracking.js +23 -62
  314. package/esm/ui/usePlacedMenuFocus.d.ts +19 -0
  315. package/esm/ui/usePlacedMenuFocus.js +28 -0
  316. package/esm/util/Base1DViewModel.d.ts +5 -3
  317. package/esm/util/Base1DViewModel.js +5 -3
  318. package/esm/util/SvgCanvas.js +1 -1
  319. package/esm/util/aggregateFieldName.d.ts +1 -10
  320. package/esm/util/aggregateFieldName.js +1 -8
  321. package/esm/util/analytics.d.ts +4 -6
  322. package/esm/util/analytics.js +143 -12
  323. package/esm/util/bezierConnector.d.ts +20 -0
  324. package/esm/util/bezierConnector.js +34 -100
  325. package/esm/util/cacheBudgets.d.ts +3 -0
  326. package/esm/util/cacheBudgets.js +3 -0
  327. package/esm/util/categoricalField.d.ts +2 -2
  328. package/esm/util/categoricalField.js +3 -3
  329. package/esm/util/color/index.d.ts +1 -1
  330. package/esm/util/color/index.js +2 -2
  331. package/esm/util/color-bits/bit.js +1 -1
  332. package/esm/util/color-bits/parse.js +6 -6
  333. package/esm/util/colorBits.d.ts +15 -4
  334. package/esm/util/colorBits.js +38 -15
  335. package/esm/util/colorRamp.d.ts +3 -3
  336. package/esm/util/colorRamp.js +14 -2
  337. package/esm/util/colorScale.d.ts +114 -20
  338. package/esm/util/colorScale.js +124 -26
  339. package/esm/util/colorSchemes.d.ts +6 -4
  340. package/esm/util/colorSchemes.js +6 -3
  341. package/esm/util/createSvgRasterCanvas.d.ts +14 -1
  342. package/esm/util/createSvgRasterCanvas.js +36 -12
  343. package/esm/util/diagonalizeRegions.js +18 -9
  344. package/esm/util/featureTransforms.d.ts +2 -2
  345. package/esm/util/featureTransforms.js +85 -135
  346. package/esm/util/fileHandleStore.js +5 -0
  347. package/esm/util/groupKeys.d.ts +5 -4
  348. package/esm/util/groupKeys.js +15 -9
  349. package/esm/util/index.js +1 -1
  350. package/esm/util/installFetch.d.ts +2 -2
  351. package/esm/util/installPrerequisiteFetch.d.ts +8 -3
  352. package/esm/util/installPrerequisiteFetch.js +9 -7
  353. package/esm/util/io/RemoteFileWithRangeCache.d.ts +1 -1
  354. package/esm/util/io/RemoteFileWithRangeCache.js +1 -1
  355. package/esm/util/jexl.js +1 -1
  356. package/esm/util/layouts/GranularRectLayout.d.ts +19 -3
  357. package/esm/util/layouts/GranularRectLayout.js +57 -34
  358. package/esm/util/leadingEdgeAutorun.d.ts +9 -1
  359. package/esm/util/leadingEdgeAutorun.js +5 -2
  360. package/esm/util/markEncoding.d.ts +10 -8
  361. package/esm/util/markEncoding.js +50 -12
  362. package/esm/util/markEncodingTypes.d.ts +74 -20
  363. package/esm/util/originCut.d.ts +14 -0
  364. package/esm/util/originCut.js +19 -0
  365. package/esm/util/paintLayer.d.ts +1 -1
  366. package/esm/util/paintLayer.js +4 -3
  367. package/esm/util/pathSeries.d.ts +18 -0
  368. package/esm/util/pathSeries.js +143 -0
  369. package/esm/util/pressOwner.d.ts +20 -0
  370. package/esm/util/pressOwner.js +26 -0
  371. package/esm/util/quantileExtent.d.ts +3 -3
  372. package/esm/util/quantileExtent.js +3 -3
  373. package/esm/util/rowStackGeometry.d.ts +1 -1
  374. package/esm/util/rowStackGeometry.js +1 -1
  375. package/esm/util/sessionActivity.d.ts +36 -0
  376. package/esm/util/sessionActivity.js +88 -0
  377. package/esm/util/stepOutputs.d.ts +165 -0
  378. package/esm/util/stepOutputs.js +201 -0
  379. package/esm/util/stepTables.d.ts +7 -3
  380. package/esm/util/stepTables.js +86 -3
  381. package/esm/util/thresholdScale.d.ts +1 -1
  382. package/esm/util/thresholdScale.js +1 -1
  383. package/esm/util/tracks.js +1 -1
  384. package/esm/util/usePanZoom.js +4 -10
  385. package/esm/util/windowStep.d.ts +6 -0
  386. package/esm/util/windowStep.js +153 -0
  387. package/package.json +23 -15
  388. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +0 -40
  389. package/esm/data_adapters/BaseAdapter/featureDensity.js +0 -31
  390. package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +0 -11
  391. package/esm/rpc/methods/CoreGetFeatureDensity.js +0 -22
@@ -0,0 +1,17 @@
1
+ import { cssColorToHex } from '../util/colorBits.js';
2
+ import { rampLabels } from './colorScale.js';
3
+ /**
4
+ * A ramp's bar as columns, for a host that draws the key itself, such as R
5
+ * through V8: each stop's `offset`, `#rrggbb` `color` and `opacity`, and the
6
+ * end labels the on-screen bar prints.
7
+ */
8
+ export function rampKeyOf(scale) {
9
+ return {
10
+ id: scale.id,
11
+ title: scale.title ?? '',
12
+ ...rampLabels(scale),
13
+ offset: scale.stops.map(stop => stop.offset),
14
+ color: scale.stops.map(stop => cssColorToHex(stop.color)),
15
+ opacity: scale.stops.map(stop => stop.opacity ?? 1),
16
+ };
17
+ }
@@ -6,11 +6,6 @@ import type { MenuItem } from './MenuTypes.ts';
6
6
  * multi-row painting with no legend) drops the row rather than opening an empty
7
7
  * submenu.
8
8
  *
9
- * One helper because this was eleven hand-written literals that had already
10
- * drifted three ways: the wiggle family said `'Show'` where everyone else said
11
- * `'Show...'`, only some set the redundant `type: 'subMenu'`, and only the
12
- * wiggle family omitted the empty submenu.
13
- *
14
9
  * Not exported from `ui/menuItems.ts`: the icon is a value import, and that
15
10
  * entry is the React-free one (see its header). Import this module directly —
16
11
  * `@jbrowse/core/ui/showSubMenu` — which costs one icon rather than the
@@ -1,4 +1,5 @@
1
1
  import VisibilityIcon from '@mui/icons-material/Visibility';
2
+ import { subMenuIfAny } from './MenuTypes.js';
2
3
  /**
3
4
  * The "Show..." submenu every display groups its visibility toggles under, and
4
5
  * the empty-omit that goes with it: a display whose toggles are all
@@ -6,25 +7,15 @@ import VisibilityIcon from '@mui/icons-material/Visibility';
6
7
  * multi-row painting with no legend) drops the row rather than opening an empty
7
8
  * submenu.
8
9
  *
9
- * One helper because this was eleven hand-written literals that had already
10
- * drifted three ways: the wiggle family said `'Show'` where everyone else said
11
- * `'Show...'`, only some set the redundant `type: 'subMenu'`, and only the
12
- * wiggle family omitted the empty submenu.
13
- *
14
10
  * Not exported from `ui/menuItems.ts`: the icon is a value import, and that
15
11
  * entry is the React-free one (see its header). Import this module directly —
16
12
  * `@jbrowse/core/ui/showSubMenu` — which costs one icon rather than the
17
13
  * `@jbrowse/core/ui` barrel's ~80 Material components.
18
14
  */
19
15
  export function makeShowSubMenu(items) {
20
- return items.length
21
- ? [
22
- {
23
- label: 'Show...',
24
- icon: VisibilityIcon,
25
- type: 'subMenu',
26
- subMenu: items,
27
- },
28
- ]
29
- : [];
16
+ return subMenuIfAny({
17
+ label: 'Show...',
18
+ icon: VisibilityIcon,
19
+ subMenu: items,
20
+ });
30
21
  }
package/esm/ui/theme.d.ts CHANGED
@@ -14,9 +14,9 @@ type FramesOptions = FrameTuple<PaletteColorOptions>;
14
14
  declare module '@mui/material/styles' {
15
15
  interface Palette extends StringColors {
16
16
  /**
17
- * The primary colour where it marks something on the page's own ground,
17
+ * The primary color where it marks something on the page's own ground,
18
18
  * such as a checked box or a selected row. `primary.main` in light mode,
19
- * and the secondary text colour in dark mode, where a midnight primary
19
+ * and the secondary text color in dark mode, where a midnight primary
20
20
  * vanishes
21
21
  */
22
22
  accent: string;
package/esm/ui/theme.js CHANGED
@@ -67,7 +67,7 @@ const baseThemeOptions = {
67
67
  components: {
68
68
  MuiAppBar: {
69
69
  // JBrowse's header keeps its brand in dark mode; MUI's default is to
70
- // flatten it to the paper colour. A property of the app rather than of
70
+ // flatten it to the paper color. A property of the app rather than of
71
71
  // one palette — it used to sit on `darkStock` alone, so the theme a
72
72
  // reader reaches by picking Dark over the default palette lost the
73
73
  // header the old dark theme had. MUI reads this only in dark mode.
@@ -74,6 +74,7 @@ export declare function useAssemblySelection(session: AbstractSessionModel, loca
74
74
  getCanonicalRefName2(refName: string): string;
75
75
  isValidRefName(refName: string): boolean;
76
76
  } & {
77
+ isCircularRefName(refName: string): boolean;
77
78
  getRefNamePosition(refName: string): number | undefined;
78
79
  getAliasesForRefName(refName: string): string[];
79
80
  getRefNameMapForAdapter(adapterConf: {
@@ -141,6 +142,7 @@ export declare function useAssemblySelection(session: AbstractSessionModel, loca
141
142
  getCanonicalRefName2(refName: string): string;
142
143
  isValidRefName(refName: string): boolean;
143
144
  } & {
145
+ isCircularRefName(refName: string): boolean;
144
146
  getRefNamePosition(refName: string): number | undefined;
145
147
  getAliasesForRefName(refName: string): string[];
146
148
  getRefNameMapForAdapter(adapterConf: {
@@ -20,28 +20,16 @@ export declare function useClearTrackedPointer(): () => void;
20
20
  * Container-relative mouse position for the overlays that follow the pointer
21
21
  * (`Crosshairs`, tooltips), coalesced to one update per frame.
22
22
  *
23
- * The position is measured against the box of whatever element the handlers are
24
- * bound to, which is what the overlays are positioned in — off `currentTarget`,
25
- * so there is no ref to pass and no way to bind the two to different elements.
23
+ * The position is measured against the box of the element the handlers are
24
+ * bound to, off `currentTarget`, which is what the overlays are positioned in.
26
25
  * A display that also hit-tests takes `onMove`, so its hit and its guides come
27
- * off one measurement in one frame instead of two pointer paths that have to
28
- * agree.
26
+ * off one measurement in one frame.
29
27
  *
30
- * **It returns a `mouseTracker` rather than the position, and that is the
31
- * load-bearing part.** Its one caller is `DisplayChromeBase`, which owns the
32
- * container the handlers bind to — so if the position were state here, every
33
- * mouse move would re-render the chrome itself (re-running
34
- * `useRenderingBackend`), the status container with a fresh inline `style`
35
- * object, all three overlays, and only then the body that actually wanted the
36
- * coordinate. That is a whole display's chrome repainting because the cursor
37
- * moved a pixel over it; it cost a full document `Layout` plus three `Paint`s
38
- * per mousemove on the wiggle displays, back when each display called this hook
39
- * itself and every one of them had it.
40
- *
41
- * So the position is published instead, and whoever wants it calls
42
- * `useMouseState(mouseTracker)` — from inside the chrome's body, where the
43
- * overlays live. Re-rendering then starts at the component that reads it.
44
- * Passing the tracker down a prop is free; passing `mouseState` down is the bug.
28
+ * It returns a `mouseTracker` and not the position: the caller is
29
+ * `DisplayChromeBase`, and position held as state there would re-render the
30
+ * whole chrome on every mouse move. Whoever draws at the cursor calls
31
+ * `useMouseState(mouseTracker)`, so re-rendering starts at that component.
32
+ * Pass the tracker down, never the position.
45
33
  */
46
34
  export declare function useMouseTracking(onMove?: (state?: MouseState) => void): {
47
35
  mouseTracker: MouseTracker;
@@ -27,16 +27,11 @@ function createMouseStore() {
27
27
  /**
28
28
  * Drop the tracked pointer, published by whoever bound the handlers.
29
29
  *
30
- * `mouseleave` reports the pointer leaving an element, and the browser decides
31
- * that by comparing the hover chain before a move to the chain after it. A menu
32
- * portalled to the body opens under the cursor with no move at all, and closing
33
- * it detaches the chain's nodes — so hover restarts at `body` and the display
34
- * the menu covered is never told anything again. Its overlays then keep drawing
35
- * at the coordinate the pointer had when the menu opened, wherever the pointer
36
- * has since gone.
37
- *
38
- * `ContextMenu` calls this on close, which is why the default is a no-op: a menu
39
- * raised outside a display's chrome has no tracked pointer to drop.
30
+ * A menu portalled to the body opens under the cursor with no move, and
31
+ * closing it detaches the hover chain, so the display it covered never gets a
32
+ * `mouseleave` and its overlays keep drawing where the menu opened.
33
+ * `ContextMenu` calls this on close; the default is a no-op for a menu raised
34
+ * outside a display's chrome.
40
35
  */
41
36
  const ClearTrackedPointerContext = createContext(() => { });
42
37
  export const ClearTrackedPointerProvider = ClearTrackedPointerContext.Provider;
@@ -47,44 +42,25 @@ export function useClearTrackedPointer() {
47
42
  * Container-relative mouse position for the overlays that follow the pointer
48
43
  * (`Crosshairs`, tooltips), coalesced to one update per frame.
49
44
  *
50
- * The position is measured against the box of whatever element the handlers are
51
- * bound to, which is what the overlays are positioned in — off `currentTarget`,
52
- * so there is no ref to pass and no way to bind the two to different elements.
45
+ * The position is measured against the box of the element the handlers are
46
+ * bound to, off `currentTarget`, which is what the overlays are positioned in.
53
47
  * A display that also hit-tests takes `onMove`, so its hit and its guides come
54
- * off one measurement in one frame instead of two pointer paths that have to
55
- * agree.
56
- *
57
- * **It returns a `mouseTracker` rather than the position, and that is the
58
- * load-bearing part.** Its one caller is `DisplayChromeBase`, which owns the
59
- * container the handlers bind to — so if the position were state here, every
60
- * mouse move would re-render the chrome itself (re-running
61
- * `useRenderingBackend`), the status container with a fresh inline `style`
62
- * object, all three overlays, and only then the body that actually wanted the
63
- * coordinate. That is a whole display's chrome repainting because the cursor
64
- * moved a pixel over it; it cost a full document `Layout` plus three `Paint`s
65
- * per mousemove on the wiggle displays, back when each display called this hook
66
- * itself and every one of them had it.
48
+ * off one measurement in one frame.
67
49
  *
68
- * So the position is published instead, and whoever wants it calls
69
- * `useMouseState(mouseTracker)` — from inside the chrome's body, where the
70
- * overlays live. Re-rendering then starts at the component that reads it.
71
- * Passing the tracker down a prop is free; passing `mouseState` down is the bug.
50
+ * It returns a `mouseTracker` and not the position: the caller is
51
+ * `DisplayChromeBase`, and position held as state there would re-render the
52
+ * whole chrome on every mouse move. Whoever draws at the cursor calls
53
+ * `useMouseState(mouseTracker)`, so re-rendering starts at that component.
54
+ * Pass the tracker down, never the position.
72
55
  */
73
56
  export function useMouseTracking(onMove) {
74
57
  const rafRef = useRef(undefined);
75
58
  const storeRef = useRef(undefined);
76
59
  storeRef.current ??= createMouseStore();
77
60
  const store = storeRef.current;
78
- // Reached through a ref rather than captured, so `handleMouseLeave` below can
79
- // be identity-stable — one of its callers is an effect, and a handler that
80
- // changed identity every render would make that effect re-run every render.
81
- // Reading the latest is also the better answer for the frame callback, which
82
- // runs after the render whose closure scheduled it.
83
- //
84
- // Written in an effect rather than during render: a render React discards must
85
- // not leave this pointing at a callback from it. Nothing can read it before
86
- // the first commit — both users are event/effect callbacks — and `useRef`'s
87
- // initial value covers the first commit itself.
61
+ // Reached through a ref so `handleMouseLeave` is identity-stable (an effect
62
+ // depends on it), and written in an effect so a render React discards cannot
63
+ // leave it pointing at that render's callback.
88
64
  const onMoveRef = useRef(onMove);
89
65
  useEffect(() => {
90
66
  onMoveRef.current = onMove;
@@ -92,11 +68,10 @@ export function useMouseTracking(onMove) {
92
68
  /**
93
69
  * Drop the published position and tell `onMove` the pointer is gone.
94
70
  *
95
- * Bound as the container's `onMouseLeave` — and called directly for the two
96
- * cases `mouseleave` cannot report: the container being *removed* rather than
97
- * left, and a portalled menu closing over it. `DisplayChromeBase` makes both
98
- * calls, the second by publishing this on `ClearTrackedPointerProvider`.
99
- * Identity-stable for both.
71
+ * Bound as the container's `onMouseLeave`, and called directly for the three
72
+ * cases `mouseleave` cannot report: the container being removed, a portalled
73
+ * menu closing over it, and the pointer moving onto a portalled overlay.
74
+ * `DisplayChromeBase` makes all three calls. Identity-stable.
100
75
  */
101
76
  const handleMouseLeave = useCallback(() => {
102
77
  if (rafRef.current) {
@@ -107,28 +82,14 @@ export function useMouseTracking(onMove) {
107
82
  onMoveRef.current?.(undefined);
108
83
  }, [store]);
109
84
  const handleMouseMove = (event) => {
110
- // An overlay portaled out of the container still *bubbles* its React events
111
- // here, even though its DOM node is not a descendant — so the coordinate
112
- // would be measured against a box the pointer isn't in. HiC guarded this by
113
- // hand (its resolution dropdown and legend portal); it is a hazard for any
114
- // display with a portaled overlay, and several have one, so the guard lives
115
- // here and applies to all of them. Treated as a leave: the pointer is over
116
- // something else, and the guides should drop rather than freeze.
117
- const { target } = event;
118
- if (target instanceof Node && !event.currentTarget.contains(target)) {
119
- handleMouseLeave();
120
- return;
121
- }
122
85
  if (rafRef.current) {
123
86
  cancelAnimationFrame(rafRef.current);
124
87
  }
125
88
  const clientX = event.clientX;
126
89
  const clientY = event.clientY;
127
- // Captured here rather than read in the frame: React clears `currentTarget`
128
- // once the handler returns. `isConnected` then stands in for the ref check
129
- // this used to do — a display unmounted between the move and the frame
130
- // measures as a zero rect, and would publish the client point as if the
131
- // pointer were at the origin of a box that is gone.
90
+ // Captured here: React clears `currentTarget` once the handler returns. A
91
+ // display unmounted before the frame measures as a zero rect, hence the
92
+ // `isConnected` check.
132
93
  const container = event.currentTarget;
133
94
  rafRef.current = requestAnimationFrame(() => {
134
95
  if (container.isConnected) {
@@ -0,0 +1,19 @@
1
+ import type { PopoverActions } from '@mui/material';
2
+ /**
3
+ * Props that move a MUI Menu's opening focus to after the menu is placed.
4
+ *
5
+ * MUI focuses the first row while the menu mounts, before Popover writes the
6
+ * paper's position, so the focused row still sits at the viewport's top-left.
7
+ * Firefox scrolls every enclosing frame to reveal a focused element, so a page
8
+ * that embeds JBrowse in an iframe jumped to the frame's top whenever a menu
9
+ * opened with that top scrolled out of view.
10
+ *
11
+ * The `onEntering` returned here places the paper through Popover's
12
+ * `updatePosition`, then focuses the first row without scrolling anything.
13
+ */
14
+ export declare function usePlacedMenuFocus(): {
15
+ action: import("react").RefObject<PopoverActions | null>;
16
+ autoFocus: boolean;
17
+ disableAutoFocus: boolean;
18
+ onEntering: (paper: HTMLElement) => void;
19
+ };
@@ -0,0 +1,28 @@
1
+ import { useRef } from 'react';
2
+ const FIRST_ROW = '[role^="menuitem"]:not(.Mui-disabled)';
3
+ /**
4
+ * Props that move a MUI Menu's opening focus to after the menu is placed.
5
+ *
6
+ * MUI focuses the first row while the menu mounts, before Popover writes the
7
+ * paper's position, so the focused row still sits at the viewport's top-left.
8
+ * Firefox scrolls every enclosing frame to reveal a focused element, so a page
9
+ * that embeds JBrowse in an iframe jumped to the frame's top whenever a menu
10
+ * opened with that top scrolled out of view.
11
+ *
12
+ * The `onEntering` returned here places the paper through Popover's
13
+ * `updatePosition`, then focuses the first row without scrolling anything.
14
+ */
15
+ export function usePlacedMenuFocus() {
16
+ const action = useRef(null);
17
+ return {
18
+ action,
19
+ autoFocus: false,
20
+ disableAutoFocus: true,
21
+ onEntering: (paper) => {
22
+ action.current?.updatePosition();
23
+ paper
24
+ .querySelector(FIRST_ROW)
25
+ ?.focus({ preventScroll: true });
26
+ },
27
+ };
28
+ }
@@ -4,9 +4,11 @@ import type { Instance } from '@jbrowse/mobx-state-tree';
4
4
  /**
5
5
  * #stateModel Base1DView
6
6
  * #category general
7
- * used in non-lgv view representations of a 1d view e.g. the two axes of the
8
- * dotplot use this. categorized General rather than View because it is not a
9
- * pluggable view type, which the name-suffix heuristic would otherwise assume
7
+ * Holds a one-dimensional axis of displayed regions, with its zoom and scroll
8
+ * offset, for views other than the linear genome view, such as the two axes of
9
+ * the dotplot.
10
+ *
11
+ * Its page sits under General because it is not a pluggable view type.
10
12
  */
11
13
  declare const Base1DView: import("@jbrowse/mobx-state-tree").IModelType<{
12
14
  id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
@@ -7,9 +7,11 @@ import { ElementId } from './types/mst.js';
7
7
  /**
8
8
  * #stateModel Base1DView
9
9
  * #category general
10
- * used in non-lgv view representations of a 1d view e.g. the two axes of the
11
- * dotplot use this. categorized General rather than View because it is not a
12
- * pluggable view type, which the name-suffix heuristic would otherwise assume
10
+ * Holds a one-dimensional axis of displayed regions, with its zoom and scroll
11
+ * offset, for views other than the linear genome view, such as the two axes of
12
+ * the dotplot.
13
+ *
14
+ * Its page sits under General because it is not a pluggable view type.
13
15
  */
14
16
  const Base1DView = types
15
17
  .model('Base1DView', {
@@ -175,7 +175,7 @@ export class SvgCanvas {
175
175
  // treats as the same rect anchored at `x-w`) is NOT normalized here — SVG
176
176
  // would emit `width="-w"` and silently not render. Callers must pass a
177
177
  // non-negative size; spans resolve both edges and take
178
- // `left = min(x1,x2)` / `w = abs(x2-x1)` (see render-core/CLAUDE.md), the
178
+ // `left = min(x1,x2)` / `w = abs(x2-x1)`, the
179
179
  // same convention that keeps reversed blocks correct.
180
180
  transformRect(x, y, w, h) {
181
181
  const [tx, ty] = this.transformPoint(this.a < 0 ? x + w : x, this.d < 0 ? y + h : y);
@@ -1,10 +1 @@
1
- /**
2
- * The field an aggregate op writes: `as` where named, else `count` for a
3
- * count, else `<op>_<field>`. Imports nothing, so the validator's copy of the
4
- * mark rule list carries it unchanged.
5
- */
6
- export declare function aggregateFieldName({ op, field, as, }: {
7
- op: string;
8
- field?: string;
9
- as?: string;
10
- }): string;
1
+ export { aggregateFieldName } from './stepOutputs.ts';
@@ -1,8 +1 @@
1
- /**
2
- * The field an aggregate op writes: `as` where named, else `count` for a
3
- * count, else `<op>_<field>`. Imports nothing, so the validator's copy of the
4
- * mark rule list carries it unchanged.
5
- */
6
- export function aggregateFieldName({ op, field, as, }) {
7
- return as || (op === 'count' || !field ? op : `${op}_${field}`);
8
- }
1
+ export { aggregateFieldName } from './stepOutputs.js';
@@ -1,4 +1,5 @@
1
1
  import type { AnyConfigurationModel, TrackConfigEntry } from '../configuration/index.ts';
2
+ import type { ActivitySession } from './sessionActivity.ts';
2
3
  declare global {
3
4
  interface Window {
4
5
  ga?: (...args: unknown[]) => void;
@@ -12,14 +13,10 @@ interface AnalyticsRootModel {
12
13
  name?: string;
13
14
  }[];
14
15
  };
15
- session?: {
16
- sessionTracks: {
17
- type: string;
18
- }[];
19
- views: unknown[];
20
- };
16
+ session?: ActivitySession;
21
17
  version: string;
22
18
  }
19
+ export declare function urlParamNames(search: string): string;
23
20
  type AnalyticsRootModelWithConfig = AnalyticsRootModel & {
24
21
  jbrowse: {
25
22
  configuration: AnyConfigurationModel;
@@ -27,5 +24,6 @@ type AnalyticsRootModelWithConfig = AnalyticsRootModel & {
27
24
  };
28
25
  export declare function writeAWSAnalytics(rootModel: AnalyticsRootModel, initialTimestamp: number, sessionQuery?: string | null): Promise<void>;
29
26
  export declare function writeGAAnalytics(rootModel: AnalyticsRootModel, initialTimestamp: number): Promise<void>;
27
+ export declare function writeAWSSessionEnd(): Promise<void>;
30
28
  export declare function doAnalytics(rootModel: AnalyticsRootModelWithConfig | undefined, initialTimestamp: number, initialSessionQuery: string | null | undefined): void;
31
29
  export {};
@@ -1,14 +1,58 @@
1
1
  import { effectiveRenderer, getGraphicsCapabilities, } from '@jbrowse/render-core/graphicsCapabilities';
2
2
  import { readConfObject } from '../configuration/index.js';
3
3
  import { isElectron, rIC } from '../util/index.js';
4
+ import { createSessionActivity, describeSession, tallyTypes, } from './sessionActivity.js';
4
5
  import { getConfAssemblyNamesOrNone } from './tracks.js';
6
+ const analyticsUrl = 'https://analytics.jbrowse.org/api/v1';
7
+ // Ties a page load's end reports to its start report. It lives in memory only,
8
+ // so a reload gets a new one and nothing follows a user from load to load.
9
+ let pageLoadId;
10
+ function getPageLoadId() {
11
+ pageLoadId ??=
12
+ typeof crypto.randomUUID === 'function'
13
+ ? crypto.randomUUID()
14
+ : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
15
+ return pageLoadId;
16
+ }
17
+ // Names only, and only JBrowse's own: says whether a load was a link to a
18
+ // location or a set of tracks without saying which. Read when this module
19
+ // loads, because jbrowse-web folds `loc`, `tracks` and `assembly` into a
20
+ // `session` parameter before the report goes out.
21
+ const knownUrlParams = [
22
+ 'assembly',
23
+ 'config',
24
+ 'highlight',
25
+ 'loc',
26
+ 'nav',
27
+ 'session',
28
+ 'sessionName',
29
+ 'sessionTracks',
30
+ 'tracklist',
31
+ 'tracks',
32
+ ];
33
+ export function urlParamNames(search) {
34
+ const params = new URLSearchParams(search);
35
+ return knownUrlParams.filter(name => params.has(name)).join(',');
36
+ }
37
+ const initialUrlParams = typeof window === 'undefined' ? '' : urlParamNames(window.location.search);
38
+ function sessionTrackTypeCounts(session) {
39
+ const counts = {};
40
+ for (const track of session?.sessionTracks ?? []) {
41
+ const key = `sessionTrack-types-${track.type}`;
42
+ counts[key] = (counts[key] ?? 0) + 1;
43
+ }
44
+ return counts;
45
+ }
46
+ async function send(stats, init) {
47
+ const qs = new URLSearchParams(Object.entries(stats).map(([key, value]) => [key, String(value)])).toString();
48
+ await fetch(`${analyticsUrl}?${qs}`, init);
49
+ }
5
50
  // Both writers are fire-and-forget from several call sites, so they swallow
6
51
  // their own failures rather than rejecting: a floating rejected promise trips
7
52
  // the webpack-dev-server overlay (it listens for unhandledrejection), and an
8
53
  // analytics ping is never worth interrupting a session for.
9
54
  export async function writeAWSAnalytics(rootModel, initialTimestamp, sessionQuery) {
10
55
  try {
11
- const url = 'https://analytics.jbrowse.org/api/v1';
12
56
  const multiAssemblyTracks = rootModel.jbrowse.tracks.filter(track => getConfAssemblyNamesOrNone(track).length > 1).length;
13
57
  // The rung createGpuHal built where a display has built one by idle time,
14
58
  // else the ladder's prediction with any page-wide pin applied — so a
@@ -25,8 +69,11 @@ export async function writeAWSAnalytics(rootModel, initialTimestamp, sessionQuer
25
69
  const softwareRendering = capabilities.softwareWebgl ?? 'unknown';
26
70
  const { jbrowse: config, session, version: ver } = rootModel;
27
71
  const { tracks, assemblies, plugins } = config;
72
+ const shape = describeSession(session);
28
73
  // stats to be recorded in db
29
74
  const stats = {
75
+ event: 'start',
76
+ sid: getPageLoadId(),
30
77
  ver,
31
78
  'plugins-count': plugins?.length ?? 0,
32
79
  'plugin-names': plugins?.map(p => p.name).join(','),
@@ -34,6 +81,9 @@ export async function writeAWSAnalytics(rootModel, initialTimestamp, sessionQuer
34
81
  'tracks-count': tracks.length,
35
82
  'session-tracks-count': session?.sessionTracks.length ?? 0,
36
83
  'open-views': session?.views.length ?? 0,
84
+ 'view-types': tallyTypes(shape.viewTypes),
85
+ 'open-track-types': tallyTypes(shape.trackTypes),
86
+ 'url-params': initialUrlParams,
37
87
  'synteny-tracks-count': multiAssemblyTracks,
38
88
  // No `saved-sessions-count`: it counted localStorage keys matching
39
89
  // `localSaved-`, a format nothing has written since autosaved sessions
@@ -62,14 +112,8 @@ export async function writeAWSAnalytics(rootModel, initialTimestamp, sessionQuer
62
112
  const key = `track-types-${track.type}`;
63
113
  trackTypeCounts[key] = (trackTypeCounts[key] ?? 0) + 1;
64
114
  }
65
- const sessionTrackTypeCounts = {};
66
- for (const track of session?.sessionTracks ?? []) {
67
- const key = `sessionTrack-types-${track.type}`;
68
- sessionTrackTypeCounts[key] = (sessionTrackTypeCounts[key] ?? 0) + 1;
69
- }
70
- Object.assign(stats, trackTypeCounts, sessionTrackTypeCounts);
71
- const qs = new URLSearchParams(Object.entries(stats).map(([key, value]) => [key, String(value)])).toString();
72
- await fetch(`${url}?${qs}`);
115
+ Object.assign(stats, trackTypeCounts, sessionTrackTypeCounts(session));
116
+ await send(stats);
73
117
  }
74
118
  catch (e) {
75
119
  console.warn('Failed to write analytics to AWS.', e);
@@ -109,6 +153,83 @@ export async function writeGAAnalytics(rootModel, initialTimestamp) {
109
153
  console.warn('Failed to write analytics to GA.', e);
110
154
  }
111
155
  }
156
+ // What the page load's sessions held while in use, for the end report.
157
+ const activity = createSessionActivity();
158
+ let latestRootModel;
159
+ let endReportsInstalled = false;
160
+ let endReportsSent = 0;
161
+ let lastEndSignature;
162
+ let visibleMs = 0;
163
+ let visibleSince;
164
+ let visibleMsAtLastEnd = 0;
165
+ const maxEndReports = 10;
166
+ const resendAfterVisibleMs = 60_000;
167
+ // The end report says what a session came to hold: the view, track and widget
168
+ // types open when the tab was hidden and those opened at any point before.
169
+ // A tab is hidden many times before it closes and the close itself is not
170
+ // reliably observable, so each hide sends one, numbered by `seq`, when the
171
+ // session changed or another minute was spent on the page. The last one for a
172
+ // `sid` is the session's end.
173
+ export async function writeAWSSessionEnd() {
174
+ try {
175
+ if (!activity.watching || endReportsSent >= maxEndReports) {
176
+ return;
177
+ }
178
+ const seen = activity.stats();
179
+ const signature = JSON.stringify(seen);
180
+ if (signature === lastEndSignature &&
181
+ visibleMs - visibleMsAtLastEnd < resendAfterVisibleMs) {
182
+ return;
183
+ }
184
+ lastEndSignature = signature;
185
+ visibleMsAtLastEnd = visibleMs;
186
+ endReportsSent += 1;
187
+ const stats = {
188
+ event: 'end',
189
+ sid: getPageLoadId(),
190
+ seq: endReportsSent,
191
+ duration: Math.round(performance.now() / 1000),
192
+ 'visible-time': Math.round(visibleMs / 1000),
193
+ ...seen,
194
+ electron: isElectron,
195
+ jb2: true,
196
+ };
197
+ try {
198
+ const { session, version } = latestRootModel ?? {};
199
+ stats.ver = version;
200
+ stats['session-tracks-count'] = session?.sessionTracks.length ?? 0;
201
+ Object.assign(stats, sessionTrackTypeCounts(session));
202
+ }
203
+ catch {
204
+ // root model left its state tree; the accumulated types still go out
205
+ }
206
+ // keepalive lets the request outlive the page it was sent from
207
+ await send(stats, { keepalive: true });
208
+ }
209
+ catch (e) {
210
+ console.warn('Failed to write analytics to AWS.', e);
211
+ }
212
+ }
213
+ function installEndReports() {
214
+ if (!endReportsInstalled) {
215
+ endReportsInstalled = true;
216
+ if (document.visibilityState === 'visible') {
217
+ visibleSince = performance.now();
218
+ }
219
+ document.addEventListener('visibilitychange', () => {
220
+ if (document.visibilityState === 'hidden') {
221
+ if (visibleSince !== undefined) {
222
+ visibleMs += performance.now() - visibleSince;
223
+ visibleSince = undefined;
224
+ }
225
+ void writeAWSSessionEnd();
226
+ }
227
+ else {
228
+ visibleSince = performance.now();
229
+ }
230
+ });
231
+ }
232
+ }
112
233
  // One pageview per page load, not per pluginManager. jbrowse-web rebuilds the
113
234
  // whole pluginManager (and rootModel) whenever plugins change, and StrictMode
114
235
  // builds it twice on mount — without this guard each rebuild re-pings AWS and
@@ -116,9 +237,19 @@ export async function writeGAAnalytics(rootModel, initialTimestamp) {
116
237
  // growing the document on every plugin install.
117
238
  let analyticsSent = false;
118
239
  export function doAnalytics(rootModel, initialTimestamp, initialSessionQuery) {
119
- if (rootModel &&
120
- !analyticsSent &&
121
- !readConfObject(rootModel.jbrowse.configuration, 'disableAnalytics')) {
240
+ if (!rootModel) {
241
+ return;
242
+ }
243
+ // a config that opts out stops the end reports too, whichever config or
244
+ // session started them
245
+ if (readConfObject(rootModel.jbrowse.configuration, 'disableAnalytics')) {
246
+ activity.stop();
247
+ return;
248
+ }
249
+ latestRootModel = rootModel;
250
+ activity.watch(() => rootModel.session);
251
+ installEndReports();
252
+ if (!analyticsSent) {
122
253
  analyticsSent = true;
123
254
  // writeGAAnalytics injects Google's scripts and writeAWSAnalytics probes
124
255
  // graphics capabilities, hundreds of ms of main-thread work together. Idle