react-msaview 6.4.2 → 7.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 (212) hide show
  1. package/README.md +6 -5
  2. package/bundle/index.js +100 -101
  3. package/bundle/index.js.map +4 -4
  4. package/dist/components/Loading.js +2 -2
  5. package/dist/components/Loading.js.map +1 -1
  6. package/dist/components/MSAViewer.d.ts +10 -2
  7. package/dist/components/MSAViewer.js +90 -2
  8. package/dist/components/MSAViewer.js.map +1 -1
  9. package/dist/components/ResizeHandles.d.ts +3 -3
  10. package/dist/components/ResizeHandles.js +28 -21
  11. package/dist/components/ResizeHandles.js.map +1 -1
  12. package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
  13. package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
  14. package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
  15. package/dist/components/dialogs/FeatureDialog.js +13 -9
  16. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  17. package/dist/components/header/Header.js +4 -0
  18. package/dist/components/header/Header.js.map +1 -1
  19. package/dist/components/header/HeaderStatusArea.js +0 -2
  20. package/dist/components/header/HeaderStatusArea.js.map +1 -1
  21. package/dist/components/header/LoadWarnings.d.ts +6 -0
  22. package/dist/components/header/LoadWarnings.js +36 -0
  23. package/dist/components/header/LoadWarnings.js.map +1 -0
  24. package/dist/components/header/MultiAlignmentSelector.js +0 -0
  25. package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
  26. package/dist/components/header/TreeSettingsMenu.js +9 -1
  27. package/dist/components/header/TreeSettingsMenu.js.map +1 -1
  28. package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
  29. package/dist/components/header/UnshareableDataWarning.js +42 -0
  30. package/dist/components/header/UnshareableDataWarning.js.map +1 -0
  31. package/dist/components/header/getAnnotationsMenu.js +14 -14
  32. package/dist/components/header/getAnnotationsMenu.js.map +1 -1
  33. package/dist/components/import/ImportForm.js +1 -1
  34. package/dist/components/import/ImportForm.js.map +1 -1
  35. package/dist/components/import/ImportFormExamples.js +2 -6
  36. package/dist/components/import/ImportFormExamples.js.map +1 -1
  37. package/dist/components/import/util.js +3 -0
  38. package/dist/components/import/util.js.map +1 -1
  39. package/dist/components/msa/MSACanvasBlock.js +4 -5
  40. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  41. package/dist/components/msa/msaRaster.d.ts +13 -3
  42. package/dist/components/msa/msaRaster.js +173 -61
  43. package/dist/components/msa/msaRaster.js.map +1 -1
  44. package/dist/components/msa/renderHighlights.d.ts +39 -1
  45. package/dist/components/msa/renderHighlights.js +71 -6
  46. package/dist/components/msa/renderHighlights.js.map +1 -1
  47. package/dist/components/msa/renderMSABlock.d.ts +1 -2
  48. package/dist/components/msa/renderMSABlock.js +24 -28
  49. package/dist/components/msa/renderMSABlock.js.map +1 -1
  50. package/dist/components/msa/renderMSAMouseover.js +9 -30
  51. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  52. package/dist/components/renderCtx.d.ts +1 -1
  53. package/dist/components/tracks/TrackBlocks.js +10 -11
  54. package/dist/components/tracks/TrackBlocks.js.map +1 -1
  55. package/dist/components/tracks/drawTracks.d.ts +26 -8
  56. package/dist/components/tracks/drawTracks.js +123 -13
  57. package/dist/components/tracks/drawTracks.js.map +1 -1
  58. package/dist/components/tree/TreeCanvas.js +2 -3
  59. package/dist/components/tree/TreeCanvas.js.map +1 -1
  60. package/dist/components/tree/TreeCanvasBlock.js +4 -2
  61. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  62. package/dist/components/tree/TreeRuler.js +13 -3
  63. package/dist/components/tree/TreeRuler.js.map +1 -1
  64. package/dist/components/tree/renderTreeCanvas.d.ts +0 -1
  65. package/dist/components/tree/renderTreeCanvas.js +70 -30
  66. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  67. package/dist/components/tree/scaleBar.d.ts +10 -0
  68. package/dist/components/tree/scaleBar.js +24 -0
  69. package/dist/components/tree/scaleBar.js.map +1 -0
  70. package/dist/constants.d.ts +3 -1
  71. package/dist/constants.js +18 -1
  72. package/dist/constants.js.map +1 -1
  73. package/dist/fetchUtils.d.ts +7 -7
  74. package/dist/fetchUtils.js +4 -32
  75. package/dist/fetchUtils.js.map +1 -1
  76. package/dist/hierarchy.d.ts +2 -1
  77. package/dist/hierarchy.js +16 -10
  78. package/dist/hierarchy.js.map +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +8 -2
  81. package/dist/index.js.map +1 -1
  82. package/dist/model/DataModel.js +5 -2
  83. package/dist/model/DataModel.js.map +1 -1
  84. package/dist/model.d.ts +454 -177
  85. package/dist/model.js +1180 -511
  86. package/dist/model.js.map +1 -1
  87. package/dist/renderToStaticMarkup.d.ts +11 -0
  88. package/dist/renderToStaticMarkup.js +30 -7
  89. package/dist/renderToStaticMarkup.js.map +1 -1
  90. package/dist/renderToSvg.js +25 -19
  91. package/dist/renderToSvg.js.map +1 -1
  92. package/dist/rowCoordinateCalculations.d.ts +25 -25
  93. package/dist/rowCoordinateCalculations.js +12 -36
  94. package/dist/rowCoordinateCalculations.js.map +1 -1
  95. package/dist/seqPosToGlobalCol.js +3 -1
  96. package/dist/seqPosToGlobalCol.js.map +1 -1
  97. package/dist/svgTestUtil.d.ts +144 -82
  98. package/dist/types.d.ts +97 -3
  99. package/dist/util.d.ts +11 -4
  100. package/dist/util.js +30 -10
  101. package/dist/util.js.map +1 -1
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/dist/wuss.d.ts +14 -0
  105. package/dist/wuss.js +55 -0
  106. package/dist/wuss.js.map +1 -0
  107. package/package.json +10 -8
  108. package/src/components/Loading.tsx +12 -2
  109. package/src/components/MSAViewer.tsx +106 -2
  110. package/src/components/ResizeHandles.tsx +31 -31
  111. package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
  112. package/src/components/dialogs/FeatureDialog.tsx +13 -9
  113. package/src/components/header/Header.tsx +4 -0
  114. package/src/components/header/HeaderStatusArea.tsx +0 -5
  115. package/src/components/header/LoadWarnings.tsx +49 -0
  116. package/src/components/header/MultiAlignmentSelector.tsx +0 -0
  117. package/src/components/header/TreeSettingsMenu.tsx +9 -1
  118. package/src/components/header/UnshareableDataWarning.tsx +58 -0
  119. package/src/components/header/getAnnotationsMenu.ts +16 -17
  120. package/src/components/import/ImportForm.tsx +2 -2
  121. package/src/components/import/ImportFormExamples.tsx +2 -6
  122. package/src/components/import/util.ts +3 -0
  123. package/src/components/msa/MSACanvasBlock.tsx +4 -5
  124. package/src/components/msa/msaRaster.ts +216 -59
  125. package/src/components/msa/renderHighlights.ts +103 -5
  126. package/src/components/msa/renderMSABlock.ts +25 -36
  127. package/src/components/msa/renderMSAMouseover.ts +9 -39
  128. package/src/components/renderCtx.ts +1 -0
  129. package/src/components/tracks/TrackBlocks.tsx +10 -13
  130. package/src/components/tracks/drawTracks.ts +165 -17
  131. package/src/components/tree/TreeCanvas.tsx +2 -3
  132. package/src/components/tree/TreeCanvasBlock.tsx +4 -2
  133. package/src/components/tree/TreeRuler.tsx +38 -3
  134. package/src/components/tree/renderTreeCanvas.ts +79 -35
  135. package/src/components/tree/scaleBar.ts +23 -0
  136. package/src/constants.ts +20 -1
  137. package/src/fetchUtils.ts +7 -40
  138. package/src/hierarchy.ts +20 -11
  139. package/src/index.ts +18 -2
  140. package/src/model/DataModel.ts +6 -2
  141. package/src/model.ts +1352 -616
  142. package/src/rawImports.d.ts +9 -0
  143. package/src/renderToStaticMarkup.ts +34 -7
  144. package/src/renderToSvg.tsx +33 -27
  145. package/src/rowCoordinateCalculations.ts +15 -59
  146. package/src/seqPosToGlobalCol.ts +3 -1
  147. package/src/types.ts +131 -4
  148. package/src/util.ts +31 -14
  149. package/src/version.ts +1 -1
  150. package/src/wuss.ts +62 -0
  151. package/dist/components/dialogs/InterProScanDialog.js +0 -137
  152. package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
  153. package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
  154. package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
  155. package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
  156. package/dist/launchInterProScan.d.ts +0 -13
  157. package/dist/launchInterProScan.js +0 -110
  158. package/dist/launchInterProScan.js.map +0 -1
  159. package/dist/useColorContrast.d.ts +0 -10
  160. package/dist/useColorContrast.js +0 -13
  161. package/dist/useColorContrast.js.map +0 -1
  162. package/src/clustalX.test.ts +0 -74
  163. package/src/colSpace.test.ts +0 -67
  164. package/src/collapseLogic.test.ts +0 -115
  165. package/src/colorSchemes.docs.test.ts +0 -57
  166. package/src/columnCounts.test.ts +0 -73
  167. package/src/columnStats.test.ts +0 -94
  168. package/src/columnTracks.test.ts +0 -97
  169. package/src/components/dialogs/InterProScanDialog.tsx +0 -214
  170. package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
  171. package/src/components/minimap/minimapLayout.test.ts +0 -71
  172. package/src/components/msa/msaRaster.test.ts +0 -145
  173. package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
  174. package/src/components/tree/renderTreeCanvas.test.ts +0 -296
  175. package/src/dataInitialized.test.ts +0 -42
  176. package/src/domainBands.test.ts +0 -122
  177. package/src/domainLetterColor.test.ts +0 -80
  178. package/src/exportFileName.test.ts +0 -40
  179. package/src/fetchUtils.test.ts +0 -83
  180. package/src/flatToTree.test.ts +0 -51
  181. package/src/hierarchy.test.ts +0 -228
  182. package/src/highlights.test.ts +0 -70
  183. package/src/impgRender.test.tsx +0 -68
  184. package/src/largeTree.test.ts +0 -67
  185. package/src/launchInterProScan.ts +0 -167
  186. package/src/loadErrorDisplay.test.tsx +0 -102
  187. package/src/modelFilehandleLoaders.test.ts +0 -137
  188. package/src/modelReset.test.ts +0 -120
  189. package/src/neighborJoining.test.ts +0 -164
  190. package/src/parseAsn1.test.ts +0 -36
  191. package/src/propertyConservation.test.ts +0 -36
  192. package/src/renderColumnTracksSvg.test.tsx +0 -108
  193. package/src/renderDomainsSvg.test.tsx +0 -118
  194. package/src/renderHighlightsSvg.test.tsx +0 -85
  195. package/src/renderMinimapSvg.test.tsx +0 -62
  196. package/src/renderRasterSvg.test.tsx +0 -144
  197. package/src/renderSequenceLogoSvg.test.tsx +0 -165
  198. package/src/renderToSvg.test.tsx +0 -65
  199. package/src/reset.test.ts +0 -61
  200. package/src/rowCoordinateCalculations.test.ts +0 -211
  201. package/src/rowSpace.test.ts +0 -46
  202. package/src/segmentOverlay.test.ts +0 -70
  203. package/src/seqPosToGlobalCol.test.ts +0 -59
  204. package/src/sequenceLogo.test.ts +0 -88
  205. package/src/setFontSize.test.ts +0 -33
  206. package/src/stripDefault.test.ts +0 -48
  207. package/src/stripDefaultSnapshot.test.ts +0 -87
  208. package/src/treeMetadata.test.ts +0 -39
  209. package/src/useCanvasAutorun.test.tsx +0 -98
  210. package/src/useColorContrast.ts +0 -18
  211. package/src/viewChrome.test.tsx +0 -134
  212. package/src/wheelZoom.test.ts +0 -46
