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

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 (637) hide show
  1. package/README.md +1709 -390
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.d.ts +3 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +5 -5
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -5
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +34 -29
  6. package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCard.js +1 -4
  7. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.d.ts +11 -0
  8. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +37 -14
  9. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.d.ts +1 -1
  10. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.js +15 -31
  11. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +4 -3
  12. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.js +12 -25
  13. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetailsFrame.d.ts +11 -0
  14. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetailsFrame.js +11 -0
  15. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.d.ts +8 -0
  16. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.js +24 -0
  17. package/esm/BaseFeatureWidget/BaseFeatureDetail/Formatter.js +6 -4
  18. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
  19. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
  20. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts +3 -2
  21. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.js +5 -3
  22. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.d.ts +6 -2
  23. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +7 -18
  24. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.d.ts +16 -0
  25. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +49 -0
  26. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.d.ts +0 -8
  27. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.js +6 -29
  28. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceContents.js +7 -34
  29. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
  30. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceName.js +2 -2
  31. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/TranscriptSelector.js +3 -1
  32. package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.d.ts +12 -0
  33. package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.js +12 -5
  34. package/esm/BaseFeatureWidget/SequenceFeatureDetails/useSequenceData.js +8 -5
  35. package/esm/BaseFeatureWidget/configSchema.d.ts +1 -1
  36. package/esm/BaseFeatureWidget/formatDetails.d.ts +13 -29
  37. package/esm/BaseFeatureWidget/formatDetails.js +62 -83
  38. package/esm/BaseFeatureWidget/index.d.ts +2 -1
  39. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +42 -29
  40. package/esm/BaseFeatureWidget/stateModelFactory.js +98 -98
  41. package/esm/BaseFeatureWidget/types.d.ts +12 -6
  42. package/esm/BaseFeatureWidget/util.d.ts +0 -10
  43. package/esm/BaseFeatureWidget/util.js +0 -17
  44. package/esm/CorePlugin.js +34 -3
  45. package/esm/PluginLoader.d.ts +24 -13
  46. package/esm/PluginLoader.js +167 -51
  47. package/esm/PluginManager.d.ts +130 -24
  48. package/esm/PluginManager.js +180 -32
  49. package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
  50. package/esm/ReExports/MuiDataGridReExports.js +2 -2
  51. package/esm/ReExports/coreModules.generated.d.ts +2 -0
  52. package/esm/ReExports/coreModules.generated.js +530 -0
  53. package/esm/ReExports/coreWorkerModules.generated.d.ts +2 -0
  54. package/esm/ReExports/coreWorkerModules.generated.js +490 -0
  55. package/esm/ReExports/frameworkModules.d.ts +2 -0
  56. package/esm/ReExports/frameworkModules.js +68 -0
  57. package/esm/ReExports/frameworkShared.d.ts +12 -0
  58. package/esm/ReExports/frameworkShared.js +16 -0
  59. package/esm/ReExports/frameworkWorkerModules.generated.d.ts +2 -0
  60. package/esm/ReExports/frameworkWorkerModules.generated.js +130 -0
  61. package/esm/ReExports/list.js +528 -79
  62. package/esm/ReExports/modules.d.ts +1 -1
  63. package/esm/ReExports/modules.js +10 -165
  64. package/esm/ReExports/registry.d.ts +1 -0
  65. package/esm/ReExports/registry.js +23 -5
  66. package/esm/ReExports/uiStub.d.ts +3 -0
  67. package/esm/ReExports/uiStub.js +33 -0
  68. package/esm/ReExports/workerModules.d.ts +2 -0
  69. package/esm/ReExports/workerModules.js +11 -0
  70. package/esm/TextSearch/TextSearchManager.d.ts +27 -13
  71. package/esm/TextSearch/TextSearchManager.js +77 -36
  72. package/esm/TextSearch/places.d.ts +12 -0
  73. package/esm/TextSearch/places.js +94 -0
  74. package/esm/assemblyManager/assembly.d.ts +21 -19
  75. package/esm/assemblyManager/assembly.js +28 -26
  76. package/esm/assemblyManager/assemblyAdapters.d.ts +1 -1
  77. package/esm/assemblyManager/assemblyAdapters.js +8 -2
  78. package/esm/assemblyManager/assemblyConfigSchema.d.ts +31 -90
  79. package/esm/assemblyManager/assemblyConfigSchema.js +35 -47
  80. package/esm/assemblyManager/assemblyManager.d.ts +35 -180
  81. package/esm/assemblyManager/assemblyManager.js +47 -51
  82. package/esm/assemblyManager/expandAssemblyConfigShorthand.d.ts +25 -18
  83. package/esm/assemblyManager/expandAssemblyConfigShorthand.js +78 -49
  84. package/esm/assemblyManager/geneticCodes.js +2 -5
  85. package/esm/assemblyManager/getSequenceAdapterConfig.d.ts +10 -0
  86. package/esm/assemblyManager/getSequenceAdapterConfig.js +10 -0
  87. package/esm/assemblyManager/indexAssemblyNames.d.ts +9 -0
  88. package/esm/assemblyManager/indexAssemblyNames.js +22 -0
  89. package/esm/assemblyManager/loadRefNameMap.d.ts +1 -1
  90. package/esm/assemblyManager/loadRefNameMap.js +4 -9
  91. package/esm/assemblyManager/refNameMapKey.d.ts +7 -0
  92. package/esm/assemblyManager/refNameMapKey.js +12 -0
  93. package/esm/checkPlugins.d.ts +2 -0
  94. package/esm/checkPlugins.js +38 -17
  95. package/esm/configuration/bamIndexFields.d.ts +49 -0
  96. package/esm/configuration/bamIndexFields.js +41 -0
  97. package/esm/configuration/configurationSchema.d.ts +101 -71
  98. package/esm/configuration/configurationSchema.js +207 -134
  99. package/esm/configuration/configurationSchemaUnion.d.ts +39 -0
  100. package/esm/configuration/configurationSchemaUnion.js +56 -0
  101. package/esm/configuration/configurationSlot.d.ts +150 -60
  102. package/esm/configuration/configurationSlot.js +103 -75
  103. package/esm/configuration/fillLocations.d.ts +14 -0
  104. package/esm/configuration/fillLocations.js +14 -0
  105. package/esm/configuration/formatAboutConfigSchema.d.ts +7 -21
  106. package/esm/configuration/formatDetailsConfigSchema.d.ts +11 -37
  107. package/esm/configuration/formatDetailsConfigSchema.js +10 -13
  108. package/esm/configuration/fullConfSnapshot.d.ts +4 -19
  109. package/esm/configuration/fullConfSnapshot.js +30 -52
  110. package/esm/configuration/getConf.d.ts +45 -41
  111. package/esm/configuration/getConf.js +111 -44
  112. package/esm/configuration/index.d.ts +26 -11
  113. package/esm/configuration/index.js +16 -7
  114. package/esm/configuration/indexType.d.ts +26 -0
  115. package/esm/configuration/indexType.js +38 -0
  116. package/esm/configuration/mergeFormatCallbacks.d.ts +6 -7
  117. package/esm/configuration/mergeFormatCallbacks.js +13 -10
  118. package/esm/configuration/plot.d.ts +61 -0
  119. package/esm/configuration/plot.js +142 -0
  120. package/esm/configuration/readConfObject.d.ts +2 -24
  121. package/esm/configuration/readConfObject.js +20 -63
  122. package/esm/configuration/requirements.d.ts +37 -0
  123. package/esm/configuration/requirements.js +88 -0
  124. package/esm/configuration/schemaRegistry.d.ts +32 -15
  125. package/esm/configuration/schemaRegistry.js +33 -35
  126. package/esm/configuration/schemaTypes.d.ts +21 -5
  127. package/esm/configuration/schemaTypes.js +66 -55
  128. package/esm/configuration/slotFacade.d.ts +12 -29
  129. package/esm/configuration/slotFacade.js +44 -23
  130. package/esm/configuration/snapshotPreprocess.d.ts +43 -0
  131. package/esm/configuration/snapshotPreprocess.js +161 -0
  132. package/esm/configuration/tabixIndexFields.d.ts +30 -4
  133. package/esm/configuration/tabixIndexFields.js +21 -4
  134. package/esm/configuration/tabixShorthand.d.ts +34 -17
  135. package/esm/configuration/tabixShorthand.js +49 -22
  136. package/esm/configuration/types.d.ts +182 -43
  137. package/esm/configuration/uriShorthand.d.ts +9 -0
  138. package/esm/configuration/uriShorthand.js +16 -0
  139. package/esm/data_adapters/BaseAdapter/BaseAdapter.d.ts +13 -19
  140. package/esm/data_adapters/BaseAdapter/BaseAdapter.js +12 -19
  141. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +40 -2
  142. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +68 -5
  143. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +40 -0
  144. package/esm/data_adapters/BaseAdapter/featureDensity.js +31 -0
  145. package/esm/data_adapters/BaseAdapter/index.d.ts +23 -3
  146. package/esm/data_adapters/BaseAdapter/index.js +1 -0
  147. package/esm/data_adapters/BaseAdapter/rowSources.d.ts +37 -0
  148. package/esm/data_adapters/BaseAdapter/rowSources.js +7 -0
  149. package/esm/data_adapters/BaseAdapter/stats.d.ts +33 -1
  150. package/esm/data_adapters/BaseAdapter/stats.js +52 -13
  151. package/esm/data_adapters/BaseAdapter/types.d.ts +8 -12
  152. package/esm/data_adapters/BaseAdapter/zoomRange.d.ts +10 -0
  153. package/esm/data_adapters/CytobandAdapter/CytobandAdapter.js +1 -1
  154. package/esm/data_adapters/CytobandAdapter/configSchema.d.ts +7 -11
  155. package/esm/data_adapters/CytobandAdapter/configSchema.js +3 -17
  156. package/esm/data_adapters/dataAdapterCache.d.ts +19 -2
  157. package/esm/data_adapters/dataAdapterCache.js +44 -10
  158. package/esm/data_adapters/getFeatureAdapter.d.ts +6 -4
  159. package/esm/data_adapters/getFeatureAdapter.js +8 -8
  160. package/esm/data_adapters/getSequenceSubAdapter.d.ts +7 -9
  161. package/esm/data_adapters/getSequenceSubAdapter.js +8 -10
  162. package/esm/pluggableElementTypes/AdapterType.d.ts +8 -8
  163. package/esm/pluggableElementTypes/AdapterType.js +1 -1
  164. package/esm/pluggableElementTypes/DisplayType.d.ts +53 -16
  165. package/esm/pluggableElementTypes/DisplayType.js +28 -12
  166. package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +32 -0
  167. package/esm/pluggableElementTypes/LazyStateModelElement.js +77 -0
  168. package/esm/pluggableElementTypes/PluggableElementBase.d.ts +3 -5
  169. package/esm/pluggableElementTypes/PluggableElementBase.js +3 -5
  170. package/esm/pluggableElementTypes/RpcMethodType.d.ts +11 -1
  171. package/esm/pluggableElementTypes/RpcMethodType.js +25 -9
  172. package/esm/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions.d.ts +1 -2
  173. package/esm/pluggableElementTypes/TextSearchAdapterType.d.ts +7 -7
  174. package/esm/pluggableElementTypes/ViewType.d.ts +20 -4
  175. package/esm/pluggableElementTypes/ViewType.js +32 -4
  176. package/esm/pluggableElementTypes/WidgetType.d.ts +6 -0
  177. package/esm/pluggableElementTypes/WidgetType.js +6 -0
  178. package/esm/pluggableElementTypes/addMenuItems.d.ts +3 -2
  179. package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
  180. package/esm/pluggableElementTypes/extendElementType.js +9 -5
  181. package/esm/pluggableElementTypes/index.d.ts +2 -1
  182. package/esm/pluggableElementTypes/index.js +2 -9
  183. package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +19 -9
  184. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +122 -28
  185. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +155 -11
  186. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +65 -16
  187. package/esm/pluggableElementTypes/models/BaseTrackModel.js +179 -117
  188. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +87 -18
  189. package/esm/pluggableElementTypes/models/BaseViewModel.js +54 -11
  190. package/esm/pluggableElementTypes/models/InternetAccountModel.d.ts +26 -16
  191. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +15 -11
  192. package/esm/pluggableElementTypes/models/assertDisplayContract.js +25 -32
  193. package/esm/pluggableElementTypes/models/baseConnectionConfig.d.ts +22 -18
  194. package/esm/pluggableElementTypes/models/baseConnectionConfig.js +5 -5
  195. package/esm/pluggableElementTypes/models/baseInternetAccountConfig.d.ts +26 -31
  196. package/esm/pluggableElementTypes/models/baseTrackConfig.d.ts +108 -147
  197. package/esm/pluggableElementTypes/models/baseTrackConfig.js +96 -73
  198. package/esm/pluggableElementTypes/models/components/SaveTrackData.js +4 -6
  199. package/esm/pluggableElementTypes/models/components/fetchTrackData.d.ts +3 -4
  200. package/esm/pluggableElementTypes/models/components/fetchTrackData.js +3 -3
  201. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.d.ts +23 -13
  202. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.js +80 -48
  203. package/esm/pluggableElementTypes/models/index.d.ts +2 -3
  204. package/esm/pluggableElementTypes/models/index.js +2 -3
  205. package/esm/pluggableElementTypes/models/migrateTrackConfig.d.ts +15 -1
  206. package/esm/pluggableElementTypes/models/migrateTrackConfig.js +85 -25
  207. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.d.ts +4 -3
  208. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.js +141 -19
  209. package/esm/pluggableElementTypes/models/saveTrackFileTypes/types.d.ts +3 -3
  210. package/esm/pluginDefinitions.d.ts +34 -7
  211. package/esm/pluginDefinitions.js +54 -20
  212. package/esm/rpc/BaseRpcDriver.d.ts +2 -2
  213. package/esm/rpc/BaseRpcDriver.js +25 -30
  214. package/esm/rpc/MainThreadRpcDriver.d.ts +2 -2
  215. package/esm/rpc/MainThreadRpcDriver.js +13 -8
  216. package/esm/rpc/RpcClient.d.ts +18 -6
  217. package/esm/rpc/RpcClient.js +51 -16
  218. package/esm/rpc/RpcManager.d.ts +14 -10
  219. package/esm/rpc/RpcManager.js +11 -1
  220. package/esm/rpc/RpcRegistry.d.ts +40 -7
  221. package/esm/rpc/RpcServer.d.ts +3 -1
  222. package/esm/rpc/RpcServer.js +19 -12
  223. package/esm/rpc/WebWorkerRpcDriver.d.ts +11 -4
  224. package/esm/rpc/WebWorkerRpcDriver.js +64 -68
  225. package/esm/rpc/byteBudget.d.ts +20 -5
  226. package/esm/rpc/byteBudget.js +16 -5
  227. package/esm/rpc/configSchema.d.ts +7 -21
  228. package/esm/rpc/coreRpcMethods.d.ts +4 -0
  229. package/esm/rpc/coreRpcMethods.js +4 -0
  230. package/esm/rpc/methods/CoreGetEncodedFeature.d.ts +13 -0
  231. package/esm/rpc/methods/CoreGetEncodedFeature.js +32 -0
  232. package/esm/rpc/methods/CoreGetEncodedLayers.d.ts +16 -0
  233. package/esm/rpc/methods/CoreGetEncodedLayers.js +59 -0
  234. package/esm/rpc/methods/CoreGetExportData.js +3 -4
  235. package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +11 -0
  236. package/esm/rpc/methods/CoreGetFeatureDensity.js +22 -0
  237. package/esm/rpc/methods/CoreGetFeatures.js +3 -5
  238. package/esm/rpc/methods/CoreGetRefNames.js +2 -12
  239. package/esm/rpc/methods/CoreGetRegionByteEstimate.js +1 -1
  240. package/esm/rpc/methods/CoreGetSequence.js +2 -2
  241. package/esm/rpc/methods/CoreLoadAdapterCode.d.ts +13 -0
  242. package/esm/rpc/methods/CoreLoadAdapterCode.js +16 -0
  243. package/esm/rpc/methods/layerFeatures.d.ts +33 -0
  244. package/esm/rpc/methods/layerFeatures.js +29 -0
  245. package/esm/svg/SvgExport.js +6 -7
  246. package/esm/svg/SvgThemeProviders.d.ts +12 -0
  247. package/esm/svg/SvgThemeProviders.js +15 -0
  248. package/esm/svg/exportViewSvg.d.ts +28 -0
  249. package/esm/svg/exportViewSvg.js +13 -0
  250. package/esm/svg/normalizeSvgMarkup.d.ts +7 -0
  251. package/esm/svg/normalizeSvgMarkup.js +99 -0
  252. package/esm/svg/serializeSvg.d.ts +7 -0
  253. package/esm/svg/serializeSvg.js +11 -0
  254. package/esm/svg/svgId.d.ts +1 -1
  255. package/esm/svg/svgId.js +1 -1
  256. package/esm/svg/svgReady.d.ts +9 -7
  257. package/esm/svg/svgReady.js +8 -7
  258. package/esm/svg/trackNames.d.ts +7 -5
  259. package/esm/svg/trackNames.js +12 -9
  260. package/esm/svg/wrapSvgExport.js +6 -74
  261. package/esm/ui/AddCustomPluginDialog.js +3 -8
  262. package/esm/ui/AppReadyMarker.d.ts +45 -0
  263. package/esm/ui/AppReadyMarker.js +89 -0
  264. package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
  265. package/esm/ui/CascadingMenu.js +181 -104
  266. package/esm/ui/DropDownMenu.js +2 -1
  267. package/esm/ui/ErrorBanner.js +1 -1
  268. package/esm/ui/ErrorBoundary.d.ts +2 -2
  269. package/esm/ui/ErrorMessageStackTraceContents.js +2 -1
  270. package/esm/ui/ErrorMessageStackTraceDialog.js +5 -11
  271. package/esm/ui/ExportSvgDialog.d.ts +1 -1
  272. package/esm/ui/FileDropZone.js +2 -1
  273. package/esm/ui/FileSelector/useInternetAccounts.d.ts +156 -96
  274. package/esm/ui/HoverMenu.d.ts +1 -2
  275. package/esm/ui/HoverMenu.js +6 -3
  276. package/esm/ui/JexlFilterDialog.d.ts +13 -10
  277. package/esm/ui/JexlFilterDialog.js +122 -50
  278. package/esm/ui/JexlFilterRowEditors.d.ts +15 -0
  279. package/esm/ui/JexlFilterRowEditors.js +90 -0
  280. package/esm/ui/LazyBaseTooltip.d.ts +4 -0
  281. package/esm/ui/LazyBaseTooltip.js +9 -0
  282. package/esm/ui/LegendSwatchGlyph.js +26 -21
  283. package/esm/ui/LoadingOverlay.d.ts +14 -0
  284. package/esm/ui/LoadingOverlay.js +4 -2
  285. package/esm/ui/MenuTypes.d.ts +23 -53
  286. package/esm/ui/MenuTypes.js +3 -0
  287. package/esm/ui/MonospaceTextField.d.ts +2 -1
  288. package/esm/ui/MonospaceTextField.js +23 -20
  289. package/esm/ui/PaletteContext.d.ts +10 -5
  290. package/esm/ui/PaletteContext.js +44 -6
  291. package/esm/ui/RefNameAutocomplete/SearchOption.d.ts +13 -0
  292. package/esm/ui/RefNameAutocomplete/SearchOption.js +45 -0
  293. package/esm/ui/RefNameAutocomplete/index.d.ts +1 -2
  294. package/esm/ui/RefNameAutocomplete/index.js +8 -2
  295. package/esm/ui/RefNameAutocomplete/util.d.ts +13 -0
  296. package/esm/ui/RefNameAutocomplete/util.js +42 -1
  297. package/esm/ui/ResizeHandle.d.ts +3 -1
  298. package/esm/ui/ResizeHandle.js +44 -11
  299. package/esm/ui/ScrollChrome.d.ts +13 -0
  300. package/esm/ui/ScrollChrome.js +11 -0
  301. package/esm/ui/ScrollEdgeShadow.d.ts +6 -9
  302. package/esm/ui/ScrollEdgeShadow.js +14 -35
  303. package/esm/ui/ScrollZoomToggle.d.ts +4 -27
  304. package/esm/ui/ScrollZoomToggle.js +34 -51
  305. package/esm/ui/SessionJsonPanel.d.ts +3 -0
  306. package/esm/ui/SessionJsonPanel.js +14 -0
  307. package/esm/ui/SettingsChangesTable.d.ts +1 -0
  308. package/esm/ui/SettingsChangesTable.js +49 -11
  309. package/esm/ui/ShareLinkField.d.ts +1 -3
  310. package/esm/ui/ShareLinkField.js +13 -40
  311. package/esm/ui/SizeSliderRow.d.ts +1 -3
  312. package/esm/ui/SizeSliderRow.js +4 -6
  313. package/esm/ui/SnackbarModel.js +79 -67
  314. package/esm/ui/StatusProgressBar.js +2 -2
  315. package/esm/ui/SvgColorLegend.d.ts +9 -4
  316. package/esm/ui/SvgColorLegend.js +82 -41
  317. package/esm/ui/VerticalScrollbar.d.ts +13 -34
  318. package/esm/ui/VerticalScrollbar.js +29 -83
  319. package/esm/ui/ViewLoadingScreen.d.ts +5 -4
  320. package/esm/ui/ViewLoadingScreen.js +8 -32
  321. package/esm/ui/colorScale.d.ts +92 -0
  322. package/esm/ui/colorScale.js +72 -0
  323. package/esm/ui/colors.d.ts +64 -0
  324. package/esm/ui/colors.js +230 -1
  325. package/esm/ui/hoverBoxStyle.d.ts +14 -2
  326. package/esm/ui/hoverBoxStyle.js +17 -2
  327. package/esm/ui/index.d.ts +12 -12
  328. package/esm/ui/index.js +14 -22
  329. package/esm/ui/launchViewMenu.js +15 -5
  330. package/esm/ui/legendMenuItem.d.ts +10 -32
  331. package/esm/ui/legendMenuItem.js +9 -36
  332. package/esm/ui/legendSpec.d.ts +15 -8
  333. package/esm/ui/legendSpec.js +14 -23
  334. package/esm/ui/makeSizeMenu.d.ts +0 -6
  335. package/esm/ui/makeSizeMenu.js +6 -30
  336. package/esm/ui/measureLegendText.js +1 -1
  337. package/esm/ui/menuItemAdornment.d.ts +9 -20
  338. package/esm/ui/menuItemAdornment.js +10 -32
  339. package/esm/ui/menuItems.d.ts +2 -7
  340. package/esm/ui/menuItems.js +1 -6
  341. package/esm/ui/multiTrackMenuItems.d.ts +6 -0
  342. package/esm/ui/palette.d.ts +118 -116
  343. package/esm/ui/palette.js +114 -75
  344. package/esm/ui/replaceViewAction.d.ts +1 -1
  345. package/esm/ui/replaceViewAction.js +1 -1
  346. package/esm/ui/theme.d.ts +43 -119
  347. package/esm/ui/theme.js +62 -78
  348. package/esm/ui/toggleMenuItems.d.ts +1 -3
  349. package/esm/ui/toggleMenuItems.js +6 -5
  350. package/esm/ui/useAssemblySelection.d.ts +4 -4
  351. package/esm/ui/viewHeaderHeight.d.ts +1 -0
  352. package/esm/ui/viewHeaderHeight.js +1 -0
  353. package/esm/util/Base1DUtils.d.ts +5 -3
  354. package/esm/util/Base1DUtils.js +14 -6
  355. package/esm/util/Base1DViewModel.d.ts +2 -1
  356. package/esm/util/Base1DViewModel.js +3 -2
  357. package/esm/util/SvgCanvas.d.ts +15 -13
  358. package/esm/util/SvgCanvas.js +76 -56
  359. package/esm/util/TimeTraveller.d.ts +3 -0
  360. package/esm/util/TimeTraveller.js +34 -2
  361. package/esm/util/aborting.d.ts +39 -0
  362. package/esm/util/aborting.js +88 -6
  363. package/esm/util/adapterMetadata.d.ts +1 -1
  364. package/esm/util/adapterMetadata.js +6 -5
  365. package/esm/util/addAndShowTrack.d.ts +2 -5
  366. package/esm/util/addAndShowTrack.js +5 -1
  367. package/esm/util/addRelativeUris.d.ts +17 -5
  368. package/esm/util/addRelativeUris.js +46 -10
  369. package/esm/util/addTrackFromWidget.d.ts +2 -5
  370. package/esm/util/addTrackFromWidget.js +5 -4
  371. package/esm/util/aggregateFieldName.d.ts +10 -0
  372. package/esm/util/aggregateFieldName.js +8 -0
  373. package/esm/util/analytics.js +46 -13
  374. package/esm/util/animationAllowed.d.ts +9 -0
  375. package/esm/util/animationAllowed.js +13 -0
  376. package/esm/util/applyRowResizeWheel.d.ts +10 -5
  377. package/esm/util/applyRowResizeWheel.js +10 -21
  378. package/esm/util/bandHeight.d.ts +10 -0
  379. package/esm/util/bandHeight.js +29 -0
  380. package/esm/util/bandLayout.d.ts +4 -4
  381. package/esm/util/bandLayout.js +4 -4
  382. package/esm/util/baseDisplayConfig.d.ts +8 -0
  383. package/esm/util/baseDisplayConfig.js +27 -0
  384. package/esm/util/bezierConnector.d.ts +4 -3
  385. package/esm/util/bezierConnector.js +38 -45
  386. package/esm/util/bgzfWorkerPool.d.ts +20 -74
  387. package/esm/util/bgzfWorkerPool.js +20 -74
  388. package/esm/util/binnedAggregate.d.ts +17 -0
  389. package/esm/util/binnedAggregate.js +275 -0
  390. package/esm/util/cacheBudgets.d.ts +22 -19
  391. package/esm/util/cacheBudgets.js +22 -19
  392. package/esm/util/cachedSetup.d.ts +16 -6
  393. package/esm/util/cachedSetup.js +108 -38
  394. package/esm/util/categoricalField.d.ts +56 -0
  395. package/esm/util/categoricalField.js +73 -0
  396. package/esm/util/cellMatches.d.ts +23 -0
  397. package/esm/util/cellMatches.js +264 -0
  398. package/esm/util/cellsStep.d.ts +29 -0
  399. package/esm/util/cellsStep.js +437 -0
  400. package/esm/util/clampToContig.d.ts +17 -0
  401. package/esm/util/clampToContig.js +19 -0
  402. package/esm/util/coarseStripHTML.js +1 -2
  403. package/esm/util/color/cssColorsLevel4.d.ts +1 -0
  404. package/esm/util/color/cssColorsLevel4.js +1 -0
  405. package/esm/util/color/index.d.ts +5 -3
  406. package/esm/util/color/index.js +7 -4
  407. package/esm/util/colorBits.d.ts +3 -3
  408. package/esm/util/colorBits.js +19 -44
  409. package/esm/util/colorRamp.d.ts +49 -5
  410. package/esm/util/colorRamp.js +169 -18
  411. package/esm/util/colorScale.d.ts +156 -0
  412. package/esm/util/colorScale.js +243 -0
  413. package/esm/util/colorSchemes.d.ts +21 -0
  414. package/esm/util/colorSchemes.js +30 -0
  415. package/esm/util/copyToClipboard.js +8 -1
  416. package/esm/util/{createStopTokenRotation.d.ts → createAbortRotation.d.ts} +21 -23
  417. package/esm/util/{createStopTokenRotation.js → createAbortRotation.js} +21 -52
  418. package/esm/util/createSvgRasterCanvas.d.ts +10 -0
  419. package/esm/util/cssColorParse.d.ts +15 -0
  420. package/esm/util/cssColorParse.js +53 -0
  421. package/esm/util/diagonalizeRegions.d.ts +2 -3
  422. package/esm/util/diagonalizeRegions.js +8 -13
  423. package/esm/util/expandLooseSearchIndex.d.ts +19 -0
  424. package/esm/util/expandLooseSearchIndex.js +29 -0
  425. package/esm/util/featureTable.d.ts +224 -0
  426. package/esm/util/featureTable.js +366 -0
  427. package/esm/util/featureTransforms.d.ts +81 -0
  428. package/esm/util/featureTransforms.js +1231 -0
  429. package/esm/util/featureTypes.d.ts +24 -0
  430. package/esm/util/featureTypes.js +35 -0
  431. package/esm/util/fetchAndMaybeUnzip.js +16 -9
  432. package/esm/util/fetchContext.d.ts +7 -8
  433. package/esm/util/fetchContext.js +3 -3
  434. package/esm/util/fetchHub.d.ts +4 -2
  435. package/esm/util/fetchHub.js +2 -2
  436. package/esm/util/fetchPhases.d.ts +10 -10
  437. package/esm/util/fetchSeq.d.ts +2 -3
  438. package/esm/util/fetchSeq.js +2 -2
  439. package/esm/util/fieldReader.d.ts +17 -0
  440. package/esm/util/fieldReader.js +62 -0
  441. package/esm/util/formatBytes.js +1 -1
  442. package/esm/util/formatGuessers.d.ts +25 -14
  443. package/esm/util/formatGuessers.js +42 -27
  444. package/esm/util/formatRelativeTime.js +1 -1
  445. package/esm/util/freezeDeep.d.ts +8 -10
  446. package/esm/util/freezeDeep.js +8 -10
  447. package/esm/util/getLocationUri.d.ts +2 -1
  448. package/esm/util/getLocationUri.js +8 -2
  449. package/esm/util/groupKeys.d.ts +76 -0
  450. package/esm/util/groupKeys.js +156 -0
  451. package/esm/util/highlights.d.ts +10 -6
  452. package/esm/util/highlights.js +12 -25
  453. package/esm/util/hooks.d.ts +31 -2
  454. package/esm/util/hooks.js +72 -3
  455. package/esm/util/index.d.ts +11 -11
  456. package/esm/util/index.js +11 -10
  457. package/esm/util/indexCandidates.d.ts +1 -31
  458. package/esm/util/indexCandidates.js +5 -63
  459. package/esm/util/installFetch.d.ts +77 -37
  460. package/esm/util/installFetch.js +65 -38
  461. package/esm/util/installInitAutorun.d.ts +14 -13
  462. package/esm/util/installInitAutorun.js +17 -17
  463. package/esm/util/installPrerequisiteFetch.d.ts +115 -0
  464. package/esm/util/installPrerequisiteFetch.js +111 -0
  465. package/esm/util/intervals.js +9 -4
  466. package/esm/util/io/index.js +22 -15
  467. package/esm/util/isDataCurrent.d.ts +7 -5
  468. package/esm/util/isDataCurrent.js +9 -6
  469. package/esm/util/isTextEntryFocused.d.ts +7 -0
  470. package/esm/util/isTextEntryFocused.js +16 -0
  471. package/esm/util/jexl.js +24 -21
  472. package/esm/util/jexlFilterRows.d.ts +89 -0
  473. package/esm/util/jexlFilterRows.js +252 -0
  474. package/esm/util/jexlFilters.d.ts +32 -57
  475. package/esm/util/jexlFilters.js +31 -29
  476. package/esm/util/jexlStrings.d.ts +3 -4
  477. package/esm/util/jexlStrings.js +2 -3
  478. package/esm/util/layouts/GranularRectLayout.d.ts +8 -1
  479. package/esm/util/layouts/GranularRectLayout.js +25 -8
  480. package/esm/util/lazyAfterAttach.d.ts +13 -0
  481. package/esm/util/lazyAfterAttach.js +31 -0
  482. package/esm/util/lazyWithPreload.d.ts +19 -0
  483. package/esm/util/lazyWithPreload.js +27 -0
  484. package/esm/util/legendCandidates.d.ts +72 -0
  485. package/esm/util/legendCandidates.js +138 -0
  486. package/esm/util/locString.js +5 -2
  487. package/esm/util/localStorage.js +4 -4
  488. package/esm/util/markEncoding.d.ts +150 -0
  489. package/esm/util/markEncoding.js +885 -0
  490. package/esm/util/markEncodingTypes.d.ts +595 -0
  491. package/esm/util/markEncodingTypes.js +8 -0
  492. package/esm/util/mst-reflection.d.ts +2 -20
  493. package/esm/util/mst-reflection.js +3 -53
  494. package/esm/util/mstUtils.d.ts +31 -23
  495. package/esm/util/mstUtils.js +39 -24
  496. package/esm/util/numericUtils.d.ts +7 -0
  497. package/esm/util/numericUtils.js +16 -0
  498. package/esm/util/numericValue.d.ts +14 -0
  499. package/esm/util/numericValue.js +34 -0
  500. package/esm/util/openFeatureWidget.d.ts +5 -0
  501. package/esm/util/openFeatureWidget.js +2 -2
  502. package/esm/util/openViews.d.ts +17 -0
  503. package/esm/util/openViews.js +22 -0
  504. package/esm/util/parentWalk.d.ts +1 -1
  505. package/esm/util/parentWalk.js +1 -1
  506. package/esm/util/parseLineByLine.d.ts +4 -5
  507. package/esm/util/parseLineByLine.js +8 -14
  508. package/esm/util/pluginStore.d.ts +6 -8
  509. package/esm/util/pluginStore.js +17 -16
  510. package/esm/util/preloadComponent.d.ts +5 -0
  511. package/esm/util/preloadComponent.js +11 -0
  512. package/esm/util/progress.d.ts +22 -22
  513. package/esm/util/progress.js +27 -26
  514. package/esm/util/quantileExtent.d.ts +49 -0
  515. package/esm/util/quantileExtent.js +162 -0
  516. package/esm/util/range.d.ts +13 -9
  517. package/esm/util/range.js +17 -8
  518. package/esm/util/renameRegions.d.ts +26 -6
  519. package/esm/util/renameRegions.js +68 -54
  520. package/esm/util/renderToStaticMarkup.js +24 -14
  521. package/esm/util/rxjs.d.ts +23 -8
  522. package/esm/util/rxjs.js +61 -15
  523. package/esm/util/samplesTsv.d.ts +49 -0
  524. package/esm/util/samplesTsv.js +86 -0
  525. package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
  526. package/esm/util/scheduleDetachedDestroy.js +24 -0
  527. package/esm/util/scrollLatch.d.ts +1 -0
  528. package/esm/util/scrollLatch.js +8 -0
  529. package/esm/util/selectEncodedFeature.d.ts +16 -0
  530. package/esm/util/selectEncodedFeature.js +34 -0
  531. package/esm/util/sessionSharing.d.ts +7 -5
  532. package/esm/util/sessionSharing.js +23 -23
  533. package/esm/util/shapeNameList.d.ts +2 -0
  534. package/esm/util/shapeNameList.js +6 -0
  535. package/esm/util/shapeNames.d.ts +7 -0
  536. package/esm/util/shapeNames.js +11 -0
  537. package/esm/util/simpleFeature.d.ts +0 -1
  538. package/esm/util/springAnimate.js +1 -1
  539. package/esm/util/starFusion.d.ts +26 -0
  540. package/esm/util/starFusion.js +37 -0
  541. package/esm/util/stepTables.d.ts +96 -0
  542. package/esm/util/stepTables.js +277 -0
  543. package/esm/util/svAlt.d.ts +145 -0
  544. package/esm/util/svAlt.js +364 -0
  545. package/esm/util/svgColorProps.d.ts +11 -0
  546. package/esm/util/svgColorProps.js +28 -1
  547. package/esm/util/systemColorScheme.d.ts +12 -0
  548. package/esm/util/systemColorScheme.js +27 -0
  549. package/esm/util/tabix.d.ts +19 -10
  550. package/esm/util/tabix.js +19 -14
  551. package/esm/util/thresholdScale.d.ts +91 -0
  552. package/esm/util/thresholdScale.js +166 -0
  553. package/esm/util/timeGate.d.ts +4 -5
  554. package/esm/util/timeGate.js +4 -5
  555. package/esm/util/trackConfigDelta.d.ts +26 -26
  556. package/esm/util/trackConfigDelta.js +63 -47
  557. package/esm/util/tracks.d.ts +120 -66
  558. package/esm/util/tracks.js +501 -151
  559. package/esm/util/translateTranscript.d.ts +44 -0
  560. package/esm/util/translateTranscript.js +102 -0
  561. package/esm/util/types/data.d.ts +0 -2
  562. package/esm/util/types/index.d.ts +121 -22
  563. package/esm/util/types/index.js +9 -0
  564. package/esm/util/types/mst.d.ts +3 -0
  565. package/esm/util/types/mst.js +4 -0
  566. package/esm/util/types/renameIds.d.ts +1 -0
  567. package/esm/util/types/renameIds.js +29 -0
  568. package/esm/util/types/services.d.ts +1 -1
  569. package/esm/util/unknownSnapshotKeys.d.ts +53 -0
  570. package/esm/util/unknownSnapshotKeys.js +76 -0
  571. package/esm/util/useFeatureSequence.js +5 -5
  572. package/esm/util/useFetch.d.ts +3 -4
  573. package/esm/util/useFetch.js +19 -10
  574. package/esm/util/useFetchPlugins.d.ts +6 -2
  575. package/esm/util/useFetchPlugins.js +7 -3
  576. package/esm/util/usePanZoom.js +10 -3
  577. package/esm/util/usePanelVirtualScroll.d.ts +7 -35
  578. package/esm/util/usePanelVirtualScroll.js +9 -36
  579. package/esm/util/useRafCommit.js +1 -0
  580. package/esm/util/useRowVirtualScroll.d.ts +6 -29
  581. package/esm/util/useRowVirtualScroll.js +8 -49
  582. package/esm/util/useVirtualScrollWheel.d.ts +20 -4
  583. package/esm/util/useVirtualScrollWheel.js +40 -74
  584. package/esm/util/viewHighlights.d.ts +3 -0
  585. package/esm/util/viewHighlights.js +5 -0
  586. package/esm/util/viewStatus.d.ts +47 -15
  587. package/esm/util/viewStatus.js +34 -0
  588. package/esm/util/wheelZoom.d.ts +7 -1
  589. package/esm/util/wheelZoom.js +85 -19
  590. package/esm/util/whenViewSettled.d.ts +55 -8
  591. package/esm/util/whenViewSettled.js +56 -7
  592. package/esm/util/withFeatureDetails.js +4 -0
  593. package/esm/util/withLaunchInput.d.ts +174 -0
  594. package/esm/util/withLaunchInput.js +274 -0
  595. package/package.json +75 -24
  596. package/esm/BaseFeatureWidget/BaseFeatureDetail/Position.d.ts +0 -2
  597. package/esm/BaseFeatureWidget/BaseFeatureDetail/Position.js +0 -8
  598. package/esm/BaseFeatureWidget/BaseFeatureDetail/types.d.ts +0 -8
  599. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.d.ts +0 -80
  600. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.js +0 -583
  601. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +0 -141
  602. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.js +0 -1116
  603. package/esm/ReExports/BaseFeatureDetails.d.ts +0 -1
  604. package/esm/ReExports/BaseFeatureDetails.js +0 -10
  605. package/esm/ReExports/index.d.ts +0 -1
  606. package/esm/ReExports/index.js +0 -1
  607. package/esm/ReExports/publicUtil.d.ts +0 -1
  608. package/esm/ReExports/publicUtil.js +0 -28
  609. package/esm/configuration/promotableDefaults.d.ts +0 -199
  610. package/esm/configuration/promotableDefaults.js +0 -326
  611. package/esm/configuration/promotablePin.d.ts +0 -55
  612. package/esm/configuration/promotablePin.js +0 -1
  613. package/esm/configuration/promotableResolve.d.ts +0 -108
  614. package/esm/configuration/promotableResolve.js +0 -117
  615. package/esm/configuration/promotableSlots.d.ts +0 -12
  616. package/esm/configuration/promotableSlots.js +0 -45
  617. package/esm/configuration/slotShape.d.ts +0 -12
  618. package/esm/configuration/slotShape.js +0 -84
  619. package/esm/pluggableElementTypes/models/HighlightsMixin.d.ts +0 -51
  620. package/esm/pluggableElementTypes/models/HighlightsMixin.js +0 -78
  621. package/esm/ui/PinAdornment.d.ts +0 -5
  622. package/esm/ui/PinAdornment.js +0 -79
  623. package/esm/ui/SvgGradientLegend.d.ts +0 -26
  624. package/esm/ui/SvgGradientLegend.js +0 -26
  625. package/esm/ui/highlightChipReveal.d.ts +0 -32
  626. package/esm/ui/highlightChipReveal.js +0 -39
  627. package/esm/ui/promotableMenuItems.d.ts +0 -19
  628. package/esm/ui/promotableMenuItems.js +0 -89
  629. package/esm/ui/promotablePinCoverage.d.ts +0 -44
  630. package/esm/ui/promotablePinCoverage.js +0 -87
  631. package/esm/util/applyInitSettings.d.ts +0 -79
  632. package/esm/util/applyInitSettings.js +0 -91
  633. package/esm/util/openDisplays.d.ts +0 -23
  634. package/esm/util/openDisplays.js +0 -79
  635. package/esm/util/stopToken.d.ts +0 -211
  636. package/esm/util/stopToken.js +0 -438
  637. /package/esm/{BaseFeatureWidget/BaseFeatureDetail/types.js → data_adapters/BaseAdapter/zoomRange.js} +0 -0
