@jbrowse/core 2.11.1 → 2.12.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 (64) hide show
  1. package/BaseFeatureWidget/BaseFeatureDetail/DataGridDetails.js +17 -26
  2. package/BaseFeatureWidget/BaseFeatureDetail/index.js +1 -3
  3. package/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.js +24 -85
  4. package/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.js +2 -2
  5. package/BaseFeatureWidget/SequenceFeatureDetails/SequencePanel.d.ts +3 -4
  6. package/BaseFeatureWidget/SequenceFeatureDetails/SequencePanel.js +55 -24
  7. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.d.ts +9 -0
  8. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.js +69 -0
  9. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceFeatureMenu.d.ts +9 -0
  10. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceFeatureMenu.js +126 -0
  11. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.d.ts +6 -0
  12. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.js +68 -0
  13. package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SettingsDialog.js +19 -10
  14. package/BaseFeatureWidget/SequenceFeatureDetails/model.d.ts +47 -0
  15. package/BaseFeatureWidget/SequenceFeatureDetails/model.js +83 -9
  16. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDNASequence.d.ts +3 -1
  17. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDNASequence.js +76 -19
  18. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDSSequence.d.ts +5 -2
  19. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDSSequence.js +12 -3
  20. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/GenomicSequence.d.ts +7 -2
  21. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/GenomicSequence.js +51 -5
  22. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/ProteinSequence.d.ts +5 -2
  23. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/ProteinSequence.js +12 -3
  24. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/SequenceDisplay.d.ts +11 -0
  25. package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/SequenceDisplay.js +30 -0
  26. package/BaseFeatureWidget/SequenceFeatureDetails/util.d.ts +11 -0
  27. package/BaseFeatureWidget/SequenceFeatureDetails/util.js +43 -1
  28. package/BaseFeatureWidget/stateModelFactory.d.ts +32 -2
  29. package/PluginManager.d.ts +2 -11
  30. package/ReExports/modules.d.ts +2 -11
  31. package/configuration/util.js +4 -11
  32. package/package.json +5 -3
  33. package/pluggableElementTypes/models/BaseDisplayModel.d.ts +3 -3
  34. package/pluggableElementTypes/models/BaseDisplayModel.js +3 -3
  35. package/pluggableElementTypes/renderers/util/serializableFilterChain.js +4 -1
  36. package/rpc/methods/util.d.ts +3 -2
  37. package/rpc/methods/util.js +0 -7
  38. package/stories/JBrowseCore.stories.d.ts +5 -0
  39. package/stories/JBrowseCore.stories.js +10 -0
  40. package/stories/examples/WithSequencePanel.d.ts +7 -0
  41. package/stories/examples/WithSequencePanel.js +43 -0
  42. package/stories/examples/index.d.ts +1 -0
  43. package/stories/examples/index.js +17 -0
  44. package/stories/examples/util.d.ts +33 -0
  45. package/stories/examples/util.js +235 -0
  46. package/tsconfig.build.tsbuildinfo +1 -1
  47. package/ui/Dialog.js +2 -1
  48. package/ui/ErrorMessageStackTraceDialog.js +13 -8
  49. package/util/Base1DUtils.d.ts +1 -1
  50. package/util/Base1DUtils.js +3 -7
  51. package/util/Base1DViewModel.d.ts +5 -16
  52. package/util/Base1DViewModel.js +6 -12
  53. package/util/blockTypes.d.ts +4 -0
  54. package/util/blockTypes.js +14 -3
  55. package/util/calculateDynamicBlocks.js +2 -3
  56. package/util/index.d.ts +1 -1
  57. package/util/range.d.ts +1 -1
  58. package/util/tracks.d.ts +3 -2
  59. package/util/tracks.js +10 -6
  60. package/util/types/index.d.ts +4 -1
  61. package/ui/ResizeBar.d.ts +0 -7
  62. package/ui/ResizeBar.js +0 -80
  63. package/ui/useResizeBar.d.ts +0 -5
  64. package/ui/useResizeBar.js +0 -22
@@ -32,14 +32,11 @@ const x_data_grid_1 = require("@mui/x-data-grid");
32
32
  const material_1 = require("@mui/material");
33
33
  // locals
34
34
  const util_1 = require("../../util");
35
- const ResizeBar_1 = __importDefault(require("../../ui/ResizeBar"));
36
35
  const FieldName_1 = __importDefault(require("./FieldName"));
