@teselagen/ove 0.7.26 → 0.7.28

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 (304) hide show
  1. package/AASliver.js +187 -0
  2. package/AddLaddersDialog.js +82 -0
  3. package/AdditionalCutsiteInfoDialog.js +599 -0
  4. package/AlignmentView/Mismatches.d.ts +3 -3
  5. package/AlignmentVisibilityTool.js +105 -0
  6. package/AnnotationContainerHolder.js +20 -0
  7. package/AnnotationPositioner.js +27 -0
  8. package/AutoAnnotate.js +501 -0
  9. package/AutoAnnotateBpMatchingDialog.js +208 -0
  10. package/Axis.js +151 -0
  11. package/AxisNumbers.js +35 -0
  12. package/Browser.js +106 -0
  13. package/Caret.js +63 -0
  14. package/Chromatogram.js +293 -0
  15. package/CircularDnaSequence.js +73 -0
  16. package/CircularView/Labels/index.d.ts +1 -1
  17. package/CircularView/index.d.ts +0 -1
  18. package/CircularZoomMinimap.js +16 -0
  19. package/ColorPicker.js +30 -0
  20. package/CommandHotkeyHandler.js +44 -0
  21. package/CreateAnnotationsPage.d.ts +4 -4
  22. package/CreateAnnotationsPage.js +98 -0
  23. package/Cutsite.js +18 -0
  24. package/CutsiteProperties.js +176 -0
  25. package/CutsiteSelectionLayers.js +47 -0
  26. package/Cutsites.js +271 -0
  27. package/DeletionLayer.js +28 -0
  28. package/DigestTool/Ladder.d.ts +1 -1
  29. package/DropHandler.css +21 -0
  30. package/DropHandler.js +64 -0
  31. package/EditCaretPosition.js +234 -0
  32. package/EditTrackNameDialog.js +30 -0
  33. package/Feature.js +83 -0
  34. package/FeatureProperties.js +6 -0
  35. package/FillWindow.js +47 -0
  36. package/GenbankView.js +74 -0
  37. package/GeneralProperties.js +117 -0
  38. package/GenericAnnotationProperties.js +406 -0
  39. package/GlobalDialog.js +73 -0
  40. package/GlobalDialogUtils.js +110 -0
  41. package/GoToDialog.js +25 -0
  42. package/HorizontalPanelDragHandle.js +35 -0
  43. package/Keyboard.js +85 -0
  44. package/Labels.js +327 -0
  45. package/Ladder.css +20 -0
  46. package/Ladder.js +303 -0
  47. package/MeltingTemp.js +85 -0
  48. package/Menlo.ttf +0 -0
  49. package/Minimap.js +515 -0
  50. package/Mismatches.js +134 -0
  51. package/Monaco.ttf +0 -0
  52. package/MultipleSeqsDetectedOnImportDialog.js +74 -0
  53. package/Orf.js +109 -0
  54. package/OrfProperties.js +117 -0
  55. package/Orfs.js +35 -0
  56. package/PCRTool.js +179 -0
  57. package/PairwiseAlignmentView.js +68 -0
  58. package/Part.js +34 -0
  59. package/PartProperties.js +9 -0
  60. package/PassThrough.js +3 -0
  61. package/PerformantSelectionLayer.js +32 -0
  62. package/PinchHelper.js +24 -0
  63. package/PointedAnnotation.js +347 -0
  64. package/PositionAnnotationOnCircle.js +26 -0
  65. package/Primer.js +41 -0
  66. package/PrimerProperties.js +19 -0
  67. package/Reflex/index.d.ts +0 -1
  68. package/ReflexContainer.js +802 -0
  69. package/ReflexElement.js +160 -0
  70. package/ReflexEvents.js +77 -0
  71. package/ReflexSplitter.js +205 -0
  72. package/RenameSequenceDialog.js +7 -0
  73. package/RotateCircularViewSlider.js +93 -0
  74. package/RowView/index.d.ts +0 -1
  75. package/SelectDialog.js +150 -0
  76. package/SequenceName.js +15 -0
  77. package/SimpleCircularOrLinearView.js +381 -0
  78. package/SimpleOligoPreview.js +39 -0
  79. package/SingleEnzymeCutsiteInfo.js +139 -0
  80. package/ToolBar/ToolbarItem.d.ts +1 -3
  81. package/ToolbarItem.js +192 -0
  82. package/Translation.js +198 -0
  83. package/TranslationProperties.js +149 -0
  84. package/UncontrolledSliderWithPlusMinusBtns.css +5 -0
  85. package/UncontrolledSliderWithPlusMinusBtns.js +134 -0
  86. package/VeTopRightContainer.js +12 -0
  87. package/ZoomCircularViewSlider.js +62 -0
  88. package/ZoomLinearView.js +47 -0
  89. package/addAlignment.js +6 -0
  90. package/addMetaToActionCreators.js +12 -0
  91. package/addWrappedAddons.js +20 -0
  92. package/alignmentTool.js +503 -0
  93. package/alignments.js +379 -0
  94. package/annotationLabelVisibility.js +2 -0
  95. package/annotationSearchSelector.js +24 -0
  96. package/annotationTypes.js +35 -0
  97. package/annotationVisibility.js +196 -0
  98. package/annotationsToSupport.js +104 -0
  99. package/arrayToObjWithIds.js +17 -0
  100. package/arrayUtils.js +19 -0
  101. package/array_move.js +10 -0
  102. package/calculateTickMarkPositionsForGivenRange.js +47 -0
  103. package/caretPosition.js +27 -0
  104. package/cdsFeaturesSelector.js +9 -0
  105. package/charWidth.js +22 -0
  106. package/circular.js +19 -0
  107. package/circularSelector.js +4 -0
  108. package/clickAndDragUtils.js +576 -0
  109. package/coerceInitialValue.js +7 -0
  110. package/combineReducersDontIgnoreKeys.js +12 -0
  111. package/commandUtils.js +20 -0
  112. package/constants.js +2 -0
  113. package/copyOptions.js +34 -0
  114. package/createFragmentLines.js +120 -0
  115. package/createMergedDefaultStateReducer.js +30 -0
  116. package/createMetaAction.js +12 -0
  117. package/createSequenceInputPopup.js +290 -0
  118. package/createSequenceInputPopupStyle.css +87 -0
  119. package/createSimpleDialog.js +89 -0
  120. package/createYourOwnEnzyme.js +39 -0
  121. package/cutsiteLabelColorSelector.js +6 -0
  122. package/cutsiteTool.js +88 -0
  123. package/cutsitesByRangeSelector.js +5 -0
  124. package/cutsitesSelector.js +61 -0
  125. package/darkmode.css +98 -0
  126. package/defaultConfig.js +150 -0
  127. package/deletionLayers.js +36 -0
  128. package/description.js +21 -0
  129. package/digestTool.js +34 -0
  130. package/dnaToColor.js +17 -0
  131. package/downloadTool.js +39 -0
  132. package/draggableClassnames.js +5 -0
  133. package/drawAnnotations.js +440 -0
  134. package/drawDirectedPiePiece.js +142 -0
  135. package/editTool.js +49 -0
  136. package/editorSelector.js +2 -0
  137. package/editorUtils.js +205 -0
  138. package/estimateRowHeight.js +184 -0
  139. package/featureLengthsToHide.js +27 -0
  140. package/featureTool.js +34 -0
  141. package/features.js +19 -0
  142. package/featuresSelector.js +8 -0
  143. package/filteredCutsitesSelector.js +136 -0
  144. package/filteredFeaturesSelector.js +32 -0
  145. package/filteredPartsSelector.js +57 -0
  146. package/filteredPrimersSelector.js +27 -0
  147. package/filteredRestrictionEnzymesSelector.js +1 -0
  148. package/find.png +0 -0
  149. package/findTool.js +79 -0
  150. package/findToolConstants.js +1 -0
  151. package/frameTranslations.js +52 -0
  152. package/fullscreen.png +0 -0
  153. package/getAdditionalEnzymesSelector.js +46 -0
  154. package/getAngleForPositionMidpoint.js +3 -0
  155. package/getAnnotationClassnames.js +12 -0
  156. package/getAnnotationNameAndStartStopString.js +61 -0
  157. package/getBpsPerRow.js +19 -0
  158. package/getCutsiteLabelHeights.js +56 -0
  159. package/getGapMap.js +12 -0
  160. package/getGaps.js +27 -0
  161. package/getInternalLabel.js +40 -0
  162. package/getOveHotkeyDefs.js +12 -0
  163. package/getPairwiseOverviewLinearViewOptions.js +38 -0
  164. package/getRangeAnglesSpecial.js +12 -0
  165. package/getStructuredBases.js +97 -0
  166. package/getTrackFromEvent.js +25 -0
  167. package/getVisibleStartEnd.js +7 -0
  168. package/getXStartAndWidthFromNonCircularRange.js +12 -0
  169. package/getXStartAndWidthOfRangeWrtRow.js +27 -0
  170. package/getXStartAndWidthOfRowAnnotation.js +19 -0
  171. package/getYOffset.js +15 -0
  172. package/hoveredAnnotation.js +24 -0
  173. package/{html2canvas.esm--JN4fLQL.js → html2canvas.esm-DiGWN1gP.js} +187 -229
  174. package/{html2canvas.esm-B7d7VJmQ.cjs → html2canvas.esm-J1esNpMJ.cjs} +187 -229
  175. package/importTool.js +27 -0
  176. package/index.cjs.js +48165 -47142
  177. package/index.es.js +47699 -46676
  178. package/index.js +71 -0
  179. package/inlineFindTool.js +38 -0
  180. package/isElementInViewport.js +29 -0
  181. package/isEnzymeFilterAndSelector.js +1 -0
  182. package/isTargetWithinEl.js +6 -0
  183. package/labelLineIntensity.js +25 -0
  184. package/labelSize.js +23 -0
  185. package/ladderDefaults.js +25 -0
  186. package/lastSavedId.js +20 -0
  187. package/lineageLines.js +11 -0
  188. package/linear.png +0 -0
  189. package/makeStore.js +34 -0
  190. package/massageTickSpacing.js +19 -0
  191. package/materiallyAvailable.js +19 -0
  192. package/middleware.js +112 -0
  193. package/minimumOrfSize.js +24 -0
  194. package/minimumOrfSizeSelector.js +2 -0
  195. package/modalActions.js +3 -0
  196. package/moveCaret.js +58 -0
  197. package/name.js +19 -0
  198. package/normalizeAngle.js +3 -0
  199. package/normalizeAngleRange.js +9 -0
  200. package/oligoTool.js +30 -0
  201. package/onlyUpdateForKeysDeep.js +31 -0
  202. package/orfFrameToColorMap.js +10 -0
  203. package/orfTool.js +136 -0
  204. package/orfsSelector.js +15 -0
  205. package/ove.css +12107 -0
  206. package/package.json +8 -7
  207. package/panelsShown.js +294 -0
  208. package/partLengthsToHide.js +23 -0
  209. package/partOverhangs.js +6 -0
  210. package/partTagSearch.js +69 -0
  211. package/partTool.js +45 -0
  212. package/parts.js +19 -0
  213. package/partsSelector.js +8 -0
  214. package/pie.png +0 -0
  215. package/polarToSpecialCartesian.js +7 -0
  216. package/positionCutsites.js +6 -0
  217. package/prepareRowData.js +64 -0
  218. package/primerBases.js +221 -0
  219. package/primerLengthsToHide.js +27 -0
  220. package/primers.js +19 -0
  221. package/primersSelector.js +8 -0
  222. package/print.png +0 -0
  223. package/printTool.js +31 -0
  224. package/propertiesTool.js +40 -0
  225. package/proteinUtils.js +3 -0
  226. package/pureNoFunc.js +18 -0
  227. package/readOnly.js +25 -0
  228. package/redoTool.js +30 -0
  229. package/reflex-styles.css +128 -0
  230. package/reflex-styles.css.map +9 -0
  231. package/relaxLabelAngles.js +157 -0
  232. package/relaxLabels_DEPRECATED.js +105 -0
  233. package/replacementLayers.js +36 -0
  234. package/restrictionEnzymes.js +52 -0
  235. package/restrictionEnzymesSelector.js +34 -0
  236. package/rowviewContants.js +3 -0
  237. package/ruler.css +89 -0
  238. package/save.png +0 -0
  239. package/saveTool.js +44 -0
  240. package/searchLayersSelector.js +71 -0
  241. package/selectedAnnotations.js +89 -0
  242. package/selectedAnnotationsSelector.js +1 -0
  243. package/selectedCutsitesSelector.js +21 -0
  244. package/selectedPartTags.js +21 -0
  245. package/selectionLayer.js +25 -0
  246. package/selectors/annotationSearchSelector.d.ts +1 -1
  247. package/sequence.js +12 -0
  248. package/sequenceDataHistory.js +43 -0
  249. package/sequenceDataSelector.js +2 -0
  250. package/sequenceLengthSelector.js +5 -0
  251. package/sequenceSelector.js +4 -0
  252. package/sharedActionCreators.js +0 -0
  253. package/shouldFlipText.js +4 -0
  254. package/shouldRerender.js +27 -0
  255. package/showFileDialog.js +25 -0
  256. package/showGCContent.js +23 -0
  257. package/show_cut_sites.png +0 -0
  258. package/show_features.png +0 -0
  259. package/show_orfs.png +0 -0
  260. package/show_primers.png +0 -0
  261. package/simpleDialog.css +13 -0
  262. package/specialCutsiteFilterOptions.js +22 -0
  263. package/src/Editor/DropHandler.js +2 -1
  264. package/src/Editor/index.js +0 -2
  265. package/src/RowItem/StackedAnnotations/getStructuredBases.js +20 -6
  266. package/src/ToolBar/cutsiteTool.js +1 -1
  267. package/src/helperComponents/PropertiesDialog/TranslationProperties.js +2 -1
  268. package/style.css +3 -12100
  269. package/tagsToBoldSelector.js +2 -0
  270. package/toggle_views.svg +1 -0
  271. package/toolBar.js +23 -0
  272. package/translationSearchMatchesSelector.js +14 -0
  273. package/translations.js +20 -0
  274. package/translationsRawSelector.js +8 -0
  275. package/translationsSelector.js +137 -0
  276. package/typeField.js +24 -0
  277. package/undoTool.js +30 -0
  278. package/updateEditor.d.ts +1 -3
  279. package/updateEditor.js +200 -0
  280. package/updateLabelsForInViewFeatures.js +55 -0
  281. package/updateLabelsForInViewFeaturesCircView.js +41 -0
  282. package/updateTrackHelper.js +58 -0
  283. package/uppercaseSequenceMapFont.js +25 -0
  284. package/upsertDeleteActionGenerator.js +31 -0
  285. package/useAAColorType.js +8 -0
  286. package/useAdditionalOrfStartCodons.js +24 -0
  287. package/useAnnotationLimits.js +42 -0
  288. package/useChromatogramPrefs.js +31 -0
  289. package/useFormValue.js +7 -0
  290. package/useLadders.js +6 -0
  291. package/useMeltingTemp.js +7 -0
  292. package/useTmType.js +10 -0
  293. package/userDefinedHandlersAndOpts.js +61 -0
  294. package/utils/getAnnotationNameAndStartStopString.d.ts +1 -5
  295. package/utils/selectionLayer.d.ts +2 -2
  296. package/utils.js +37 -0
  297. package/versionHistory.js +26 -0
  298. package/versionHistoryTool.js +21 -0
  299. package/viewSubmenu.js +479 -0
  300. package/visibilityTool.js +39 -0
  301. package/withEditorInteractions/getBpsPerRow.d.ts +1 -3
  302. package/withHover.js +113 -0
  303. package/withRestrictionEnzymes.js +15 -0
  304. package/index.umd.js +0 -188322
