@jbrowse/core 5.0.0-beta.7 → 5.0.0-beta.9

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 (379) hide show
  1. package/README.md +427 -130
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.d.ts +3 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +5 -3
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -5
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +8 -9
  6. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.js +8 -13
  7. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -1
  8. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.js +3 -3
  9. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.d.ts +8 -0
  10. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.js +24 -0
  11. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts +3 -2
  12. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.js +5 -3
  13. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.d.ts +1 -0
  14. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +1 -4
  15. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.d.ts +16 -0
  16. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +53 -0
  17. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.d.ts +0 -8
  18. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.js +0 -16
  19. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceContents.js +7 -34
  20. package/esm/BaseFeatureWidget/configSchema.d.ts +1 -1
  21. package/esm/BaseFeatureWidget/formatDetails.d.ts +13 -29
  22. package/esm/BaseFeatureWidget/formatDetails.js +46 -79
  23. package/esm/BaseFeatureWidget/index.d.ts +1 -0
  24. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +35 -28
  25. package/esm/BaseFeatureWidget/stateModelFactory.js +94 -102
  26. package/esm/BaseFeatureWidget/types.d.ts +3 -0
  27. package/esm/BaseFeatureWidget/util.d.ts +0 -3
  28. package/esm/BaseFeatureWidget/util.js +0 -17
  29. package/esm/PluginLoader.d.ts +14 -9
  30. package/esm/PluginLoader.js +34 -26
  31. package/esm/PluginManager.d.ts +4 -4
  32. package/esm/PluginManager.js +1 -1
  33. package/esm/ReExports/coreModules.generated.d.ts +2 -0
  34. package/esm/ReExports/coreModules.generated.js +492 -0
  35. package/esm/ReExports/coreWorkerModules.generated.d.ts +2 -0
  36. package/esm/ReExports/coreWorkerModules.generated.js +453 -0
  37. package/esm/ReExports/frameworkModules.d.ts +2 -0
  38. package/esm/ReExports/frameworkModules.js +67 -0
  39. package/esm/ReExports/frameworkShared.d.ts +12 -0
  40. package/esm/ReExports/frameworkShared.js +16 -0
  41. package/esm/ReExports/frameworkWorkerModules.generated.d.ts +2 -0
  42. package/esm/ReExports/frameworkWorkerModules.generated.js +130 -0
  43. package/esm/ReExports/list.js +493 -79
  44. package/esm/ReExports/modules.d.ts +1 -1
  45. package/esm/ReExports/modules.js +10 -87
  46. package/esm/ReExports/registry.d.ts +1 -0
  47. package/esm/ReExports/registry.js +23 -5
  48. package/esm/ReExports/uiStub.d.ts +2 -1
  49. package/esm/ReExports/uiStub.js +24 -2
  50. package/esm/ReExports/workerModules.js +8 -12
  51. package/esm/TextSearch/TextSearchManager.d.ts +3 -12
  52. package/esm/TextSearch/TextSearchManager.js +22 -10
  53. package/esm/assemblyManager/assembly.d.ts +10 -14
  54. package/esm/assemblyManager/assembly.js +10 -14
  55. package/esm/assemblyManager/assemblyConfigSchema.d.ts +23 -81
  56. package/esm/assemblyManager/assemblyManager.d.ts +10 -16
  57. package/esm/assemblyManager/assemblyManager.js +7 -10
  58. package/esm/assemblyManager/loadRefNameMap.js +3 -3
  59. package/esm/configuration/configurationSchema.d.ts +75 -31
  60. package/esm/configuration/configurationSchema.js +74 -40
  61. package/esm/configuration/configurationSchemaUnion.d.ts +39 -0
  62. package/esm/configuration/configurationSchemaUnion.js +59 -0
  63. package/esm/configuration/configurationSlot.d.ts +37 -12
  64. package/esm/configuration/configurationSlot.js +83 -22
  65. package/esm/configuration/formatAboutConfigSchema.d.ts +7 -21
  66. package/esm/configuration/formatDetailsConfigSchema.d.ts +11 -37
  67. package/esm/configuration/formatDetailsConfigSchema.js +10 -13
  68. package/esm/configuration/getConf.d.ts +17 -9
  69. package/esm/configuration/getConf.js +52 -7
  70. package/esm/configuration/index.d.ts +11 -4
  71. package/esm/configuration/index.js +7 -4
  72. package/esm/configuration/mergeFormatCallbacks.d.ts +6 -7
  73. package/esm/configuration/mergeFormatCallbacks.js +13 -10
  74. package/esm/configuration/readConfObject.d.ts +2 -22
  75. package/esm/configuration/readConfObject.js +15 -49
  76. package/esm/configuration/requirements.d.ts +37 -0
  77. package/esm/configuration/requirements.js +88 -0
  78. package/esm/configuration/schemaRegistry.d.ts +21 -1
  79. package/esm/configuration/schemaRegistry.js +11 -0
  80. package/esm/configuration/schemaTypes.d.ts +3 -0
  81. package/esm/configuration/schemaTypes.js +10 -0
  82. package/esm/configuration/slotFacade.d.ts +35 -4
  83. package/esm/configuration/slotFacade.js +96 -9
  84. package/esm/configuration/snapshotPreprocess.d.ts +27 -0
  85. package/esm/configuration/snapshotPreprocess.js +102 -0
  86. package/esm/configuration/types.d.ts +161 -22
  87. package/esm/data_adapters/BaseAdapter/BaseAdapter.d.ts +2 -2
  88. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +11 -2
  89. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +12 -1
  90. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +2 -3
  91. package/esm/data_adapters/BaseAdapter/featureDensity.js +2 -3
  92. package/esm/data_adapters/BaseAdapter/index.d.ts +22 -3
  93. package/esm/data_adapters/BaseAdapter/types.d.ts +3 -4
  94. package/esm/data_adapters/BaseAdapter/zoomRange.d.ts +10 -0
  95. package/esm/data_adapters/BaseAdapter/zoomRange.js +1 -0
  96. package/esm/data_adapters/CytobandAdapter/configSchema.d.ts +9 -11
  97. package/esm/data_adapters/getSequenceSubAdapter.d.ts +1 -3
  98. package/esm/data_adapters/getSequenceSubAdapter.js +1 -3
  99. package/esm/pluggableElementTypes/AdapterType.d.ts +7 -7
  100. package/esm/pluggableElementTypes/RpcMethodType.d.ts +1 -1
  101. package/esm/pluggableElementTypes/RpcMethodType.js +3 -8
  102. package/esm/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions.d.ts +1 -2
  103. package/esm/pluggableElementTypes/TextSearchAdapterType.d.ts +7 -7
  104. package/esm/pluggableElementTypes/index.d.ts +1 -1
  105. package/esm/pluggableElementTypes/index.js +1 -1
  106. package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +17 -7
  107. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +45 -48
  108. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +40 -36
  109. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +10 -13
  110. package/esm/pluggableElementTypes/models/BaseTrackModel.js +6 -6
  111. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +37 -17
  112. package/esm/pluggableElementTypes/models/BaseViewModel.js +25 -10
  113. package/esm/pluggableElementTypes/models/InternetAccountModel.d.ts +26 -16
  114. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +1 -1
  115. package/esm/pluggableElementTypes/models/baseConnectionConfig.d.ts +22 -18
  116. package/esm/pluggableElementTypes/models/baseConnectionConfig.js +5 -5
  117. package/esm/pluggableElementTypes/models/baseInternetAccountConfig.d.ts +26 -31
  118. package/esm/pluggableElementTypes/models/baseTrackConfig.d.ts +57 -141
  119. package/esm/pluggableElementTypes/models/baseTrackConfig.js +22 -26
  120. package/esm/pluggableElementTypes/models/components/SaveTrackData.js +2 -2
  121. package/esm/pluggableElementTypes/models/components/fetchTrackData.d.ts +3 -4
  122. package/esm/pluggableElementTypes/models/components/fetchTrackData.js +3 -3
  123. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.d.ts +15 -7
  124. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.js +38 -29
  125. package/esm/pluggableElementTypes/models/index.d.ts +1 -2
  126. package/esm/pluggableElementTypes/models/index.js +1 -2
  127. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.d.ts +3 -3
  128. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.js +4 -4
  129. package/esm/pluggableElementTypes/models/saveTrackFileTypes/types.d.ts +3 -3
  130. package/esm/rpc/BaseRpcDriver.d.ts +1 -2
  131. package/esm/rpc/BaseRpcDriver.js +23 -30
  132. package/esm/rpc/MainThreadRpcDriver.d.ts +2 -2
  133. package/esm/rpc/MainThreadRpcDriver.js +13 -8
  134. package/esm/rpc/RpcClient.d.ts +17 -6
  135. package/esm/rpc/RpcClient.js +42 -12
  136. package/esm/rpc/RpcManager.d.ts +8 -10
  137. package/esm/rpc/RpcManager.js +1 -1
  138. package/esm/rpc/RpcRegistry.d.ts +8 -2
  139. package/esm/rpc/RpcServer.d.ts +3 -1
  140. package/esm/rpc/RpcServer.js +19 -12
  141. package/esm/rpc/WebWorkerRpcDriver.d.ts +3 -3
  142. package/esm/rpc/WebWorkerRpcDriver.js +9 -47
  143. package/esm/rpc/byteBudget.d.ts +3 -5
  144. package/esm/rpc/byteBudget.js +4 -4
  145. package/esm/rpc/configSchema.d.ts +7 -21
  146. package/esm/rpc/coreRpcMethods.d.ts +1 -0
  147. package/esm/rpc/coreRpcMethods.js +1 -0
  148. package/esm/rpc/methods/CoreEncodeFeatures.d.ts +6 -5
  149. package/esm/rpc/methods/CoreEncodeFeatures.js +26 -31
  150. package/esm/rpc/methods/CoreGetEncodedFeature.d.ts +13 -0
  151. package/esm/rpc/methods/CoreGetEncodedFeature.js +31 -0
  152. package/esm/rpc/methods/CoreGetExportData.js +2 -2
  153. package/esm/rpc/methods/CoreGetFeatureDensity.js +2 -2
  154. package/esm/rpc/methods/CoreGetFeatures.js +2 -2
  155. package/esm/rpc/methods/CoreGetSequence.js +2 -2
  156. package/esm/rpc/methods/layerFeatures.d.ts +26 -0
  157. package/esm/rpc/methods/layerFeatures.js +40 -0
  158. package/esm/svg/SvgExport.js +3 -4
  159. package/esm/svg/SvgThemeProviders.d.ts +12 -0
  160. package/esm/svg/SvgThemeProviders.js +15 -0
  161. package/esm/svg/exportViewSvg.d.ts +32 -0
  162. package/esm/svg/exportViewSvg.js +13 -0
  163. package/esm/svg/normalizeSvgMarkup.d.ts +7 -0
  164. package/esm/svg/normalizeSvgMarkup.js +99 -0
  165. package/esm/svg/serializeSvg.d.ts +7 -0
  166. package/esm/svg/serializeSvg.js +11 -0
  167. package/esm/svg/svgReady.d.ts +8 -7
  168. package/esm/svg/svgReady.js +8 -7
  169. package/esm/svg/trackNames.d.ts +5 -5
  170. package/esm/svg/trackNames.js +6 -6
  171. package/esm/svg/wrapSvgExport.js +6 -74
  172. package/esm/ui/CascadingMenu.js +83 -86
  173. package/esm/ui/ErrorMessageStackTraceDialog.js +0 -5
  174. package/esm/ui/FileSelector/useInternetAccounts.d.ts +156 -96
  175. package/esm/ui/HoverMenu.d.ts +1 -2
  176. package/esm/ui/HoverMenu.js +6 -3
  177. package/esm/ui/JexlFilterDialog.d.ts +13 -10
  178. package/esm/ui/JexlFilterDialog.js +122 -49
  179. package/esm/ui/JexlFilterRowEditors.d.ts +15 -0
  180. package/esm/ui/JexlFilterRowEditors.js +90 -0
  181. package/esm/ui/LazyBaseTooltip.d.ts +4 -0
  182. package/esm/ui/LazyBaseTooltip.js +9 -0
  183. package/esm/ui/LoadingOverlay.js +3 -1
  184. package/esm/ui/MonospaceTextField.d.ts +2 -1
  185. package/esm/ui/MonospaceTextField.js +21 -19
  186. package/esm/ui/PaletteContext.d.ts +7 -9
  187. package/esm/ui/PaletteContext.js +24 -10
  188. package/esm/ui/RefNameAutocomplete/index.d.ts +1 -2
  189. package/esm/ui/RefNameAutocomplete/index.js +1 -1
  190. package/esm/ui/ScrollChrome.d.ts +6 -9
  191. package/esm/ui/ScrollChrome.js +5 -6
  192. package/esm/ui/ScrollEdgeShadow.d.ts +6 -9
  193. package/esm/ui/ScrollEdgeShadow.js +9 -24
  194. package/esm/ui/SettingsChangesTable.js +3 -3
  195. package/esm/ui/VerticalScrollbar.d.ts +13 -34
  196. package/esm/ui/VerticalScrollbar.js +29 -83
  197. package/esm/ui/ViewLoadingScreen.d.ts +2 -2
  198. package/esm/ui/ViewLoadingScreen.js +3 -3
  199. package/esm/ui/colorScale.d.ts +26 -1
  200. package/esm/ui/colorScale.js +28 -5
  201. package/esm/ui/colors.d.ts +49 -1
  202. package/esm/ui/colors.js +139 -4
  203. package/esm/ui/hoverBoxStyle.d.ts +14 -2
  204. package/esm/ui/hoverBoxStyle.js +17 -2
  205. package/esm/ui/index.d.ts +5 -3
  206. package/esm/ui/index.js +9 -7
  207. package/esm/ui/launchViewMenu.js +3 -3
  208. package/esm/ui/legendSpec.d.ts +2 -0
  209. package/esm/ui/legendSpec.js +3 -0
  210. package/esm/ui/palette.d.ts +0 -1
  211. package/esm/ui/palette.js +3 -27
  212. package/esm/ui/replaceViewAction.d.ts +1 -1
  213. package/esm/ui/replaceViewAction.js +1 -1
  214. package/esm/ui/theme.d.ts +1 -1
  215. package/esm/ui/theme.js +6 -40
  216. package/esm/ui/viewHeaderHeight.d.ts +1 -0
  217. package/esm/ui/viewHeaderHeight.js +1 -0
  218. package/esm/util/Base1DUtils.d.ts +1 -1
  219. package/esm/util/Base1DUtils.js +2 -2
  220. package/esm/util/SvgCanvas.d.ts +15 -13
  221. package/esm/util/SvgCanvas.js +72 -53
  222. package/esm/util/aborting.d.ts +39 -0
  223. package/esm/util/aborting.js +84 -0
  224. package/esm/util/adapterMetadata.d.ts +1 -1
  225. package/esm/util/adapterMetadata.js +6 -6
  226. package/esm/util/addAndShowTrack.d.ts +1 -4
  227. package/esm/util/addRelativeUris.d.ts +10 -2
  228. package/esm/util/addRelativeUris.js +22 -7
  229. package/esm/util/addTrackFromWidget.d.ts +2 -5
  230. package/esm/util/animationAllowed.d.ts +9 -0
  231. package/esm/util/animationAllowed.js +13 -0
  232. package/esm/util/applyRowResizeWheel.d.ts +10 -5
  233. package/esm/util/applyRowResizeWheel.js +10 -21
  234. package/esm/util/bandLayout.d.ts +4 -4
  235. package/esm/util/bandLayout.js +4 -4
  236. package/esm/util/bezierConnector.js +5 -4
  237. package/esm/util/bgzfWorkerPool.d.ts +20 -74
  238. package/esm/util/bgzfWorkerPool.js +20 -74
  239. package/esm/util/cachedSetup.d.ts +1 -1
  240. package/esm/util/cachedSetup.js +2 -2
  241. package/esm/util/categoricalField.d.ts +37 -0
  242. package/esm/util/categoricalField.js +52 -0
  243. package/esm/util/color/cssColorsLevel4.d.ts +1 -0
  244. package/esm/util/color/cssColorsLevel4.js +1 -0
  245. package/esm/util/color/index.d.ts +5 -3
  246. package/esm/util/color/index.js +7 -4
  247. package/esm/util/colorBits.d.ts +1 -2
  248. package/esm/util/colorBits.js +17 -39
  249. package/esm/util/colorRamp.d.ts +27 -1
  250. package/esm/util/colorRamp.js +56 -2
  251. package/esm/util/colorSchemes.d.ts +9 -0
  252. package/esm/util/colorSchemes.js +7 -0
  253. package/esm/util/{createStopTokenRotation.d.ts → createAbortRotation.d.ts} +11 -14
  254. package/esm/util/{createStopTokenRotation.js → createAbortRotation.js} +14 -26
  255. package/esm/util/cssColorParse.d.ts +15 -0
  256. package/esm/util/cssColorParse.js +53 -0
  257. package/esm/util/diagonalizeRegions.d.ts +2 -3
  258. package/esm/util/diagonalizeRegions.js +7 -12
  259. package/esm/util/expandLooseSearchIndex.d.ts +7 -0
  260. package/esm/util/expandLooseSearchIndex.js +25 -0
  261. package/esm/util/featureTransforms.d.ts +30 -3
  262. package/esm/util/featureTransforms.js +233 -36
  263. package/esm/util/fetchAndMaybeUnzip.js +5 -6
  264. package/esm/util/fetchContext.d.ts +5 -6
  265. package/esm/util/fetchContext.js +1 -1
  266. package/esm/util/fetchHub.d.ts +3 -1
  267. package/esm/util/fetchHub.js +2 -2
  268. package/esm/util/fetchSeq.d.ts +2 -3
  269. package/esm/util/fetchSeq.js +2 -2
  270. package/esm/util/fieldReader.d.ts +17 -0
  271. package/esm/util/fieldReader.js +62 -0
  272. package/esm/util/groupKeys.d.ts +75 -0
  273. package/esm/util/groupKeys.js +152 -0
  274. package/esm/util/highlights.d.ts +6 -4
  275. package/esm/util/highlights.js +12 -25
  276. package/esm/util/hooks.d.ts +1 -2
  277. package/esm/util/hooks.js +1 -2
  278. package/esm/util/index.d.ts +3 -3
  279. package/esm/util/index.js +4 -3
  280. package/esm/util/indexCandidates.js +1 -1
  281. package/esm/util/installFetch.d.ts +13 -10
  282. package/esm/util/installFetch.js +11 -10
  283. package/esm/util/installPrerequisiteFetch.d.ts +5 -3
  284. package/esm/util/installPrerequisiteFetch.js +3 -4
  285. package/esm/util/io/index.js +12 -12
  286. package/esm/util/isDataCurrent.d.ts +7 -5
  287. package/esm/util/isDataCurrent.js +9 -6
  288. package/esm/util/jexl.js +24 -21
  289. package/esm/util/jexlFilterRows.d.ts +89 -0
  290. package/esm/util/jexlFilterRows.js +252 -0
  291. package/esm/util/jexlFilters.d.ts +7 -5
  292. package/esm/util/jexlStrings.d.ts +3 -4
  293. package/esm/util/jexlStrings.js +2 -3
  294. package/esm/util/legendCandidates.d.ts +31 -27
  295. package/esm/util/legendCandidates.js +79 -53
  296. package/esm/util/localStorage.js +4 -4
  297. package/esm/util/markEncoding.d.ts +32 -16
  298. package/esm/util/markEncoding.js +177 -150
  299. package/esm/util/markEncodingTypes.d.ts +137 -66
  300. package/esm/util/mstUtils.d.ts +19 -22
  301. package/esm/util/mstUtils.js +19 -22
  302. package/esm/util/numericUtils.d.ts +7 -0
  303. package/esm/util/numericUtils.js +16 -0
  304. package/esm/util/numericValue.d.ts +14 -0
  305. package/esm/util/numericValue.js +34 -0
  306. package/esm/util/openFeatureWidget.js +1 -2
  307. package/esm/util/openViews.d.ts +1 -0
  308. package/esm/util/openViews.js +3 -3
  309. package/esm/util/parseLineByLine.d.ts +3 -4
  310. package/esm/util/parseLineByLine.js +7 -13
  311. package/esm/util/progress.d.ts +21 -21
  312. package/esm/util/progress.js +27 -26
  313. package/esm/util/renameRegions.d.ts +1 -2
  314. package/esm/util/renderToStaticMarkup.js +16 -16
  315. package/esm/util/rxjs.d.ts +7 -8
  316. package/esm/util/rxjs.js +12 -15
  317. package/esm/util/simpleFeature.d.ts +0 -1
  318. package/esm/util/svgColorProps.d.ts +11 -0
  319. package/esm/util/svgColorProps.js +28 -1
  320. package/esm/util/tabix.d.ts +3 -4
  321. package/esm/util/tabix.js +6 -7
  322. package/esm/util/thresholdScale.d.ts +54 -0
  323. package/esm/util/thresholdScale.js +112 -0
  324. package/esm/util/timeGate.d.ts +4 -5
  325. package/esm/util/timeGate.js +4 -5
  326. package/esm/util/trackConfigDelta.d.ts +22 -18
  327. package/esm/util/trackConfigDelta.js +40 -38
  328. package/esm/util/tracks.d.ts +27 -4
  329. package/esm/util/tracks.js +116 -43
  330. package/esm/util/translateTranscript.d.ts +44 -0
  331. package/esm/util/translateTranscript.js +102 -0
  332. package/esm/util/types/index.d.ts +19 -7
  333. package/esm/util/types/services.d.ts +1 -1
  334. package/esm/util/unknownSnapshotKeys.d.ts +15 -0
  335. package/esm/util/unknownSnapshotKeys.js +13 -0
  336. package/esm/util/useFeatureSequence.js +4 -4
  337. package/esm/util/useFetch.d.ts +3 -4
  338. package/esm/util/useFetch.js +5 -6
  339. package/esm/util/usePanelVirtualScroll.d.ts +7 -39
  340. package/esm/util/usePanelVirtualScroll.js +9 -40
  341. package/esm/util/useRowVirtualScroll.d.ts +6 -29
  342. package/esm/util/useRowVirtualScroll.js +8 -49
  343. package/esm/util/useVirtualScrollWheel.d.ts +20 -4
  344. package/esm/util/useVirtualScrollWheel.js +40 -84
  345. package/esm/util/viewHighlights.d.ts +3 -0
  346. package/esm/util/viewHighlights.js +5 -0
  347. package/esm/util/viewStatus.d.ts +24 -15
  348. package/esm/util/viewStatus.js +17 -0
  349. package/esm/util/withLaunchInput.d.ts +1 -1
  350. package/esm/util/withLaunchInput.js +0 -4
  351. package/package.json +26 -12
  352. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.d.ts +0 -80
  353. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.js +0 -583
  354. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +0 -141
  355. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.js +0 -1116
  356. package/esm/ReExports/BaseFeatureDetails.d.ts +0 -1
  357. package/esm/ReExports/BaseFeatureDetails.js +0 -10
  358. package/esm/ReExports/barrelOnlyNames.d.ts +0 -5
  359. package/esm/ReExports/barrelOnlyNames.js +0 -63
  360. package/esm/ReExports/index.d.ts +0 -1
  361. package/esm/ReExports/index.js +0 -1
  362. package/esm/ReExports/publicTracks.d.ts +0 -1
  363. package/esm/ReExports/publicTracks.js +0 -14
  364. package/esm/ReExports/publicUi.d.ts +0 -4
  365. package/esm/ReExports/publicUi.js +0 -33
  366. package/esm/ReExports/publicUtil.d.ts +0 -1
  367. package/esm/ReExports/publicUtil.js +0 -32
  368. package/esm/ReExports/sharedModules.d.ts +0 -96
  369. package/esm/ReExports/sharedModules.js +0 -66
  370. package/esm/ReExports/workerNamespaceNames.d.ts +0 -11
  371. package/esm/ReExports/workerNamespaceNames.js +0 -275
  372. package/esm/pluggableElementTypes/models/HighlightsMixin.d.ts +0 -51
  373. package/esm/pluggableElementTypes/models/HighlightsMixin.js +0 -78
  374. package/esm/ui/highlightChipReveal.d.ts +0 -32
  375. package/esm/ui/highlightChipReveal.js +0 -39
  376. package/esm/util/adapterConfigKey.d.ts +0 -12
  377. package/esm/util/adapterConfigKey.js +0 -14
  378. package/esm/util/stopToken.d.ts +0 -212
  379. package/esm/util/stopToken.js +0 -438