37
- const useResizeBar_1 = require("../../ui/useResizeBar");
38
36
  const ui_1 = require("../../ui");
39
37
  const useStyles = (0, mui_1.makeStyles)()(theme => ({
40
38
  margin: {
41
- margin: theme.spacing(1),
42
- width: '100%',
39
+ marginBottom: theme.spacing(4),
43
40
  },
44
41
  cell: {
45
42
  whiteSpace: 'nowrap',
@@ -49,7 +46,6 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
49
46
  }));
50
47
  function DataGridDetails({ value, prefix, name, }) {
51
48
  const { classes } = useStyles();
52
- const { ref, scrollLeft } = (0, useResizeBar_1.useResizeBar)();
53
49
  const [checked, setChecked] = (0, react_1.useState)(false);
54
50
  const keys = Object.keys(value[0]).sort();
55
51
  const unionKeys = new Set(keys);
@@ -77,31 +73,26 @@ function DataGridDetails({ value, prefix, name, }) {
77
73
  else {
78
74
  colNames = [...unionKeys];
79
75
  }
80
- const [widths, setWidths] = (0, react_1.useState)(colNames.map(e => (0, util_1.measureGridWidth)(rows.map(r => r[e]))));
76
+ const widths = colNames.map(e => (0, util_1.measureGridWidth)(rows.map(r => r[e])));
81
77
  if (unionKeys.size < keys.length + 5) {
82
- return (react_1.default.createElement(react_1.default.Fragment, null,
78
+ return (react_1.default.createElement("div", { className: classes.margin },
83
79
  react_1.default.createElement(FieldName_1.default, { prefix: prefix, name: name }),
84
80
  react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Checkbox, { checked: checked, onChange: event => setChecked(event.target.checked) }), label: react_1.default.createElement(material_1.Typography, { variant: "body2" }, "Show options") }),
85
- react_1.default.createElement("div", { className: classes.margin, ref: ref },
86
- react_1.default.createElement(ResizeBar_1.default, { widths: widths, setWidths: setWidths, scrollLeft: scrollLeft }),
87
- react_1.default.createElement(x_data_grid_1.DataGrid, { disableRowSelectionOnClick: true,
88
- // @ts-expect-error the rows gets confused by the renderCell of the
89
- // columns below
90
- rows: rows, rowCount: 25, rowHeight: 25, columnHeaderHeight: 35, hideFooter: rows.length < 25, slots: { toolbar: checked ? x_data_grid_1.GridToolbar : null }, slotProps: {
91
- toolbar: {
92
- printOptions: {
93
- disableToolbarButton: true,
94
- },
81
+ react_1.default.createElement(x_data_grid_1.DataGrid, { disableRowSelectionOnClick: true, rows: rows, rowCount: 25, rowHeight: 25, columnHeaderHeight: 35, hideFooter: rows.length < 25, slots: { toolbar: checked ? x_data_grid_1.GridToolbar : null }, slotProps: {
82
+ toolbar: {
83
+ printOptions: {
84
+ disableToolbarButton: true,
95
85
  },
96
- }, columns: colNames.map((val, index) => ({
97
- field: val,
98
- renderCell: params => {
99
- const value = params.value;
100
- return (react_1.default.createElement("div", { className: classes.cell },
101
- react_1.default.createElement(ui_1.SanitizedHTML, { html: (0, util_1.getStr)(value) })));
102
- },
103
- width: widths[index],
104
- })) }))));
86
+ },
87
+ }, columns: colNames.map((val, index) => ({
88
+ field: val,
89
+ renderCell: params => {
90
+ const value = params.value;
91
+ return (react_1.default.createElement("div", { className: classes.cell },
92
+ react_1.default.createElement(ui_1.SanitizedHTML, { html: (0, util_1.getStr)(value) })));
93
+ },
94
+ width: widths[index],
95
+ })) })));
105
96
  }
106
97
  return null;
107
98
  }
@@ -69,9 +69,7 @@ function BaseCard({ children, title, defaultExpanded = true, }) {
69
69
  const [expanded, setExpanded] = (0, react_1.useState)(defaultExpanded);
70
70
  return (react_1.default.createElement(material_1.Accordion, { expanded: expanded, onChange: () => setExpanded(s => !s), TransitionProps: { unmountOnExit: true, timeout: 150 } },
71
71
  react_1.default.createElement(material_1.AccordionSummary, { expandIcon: react_1.default.createElement(ExpandMore_1.default, { className: classes.expandIcon }) },
72
- react_1.default.createElement(material_1.Typography, { variant: "button" },
73
- " ",
74
- title)),
72
+ react_1.default.createElement(material_1.Typography, { variant: "button" }, title)),
75
73
  react_1.default.createElement(material_1.AccordionDetails, { className: classes.expansionPanelDetails }, children)));
