react-msaview 6.5.0 → 8.0.0

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 (414) hide show
  1. package/README.md +13 -11
  2. package/bundle/index.js +122 -112
  3. package/bundle/index.js.map +4 -4
  4. package/dist/colorSchemes.js +1 -2
  5. package/dist/colorSchemes.js.map +1 -1
  6. package/dist/columnStats.d.ts +28 -0
  7. package/dist/columnStats.js +34 -0
  8. package/dist/columnStats.js.map +1 -0
  9. package/dist/components/DragHandle.d.ts +3 -2
  10. package/dist/components/DragHandle.js +11 -5
  11. package/dist/components/DragHandle.js.map +1 -1
  12. package/dist/components/Loading.js +2 -2
  13. package/dist/components/Loading.js.map +1 -1
  14. package/dist/components/MSAView.js +17 -6
  15. package/dist/components/MSAView.js.map +1 -1
  16. package/dist/components/MSAViewer.d.ts +69 -4
  17. package/dist/components/MSAViewer.js +201 -8
  18. package/dist/components/MSAViewer.js.map +1 -1
  19. package/dist/components/PortalTooltip.d.ts +11 -0
  20. package/dist/components/PortalTooltip.js +29 -0
  21. package/dist/components/PortalTooltip.js.map +1 -0
  22. package/dist/components/ResizeHandles.d.ts +3 -3
  23. package/dist/components/ResizeHandles.js +13 -24
  24. package/dist/components/ResizeHandles.js.map +1 -1
  25. package/dist/components/SequenceTextArea.js +3 -3
  26. package/dist/components/SequenceTextArea.js.map +1 -1
  27. package/dist/components/Track.js +41 -22
  28. package/dist/components/Track.js.map +1 -1
  29. package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
  30. package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
  31. package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
  32. package/dist/components/dialogs/ExportSVGDialog.js +5 -3
  33. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
  34. package/dist/components/dialogs/FeatureDialog.js +13 -9
  35. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  36. package/dist/components/dialogs/TrackInfoDialog.js +1 -1
  37. package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
  38. package/dist/components/header/GappynessSlider.js +6 -11
  39. package/dist/components/header/GappynessSlider.js.map +1 -1
  40. package/dist/components/header/Header.js +7 -0
  41. package/dist/components/header/Header.js.map +1 -1
  42. package/dist/components/header/HeaderStatusArea.js +0 -2
  43. package/dist/components/header/HeaderStatusArea.js.map +1 -1
  44. package/dist/components/header/LoadWarnings.d.ts +6 -0
  45. package/dist/components/header/LoadWarnings.js +35 -0
  46. package/dist/components/header/LoadWarnings.js.map +1 -0
  47. package/dist/components/header/MultiAlignmentSelector.js +0 -0
  48. package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
  49. package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
  50. package/dist/components/header/ScrollZoomIcons.js +35 -0
  51. package/dist/components/header/ScrollZoomIcons.js.map +1 -0
  52. package/dist/components/header/TreeSettingsMenu.js +7 -1
  53. package/dist/components/header/TreeSettingsMenu.js.map +1 -1
  54. package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
  55. package/dist/components/header/UnshareableDataWarning.js +40 -0
  56. package/dist/components/header/UnshareableDataWarning.js.map +1 -0
  57. package/dist/components/header/ZoomControls.js +49 -6
  58. package/dist/components/header/ZoomControls.js.map +1 -1
  59. package/dist/components/header/getAnnotationsMenu.js +11 -14
  60. package/dist/components/header/getAnnotationsMenu.js.map +1 -1
  61. package/dist/components/header/settingsMenuItems.js +10 -7
  62. package/dist/components/header/settingsMenuItems.js.map +1 -1
  63. package/dist/components/import/ImportForm.js +1 -1
  64. package/dist/components/import/ImportForm.js.map +1 -1
  65. package/dist/components/import/ImportFormExamples.js +2 -6
  66. package/dist/components/import/ImportFormExamples.js.map +1 -1
  67. package/dist/components/import/util.js +2 -0
  68. package/dist/components/import/util.js.map +1 -1
  69. package/dist/components/minimap/Minimap.js +1 -2
  70. package/dist/components/minimap/Minimap.js.map +1 -1
  71. package/dist/components/msa/AnnotationLegend.js +27 -19
  72. package/dist/components/msa/AnnotationLegend.js.map +1 -1
  73. package/dist/components/msa/MSACanvas.js +1 -1
  74. package/dist/components/msa/MSACanvas.js.map +1 -1
  75. package/dist/components/msa/MSACanvasBlock.js +17 -20
  76. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  77. package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
  78. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  79. package/dist/components/msa/domainBandCursor.d.ts +7 -11
  80. package/dist/components/msa/domainBandCursor.js +7 -11
  81. package/dist/components/msa/domainBandCursor.js.map +1 -1
  82. package/dist/components/msa/drawFeatureSpans.d.ts +53 -0
  83. package/dist/components/msa/drawFeatureSpans.js +78 -0
  84. package/dist/components/msa/drawFeatureSpans.js.map +1 -0
  85. package/dist/components/msa/legendRows.d.ts +8 -0
  86. package/dist/components/msa/legendRows.js +16 -0
  87. package/dist/components/msa/legendRows.js.map +1 -0
  88. package/dist/components/msa/msaRaster.d.ts +30 -27
  89. package/dist/components/msa/msaRaster.js +193 -90
  90. package/dist/components/msa/msaRaster.js.map +1 -1
  91. package/dist/components/msa/packDomainLanes.d.ts +20 -0
  92. package/dist/components/msa/packDomainLanes.js +33 -0
  93. package/dist/components/msa/packDomainLanes.js.map +1 -0
  94. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
  95. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +51 -87
  96. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  97. package/dist/components/msa/renderHighlights.d.ts +44 -4
  98. package/dist/components/msa/renderHighlights.js +99 -11
  99. package/dist/components/msa/renderHighlights.js.map +1 -1
  100. package/dist/components/msa/renderMSABlock.d.ts +1 -2
  101. package/dist/components/msa/renderMSABlock.js +28 -31
  102. package/dist/components/msa/renderMSABlock.js.map +1 -1
  103. package/dist/components/msa/renderMSAMouseover.js +9 -30
  104. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  105. package/dist/components/msa/tileColor.js +4 -7
  106. package/dist/components/msa/tileColor.js.map +1 -1
  107. package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
  108. package/dist/components/msa/useMsaBlockMouse.js +6 -6
  109. package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
  110. package/dist/components/renderCtx.d.ts +1 -1
  111. package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
  112. package/dist/components/rowpanels/RowPanelBlock.js +86 -0
  113. package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
  114. package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
  115. package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
  116. package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
  117. package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
  118. package/dist/components/rowpanels/RowPanels.js +32 -0
  119. package/dist/components/rowpanels/RowPanels.js.map +1 -0
  120. package/dist/components/rowpanels/headerLayout.d.ts +1 -0
  121. package/dist/components/rowpanels/headerLayout.js +5 -0
  122. package/dist/components/rowpanels/headerLayout.js.map +1 -0
  123. package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
  124. package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
  125. package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
  126. package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
  127. package/dist/components/rowpanels/renderRowPanel.js +22 -0
  128. package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
  129. package/dist/components/rowpanels/renderStrip.d.ts +20 -0
  130. package/dist/components/rowpanels/renderStrip.js +26 -0
  131. package/dist/components/rowpanels/renderStrip.js.map +1 -0
  132. package/dist/components/tracks/TrackBlocks.js +13 -16
  133. package/dist/components/tracks/TrackBlocks.js.map +1 -1
  134. package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
  135. package/dist/components/tracks/TrackTooltipContent.js +109 -0
  136. package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
  137. package/dist/components/tracks/drawTracks.d.ts +30 -12
  138. package/dist/components/tracks/drawTracks.js +127 -34
  139. package/dist/components/tracks/drawTracks.js.map +1 -1
  140. package/dist/components/tracks/useTrackHover.d.ts +22 -0
  141. package/dist/components/tracks/useTrackHover.js +30 -0
  142. package/dist/components/tracks/useTrackHover.js.map +1 -0
  143. package/dist/components/tree/CladeLabels.d.ts +12 -0
  144. package/dist/components/tree/CladeLabels.js +48 -0
  145. package/dist/components/tree/CladeLabels.js.map +1 -0
  146. package/dist/components/tree/TreeCanvas.js +6 -4
  147. package/dist/components/tree/TreeCanvas.js.map +1 -1
  148. package/dist/components/tree/TreeCanvasBlock.js +6 -21
  149. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  150. package/dist/components/tree/TreeOverview.d.ts +14 -0
  151. package/dist/components/tree/TreeOverview.js +75 -0
  152. package/dist/components/tree/TreeOverview.js.map +1 -0
  153. package/dist/components/tree/TreeRuler.js +11 -5
  154. package/dist/components/tree/TreeRuler.js.map +1 -1
  155. package/dist/components/tree/cladeBrackets.d.ts +25 -0
  156. package/dist/components/tree/cladeBrackets.js +51 -0
  157. package/dist/components/tree/cladeBrackets.js.map +1 -0
  158. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
  159. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  160. package/dist/components/tree/renderTreeCanvas.d.ts +0 -1
  161. package/dist/components/tree/renderTreeCanvas.js +221 -47
  162. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  163. package/dist/components/tree/renderTreeOverview.d.ts +52 -0
  164. package/dist/components/tree/renderTreeOverview.js +138 -0
  165. package/dist/components/tree/renderTreeOverview.js.map +1 -0
  166. package/dist/components/tree/scaleBar.d.ts +10 -0
  167. package/dist/components/tree/scaleBar.js +24 -0
  168. package/dist/components/tree/scaleBar.js.map +1 -0
  169. package/dist/components/tree/useTreeHover.js +2 -4
  170. package/dist/components/tree/useTreeHover.js.map +1 -1
  171. package/dist/constants.d.ts +18 -1
  172. package/dist/constants.js +51 -8
  173. package/dist/constants.js.map +1 -1
  174. package/dist/createPaletteMap.d.ts +7 -6
  175. package/dist/createPaletteMap.js +10 -9
  176. package/dist/createPaletteMap.js.map +1 -1
  177. package/dist/element.d.ts +13 -0
  178. package/dist/element.js +269 -0
  179. package/dist/element.js.map +1 -0
  180. package/dist/featureFields.d.ts +11 -0
  181. package/dist/featureFields.js +17 -0
  182. package/dist/featureFields.js.map +1 -0
  183. package/dist/fetchUtils.d.ts +7 -7
  184. package/dist/fetchUtils.js +4 -32
  185. package/dist/fetchUtils.js.map +1 -1
  186. package/dist/flatToTree.js +1 -2
  187. package/dist/flatToTree.js.map +1 -1
  188. package/dist/ggplotPalettes.d.ts +10 -0
  189. package/dist/ggplotPalettes.js +58 -0
  190. package/dist/ggplotPalettes.js.map +1 -1
  191. package/dist/hierarchy.d.ts +29 -1
  192. package/dist/hierarchy.js +82 -19
  193. package/dist/hierarchy.js.map +1 -1
  194. package/dist/index.d.ts +10 -1
  195. package/dist/index.js +10 -2
  196. package/dist/index.js.map +1 -1
  197. package/dist/model/DataModel.js +4 -4
  198. package/dist/model/DataModel.js.map +1 -1
  199. package/dist/model/msaModel.d.ts +3 -2
  200. package/dist/model/msaModel.js +3 -2
  201. package/dist/model/msaModel.js.map +1 -1
  202. package/dist/model/treeModel.d.ts +30 -0
  203. package/dist/model/treeModel.js +37 -1
  204. package/dist/model/treeModel.js.map +1 -1
  205. package/dist/model.d.ts +792 -259
  206. package/dist/model.js +2092 -675
  207. package/dist/model.js.map +1 -1
  208. package/dist/mount.d.ts +11 -0
  209. package/dist/mount.js +22 -0
  210. package/dist/mount.js.map +1 -0
  211. package/dist/neighborJoining.js +8 -32
  212. package/dist/neighborJoining.js.map +1 -1
  213. package/dist/renderToStaticMarkup.d.ts +15 -13
  214. package/dist/renderToStaticMarkup.js +37 -25
  215. package/dist/renderToStaticMarkup.js.map +1 -1
  216. package/dist/renderToSvg.js +198 -68
  217. package/dist/renderToSvg.js.map +1 -1
  218. package/dist/rowCoordinateCalculations.d.ts +26 -28
  219. package/dist/rowCoordinateCalculations.js +13 -39
  220. package/dist/rowCoordinateCalculations.js.map +1 -1
  221. package/dist/scales.d.ts +22 -0
  222. package/dist/scales.js +30 -0
  223. package/dist/scales.js.map +1 -0
  224. package/dist/seqPosToGlobalCol.d.ts +2 -3
  225. package/dist/seqPosToGlobalCol.js +5 -4
  226. package/dist/seqPosToGlobalCol.js.map +1 -1
  227. package/dist/sequenceLogo.d.ts +6 -11
  228. package/dist/sequenceLogo.js +6 -11
  229. package/dist/sequenceLogo.js.map +1 -1
  230. package/dist/stripDefault.d.ts +7 -14
  231. package/dist/stripDefault.js +7 -14
  232. package/dist/stripDefault.js.map +1 -1
  233. package/dist/svgTestUtil.d.ts +306 -124
  234. package/dist/types.d.ts +295 -3
  235. package/dist/umd.d.ts +2 -0
  236. package/dist/umd.js +4 -2
  237. package/dist/umd.js.map +1 -1
  238. package/dist/useCanvasAutorun.d.ts +5 -10
  239. package/dist/useCanvasAutorun.js +5 -10
  240. package/dist/useCanvasAutorun.js.map +1 -1
  241. package/dist/useMsaSvgFigure.d.ts +20 -0
  242. package/dist/useMsaSvgFigure.js +46 -0
  243. package/dist/useMsaSvgFigure.js.map +1 -0
  244. package/dist/util.d.ts +10 -4
  245. package/dist/util.js +37 -10
  246. package/dist/util.js.map +1 -1
  247. package/dist/version.d.ts +1 -1
  248. package/dist/version.js +1 -1
  249. package/dist/wuss.d.ts +14 -0
  250. package/dist/wuss.js +55 -0
  251. package/dist/wuss.js.map +1 -0
  252. package/package.json +23 -14
  253. package/src/colorSchemes.ts +1 -2
  254. package/src/columnStats.ts +58 -0
  255. package/src/components/DragHandle.tsx +18 -7
  256. package/src/components/Loading.tsx +14 -8
  257. package/src/components/MSAView.tsx +19 -5
  258. package/src/components/MSAViewer.tsx +326 -10
  259. package/src/components/PortalTooltip.tsx +47 -0
  260. package/src/components/ResizeHandles.tsx +21 -36
  261. package/src/components/SequenceTextArea.tsx +3 -3
  262. package/src/components/Track.tsx +55 -18
  263. package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
  264. package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
  265. package/src/components/dialogs/FeatureDialog.tsx +13 -9
  266. package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
  267. package/src/components/header/GappynessSlider.tsx +6 -11
  268. package/src/components/header/Header.tsx +10 -0
  269. package/src/components/header/HeaderStatusArea.tsx +0 -5
  270. package/src/components/header/LoadWarnings.tsx +48 -0
  271. package/src/components/header/MultiAlignmentSelector.tsx +0 -0
  272. package/src/components/header/ScrollZoomIcons.tsx +52 -0
  273. package/src/components/header/TreeSettingsMenu.tsx +7 -1
  274. package/src/components/header/UnshareableDataWarning.tsx +56 -0
  275. package/src/components/header/ZoomControls.tsx +74 -14
  276. package/src/components/header/getAnnotationsMenu.ts +13 -17
  277. package/src/components/header/settingsMenuItems.ts +11 -6
  278. package/src/components/import/ImportForm.tsx +2 -2
  279. package/src/components/import/ImportFormExamples.tsx +4 -8
  280. package/src/components/import/util.ts +2 -0
  281. package/src/components/minimap/Minimap.tsx +1 -2
  282. package/src/components/msa/AnnotationLegend.tsx +48 -38
  283. package/src/components/msa/MSACanvas.tsx +3 -5
  284. package/src/components/msa/MSACanvasBlock.tsx +17 -21
  285. package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
  286. package/src/components/msa/domainBandCursor.ts +7 -11
  287. package/src/components/msa/drawFeatureSpans.ts +150 -0
  288. package/src/components/msa/legendRows.ts +24 -0
  289. package/src/components/msa/msaRaster.ts +236 -88
  290. package/src/components/msa/packDomainLanes.ts +36 -0
  291. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
  292. package/src/components/msa/renderHighlights.ts +141 -10
  293. package/src/components/msa/renderMSABlock.ts +29 -38
  294. package/src/components/msa/renderMSAMouseover.ts +9 -39
  295. package/src/components/msa/tileColor.ts +4 -7
  296. package/src/components/msa/useMsaBlockMouse.ts +6 -6
  297. package/src/components/renderCtx.ts +1 -0
  298. package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
  299. package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
  300. package/src/components/rowpanels/RowPanels.tsx +77 -0
  301. package/src/components/rowpanels/headerLayout.ts +5 -0
  302. package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
  303. package/src/components/rowpanels/renderRowPanel.ts +41 -0
  304. package/src/components/rowpanels/renderStrip.ts +46 -0
  305. package/src/components/tracks/TrackBlocks.tsx +13 -18
  306. package/src/components/tracks/TrackTooltipContent.tsx +156 -0
  307. package/src/components/tracks/drawTracks.ts +169 -38
  308. package/src/components/tracks/useTrackHover.ts +42 -0
  309. package/src/components/tree/CladeLabels.tsx +77 -0
  310. package/src/components/tree/TreeCanvas.tsx +4 -3
  311. package/src/components/tree/TreeCanvasBlock.tsx +10 -32
  312. package/src/components/tree/TreeOverview.tsx +106 -0
  313. package/src/components/tree/TreeRuler.tsx +29 -5
  314. package/src/components/tree/cladeBrackets.ts +73 -0
  315. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
  316. package/src/components/tree/renderTreeCanvas.ts +312 -48
  317. package/src/components/tree/renderTreeOverview.ts +212 -0
  318. package/src/components/tree/scaleBar.ts +23 -0
  319. package/src/components/tree/useTreeHover.ts +2 -4
  320. package/src/constants.ts +61 -8
  321. package/src/createPaletteMap.ts +10 -9
  322. package/src/element.ts +321 -0
  323. package/src/featureFields.ts +19 -0
  324. package/src/fetchUtils.ts +7 -40
  325. package/src/flatToTree.ts +1 -2
  326. package/src/ggplotPalettes.ts +60 -0
  327. package/src/hierarchy.ts +97 -20
  328. package/src/index.ts +46 -6
  329. package/src/model/DataModel.ts +5 -4
  330. package/src/model/msaModel.ts +3 -2
  331. package/src/model/treeModel.ts +42 -0
  332. package/src/model.ts +2492 -793
  333. package/src/mount.tsx +32 -0
  334. package/src/neighborJoining.ts +8 -32
  335. package/src/rawImports.d.ts +9 -0
  336. package/src/renderToStaticMarkup.ts +41 -25
  337. package/src/renderToSvg.tsx +365 -92
  338. package/src/rowCoordinateCalculations.ts +16 -62
  339. package/src/scales.ts +47 -0
  340. package/src/seqPosToGlobalCol.ts +5 -4
  341. package/src/sequenceLogo.ts +6 -11
  342. package/src/stripDefault.ts +7 -14
  343. package/src/types.ts +352 -12
  344. package/src/umd.ts +4 -2
  345. package/src/useCanvasAutorun.ts +5 -10
  346. package/src/useMsaSvgFigure.ts +72 -0
  347. package/src/util.ts +40 -14
  348. package/src/version.ts +1 -1
  349. package/src/wuss.ts +62 -0
  350. package/dist/components/dialogs/InterProScanDialog.js +0 -137
  351. package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
  352. package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
  353. package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
  354. package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
  355. package/dist/components/msa/ColumnStats.js +0 -42
  356. package/dist/components/msa/ColumnStats.js.map +0 -1
  357. package/dist/launchInterProScan.d.ts +0 -13
  358. package/dist/launchInterProScan.js +0 -110
  359. package/dist/launchInterProScan.js.map +0 -1
  360. package/dist/useColorContrast.d.ts +0 -10
  361. package/dist/useColorContrast.js +0 -13
  362. package/dist/useColorContrast.js.map +0 -1
  363. package/src/clustalX.test.ts +0 -74
  364. package/src/colSpace.test.ts +0 -67
  365. package/src/collapseLogic.test.ts +0 -115
  366. package/src/colorSchemes.docs.test.ts +0 -57
  367. package/src/columnCounts.test.ts +0 -73
  368. package/src/columnStats.test.ts +0 -94
  369. package/src/columnTracks.test.ts +0 -97
  370. package/src/components/dialogs/InterProScanDialog.tsx +0 -214
  371. package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
  372. package/src/components/minimap/minimapLayout.test.ts +0 -71
  373. package/src/components/msa/ColumnStats.tsx +0 -54
  374. package/src/components/msa/msaRaster.test.ts +0 -145
  375. package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
  376. package/src/components/tree/renderTreeCanvas.test.ts +0 -296
  377. package/src/dataInitialized.test.ts +0 -42
  378. package/src/domainBands.test.ts +0 -122
  379. package/src/domainLetterColor.test.ts +0 -80
  380. package/src/exportFileName.test.ts +0 -40
  381. package/src/fetchUtils.test.ts +0 -83
  382. package/src/flatToTree.test.ts +0 -51
  383. package/src/hierarchy.test.ts +0 -228
  384. package/src/highlights.test.ts +0 -70
  385. package/src/impgRender.test.tsx +0 -68
  386. package/src/largeTree.test.ts +0 -67
  387. package/src/launchInterProScan.ts +0 -167
  388. package/src/loadErrorDisplay.test.tsx +0 -102
  389. package/src/modelFilehandleLoaders.test.ts +0 -137
  390. package/src/modelReset.test.ts +0 -120
  391. package/src/neighborJoining.test.ts +0 -164
  392. package/src/parseAsn1.test.ts +0 -36
  393. package/src/propertyConservation.test.ts +0 -36
  394. package/src/renderColumnTracksSvg.test.tsx +0 -108
  395. package/src/renderDomainsSvg.test.tsx +0 -118
  396. package/src/renderHighlightsSvg.test.tsx +0 -85
  397. package/src/renderMinimapSvg.test.tsx +0 -62
  398. package/src/renderRasterSvg.test.tsx +0 -144
  399. package/src/renderSequenceLogoSvg.test.tsx +0 -165
  400. package/src/renderToSvg.test.tsx +0 -65
  401. package/src/reset.test.ts +0 -61
  402. package/src/rowCoordinateCalculations.test.ts +0 -211
  403. package/src/rowSpace.test.ts +0 -46
  404. package/src/segmentOverlay.test.ts +0 -70
  405. package/src/seqPosToGlobalCol.test.ts +0 -59
  406. package/src/sequenceLogo.test.ts +0 -88
  407. package/src/setFontSize.test.ts +0 -33
  408. package/src/stripDefault.test.ts +0 -48
  409. package/src/stripDefaultSnapshot.test.ts +0 -87
  410. package/src/treeMetadata.test.ts +0 -39
  411. package/src/useCanvasAutorun.test.tsx +0 -98
  412. package/src/useColorContrast.ts +0 -18
  413. package/src/viewChrome.test.tsx +0 -134
  414. package/src/wheelZoom.test.ts +0 -46
