react-msaview 8.3.0 → 8.4.1

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 (125) hide show
  1. package/bundle/index.js +499 -295
  2. package/bundle/index.js.map +4 -4
  3. package/dist/blockFasta.d.ts +6 -0
  4. package/dist/blockFasta.js +12 -0
  5. package/dist/blockFasta.js.map +1 -0
  6. package/dist/colorSchemes.d.ts +7 -0
  7. package/dist/colorSchemes.js +15 -0
  8. package/dist/colorSchemes.js.map +1 -1
  9. package/dist/components/MSAView.js +15 -9
  10. package/dist/components/MSAView.js.map +1 -1
  11. package/dist/components/MSAViewer.d.ts +28 -7
  12. package/dist/components/MSAViewer.js +61 -22
  13. package/dist/components/MSAViewer.js.map +1 -1
  14. package/dist/components/MetadataTable.d.ts +5 -0
  15. package/dist/components/MetadataTable.js +29 -0
  16. package/dist/components/MetadataTable.js.map +1 -0
  17. package/dist/components/Track.js +11 -2
  18. package/dist/components/Track.js.map +1 -1
  19. package/dist/components/dialogs/MetadataDialog.js +5 -6
  20. package/dist/components/dialogs/MetadataDialog.js.map +1 -1
  21. package/dist/components/header/ColorSchemeMenu.d.ts +6 -0
  22. package/dist/components/header/ColorSchemeMenu.js +23 -5
  23. package/dist/components/header/ColorSchemeMenu.js.map +1 -1
  24. package/dist/components/header/GoToBox.d.ts +338 -0
  25. package/dist/components/header/GoToBox.js +31 -0
  26. package/dist/components/header/GoToBox.js.map +1 -0
  27. package/dist/components/header/Header.js +4 -2
  28. package/dist/components/header/Header.js.map +1 -1
  29. package/dist/components/header/SelectionMenu.d.ts +12 -0
  30. package/dist/components/header/SelectionMenu.js +72 -0
  31. package/dist/components/header/SelectionMenu.js.map +1 -0
  32. package/dist/components/header/goTo.d.ts +20 -0
  33. package/dist/components/header/goTo.js +69 -0
  34. package/dist/components/header/goTo.js.map +1 -0
  35. package/dist/components/msa/MSACanvas.js +13 -2
  36. package/dist/components/msa/MSACanvas.js.map +1 -1
  37. package/dist/components/msa/MSACanvasBlock.js +5 -1
  38. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  39. package/dist/components/msa/msaKeys.js +6 -0
  40. package/dist/components/msa/msaKeys.js.map +1 -1
  41. package/dist/components/msa/msaRaster.js +1 -0
  42. package/dist/components/msa/msaRaster.js.map +1 -1
  43. package/dist/components/msa/renderHighlights.d.ts +14 -3
  44. package/dist/components/msa/renderHighlights.js +29 -4
  45. package/dist/components/msa/renderHighlights.js.map +1 -1
  46. package/dist/components/msa/tileColor.js +9 -8
  47. package/dist/components/msa/tileColor.js.map +1 -1
  48. package/dist/components/msa/useMsaBlockMouse.d.ts +1 -1
  49. package/dist/components/msa/useMsaBlockMouse.js +18 -11
  50. package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
  51. package/dist/components/overlayColors.d.ts +2 -0
  52. package/dist/components/overlayColors.js +3 -0
  53. package/dist/components/overlayColors.js.map +1 -1
  54. package/dist/components/selectionDrag.d.ts +17 -0
  55. package/dist/components/selectionDrag.js +30 -0
  56. package/dist/components/selectionDrag.js.map +1 -0
  57. package/dist/components/tracks/useTrackHover.d.ts +3 -1
  58. package/dist/components/tracks/useTrackHover.js +26 -6
  59. package/dist/components/tracks/useTrackHover.js.map +1 -1
  60. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +9 -8
  61. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  62. package/dist/constants.d.ts +1 -1
  63. package/dist/constants.js +6 -6
  64. package/dist/constants.js.map +1 -1
  65. package/dist/element.d.ts +7 -3
  66. package/dist/element.js +32 -4
  67. package/dist/element.js.map +1 -1
  68. package/dist/featuresLayer.d.ts +8 -0
  69. package/dist/featuresLayer.js +42 -0
  70. package/dist/featuresLayer.js.map +1 -0
  71. package/dist/index.d.ts +1 -1
  72. package/dist/model/DataModel.d.ts +1 -1
  73. package/dist/model/DataModel.js +3 -3
  74. package/dist/model/DataModel.js.map +1 -1
  75. package/dist/model/msaModel.d.ts +14 -1
  76. package/dist/model/msaModel.js +17 -1
  77. package/dist/model/msaModel.js.map +1 -1
  78. package/dist/model.d.ts +242 -187
  79. package/dist/model.js +264 -45
  80. package/dist/model.js.map +1 -1
  81. package/dist/svgTestUtil.d.ts +284 -336
  82. package/dist/types.d.ts +50 -0
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +1 -1
  85. package/package.json +6 -6
  86. package/src/blockFasta.ts +18 -0
  87. package/src/colorSchemes.ts +20 -0
  88. package/src/components/MSAView.tsx +16 -9
  89. package/src/components/MSAViewer.tsx +95 -26
  90. package/src/components/MetadataTable.tsx +55 -0
  91. package/src/components/Track.tsx +14 -1
  92. package/src/components/dialogs/MetadataDialog.tsx +9 -8
  93. package/src/components/header/ColorSchemeMenu.tsx +31 -12
  94. package/src/components/header/GoToBox.tsx +64 -0
  95. package/src/components/header/Header.tsx +6 -2
  96. package/src/components/header/SelectionMenu.tsx +117 -0
  97. package/src/components/header/goTo.ts +75 -0
  98. package/src/components/msa/MSACanvas.tsx +12 -2
  99. package/src/components/msa/MSACanvasBlock.tsx +5 -1
  100. package/src/components/msa/msaKeys.ts +6 -0
  101. package/src/components/msa/msaRaster.ts +1 -0
  102. package/src/components/msa/renderHighlights.ts +46 -4
  103. package/src/components/msa/tileColor.ts +9 -8
  104. package/src/components/msa/useMsaBlockMouse.ts +24 -27
  105. package/src/components/overlayColors.ts +4 -0
  106. package/src/components/selectionDrag.ts +42 -0
  107. package/src/components/tracks/useTrackHover.ts +28 -6
  108. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +14 -16
  109. package/src/constants.ts +6 -6
  110. package/src/element.ts +45 -5
  111. package/src/featuresLayer.ts +48 -0
  112. package/src/index.ts +5 -0
  113. package/src/model/DataModel.ts +3 -3
  114. package/src/model/msaModel.ts +19 -1
  115. package/src/model.ts +313 -55
  116. package/src/types.ts +58 -0
  117. package/src/version.ts +1 -1
  118. package/dist/components/header/RowSearch.d.ts +0 -6
  119. package/dist/components/header/RowSearch.js +0 -15
  120. package/dist/components/header/RowSearch.js.map +0 -1
  121. package/dist/components/header/revealRow.d.ts +0 -3
  122. package/dist/components/header/revealRow.js +0 -15
  123. package/dist/components/header/revealRow.js.map +0 -1
  124. package/src/components/header/RowSearch.tsx +0 -34
  125. package/src/components/header/revealRow.ts +0 -17