76
74
  }
77
75
  exports.BaseCard = BaseCard;
@@ -28,110 +28,49 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importStar(require("react"));
30
30
  const material_1 = require("@mui/material");
31
- const mui_1 = require("tss-react/mui");
32
31
  const mobx_react_1 = require("mobx-react");
33
- const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
34
32
  // locals
35
33
  const hooks_1 = require("./hooks");
36
34
  const ui_1 = require("../../ui");
37
- const util_1 = require("../../util");
38
35
  // icons
39
- const Settings_1 = __importDefault(require("@mui/icons-material/Settings"));
36
+ const SequenceFeatureMenu_1 = __importDefault(require("./dialogs/SequenceFeatureMenu"));
37
+ const SequenceTypeSelector_1 = __importDefault(require("./dialogs/SequenceTypeSelector"));
40
38
  // lazies
41
39
  const SequencePanel = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./SequencePanel'))));
42
- const SettingsDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./dialogs/SettingsDialog'))));
43
- const useStyles = (0, mui_1.makeStyles)()({
44
- formControl: {
45
- margin: 0,
46
- marginLeft: 4,
47
- },
48
- });
40
+ const SequenceDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./dialogs/SequenceDialog'))));
49
41
  // set the key on this component to feature.id to clear state after new feature
50
42
  // is selected