@@ -0,0 +1,139 @@
1
+ import React, { useCallback, useMemo } from "react";
2
+ import { DataTable } from "@teselagen/ui";
3
+ import { CutsiteTag } from "../../CutsiteFilter/AdditionalCutsiteInfoDialog";
4
+ import EnzymeViewer from "../../EnzymeViewer";
5
+ import { getEnzymeAliases } from "../../utils/editorUtils";
6
+
7
+ const schema = {
8
+ fields: [
9
+ { path: "topSnipPosition", displayName: "Top Snip", type: "string" },
10
+ { path: "position", type: "string" },
11
+ { path: "strand", type: "string" }
12
+ ]
13
+ };
14
+
15
+ export default function SingleEnzymeCutsiteInfo({
16
+ cutsiteGroup,
17
+ enzyme,
18
+ dispatch,
19
+ allRestrictionEnzymes,
20
+ editorName,
21
+ selectedAnnotationId,
22
+ allCutsites,
23
+ filteredCutsites: { cutsitesByName: cutsitesByNameActive }
24
+ }) {
25
+ const onRowSelect = useCallback(
26
+ ([record]) => {
27
+ if (!record) return;
28
+
29
+ dispatch({
30
+ type: "CARET_POSITION_UPDATE",
31
+ payload: record.topSnipPosition,
32
+ meta: {
33
+ editorName
34
+ }
35
+ });
36
+ },
37
+ [dispatch, editorName]
38
+ );
39
+
40
+ const aliases = useMemo(() => getEnzymeAliases(enzyme), [enzyme]);
41
+ const entities = useMemo(
42
+ () =>
43
+ cutsiteGroup
44
+ .sort((a, b) => a.topSnipPosition - b.topSnipPosition)
45
+ .map(
46
+ ({
47
+ restrictionEnzyme: { forwardRegex, reverseRegex } = {},
48
+ forward,
49
+ id,
50
+ topSnipBeforeBottom,
51
+ topSnipPosition,
52
+ bottomSnipPosition
53
+ }) => {
54
+ return {
55
+ id,
56
+ topSnipPosition,
57
+ position: topSnipBeforeBottom
58
+ ? topSnipPosition + " - " + bottomSnipPosition
59
+ : bottomSnipPosition + " - " + topSnipPosition,
60
+ strand:
61
+ forwardRegex === reverseRegex
62
+ ? "Palindromic"
63
+ : forward
64
+ ? "1"
65
+ : "-1"
66
+ };
67
+ }
68
+ ),
69
+ [cutsiteGroup]
70
+ );
71
+
72
+ return (
73
+ <div>
74
+ <div
75
+ className="ve-enzymeSubrow"
76
+ style={{
77
+ margin: 10
78
+ }}
79
+ >
80
+ {enzyme && (
81
+ <EnzymeViewer
82
+ sequence={enzyme.site}
83
+ reverseSnipPosition={enzyme.bottomSnipOffset}
84
+ forwardSnipPosition={enzyme.topSnipOffset}
85
+ />
86
+ )}
87
+ <br />
88
+ {entities && !!entities.length && (
89
+ <div>
90
+ <DataTable
91
+ style={{ minHeight: 0, maxHeight: 200 }}
92
+ selectedIds={selectedAnnotationId}
93
+ maxHeight={300}
94
+ onRowSelect={onRowSelect}
95
+ formName="cutLocations"
96
+ isSingleSelect
97
+ compact
98
+ noRouter
99
+ minimalStyle
100
+ scrollToSelectedRowRelativeToDom
101
+ noHeader
102
+ isSimple
103
+ noFullscreenButton
104
+ isInfinite
105
+ withSearch={false}
106
+ withFilter={false}
107
+ schema={schema}
108
+ entities={entities}
109
+ />
110
+ </div>
111
+ )}
112
+ {aliases && aliases.length && (
113
+ <div style={{ marginTop: 10 }}>
114
+ Aliases:
115
+ <div style={{ display: "flex", flexWrap: "wrap" }}>
116
+ {aliases.map((n, i) => {
117
+ return (
118
+ <CutsiteTag
119
+ allRestrictionEnzymes={allRestrictionEnzymes}
120
+ cutsitesByNameActive={cutsitesByNameActive}
121
+ cutsitesByName={allCutsites.cutsitesByName}
122
+ key={i}
123
+ name={n}
124
+ doNotShowCuts
125
+ />
126
+ );
127
+ })}
128
+ </div>
129
+ </div>
130
+ )}
131
+ </div>
132
+ </div>
133
+ );
134
+ }
135
+
136
+ // export default compose(
137
+ // withEditorProps,
138
+ // withRestrictionEnzymes
139
+ // )(SingleEnzymeCutsiteInfo);
@@ -6,9 +6,7 @@ export default _default;
6
6
  declare class ToolbarItem extends React.Component<any, any, any> {
7
7
  constructor(props: any);
8
8
  constructor(props: any, context: any);
9
- toggleDropdown: ({ forceClose }?: {
10
- forceClose: any;
11
- }) => void;
9
+ toggleDropdown: ({ forceClose }?: {}) => void;
12
10
  render(): import("react/jsx-runtime").JSX.Element | null;
13
11
  dropdownNode: HTMLDivElement | undefined;
14
12
  }