@@ -1,22 +1,36 @@
1
1
  import React, { lazy, useCallback, useRef, useState } from 'react'
2
2
 
3
+ import BaseTooltip from '@jbrowse/core/ui/BaseTooltip'
3
4
  import { makeStyles } from '@jbrowse/core/util/tss-react'
4
5
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'
5
6
  import { IconButton, Menu, MenuItem } from '@mui/material'
6
7
  import { observer } from 'mobx-react'
7
8
 
8
9
  import { useWheelScroll } from '../useWheelScroll.ts'
10
+ import TrackTooltipContent from './tracks/TrackTooltipContent.tsx'
11
+ import { useTrackHover } from './tracks/useTrackHover.ts'
9
12
 
10
13
  import type { MsaViewModel } from '../model.ts'
11
14
  import type { BasicTrack } from '../types.ts'
12
15
 
13
16
  const TrackInfoDialog = lazy(() => import('./dialogs/TrackInfoDialog.tsx'))
14
17
 
15
- const useStyles = makeStyles()({
18
+ const useStyles = makeStyles()(theme => ({
16
19
  button: {
17
20
  padding: 0,
18
21
  },
19
- })
22
+ // a hairline under every track but the last, across the labels as well as
23
+ // the alignment. The divider a track's resize handle draws covers only the
24
+ // alignment, and tracks sharing a height have no handle between them. Inset,
25
+ // so the line costs no layout height: totalTrackAreaHeight sums the model's
26
+ // heights, and the column indicator is drawn against that sum
27
+ row: {
28
+ display: 'flex',
29
+ '&:not(:last-child)': {
30
+ boxShadow: `inset 0 -1px 0 ${theme.palette.divider}`,
31
+ },
32
+ },
33
+ }))
20
34
 