51
43
  const SequenceFeatureDetails = (0, mobx_react_1.observer)(function ({ model, feature, }) {
52
- var _a, _b;
53
44
  const { sequenceFeatureDetails } = model;
54
- const { intronBp, upDownBp } = sequenceFeatureDetails;
55
- const { classes } = useStyles();
45
+ const { upDownBp } = sequenceFeatureDetails;
56
46
  const seqPanelRef = (0, react_1.useRef)(null);
47
+ const [openInDialog, setOpenInDialog] = (0, react_1.useState)(false);
57
48
  const [force, setForce] = (0, react_1.useState)(false);
58
- const hasCDS = (_a = feature.subfeatures) === null || _a === void 0 ? void 0 : _a.some(sub => sub.type === 'CDS');
59
- const hasExon = (_b = feature.subfeatures) === null || _b === void 0 ? void 0 : _b.some(sub => sub.type === 'exon');
60
- const hasExonOrCDS = hasExon || hasCDS;
61
49
  const { sequence, error } = (0, hooks_1.useFeatureSequence)(model, feature, upDownBp, force);
62
- const [mode, setMode] = (0, react_1.useState)(hasCDS ? 'cds' : hasExon ? 'cdna' : 'genomic');
50
+ (0, react_1.useEffect)(() => {
51
+ sequenceFeatureDetails.setFeature(feature);
52
+ }, [sequenceFeatureDetails, feature]);
63
53
  return (react_1.default.createElement(react_1.default.Fragment, null,
64
54
  react_1.default.createElement("div", null,
65
- react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
66
- react_1.default.createElement(material_1.Select, { size: "small", value: mode, onChange: event => setMode(event.target.value) }, Object.entries({
67
- ...(hasCDS
68
- ? {
69
- cds: 'CDS',
70
- }
71
- : {}),
72
- ...(hasCDS
73
- ? {
74
- protein: 'Protein',
75
- }
76
- : {}),
77
- ...(hasExonOrCDS
78
- ? {
79
- cdna: 'cDNA',
80
- }
81
- : {}),
82
- ...(hasExonOrCDS
83
- ? {
84
- gene: `Genomic w/ full introns`,
85
- }
86
- : {}),
87
- ...(hasExonOrCDS
88
- ? {
89
- gene_updownstream: `Genomic w/ full introns +/- ${upDownBp}bp up+down stream`,
90
- }
91
- : {}),
92
- ...(hasExonOrCDS
93
- ? {
94
- gene_collapsed_intron: `Genomic w/ ${intronBp}bp intron`,
95
- }
96
- : {}),
97
- ...(hasExonOrCDS
98
- ? {
99
- gene_updownstream_collapsed_intron: `Genomic w/ ${intronBp}bp intron +/- ${upDownBp}bp up+down stream `,
100
- }
101
- : {}),
102
- ...(!hasExonOrCDS
103
- ? {
104
- genomic: 'Genomic',
105
- }
106
- : {}),
107
- ...(!hasExonOrCDS
108
- ? {
109
- genomic_sequence_updownstream: `Genomic +/- ${upDownBp}bp up+down stream`,
110
- }
111
- : {}),
112
- }).map(([key, val]) => (react_1.default.createElement(material_1.MenuItem, { key: key, value: key }, val))))),
113
- react_1.default.createElement(material_1.Button, { className: classes.formControl, variant: "contained", onClick: () => {
114
- const ref = seqPanelRef.current;
115
- if (ref) {
116
- (0, copy_to_clipboard_1.default)(ref.textContent || '', { format: 'text/plain' });
117
- }
118
- } }, "Copy plaintext"),
119
- react_1.default.createElement(material_1.Button, { className: classes.formControl, variant: "contained", onClick: () => {
120
- const ref = seqPanelRef.current;
121
- if (ref) {
122
- (0, copy_to_clipboard_1.default)(ref.innerHTML, { format: 'text/html' });
123
- }
124
- } }, "Copy HTML"),
125
- react_1.default.createElement(material_1.IconButton, { className: classes.formControl, onClick: () => (0, util_1.getSession)(model).queueDialog(handleClose => [
126
- SettingsDialog,
127
- { model: sequenceFeatureDetails, handleClose },
128
- ]) },
129
- react_1.default.createElement(Settings_1.default, null))),
130
- react_1.default.createElement("div", null,
55
+ react_1.default.createElement(SequenceTypeSelector_1.default, { model: sequenceFeatureDetails }),
56
+ react_1.default.createElement(SequenceFeatureMenu_1.default, { ref: seqPanelRef, model: sequenceFeatureDetails, extraItems: [
57
+ {
58
+ label: 'Open in dialog',
59
+ onClick: () => {
60
+ // this is given a setTimeout because it allows the menu to
61
+ // close before dialog opens
62
+ setTimeout(() => setOpenInDialog(true), 1);
63
+ },
64
+ },
65
+ ] })),
66
+ openInDialog ? (react_1.default.createElement("div", null,
67
+ "Open in dialog...",
68
+ react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(ui_1.LoadingEllipses, null) },
69
+ react_1.default.createElement(SequenceDialog, { model: model, feature: feature, handleClose: () => setOpenInDialog(false) })))) : (react_1.default.createElement("div", null,
131
70
  feature.type === 'gene' ? (react_1.default.createElement(material_1.Typography, null, "Note: inspect subfeature sequences for protein/CDS computations")) : null,
132
71
  error ? (react_1.default.createElement(ui_1.ErrorMessage, { error: error })) : !sequence ? (react_1.default.createElement(ui_1.LoadingEllipses, null)) : sequence ? ('error' in sequence ? (react_1.default.createElement(react_1.default.Fragment, null,
133
72
  react_1.default.createElement(material_1.Typography, { color: "error" }, sequence.error),
134
73
  react_1.default.createElement(material_1.Button, { variant: "contained", color: "inherit", onClick: () => setForce(true) }, "Force load"))) : (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(ui_1.LoadingEllipses, null) },
135
- react_1.default.createElement(SequencePanel, { ref: seqPanelRef, feature: feature, mode: mode, sequence: sequence, model: sequenceFeatureDetails })))) : (react_1.default.createElement(material_1.Typography, null, "No sequence found")))));
74
+ react_1.default.createElement(SequencePanel, { ref: seqPanelRef, feature: feature, sequence: sequence, model: sequenceFeatureDetails })))) : (react_1.default.createElement(material_1.Typography, null, "No sequence found"))))));
136
75
  });
137
76
  exports.default = SequenceFeatureDetails;
@@ -53,7 +53,7 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
53
53
  const SequenceFeaturePanel = (0, mobx_react_1.observer)(function ({ model, feature, }) {
54
54
  const { classes } = useStyles();
55
55
  const [shown, setShown] = (0, react_1.useState)(false);
56
- return !model ? null : (react_1.default.createElement("div", { className: classes.container },
56
+ return model ? (react_1.default.createElement("div", { className: classes.container },
57
57
  react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
58
58
  react_1.default.createElement(material_1.Button, { variant: "contained", onClick: () => setShown(!shown) }, shown ? 'Hide feature sequence' : 'Show feature sequence')),
59
59
  react_1.default.createElement(material_1.IconButton, { onClick: () => (0, util_1.getSession)(model).queueDialog(handleClose => [
@@ -62,6 +62,6 @@ const SequenceFeaturePanel = (0, mobx_react_1.observer)(function ({ model, featu
62
62
  ]) },
63
63
  react_1.default.createElement(Help_1.default, null)),
64
64
  shown ? (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(ui_1.LoadingEllipses, null) },
65
- react_1.default.createElement(SequenceFeatureDetails, { key: feature.uniqueId, model: model, feature: feature }))) : null));
65
+ react_1.default.createElement(SequenceFeatureDetails, { key: feature.uniqueId, model: model, feature: feature }))) : null)) : null;
66
66
  });