package/dist/types.d.ts CHANGED
@@ -4,13 +4,14 @@ export interface Accession {
4
4
  name: string;
5
5
  description: string;
6
6
  }
7
- export type TrackKind = 'text' | 'bar' | 'logo';
7
+ export type TrackKind = 'text' | 'bar' | 'logo' | 'arc' | 'ruler';
8
8
  export interface BasicTrackModel {
9
9
  id: string;
10
10
  name: string;
11
11
  associatedRowName?: string;
12
12
  height: number;
13
13
  kind: TrackKind;
14
+ defaultOff?: boolean;
14
15
  }
15
16
  export interface TextTrackModel extends BasicTrackModel {
16
17
  customColorScheme?: Record<string, string>;
@@ -19,22 +20,115 @@ export interface TextTrackModel extends BasicTrackModel {
19
20
  export interface BarTrackModel extends BasicTrackModel {
20
21
  barColor?: string;
21
22
  }
23
+ export interface Arc {
24
+ start: number;
25
+ end: number;
26
+ color?: string;
27
+ }
28
+ export interface ArcTrackModel extends BasicTrackModel {
29
+ arcs?: Arc[];
30
+ arcColor?: string;
31
+ }
22
32
  export interface BasicTrack {
23
33
  ReactComponent: React.FC<any>;
24
- model: TextTrackModel & BarTrackModel;
34
+ model: TextTrackModel & BarTrackModel & ArcTrackModel;
35
+ }
36
+ export interface ArcSpec {
37
+ start: number;
38
+ end: number;
39
+ color?: string;
25
40
  }
26
41
  export interface ColumnTrackSpec {
27
42
  id: string;
28
43
  name: string;
29
- kind: 'bar' | 'text';
44
+ kind: 'bar' | 'text' | 'arc';
30
45
  values?: number[];
31
46
  data?: string;
47
+ arcs?: ArcSpec[];
32
48
  max?: number;
33
49
  color?: string;
34
50
  colors?: Record<string, string>;
35
51
  row?: string;
36
52
  height?: number;
37
53
  }
54
+ export interface ResidueSegment {
55
+ rowStart: number;
56
+ rowEnd: number;
57
+ structStart: number;
58
+ structEnd: number;
59
+ }
60
+ export interface MappedStructure {
61
+ id: string;
62
+ kind?: 'experimental' | 'predicted';
63
+ asymId?: string;
64
+ url?: string;
65
+ }
66
+ /**
67
+ * Which residue of which structure a row's residue is, as data. Computed by
68
+ * whatever knows how -- SIFTS, an AlphaFold model, a curator -- and carried in
69
+ * the snapshot, because the viewer cannot work it out: matching a row to a
70
+ * structure by sequence equality fails for a construct with an expression tag,
71
+ * a truncation, an engineered residue, or a row that is a subsequence of the
72
+ * entry, and it fails in the direction that looks like it worked.
73
+ *
74
+ * Positions are 1-based and inclusive on both sides, as GFF and `highlights`
75
+ * are. Structure positions are `label_seq_id`, the index into the entity's
76
+ * SEQRES; author numbering carries insertion codes and stays out.
77
+ *
78
+ * `unobserved` is in structure positions: present in SEQRES with no
79
+ * coordinates. Worth distinguishing from unmapped, because "the
80
+ * crystallographer could not see it" and "this protein does not have that
81
+ * residue" mean different things to a reader.
82
+ */
83
+ export interface ResidueMapping {
84
+ row: string;
85
+ accession?: string;
86
+ structure: MappedStructure;
87
+ segments: ResidueSegment[];
88
+ unobserved?: [number, number][];
89
+ /**
90
+ * ungapped length of the row this was computed against. Optional, and worth
91
+ * setting: a mapping outlives the alignment it was made for, and pointing at
92
+ * residue 58 of a sequence that has since been re-aligned, revised or swapped
93
+ * is the failure this whole layer exists to avoid. Declared here, the viewer
94
+ * can notice and refuse instead of answering from stale arithmetic.
95
+ */
96
+ rowLength?: number;
97
+ generated?: {
98
+ by?: string;
99
+ date?: string;
100
+ sourceSha256?: string;
101
+ };
102
+ }
103
+ export interface ResidueMappingProblem {
104
+ row: string;
105
+ structureId: string;
106
+ /**
107
+ * `mapping` means the whole mapping is out: the evidence is about the row it
108
+ * claims, so nothing it says can be trusted. `segment` takes only that
109
+ * segment, since the rest of the mapping still describes residues that exist.
110
+ */
111
+ scope: 'mapping' | 'segment';
112
+ reason: string;
113
+ }
114
+ export interface StructureResidue {
115
+ structure: MappedStructure;
116
+ position: number;
117
+ observed: boolean;
118
+ }
119
+ export interface RowResidue {
120
+ rowName: string;
121
+ seqPos: number;
122
+ }
123
+ /**
124
+ * One loaded document that the snapshot leaves behind, and how big it is.
125
+ * `what` names it the way the import form does, since that is where the reader
126
+ * would go to load it differently.
127
+ */
128
+ export interface UnshareableData {
129
+ what: 'alignment' | 'tree' | 'annotations' | 'row metadata' | 'data tracks';
130
+ bytes: number;
131
+ }
38
132
  export type { Annotation };
39
133
  export type TidyDomainAnnotation = Annotation;
40
134
  export interface DomainBand {
package/dist/util.d.ts CHANGED
@@ -3,9 +3,17 @@ export declare function adjustColorForContrast(color: string, bg: string): strin
3
3
  export declare function transform<T>(obj: Record<string, T>, cb: (arg0: [string, T]) => [string, T]): {
4
4
  [k: string]: T;
5
5
  };
6
- export declare function colorContrast(colorScheme: Record<string, string>, theme: Theme): {
7
- [k: string]: string;
8
- };
6
+ /**
7
+ * Readable letter color over a given cell color, memoized per theme.
8
+ *
9
+ * A dynamic scheme colors a cell from its column, so there is no letter->color
10
+ * table to precompute a contrast table from; asking per cell color covers the
11
+ * dynamic schemes, the static ones and a track's own `colors` alike. An
12
+ * uncolored cell sits on the theme's background, where the theme's own text
13
+ * color is what stays readable -- `black` turned every gap and every uncolored
14
+ * cell invisible in the dark theme.
15
+ */
16
+ export declare function contrastTextFn(theme: Theme): (color: string | undefined) => string;
9
17
  export declare function dropBlanks<T>(blanks: number[], arr: T[]): T[];
10
18
  export declare function skipBlanks(blanks: number[], str: string): string;
11
19
  export declare function computeRowInsertions(blanks: number[], seq: string): {
@@ -16,4 +24,3 @@ export declare function len(a: {
16
24
  end: number;
17
25
  start: number;
18
26
  }): number;
19
- export declare function isBlank(s?: string): s is "-" | ".";
package/dist/util.js CHANGED
@@ -26,11 +26,36 @@ export function adjustColorForContrast(color, bg) {
26
26
  export function transform(obj, cb) {
27
27
  return Object.fromEntries(Object.entries(obj).map(cb));
28
28
  }
29
- export function colorContrast(colorScheme, theme) {
30
- return transform(colorScheme, ([letter, color]) => [
31
- letter,
32
- theme.palette.getContrastText(colord(color).toHex()),
33
- ]);
29
+ const contrastTextCaches = new WeakMap();
30
+ /**
31
+ * Readable letter color over a given cell color, memoized per theme.
32
+ *
33
+ * A dynamic scheme colors a cell from its column, so there is no letter->color
34
+ * table to precompute a contrast table from; asking per cell color covers the
35
+ * dynamic schemes, the static ones and a track's own `colors` alike. An
36
+ * uncolored cell sits on the theme's background, where the theme's own text
37
+ * color is what stays readable -- `black` turned every gap and every uncolored
38
+ * cell invisible in the dark theme.
39
+ */
40
+ export function contrastTextFn(theme) {
41
+ let cache = contrastTextCaches.get(theme);
42
+ if (!cache) {
43
+ cache = new Map();
44
+ contrastTextCaches.set(theme, cache);
45
+ }
46
+ const fallback = theme.palette.text.primary;
47
+ return (color) => {
48
+ if (!color) {
49
+ return fallback;
50
+ }
51
+ const hit = cache.get(color);
52
+ if (hit !== undefined) {
53
+ return hit;
54
+ }
55
+ const out = theme.palette.getContrastText(colord(color).toHex());
56
+ cache.set(color, out);
57
+ return out;
58
+ };
34
59
  }
35
60
  export function dropBlanks(blanks, arr) {
36
61
  if (blanks.length === 0) {
@@ -95,9 +120,4 @@ export function computeRowInsertions(blanks, seq) {
95
120
  export function len(a) {
96
121
  return a.end - a.start;
97
122
  }
98
- // https://sonnhammer.sbc.su.se/Stockholm.html
99
- // gaps can be a . or - in stockholm
100
- export function isBlank(s) {
101
- return s === '-' || s === '.';
102
- }
103
123
  //# sourceMappingURL=util.js.map
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,UAAU,MAAM,qBAAqB,CAAA;AAC5C,OAAO,WAAW,MAAM,sBAAsB,CAAA;AAI9C,MAAM,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;AAEjC,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAA;AAErD,0EAA0E;AAC1E,uEAAuE;AACvE,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,EAAU;IAC9D,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,EAAE,EAAE,CAAA;IACjC,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAChD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACrB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,GAAG,CAAA;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACjD,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,CAAA;IACxB,mBAAmB,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACzC,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,GAAsB,EACtB,EAAsC;IAEtC,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAA8B,CAAA;AAEpE;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,IAAI,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACzC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,IAAI,GAAG,EAAE,CAAA;QACjB,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACtC,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAA;IAC3C,OAAO,CAAC,KAAyB,EAAE,EAAE;QACnC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,OAAO,GAAG,CAAA;QACZ,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;QAChE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACrB,OAAO,GAAG,CAAA;IACZ,CAAC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAI,MAAgB,EAAE,GAAQ;IACtD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAgB,EAAE,GAAW;IACtD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,EAAE,CAAA;IACjB,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;QAC9B,IAAI,QAAQ,GAAG,OAAO,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC3C,CAAC;QACD,OAAO,GAAG,QAAQ,GAAG,CAAC,CAAA;IACxB,CAAC;IACD,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAgB,EAAE,GAAW;IAChE,MAAM,UAAU,GAAuC,EAAE,CAAA;IACzD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAA;IAC/B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,gBAAgB,GAAG,CAAC,CAAC,CAAA;IACzB,IAAI,WAAW,GAAa,EAAE,CAAA;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,QAAQ,GAAG,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,oEAAoE;YACpE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC3C,IAAI,gBAAgB,KAAK,UAAU,EAAE,CAAC;oBACpC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAA;gBAC3B,CAAC;qBAAM,CAAC;oBACN,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3B,UAAU,CAAC,IAAI,CAAC;4BACd,GAAG,EAAE,gBAAgB;4BACrB,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;yBAC9B,CAAC,CAAA;oBACJ,CAAC;oBACD,gBAAgB,GAAG,UAAU,CAAA;oBAC7B,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAA;gBACzB,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,CAAA;QACZ,CAAC;aAAM,CAAC;YACN,UAAU,EAAE,CAAA;QACd,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAC3E,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAiC;IACnD,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAA;AACxB,CAAC"}
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.4.2";
1
+ export declare const version = "7.0.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '6.4.2';
1
+ export const version = '7.0.0';
2
2
  //# sourceMappingURL=version.js.map
package/dist/wuss.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface BasePair {
2
+ /** 0-based column */
3
+ start: number;
4
+ /** 0-based column */
5
+ end: number;
6
+ /** the pair crosses a helix rather than nesting inside one */
7
+ pseudoknot: boolean;
8
+ }
9
+ /**
10
+ * The base pairs a WUSS string encodes, as 0-based column indexes. Unmatched
11
+ * brackets are dropped rather than throwing: a hand-edited or truncated
12
+ * alignment should still draw the helices it does close.
13
+ */
14
+ export declare function parseWuss(ss: string): BasePair[];
package/dist/wuss.js ADDED
@@ -0,0 +1,55 @@
1
+ // WUSS notation (Rfam's `#=GC SS_cons`) names a consensus secondary structure
2
+ // by pairing columns. Nested helices use bracket pairs -- <>, (), [], {} --
3
+ // each type kept on its own stack, and a pseudoknot, which by definition
4
+ // crosses a helix it cannot nest inside, uses a letter pair instead: `A` opens
5
+ // and `a` closes, `B`/`b` for a second one. Everything else (. , _ - : ~) is
6
+ // unpaired.
7
+ const closeToOpen = {
8
+ '>': '<',
9
+ ')': '(',
10
+ ']': '[',
11
+ '}': '{',
12
+ };
13
+ const opens = new Set(Object.values(closeToOpen));
14
+ /**
15
+ * The base pairs a WUSS string encodes, as 0-based column indexes. Unmatched
16
+ * brackets are dropped rather than throwing: a hand-edited or truncated
17
+ * alignment should still draw the helices it does close.
18
+ */
19
+ export function parseWuss(ss) {
20
+ const stacks = new Map();
21
+ const pairs = [];
22
+ const push = (key, col) => {
23
+ const stack = stacks.get(key);
24
+ if (stack) {
25
+ stack.push(col);
26
+ }
27
+ else {
28
+ stacks.set(key, [col]);
29
+ }
30
+ };
31
+ const pop = (key, col, pseudoknot) => {
32
+ const start = stacks.get(key)?.pop();
33
+ if (start !== undefined) {
34
+ pairs.push({ start, end: col, pseudoknot });
35
+ }
36
+ };
37
+ for (let col = 0; col < ss.length; col++) {
38
+ const ch = ss[col];
39
+ const opener = closeToOpen[ch];
40
+ if (opens.has(ch)) {
41
+ push(ch, col);
42
+ }
43
+ else if (opener) {
44
+ pop(opener, col, false);
45
+ }
46
+ else if (ch >= 'A' && ch <= 'Z') {
47
+ push(ch, col);
48
+ }
49
+ else if (ch >= 'a' && ch <= 'z') {
50
+ pop(ch.toUpperCase(), col, true);
51
+ }
52
+ }
53
+ return pairs.sort((a, b) => a.start - b.start);
54
+ }
55
+ //# sourceMappingURL=wuss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wuss.js","sourceRoot":"","sources":["../src/wuss.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,YAAY;AAEZ,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;CACT,CAAA;AACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAA;AAWjD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAA;IAC1C,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,CAAA;IACD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,UAAmB,EAAE,EAAE;QAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAA;QACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC,CAAA;IAED,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAE,CAAA;QACnB,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA;QAC9B,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACf,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;QACzB,CAAC;aAAM,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACf,CAAC;aAAM,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;YAClC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;AAChD,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-msaview",
3
3
  "author": "Colin",
4
- "version": "6.4.2",
4
+ "version": "7.0.0",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "repository": {
@@ -19,17 +19,19 @@
19
19
  "files": [
20
20
  "dist",
21
21
  "bundle",
22
- "src"
22
+ "src",
23
+ "!src/**/*.test.ts",
24
+ "!src/**/*.test.tsx"
23
25
  ],
24
26
  "engines": {
25
- "node": ">=10"
27
+ "node": ">=18"
26
28
  },
27
29
  "peerDependencies": {
28
30
  "@jbrowse/core": ">=2.0.0",
29
- "@jbrowse/mobx-state-tree": "^6.0.0",
31
+ "@jbrowse/mobx-state-tree": ">=5.0.0",
30
32
  "@mui/icons-material": ">=5.0.0",
31
33
  "@mui/material": ">=5.0.0",
32
- "mobx": ">=7.0.0",
34
+ "mobx": ">=6.0.0",
33
35
  "mobx-react": ">=9.0.0",
34
36
  "react": ">=16.8.0",
35
37
  "react-dom": ">=16.8.0"
@@ -40,11 +42,11 @@
40
42
  "esbuild": "^0.28.1"
41
43
  },
42
44
  "dependencies": {
43
- "@gmod/newick": "^1.0.0",
44
- "@jbrowse/svgcanvas": "6.4.2",
45
+ "@gmod/newick": "^1.0.3",
46
+ "@jbrowse/svgcanvas": "7.0.0",
45
47
  "colord": "^2.9.3",
46
48
  "flatbush": "^4.6.2",
47
- "msa-parsers": "6.4.2"
49
+ "msa-parsers": "7.0.0"
48
50
  },
49
51
  "scripts": {
50
52
  "clean": "rimraf dist bundle",
@@ -83,13 +83,23 @@ const Reset = observer(function ({
83
83
  })
84
84
 
85
85
  const Loading = observer(function ({ model }: { model: MsaViewModel }) {
86
- const { isLoading, dataInitialized, error, msaFilehandle, treeFilehandle } =
87
- model
86
+ const {
87
+ isLoading,
88
+ dataInitialized,
89
+ error,
90
+ resetCount,
91
+ msaFilehandle,
92
+ treeFilehandle,
93
+ } = model
88
94
  const hasPendingFilehandle = !!(msaFilehandle || treeFilehandle)
89
95
 
90
96
  return (
91
97
  <div>
98
+ {/* keyed on the reset counter: the boundary holds the error it caught
99
+ until it is remounted, so without this "Return to import form" put
100
+ the model back and left the error screen up */}
92
101
  <ErrorBoundary
102
+ key={resetCount}
93
103
  FallbackComponent={e => <Reset model={model} error={e.error} />}
94
104
  >
95
105
  {dataInitialized ? (
@@ -1,13 +1,14 @@
1
- import React, { useEffect, useState } from 'react'
1
+ import React, { useEffect, useRef, useState } from 'react'
2
2
 
3
3
  import { createJBrowseTheme } from '@jbrowse/core/ui/theme'
4
4
  import useMeasure from '@jbrowse/core/util/useMeasure'
5
+ import { destroy, isAlive } from '@jbrowse/mobx-state-tree'
5
6
  import { ThemeProvider } from '@mui/material/styles'
6
7
 
7
8
  import MSAModelF from '../model.ts'
8
9
  import Loading from './Loading.tsx'
9
10
 
10
- import type { ColumnTrackSpec, Highlight } from '../types.ts'
11
+ import type { ColumnTrackSpec, Highlight, ResidueMapping } from '../types.ts'
11
12
  import type { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
12
13
 
13
14
  const theme = createJBrowseTheme()
@@ -25,6 +26,12 @@ interface MSAViewerProps {
25
26
  colWidth?: number
26
27
  /** initial per-row pixel height */
27
28
  rowHeight?: number
29
+ /**
30
+ * hide columns at least this percent gaps (default 100, i.e. hide nothing).
31
+ * A deep family's alignment is mostly insertions carried by a few members;
32
+ * dropping those columns is what makes the rest readable
33
+ */
34
+ allowedGappyness?: number
28
35
  /** alignment columns (0-based) to highlight with a persistent overlay */
29
36
  highlightColumns?: number[]
30
37
  /**
@@ -37,6 +44,8 @@ interface MSAViewerProps {
37
44
  relativeTo?: string
38
45
  /** tracks supplied as data: per-column bar values or a text row (see docs/layers.md) */
39
46
  columnTracks?: ColumnTrackSpec[]
47
+ /** which residue of which structure each row's residues are (see docs/layers.md) */
48
+ residueMappings?: ResidueMapping[]
40
49
  /** draw the phylogenetic tree (default true); false leaves a labels-only gutter */
41
50
  drawTree?: boolean
42
51
  /** fixed width (px) of the tree/label area */
@@ -56,10 +65,12 @@ export default function MSAViewer({
56
65
  height,
57
66
  colWidth,
58
67
  rowHeight,
68
+ allowedGappyness,
59
69
  highlightColumns,
60
70
  highlights,
61
71
  relativeTo,
62
72
  columnTracks,
73
+ residueMappings,
63
74
  drawTree,
64
75
  treeAreaWidth,
65
76
  autoTreeAreaWidth,
@@ -79,16 +90,22 @@ export default function MSAViewer({
79
90
  ...(height ? { height } : {}),
80
91
  ...(colWidth ? { colWidth } : {}),
81
92
  ...(rowHeight ? { rowHeight } : {}),
93
+ ...(allowedGappyness !== undefined ? { allowedGappyness } : {}),
82
94
  ...(highlightColumns ? { highlightColumns } : {}),
83
95
  ...(highlights ? { highlights } : {}),
84
96
  ...(relativeTo ? { relativeTo } : {}),
85
97
  ...(columnTracks ? { columnTracks } : {}),
98
+ ...(residueMappings ? { residueMappings } : {}),
86
99
  ...(drawTree !== undefined ? { drawTree } : {}),
87
100
  ...(treeAreaWidth ? { treeAreaWidth } : {}),
88
101
  ...(autoTreeAreaWidth ? { autoTreeAreaWidth } : {}),
89
102
  }),
90
103
  )
91
104
 
105
+ const destroyTimer = useRef<ReturnType<typeof setTimeout> | undefined>(
106
+ undefined,
107
+ )
108
+
92
109
  const [ref, { width }] = useMeasure()
93
110
  useEffect(() => {
94
111
  if (width) {
@@ -96,6 +113,93 @@ export default function MSAViewer({
96
113
  }
97
114
  }, [model, width])
98
115
 
116
+ // The props below stay live after mount: change one and it drives the model,
117
+ // so a host can put a control on the viewer -- an expand button, a diff
118
+ // toggle, a color-scheme picker -- without remounting it and re-fetching its
119
+ // alignment. Each effect depends only on its own prop, so a change the user
120
+ // makes inside the viewer (picking a scheme from the menu, dragging a row
121
+ // taller) survives the host's next render rather than being snapped back.
122
+ // Data props are not among them: new msa/tree/gff is a different alignment,
123
+ // which is a new model, which React spells `key`.
124
+ useEffect(() => {
125
+ if (height !== undefined) {
126
+ model.setHeight(height)
127
+ }
128
+ }, [model, height])
129
+ useEffect(() => {
130
+ if (colorScheme !== undefined) {
131
+ model.setColorSchemeName(colorScheme)
132
+ }
133
+ }, [model, colorScheme])
134
+ useEffect(() => {
135
+ if (colWidth !== undefined) {
136
+ model.setColWidth(colWidth)
137
+ }
138
+ }, [model, colWidth])
139
+ useEffect(() => {
140
+ if (rowHeight !== undefined) {
141
+ model.setRowHeight(rowHeight)
142
+ }
143
+ }, [model, rowHeight])
144
+ useEffect(() => {
145
+ if (allowedGappyness !== undefined) {
146
+ model.setAllowedGappyness(allowedGappyness)
147
+ }
148
+ }, [model, allowedGappyness])
149
+ useEffect(() => {
150
+ if (drawTree !== undefined) {
151
+ model.setDrawTree(drawTree)
152
+ }
153
+ }, [model, drawTree])
154
+ useEffect(() => {
155
+ if (treeAreaWidth !== undefined) {
156
+ model.setTreeAreaWidth(treeAreaWidth)
157
+ }
158
+ }, [model, treeAreaWidth])
159
+ // unguarded: dropping the prop is how a host turns the reference diff back off
160
+ useEffect(() => {
161
+ model.drawRelativeTo(relativeTo)
162
+ }, [model, relativeTo])
163
+
164
+ // the data layers, keyed by content: a host that computes one inline hands a
165
+ // new array on every render, and replacing the model's copy each time would
166
+ // redraw the overlay for nothing
167
+ const highlightsKey = JSON.stringify(highlights ?? [])
168
+ useEffect(() => {
169
+ model.setHighlights(JSON.parse(highlightsKey))
170
+ }, [model, highlightsKey])
171
+ const columnTracksKey = JSON.stringify(columnTracks ?? [])
172
+ useEffect(() => {
173
+ model.setColumnTracks(JSON.parse(columnTracksKey))
174
+ }, [model, columnTracksKey])
175
+ const residueMappingsKey = JSON.stringify(residueMappings ?? [])
176
+ useEffect(() => {
177
+ model.setResidueMappings(JSON.parse(residueMappingsKey))
178
+ }, [model, residueMappingsKey])
179
+ const highlightColumnsKey = JSON.stringify(highlightColumns ?? null)
180
+ useEffect(() => {
181
+ model.setHighlightedColumns(JSON.parse(highlightColumnsKey) ?? undefined)
182
+ }, [model, highlightColumnsKey])
183
+
184
+ // the model owns a matchMedia listener and whatever fetches its filehandles
185
+ // started, so an unmounted viewer that keeps its model keeps those too. The
186
+ // destroy is deferred by a tick because React's StrictMode mounts, unmounts
187
+ // and remounts with the same state: the remount's effect cancels it
188
+ useEffect(() => {
189
+ if (destroyTimer.current !== undefined) {
190
+ clearTimeout(destroyTimer.current)
191
+ destroyTimer.current = undefined
192
+ }
193
+ return () => {
194
+ destroyTimer.current = setTimeout(() => {
195
+ destroyTimer.current = undefined
196
+ if (isAlive(model)) {
197
+ destroy(model)
198
+ }
199
+ })
200
+ }
201
+ }, [model])
202
+
99
203
  return (
100
204
  <ThemeProvider theme={theme}>
101
205
  <div ref={ref}>
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react'
5
5
  import DragHandle from './DragHandle.tsx'
6
6
 
7
7
  import type { MsaViewModel } from '../model.ts'
8
- import type { TrackKind } from '../types.ts'
8
+ import type { BasicTrack, TrackKind } from '../types.ts'
9
9
 
10
10
  export const VerticalResizeHandle = observer(function ({
11
11
  model,
@@ -51,53 +51,53 @@ export const HorizontalResizeHandle = observer(function ({
51
51
  )
52
52
  })
53
53
 
54
- // The height behind each resizable track kind. Both bar tracks read one height
55
- // so conservation and property conservation stay directly comparable; the logo
56
- // keeps its own, being taller by default. Text tracks are absent: they are one
57
- // alignment row tall and follow rowHeight, so the zoom controls already size
58
- // them.
59
- const trackHeights: Partial<
60
- Record<
61
- TrackKind,
62
- {
63
- get: (model: MsaViewModel) => number
64
- set: (model: MsaViewModel, height: number) => void
65
- }
66
- >
54
+ // The volatile behind each resizable kind of computed track. Both bar tracks
55
+ // write one height so conservation and property conservation stay directly
56
+ // comparable; the logo keeps its own, being taller by default. Text tracks are
57
+ // absent: they are one alignment row tall and follow rowHeight, so the zoom
58
+ // controls already size them.
59
+ const setTrackHeight: Partial<
60
+ Record<TrackKind, (model: MsaViewModel, height: number) => void>
67
61
  > = {
68
- bar: {
69
- get: model => model.conservationTrackHeight,
70
- set: (model, height) => {
71
- model.setConservationTrackHeight(height)
72
- },
62
+ bar: (model, height) => {
63
+ model.setConservationTrackHeight(height)
73
64
  },
74
- logo: {
75
- get: model => model.sequenceLogoTrackHeight,
76
- set: (model, height) => {
77
- model.setSequenceLogoTrackHeight(height)
78
- },
65
+ logo: (model, height) => {
66
+ model.setSequenceLogoTrackHeight(height)
67
+ },
68
+ arc: (model, height) => {
69
+ model.setArcTrackHeight(height)
79
70
  },
80
71
  }
81
72
 
82
73
  export const TrackResizeHandle = observer(function ({
83
74
  model,
84
- kind,
75
+ track,
85
76
  }: {
86
77
  model: MsaViewModel
87
- kind: TrackKind
78
+ track: BasicTrack
88
79
  }) {
89
- const height = trackHeights[kind]
80
+ const { id, kind, height } = track.model
81
+ const setHeight = setTrackHeight[kind]
82
+ // a data track carries its own height, so its handle resizes that track --
83
+ // dragging one used to resize every track of its kind instead
84
+ const ownHeight = model.columnTracks.some(t => t.id === id)
90
85
  const onDrag = useCallback(
91
86
  (delta: number, startHeight: number) => {
92
- height?.set(model, Math.max(10, startHeight + delta))
87
+ const next = Math.max(10, startHeight + delta)
88
+ if (ownHeight) {
89
+ model.setColumnTrackHeight(id, next)
90
+ } else {
91
+ setTrackHeight[kind]?.(model, next)
92
+ }
93
93
  },
94
- [model, height],
94
+ [model, id, kind, ownHeight],
95
95
  )
96
- return height ? (
96
+ return setHeight ? (
97
97
  <DragHandle
98
98
  axis="y"
99
99
  variant="resizer"
100
- getStart={() => height.get(model)}
100
+ getStart={() => height}
101
101
  onDrag={onDrag}
102
102
  style={{
103
103
  position: 'absolute',