@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
package/editorUtils.js ADDED
@@ -0,0 +1,205 @@
1
+ import { getRangeLength, getSequenceWithinRange } from "@teselagen/range-utils";
2
+ import React from "react";
3
+ import { divideBy3 } from "./proteinUtils";
4
+ import {
5
+ getInsertBetweenVals,
6
+ calculatePercentGC,
7
+ aliasedEnzymesByName
8
+ } from "@teselagen/sequence-utils";
9
+ import { get, sortBy } from "lodash-es";
10
+ import VeWarning from "../helperComponents/VeWarning";
11
+ import { normalizePositionByRangeLength } from "@teselagen/range-utils";
12
+ import { filter } from "lodash-es";
13
+
14
+ export function getSelectionMessage({
15
+ caretPosition = -1,
16
+ selectionLayer = { start: -1, end: -1 },
17
+ customTitle,
18
+ sequenceLength,
19
+ sequenceData,
20
+ showGCContent, //these are only passed in for the status bar
21
+ GCDecimalDigits, //these are only passed in for the status bar
22
+ isProtein
23
+ }) {
24
+ let _selectionLayer = selectionLayer;
25
+ const isSelecting = selectionLayer.start > -1;
26
+ if (isSelecting) {
27
+ _selectionLayer = getSelFromWrappedAddon(selectionLayer, sequenceLength);
28
+ const length = getRangeLength(_selectionLayer, sequenceLength);
29
+ const GCContent = (numDecimalDigits = 0) =>
30
+ calculatePercentGC(
31
+ getSequenceWithinRange(_selectionLayer, sequenceData.sequence)
32
+ ).toFixed(numDecimalDigits);
33
+ const seqLen = divideBy3(length, isProtein);
34
+ return `${customTitle || "Selecting"} ${seqLen} ${
35
+ (isProtein ? "AA" : "bp") + (seqLen === 1 ? "" : "s")
36
+ } from ${divideBy3(_selectionLayer.start, isProtein) + 1} to ${divideBy3(
37
+ _selectionLayer.end + 1,
38
+ isProtein
39
+ )}${
40
+ showGCContent && !isProtein ? ` (${GCContent(GCDecimalDigits)}% GC)` : ""
41
+ }`;
42
+ } else if (caretPosition > -1) {
43
+ const insertBetween = getInsertBetweenVals(
44
+ caretPosition,
45
+ _selectionLayer,
46
+ sequenceLength
47
+ );
48
+ return (
49
+ `Caret Between ` +
50
+ (isProtein
51
+ ? `AAs ${divideBy3(insertBetween[0], true)} and ${divideBy3(
52
+ insertBetween[1] + 2,
53
+ true
54
+ )}`
55
+ : `Bases ${insertBetween[0]} and ${insertBetween[1]}`)
56
+ );
57
+ } else {
58
+ return "No Selection";
59
+ }
60
+ }
61
+
62
+ export function preventDefaultStopPropagation(e) {
63
+ if (e) {
64
+ e.stopPropagation();
65
+ e.preventDefault();
66
+ }
67
+ }
68
+
69
+ export function getNodeToRefocus(caretEl) {
70
+ let nodeToReFocus;
71
+ if (
72
+ caretEl &&
73
+ caretEl.closest &&
74
+ caretEl.closest(".veVectorInteractionWrapper")
75
+ ) {
76
+ nodeToReFocus = caretEl.closest(".veVectorInteractionWrapper");
77
+ }
78
+ return nodeToReFocus;
79
+ }
80
+
81
+ export function getEmptyText({ sequenceData, caretPosition }) {
82
+ return sequenceData.sequence.length === 0 && caretPosition === -1 ? (
83
+ <div className="veEmptySeqText">Insert Sequence Here</div>
84
+ ) : null;
85
+ }
86
+
87
+ export function tryToRefocusEditor() {
88
+ const ed = document.querySelector(".veVectorInteractionWrapper");
89
+ ed && ed.focus();
90
+ }
91
+ export function getCustomEnzymes() {
92
+ try {
93
+ const customEnzymes = JSON.parse(
94
+ window.localStorage.getItem("customEnzymes") || "{}"
95
+ );
96
+ return customEnzymes;
97
+ } catch (error) {
98
+ return {};
99
+ }
100
+ }
101
+ export function addCustomEnzyme(newEnz) {
102
+ const customEnzymes = getCustomEnzymes();
103
+ window.localStorage.setItem(
104
+ "customEnzymes",
105
+ JSON.stringify({
106
+ ...customEnzymes,
107
+ [newEnz.name.toLowerCase()]: newEnz
108
+ })
109
+ );
110
+ }
111
+
112
+ export function pareDownAnnotations(annotations, max) {
113
+ let annotationsToPass = annotations;
114
+ let paredDown = false;
115
+ if (Object.keys(annotations).length > max) {
116
+ paredDown = true;
117
+ const sortedAnnotations = sortBy(annotations, function (annotation) {
118
+ return -getRangeLength(annotation);
119
+ });
120
+ annotationsToPass = sortedAnnotations.slice(0, max).reduce(function (
121
+ obj,
122
+ item
123
+ ) {
124
+ obj[item.id] = item;
125
+ return obj;
126
+ }, {});
127
+ }
128
+ return [annotationsToPass, paredDown];
129
+ }
130
+ export function getParedDownWarning({ nameUpper, maxToShow, isAdjustable }) {
131
+ return (
132
+ <VeWarning
133
+ key={`ve-warning-max${nameUpper}ToDisplay`}
134
+ data-test={`ve-warning-max${nameUpper}ToDisplay`}
135
+ tooltip={`Warning: More than ${maxToShow} ${
136
+ nameUpper === "Cutsites" ? "Cut Sites" : nameUpper
137
+ }. Only displaying ${maxToShow} ${
138
+ isAdjustable ? "(Configure this under View > Limits)" : ""
139
+ } `}
140
+ />
141
+ );
142
+ }
143
+
144
+ export function getClientX(event) {
145
+ return event.clientX || get(event, "touches[0].clientX");
146
+ }
147
+ export function getClientY(event) {
148
+ return event.clientY || get(event, "touches[0].clientY");
149
+ }
150
+
151
+ export function hideAnnByLengthFilter(hideOpts, ann, seqLen) {
152
+ const featLength = getRangeLength(ann, seqLen);
153
+ return (
154
+ hideOpts.enabled && (featLength < hideOpts.min || featLength > hideOpts.max)
155
+ );
156
+ }
157
+
158
+ export function getSelFromWrappedAddon(selectionLayer, sequenceLength) {
159
+ const selToUse = {
160
+ ...selectionLayer
161
+ };
162
+ if (selectionLayer.isWrappedAddon) {
163
+ const oldEnd = selToUse.end;
164
+ selToUse.end = normalizePositionByRangeLength(
165
+ selToUse.start - 1,
166
+ sequenceLength
167
+ );
168
+ selToUse.start = normalizePositionByRangeLength(oldEnd + 1, sequenceLength);
169
+ delete selToUse.isWrappedAddon;
170
+ }
171
+ return selToUse;
172
+ }
173
+
174
+ export function getStripedPattern({ color, id }) {
175
+ return (
176
+ <pattern
177
+ id={`diagonalHatch-${id}`}
178
+ patternUnits="userSpaceOnUse"
179
+ width="4"
180
+ height="4"
181
+ >
182
+ <path
183
+ d="M-1,1 l2,-2
184
+ M0,4 l4,-4
185
+ M3,5 l2,-2"
186
+ style={{
187
+ stroke: color,
188
+ strokeWidth: 2,
189
+ fill: "blue",
190
+ opacity: 0.4
191
+ }}
192
+ />
193
+ </pattern>
194
+ );
195
+ }
196
+ export const getEnzymeAliases = enzyme => {
197
+ let lowerName = (enzyme.name && enzyme.name.toLowerCase()) || "";
198
+ if (typeof enzyme === "string") {
199
+ lowerName = enzyme.toLowerCase();
200
+ }
201
+ return filter(
202
+ (aliasedEnzymesByName[lowerName] || {}).aliases,
203
+ n => n.toLowerCase() !== lowerName //filter out current enzyme
204
+ );
205
+ };
@@ -0,0 +1,184 @@
1
+ import { forEach } from "lodash-es";
2
+
3
+ const debug = 0;
4
+ // const debug = console.log("comment me back out!") || 1;
5
+
6
+ export const rowHeights = {
7
+ rowJumpButtons: { height: 30 },
8
+ spacer: { height: 10 },
9
+ aminoAcidNumbers: { height: 9 },
10
+ translations: { spaceBetweenAnnotations: 2, marginTop: 5, height: 17 },
11
+ chromatogram: { height: 134 },
12
+ parts: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
13
+ primers: { spaceBetweenAnnotations: 2, marginTop: 5, height: 18 },
14
+ features: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
15
+ warnings: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
16
+ assemblyPieces: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
17
+ lineageAnnotations: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
18
+ orfs: { spaceBetweenAnnotations: 2, marginTop: 5, height: 15 },
19
+ //tnrtodo -- we should estimate external label height for parts/features/primers
20
+ cutsiteLabels: { spaceBetweenAnnotations: 0, height: 15 },
21
+ sequence: { height: 15 },
22
+ reverseSequence: { height: 15 },
23
+ axis: { marginTop: 5, height: 15 }
24
+ };
25
+
26
+ rowHeights.primaryProteinSequence = rowHeights.translations;
27
+
28
+ Object.keys(rowHeights).forEach(k => {
29
+ rowHeights[k].type = k;
30
+ rowHeights[k].marginTop = rowHeights[k].marginTop || 0;
31
+ rowHeights[k].marginBottom = rowHeights[k].marginBottom || 0;
32
+ rowHeights[k].spaceBetweenAnnotations =
33
+ rowHeights[k].spaceBetweenAnnotations || 0;
34
+ });
35
+ const translations = {
36
+ getHeight: props => {
37
+ if (props.annotationVisibility.aminoAcidNumbers) {
38
+ return [rowHeights.aminoAcidNumbers.type, rowHeights.translations.type];
39
+ }
40
+ return rowHeights.translations.type;
41
+ },
42
+ hasYOffset: true
43
+ };
44
+
45
+ const annotationsToCompute = {
46
+ spacer: {
47
+ alwaysVisible: true,
48
+ height: rowHeights.spacer.type
49
+ },
50
+ primaryProteinSequence: translations,
51
+ translations,
52
+ parts: {
53
+ height: rowHeights.parts.type,
54
+ hasYOffset: true
55
+ },
56
+ primers: {
57
+ height: rowHeights.primers.type,
58
+ hasYOffset: true
59
+ },
60
+ features: {
61
+ height: rowHeights.features.type,
62
+ hasYOffset: true
63
+ },
64
+ chromatogram: {
65
+ height: rowHeights.chromatogram.type
66
+ },
67
+ warnings: {
68
+ height: rowHeights.warnings.type,
69
+ hasYOffset: true
70
+ },
71
+ orfs: {
72
+ height: rowHeights.orfs.type,
73
+ hasYOffset: true
74
+ },
75
+ sequence: {
76
+ height: rowHeights.sequence.type
77
+ },
78
+ reverseSequence: {
79
+ height: rowHeights.reverseSequence.type
80
+ },
81
+ axis: {
82
+ height: rowHeights.axis.type
83
+ },
84
+ cutsiteLabels: {
85
+ typeOverride: "cutsites",
86
+ height: rowHeights.cutsiteLabels.type,
87
+ hasYOffset: true
88
+ }
89
+ };
90
+
91
+ export default props => {
92
+ let {
93
+ index,
94
+ cache,
95
+ clearCache,
96
+ chromatogramData,
97
+ rowCount,
98
+ row,
99
+ showJumpButtons,
100
+ annotationVisibility
101
+ } = props;
102
+ if (clearCache) {
103
+ cache = {};
104
+ }
105
+
106
+ if (cache[index]) {
107
+ return cache[index];
108
+ }
109
+ if (!row) return 0;
110
+ let totalHeight = 0; //account for spacer
111
+ if (showJumpButtons && (index === 0 || index === rowCount - 1)) {
112
+ totalHeight += rowHeights.rowJumpButtons.height;
113
+ }
114
+ forEach(
115
+ annotationsToCompute,
116
+ (
117
+ { height: _height, alwaysVisible, getHeight, hasYOffset, typeOverride },
118
+ key
119
+ ) => {
120
+ const shouldShow =
121
+ alwaysVisible || annotationVisibility[typeOverride || key];
122
+ if (!shouldShow) return;
123
+ if (key === "chromatogram" && !chromatogramData) return;
124
+ const heightKeys = getHeight ? getHeight(props) : _height;
125
+ const [annotationHeight, marginHeight] = getSummedHeights(
126
+ heightKeys,
127
+ props
128
+ );
129
+
130
+ let heightToAdd = annotationHeight;
131
+ if (hasYOffset) {
132
+ const annotations = row[typeOverride || key];
133
+ if (hasYOffset) {
134
+ let maxYOffset = 0;
135
+ annotations &&
136
+ annotations.forEach(a => {
137
+ if (a.yOffset + 1 > maxYOffset) maxYOffset = a.yOffset + 1;
138
+ });
139
+ heightToAdd = maxYOffset * annotationHeight;
140
+ }
141
+ }
142
+ if (heightToAdd > 0) heightToAdd += marginHeight;
143
+
144
+ if (debug) {
145
+ heightToAdd !== 0 &&
146
+ console.info(`heightToAdd, key:`, heightToAdd, key);
147
+ }
148
+ totalHeight += heightToAdd;
149
+ }
150
+ );
151
+ if (debug) {
152
+ console.info(`totalHeight:`, totalHeight);
153
+ }
154
+ if (annotationVisibility.compactNames) {
155
+ totalHeight = Math.max(totalHeight, 31);
156
+ }
157
+ cache[index] = totalHeight;
158
+ return totalHeight;
159
+ };
160
+
161
+ function getHeights(heightKey, props) {
162
+ const annotationHeight = !heightKey
163
+ ? 0
164
+ : props[heightKey + "Height"] || (rowHeights[heightKey] || {}).height || 0;
165
+
166
+ const marginHeight =
167
+ (props[heightKey + "MarginTop"] ||
168
+ (rowHeights[heightKey] || {}).marginTop ||
169
+ 0) +
170
+ (props[heightKey + "MarginBottom"] ||
171
+ (rowHeights[heightKey] || {}).marginBottom ||
172
+ 0);
173
+ return [annotationHeight, marginHeight];
174
+ }
175
+ function getSummedHeights(heightKeys, props) {
176
+ let height = 0;
177
+ let marginHeight = 0;
178
+ (Array.isArray(heightKeys) ? heightKeys : [heightKeys]).forEach(k => {
179
+ const [h, m] = getHeights(k, props);
180
+ height += h;
181
+ marginHeight += m;
182
+ });
183
+ return [height, marginHeight];
184
+ }
@@ -0,0 +1,27 @@
1
+ import createMergedDefaultStateReducer from "./utils/createMergedDefaultStateReducer";
2
+ import createAction from "./utils/createMetaAction";
3
+
4
+ // ------------------------------------
5
+ // Actions
6
+ // ------------------------------------
7
+ export const updateFeatureLengthsToHide = createAction(
8
+ "updateFeatureLengthsToHide"
9
+ );
10
+ export const toggleFeatureLengthsToHide = createAction(
11
+ "toggleFeatureLengthsToHide"
12
+ );
13
+
14
+ // ------------------------------------
15
+ // Reducer
16
+ // ------------------------------------
17
+ export default createMergedDefaultStateReducer(
18
+ {
19
+ [updateFeatureLengthsToHide]: (state, payload) => {
20
+ return { ...state, ...payload };
21
+ },
22
+ [toggleFeatureLengthsToHide]: state => {
23
+ return { ...state, enabled: !state["enabled"] };
24
+ }
25
+ },
26
+ { enabled: false, min: 0, max: 800 }
27
+ );
package/featureTool.js ADDED
@@ -0,0 +1,34 @@
1
+ import { Icon } from "@blueprintjs/core";
2
+ // import { Checkbox, Button } from "@blueprintjs/core";
3
+ import React from "react";
4
+ // import { connect } from "react-redux";
5
+ // import { convertRangeTo1Based } from "@teselagen/range-utils";
6
+ import { featureIcon } from "@teselagen/ui";
7
+ import ToolbarItem from "./ToolbarItem";
8
+ import { connectToEditor } from "../withEditorProps";
9
+
10
+ export default connectToEditor(
11
+ ({ annotationVisibility = {}, toolBar = {} }) => {
12
+ return {
13
+ toggled: annotationVisibility.features,
14
+ isOpen: toolBar.openItem === "featureTool"
15
+ };
16
+ }
17
+ )(({ toolbarItemProps, toggled, annotationVisibilityToggle, isOpen }) => {
18
+ return (
19
+ <ToolbarItem
20
+ {...{
21
+ Icon: <Icon icon={featureIcon} />,
22
+ onIconClick: function () {
23
+ annotationVisibilityToggle("features");
24
+ },
25
+ toggled,
26
+ tooltip: "Show features",
27
+ tooltipToggled: "Hide features",
28
+ // Dropdown: ConnectedFeatureToolDropdown,
29
+ dropdowntooltip: (!isOpen ? "Show" : "Hide") + " Feature Options",
30
+ ...toolbarItemProps
31
+ }}
32
+ />
33
+ );
34
+ });
package/features.js ADDED
@@ -0,0 +1,19 @@
1
+ import { createReducer } from "redux-act";
2
+ import createAction from "../utils/createMetaAction";
3
+ import upsertDeleteActionGenerator from "./upsertDeleteActionGenerator";
4
+
5
+ // ------------------------------------
6
+ // Actions
7
+ // ------------------------------------
8
+ export const upsertFeature = createAction("UPSERT_FEATURE");
9
+ export const deleteFeature = createAction("DELETE_FEATURE");
10
+
11
+ // ------------------------------------
12
+ // Reducer
13
+ // ------------------------------------
14
+ export default createReducer(
15
+ {
16
+ ...upsertDeleteActionGenerator(upsertFeature, deleteFeature)
17
+ },
18
+ {}
19
+ );
@@ -0,0 +1,8 @@
1
+ import { createSelector } from "reselect";
2
+ import sequenceDataSelector from "./sequenceDataSelector";
3
+
4
+ function featuresRawSelector(sequenceData) {
5
+ return sequenceData.features;
6
+ }
7
+
8
+ export default createSelector(sequenceDataSelector, featuresRawSelector);
@@ -0,0 +1,136 @@
1
+ import flatmap from "lodash/flatMap";
2
+ import { createSelector } from "reselect";
3
+ import cutsitesSelector from "./cutsitesSelector";
4
+ import filteredRestrictionEnzymesSelector from "./filteredRestrictionEnzymesSelector";
5
+ import specialCutsiteFilterOptions from "../constants/specialCutsiteFilterOptions";
6
+ import { flatMap } from "lodash-es";
7
+ import isEnzymeFilterAndSelector from "./isEnzymeFilterAndSelector";
8
+
9
+ export default createSelector(
10
+ cutsitesSelector,
11
+ filteredRestrictionEnzymesSelector,
12
+ isEnzymeFilterAndSelector,
13
+ (state, addEnzs, enzymeGroupsOverride) => enzymeGroupsOverride,
14
+ function (
15
+ { cutsitesByName },
16
+ filteredRestrictionEnzymes,
17
+ isEnzymeFilterAnd,
18
+ enzymeGroupsOverride
19
+ ) {
20
+ const returnVal = {
21
+ cutsitesByName: {}
22
+ };
23
+ // const cutsitesByName = getLowerCaseObj(cutsitesByName);
24
+ const hiddenEnzymesByName = {};
25
+ let filteredEnzymes = [];
26
+ let enzymesFromGroups = [];
27
+ let hasUserGroup;
28
+ let groupCount = 0;
29
+ //handle adding enzymes that are included in user created groups
30
+ filteredRestrictionEnzymes.forEach(e => {
31
+ if (e.value.includes("__userCreatedGroup")) {
32
+ hasUserGroup = true;
33
+ const existingGroups = {
34
+ ...window.getExistingEnzymeGroups(),
35
+ ...enzymeGroupsOverride
36
+ };
37
+ const enzymes =
38
+ existingGroups[e.value.replace("__userCreatedGroup", "")] || [];
39
+ const zs = flatMap(enzymes, e => (e ? { value: e } : []));
40
+ filteredEnzymes = filteredEnzymes.concat(zs);
41
+ enzymesFromGroups = enzymesFromGroups.concat(zs);
42
+ groupCount += 1;
43
+ } else if (e.isHidden) {
44
+ hiddenEnzymesByName[e.value] = e;
45
+ } else {
46
+ if (!e) return;
47
+ groupCount += 1;
48
+ filteredEnzymes.push(e);
49
+ }
50
+ });
51
+ const cutSiteList = [];
52
+ if (!filteredEnzymes || (filteredEnzymes.length === 0 && !hasUserGroup)) {
53
+ returnVal.cutsitesByName = cutsitesByName;
54
+ } else {
55
+ //loop through each filter option ('Single Cutters', 'BamHI')
56
+ filteredEnzymes.forEach(function ({ value, ...rest }) {
57
+ if (!value) {
58
+ console.error(`Missing value for filtered enzyme`, rest);
59
+ return;
60
+ }
61
+ const lowerValue = value.toLowerCase();
62
+ const cutsThisManyTimes =
63
+ specialCutsiteFilterOptions[value] &&
64
+ specialCutsiteFilterOptions[value].cutsThisManyTimes;
65
+ if (value === "type2s") {
66
+ Object.keys(cutsitesByName).forEach(function (key) {
67
+ if (hiddenEnzymesByName[key]) return; //don't show that cutsite
68
+ if (
69
+ cutsitesByName[key].length &&
70
+ cutsitesByName[key][0]?.restrictionEnzyme?.isType2S
71
+ ) {
72
+ cutSiteList.push(key);
73
+ returnVal.cutsitesByName[key] = cutsitesByName[key];
74
+ }
75
+ });
76
+ } else if (cutsThisManyTimes > 0) {
77
+ //the cutter type is either 1,2,3 for single, double or triple cutters
78
+ Object.keys(cutsitesByName).forEach(function (key) {
79
+ if (hiddenEnzymesByName[key]) return; //don't show that cutsite
80
+ if (cutsitesByName[key].length === cutsThisManyTimes) {
81
+ cutSiteList.push(key);
82
+ returnVal.cutsitesByName[key] = cutsitesByName[key];
83
+ }
84
+ });
85
+ } else {
86
+ if (hiddenEnzymesByName[lowerValue]) return; //don't show that cutsite
87
+ //normal enzyme ('BamHI')
88
+ if (!cutsitesByName[lowerValue]) return;
89
+ cutSiteList.push(lowerValue);
90
+ returnVal.cutsitesByName[lowerValue] = cutsitesByName[lowerValue];
91
+ }
92
+ });
93
+ }
94
+
95
+ const enzymeCounts = {};
96
+ cutSiteList.forEach(
97
+ enzyme =>
98
+ (enzymeCounts[enzyme] = enzymeCounts[enzyme]
99
+ ? enzymeCounts[enzyme] + 1
100
+ : 1)
101
+ );
102
+
103
+ const intersectionCutSites = [];
104
+ Object.keys(enzymeCounts).forEach(key => {
105
+ if (enzymeCounts[key] === groupCount) intersectionCutSites.push(key);
106
+ });
107
+
108
+ returnVal.cutsiteIntersectionCount = intersectionCutSites.length;
109
+
110
+ const cutsbyname_AND = {};
111
+ intersectionCutSites.forEach(value => {
112
+ cutsbyname_AND[value] = cutsitesByName[value];
113
+ });
114
+
115
+ returnVal.cutsiteTotalCount = Object.keys(returnVal.cutsitesByName).length;
116
+
117
+ if (isEnzymeFilterAnd && returnVal.cutsiteIntersectionCount > 0) {
118
+ returnVal.cutsitesByName = cutsbyname_AND;
119
+ }
120
+
121
+ returnVal.cutsitesArray = flatmap(
122
+ returnVal.cutsitesByName,
123
+ cutsitesByNameArray => cutsitesByNameArray
124
+ );
125
+ returnVal.cutsitesById = returnVal.cutsitesArray.reduce(function (
126
+ obj,
127
+ item
128
+ ) {
129
+ if (item && item.id) {
130
+ obj[item.id] = item;
131
+ }
132
+ return obj;
133
+ }, {});
134
+ return returnVal;
135
+ }
136
+ );
@@ -0,0 +1,32 @@
1
+ import { createSelector } from "reselect";
2
+ import { omitBy } from "lodash-es";
3
+ import featuresSelector from "./featuresSelector";
4
+ import sequenceLengthSelector from "./sequenceLengthSelector";
5
+ import { hideAnnByLengthFilter } from "../utils/editorUtils";
6
+
7
+ function filteredFeaturesSelector(
8
+ features,
9
+ seqLen,
10
+ featureIndividualToHide,
11
+ featureTypesToHide,
12
+ lengthsToHide
13
+ ) {
14
+ return omitBy(features, ann => {
15
+ const hideIndividually = featureIndividualToHide[ann.id];
16
+ const hideFeaturesByType = featureTypesToHide[ann.type];
17
+ return (
18
+ hideAnnByLengthFilter(lengthsToHide, ann, seqLen) ||
19
+ hideFeaturesByType ||
20
+ hideIndividually
21
+ );
22
+ });
23
+ }
24
+
25
+ export default createSelector(
26
+ featuresSelector,
27
+ sequenceLengthSelector,
28
+ state => state.annotationVisibility.featureIndividualToHide,
29
+ state => state.annotationVisibility.featureTypesToHide,
30
+ state => state.featureLengthsToHide,
31
+ filteredFeaturesSelector
32
+ );