67
67
  exports.default = SequenceFeaturePanel;
@@ -2,11 +2,10 @@ import React from 'react';
2
2
  import { SimpleFeatureSerialized } from '../../util';
3
3
  import { SeqState } from '../util';
4
4
  import { SequenceFeatureDetailsModel } from './model';
5
- interface SeqPanelProps {
5
+ interface SequencePanelProps {
6
6
  sequence: SeqState;
7
7
  feature: SimpleFeatureSerialized;
8
- mode: string;
9
8
  model: SequenceFeatureDetailsModel;
10
9
  }
11
- declare const SeqPanel: React.ForwardRefExoticComponent<SeqPanelProps & React.RefAttributes<HTMLDivElement>>;
12
- export default SeqPanel;
10
+ declare const SequencePanel: React.ForwardRefExoticComponent<SequencePanelProps & React.RefAttributes<HTMLDivElement>>;
11
+ export default SequencePanel;
@@ -4,14 +4,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
+ const mobx_react_1 = require("mobx-react");
8
+ // locals
7
9
  const util_1 = require("../../util");
8
10
  const util_2 = require("../util");
11
+ // panel types
9
12
  const CDNASequence_1 = __importDefault(require("./seqtypes/CDNASequence"));
10
13
  const ProteinSequence_1 = __importDefault(require("./seqtypes/ProteinSequence"));
11
14
  const GenomicSequence_1 = __importDefault(require("./seqtypes/GenomicSequence"));
12
15
  const CDSSequence_1 = __importDefault(require("./seqtypes/CDSSequence"));
13
- const SeqPanel = react_1.default.forwardRef(function SeqPanel2(props, ref) {
14
- const { model, feature, mode } = props;
16
+ function getStrand(strand) {
17
+ if (strand === -1) {
18
+ return '(-)';
19
+ }
20
+ else if (strand === 1) {
21
+ return '(+)';
22
+ }
23
+ else {
24
+ return '';
25
+ }
26
+ }
27
+ function WordWrap({ children }) {
28
+ return (react_1.default.createElement("pre", { style: {
29
+ /* raw styles instead of className so that html copy works */
30
+ fontFamily: 'monospace',
31
+ color: 'black',
32
+ fontSize: 11,
33
+ } }, children));
34
+ }
35
+ function NoWordWrap({ children }) {
36
+ return (react_1.default.createElement("div", { style: {
37
+ /* raw styles instead of className so that html copy works */
38
+ fontFamily: 'monospace',
39
+ color: 'black',
40
+ fontSize: 11,
41
+ maxWidth: 600,
42
+ whiteSpace: 'wrap',
43
+ wordBreak: 'break-all',
44
+ } }, children));
45
+ }
46
+ const SequencePanel = (0, mobx_react_1.observer)(react_1.default.forwardRef(function S(props, ref) {
47
+ const { model, feature } = props;
48
+ const { showCoordinates, mode } = model;
15
49
  let { sequence: { seq, upstream = '', downstream = '' }, } = props;
16
50
  const { subfeatures = [] } = feature;
17
51
  const children = subfeatures
@@ -21,10 +55,10 @@ const SeqPanel = react_1.default.forwardRef(function SeqPanel2(props, ref) {
21
55
  start: sub.start - feature.start,
22
56
  end: sub.end - feature.start,
23
57
  }));
24
- // we filter duplicate entries in cds and exon lists duplicate entries may be
25
- // rare but was seen in Gencode v36 track NCList, likely a bug on GFF3 or
26
- // probably worth ignoring here (produces broken protein translations if
27
- // included)
58
+ // we filter duplicate entries in cds and exon lists duplicate entries
59
+ // may be rare but was seen in Gencode v36 track NCList, likely a bug
60
+ // on GFF3 or probably worth ignoring here (produces broken protein
61
+ // translations if included)
28
62
  //
29
63
  // position 1:224,800,006..225,203,064 gene ENSG00000185842.15 first
30
64
  // transcript ENST00000445597.6
@@ -57,21 +91,18 @@ const SeqPanel = react_1.default.forwardRef(function SeqPanel2(props, ref) {
57
91
  utr = (0, util_2.revlist)(utr, seq.length);
58
92
  }
59
93
  const codonTable = (0, util_1.generateCodonTable)(util_1.defaultCodonTable);
60
- return (react_1.default.createElement("div", { ref: ref, "data-testid": "sequence_panel" },
61
- react_1.default.createElement("div", { style: {
62
- /* raw styles instead of className so that html copy works */
63
- fontFamily: 'monospace',
64
- wordWrap: 'break-word',
65
- overflow: 'auto',
66
- color: 'black',
67
- fontSize: 12,
68
- maxWidth: 600,
69
- maxHeight: 300,
70
- } },
71
- react_1.default.createElement("span", { style: { background: 'white' } }, `>${feature.name ||
72
- feature.id ||
73
- `${feature.refName}:${feature.start + 1}-${feature.end}`}-${mode}\n`),
74
- react_1.default.createElement("br", null),
75
- mode === 'genomic' ? (react_1.default.createElement(GenomicSequence_1.default, { sequence: seq })) : mode === 'genomic_sequence_updownstream' ? (react_1.default.createElement(GenomicSequence_1.default, { sequence: seq, upstream: upstream, downstream: downstream })) : mode === 'cds' ? (react_1.default.createElement(CDSSequence_1.default, { cds: cds, sequence: seq })) : mode === 'cdna' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, cds: cds, utr: utr, sequence: seq })) : mode === 'protein' ? (react_1.default.createElement(ProteinSequence_1.default, { cds: cds, codonTable: codonTable, sequence: seq })) : mode === 'gene' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, cds: cds, utr: utr, sequence: seq, includeIntrons: true })) : mode === 'gene_collapsed_intron' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, cds: cds, sequence: seq, utr: utr, includeIntrons: true, collapseIntron: true })) : mode === 'gene_updownstream' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, cds: cds, sequence: seq, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true })) : mode === 'gene_updownstream_collapsed_intron' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, cds: cds, sequence: seq, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true, collapseIntron: true })) : (react_1.default.createElement("div", null, "Unknown type")))));
76
- });
77
- exports.default = SeqPanel;
94
+ const Container = showCoordinates ? WordWrap : NoWordWrap;
95
+ return (react_1.default.createElement("div", { "data-testid": "sequence_panel", ref: ref, style: { maxHeight: 300, overflow: 'auto' } },
96
+ react_1.default.createElement(Container, null,
97
+ react_1.default.createElement("div", { style: { background: 'white' } }, `>${[
98
+ (feature.name || feature.id) + '-' + mode,
99
+ `${feature.refName}:${(0, util_1.toLocale)(feature.start + 1)}-${(0, util_1.toLocale)(feature.end)}${getStrand(feature.strand)}`,
100
+ mode.endsWith('updownstream')
101
+ ? `+/- ${(0, util_1.toLocale)(model.upDownBp)} up/downstream bp`
102
+ : '',
103
+ ]
104
+ .filter(f => !!f)
105
+ .join(' ')}\n`),
106
+ mode === 'genomic' ? (react_1.default.createElement(GenomicSequence_1.default, { feature: feature, model: model, sequence: seq })) : mode === 'genomic_sequence_updownstream' ? (react_1.default.createElement(GenomicSequence_1.default, { model: model, feature: feature, sequence: seq, upstream: upstream, downstream: downstream })) : mode === 'cds' ? (react_1.default.createElement(CDSSequence_1.default, { model: model, cds: cds, sequence: seq })) : mode === 'cdna' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, feature: feature, cds: cds, utr: utr, sequence: seq })) : mode === 'protein' ? (react_1.default.createElement(ProteinSequence_1.default, { model: model, cds: cds, codonTable: codonTable, sequence: seq })) : mode === 'gene' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, feature: feature, cds: cds, utr: utr, sequence: seq, includeIntrons: true })) : mode === 'gene_collapsed_intron' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, feature: feature, cds: cds, sequence: seq, utr: utr, includeIntrons: true, collapseIntron: true })) : mode === 'gene_updownstream' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, feature: feature, cds: cds, sequence: seq, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true })) : mode === 'gene_updownstream_collapsed_intron' ? (react_1.default.createElement(CDNASequence_1.default, { model: model, exons: exons, feature: feature, cds: cds, sequence: seq, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true, collapseIntron: true })) : (react_1.default.createElement("div", null, "Unknown type")))));
107
+ }));
108
+ exports.default = SequencePanel;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { SimpleFeatureSerialized } from '../../../util';
3
+ import { BaseFeatureWidgetModel } from '../../stateModelFactory';
4
+ declare const SequenceDialog: ({ handleClose, model, feature, }: {
5
+ handleClose: () => void;
6
+ feature: SimpleFeatureSerialized;
7
+ model: BaseFeatureWidgetModel;
8
+ }) => React.JSX.Element;
9
+ export default SequenceDialog;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const react_1 = __importStar(require("react"));
30
+ const material_1 = require("@mui/material");
31
+ const ui_1 = require("@jbrowse/core/ui");
32
+ const mui_1 = require("tss-react/mui");
33
+ const mobx_react_1 = require("mobx-react");
34
+ // locals
35
+ const hooks_1 = require("../hooks");
36
+ const SequencePanel_1 = __importDefault(require("../SequencePanel"));
37
+ const SequenceFeatureMenu_1 = __importDefault(require("./SequenceFeatureMenu"));
38
+ const SequenceTypeSelector_1 = __importDefault(require("./SequenceTypeSelector"));
39
+ const useStyles = (0, mui_1.makeStyles)()({
40
+ dialogContent: {
41
+ width: '80em',
42
+ },
43
+ formControl: {
44
+ margin: 0,
45
+ marginLeft: 4,
46
+ },
47
+ });
48
+ const SequenceDialog = (0, mobx_react_1.observer)(function ({ handleClose, model, feature, }) {
49
+ const { sequenceFeatureDetails } = model;
50
+ const { upDownBp } = sequenceFeatureDetails;
51
+ const { classes } = useStyles();
52
+ const seqPanelRef = (0, react_1.useRef)(null);
53
+ const [force, setForce] = (0, react_1.useState)(false);
54
+ const { sequence, error } = (0, hooks_1.useFeatureSequence)(model, feature, upDownBp, force);
55
+ return (react_1.default.createElement(ui_1.Dialog, { maxWidth: "xl", open: true, onClose: () => handleClose(), title: "Sequence view" },
56
+ react_1.default.createElement(material_1.DialogContent, { className: classes.dialogContent },
57
+ react_1.default.createElement("div", null,
58
+ react_1.default.createElement(SequenceTypeSelector_1.default, { model: sequenceFeatureDetails }),
59
+ react_1.default.createElement(SequenceFeatureMenu_1.default, { ref: seqPanelRef, model: sequenceFeatureDetails })),
60
+ react_1.default.createElement("div", null,
61
+ feature.type === 'gene' ? (react_1.default.createElement(material_1.Typography, null, "Note: inspect subfeature sequences for protein/CDS computations")) : null,
62
+ error ? (react_1.default.createElement(ui_1.ErrorMessage, { error: error })) : !sequence ? (react_1.default.createElement(ui_1.LoadingEllipses, null)) : sequence ? ('error' in sequence ? (react_1.default.createElement(react_1.default.Fragment, null,
63
+ react_1.default.createElement(material_1.Typography, { color: "error" }, sequence.error),
64
+ react_1.default.createElement(material_1.Button, { variant: "contained", color: "inherit", onClick: () => setForce(true) }, "Force load"))) : (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(ui_1.LoadingEllipses, null) },
65
+ react_1.default.createElement(SequencePanel_1.default, { ref: seqPanelRef, feature: feature, sequence: sequence, model: sequenceFeatureDetails })))) : (react_1.default.createElement(material_1.Typography, null, "No sequence found")))),
66
+ react_1.default.createElement(material_1.DialogActions, null,
67
+ react_1.default.createElement(material_1.Button, { onClick: () => handleClose(), variant: "contained" }, "Close"))));
68
+ });
69
+ exports.default = SequenceDialog;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { SequenceFeatureDetailsModel } from '../model';
3
+ import { MenuItem } from '../../../ui';
4
+ interface Props {
5
+ model: SequenceFeatureDetailsModel;
6
+ extraItems?: MenuItem[];
7
+ }
8
+ declare const SequenceFeatureMenu: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLDivElement>>;
9
+ export default SequenceFeatureMenu;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const react_1 = __importStar(require("react"));
30
+ const mobx_react_1 = require("mobx-react");
31
+ const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
32
+ const file_saver_1 = require("file-saver");
33
+ // locals
34
+ const CascadingMenuButton_1 = __importDefault(require("../../../ui/CascadingMenuButton"));
35
+ // icons
36
+ const MoreVert_1 = __importDefault(require("@mui/icons-material/MoreVert"));
37
+ const Settings_1 = __importDefault(require("@mui/icons-material/Settings"));
38
+ // lazies
39
+ const SequenceFeatureSettingsDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./SettingsDialog'))));
40
+ const SequenceFeatureMenu = (0, mobx_react_1.observer)(react_1.default.forwardRef(function SequenceFeatureMenu2({ model, extraItems = [] }, ref) {
41
+ if (typeof ref === 'function') {
42
+ throw new Error('needs a non function ref');
43
+ }
44
+ const [showSettings, setShowSettings] = (0, react_1.useState)(false);
45
+ const { showCoordinatesSetting, showGenomicCoordsOption } = model;
46
+ return (react_1.default.createElement(react_1.default.Fragment, null,
47
+ react_1.default.createElement(CascadingMenuButton_1.default, { menuItems: [
48
+ {
49
+ label: 'Copy plaintext',
50
+ onClick: () => {
51
+ const r = ref === null || ref === void 0 ? void 0 : ref.current;
52
+ if (r) {
53
+ (0, copy_to_clipboard_1.default)(r.textContent || '', { format: 'text/plain' });
54
+ }
55
+ },
56
+ },
57
+ {
58
+ label: 'Copy HTML',
59
+ onClick: () => {
60
+ const r = ref === null || ref === void 0 ? void 0 : ref.current;
61
+ if (r) {
62
+ (0, copy_to_clipboard_1.default)(r.outerHTML, { format: 'text/html' });
63
+ }
64
+ },
65
+ },
66
+ {
67
+ label: 'Download plaintext',
68
+ onClick: () => {
69
+ const r = ref === null || ref === void 0 ? void 0 : ref.current;
70
+ if (r) {
71
+ (0, file_saver_1.saveAs)(new Blob([r.textContent || ''], {
72
+ type: 'text/plain;charset=utf-8',
73
+ }), 'sequence.txt');
74
+ }
75
+ },
76
+ },
77
+ {
78
+ label: 'Download HTML',
79
+ onClick: () => {
80
+ const r = ref === null || ref === void 0 ? void 0 : ref.current;
81
+ if (r) {
82
+ (0, file_saver_1.saveAs)(new Blob([r.outerHTML || ''], {
83
+ type: 'text/html;charset=utf-8',
84
+ }), 'sequence.html');
85
+ }
86
+ },
87
+ },
88
+ ...extraItems,
89
+ {
90
+ label: 'Show coordinates?',
91
+ type: 'subMenu',
92
+ subMenu: [
93
+ {
94
+ label: 'No coordinates',
95
+ type: 'radio',
96
+ checked: showCoordinatesSetting === 'none',
97
+ onClick: () => model.setShowCoordinates('none'),
98
+ },
99
+ {
100
+ label: 'Coordinates relative to feature start',
101
+ type: 'radio',
102
+ checked: showCoordinatesSetting === 'relative',
103
+ onClick: () => model.setShowCoordinates('relative'),
104
+ },
105
+ ...(showGenomicCoordsOption
106
+ ? [
107
+ {
108
+ label: 'Coordinates relative to genome (only available for continuous genome based sequence types)',
109
+ type: 'radio',
110
+ checked: showCoordinatesSetting === 'genomic',
111
+ onClick: () => model.setShowCoordinates('genomic'),
112
+ },
113
+ ]
114
+ : []),
115
+ ],
116
+ },
117
+ {
118
+ label: 'Settings',
119
+ icon: Settings_1.default,
120
+ onClick: () => setShowSettings(true),
121
+ },
122
+ ] },
123
+ react_1.default.createElement(MoreVert_1.default, null)),
124
+ showSettings ? (react_1.default.createElement(SequenceFeatureSettingsDialog, { model: model, handleClose: () => setShowSettings(false) })) : null));
125
+ }));
126
+ exports.default = SequenceFeatureMenu;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { SequenceFeatureDetailsModel } from '../model';
3
+ declare const SequenceTypeSelector: ({ model, }: {
4
+ model: SequenceFeatureDetailsModel;
5
+ }) => React.JSX.Element;
6
+ export default SequenceTypeSelector;