package/esm/util/tabix.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { createStatusFanOut, downloadStatus } from './progress.js';
2
2
  import { calculateRedispatchRange } from './range.js';
3
- import { withStopTokenSignal } from './stopToken.js';
4
3
  /**
5
4
  * Read the feature type (column 3) from a raw GFF3/GTF line without a full
6
5
  * split. Used only to classify a line for redispatch.
@@ -18,15 +17,15 @@ function extractType(line) {
18
17
  * label, capturing each line's byte offset, indexed start/end, and feature type
19
18
  * into a {@link TabixLine}. Shared by the GFF3 and GTF tabix adapters.
20
19
  *
21
- * The stop token becomes the read's `AbortSignal`, so a cancelled fetch drops
20
+ * The signal becomes the read's `AbortSignal`, so a cancelled fetch drops
22
21
  * its block reads at the socket instead of downloading them and discarding the
23
22
  * lines. @gmod/tabix aborts a block shared between callers only once every
24
23
  * joined caller has aborted (`AggregateAbortController`), so this can't cancel a
25
24
  * chunk another region still needs.
26
25
  */
27
- export function readTabixLines(gff, refName, start, end, statusCallback, stopToken) {
26
+ export function readTabixLines(gff, refName, start, end, statusCallback, signal) {
28
27
  const lines = [];
29
- return withStopTokenSignal(stopToken, signal => downloadStatus('Downloading features', statusCallback, onProgress => gff.getLines(refName, start, end, {
28
+ return downloadStatus('Downloading features', statusCallback, onProgress => gff.getLines(refName, start, end, {
30
29
  lineCallback: (line, offset, s, e) => {
31
30
  lines.push({
32
31
  line,
@@ -38,15 +37,21 @@ export function readTabixLines(gff, refName, start, end, statusCallback, stopTok
38
37
  },
39
38
  onProgress,
40
39
  signal,
41
- }))).then(() => lines);
40
+ })).then(() => lines);
42
41
  }
43
42
  /**
44
43
  * Read a region's tabix lines, then — if any feature found there extends past
45
44
  * the query — read the overhang on either side, so a parent line's children (a
46
45
  * gene's exons, a transcript's CDS) outside the original window are pulled in
47
- * and the parent/child tree resolves fully. Types in `dontRedispatchSet` are
48
- * excluded from the bounds, so one chromosome-spanning record can't force a
49
- * whole-chromosome refetch.
46
+ * and the parent/child tree resolves fully. `expands` decides which lines widen
47
+ * the bound, so one chromosome-spanning record can't force a whole-chromosome
48
+ * refetch; {@link calculateRedispatchRange} says why that is a predicate.
49
+ *
50
+ * **There is one control, and skipping the expansion is a value of it**: an
51
+ * `expands` that admits nothing reads the query and stops. A caller that wants
52
+ * that says so to its adapter, which is the layer that knows whether its format
53
+ * can honour it — see `Gff3TabixAdapter`, and `GtfTabixAdapter` for a format
54
+ * that cannot.
50
55
  *
51
56
  * **The flanks, not the union.** Re-reading `[minStart, maxEnd]` returns
52
57
  * everything the first read already had — a second full read of the query range
@@ -74,13 +79,13 @@ export function readTabixLines(gff, refName, start, end, statusCallback, stopTok
74
79
  export async function readTabixLinesRedispatched(file,
75
80
  // the region's locus only — kept structural, like TabixLineSource above, so
76
81
  // this module stays free of the `types` barrel and its MST models
77
- query, dontRedispatchSet, opts = {}) {
78
- const { statusCallback, stopToken } = opts;
82
+ query, expands, opts = {}) {
83
+ const { statusCallback, signal } = opts;
79
84
  // `cb` is not optional: each read decides where it reports, and the flanks
80
85
  // report somewhere the first read does not
81
- const read = (start, end, cb) => readTabixLines(file, query.refName, start, end, cb, stopToken);
86
+ const read = (start, end, cb) => readTabixLines(file, query.refName, start, end, cb, signal);
82
87
  const lines = await read(query.start, query.end, statusCallback);
83
- const redispatch = calculateRedispatchRange(lines, dontRedispatchSet, query.start, query.end);
88
+ const redispatch = calculateRedispatchRange(lines, expands, query.start, query.end);
84
89
  if (redispatch) {
85
90
  const slot = createStatusFanOut(statusCallback);
86
91
  const flanks = await Promise.all([
@@ -138,6 +143,6 @@ function mergeTabixLines(...groups) {
138
143
  * commented block and then the counted rows used to fetch and decompress the
139
144
  * same bytes twice, which every bare-header file did on every call.
140
145
  */
141
- export function readTabixHeaderLines(file) {
142
- return file.getHeaderLines();
146
+ export function readTabixHeaderLines(file, opts) {
147
+ return file.getHeaderLines(opts);
143
148
  }
@@ -0,0 +1,91 @@
1
+ import type { CategoricalScale } from '../ui/colorScale.ts';
2
+ import type { CategoricalField } from './categoricalField.ts';
3
+ /**
4
+ * #api
5
+ * A domain written as strings — the shared `domain` slot is a `stringArray` —
6
+ * read back as the numbers it names. A member that is not a number reads NaN,
7
+ * which every comparison against it declines.
8
+ */
9
+ export declare function numericDomain(domain: readonly (string | number)[]): number[];
10
+ /**
11
+ * #api
12
+ * A threshold scale's cut points as {@link thresholdIndex} walks them: the
13
+ * numbers the domain names, ascending. Cuts written high to low, as p-value
14
+ * thresholds often are, left the middle interval unreachable, the walk stopping
15
+ * at the first cut a value is under.
16
+ */
17
+ export declare function thresholdCuts(domain: readonly (string | number)[]): number[];
18
+ /**
19
+ * #api
20
+ * The bin a value falls in: how many of the ascending cut points it is at or
21
+ * past, so a palette with one more entry than the domain paints it as
22
+ * `palette[thresholdIndex(value, domain)]`. A value that is not a number is
23
+ * in no bin and answers -1; an infinite one takes the end bin on its side, as
24
+ * d3's threshold scale places it, so a `-log10` of a zero p-value lands in
25
+ * the top bin.
26
+ */
27
+ export declare function thresholdIndex(value: unknown, domain: readonly number[]): number;
28
+ /**
29
+ * #api
30
+ * The colour of each interval, in order: the declared palette, and the
31
+ * default categorical palette where it runs out.
32
+ */
33
+ export declare function thresholdPalette(bins: number, palette?: readonly string[]): string[];
34
+ /**
35
+ * #api
36
+ * What a threshold scale's bins are called in a key, one label per palette
37
+ * entry: `< a` below the first cut, `a – b` between two, `≥ b` past the last.
38
+ */
39
+ export declare function thresholdLabels(domain: readonly number[]): string[];
40
+ /**
41
+ * #api
42
+ * The key a value holding text that is no number files under on a threshold
43
+ * scale, painted the misconfiguration grey rather than passing for a missing
44
+ * value.
45
+ */
46
+ export declare const NOT_A_NUMBER_LABEL = "(not a number)";
47
+ /**
48
+ * #api
49
+ * A threshold key's rows: every interval, painted or not, since the bins are
50
+ * the whole domain, then the not-a-number and no-value rows where a feature
51
+ * took one, in the order `thresholdField` sorts them.
52
+ */
53
+ export declare function thresholdKeyEntries(cuts: readonly number[], range: readonly string[] | undefined, met: {
54
+ missing?: boolean;
55
+ notNumber?: boolean;
56
+ }, names?: readonly string[]): {
57
+ value: string;
58
+ label: string;
59
+ color: string;
60
+ missing?: true;
61
+ }[];
62
+ /**
63
+ * #api
64
+ * The rows a ramp's key lists beside its bar once a feature painted one: the
65
+ * not-a-number and no-value rows a threshold's key ends with. Empty while
66
+ * neither painted.
67
+ */
68
+ export declare function rampGapScales(id: string, met: {
69
+ missing?: boolean;
70
+ notNumber?: boolean;
71
+ }): CategoricalScale[];
72
+ /**
73
+ * #api
74
+ * Whether a field holds no value at all, as against text that fails to parse:
75
+ * absent, empty, or a VCF's `AF=.`, which arrives as `[undefined]`.
76
+ */
77
+ export declare function isMissing(value: unknown): boolean;
78
+ /**
79
+ * #api
80
+ * A threshold scale read the way every categorical channel reads its field: a
81
+ * value files under the label of the bin it falls in, a feature with no value
82
+ * under `''`, and text that is no number under {@link NOT_A_NUMBER_LABEL}.
83
+ * The bins are the whole domain, so a key lists each one. `labels` names the
84
+ * bins in a key, one each from the lowest, where a config spells them for a
85
+ * reader; a bin's key stays its interval.
86
+ */
87
+ export declare function thresholdField(field: string, { domain, range, labels: names, }?: {
88
+ domain?: readonly string[];
89
+ range?: readonly string[];
90
+ labels?: readonly string[];
91
+ }): CategoricalField;
@@ -0,0 +1,166 @@
1
+ import { categoricalPalette } from '../ui/colors.js';
2
+ import { NO_VALUE_LABEL, keyNames } from './categoricalField.js';
3
+ import { MISCONFIGURED_COLOR, NO_CATEGORY_COLOR } from './color/index.js';
4
+ import { groupKeyComparator, valueText } from './groupKeys.js';
5
+ import { numericValue } from './numericValue.js';
6
+ /**
7
+ * #api
8
+ * A domain written as strings — the shared `domain` slot is a `stringArray` —
9
+ * read back as the numbers it names. A member that is not a number reads NaN,
10
+ * which every comparison against it declines.
11
+ */
12
+ export function numericDomain(domain) {
13
+ return domain.map(Number);
14
+ }
15
+ /**
16
+ * #api
17
+ * A threshold scale's cut points as {@link thresholdIndex} walks them: the
18
+ * numbers the domain names, ascending. Cuts written high to low, as p-value
19
+ * thresholds often are, left the middle interval unreachable, the walk stopping
20
+ * at the first cut a value is under.
21
+ */
22
+ export function thresholdCuts(domain) {
23
+ return numericDomain(domain)
24
+ .filter(cut => Number.isFinite(cut))
25
+ .sort((a, b) => a - b);
26
+ }
27
+ /**
28
+ * #api
29
+ * The bin a value falls in: how many of the ascending cut points it is at or
30
+ * past, so a palette with one more entry than the domain paints it as
31
+ * `palette[thresholdIndex(value, domain)]`. A value that is not a number is
32
+ * in no bin and answers -1; an infinite one takes the end bin on its side, as
33
+ * d3's threshold scale places it, so a `-log10` of a zero p-value lands in
34
+ * the top bin.
35
+ */
36
+ export function thresholdIndex(value, domain) {
37
+ const v = numericValue(value);
38
+ if (Number.isNaN(v)) {
39
+ return -1;
40
+ }
41
+ let i = 0;
42
+ while (i < domain.length && v >= domain[i]) {
43
+ i++;
44
+ }
45
+ return i;
46
+ }
47
+ /**
48
+ * #api
49
+ * The colour of each interval, in order: the declared palette, and the
50
+ * default categorical palette where it runs out.
51
+ */
52
+ export function thresholdPalette(bins, palette = []) {
53
+ return Array.from({ length: bins }, (_, i) => palette[i] ?? categoricalPalette[i % categoricalPalette.length]);
54
+ }
55
+ /**
56
+ * #api
57
+ * What a threshold scale's bins are called in a key, one label per palette
58
+ * entry: `< a` below the first cut, `a – b` between two, `≥ b` past the last.
59
+ */
60
+ export function thresholdLabels(domain) {
61
+ if (domain.length === 0) {
62
+ return ['any value'];
63
+ }
64
+ return [
65
+ `< ${domain[0]}`,
66
+ ...domain.slice(1).map((cut, i) => `${domain[i]} – ${cut}`),
67
+ `≥ ${domain.at(-1)}`,
68
+ ];
69
+ }
70
+ /**
71
+ * #api
72
+ * The key a value holding text that is no number files under on a threshold
73
+ * scale, painted the misconfiguration grey rather than passing for a missing
74
+ * value.
75
+ */
76
+ export const NOT_A_NUMBER_LABEL = '(not a number)';
77
+ /**
78
+ * #api
79
+ * A threshold key's rows: every interval, painted or not, since the bins are
80
+ * the whole domain, then the not-a-number and no-value rows where a feature
81
+ * took one, in the order `thresholdField` sorts them.
82
+ */
83
+ export function thresholdKeyEntries(cuts, range, met, names = []) {
84
+ const labels = thresholdLabels(cuts);
85
+ const colors = thresholdPalette(labels.length, range);
86
+ return [
87
+ ...labels.map((label, i) => ({
88
+ value: label,
89
+ label: names[i] ?? label,
90
+ color: colors[i],
91
+ })),
92
+ ...(met.notNumber
93
+ ? [
94
+ {
95
+ value: NOT_A_NUMBER_LABEL,
96
+ label: NOT_A_NUMBER_LABEL,
97
+ color: MISCONFIGURED_COLOR,
98
+ },
99
+ ]
100
+ : []),
101
+ ...(met.missing
102
+ ? [
103
+ {
104
+ value: '',
105
+ label: NO_VALUE_LABEL,
106
+ color: NO_CATEGORY_COLOR,
107
+ missing: true,
108
+ },
109
+ ]
110
+ : []),
111
+ ];
112
+ }
113
+ /**
114
+ * #api
115
+ * The rows a ramp's key lists beside its bar once a feature painted one: the
116
+ * not-a-number and no-value rows a threshold's key ends with. Empty while
117
+ * neither painted.
118
+ */
119
+ export function rampGapScales(id, met) {
120
+ const entries = thresholdKeyEntries([], undefined, met).slice(1);
121
+ return entries.length > 0 ? [{ kind: 'categorical', id, entries }] : [];
122
+ }
123
+ /**
124
+ * #api
125
+ * Whether a field holds no value at all, as against text that fails to parse:
126
+ * absent, empty, or a VCF's `AF=.`, which arrives as `[undefined]`.
127
+ */
128
+ export function isMissing(value) {
129
+ return Array.isArray(value)
130
+ ? value.every(v => v === undefined || v === null)
131
+ : valueText(value) === '';
132
+ }
133
+ /**
134
+ * #api
135
+ * A threshold scale read the way every categorical channel reads its field: a
136
+ * value files under the label of the bin it falls in, a feature with no value
137
+ * under `''`, and text that is no number under {@link NOT_A_NUMBER_LABEL}.
138
+ * The bins are the whole domain, so a key lists each one. `labels` names the
139
+ * bins in a key, one each from the lowest, where a config spells them for a
140
+ * reader; a bin's key stays its interval.
141
+ */
142
+ export function thresholdField(field, { domain = [], range = [], labels: names = [], } = {}) {
143
+ const cuts = thresholdCuts(domain);
144
+ const labels = thresholdLabels(cuts);
145
+ const named = keyNames(labels, names);
146
+ const palette = thresholdPalette(labels.length, range);
147
+ const colorOf = new Map(labels.map((label, i) => [label, palette[i]]));
148
+ return {
149
+ field,
150
+ domain: labels,
151
+ closed: true,
152
+ key: value => {
153
+ if (isMissing(value)) {
154
+ return '';
155
+ }
156
+ const bin = thresholdIndex(value, cuts);
157
+ return bin < 0 ? NOT_A_NUMBER_LABEL : labels[bin];
158
+ },
159
+ compare: groupKeyComparator([...labels, NOT_A_NUMBER_LABEL]),
160
+ label: key => (key === '' ? NO_VALUE_LABEL : (named.get(key) ?? key)),
161
+ sectionLabel: key => `${field}: ${key === '' ? 'none' : key}`,
162
+ color: key => key === ''
163
+ ? NO_CATEGORY_COLOR
164
+ : (colorOf.get(key) ?? MISCONFIGURED_COLOR),
165
+ };
166
+ }
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * `Date.now()` costs ~40ns, invisible until the loop is a 666k-read pileup —
7
7
  * there it measured ~28ms per gated callsite, and the alignments worker has two
8
- * of them (the progress emit in `createProgressReporter` and the stop-token
9
- * check in `checkStopTokenThrottled`). Both previously read the clock per call, on the
8
+ * of them (the progress emit in `createProgressReporter` and the yield in
9
+ * `createAbortBreakpoint`). Both previously read the clock per call, on the
10
10
  * documented reasoning that it was negligible next to the per-item work; at
11
11
  * this item count it measurably isn't.
12
12
  *
@@ -18,9 +18,8 @@
18
18
  * measure a low rate and hold a stride of 1, gating on time alone as before,
19
19
  * while a millions-of-calls loop thins itself out.
20
20
  *
21
- * `intervalMs` is per call rather than fixed at construction: it was added for
22
- * `checkStopTokenThrottled`, whose (since-deleted) sync-XHR probe backed off
23
- * linearly over a long loop. Both current callers pass a constant.
21
+ * `intervalMs` is per call rather than fixed at construction; both current
22
+ * callers pass a constant.
24
23
  */
25
24
  export declare function createTimeGate(): (intervalMs: number) => boolean;
26
25
  export type TimeGate = ReturnType<typeof createTimeGate>;
@@ -24,8 +24,8 @@ const STRIDE_GROWTH_LIMIT = 8;
24
24
  *
25
25
  * `Date.now()` costs ~40ns, invisible until the loop is a 666k-read pileup —
26
26
  * there it measured ~28ms per gated callsite, and the alignments worker has two
27
- * of them (the progress emit in `createProgressReporter` and the stop-token
28
- * check in `checkStopTokenThrottled`). Both previously read the clock per call, on the
27
+ * of them (the progress emit in `createProgressReporter` and the yield in
28
+ * `createAbortBreakpoint`). Both previously read the clock per call, on the
29
29
  * documented reasoning that it was negligible next to the per-item work; at
30
30
  * this item count it measurably isn't.
31
31
  *
@@ -37,9 +37,8 @@ const STRIDE_GROWTH_LIMIT = 8;
37
37
  * measure a low rate and hold a stride of 1, gating on time alone as before,
38
38
  * while a millions-of-calls loop thins itself out.
39
39
  *
40
- * `intervalMs` is per call rather than fixed at construction: it was added for
41
- * `checkStopTokenThrottled`, whose (since-deleted) sync-XHR probe backed off
42
- * linearly over a long loop. Both current callers pass a constant.
40
+ * `intervalMs` is per call rather than fixed at construction; both current
41
+ * callers pass a constant.
43
42
  */
44
43
  export function createTimeGate() {
45
44
  let stride = 1;
@@ -12,24 +12,22 @@
12
12
  * - `diffTrackConfig(base, edited)` — the minimal delta
13
13
  * - `mergeTrackConfig(base, delta)` — reconstruct the effective config
14
14
  *
15
- * Deliberate limitation (no tombstones): a delta records adds/changes only, not
16
- * deletions. If a user *resets* a slot the admin had customized (base has it,
17
- * edited omits it), the delta can't express "drop below the admin value", so the
18
- * field keeps following the base across a reload. This keeps the merge trivial
19
- * and the shared JSON free of deletion sentinels, and following the admin value
20
- * is a defensible outcome.
21
- *
22
- * What it is NOT free to conflate is a removal with a reset. Both diff to an
23
- * empty delta, and `SessionTracks.updateTrackConfiguration` used to read that as
24
- * "the edit netted back to the base" and revert the track's working copy — which
25
- * undid a removal on screen 400ms after it landed. Promotable slots made that
26
- * reachable rather than rare: the promoted-default snackbar's "Override N
27
- * customized tracks" exists to unset a slot, and an admin config is free to set
28
- * one. That branch now keeps the working copy; see the comment there.
15
+ * A delta is a JSON Merge Patch (RFC 7396) over the base, so a `null` member is
16
+ * a reset: the merge removes the member and the schema's default applies. That
17
+ * is ADR-146's spelling of a reset, and the diff writes one wherever the base
18
+ * sets a member the edited config lacks — a slot put back to its default, or a
19
+ * list emptied, since `stripDefault` drops both from a snapshot. Where the edit
20
+ * left a whole namespace at its default, the nulls land on the members the base
21
+ * set inside it rather than on the namespace, so a member the admin adds there
22
+ * later still flows through. The inference
23
+ * is exact only because both sides are post-`stripDefault` snapshots: a member
24
+ * the admin wrote at its default is absent from both, where a `null` for it
25
+ * would block a later admin value. As in RFC 7396, a delta cannot set a member
26
+ * to a literal `null`; null and absent are one state.
29
27
  *
30
28
  * `displays` is merged by `displayId` so an edit to one display doesn't pin the
31
- * others. Nested config objects (e.g. `adapter`) recurse. Any other array (value
32
- * arrays like `jexlFilters`, `assemblyNames`) is replaced wholesale when changed.
29
+ * others, and by `type` where the base has no display of that id. Nested config objects (e.g. `adapter`) recurse. Any other array (value
30
+ * arrays like `filter`, `assemblyNames`) is replaced wholesale when changed.
33
31
  *
34
32
  * Subtlety worth not "optimizing": when the base has NO `displays` array but the
35
33
  * edited snapshot does (common — a track config that omits displays gets a stub
@@ -44,24 +42,26 @@ type Json = string | number | boolean | null | undefined | Json[] | {
44
42
  [key: string]: Json;
45
43
  };
46
44
  /**
47
- * Minimal delta of `edited` against `base`. Both are plain config snapshots
48
- * (post-stripDefault). Records adds/changes only; see the module note on the
49
- * no-tombstone limitation. Always retains `trackId` so the delta is
50
- * self-identifying.
45
+ * Minimal delta of `edited` against `base`, both post-stripDefault snapshots. A
46
+ * member `base` sets and `edited` lacks is a `null` (see the module note).
47
+ * Always retains `trackId` so the delta is self-identifying.
51
48
  */
52
49
  export declare function diffTrackConfig(base: Record<string, unknown>, edited: Record<string, unknown>): Record<string, unknown>;
53
50
  /**
54
51
  * Reconstruct the effective config by layering `delta` over the live `base`.
55
- * Inverse of `diffTrackConfig` on the add/change path (see module note).
52
+ * A `null` removes the member it names, and one naming something the base no
53
+ * longer has is dropped, so no `null` member reaches the config a track
54
+ * hydrates from.
56
55
  */
57
56
  export declare function mergeTrackConfig(base: Record<string, unknown>, delta: Record<string, unknown>): Record<string, unknown>;
58
- /** A single overridden slot: the dotted `path`, its base `from` and edited `to`. */
57
+ /**
58
+ * A single overridden slot: the dotted `path`, its base `from` and edited `to`,
59
+ * which is `undefined` for a reset.
60
+ */
59
61
  export interface TrackConfigChange {
60
62
  /**
61
- * Where the setting lives, and — for a row a UI can revert — its **address**:
62
- * `resetPreferenceChange` parses a promoted display-type default's path back
63
- * into the type and slot it clears. So a producer that wants a friendlier
64
- * heading sets `label` and leaves this alone.
63
+ * Where the setting lives. A producer that wants a friendlier heading sets
64
+ * `label` and leaves this alone.
65
65
  */
66
66
  path: string[];
67
67
  from: Json;
@@ -12,24 +12,22 @@
12
12
  * - `diffTrackConfig(base, edited)` — the minimal delta
13
13
  * - `mergeTrackConfig(base, delta)` — reconstruct the effective config
14
14
  *
15
- * Deliberate limitation (no tombstones): a delta records adds/changes only, not
16
- * deletions. If a user *resets* a slot the admin had customized (base has it,
17
- * edited omits it), the delta can't express "drop below the admin value", so the
18
- * field keeps following the base across a reload. This keeps the merge trivial
19
- * and the shared JSON free of deletion sentinels, and following the admin value
20
- * is a defensible outcome.
21
- *
22
- * What it is NOT free to conflate is a removal with a reset. Both diff to an
23
- * empty delta, and `SessionTracks.updateTrackConfiguration` used to read that as
24
- * "the edit netted back to the base" and revert the track's working copy — which
25
- * undid a removal on screen 400ms after it landed. Promotable slots made that
26
- * reachable rather than rare: the promoted-default snackbar's "Override N
27
- * customized tracks" exists to unset a slot, and an admin config is free to set
28
- * one. That branch now keeps the working copy; see the comment there.
15
+ * A delta is a JSON Merge Patch (RFC 7396) over the base, so a `null` member is
16
+ * a reset: the merge removes the member and the schema's default applies. That
17
+ * is ADR-146's spelling of a reset, and the diff writes one wherever the base
18
+ * sets a member the edited config lacks — a slot put back to its default, or a
19
+ * list emptied, since `stripDefault` drops both from a snapshot. Where the edit
20
+ * left a whole namespace at its default, the nulls land on the members the base
21
+ * set inside it rather than on the namespace, so a member the admin adds there
22
+ * later still flows through. The inference
23
+ * is exact only because both sides are post-`stripDefault` snapshots: a member
24
+ * the admin wrote at its default is absent from both, where a `null` for it
25
+ * would block a later admin value. As in RFC 7396, a delta cannot set a member
26
+ * to a literal `null`; null and absent are one state.
29
27
  *
30
28
  * `displays` is merged by `displayId` so an edit to one display doesn't pin the
31
- * others. Nested config objects (e.g. `adapter`) recurse. Any other array (value
32
- * arrays like `jexlFilters`, `assemblyNames`) is replaced wholesale when changed.
29
+ * others, and by `type` where the base has no display of that id. Nested config objects (e.g. `adapter`) recurse. Any other array (value
30
+ * arrays like `filter`, `assemblyNames`) is replaced wholesale when changed.
33
31
  *
34
32
  * Subtlety worth not "optimizing": when the base has NO `displays` array but the
35
33
  * edited snapshot does (common — a track config that omits displays gets a stub
@@ -51,10 +49,14 @@ function isDisplayArray(v) {
51
49
  v.length > 0 &&
52
50
  v.every(e => isPlainObject(e) && typeof e.displayId === 'string'));
53
51
  }
54
- // Sentinel returned by diffValue when a value is unchanged, so callers can tell
55
- // "no delta" apart from a legitimate `undefined` slot value.
56
52
  const UNCHANGED = Symbol('unchanged');
57
53
  function diffValue(base, edited) {
54
+ if (edited == null) {
55
+ if (base == null) {
56
+ return UNCHANGED;
57
+ }
58
+ return isPlainObject(base) ? diffValue(base, {}) : null;
59
+ }
58
60
  if (deepEqual(base, edited)) {
59
61
  return UNCHANGED;
60
62
  }
@@ -67,13 +69,10 @@ function diffValue(base, edited) {
67
69
  if (baseDisplay) {
68
70
  const d = diffValue(baseDisplay, editedDisplay);
69
71
  if (d !== UNCHANGED) {
70
- // always re-key the delta entry by displayId so merge can realign it
71
72
  out.push({ ...d, displayId: id });
72
73
  }
73
74
  }
74
75
  else {
75
- // a display present only in the edited config (e.g. an added display):
76
- // carry it whole
77
76
  out.push(editedDisplay);
78
77
  }
79
78
  }
@@ -81,25 +80,20 @@ function diffValue(base, edited) {
81
80
  }
82
81
  if (isPlainObject(edited) && isPlainObject(base)) {
83
82
  const out = {};
84
- for (const [k, v] of Object.entries(edited)) {
85
- const d = diffValue(base[k], v);
83
+ for (const k of new Set([...Object.keys(base), ...Object.keys(edited)])) {
84
+ const d = diffValue(base[k], edited[k]);
86
85
  if (d !== UNCHANGED) {
87
86
  out[k] = d;
88
87
  }
89
88
  }
90
- // an object whose only difference from base is dropped keys (a reset the
91
- // delta can't express, see module note) yields no adds/changes: treat it as
92
- // unchanged rather than emitting a content-free entry
93
89
  return Object.keys(out).length > 0 ? out : UNCHANGED;
94
90
  }
95
- // scalar, or an object/array replacing a scalar (or a value array): replace
96
91
  return edited;
97
92
  }
98
93
  /**
99
- * Minimal delta of `edited` against `base`. Both are plain config snapshots
100
- * (post-stripDefault). Records adds/changes only; see the module note on the
101
- * no-tombstone limitation. Always retains `trackId` so the delta is
102
- * self-identifying.
94
+ * Minimal delta of `edited` against `base`, both post-stripDefault snapshots. A
95
+ * member `base` sets and `edited` lacks is a `null` (see the module note).
96
+ * Always retains `trackId` so the delta is self-identifying.
103
97
  */
104
98
  export function diffTrackConfig(base, edited) {
105
99
  const d = diffValue(base, edited);
@@ -107,35 +101,57 @@ export function diffTrackConfig(base, edited) {
107
101
  const trackId = (edited.trackId ?? base.trackId);
108
102
  return { ...delta, trackId };
109
103
  }
104
+ // A delta display naming an id the base lacks lands on the base display of its
105
+ // type, keeping the base's id: a track holds one display per type, and a
106
+ // migrated session addresses the display by the id its old type minted.
110
107
  function mergeValue(base, delta) {
111
- if (isDisplayArray(delta) && isDisplayArray(base)) {
112
- const deltaById = new Map(delta.map(d => [d.displayId, d]));
113
- const merged = base.map(baseDisplay => {
114
- const d = deltaById.get(baseDisplay.displayId);
115
- return d ? mergeValue(baseDisplay, d) : baseDisplay;
116
- });
117
- // displays present only in the delta (added by the user) append after base
118
- const baseIds = new Set(base.map(d => d.displayId));
108
+ if (isDisplayArray(delta)) {
109
+ const baseDisplays = isDisplayArray(base) ? base : [];
110
+ const baseIds = new Set(baseDisplays.map(d => d.displayId));
111
+ const deltaByBaseId = new Map();
112
+ const added = [];
119
113
  for (const d of delta) {
120
- if (!baseIds.has(d.displayId)) {
121
- merged.push(d);
114
+ const byType = baseIds.has(d.displayId)
115
+ ? undefined
116
+ : baseDisplays.find(b => d.type !== undefined && b.type === d.type);
117
+ const id = (byType?.displayId ?? d.displayId);
118
+ if (baseIds.has(id)) {
119
+ const onId = { ...d, displayId: id };
120
+ const earlier = deltaByBaseId.get(id);
121
+ deltaByBaseId.set(id, earlier ? mergeValue(earlier, onId) : onId);
122
+ }
123
+ else {
124
+ added.push(d);
122
125
  }
123
126
  }
127
+ const merged = baseDisplays.map(baseDisplay => {
128
+ const d = deltaByBaseId.get(baseDisplay.displayId);
129
+ return d ? mergeValue(baseDisplay, d) : baseDisplay;
130
+ });
131
+ for (const d of added) {
132
+ merged.push(mergeValue(undefined, d));
133
+ }
124
134
  return merged;
125
135
  }
126
- if (isPlainObject(delta) && isPlainObject(base)) {
127
- const out = { ...base };
136
+ if (isPlainObject(delta)) {
137
+ const out = isPlainObject(base) ? { ...base } : {};
128
138
  for (const [k, v] of Object.entries(delta)) {
129
- out[k] = mergeValue(base[k], v);
139
+ if (v === null) {
140
+ delete out[k];
141
+ }
142
+ else {
143
+ out[k] = mergeValue(out[k], v);
144
+ }
130
145
  }
131
146
  return out;
132
147
  }
133
- // scalar / value array / type mismatch: delta wins
134
148
  return delta;
135
149
  }
136
150
  /**
137
151
  * Reconstruct the effective config by layering `delta` over the live `base`.
138
- * Inverse of `diffTrackConfig` on the add/change path (see module note).
152
+ * A `null` removes the member it names, and one naming something the base no
153
+ * longer has is dropped, so no `null` member reaches the config a track
154
+ * hydrates from.
139
155
  */
140
156
  export function mergeTrackConfig(base, delta) {
141
157
  return mergeValue(base, delta);
@@ -174,7 +190,7 @@ function walkDelta(base, delta, path, out, identityKeys = IDENTITY_KEYS) {
174
190
  }
175
191
  }
176
192
  else {
177
- out.push({ path, from: base, to: delta });
193
+ out.push({ path, from: base, to: delta ?? undefined });
178
194
  }
179
195
  }
180
196
  /**