@@ -1,31 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useRef, useState } from 'react';
3
+ import { observer } from 'mobx-react';
3
4
  import { clamp } from '../util/numericUtils.js';
4
5
  import { makeStyles } from '../util/tss-react/index.js';
5
6
  import { usePointerDrag } from '../util/usePointerDrag.js';
6
7
  import { useRafCommit } from '../util/useRafCommit.js';
7
8
  import { useVirtualScrollWheel } from '../util/useVirtualScrollWheel.js';
8
9
  /**
9
- * How much of a display's right edge this occupies while it is drawn.
10
- *
11
- * Exported because the things that have to *clear* it are drawn by the displays
12
- * that mount it, not by this file: the bottom-right indicator row and the
13
- * alignments coverage axis label. Both kept a private copy of the number (and
14
- * the alignments indicator row kept none at all, so its chips were drawn over
15
- * the thumb), which is a copy that can only be checked by looking at two files
16
- * at once.
10
+ * How much of a display's right edge this occupies while it is drawn, for the
11
+ * chrome the displays draw beside it.
17
12
  */
18
13
  export const VERTICAL_SCROLLBAR_WIDTH = 12;
19
- /**
20
- * Where the right edge of anything that has to sit *beside* the thumb goes: the
21
- * track's width plus a hair of air, so a chip or an axis label doesn't touch it.
22
- *
23
- * The four call sites all spelled `VERTICAL_SCROLLBAR_WIDTH + 2` inline, which
24
- * is the same copy the width constant was exported to stop — one addition
25
- * further along. The `+ 2` is a gap and belongs to the thing being cleared, not
26
- * to the scrollbar's own geometry, so it is named rather than folded into the
27
- * width (`right: 2` on the thumb is a different 2 and must not move with it).
28
- */
14
+ /** Where the right edge of something sitting beside the thumb goes. */
29
15
  export const VERTICAL_SCROLLBAR_CLEARANCE = VERTICAL_SCROLLBAR_WIDTH + 2;