@@ -1,11 +1,10 @@
1
1
  import React from 'react'
2
2
 
3
- import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes'
4
- import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard'
5
3
  import { Dialog } from '@jbrowse/core/ui'
6
- import { DialogContent } from '@mui/material'
4
+ import { DialogContent, Typography } from '@mui/material'
7
5
  import { observer } from 'mobx-react'
8
6
 
7
+ import MetadataTable from '../../MetadataTable.tsx'
9
8
  import SequenceTextArea from '../../SequenceTextArea.tsx'
10
9
 
11
10
  import type { MsaViewModel } from '../../../model.ts'
@@ -34,20 +33,19 @@ const TreeNodeInfoDialog = observer(function ({
34
33
  maxWidth="xl"
35
34
  >
36
35
  <DialogContent>
37
- <BaseCard title="Attributes">
38
- <Attributes attributes={{ nodeName, ...info }} />
39
- </BaseCard>
40
- <BaseCard title="Sequence">
41
- {res ? (
42
- <SequenceTextArea str={[res]} />
43
- ) : (
44
- <div>Sequence not found</div>
45
- )}
46
- </BaseCard>
36
+ <Typography variant="h6">Attributes</Typography>
37
+ <MetadataTable record={{ nodeName, ...info }} />
38
+ <Typography variant="h6">Sequence</Typography>
39
+ {res ? (
40
+ <SequenceTextArea str={[res]} />
41
+ ) : (
42
+ <Typography>Sequence not found</Typography>
43
+ )}
47
44
  {metadata ? (
48
- <BaseCard title="Extra metadata">
49
- <Attributes attributes={metadata} />
50
- </BaseCard>
45
+ <>
46
+ <Typography variant="h6">Extra metadata</Typography>
47
+ <MetadataTable record={metadata} />
48
+ </>
51
49
  ) : null}
52
50
  </DialogContent>
53
51
  </Dialog>
package/src/constants.ts CHANGED
@@ -106,12 +106,12 @@ export const rowTintAlpha = 0.25
106
106
  export const cladeHighlightColor = '#fff3c4'
107
107
  export const cladeHighlightAlpha = 0.6
108
108
 
109
- // The largest inline document the snapshot carries. A larger pasted or
110
- // locally-opened file stays in the live model and out of the snapshot, and
111
- // `unshareableData` warns using the same number. The demo app gzips the
112
- // snapshot into `?data=`, where 15 kB of the hosted protein alignments encodes
113
- // to 6,300-7,600 characters, under the 8,192 gmod.org accepts.
114
- export const maxInlineSnapshotBytes = 15_000
109
+ // The largest inline document a snapshot carries by default, which keeps a
110
+ // jbrowse session small. A larger pasted or locally-opened file stays in the
111
+ // live model and out of the snapshot, and `unshareableData` warns using the
112
+ // same number. `MSAModelF({ maxInlineSnapshotBytes })` sets another; the demo
113
+ // app's links hold far more.
114
+ export const maxInlineSnapshotBytes = 50_000
115
115
 
116
116
  // Height of the band the `rowPanels` headers draw in, above the strips in the
117
117
  // top area beside the tree ruler and the minimap. A panel wider than the band
package/src/element.ts CHANGED
@@ -7,15 +7,26 @@ import type { MsaViewModel } from './model.ts'
7
7
  import type { MountedViewer } from './mount.tsx'
8
8
  import type {
9
9
  Cell,
10
+ ColorScheme,
10
11
  ColumnTrackSpec,
12
+ Feature,
11
13
  Highlight,
14
+ MsaSelection,
12
15
  ResidueMapping,
13
16
  Viewport,
14
17
  } from './types.ts'
15
18
 
16
19
  type ElementData = Pick<
17
20
  MSAViewerProps,
18
- 'msa' | 'tree' | 'gff' | 'highlights' | 'columnTracks' | 'residueMappings'
21
+ | 'msa'
22
+ | 'tree'
23
+ | 'gff'
24
+ | 'features'
25
+ | 'colorScheme'
26
+ | 'highlights'
27
+ | 'columnTracks'
28
+ | 'residueMappings'
29
+ | 'selection'
19
30
  >
20
31
 
21
32
  interface NightingaleManager extends HTMLElement {
@@ -78,9 +89,13 @@ function residueRange(model: MsaViewModel, row: string, viewport: Viewport) {
78
89
  /**
79
90
  * Registers a custom element that renders MSAViewer, for pages with no React.
80
91
  * Attributes: msa-url, tree-url, gff-url, color-scheme, height, hide-header,
81
- * theme, tree-area-width and reference-row. Properties: msa, tree and gff text, highlights,
82
- * columnTracks and residueMappings. Events: cell-hover, cell-click and
83
- * viewport-change, each with the MSAViewer callback's value as detail.
92
+ * theme, tree-area-width and reference-row. Properties: msa, tree and gff text,
93
+ * features, colorScheme, highlights, columnTracks, residueMappings and
94
+ * selection. The
95
+ * colorScheme property takes a `{map}` the color-scheme attribute cannot hold,
96
+ * and wins over the attribute while set. Events: cell-hover, cell-click,
97
+ * viewport-change and selection-change, each with the MSAViewer callback's
98
+ * value as detail.
84
99
  *
85
100
  * Inside a <nightingale-manager>, the element registers with it and speaks its
86
101
  * protocol: it follows the display-start, display-end and highlight attributes
@@ -122,6 +137,18 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
122
137
  set gff(value: string | undefined) {
123
138
  this.#setData({ gff: value })
124
139
  }
140
+ get features() {
141
+ return this.#data.features
142
+ }
143
+ set features(value: Feature[] | undefined) {
144
+ this.#setData({ features: value })
145
+ }
146
+ get colorScheme() {
147
+ return this.#data.colorScheme
148
+ }
149
+ set colorScheme(value: ColorScheme | undefined) {
150
+ this.#setData({ colorScheme: value })
151
+ }
125
152
  get highlights() {
126
153
  return this.#data.highlights
127
154
  }
@@ -140,6 +167,13 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
140
167
  set residueMappings(value: ResidueMapping[] | undefined) {
141
168
  this.#setData({ residueMappings: value })
142
169
  }
170
+ // the viewer's selection, which the reader's drags change
171
+ get selection() {
172
+ return this.#model ? this.#model.selection : this.#data.selection
173
+ }
174
+ set selection(value: MsaSelection | undefined) {
175
+ this.#setData({ selection: value })
176
+ }
143
177
 
144
178
  get #referenceRow() {
145
179
  return this.getAttribute('reference-row') ?? undefined
@@ -157,7 +191,10 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
157
191
  msaFilehandle: location(this.getAttribute('msa-url')),
158
192
  treeFilehandle: location(this.getAttribute('tree-url')),
159
193
  gffFilehandle: location(this.getAttribute('gff-url')),
160
- colorScheme: this.getAttribute('color-scheme') ?? undefined,
194
+ colorScheme:
195
+ this.#data.colorScheme ??
196
+ this.getAttribute('color-scheme') ??
197
+ undefined,
161
198
  height: numberAttribute(this.getAttribute('height')),
162
199
  treeAreaWidth: numberAttribute(this.getAttribute('tree-area-width')),
163
200
  hideHeader: this.hasAttribute('hide-header'),
@@ -173,6 +210,9 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
173
210
  this.#emit('viewport-change', viewport)
174
211
  this.#reportRange(viewport)
175
212
  },
213
+ onSelectionChange: selection => {
214
+ this.#emit('selection-change', selection)
215
+ },
176
216
  onModel: model => {
177
217
  this.#model = model
178
218
  this.#followRange()
@@ -0,0 +1,48 @@
1
+ import type { Annotation, Feature } from './types.ts'
2
+
3
+ const placement = new Set(['row', 'start', 'end'])
4
+
5
+ // The colors and labels are maps keyed by annotation, and a getter read
6
+ // outside a reaction recomputes on every read. Caching on the frozen feature
7
+ // gives it one annotation however often the layer converts.
8
+ const converted = new WeakMap<Feature, Annotation>()
9
+
10
+ /**
11
+ * The `features` layer as the annotations a GFF would parse to. Every field
12
+ * but the placement is also an attribute, as a string like a GFF value, so an
13
+ * encoding reads `type` or a host's own field the way it reads a GFF column 9
14
+ * key.
15
+ */
16
+ export function featuresToAnnotations(features: Feature[]): Annotation[] {
17
+ return features.map(feature => {
18
+ const cached = converted.get(feature)
19
+ if (cached) {
20
+ return cached
21
+ }
22
+ const annotation = featureAnnotation(feature)
23
+ converted.set(feature, annotation)
24
+ return annotation
25
+ })
26
+ }
27
+
28
+ function featureAnnotation(feature: Feature): Annotation {
29
+ const { row, start, end, name, description, type, strand, color } = feature
30
+ const accession = name ?? `${row}:${start}-${end}`
31
+ const attributes = Object.fromEntries(
32
+ Object.entries(feature)
33
+ .filter(([key, value]) => !placement.has(key) && value !== undefined)
34
+ .map(([key, value]) => [key, String(value)]),
35
+ )
36
+ return {
37
+ id: row,
38
+ accession,
39
+ name: name ?? accession,
40
+ description: description ?? name ?? accession,
41
+ featureType: type,
42
+ start,
43
+ end,
44
+ strand: strand === '+' ? 1 : strand === '-' ? -1 : undefined,
45
+ color,
46
+ attributes,
47
+ }
48
+ }
package/src/index.ts CHANGED
@@ -60,13 +60,16 @@ export type {
60
60
  Cell,
61
61
  Clade,
62
62
  CladeMark,
63
+ ColorScheme,
63
64
  ColumnTrackSpec,
64
65
  DomainBand,
65
66
  Encoding,
66
67
  EncodingChannel,
68
+ Feature,
67
69
  Highlight,
68
70
  Legend,
69
71
  LegendEntry,
72
+ MsaSelection,
70
73
  Node,
71
74
  MappedStructure,
72
75
  NodeWithIds,
@@ -80,6 +83,8 @@ export type {
80
83
  ResolvedEncoding,
81
84
  ResolvedHighlight,
82
85
  ResolvedRowPanel,
86
+ ResolvedSelection,
87
+ RowDataInput,
83
88
  RowPanelSpec,
84
89
  RowResidue,
85
90
  StructureResidue,
@@ -9,7 +9,7 @@ import { maxInlineSnapshotBytes } from '../constants.ts'
9
9
  * data will not be persisted in saved session snapshots, it will be fetched
10
10
  * from msaFilehandle at startup
11
11
  */
12
- export function DataModelF() {
12
+ export function DataModelF(maxInlineBytes = maxInlineSnapshotBytes) {
13
13
  return types
14
14
  .model({
15
15
  /**
@@ -56,12 +56,12 @@ export function DataModelF() {
56
56
  },
57
57
  }))
58
58
  .postProcessSnapshot(snap =>
59
- // drops any field over maxInlineSnapshotBytes; the parent model's
59
+ // drops any field over maxInlineBytes; the parent model's
60
60
  // `unshareableData` reports what was dropped
61
61
  Object.fromEntries(
62
62
  Object.entries(snap).map(([key, text]) => [
63
63
  key,
64
- text && text.length > maxInlineSnapshotBytes ? undefined : text,
64
+ text && text.length > maxInlineBytes ? undefined : text,
65
65
  ]),
66
66
  ),
67
67
  )
@@ -29,6 +29,13 @@ export function MSAModelF() {
29
29
  */
30
30
  colorSchemeName: stripDefault(types.string, defaultColorSchemeName),
31
31
 
32
+ /**
33
+ * #property
34
+ * a color per residue letter, which replaces the `colorSchemeName` table
35
+ * while set. A letter the map leaves out takes no color
36
+ */
37
+ customColorScheme: types.frozen<Record<string, string> | undefined>(),
38
+
32
39
  /**
33
40
  * #property
34
41
  * show a tooltip with the hovered column's value for a track while
@@ -49,10 +56,21 @@ export function MSAModelF() {
49
56
  .actions(self => ({
50
57
  /**
51
58
  * #action
52
- * set color scheme name
59
+ * pick a scheme from the built-in table, which clears
60
+ * `customColorScheme`
53
61
  */
54
62
  setColorSchemeName(name: string) {
55
63
  self.colorSchemeName = name
64
+ self.customColorScheme = undefined
65
+ },
66
+
67
+ /**
68
+ * #action
69
+ * color residues from a map of letter to color, or pass undefined to
70
+ * return to `colorSchemeName`
71
+ */
72
+ setCustomColorScheme(map?: Record<string, string>) {
73
+ self.customColorScheme = map
56
74
  },
57
75
 
58
76
  /**