package/ToolbarItem.js ADDED
@@ -0,0 +1,192 @@
1
+ import { connectToEditor } from "../withEditorProps";
2
+ // import download from 'in-browser-download'
3
+ import {
4
+ Popover,
5
+ Position,
6
+ Tooltip,
7
+ Icon as BpIcon,
8
+ AnchorButton,
9
+ Intent
10
+ } from "@blueprintjs/core";
11
+ import React from "react";
12
+ import "./style.css";
13
+ import { noop } from "lodash-es";
14
+
15
+ class ToolbarItem extends React.Component {
16
+ toggleDropdown = ({ forceClose } = {}) => {
17
+ const { toolName, isOpen } = this.props;
18
+
19
+ this.props.openToolbarItemUpdate(isOpen || forceClose ? "" : toolName);
20
+ };
21
+
22
+ render() {
23
+ const { overrides = {} } = this.props;
24
+ const {
25
+ isOpen,
26
+ index,
27
+ Icon,
28
+ // dynamicIcon,
29
+ onIconClick = noop,
30
+ tooltip = "",
31
+ tooltipToggled,
32
+ dropdowntooltip = "",
33
+ Dropdown,
34
+ disabled,
35
+ isHidden,
36
+ renderIconAbove,
37
+ noDropdownIcon,
38
+ IconWrapper,
39
+ editorName,
40
+ popoverDisabled,
41
+ IconWrapperProps,
42
+ toolName,
43
+ dropdownicon,
44
+ tooltipDisabled,
45
+ toggled = false,
46
+ ...rest
47
+ } = { ...this.props, ...overrides };
48
+ if (!toolName) console.warn("toolName is required!");
49
+ if (isHidden) return null;
50
+ let tooltipToDisplay = tooltip;
51
+ if (toggled && tooltipToggled) {
52
+ tooltipToDisplay = tooltipToggled;
53
+ }
54
+ // const Dropdown = _DropDown && withEditorProps && withEditorProps(_DropDown);
55
+
56
+ const buttonTarget = (
57
+ <div
58
+ className={
59
+ `veToolbarItemOuter ve-tool-container-${toolName}` +
60
+ (disabled ? " disabled " : "")
61
+ }
62
+ >
63
+ {renderIconAbove && (
64
+ <div>
65
+ <div className="veToolbarItem">{Icon}</div>
66
+ </div>
67
+ )}
68
+
69
+ {Icon && !renderIconAbove && (
70
+ <Tooltip
71
+ disabled={tooltipDisabled}
72
+ portalClassName="ve-toolbar-item-popover"
73
+ content={tooltipToDisplay}
74
+ >
75
+ <AnchorButton
76
+ intent={Intent.PRIMARY}
77
+ onClick={
78
+ onIconClick === "toggleDropdown"
79
+ ? this.toggleDropdown
80
+ : onIconClick
81
+ }
82
+ active={toggled}
83
+ disabled={disabled}
84
+ minimal
85
+ icon={
86
+ React.isValidElement(Icon) ? (
87
+ Icon
88
+ ) : (
89
+ <Icon toggleDropdown={this.toggleDropdown} />
90
+ )
91
+ }
92
+ />
93
+ </Tooltip>
94
+ )}
95
+ {Dropdown && !noDropdownIcon ? (
96
+ <Tooltip disabled={tooltipDisabled} content={dropdowntooltip}>
97
+ <div
98
+ className={
99
+ (isOpen ? " isOpen " : "") +
100
+ (dropdownicon ? "" : " veToolbarDropdown")
101
+ }
102
+ onClick={this.toggleDropdown}
103
+ >
104
+ {dropdownicon ? (
105
+ <div className="veToolbarIcon">
106
+ <div>{dropdownicon}</div>
107
+ </div>
108
+ ) : isOpen ? (
109
+ <BpIcon
110
+ data-test={toolName + "Dropdown"}
111
+ iconSize={13}
112
+ icon="caret-up"
113
+ />
114
+ ) : (
115
+ <BpIcon
116
+ data-test={toolName + "Dropdown"}
117
+ iconSize={13}
118
+ icon="caret-down"
119
+ />
120
+ )}
121
+ </div>
122
+ </Tooltip>
123
+ ) : null}
124
+ </div>
125
+ );
126
+ const content = (
127
+ <div
128
+ ref={n => {
129
+ if (n) this.dropdownNode = n;
130
+ }}
131
+ style={{ padding: 10, minWidth: 250, maxWidth: 350 }}
132
+ className="ve-toolbar-dropdown content"
133
+ >
134
+ {Dropdown && (
135
+ <Dropdown
136
+ {...rest}
137
+ editorName={editorName}
138
+ toggleDropdown={this.toggleDropdown}
139
+ />
140
+ )}
141
+ </div>
142
+ );
143
+ const target = IconWrapper ? (
144
+ <IconWrapper {...IconWrapperProps}>
145
+ {({ getRootProps, getInputProps }) => (
146
+ <div {...getRootProps()}>
147
+ <input {...getInputProps()} />
148
+ {buttonTarget}
149
+ </div>
150
+ )}
151
+ </IconWrapper>
152
+ ) : (
153
+ buttonTarget
154
+ );
155
+
156
+ return (
157
+ <div style={{ display: "flex", alignItems: "center" }}>
158
+ {index !== 0 && <div className="veToolbarSpacer" />}
159
+
160
+ <Popover
161
+ disabled={popoverDisabled}
162
+ isOpen={!!Dropdown && isOpen}
163
+ onClose={e => {
164
+ let srcElement;
165
+ if (e) {
166
+ srcElement = e.srcElement || e.target;
167
+ }
168
+ if (
169
+ e &&
170
+ srcElement &&
171
+ this.dropdownNode &&
172
+ (this.dropdownNode.contains(srcElement) ||
173
+ !document.body.contains(srcElement))
174
+ ) {
175
+ return;
176
+ }
177
+ this.toggleDropdown({ forceClose: true });
178
+ }}
179
+ canEscapeKeyClose
180
+ minimal
181
+ position={Position.BOTTOM}
182
+ target={target}
183
+ content={content}
184
+ />
185
+ </div>
186
+ );
187
+ }
188
+ }
189
+
190
+ export default connectToEditor(({ toolBar = {} }, { toolName }) => ({
191
+ isOpen: toolBar.openItem === toolName
192
+ }))(ToolbarItem);
package/Translation.js ADDED
@@ -0,0 +1,198 @@
1
+ import React from "react";
2
+ import {
3
+ getSequenceWithinRange,
4
+ zeroSubrangeByContainerRange
5
+ } from "@teselagen/range-utils";
6
+ import AASliver from "./AASliver";
7
+ import pureNoFunc from "../../utils/pureNoFunc";
8
+ import { proteinAlphabet } from "@teselagen/sequence-utils";
9
+
10
+ class Translation extends React.Component {
11
+ state = {
12
+ hasMounted: false
13
+ };
14
+ componentDidMount() {
15
+ this.timeout = setTimeout(() => {
16
+ this.setState({
17
+ hasMounted: true
18
+ });
19
+ }, 5);
20
+ }
21
+ componentWillUnmount() {
22
+ !window.Cypress && clearTimeout(this.timeout);
23
+ }
24
+ render() {
25
+ const {
26
+ annotationRange,
27
+ height,
28
+ showAminoAcidNumbers,
29
+ charWidth,
30
+ aminoAcidNumbersHeight,
31
+ onClick,
32
+ onRightClick,
33
+ onDoubleClick,
34
+ sequenceLength,
35
+ getGaps,
36
+ colorType,
37
+ isProtein
38
+ } = this.props;
39
+ const { hasMounted } = this.state;
40
+ const { annotation } = annotationRange;
41
+ if (!hasMounted && !isProtein) {
42
+ return <g height={height} className="translationLayer" />;
43
+ }
44
+ //we have an amino acid representation of our entire annotation, but it is an array
45
+ //starting at 0, even if the annotation starts at some arbitrary point in the sequence
46
+ const { aminoAcids = [] } = annotation;
47
+ //so we "zero" our subRange by the annotation start
48
+ const subrangeStartRelativeToAnnotationStart = zeroSubrangeByContainerRange(
49
+ annotationRange,
50
+ annotation,
51
+ sequenceLength
52
+ );
53
+ //which allows us to then get the amino acids for the subRange
54
+ const aminoAcidsForSubrange = getSequenceWithinRange(
55
+ subrangeStartRelativeToAnnotationStart,
56
+ aminoAcids
57
+ );
58
+
59
+ //we then loop over all the amino acids in the sub range and draw them onto the row
60
+ let prevAaSliver;
61
+ let nextAaSliver = aminoAcidsForSubrange[1];
62
+ // The last index in the sequence
63
+ const lastIndex = aminoAcidsForSubrange.length - 1;
64
+
65
+ const translationSVG = aminoAcidsForSubrange.map(
66
+ function (aminoAcidSliver, index) {
67
+ if (aminoAcidSliver.positionInCodon === null) {
68
+ prevAaSliver = aminoAcidSliver;
69
+ nextAaSliver = aminoAcidsForSubrange[index + 2];
70
+ return (
71
+ <rect
72
+ key={annotation.id + aminoAcidSliver.sequenceIndex}
73
+ x={index * charWidth}
74
+ y={height / 2 - height / 16}
75
+ width={charWidth}
76
+ height={height / 8}
77
+ fill="grey"
78
+ stroke="black"
79
+ strokeWidth={1}
80
+ ></rect>
81
+ );
82
+ }
83
+ const isEndFiller =
84
+ (index === 0 || prevAaSliver?.positionInCodon === null) &&
85
+ aminoAcidSliver.positionInCodon === (annotation.forward ? 2 : 0);
86
+
87
+ const isStartFiller =
88
+ (index === lastIndex || nextAaSliver?.positionInCodon === null) &&
89
+ aminoAcidSliver.positionInCodon === (annotation.forward ? 0 : 2);
90
+
91
+ let isTruncatedEnd =
92
+ (index === 0 || prevAaSliver?.positionInCodon === null) &&
93
+ aminoAcidSliver.positionInCodon === 1;
94
+ let isTruncatedStart =
95
+ (index === lastIndex || nextAaSliver?.positionInCodon === null) &&
96
+ aminoAcidSliver.positionInCodon === 1;
97
+
98
+ if (!annotation.forward) {
99
+ const holder = isTruncatedEnd;
100
+ isTruncatedEnd = isTruncatedStart;
101
+ isTruncatedStart = holder;
102
+ }
103
+ if (
104
+ aminoAcidSliver.positionInCodon !== 1 &&
105
+ !isStartFiller &&
106
+ !isEndFiller
107
+ ) {
108
+ prevAaSliver = aminoAcidSliver;
109
+ nextAaSliver = aminoAcidsForSubrange[index + 2];
110
+ return null;
111
+ }
112
+ const { gapsInside, gapsBefore } = getGaps(aminoAcidSliver.codonRange);
113
+ const gapsInsideFeatureStartToBp = getGaps({
114
+ start: annotationRange.start,
115
+ end: aminoAcidSliver.sequenceIndex
116
+ }).gapsInside;
117
+ // var relativeAAPositionInTranslation = annotationRange.start % bpsPerRow + index;
118
+ const relativeAAPositionInTranslation = index;
119
+ const aminoAcid = aminoAcidSliver.aminoAcid || {};
120
+ //get the codonIndices relative to
121
+ const alphVal = proteinAlphabet[aminoAcid.value];
122
+ let color;
123
+ if (alphVal) {
124
+ color =
125
+ colorType === "byHydrophobicity"
126
+ ? alphVal.color
127
+ : alphVal.colorByFamily;
128
+ } else {
129
+ color = aminoAcid.color;
130
+ }
131
+ prevAaSliver = aminoAcidSliver;
132
+ nextAaSliver = aminoAcidsForSubrange[index + 2];
133
+
134
+ return (
135
+ <AASliver
136
+ // isTruncatedEnd && isTruncatedStart is the special case of a single base exon
137
+ isFiller={
138
+ isEndFiller ||
139
+ isStartFiller ||
140
+ (isTruncatedEnd && isTruncatedStart)
141
+ }
142
+ isTruncatedEnd={isTruncatedEnd}
143
+ isTruncatedStart={isTruncatedStart}
144
+ onClick={function (event) {
145
+ onClick({
146
+ annotation: aminoAcidSliver.codonRange,
147
+ codonRange: aminoAcidSliver.codonRange,
148
+ event,
149
+ gapsInside,
150
+ gapsBefore
151
+ });
152
+ }}
153
+ onContextMenu={function (event) {
154
+ onRightClick &&
155
+ onRightClick({
156
+ annotation,
157
+ codonRange: aminoAcidSliver.codonRange,
158
+ event,
159
+ gapsInside,
160
+ gapsBefore
161
+ });
162
+ }}
163
+ title={`${aminoAcid.name} -- Index: ${
164
+ aminoAcidSliver.aminoAcidIndex + 1
165
+ } -- Hydrophobicity: ${aminoAcid.hydrophobicity} -- Mass: ${
166
+ aminoAcid.mass
167
+ }\n
168
+ Part of ${annotation.translationType} Translation from BPs ${
169
+ annotation.start + 1
170
+ } to ${annotation.end + 1} (${aminoAcids.length / 3} AAs)`}
171
+ showAminoAcidNumbers={showAminoAcidNumbers}
172
+ aminoAcidIndex={aminoAcidSliver.aminoAcidIndex}
173
+ onDoubleClick={function (event) {
174
+ onDoubleClick({ annotation, event });
175
+ }}
176
+ getGaps={getGaps}
177
+ key={annotation.id + aminoAcidSliver.sequenceIndex}
178
+ forward={annotation.forward}
179
+ width={charWidth}
180
+ height={
181
+ showAminoAcidNumbers ? height - aminoAcidNumbersHeight : height
182
+ }
183
+ relativeAAPositionInTranslation={
184
+ relativeAAPositionInTranslation + gapsInsideFeatureStartToBp
185
+ }
186
+ letter={aminoAcid.value}
187
+ color={color}
188
+ positionInCodon={aminoAcidSliver.positionInCodon}
189
+ />
190
+ );
191
+ }
192
+ );
193
+
194
+ return <g className="translationLayer">{translationSVG}</g>;
195
+ }
196
+ }
197
+
198
+ export default pureNoFunc(Translation);
@@ -0,0 +1,149 @@
1
+ import { Tooltip, AnchorButton } from "@blueprintjs/core";
2
+ import React from "react";
3
+ import {
4
+ DataTable,
5
+ withSelectedEntities,
6
+ createCommandMenu
7
+ } from "@teselagen/ui";
8
+ import getCommands from "../../commands";
9
+ import { map } from "lodash-es";
10
+ import { getRangeLength } from "@teselagen/range-utils";
11
+ import { connectToEditor } from "../../withEditorProps";
12
+ import { compose } from "recompose";
13
+ import selectors from "../../selectors";
14
+ import { getMassOfAaString } from "@teselagen/sequence-utils";
15
+ import { translationsSubmenu } from "../../MenuBar/viewSubmenu";
16
+ import { getVisFilter } from "./GenericAnnotationProperties";
17
+
18
+ class TranslationProperties extends React.Component {
19
+ constructor(props) {
20
+ super(props);
21
+ this.commands = getCommands(this);
22
+ }
23
+ onRowSelect = ([record]) => {
24
+ if (!record) return;
25
+ const { dispatch, editorName } = this.props;
26
+ dispatch({
27
+ type: "SELECTION_LAYER_UPDATE",
28
+ payload: record,
29
+ meta: {
30
+ editorName
31
+ }
32
+ });
33
+ };
34
+ render() {
35
+ const {
36
+ readOnly,
37
+ translations,
38
+ translationPropertiesSelectedEntities,
39
+ deleteTranslation,
40
+ sequenceLength,
41
+ selectedAnnotationId,
42
+ annotationVisibility
43
+ } = this.props;
44
+ const translationsToUse = map(translations, translation => {
45
+ let aaString = "";
46
+ for (let i = 0; i < translation.aminoAcids.length; i++) {
47
+ aaString += translation.aminoAcids[i].aminoAcid.value;
48
+ }
49
+ return {
50
+ ...translation,
51
+ sizeBps: getRangeLength(translation, sequenceLength),
52
+ sizeAa:
53
+ translation.translationType === "ORF"
54
+ ? Math.floor(getRangeLength(translation, sequenceLength) / 3 - 1)
55
+ : Math.floor(getRangeLength(translation, sequenceLength) / 3),
56
+ ...(translation.strand === undefined && {
57
+ strand: translation.forward ? 1 : -1
58
+ }),
59
+ mass: getMassOfAaString(aaString, 2, true)
60
+ };
61
+ });
62
+ return (
63
+ <div style={{ display: "flex", flexDirection: "column" }}>
64
+ <DataTable
65
+ withCheckboxes
66
+ noPadding
67
+ onRowSelect={this.onRowSelect}
68
+ selectedIds={selectedAnnotationId}
69
+ formName="translationProperties"
70
+ noRouter
71
+ compact
72
+ topLeftItems={getVisFilter(
73
+ createCommandMenu(translationsSubmenu, this.commands, {
74
+ useTicks: true
75
+ })
76
+ )}
77
+ leftOfSearchBarItems={
78
+ !readOnly && (
79
+ <Tooltip
80
+ content={
81
+ translationPropertiesSelectedEntities.length &&
82
+ translationPropertiesSelectedEntities[0].translationType !==
83
+ "User Created"
84
+ ? `Only "User Created" translations can be deleted`
85
+ : undefined
86
+ }
87
+ >
88
+ <AnchorButton
89
+ onClick={() => {
90
+ deleteTranslation(translationPropertiesSelectedEntities);
91
+ }}
92
+ intent="danger"
93
+ icon="trash"
94
+ style={{ marginLeft: 10, marginRight: 15, height: 30 }}
95
+ disabled={
96
+ !translationPropertiesSelectedEntities.length ||
97
+ translationPropertiesSelectedEntities[0].translationType !==
98
+ "User Created"
99
+ }
100
+ ></AnchorButton>
101
+ </Tooltip>
102
+ )
103
+ }
104
+ annotationVisibility={annotationVisibility} //we need to pass this in order to force the DT to rerender
105
+ hideSelectedCount
106
+ noFooter
107
+ noFullscreenButton
108
+ isInfinite
109
+ schema={{
110
+ fields: [
111
+ {
112
+ path: "translationType",
113
+ displayName: "Type",
114
+ type: "string"
115
+ },
116
+ {
117
+ path: "sizeAa",
118
+ displayName: "Size (aa)",
119
+ type: "number"
120
+ },
121
+ {
122
+ path: "mass",
123
+ displayName: "Mass (g/mol)",
124
+ type: "number"
125
+ },
126
+ { path: "strand", type: "number" }
127
+ ]
128
+ }}
129
+ entities={translationsToUse}
130
+ />
131
+ </div>
132
+ );
133
+ }
134
+ }
135
+
136
+ export default compose(
137
+ connectToEditor(editorState => {
138
+ const { readOnly, annotationVisibility = {}, sequenceData } = editorState;
139
+ return {
140
+ readOnly,
141
+ translations: selectors.translationsSelector(editorState),
142
+ orfs: selectors.orfsSelector(editorState),
143
+ annotationVisibility,
144
+ sequenceLength: (sequenceData.sequence || "").length,
145
+ sequenceData
146
+ };
147
+ }),
148
+ withSelectedEntities("translationProperties")
149
+ )(TranslationProperties);
@@ -0,0 +1,5 @@
1
+ .small-slider .bp3-slider-handle {
2
+ width: 12px;
3
+ height: 12px;
4
+ top: 2px;
5
+ }