21
35
  const TrackLabel = observer(function TrackLabel({
22
36
  model,
@@ -37,21 +51,37 @@ const TrackLabel = observer(function TrackLabel({
37
51
  const trackLabelHeight = Math.min(height, fontSize)
38
52
 
39
53
  return (
54
+ // a flex row, not inline text: zooming in grows fontSize against a tree
55
+ // area the leaf labels sized, and a name that wrapped took its menu button
56
+ // onto a second line, under the next track's button
40
57
  <div
41
58
  style={{
42
59
  width,
43
60
  height,
44
61
  flexShrink: 0,
45
- textAlign: 'right',
62
+ display: 'flex',
63
+ alignItems: 'flex-start',
64
+ justifyContent: 'flex-end',
65
+ gap: 2,
46
66
  fontSize: trackLabelHeight,
47
67
  }}
48
68
  >
49
- {drawLabels ? name : ''}{' '}
69
+ <span
70
+ title={name}
71
+ style={{
72
+ overflow: 'hidden',
73
+ textOverflow: 'ellipsis',
74
+ whiteSpace: 'nowrap',
75
+ }}
76
+ >
77
+ {drawLabels ? name : ''}
78
+ </span>
50
79
  <IconButton
51
80
  className={classes.button}
52
81
  style={{
53
82
  width: trackLabelHeight,
54
83
  height: trackLabelHeight,
84
+ flexShrink: 0,
55
85
  }}
56
86
  onClick={event => {
57
87
  setAnchorEl(event.currentTarget)
@@ -102,7 +132,7 @@ const Track = observer(function ({
102
132
  model: MsaViewModel
103
133
  track: BasicTrack
104
134
  }) {
105
- const { resizeHandleWidth, colWidth, scrollX, numColumns } = model
135
+ const { resizeHandleWidth, rowPanelsWidth, showColumnStats } = model
106
136
  const {
107
137
  model: { height },
108
138
  } = track
@@ -114,31 +144,38 @@ const Track = observer(function ({
114
144
  [model],
115
145
  )
116
146
  useWheelScroll({ ref, onScrollX })
147
+ const { classes } = useStyles()
148
+ const { hover, onMouseMove, onMouseLeave } = useTrackHover({
149
+ model,
150
+ tooltip: showColumnStats,
151
+ })
117
152
 
118
153
  return (
119
- <div style={{ display: 'flex', height }}>
154
+ <div className={classes.row} style={{ height }}>
120
155
  <TrackLabel model={model} track={track} />
121
- <div style={{ width: resizeHandleWidth, flexShrink: 0 }} />
156
+ {/* the row panels are row space, so a track leaves their column empty
157
+ and starts where the alignment canvas does */}
158
+ <div
159
+ style={{ width: rowPanelsWidth + resizeHandleWidth, flexShrink: 0 }}
160
+ />
122
161
  <div
123
162
  ref={ref}
163
+ data-testid={`track_${track.model.id}`}
124
164
  onMouseMove={event => {
125
- if (!ref.current) {
126
- return
127
- }
128
- const { left } = ref.current.getBoundingClientRect()
129
- const mouseX = event.clientX - left - scrollX
130
- const col = Math.floor(mouseX / colWidth)
131
- if (col >= 0 && col < numColumns) {
132
- model.setMousePos(col, undefined)
133
- } else {
134
- model.setMousePos(undefined, undefined)
165
+ if (ref.current) {
166
+ onMouseMove(event, ref.current)
135
167
  }
136
168
  }}
137
169
  onMouseLeave={() => {
138
- model.setMousePos(undefined, undefined)
170
+ onMouseLeave()
139
171
  }}
140
172
  >
141
173
  <track.ReactComponent model={model} track={track} />
174
+ {hover ? (
175
+ <BaseTooltip clientPoint={{ x: hover.x, y: hover.y + 15 }}>
176
+ <TrackTooltipContent model={model} track={track} col={hover.col} />
177
+ </BaseTooltip>
178
+ ) : null}
142
179
  </div>
143
180
  </div>
144
181
  )
@@ -0,0 +1,162 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import { Dialog, ErrorMessage } from '@jbrowse/core/ui'
4
+ import {
5
+ Button,
6
+ DialogActions,
7
+ DialogContent,
8
+ FormControl,
9
+ FormControlLabel,
10
+ Radio,
11
+ RadioGroup,
12
+ TextField,
13
+ Typography,
14
+ } from '@mui/material'
15
+ import { observer } from 'mobx-react'
16
+ import {
17
+ annotationsToGFF,
18
+ interProScanResponseToAnnotations,
19
+ } from 'msa-parsers'
20
+
21
+ import type { MsaViewModel } from '../../model.ts'
22
+ import type { InterProScanResponse } from 'msa-parsers'
23
+
24
+ // GFF3 as the CLI writes it, or the JSON an InterProScan run returns. Both
25
+ // arrive as text and the model keeps GFF, so the JSON is converted on the way
26
+ // in rather than given a second path through the model
27
+ function toGFF(text: string) {
28
+ const trimmed = text.trimStart()
29
+ if (!trimmed.startsWith('{')) {
30
+ return text
31
+ }
32
+ const response: InterProScanResponse = JSON.parse(trimmed)
33
+ return annotationsToGFF(interProScanResponseToAnnotations(response))
34
+ }
35
+
36
+ async function fetchText(url: string) {
37
+ const response = await fetch(url)
38
+ if (!response.ok) {
39
+ throw new Error(
40
+ `HTTP ${response.status} fetching ${url} ${await response.text()}`,
41
+ )
42
+ }
43
+ return response.text()
44
+ }
45
+
46
+ const AnnotationFileDialog = observer(function ({
47
+ handleClose,
48
+ model,
49
+ }: {
50
+ handleClose: () => void
51
+ model: MsaViewModel
52
+ }) {
53
+ const [file, setFile] = useState<File>()
54
+ const [choice, setChoice] = useState('file')
55
+ const [url, setUrl] = useState('')
56
+ const [error, setError] = useState<unknown>()
57
+ const [loading, setLoading] = useState(false)
58
+
59
+ // the error is shown here rather than notified: the standalone app and the
60
+ // MSAViewer component have no jbrowse session to notify, and asking one for
61
+ // its notify() threw out of the success path into the catch, which threw
62
+ // again on the same missing session
63
+ return (
64
+ <Dialog
65
+ maxWidth="xl"
66
+ title="Open annotation file"
67
+ onClose={() => {
68
+ handleClose()
69
+ }}
70
+ open
71
+ >
72
+ <DialogContent>
73
+ {error ? <ErrorMessage error={error} /> : null}
74
+ <Typography>
75
+ Open a GFF3 file of annotations, such as the one `react-msaview-cli
76
+ interpro` writes, or the JSON an InterProScan run returns.
77
+ </Typography>
78
+
79
+ <div style={{ display: 'flex', margin: 30 }}>
80
+ <FormControl component="fieldset">
81
+ <RadioGroup
82
+ value={choice}
83
+ onChange={event => {
84
+ setChoice(event.target.value)
85
+ }}
86
+ >
87
+ <FormControlLabel value="url" control={<Radio />} label="URL" />
88
+ <FormControlLabel value="file" control={<Radio />} label="File" />
89
+ </RadioGroup>
90
+ </FormControl>
91
+ {choice === 'url' ? (
92
+ <div>
93
+ <Typography>Open an annotation file from a URL</Typography>
94
+ <TextField
95
+ label="URL"
96
+ value={url}
97
+ onChange={event => {
98
+ setUrl(event.target.value)
99
+ }}
100
+ />
101
+ </div>
102
+ ) : (
103
+ <div style={{ paddingTop: 20 }}>
104
+ <Typography>
105
+ Open an annotation file from your local drive
106
+ </Typography>
107
+ <Button variant="outlined" component="label">
108
+ Choose File
109
+ <input
110
+ type="file"
111
+ hidden
112
+ onChange={({ target }) => {
113
+ const chosen = target.files?.[0]
114
+ if (chosen) {
115
+ setFile(chosen)
116
+ }
117
+ }}
118
+ />
119
+ </Button>
120
+ {file ? <Typography>{file.name}</Typography> : null}
121
+ </div>
122
+ )}
123
+ </div>
124
+ </DialogContent>
125
+ <DialogActions>
126
+ <Button
127
+ variant="contained"
128
+ color="primary"
129
+ disabled={loading}
130
+ onClick={() => {
131
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
132
+ ;(async () => {
133
+ setLoading(true)
134
+ setError(undefined)
135
+ try {
136
+ const text = await (choice === 'file' && file
137
+ ? file.text()
138
+ : fetchText(url))
139
+ // through the model's own GFF text, so the annotations travel
140
+ // in the snapshot and the shared URL like every other layer.
141
+ // Setting them straight onto the volatile left a view whose
142
+ // link opened without them
143
+ model.setGFF(toGFF(text))
144
+ model.setShowDomains(true)
145
+ handleClose()
146
+ } catch (e) {
147
+ console.error(e)
148
+ setError(e)
149
+ } finally {
150
+ setLoading(false)
151
+ }
152
+ })()
153
+ }}
154
+ >
155
+ Open annotations
156
+ </Button>
157
+ </DialogActions>
158
+ </Dialog>
159
+ )
160
+ })
161
+
162
+ export default AnnotationFileDialog
@@ -49,15 +49,20 @@ export default function ExportSVGDialog({
49
49
  totalWidth,
50
50
  totalHeight,
51
51
  treeAreaWidth,
52
+ rowPanelsWidth,
52
53
  turnedOnTracks,
53
54
  totalTrackAreaHeight,
54
55
  numColumns,
55
56
  leaves,
56
57
  showMsaLetters,
58
+ treeOverviewHeight,
57
59
  } = model
58
60
  const hasTracks = turnedOnTracks.length > 0
59
- const entireWidth = totalWidth + treeAreaWidth
60
- const entireHeight = totalHeight + (includeTracks ? totalTrackAreaHeight : 0)
61
+ const entireWidth = totalWidth + treeAreaWidth + rowPanelsWidth
62
+ const entireHeight =
63
+ totalHeight +
64
+ (includeTracks ? totalTrackAreaHeight : 0) +
65
+ treeOverviewHeight
61
66
  // the background is one raster image whatever its size, so what the figure
62
67
  // actually costs is its residue letters: each is an svg element of its own.
63
68
  // Past roughly this many the export runs to tens of seconds and can exhaust
@@ -16,14 +16,20 @@ import { observer } from 'mobx-react'
16
16
  import type { MsaViewModel } from '../../model.ts'
17
17
 
18
18
  const Toggles = observer(function ({ model }: { model: MsaViewModel }) {
19
- const { featureFilters } = model
19
+ // the accessions the file has, not the ones the filter map happens to hold:
20
+ // that map now carries only what the reader turned off, and before that it
21
+ // accumulated every accession of every file opened in this view
22
+ const { annotationTypes } = model
23
+ const setAll = (shown: boolean) => {
24
+ for (const accession of annotationTypes.keys()) {
25
+ model.setFilter(accession, shown)
26
+ }
27
+ }
20
28
  return (
21
29
  <div>
22
30
  <Button
23
31
  onClick={() => {
24
- for (const key of featureFilters.keys()) {
25
- model.setFilter(key, true)
26
- }
32
+ setAll(true)
27
33
  }}
28
34
  >
29
35
  Toggle all on
@@ -31,9 +37,7 @@ const Toggles = observer(function ({ model }: { model: MsaViewModel }) {
31
37
 
32
38
  <Button
33
39
  onClick={() => {
34
- for (const key of featureFilters.keys()) {
35
- model.setFilter(key, false)
36
- }
40
+ setAll(false)
37
41
  }}
38
42
  >
39
43
  Toggle all off
@@ -68,11 +72,11 @@ const FeatureTable = observer(function ({ model }: { model: MsaViewModel }) {
68
72
  <TableRow key={accession}>
69
73
  <TableCell padding="checkbox">
70
74
  <Checkbox
71
- checked={model.featureFilters.get(accession) ?? false}
75
+ checked={!model.turnedOffFeatures.get(accession)}
72
76
  onChange={() => {
73
77
  model.setFilter(
74
78
  accession,
75
- !model.featureFilters.get(accession),
79
+ !!model.turnedOffFeatures.get(accession),
76
80
  )
77
81
  }}
78
82
  />
@@ -13,7 +13,7 @@ const useStyles = makeStyles()(theme => ({
13
13
  textArea: {
14
14
  padding: theme.spacing(2),
15
15
  overflow: 'auto',
16
- background: '#ddd',
16
+ background: theme.palette.action.selected,
17
17
  wordBreak: 'break-word',
18
18
  },
19
19
  }))
@@ -23,18 +23,13 @@ const GappynessSlider = observer(function GappynessSlider({
23
23
  Hide columns w/ &ge;{allowedGappyness}% gaps
24
24
  </Typography>
25
25
  <Slider
26
- // Named, because the class alone is not enough to find it from outside.
27
- // An MSA is normally embedded beside other MUI Sliders (in JBrowse, the
28
- // linear view's own zoom control), so a `.MuiSlider-thumb` selector in a
29
- // test or a screenshot spec picks whichever comes first in the document
30
- // and drives that instead — which reads as this slider ignoring its
31
- // keyboard. Target `[data-testid="gappyness_slider"] input` to reach the
32
- // hidden range input MUI renders in the thumb, which is the node that
33
- // takes focus and receives arrow/PageUp/PageDown.
26
+ // In JBrowse other MUI Sliders share the page, so `.MuiSlider-thumb`
27
+ // can match the wrong one. Tests and screenshot specs target
28
+ // `[data-testid="gappyness_slider"] input`, the hidden range input that
29
+ // takes focus and arrow/PageUp/PageDown.
34
30
  //
35
- // Deliberately NOT `slotProps={{ input: ... }}`: passing slotProps here
36
- // widens the Slider's generic so `onChange`'s `val` infers as
37
- // `number | number[]` and no longer assigns to setAllowedGappyness.
31
+ // Not `slotProps={{ input: ... }}`: that widens `onChange`'s `val` to
32
+ // `number | number[]`, which setAllowedGappyness rejects.
38
33
  data-testid="gappyness_slider"
39
34
  style={{ width: 100 }}
40
35
  min={1}
@@ -10,9 +10,11 @@ import FileMenu from './FileMenu.tsx'
10
10
  import GappynessSlider from './GappynessSlider.tsx'
11
11
  import HeaderInfoArea from './HeaderInfoArea.tsx'
12
12
  import HeaderStatusArea from './HeaderStatusArea.tsx'
13
+ import LoadWarnings from './LoadWarnings.tsx'
13
14
  import MSASettingsMenu from './MSASettingsMenu.tsx'
14
15
  import MultiAlignmentSelector from './MultiAlignmentSelector.tsx'
15
16
  import TreeSettingsMenu from './TreeSettingsMenu.tsx'
17
+ import UnshareableDataWarning from './UnshareableDataWarning.tsx'
16
18
  import ZoomControls from './ZoomControls.tsx'
17
19
  import ZoomMenu from './ZoomMenu.tsx'
18
20
 
@@ -25,6 +27,12 @@ const Header = observer(function ({ model }: { model: MsaViewModel }) {
25
27
  useEffect(() => {
26
28
  model.setHeaderHeight(height ?? 0)
27
29
  }, [model, height])
30
+ useEffect(
31
+ () => () => {
32
+ model.setHeaderHeight(0)
33
+ },
34
+ [model],
35
+ )
28
36
  return (
29
37
  <div ref={ref} style={{ display: 'flex' }}>
30
38
  <FileMenu model={model} />
@@ -39,6 +47,8 @@ const Header = observer(function ({ model }: { model: MsaViewModel }) {
39
47
  </div>
40
48
  <HeaderInfoArea model={model} />
41
49
  <Spacer />
50
+ <LoadWarnings model={model} />
51
+ <UnshareableDataWarning model={model} />
42
52
  <HeaderStatusArea model={model} />
43
53
  <Tooltip title="About">
44
54
  <IconButton
@@ -20,11 +20,6 @@ const HeaderStatusArea = observer(({ model }: { model: MsaViewModel }) => {
20
20
  return status ? (
21
21
  <Typography className={classes.margin}>
22
22
  <LoadingEllipses message={status.msg} component="span" />{' '}
23
- {status.url ? (
24
- <a href={status.url} target="_blank" rel="noreferrer">
25
- (status)
26
- </a>
27
- ) : null}{' '}
28
23
  {status.onCancel ? (
29
24
  <Button size="small" onClick={() => status.onCancel?.()}>
30
25
  Cancel
@@ -0,0 +1,48 @@
1
+ import React from 'react'
2
+
3
+ import { makeStyles } from '@jbrowse/core/util/tss-react'
4
+ import Warning from '@mui/icons-material/Warning'
5
+ import { Tooltip, Typography } from '@mui/material'
6
+ import { observer } from 'mobx-react'
7
+
8
+ import type { MsaViewModel } from '../../model.ts'
9
+
10
+ const useStyles = makeStyles()(theme => ({
11
+ warning: {
12
+ display: 'flex',
13
+ alignItems: 'center',
14
+ gap: 4,
15
+ margin: 'auto',
16
+ marginLeft: 10,
17
+ whiteSpace: 'nowrap',
18
+ color: theme.palette.warning.main,
19
+ cursor: 'pointer',
20
+ },
21
+ }))
22
+
23
+ // A failed optional layer, such as a 404 on the annotations or row metadata
24
+ // that is not JSON, shows here as a dismissible warning. Setting `error` would
25
+ // clear dataInitialized and hide the loaded alignment.
26
+ const LoadWarnings = observer(function ({ model }: { model: MsaViewModel }) {
27
+ const { warnings } = model
28
+ const { classes } = useStyles()
29
+ if (warnings.length === 0) {
30
+ return null
31
+ }
32
+ return (
33
+ <Tooltip title={`${warnings.join(' ')} (click to dismiss)`}>
34
+ <Typography
35
+ component="div"
36
+ className={classes.warning}
37
+ onClick={() => {
38
+ model.clearWarnings()
39
+ }}
40
+ >
41
+ <Warning fontSize="small" />
42
+ {warnings.length > 1 ? `${warnings.length} warnings` : 'Warning'}
43
+ </Typography>
44
+ </Tooltip>
45
+ )
46
+ })
47
+
48
+ export default LoadWarnings
@@ -0,0 +1,52 @@
1
+ import React from 'react'
2
+
3
+ import SvgIcon from '@mui/material/SvgIcon'
4
+
5
+ import type { SvgIconProps } from '@mui/material/SvgIcon'
6
+
7
+ // Mouse glyphs with outward arrows on the axes a wheel zoom scales.
8
+ // @mui/icons-material ships only the plain `Mouse`, and three variants that
9
+ // differ only in their arrows have to share one body to stay apart at 24px.
10
+ // The body's inner subpath runs the opposite sweep, which punches the hole the
11
+ // wheel bar sits in.
12
+ const BODY =
13
+ 'M12 5a4 4 0 0 0-4 4v6a4 4 0 0 0 8 0V9a4 4 0 0 0-4-4zm0 2a2 2 0 0 1 2 2v6a2 2 0 0 1-4 0V9a2 2 0 0 1 2-2z'
14
+ const WHEEL = 'M11.2 8.6h1.6v3.2h-1.6z'
15
+ const LEFT = 'M.4 12 5 15V9z'
16
+ const RIGHT = 'M23.6 12 19 9v6z'
17
+ const UP = 'M12 .4 15 4H9z'
18
+ const DOWN = 'M12 23.6 9 20h6z'
19
+
20
+ function MouseZoom({
21
+ arrows,
22
+ ...rest
23
+ }: SvgIconProps & { arrows: readonly string[] }) {
24
+ return (
25
+ <SvgIcon {...rest}>
26
+ <path d={BODY} />
27
+ <path d={WHEEL} />
28
+ {arrows.map(d => (
29
+ <path key={d} d={d} />
30
+ ))}
31
+ </SvgIcon>
32
+ )
33
+ }
34
+
35
+ // the bare body, for a wheel that scrolls. @mui/icons-material's own `Mouse` is
36
+ // a solid silhouette, which would jump to a different drawing when the menu
37
+ // changes the mode.
38
+ export function MouseScroll(props: SvgIconProps) {
39
+ return <MouseZoom {...props} arrows={[]} />
40
+ }
41
+
42
+ export function MouseZoomBoth(props: SvgIconProps) {
43
+ return <MouseZoom {...props} arrows={[LEFT, RIGHT, UP, DOWN]} />
44
+ }
45
+
46
+ export function MouseZoomHorizontal(props: SvgIconProps) {
47
+ return <MouseZoom {...props} arrows={[LEFT, RIGHT]} />
48
+ }
49
+
50
+ export function MouseZoomVertical(props: SvgIconProps) {
51
+ return <MouseZoom {...props} arrows={[UP, DOWN]} />
52
+ }
@@ -4,6 +4,7 @@ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
4
  import AccountTree from '@mui/icons-material/AccountTree'
5
5
  import { observer } from 'mobx-react'
6
6
 
7
+ import { maxNeighborJoiningRows } from '../../constants.ts'
7
8
  import { treeSettingsMenuItems } from './settingsMenuItems.ts'
8
9
 
9
10
  import type { MsaViewModel } from '../../model.ts'
@@ -14,6 +15,7 @@ const TreeSettingsMenu = observer(function ({
14
15
  model: MsaViewModel
15
16
  }) {
16
17
  const { rows } = model
18
+ const tooManyRows = rows.length > maxNeighborJoiningRows
17
19
  return (
18
20
  <CascadingMenuButton
19
21
  data-testid="tree_settings_menu"
@@ -30,7 +32,11 @@ const TreeSettingsMenu = observer(function ({
30
32
  type: 'subMenu' as const,
31
33
  subMenu: [
32
34
  {
33
- label: 'Calculate neighbor joining tree (BLOSUM62)',
35
+ // the label shows the cap before a click would freeze the tab
36
+ label: tooManyRows
37
+ ? `Calculate neighbor joining tree (over ${maxNeighborJoiningRows} rows, use FastTree)`
38
+ : 'Calculate neighbor joining tree (BLOSUM62)',
39
+ disabled: tooManyRows,
34
40
  onClick: () => {
35
41
  try {
36
42
  model.calculateNeighborJoiningTreeFromMSA()
@@ -0,0 +1,56 @@
1
+ import React from 'react'
2
+
3
+ import { makeStyles } from '@jbrowse/core/util/tss-react'
4
+ import LinkOff from '@mui/icons-material/LinkOff'
5
+ import { Tooltip, Typography } from '@mui/material'
6
+ import { observer } from 'mobx-react'
7
+
8
+ import type { MsaViewModel } from '../../model.ts'
9
+
10
+ const useStyles = makeStyles()(theme => ({
11
+ warning: {
12
+ display: 'flex',
13
+ alignItems: 'center',
14
+ gap: 4,
15
+ margin: 'auto',
16
+ marginLeft: 10,
17
+ whiteSpace: 'nowrap',
18
+ color: theme.palette.warning.main,
19
+ cursor: 'help',
20
+ },
21
+ }))
22
+
23
+ function size(bytes: number) {
24
+ return bytes < 1_000_000
25
+ ? `${Math.round(bytes / 1000)} kB`
26
+ : `${(bytes / 1_000_000).toFixed(1)} MB`
27
+ }
28
+
29
+ // Lists loaded documents the snapshot, and so a shared URL, omits. See
30
+ // `unshareableData` on the model.
31
+ const UnshareableDataWarning = observer(function ({
32
+ model,
33
+ }: {
34
+ model: MsaViewModel
35
+ }) {
36
+ const { unshareableData } = model
37
+ const { classes } = useStyles()
38
+ if (unshareableData.length === 0) {
39
+ return null
40
+ }
41
+ const what = unshareableData
42
+ .map(({ what, bytes }) => `${what} (${size(bytes)})`)
43
+ .join(' and the ')
44
+ return (
45
+ <Tooltip
46
+ title={`The ${what} came from this computer and is too large to travel in a URL, so a link to this page opens without it. Serve the file over HTTP and open it by URL to share the view.`}
47
+ >
48
+ <Typography component="div" className={classes.warning}>
49
+ <LinkOff fontSize="small" />
50
+ Not in the link
51
+ </Typography>
52
+ </Tooltip>
53
+ )
54
+ })
55
+
56
+ export default UnshareableDataWarning