@jbrowse/core 5.0.0-beta.8 → 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
package/esm/ui/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { 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.js';
1
+ export { 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.js';
2
2
  export { default as BaseExportSvgDialog } from './BaseExportSvgDialog.js';
3
3
  export { default as ExportSvgDialog } from './ExportSvgDialog.js';
4
4
  export { useExportSvgPreference } from './useExportSvgPreference.js';
@@ -6,7 +6,8 @@ export { LogoFull, Logomark } from './Logo.js';
6
6
  export { default as AssemblySelector } from './AssemblySelector.js';
7
7
  export { useAssemblySelection } from './useAssemblySelection.js';
8
8
  export { useRecentLocations } from './useRecentLocations.js';
9
- export { RefNameAutocompleteEndAdornment, adornmentReservePx, getInputWidth, default as RefNameAutocomplete, } from './RefNameAutocomplete/index.js';
9
+ export { RefNameAutocompleteEndAdornment, default as RefNameAutocomplete, } from './RefNameAutocomplete/index.js';
10
+ export { adornmentReservePx, getInputWidth, } from './RefNameAutocomplete/util.js';
10
11
  export { default as CascadingMenu } from './CascadingMenu.js';
11
12
  export { default as CascadingMenuButton } from './CascadingMenuButton.js';
12
13
  export { default as ContextMenu } from './ContextMenu.js';
@@ -56,10 +57,11 @@ export { default as SettingsChangesTable } from './SettingsChangesTable.js';
56
57
  export { default as ActionLink } from './ActionLink.js';
57
58
  export { default as ExternalLink } from './ExternalLink.js';
58
59
  export { default as SanitizedHTML } from './SanitizedHTML.js';
59
- // BaseTooltip is deliberately NOT re-exported here: it reaches @floating-ui
60
- // (~266KB), and this barrel is imported by eager plugin entries, so the
61
- // re-export alone held that dependency on the startup path. Every consumer
62
- // deep-imports '@jbrowse/core/ui/BaseTooltip' instead.
60
+ // The eager BaseTooltip reaches @floating-ui (~266KB), and this barrel is
61
+ // imported by eager plugin entries, so the barrel serves the lazy wrapper:
62
+ // published apollo reads `BaseTooltip` off the served ui namespace. In-tree
63
+ // consumers deep-import '@jbrowse/core/ui/BaseTooltip'.
64
+ export { default as BaseTooltip } from './LazyBaseTooltip.js';
63
65
  export { default as PluggableComponent } from './PluggableComponent.js';
64
66
  export { default as PluggableComponents } from './PluggableComponents.js';
65
67
  export { default as PluggableElements } from './PluggableElements.js';
@@ -72,7 +74,7 @@ export { launchTargetsMenuItem } from './launchTargetsMenuItem.js';
72
74
  export { default as Crosshairs } from './Crosshairs.js';
73
75
  export { hoverBoxStyle } from './hoverBoxStyle.js';
74
76
  export { useMouseState, useMouseTracking } from './useMouseTracking.js';
75
- export const VIEW_HEADER_HEIGHT = 28;
77
+ export { VIEW_HEADER_HEIGHT } from './viewHeaderHeight.js';
76
78
  export { LEGEND_ROW_HEIGHT, LEGEND_SVG_GUTTER_WIDTH, LEGEND_SWATCH, default as SvgColorLegend, } from './SvgColorLegend.js';
77
79
  export { measureLegendText } from './measureLegendText.js';
78
80
  export { LegendSwatchGlyph } from './LegendSwatchGlyph.js';
@@ -34,9 +34,9 @@ export function pushIntoSubMenu(items, label, item) {
34
34
  // `rubberBandLaunchMenuItems()` on the linear genome view — because there the
35
35
  // grouping is the model's, not each contributor's, to do.
36
36
  //
37
- // Keeps its name while the label loses a word: this one is pinned by
38
- // `abiBaseline.json`, so a published plugin bundle reads it off the host at
39
- // module scope and a rename is `undefined` inside an already-shipped UMD.
37
+ // Keeps its name while the label loses a word: `@jbrowse/core/ui` serves it, so
38
+ // a published plugin bundle reads it off the host at module scope and a rename
39
+ // is `undefined` inside an already-shipped UMD.
40
40
  export function pushLaunchViewMenuItem(items, item) {
41
41
  pushIntoSubMenu(items, LAUNCH_LABEL, item);
42
42
  }
@@ -29,7 +29,9 @@ export declare function legendSwatches(item: LegendItem): LegendSwatch[];
29
29
  export interface LegendSection {
30
30
  id: string;
31
31
  title?: string;
32
+ note?: string;
32
33
  items: LegendItem[];
34
+ focusesRows?: boolean;
33
35
  }
34
36
  export interface LegendSpec {
35
37
  title?: string;
@@ -25,6 +25,9 @@ export function legendEntries(spec) {
25
25
  ...(titled && section.title !== undefined
26
26
  ? [{ key: `${section.id}-title`, label: section.title }]
27
27
  : []),
28
+ ...(section.note === undefined
29
+ ? []
30
+ : [{ key: `${section.id}-note`, label: section.note }]),
28
31
  ...section.items.map((item, idx) => ({
29
32
  key: `${section.id}-${idx}`,
30
33
  label: item.label,
@@ -126,7 +126,6 @@ export declare const colorPairRL = "#0099bb";
126
126
  export declare const colorPairLL = "#4d9a4d";
127
127
  /** #color alignments-pair-orientation | RR (← ←) | Both mates on the reverse strand */
128
128
  export declare const colorPairRR = "#5555bb";
129
- export declare const colorNeutralRead = "#c8c8c8";
130
129
  /**
131
130
  * #color alignments-pair-orientation | Inter-chromosomal | Mate on another chromosome
132
131
  * #color alignments-insert-size | Inter-chromosomal | Mate on another chromosome
package/esm/ui/palette.js CHANGED
@@ -242,30 +242,6 @@ export const colorPairRL = '#0099bb';
242
242
  export const colorPairLL = '#4d9a4d';
243
243
  /** #color alignments-pair-orientation | RR (← ←) | Both mates on the reverse strand */
244
244
  export const colorPairRR = '#5555bb';
245
- // Was `colorNostrand`, which named the one thing it essentially never paints. A
246
- // SAM record's strand is DEFINED from the reverse flag inside the adapter's
247
- // feature class (`SamRecordFeature.strand`), so it is always +1 or -1, and a
248
- // PAF/synteny block carries a real strand too — `strandCategory`'s `noStrand`
249
- // branch is the defensive third case of a `-1 | 0 | 1` return, not a category
250
- // an alignments track produces. The name survived because the two places that
251
- // DO reach 0 are strand questions of a different kind: a sashimi junction whose
252
- // spliced reads carry no XS/TS/ts tag (ordinary unstranded RNA-seq), and a
253
- // strand-valued read tag that a read simply lacks.
254
- //
255
- // What it actually paints, in volume, is neither — `nonSplit` ("Unsplit read",
256
- // the majority of a pileup under the split-read scheme) and `mapqUnavailable`
257
- // (MAPQ 255). What unites all five is that the scheme's question has no
258
- // informative answer for this read, so the value is the neutral it falls back
259
- // to rather than a statement about strand.
260
- //
261
- // It is NOT the only such neutral: `colorPairLR` #d3d3d3 is the baseline for
262
- // `normalInsert`, `noTagValue` and `plain`, and the two sit dE 3.95 apart —
263
- // close enough that `readTagColors.ts` moved its untagged-read case off this one
264
- // and onto that one, because only that one darkens under the dark theme. Whether
265
- // two neutrals are wanted at all is the open question here; this rename does not
266
- // settle it, and the dark-mode half is
267
- // `agent-docs/ideas/dark-theme-palette-gaps.md`.
268
- export const colorNeutralRead = '#c8c8c8';
269
245
  /**
270
246
  * #color alignments-pair-orientation | Inter-chromosomal | Mate on another chromosome
271
247
  * #color alignments-insert-size | Inter-chromosomal | Mate on another chromosome
@@ -497,9 +473,9 @@ const skip = '#009a8a';
497
473
  * which is the same lie louder — on a foldback the arms are opposite-strand
498
474
  * red and blue, and darkening whichever drew last reads as extra-inverted.
499
475
  *
500
- * So the value has one job: read as NEITHER segment. Every categorized grey in
501
- * the alignments vocabulary is light (`colorPairLR` #d3d3d3, `colorNeutralRead`
502
- * #c8c8c8, and `colorPairLRDark` #8a8a8a on the dark theme), so this sits past
476
+ * So the value has one job: read as NEITHER segment. The alignments vocabulary's
477
+ * one neutral grey is light (`colorPairLR` #d3d3d3, and `colorPairLRDark`
478
+ * #8a8a8a on the dark theme), so this sits past
503
479
  * the dark end of them in light mode and past the light end in dark mode,
504
480
  * which is also why it inverts rather than dimming: on a dark track background
505
481
  * a charcoal span is the background showing through, i.e. a gap where the mark
@@ -6,7 +6,7 @@ import type { SubmitFormProps } from './SubmitForm.tsx';
6
6
  * the launching view occupies.
7
7
  *
8
8
  * Every launcher anchored on what a view is already showing — the synteny
9
- * launches, "read vs ref", the derivative reconstruction — wants exactly this
9
+ * launches, "read vs ref" — wants exactly this
10
10
  * pair, and each had written the same four lines around
11
11
  * {@link ReplaceCurrentViewButton}: the guard, the button, its disabled state,
12
12
  * and the renaming of Submit that only makes sense once there are two buttons.
@@ -7,7 +7,7 @@ import ReplaceCurrentViewButton from './ReplaceCurrentViewButton.js';
7
7
  * the launching view occupies.
8
8
  *
9
9
  * Every launcher anchored on what a view is already showing — the synteny
10
- * launches, "read vs ref", the derivative reconstruction — wants exactly this
10
+ * launches, "read vs ref" — wants exactly this
11
11
  * pair, and each had written the same four lines around
12
12
  * {@link ReplaceCurrentViewButton}: the guard, the button, its disabled state,
13
13
  * and the renaming of Submit that only makes sense once there are two buttons.
package/esm/ui/theme.d.ts CHANGED
@@ -58,7 +58,7 @@ declare module '@mui/material/styles' {
58
58
  alignmentFill?: Partial<AlignmentFill>;
59
59
  }
60
60
  }
61
- export { colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorNeutralRead, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './palette.ts';
61
+ export { colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './palette.ts';
62
62
  export type { JBrowsePalette } from './palette.ts';
63
63
  /**
64
64
  * The structurally-serializable inputs that fully describe a session's active
package/esm/ui/theme.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createTheme } from '@mui/material';
1
+ import { createTheme } from '@mui/material/styles';
2
2
  import { deepMerge } from '../util/deepMerge.js';
3
3
  import { palettePresets, resolvePalette } from './palette.js';
4
4
  import { DEFAULT_FONT_SIZE, DEFAULT_SPACING } from './styleTheme.js';
@@ -9,7 +9,7 @@ import { DEFAULT_FONT_SIZE, DEFAULT_SPACING } from './styleTheme.js';
9
9
  // Static domain colors and the theme presets are re-exported from palette.ts so
10
10
  // existing `@jbrowse/core/ui` imports are unaffected. Import them from
11
11
  // `@jbrowse/core/ui/palette` to get them without pulling in Material UI.
12
- export { colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorNeutralRead, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './palette.js';
12
+ export { colorFwdStrand, colorInterchrom, colorLongInsert, colorLongreadInv, colorPairLL, colorPairLR, colorPairLRDark, colorPairRL, colorPairRR, colorRevStrand, colorShortInsert, colorSplitReadInversion, colorSupplementary, colorUnmappedMate, colorUnmappedMateDark, methylated5hmC, methylated5mC, tagColorPalette, unmethylated5mC, } from './palette.js';
13
13
  // The display names and MUI component overrides layered on top of each palette
14
14
  // preset. The colors come from palette.ts, so a preset's palette is stated once
15
15
  // and this map is the Material UI half of it.
@@ -68,6 +68,10 @@ const baseThemeOptions = {
68
68
  fontSize: DEFAULT_FONT_SIZE,
69
69
  },
70
70
  spacing: DEFAULT_SPACING,
71
+ // an animation makes every popover, dialog and hover trail the input
72
+ motion: {
73
+ reducedMotion: 'always',
74
+ },
71
75
  components: {
72
76
  MuiTooltip: {
73
77
  styleOverrides: {
@@ -90,7 +94,6 @@ const baseThemeOptions = {
90
94
  disableGutters: true,
91
95
  slotProps: {
92
96
  transition: {
93
- timeout: 150,
94
97
  unmountOnExit: true,
95
98
  },
96
99
  },
@@ -166,16 +169,6 @@ const baseThemeOptions = {
166
169
  size: 'small',
167
170
  },
168
171
  },
169
- MuiPopover: {
170
- defaultProps: {
171
- transitionDuration: 0,
172
- },
173
- },
174
- MuiMenu: {
175
- defaultProps: {
176
- transitionDuration: 0,
177
- },
178
- },
179
172
  MuiMenuItem: {
180
173
  defaultProps: {
181
174
  dense: true,
@@ -229,33 +222,6 @@ const baseThemeOptions = {
229
222
  size: 'small',
230
223
  },
231
224
  },
232
- // Speed up ripple animations for snappier feel (default is 550ms)
233
- // See https://mui.com/material-ui/api/button-base/
234
- // and https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ButtonBase/TouchRipple.js
235
- //
236
- // The click ripple only: a *focus* ripple is a different animation on the
237
- // same two elements — childPulsate, which runs `infinite` — so a blanket
238
- // 50ms turns MUI's 2500ms breath into a 20Hz strobe that never stops. It
239
- // shows up on any focus-visible button, and Chrome hands one out unasked:
240
- // it re-evaluates :focus-visible on the already-focused element after any
241
- // keystroke, and the focus event that a browser-tab switch fires on the way
242
- // back is what makes MUI act on it. So these select the enter and leaving
243
- // keyframes by name and let the pulsate keep its own duration.
244
- //
245
- // Both selectors also outrank TouchRipple's own rules on specificity, which
246
- // is what `!important` was here for.
247
- MuiButtonBase: {
248
- styleOverrides: {
249
- root: {
250
- '& .MuiTouchRipple-ripple.MuiTouchRipple-rippleVisible:not(.MuiTouchRipple-ripplePulsate)': {
251
- animationDuration: '50ms',
252
- },
253
- '& .MuiTouchRipple-child.MuiTouchRipple-childLeaving': {
254
- animationDuration: '50ms',
255
- },
256
- },
257
- },
258
- },
259
225
  },
260
226
  };
261
227
  export function createJBrowseBaseTheme(theme = {}) {
@@ -0,0 +1 @@
1
+ export declare const VIEW_HEADER_HEIGHT = 28;
@@ -0,0 +1 @@
1
+ export const VIEW_HEADER_HEIGHT = 28;
@@ -43,7 +43,7 @@ export interface ViewLayout {
43
43
  export declare function moveTo(self: MoveSnap & {
44
44
  zoomTo: (arg: number) => number;
45
45
  scrollTo: (arg: number) => void;
46
- }, start?: BpOffset, end?: BpOffset): void;
46
+ }, start?: BpOffset, end?: BpOffset, minBpPerPx?: number): void;
47
47
  /**
48
48
  * Pure version of moveTo: returns the {bpPerPx, offsetPx} that moveTo would
49
49
  * apply, without mutating any model. Assumes no bpPerPx clamping (i.e.
@@ -28,10 +28,10 @@ function computeScrollPos(self, start, bpPerPx, extraBp) {
28
28
  return Math.round((cumulativeBp(self.displayedRegions, start.index, start.offset) - extraBp) /
29
29
  bpPerPx);
30
30
  }
31
- export function moveTo(self, start, end) {
31
+ export function moveTo(self, start, end, minBpPerPx = 0) {
32
32
  if (start && end) {
33
33
  const targetBpPerPx = computeTargetBpPerPx(self, start, end);
34
- const newBpPerPx = self.zoomTo(targetBpPerPx);
34
+ const newBpPerPx = self.zoomTo(Math.max(targetBpPerPx, minBpPerPx));
35
35
  const extraBp = targetBpPerPx < newBpPerPx
36
36
  ? ((newBpPerPx - targetBpPerPx) * self.width) / 2
37
37
  : 0;
@@ -1,19 +1,21 @@
1
1
  /**
2
- * Restart clip-id numbering for a new export document.
2
+ * Run `render` as one document's clip-id numbering run, starting at 0, then put
3
+ * the counter back.
3
4
  *
4
- * Without it the counter runs for the lifetime of the process, so an export is
5
- * numbered from wherever the previous one stopped and the same view exported
6
- * twice differs in every clip id. That is the churn `svgNodeId` was written to
7
- * get rid of, arriving by a second route: diffing two saved SVGs shows changes
8
- * that aren't real, and `jest -t` on any export test but the first fails its
9
- * checked-in snapshot with a diff that is nothing but renumbering.
5
+ * Starting at 0 is what makes the same view export to the same bytes: a counter
6
+ * left running numbers each export from wherever the previous one stopped, so
7
+ * diffing two saved SVGs shows changes that aren't real and `jest -t` on any
8
+ * export test but the first fails its snapshot on renumbering alone.
10
9
  *
11
- * Called by `wrapSvgExport`, and safe there and only there: the
12
- * `renderToStaticMarkup` it wraps is synchronous, so every `PaintLayer` in the
13
- * document draws before any other export can begin. Anything that resets on a
14
- * boundary an `await` can cross would let two exports share a numbering run.
10
+ * Putting it back is what keeps a file export from renumbering the page: live
11
+ * figures (`useViewSvgFigure`) mint from the same counter into one DOM, where
12
+ * ids must not repeat, so a reset that stuck would let the next figure reuse an
13
+ * id another figure still points at.
14
+ *
15
+ * `render` must be synchronous — an `await` inside it would let two documents
16
+ * share a numbering run.
15
17
  */
16
- export declare function resetSvgClipIds(): void;
18
+ export declare function withFreshSvgClipIds<T>(render: () => T): T;
17
19
  export declare class SvgCanvas {
18
20
  private parts;
19
21
  private pathData;
@@ -36,6 +38,7 @@ export declare class SvgCanvas {
36
38
  private e;
37
39
  private f;
38
40
  private get axisAligned();
41
+ private get lengthScale();
39
42
  private transformPoint;
40
43
  private transformSize;
41
44
  private originMatrixAttr;
@@ -72,7 +75,6 @@ export declare class SvgCanvas {
72
75
  fillText(text: string, x: number, y: number): void;
73
76
  strokeText(text: string, x: number, y: number): void;
74
77
  drawImage(..._args: unknown[]): void;
75
- putImageData(..._args: unknown[]): void;
76
78
  clip(..._args: unknown[]): void;
77
79
  measureText(text: string): {
78
80
  width: number;
@@ -1,4 +1,5 @@
1
1
  import { measureText as measureTextWidth } from './measureText.js';
2
+ import { splitPaintAlpha } from './svgColorProps.js';
2
3
  const XML_ESCAPES = {
3
4
  '&': '&amp;',
4
5
  '<': '&lt;',
@@ -29,14 +30,16 @@ function parseFont(font) {
29
30
  // SVG-compatible attributes. The default sans-serif family is left off so
30
31
  // feature labels match the raw-JSX <text> elements (ruler, scalebar, etc.),
31
32
  // which set no family either; an explicitly-set family is still emitted.
32
- function fontAttrs(font) {
33
+ function fontAttrs(font, scale) {
33
34
  const { prefix, size, family } = parseFont(font);
34
35
  const tokens = prefix.split(/\s+/).filter(Boolean);
35
36
  const weight = tokens.find(t => fontWeightTokens.has(t) || /^\d{1,4}$/.test(t));
36
37
  const style = tokens.find(t => fontStyleTokens.has(t));
37
38
  return [
38
- ` font-size="${size}"`,
39
- family === '' || family === 'sans-serif' ? '' : ` font-family="${family}"`,
39
+ ` font-size="${Number(size) * scale}"`,
40
+ family === '' || family === 'sans-serif'
41
+ ? ''
42
+ : ` font-family="${escapeXml(family)}"`,
40
43
  weight ? ` font-weight="${weight}"` : '',
41
44
  style ? ` font-style="${style}"` : '',
42
45
  ].join('');
@@ -47,25 +50,34 @@ function fontAttrs(font) {
47
50
  // mint `svgcanvas-clip-0`, whereupon `url(#svgcanvas-clip-0)` resolves to the
48
51
  // first and every later layer is clipped to some other layer's rect.
49
52
  //
50
- // Document-global, not process-global: `resetSvgClipIds` below.
53
+ // Document-global, not process-global: `withFreshSvgClipIds` below.
51
54
  let clipIdCounter = 0;
52
55
  /**
53
- * Restart clip-id numbering for a new export document.
56
+ * Run `render` as one document's clip-id numbering run, starting at 0, then put
57
+ * the counter back.
54
58
  *
55
- * Without it the counter runs for the lifetime of the process, so an export is
56
- * numbered from wherever the previous one stopped and the same view exported
57
- * twice differs in every clip id. That is the churn `svgNodeId` was written to
58
- * get rid of, arriving by a second route: diffing two saved SVGs shows changes
59
- * that aren't real, and `jest -t` on any export test but the first fails its
60
- * checked-in snapshot with a diff that is nothing but renumbering.
59
+ * Starting at 0 is what makes the same view export to the same bytes: a counter
60
+ * left running numbers each export from wherever the previous one stopped, so
61
+ * diffing two saved SVGs shows changes that aren't real and `jest -t` on any
62
+ * export test but the first fails its snapshot on renumbering alone.
61
63
  *
62
- * Called by `wrapSvgExport`, and safe there and only there: the
63
- * `renderToStaticMarkup` it wraps is synchronous, so every `PaintLayer` in the
64
- * document draws before any other export can begin. Anything that resets on a
65
- * boundary an `await` can cross would let two exports share a numbering run.
64
+ * Putting it back is what keeps a file export from renumbering the page: live
65
+ * figures (`useViewSvgFigure`) mint from the same counter into one DOM, where
66
+ * ids must not repeat, so a reset that stuck would let the next figure reuse an
67
+ * id another figure still points at.
68
+ *
69
+ * `render` must be synchronous — an `await` inside it would let two documents
70
+ * share a numbering run.
66
71
  */
67
- export function resetSvgClipIds() {
72
+ export function withFreshSvgClipIds(render) {
73
+ const saved = clipIdCounter;
68
74
  clipIdCounter = 0;
75
+ try {
76
+ return render();
77
+ }
78
+ finally {
79
+ clipIdCounter = saved;
80
+ }
69
81
  }
70
82
  export class SvgCanvas {
71
83
  parts = [];
@@ -115,6 +127,13 @@ export class SvgCanvas {
115
127
  get axisAligned() {
116
128
  return this.b === 0 && this.c === 0;
117
129
  }
130
+ // How much the CTM scales a length, for what SVG draws at a size of its own
131
+ // rather than through transformed coordinates: stroke widths, dashes and
132
+ // font sizes. Exact for a uniform scale; the geometric mean otherwise, where
133
+ // a Canvas2D pen would draw an ellipse no stroke-width can state.
134
+ get lengthScale() {
135
+ return Math.sqrt(Math.abs(this.a * this.d - this.b * this.c));
136
+ }
118
137
  transformPoint(x, y) {
119
138
  return [this.a * x + this.c * y + this.e, this.b * x + this.d * y + this.f];
120
139
  }
@@ -170,23 +189,20 @@ export class SvgCanvas {
170
189
  ? 'end'
171
190
  : 'start';
172
191
  }
173
- // Split rgba(r,g,b,a) into separate color + opacity SVG attributes for
174
- // compatibility with SVG 1.1 consumers like Inkscape that don't honor the
175
- // alpha component of CSS3 rgba() fill/stroke values. Whitespace-tolerant so
176
- // spaced forms (MUI alpha(), colord toRgbString → "rgba(255, 177, 29, 0.12)")
177
- // are separated too, not just the compact "rgba(255,177,29,0.12)".
178
192
  paintAttr(name, style) {
179
193
  const s = `${style}`;
180
- const m = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)$/.exec(s);
181
- if (m) {
182
- const a = Number.parseFloat(m[4]);
183
- const base = `${name}="rgb(${m[1]},${m[2]},${m[3]})"`;
184
- return a < 1 ? `${base} ${name}-opacity="${a}"` : base;
194
+ const split = splitPaintAlpha(s);
195
+ if (!split) {
196
+ return `${name}="${s}"`;
185
197
  }
186
- return `${name}="${s}"`;
198
+ const base = `${name}="${split.color}"`;
199
+ return split.opacity < 1
200
+ ? `${base} ${name}-opacity="${split.opacity}"`
201
+ : base;
187
202
  }
188
203
  strokeAttrs() {
189
- let attrs = ` ${this.paintAttr('stroke', this.strokeStyle)} stroke-width="${this.lineWidth}"`;
204
+ const scale = this.lengthScale;
205
+ let attrs = ` ${this.paintAttr('stroke', this.strokeStyle)} stroke-width="${this.lineWidth * scale}"`;
190
206
  if (this.lineCap !== 'butt') {
191
207
  attrs += ` stroke-linecap="${this.lineCap}"`;
192
208
  }
@@ -194,7 +210,7 @@ export class SvgCanvas {
194
210
  attrs += ` stroke-linejoin="${this.lineJoin}"`;
195
211
  }
196
212
  if (this.lineDash.length > 0) {
197
- attrs += ` stroke-dasharray="${this.lineDash.join(',')}"`;
213
+ attrs += ` stroke-dasharray="${this.lineDash.map(d => d * scale).join(',')}"`;
198
214
  }
199
215
  return attrs;
200
216
  }
@@ -358,34 +374,40 @@ export class SvgCanvas {
358
374
  this.ellipse(x, y, radius, radius, 0, startAngle, endAngle, counterclockwise);
359
375
  }
360
376
  ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise = false) {
361
- const [cx, cy] = this.transformPoint(x, y);
362
377
  const [rx, ry] = this.transformSize(radiusX, radiusY);
363
- const sweep = counterclockwise ? 0 : 1;
364
- const diff = endAngle - startAngle;
365
- const deg = (rotation * 180) / Math.PI;
378
+ // A mirrored CTM turns a clockwise sweep counterclockwise on the page, and
379
+ // its rotation the other way.
380
+ const mirrored = this.a * this.d < 0;
381
+ const sweep = counterclockwise === mirrored ? 1 : 0;
382
+ const deg = ((mirrored ? -rotation : rotation) * 180) / Math.PI;
366
383
  // Canvas measures the angle on the UNROTATED ellipse and then spins the
367
384
  // whole thing, so the endpoint is the parametric point rotated — not the
368
- // point at (angle + rotation).
385
+ // point at (angle + rotation) — and then placed by the CTM.
369
386
  const at = (angle) => {
370
- const px = rx * Math.cos(angle);
371
- const py = ry * Math.sin(angle);
372
- return [
373
- cx + px * Math.cos(rotation) - py * Math.sin(rotation),
374
- cy + px * Math.sin(rotation) + py * Math.cos(rotation),
375
- ];
387
+ const px = radiusX * Math.cos(angle);
388
+ const py = radiusY * Math.sin(angle);
389
+ return this.transformPoint(x + px * Math.cos(rotation) - py * Math.sin(rotation), y + px * Math.sin(rotation) + py * Math.cos(rotation));
376
390
  };
377
- if (Math.abs(diff) >= 2 * Math.PI) {
391
+ // The angle actually swept, as Canvas2D resolves it: in the stated
392
+ // direction, a whole turn once it reaches 2π, and otherwise wrapped into
393
+ // [0, 2π) — so a clockwise sweep from 0.5π back to 0 goes the long way.
394
+ const TAU = 2 * Math.PI;
395
+ const signed = counterclockwise
396
+ ? startAngle - endAngle
397
+ : endAngle - startAngle;
398
+ const swept = signed >= TAU ? TAU : ((signed % TAU) + TAU) % TAU;
399
+ const [sx, sy] = at(startAngle);
400
+ if (swept === TAU) {
378
401
  // A closed ellipse has coincident endpoints, which an SVG arc command
379
- // degenerates on — so go round in two halves.
380
- const [mx, my] = at(startAngle);
381
- const [halfX, halfY] = at(startAngle + Math.PI);
382
- this.pathData += `M${mx},${my}A${rx},${ry} ${deg} 1 ${sweep} ${halfX},${halfY}A${rx},${ry} ${deg} 1 ${sweep} ${mx},${my}`;
402
+ // degenerates on — so go round in two halves, as a subpath of its own.
403
+ const half = counterclockwise ? -Math.PI : Math.PI;
404
+ const [hx, hy] = at(startAngle + half);
405
+ this.pathData += `M${sx},${sy}A${rx},${ry} ${deg} 1 ${sweep} ${hx},${hy}A${rx},${ry} ${deg} 1 ${sweep} ${sx},${sy}`;
383
406
  return;
384
407
  }
385
- const [sx, sy2] = at(startAngle);
386
408
  const [ex, ey] = at(endAngle);
387
- const largeArc = Math.abs(diff) > Math.PI ? 1 : 0;
388
- this.pathData += !this.pathData ? `M${sx},${sy2}` : `L${sx},${sy2}`;
409
+ const largeArc = swept > Math.PI ? 1 : 0;
410
+ this.pathData += !this.pathData ? `M${sx},${sy}` : `L${sx},${sy}`;
389
411
  this.pathData += `A${rx},${ry} ${deg} ${largeArc} ${sweep} ${ex},${ey}`;
390
412
  }
391
413
  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
@@ -441,19 +463,16 @@ export class SvgCanvas {
441
463
  fillText(text, x, y) {
442
464
  const [tx, ty] = this.transformPoint(x, y);
443
465
  const escaped = escapeXml(text);
444
- this.emit(`<text x="${tx}" y="${ty}" ${this.paintAttr('fill', this.fillStyle)}${fontAttrs(this.font)} text-anchor="${this.textAnchor()}" dominant-baseline="${this.dominantBaseline()}">${escaped}</text>`);
466
+ this.emit(`<text x="${tx}" y="${ty}" ${this.paintAttr('fill', this.fillStyle)}${fontAttrs(this.font, this.lengthScale)} text-anchor="${this.textAnchor()}" dominant-baseline="${this.dominantBaseline()}">${escaped}</text>`);
445
467
  }
446
468
  strokeText(text, x, y) {
447
469
  const [tx, ty] = this.transformPoint(x, y);
448
470
  const escaped = escapeXml(text);
449
- this.emit(`<text x="${tx}" y="${ty}" fill="none"${this.strokeAttrs()}${fontAttrs(this.font)} text-anchor="${this.textAnchor()}" dominant-baseline="${this.dominantBaseline()}">${escaped}</text>`);
471
+ this.emit(`<text x="${tx}" y="${ty}" fill="none"${this.strokeAttrs()}${fontAttrs(this.font, this.lengthScale)} text-anchor="${this.textAnchor()}" dominant-baseline="${this.dominantBaseline()}">${escaped}</text>`);
450
472
  }
451
473
  drawImage(..._args) {
452
474
  // no-op: raster images can't be meaningfully serialized to SVG paths
453
475
  }
454
- putImageData(..._args) {
455
- // no-op
456
- }
457
476
  clip(..._args) {
458
477
  // Use the current path as a clipPath, then open a `<g clip-path>`
459
478
  // group that subsequent draws will land inside. The group is closed by
@@ -20,4 +20,43 @@ export declare function handleFetchError(exception: unknown, isCurrent: () => bo
20
20
  * @param exception -
21
21
  */
22
22
  export declare function isAbortException(exception: unknown): boolean;
23
+ /**
24
+ * Throw an AbortError if `signal` has aborted. A `signal.aborted` read, so it
25
+ * is cheap enough for the body of a loop; place it after any await and in any
26
+ * per-item callback a reader hands you.
27
+ */
28
+ export declare function checkAbortSignal(signal?: AbortSignal): void;
29
+ /**
30
+ * Run an awaited stage under `signal`: checked before it starts, and again
31
+ * once it settles. The check after is the one that gets left out when the two
32
+ * are placed by hand — a stop landing during a long await otherwise goes
33
+ * unseen until the next stage.
34
+ */
35
+ export declare function withAbortCheck<T>(signal: AbortSignal | undefined, fn: () => T | Promise<T>): Promise<T>;
36
+ export interface AbortBreakpoint {
37
+ /** True once every ~50 ms of wall time, otherwise a counter bump. */
38
+ due(): boolean;
39
+ /** Yield a task so a posted abort can land, then throw if it did. */
40
+ yield(): Promise<void>;
41
+ }
42
+ /**
43
+ * Cancellation for a loop that can run for seconds without awaiting — a
44
+ * whole-genome projection, a matrix fill. A `signal.aborted` read inside such a
45
+ * loop never changes, because the abort is a posted message; the loop has to
46
+ * give the event loop a turn now and then. A loop bounded by the byte gate or
47
+ * one region's features finishes before this would matter and only checks.
48
+ *
49
+ * const breakpoint = createAbortBreakpoint(signal)
50
+ * for (const row of rows) {
51
+ * if (breakpoint.due()) {
52
+ * await breakpoint.yield()
53
+ * }
54
+ * …
55
+ * }
56
+ *
57
+ * Two calls rather than one because an `await` on a non-promise still costs a
58
+ * microtask, about 60 ns against 2 ns for the `due()` read, and a loop over
59
+ * every read in a pileup notices the difference.
60
+ */
61
+ export declare function createAbortBreakpoint(signal?: AbortSignal): AbortBreakpoint;
23
62
  export {};