30
16
  const MIN_THUMB_HEIGHT = 20;
31
17
  const useStyles = makeStyles()(theme => ({
@@ -35,12 +21,8 @@ const useStyles = makeStyles()(theme => ({
35
21
  width: VERTICAL_SCROLLBAR_WIDTH,
36
22
  cursor: 'default',
37
23
  zIndex: 10,
38
- // `usePointerDrag`'s one caller-owned requirement: without it the browser
39
- // claims a touch drag on this strip as a page scroll and no pointer stream
40
- // arrives at all, so the thumb simply doesn't drag by finger.
24
+ // without it the browser claims a touch drag as a page scroll
41
25
  touchAction: 'none',
42
- // theme-aware so the thumb stays visible in dark mode (a hardcoded black
43
- // thumb vanished against a dark canvas)
44
26
  '&:hover > *': {
45
27
  background: theme.palette.action.active,
46
28
  },
@@ -55,71 +37,41 @@ const useStyles = makeStyles()(theme => ({
55
37
  },
56
38
  }));
57
39
  /**
58
- * Draggable vertical scrollbar overlay for canvas-backed displays that scroll
59
- * their content via a `scrollTop` value (alignments pileup, variant matrix).
60
- * Renders nothing when the content fits the viewport. The thumb geometry and
61
- * the drag-to-scroll mapping live here so the consumers don't each re-derive
62
- * them; the wheel handling stays per-display (their gesture semantics differ).
40
+ * Draggable vertical scrollbar overlay for a virtually scrolled display.
41
+ * Renders nothing when the content fits.
63
42
  *
64
- * Deliberately NOT a keyboard tab stop: the surrounding views have no working
65
- * keyboard navigation to reach the scrolled content anyway, so a per-track
66
- * `tabIndex` would only add noise to the tab order. The `role="scrollbar"` +
67
- * `aria-value*` semantics are kept — they cost nothing and expose scroll
68
- * position to pointer/voice assistive tech.
43
+ * Not a keyboard tab stop: the views have no keyboard navigation to reach the
44
+ * scrolled content, so `tabIndex` would only add noise. The `role="scrollbar"`
45
+ * semantics stay for pointer and voice assistive tech.
69
46
  */
70
- export default function VerticalScrollbar({ scrollTop, setScrollTop, viewportHeight, contentHeight, controlsId, top = 0, }) {
47
+ const VerticalScrollbar = observer(function VerticalScrollbar({ model, controlsId, top = 0, }) {
71
48
  const { classes } = useStyles();
72
- // ephemeral drag anchor; null when not dragging. Pointer capture (set on the
73
- // track) delivers move/up here even when the pointer leaves the thin track,
74
- // and auto-releases on unmount — so no document listeners or effect cleanup.
75
49
  const dragRef = useRef(undefined);
76
50
  const [trackEl, setTrackEl] = useState(null);
77
- // A thumb drag's pointermove can fire faster than the frame rate, so coalesce
78
- // its scroll writes to one commit per frame; pointer-up flushes the final
79
- // (absolute) target so the resting position is exact.
80
- const { schedule: scheduleScroll, flush: flushScroll } = useRafCommit(setScrollTop);
81
- const scrollableHeight = Math.max(0, contentHeight - viewportHeight);
82
- // Wheeling while the pointer is over the scrollbar always scrolls the panel,
83
- // never zooms the view. The scrollbar overlay is a sibling of the canvas, so
84
- // its wheel events would otherwise bubble straight past the canvas's own
85
- // handler to the containing view's scroll-zoom. A native non-passive listener
86
- // here (via useVirtualScrollWheel) consumes the vertical delta into
87
- // setScrollTop and stopPropagation keeps it from reaching that scroll-zoom.
88
- useVirtualScrollWheel(trackEl, (e, applyScroll) => {
89
- applyScroll(e, { scrollTop, viewportHeight, scrollableHeight }, n => {
90
- setScrollTop(n);
91
- });
51
+ const { schedule: scheduleScroll, flush: flushScroll } = useRafCommit((n) => {
52
+ model.setScrollTop(n);
53
+ });
54
+ const { scrollTop, scrollableHeight, scrollViewportHeight: viewportHeight, } = model;
55
+ // Wheeling the scrollbar always scrolls the panel, whatever `scrollZoom`
56
+ // says, and never reaches the view.
57
+ useVirtualScrollWheel(trackEl, model, (e, scroll) => {
58
+ scroll();
92
59
  e.stopPropagation();
93
60
  });
94
61
  const clampedScrollTop = clamp(scrollTop, 0, scrollableHeight);
95
- // never taller than the track itself — on a very short viewport the
96
- // MIN_THUMB_HEIGHT floor would otherwise exceed viewportHeight, pushing
97
- // thumbTop negative (thumb drawn above the track) and making usableTrack
98
- // negative (drag mapping dead)
62
+ const contentHeight = viewportHeight + scrollableHeight;
99
63
  const thumbHeight = Math.min(viewportHeight, Math.max(MIN_THUMB_HEIGHT, viewportHeight * (viewportHeight / contentHeight)));
100
64
  const usableTrack = viewportHeight - thumbHeight;
101
- // clamp so a scrollTop past scrollableHeight (virtual-scroll displays don't
102
- // self-correct like a native overflow container) can't draw the thumb below
103
- // the track
104
65
  const thumbTop = clamp((clampedScrollTop / scrollableHeight) * usableTrack, 0, usableTrack);
105
- // The press lifecycle is `usePointerDrag`'s: primary button only, one drag per
106
- // pointer, capture on the track so moves keep arriving once the pointer leaves
107
- // the 12px strip, and auto-release on unmount. Hand-rolled here before that
108
- // existed, which cost two of the bugs it is written to prevent — a right-press
109
- // started a drag that then ran underneath its own context menu, and a second
110
- // finger landing mid-drag re-anchored the gesture.
66
+ // A press on the track above or below the thumb pages one viewport toward it
67
+ // rather than starting a drag; `dragRef` staying unset makes the captured
68
+ // moves that follow do nothing.
111
69
  const drag = usePointerDrag({
112
- // Click-to-page: a press on the track above/below the thumb jumps one
113
- // viewport toward it (like a native scrollbar) rather than starting a drag.
114
- // The thumb is pointerEvents:none so every press lands on the track; decide
115
- // page-vs-drag from its Y relative to the thumb. `dragRef` staying undefined
116
- // is what makes the paging branch ignore the moves that follow — the pointer
117
- // is captured either way, and a page press simply has nothing to do with them.
118
70
  onDragStart: e => {
119
71
  const clickY = e.clientY - e.currentTarget.getBoundingClientRect().top;
120
72
  if (clickY < thumbTop || clickY > thumbTop + thumbHeight) {
121
73
  const dir = clickY < thumbTop ? -1 : 1;
122
- setScrollTop(clamp(clampedScrollTop + dir * viewportHeight, 0, scrollableHeight));
74
+ model.setScrollTop(clamp(clampedScrollTop + dir * viewportHeight, 0, scrollableHeight));
123
75
  }
124
76
  else {
125
77
  dragRef.current = { startY: e.clientY, startScroll: clampedScrollTop };
@@ -137,22 +89,16 @@ export default function VerticalScrollbar({ scrollTop, setScrollTop, viewportHei
137
89
  dragRef.current = undefined;
138
90
  },
139
91
  });
140
- // Below every hook, not above the geometry it reads: "the content fits" is a
141
- // prop-driven condition that flips while mounted, so an early return above
142
- // `usePointerDrag` would call a different number of hooks per render. The
143
- // geometry it closes over is computed either way and simply goes unused here —
144
- // nothing renders, so nothing can dispatch a pointer event at it.
92
+ // below every hook: "the content fits" flips while mounted
145
93
  if (scrollableHeight <= 0) {
146
94
  return null;
147
95
  }
148
96
  return (_jsx("div", { ref: setTrackEl, "data-testid": "vertical-scrollbar", "data-gesture-owner": "true", className: classes.track, style: { top, height: viewportHeight }, role: "scrollbar", "aria-label": "Vertical scrollbar", "aria-controls": controlsId, "aria-orientation": "vertical", "aria-valuemin": 0, "aria-valuemax": Math.round(scrollableHeight), "aria-valuenow": Math.round(clampedScrollTop), ...drag,
149
- // Wraps the hook's own handler rather than replacing it: stopPropagation
150
- // so the press doesn't also pan the view, and it runs for every button, so
151
- // a right-press the drag ignores still doesn't reach the view. No
152
- // preventDefault, so the native focus shift can still close open popups
153
- // and the context menu still opens.
97
+ // every button, so a right-press the drag ignores doesn't pan the view
98
+ // either; no preventDefault, so focus still moves and menus still open
154
99
  onPointerDown: e => {
155
100
  e.stopPropagation();
156
101
  drag.onPointerDown(e);
157
102
  }, children: _jsx("div", { className: classes.thumb, style: { top: thumbTop, height: thumbHeight } }) }));
158
- }
103
+ });
104
+ export default VerticalScrollbar;
@@ -17,8 +17,8 @@
17
17
  * {@link LoadingProgress} directly — bare, it renders an unconstrained
18
18
  * full-width bar under an unaligned label.
19
19
  */
20
- export default function ViewLoadingScreen({ message, fraction, source, }: {
20
+ export default function ViewLoadingScreen({ message, progress, source, }: {
21
21
  message?: string;
22
- fraction?: number;
22
+ progress?: number;
23
23
  source?: string;
24
24
  }): import("react").JSX.Element;
@@ -69,8 +69,8 @@ function useStalled(key) {
69
69
  * {@link LoadingProgress} directly — bare, it renders an unconstrained
70
70
  * full-width bar under an unaligned label.
71
71
  */
72
- export default function ViewLoadingScreen({ message, fraction, source, }) {
72
+ export default function ViewLoadingScreen({ message, progress, source, }) {
73
73
  const { classes } = useStyles();
74
- const stalled = useStalled(`${message}|${fraction}|${source}`);
75
- return (_jsxs("div", { className: classes.root, children: [_jsx(LoadingProgress, { variant: "h6", message: message, fraction: fraction, barClassName: classes.bar }), stalled && source ? (_jsxs(Typography, { variant: "body2", className: classes.stalled, children: ["still waiting on ", source] })) : null] }));
74
+ const stalled = useStalled(`${message}|${progress}|${source}`);
75
+ return (_jsxs("div", { className: classes.root, children: [_jsx(LoadingProgress, { variant: "h6", message: message, fraction: progress, barClassName: classes.bar }), stalled && source ? (_jsxs(Typography, { variant: "body2", className: classes.stalled, children: ["still waiting on ", source] })) : null] }));
76
76
  }
@@ -7,10 +7,17 @@ import type { LegendSpec, LegendSwatch } from './legendSpec.ts';
7
7
  */
8
8
  export interface CategoricalEntry {
9
9
  value: string;
10
+ /**
11
+ * Every value painted in this row's color where the key is derived from
12
+ * the painting (`derivedColorScale`), `value` being the first; the label
13
+ * names them all. A row declared one value at a time leaves it unset.
14
+ */
15
+ values?: string[];
10
16
  label: string;
11
17
  color?: string;
12
18
  swatches?: LegendSwatch[];
13
19
  hidden?: boolean;
20
+ missing?: boolean;
14
21
  }
15
22
  /**
16
23
  * A color vocabulary: a finite set of values, each drawn in one color. ADR-094's
@@ -22,6 +29,9 @@ export interface CategoricalScale {
22
29
  id: string;
23
30
  title?: string;
24
31
  entries: CategoricalEntry[];
32
+ domain?: readonly string[];
33
+ focusesRows?: boolean;
34
+ note?: string;
25
35
  }
26
36
  /** One stop of a continuous ramp, `offset` in `[0, 1]`. */
27
37
  export interface RampStop {
@@ -33,7 +43,9 @@ export interface RampStop {
33
43
  * A scalar through a color ramp: ADR-094's scalar-through-a-scale
34
44
  * cardinality. `stops` are what the painter samples — read them out of the
35
45
  * same LUT the GPU uploads (`stopsFromRampLut`) so the bar is byte-identical
36
- * to the plot. `format` prints the domain ends; `toLocale` by default.
46
+ * to the plot. `format` prints the domain ends; `formatScore` by default, so
47
+ * a domain measured off the data prints `24.4` and not the float it was
48
+ * measured as.
37
49
  */
38
50
  export interface RampScale {
39
51
  kind: 'ramp';
@@ -60,5 +72,18 @@ export type ColorScale = CategoricalScale | RampScale;
60
72
  * name over its values) and a lone ramp's goes on its row.
61
73
  */
62
74
  export declare function legendSpecOf(scales: ColorScale[]): LegendSpec;
75
+ /**
76
+ * The no-value row goes after every value, in whatever orders the values: a
77
+ * `domain` never lists it, so ordering by the domain alone ranks it with the
78
+ * values the domain leaves out and the bracket its label starts with floats it
79
+ * above them all. Both places a key is ordered read this — `sectionOf` for the
80
+ * rows it draws, and `derivedColorScale` for the entries it hands back, which a
81
+ * display reads for what its key lists.
82
+ */
83
+ export declare function missingRowLast(a: {
84
+ missing?: boolean;
85
+ }, b: {
86
+ missing?: boolean;
87
+ }): number;
63
88
  /** Whether a scale has anything for a key to show. */
64
89
  export declare function colorScaleIsEmpty(scale: ColorScale): boolean;
@@ -1,8 +1,9 @@
1
- import { toLocale } from '../util/numericUtils.js';
1
+ import { groupKeyComparator } from '../util/groupKeys.js';
2
+ import { formatScore } from '../util/numericUtils.js';
2
3
  // A lone ramp names itself on its row: `FloatingLegend` and `legendEntries`
3
4
  // draw a section's title only beside other sections, and a bar of numbers
4
5
  // with nothing saying what they count is not a key.
5
- function rampItem({ title, domain, stops, format = toLocale }, lone) {
6
+ function rampItem({ title, domain, stops, format = formatScore }, lone) {
6
7
  const [min, max] = domain;
7
8
  return {
8
9
  label: lone ? (title ?? '') : '',
@@ -10,12 +11,23 @@ function rampItem({ title, domain, stops, format = toLocale }, lone) {
10
11
  };
11
12
  }
12
13
  function sectionOf(scale, lone) {
14
+ if (scale.kind !== 'categorical') {
15
+ return { id: scale.id, title: scale.title, items: [rampItem(scale, lone)] };
16
+ }
17
+ const items = scale.entries.map(entry => ({ ...entry }));
18
+ const compare = scale.domain?.length
19
+ ? groupKeyComparator(scale.domain)
20
+ : undefined;
21
+ // The sort is stable and the value half is skipped without a domain, so a
22
+ // key a display ordered itself keeps that order and only its no-value row
23
+ // moves.
24
+ items.sort((a, b) => missingRowLast(a, b) || (compare ? compare(a.value, b.value) : 0));
13
25
  return {
14
26
  id: scale.id,
15
27
  title: scale.title,
16
- items: scale.kind === 'categorical'
17
- ? scale.entries.map(entry => ({ ...entry }))
18
- : [rampItem(scale, lone)],
28
+ note: scale.note,
29
+ items,
30
+ focusesRows: scale.focusesRows,
19
31
  };
20
32
  }
21
33
  /**
@@ -35,6 +47,17 @@ export function legendSpecOf(scales) {
35
47
  sections: scales.map(scale => sectionOf(scale, scales.length === 1)),
36
48
  };
37
49
  }
50
+ /**
51
+ * The no-value row goes after every value, in whatever orders the values: a
52
+ * `domain` never lists it, so ordering by the domain alone ranks it with the
53
+ * values the domain leaves out and the bracket its label starts with floats it
54
+ * above them all. Both places a key is ordered read this — `sectionOf` for the
55
+ * rows it draws, and `derivedColorScale` for the entries it hands back, which a
56
+ * display reads for what its key lists.
57
+ */
58
+ export function missingRowLast(a, b) {
59
+ return Number(a.missing ?? false) - Number(b.missing ?? false);
60
+ }
38
61
  /** Whether a scale has anything for a key to show. */
39
62
  export function colorScaleIsEmpty(scale) {
40
63
  return scale.kind === 'categorical' && scale.entries.length === 0;
@@ -29,6 +29,23 @@ export declare const paletteColors: {
29
29
  * Past the end is the caller's problem, and the two callers answer differently
30
30
  * on purpose: an attribute palette-by hashes the VALUE (stable across
31
31
  * re-palettes), while a by-position painter has no value to hash and wraps.
32
+ *
33
+ * **It holds 14 pairs `similarColors` calls the same** — five schemes' blues,
34
+ * oranges, greens, reds and pinks — and deduping it at construction is the
35
+ * wrong reading of that, measured on the 38 GENCODE gene biotypes. Hashed,
36
+ * which is what a track with no `colorDomain` does, 30 of them land on 22
37
+ * colors and 38 on 26; the loss is the birthday collision on 40 slots, not the
38
+ * near-twins, and only 3 of the pairs they land on read alike. Pruning to the
39
+ * 30 distinct entries makes that 23 and 24, so it costs ten colors and buys
40
+ * nothing.
41
+ *
42
+ * The near-twins bite the PINNED case instead, where a `domain` spends the
43
+ * list in order: 30 listed values take 30 colors today and 7 of those pairs
44
+ * read alike. Ordering the distinct 30 first and the twins behind them fixes
45
+ * that outright (0 pairs at 30 listed values, 11 at 38 where the twins are
46
+ * reached anyway) and costs no colors — but it moves every hashed color in
47
+ * marks, GWAS, canvas, multi-row and the arrangement dialog, so it is a pass
48
+ * with a figure refresh in it.
32
49
  */
33
50
  export declare const categoricalPalette: string[];
34
51
  /**
@@ -38,10 +55,41 @@ export declare const categoricalPalette: string[];
38
55
  * paint it pink. A non-negative integer takes the slot it names, anchored at
39
56
  * 1, so `1`, `2`, `3` walk the palette in order and stay distinct; anything
40
57
  * else hashes in, stable for the same reason at the cost of an occasional
41
- * collision.
58
+ * collision. `categoricalScale` is the same rule with a domain.
42
59
  */
43
60
  export declare function categoricalValueColor(value: string): string;
44
61
  export declare function categoricalValueColor<T>(value: string, palette: readonly T[]): T;
62
+ /**
63
+ * The categorical rule every scaled channel resolves through. With no
64
+ * `domain` a value takes `categoricalValueColor`'s slot in `range`. With one,
65
+ * the listed values take `range` in order, continuing into the `fallback`
66
+ * entries `range` lacks past its end, and any other value takes a slot of the
67
+ * whole list derived from itself that no listed value holds, nor one
68
+ * `isNear` calls the same. A value's entry depends only on the value and the
69
+ * declaration, so every region agrees on it, and adding a listed value moves
70
+ * only the unlisted values on the slots it takes.
71
+ */
72
+ export declare function categoricalScale<T>(domain: readonly (string | number)[] | undefined, range: readonly T[], { fallback, isNear, }?: {
73
+ fallback?: readonly T[];
74
+ isNear?: (a: T, b: T) => boolean;
75
+ }): (value: string) => T;
76
+ /**
77
+ * Whether two CSS colors read as one: under 0.05 apart in OKLab, where the
78
+ * wide palette's tableau and category10 oranges sit 0.003 apart.
79
+ */
80
+ export declare function similarColors(a: string, b: string): boolean;
81
+ /**
82
+ * `categoricalScale` for a color channel: `palette` (the wide palette when
83
+ * empty) spent in `domain` order and continued into the wide palette, and an
84
+ * unlisted value never on a listed value's color or one that reads the same.
85
+ */
86
+ export declare function categoricalColorScale(domain: readonly (string | number)[] | undefined, palette?: readonly string[]): (value: string) => string;
87
+ /**
88
+ * The color one value of a categorical color channel paints, by
89
+ * `categoricalColorScale`. A value-less feature is neutral grey, and an array
90
+ * value joins the way a group key does.
91
+ */
92
+ export declare function categoricalColor(value: unknown, domain?: readonly string[], palette?: readonly string[]): string;
45
93
  /**
46
94
  * Deterministic non-negative 32-bit hash of a string.
47
95
  */
package/esm/ui/colors.js CHANGED
@@ -1,4 +1,7 @@
1
- import { relight } from '../util/color/index.js';
1
+ import * as convert from '../util/color-bits/convert.js';
2
+ import { NO_CATEGORY_COLOR, relight } from '../util/color/index.js';
3
+ import { cssColorToNormalizedRgb } from '../util/colorBits.js';
4
+ import { valueText } from '../util/groupKeys.js';
2
5
  const category10 = [
3
6
  '#1f77b4',
4
7
  '#ff7f0e',
@@ -108,16 +111,148 @@ export const paletteColors = {
108
111
  * Past the end is the caller's problem, and the two callers answer differently
109
112
  * on purpose: an attribute palette-by hashes the VALUE (stable across
110
113
  * re-palettes), while a by-position painter has no value to hash and wraps.
114
+ *
115
+ * **It holds 14 pairs `similarColors` calls the same** — five schemes' blues,
116
+ * oranges, greens, reds and pinks — and deduping it at construction is the
117
+ * wrong reading of that, measured on the 38 GENCODE gene biotypes. Hashed,
118
+ * which is what a track with no `colorDomain` does, 30 of them land on 22
119
+ * colors and 38 on 26; the loss is the birthday collision on 40 slots, not the
120
+ * near-twins, and only 3 of the pairs they land on read alike. Pruning to the
121
+ * 30 distinct entries makes that 23 and 24, so it costs ten colors and buys
122
+ * nothing.
123
+ *
124
+ * The near-twins bite the PINNED case instead, where a `domain` spends the
125
+ * list in order: 30 listed values take 30 colors today and 7 of those pairs
126
+ * read alike. Ordering the distinct 30 first and the twins behind them fixes
127
+ * that outright (0 pairs at 30 listed values, 11 at 38 where the twins are
128
+ * reached anyway) and costs no colors — but it moves every hashed color in
129
+ * marks, GWAS, canvas, multi-row and the arrangement dialog, so it is a pass
130
+ * with a figure refresh in it.
111
131
  */
112
132
  export const categoricalPalette = [
113
133
  ...new Set([...tableau10, ...set1, ...dark2, ...set2, ...category10].filter(hex => !NEUTRALS.has(hex.toLowerCase()))),
114
134
  ];
115
135
  export function categoricalValueColor(value, palette = categoricalPalette) {
116
- const n = palette.length;
136
+ return palette[valueSlot(value, palette.length)];
137
+ }
138
+ function valueSlot(value, n) {
117
139
  const num = Number(value);
118
140
  return value !== '' && Number.isInteger(num) && num >= 0
119
- ? palette[(num + n - 1) % n]
120
- : palette[hashString(value) % n];
141
+ ? (num + n - 1) % n
142
+ : hashString(value) % n;
143
+ }
144
+ function entryKey(entry) {
145
+ return typeof entry === 'string' ? entry.toLowerCase() : entry;
146
+ }
147
+ // The first slot derived from the value that `taken` does not hold, trying
148
+ // rehashes before walking, so the values landing on a taken slot spread over
149
+ // the free ones instead of piling onto the next.
150
+ function freeSlot(value, size, taken) {
151
+ let slot = valueSlot(value, size);
152
+ for (let salt = 1; taken.has(slot) && salt <= size; salt++) {
153
+ slot = hashString(`${salt}:${value}`) % size;
154
+ }
155
+ for (let step = 0; taken.has(slot) && step < size; step++) {
156
+ slot = (slot + 1) % size;
157
+ }
158
+ return slot;
159
+ }
160
+ /**
161
+ * The categorical rule every scaled channel resolves through. With no
162
+ * `domain` a value takes `categoricalValueColor`'s slot in `range`. With one,
163
+ * the listed values take `range` in order, continuing into the `fallback`
164
+ * entries `range` lacks past its end, and any other value takes a slot of the
165
+ * whole list derived from itself that no listed value holds, nor one
166
+ * `isNear` calls the same. A value's entry depends only on the value and the
167
+ * declaration, so every region agrees on it, and adding a listed value moves
168
+ * only the unlisted values on the slots it takes.
169
+ */
170
+ export function categoricalScale(domain, range, { fallback = [], isNear, } = {}) {
171
+ const base = range.length ? range : fallback;
172
+ const listed = [...new Set((domain ?? []).map(String))].filter(v => v !== '');
173
+ if (listed.length === 0) {
174
+ return value => base[valueSlot(value, base.length)];
175
+ }
176
+ const seen = new Set(base.map(entryKey));
177
+ const entries = [
178
+ ...base,
179
+ ...fallback.filter(entry => {
180
+ const key = entryKey(entry);
181
+ return seen.has(key) ? false : (seen.add(key), true);
182
+ }),
183
+ ];
184
+ const size = entries.length;
185
+ const rank = new Map(listed.map((value, i) => [value, i]));
186
+ const listedSlots = new Set(listed.map((_, i) => i % size));
187
+ const taken = new Set(entries.flatMap((entry, i) => listedSlots.has(i) ||
188
+ (isNear && [...listedSlots].some(j => isNear(entries[j], entry)))
189
+ ? [i]
190
+ : []));
191
+ return value => {
192
+ const i = rank.get(value);
193
+ return entries[i !== undefined
194
+ ? i % size
195
+ : taken.size < size
196
+ ? freeSlot(value, size, taken)
197
+ : valueSlot(value, size)];
198
+ };
199
+ }
200
+ const oklabByColor = new Map();
201
+ function oklabOf(color) {
202
+ let lab = oklabByColor.get(color);
203
+ if (lab === undefined) {
204
+ lab = convert.xyzd65ToOklab(...convert.xyzd50ToD65(...convert.srgbToXyzd50(...cssColorToNormalizedRgb(color))));
205
+ oklabByColor.set(color, lab);
206
+ }
207
+ return lab;
208
+ }
209
+ /**
210
+ * Whether two CSS colors read as one: under 0.05 apart in OKLab, where the
211
+ * wide palette's tableau and category10 oranges sit 0.003 apart.
212
+ */
213
+ export function similarColors(a, b) {
214
+ const [l1, a1, b1] = oklabOf(a);
215
+ const [l2, a2, b2] = oklabOf(b);
216
+ return Math.hypot(l1 - l2, a1 - a2, b1 - b2) < 0.05;
217
+ }
218
+ /**
219
+ * `categoricalScale` for a color channel: `palette` (the wide palette when
220
+ * empty) spent in `domain` order and continued into the wide palette, and an
221
+ * unlisted value never on a listed value's color or one that reads the same.
222
+ */
223
+ export function categoricalColorScale(domain, palette = []) {
224
+ return categoricalScale(domain, palette, {
225
+ fallback: categoricalPalette,
226
+ isNear: similarColors,
227
+ });
228
+ }
229
+ const MAX_CACHED_SCALES = 16;
230
+ const scaleCache = new Map();
231
+ function cachedColorScale(domain, palette) {
232
+ const key = `${domain.join('\u001F')}\u001E${palette.join('\u001F')}`;
233
+ let scale = scaleCache.get(key);
234
+ if (scale === undefined) {
235
+ if (scaleCache.size >= MAX_CACHED_SCALES) {
236
+ scaleCache.delete(scaleCache.keys().next().value);
237
+ }
238
+ scale = categoricalColorScale(domain, palette);
239
+ scaleCache.set(key, scale);
240
+ }
241
+ return scale;
242
+ }
243
+ /**
244
+ * The color one value of a categorical color channel paints, by
245
+ * `categoricalColorScale`. A value-less feature is neutral grey, and an array
246
+ * value joins the way a group key does.
247
+ */
248
+ export function categoricalColor(value, domain = [], palette = []) {
249
+ const label = valueText(value);
250
+ if (label === '') {
251
+ return NO_CATEGORY_COLOR;
252
+ }
253
+ return domain.length === 0 && palette.length === 0
254
+ ? categoricalValueColor(label)
255
+ : cachedColorScale(domain, palette)(label);
121
256
  }
122
257
  // only category10 and set1 are imported by name; the rest are reached through
123
258
  // paletteColors above
@@ -5,7 +5,19 @@ import type { CSSProperties } from 'react';
5
5
  * washes them out.
6
6
  *
7
7
  * One definition because the alternative was proven to fail: `highlightBoxColors`
8
- * exists for the same reason, after two backends drifted apart on their own alpha
9
- * literals kept in step by a comment.
8
+ * below exists for the same reason, after two backends drifted apart on their own
9
+ * alpha literals kept in step by a comment.
10
10
  */
11
11
  export declare const hoverBoxStyle: CSSProperties;
12
+ /**
13
+ * The border and fill of a pinned highlight box, off the palette's highlight
14
+ * hue. The chrome draws it on screen and `renderDisplaySvg` bakes it into the
15
+ * export, so both reach one definition.
16
+ *
17
+ * JBrowse's own `alpha`, not Material UI's: the SVG export reaches this module
18
+ * and should not drag @mui/material along.
19
+ */
20
+ export declare function highlightBoxColors(highlightMain: string): {
21
+ border: string;
22
+ fill: string;
23
+ };
@@ -1,13 +1,28 @@
1
+ import { alpha } from './palette.js';
1
2
  /**
2
3
  * The hover mark for a cell or block on a canvas display: a white wash plus a
3
4
  * dark border, never a color tint — the cell colors are the data, and a tint
4
5
  * washes them out.
5
6
  *
6
7
  * One definition because the alternative was proven to fail: `highlightBoxColors`
7
- * exists for the same reason, after two backends drifted apart on their own alpha
8
- * literals kept in step by a comment.
8
+ * below exists for the same reason, after two backends drifted apart on their own
9
+ * alpha literals kept in step by a comment.
9
10
  */
10
11
  export const hoverBoxStyle = {
11
12
  border: '1px solid rgba(0,0,0,0.5)',
12
13
  background: 'rgba(255,255,255,0.3)',
13
14
  };
15
+ /**
16
+ * The border and fill of a pinned highlight box, off the palette's highlight
17
+ * hue. The chrome draws it on screen and `renderDisplaySvg` bakes it into the
18
+ * export, so both reach one definition.
19
+ *
20
+ * JBrowse's own `alpha`, not Material UI's: the SVG export reaches this module
21
+ * and should not drag @mui/material along.
22
+ */
23
+ export function highlightBoxColors(highlightMain) {
24
+ return {
25
+ border: alpha(highlightMain, 0.9),
26
+ fill: alpha(highlightMain, 0.25),
27
+ };
28
+ }
package/esm/ui/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type JBrowseTheme, type SerializableThemeArgs, type ThemeMap, colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorNeutralRead, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, createJBrowseBaseTheme, createJBrowseTheme, createJBrowseThemeFromArgs, defaultThemes, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './theme.ts';
1
+ export { type JBrowseTheme, type SerializableThemeArgs, type ThemeMap, colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, createJBrowseBaseTheme, createJBrowseTheme, createJBrowseThemeFromArgs, defaultThemes, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './theme.ts';
2
2
  export { default as BaseExportSvgDialog } from './BaseExportSvgDialog.tsx';
3
3
  export type { BaseExportSvgOptions } from './BaseExportSvgDialog.tsx';
4
4
  export { default as ExportSvgDialog } from './ExportSvgDialog.tsx';
@@ -8,7 +8,8 @@ export { default as AssemblySelector } from './AssemblySelector.tsx';
8
8
  export { useAssemblySelection } from './useAssemblySelection.ts';
9
9
  export { useRecentLocations } from './useRecentLocations.ts';
10
10
  export type { RecentLocation } from './useRecentLocations.ts';
11
- export { RefNameAutocompleteEndAdornment, adornmentReservePx, getInputWidth, default as RefNameAutocomplete, } from './RefNameAutocomplete/index.tsx';
11
+ export { RefNameAutocompleteEndAdornment, default as RefNameAutocomplete, } from './RefNameAutocomplete/index.tsx';
12
+ export { adornmentReservePx, getInputWidth, } from './RefNameAutocomplete/util.ts';
12
13
  export { default as CascadingMenu } from './CascadingMenu.tsx';
13
14
  export { default as CascadingMenuButton } from './CascadingMenuButton.tsx';
14
15
  export { default as ContextMenu } from './ContextMenu.tsx';
@@ -60,6 +61,7 @@ export { default as SettingsChangesTable } from './SettingsChangesTable.tsx';
60
61
  export { default as ActionLink } from './ActionLink.tsx';
61
62
  export { default as ExternalLink } from './ExternalLink.tsx';
62
63
  export { default as SanitizedHTML } from './SanitizedHTML.tsx';
64
+ export { default as BaseTooltip } from './LazyBaseTooltip.tsx';
63
65
  export { default as PluggableComponent } from './PluggableComponent.tsx';
64
66
  export { default as PluggableComponents } from './PluggableComponents.tsx';
65
67
  export type { ComponentExtensionPointName } from './PluggableComponents.tsx';
@@ -78,7 +80,7 @@ export { default as Crosshairs } from './Crosshairs.tsx';
78
80
  export { hoverBoxStyle } from './hoverBoxStyle.ts';
79
81
  export { useMouseState, useMouseTracking } from './useMouseTracking.ts';
80
82
  export type { MouseState, MouseTracker } from './useMouseTracking.ts';
81
- export declare const VIEW_HEADER_HEIGHT = 28;
83
+ export { VIEW_HEADER_HEIGHT } from './viewHeaderHeight.ts';
82
84
  export { LEGEND_ROW_HEIGHT, LEGEND_SVG_GUTTER_WIDTH, LEGEND_SWATCH, default as SvgColorLegend, } from './SvgColorLegend.tsx';
83
85
  export type { ColorLegendEntry } from './SvgColorLegend.tsx';
84
86
  export { measureLegendText } from './measureLegendText.ts';