@teselagen/ove 0.0.14 → 0.0.16

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 (362) hide show
  1. package/index.umd.js +164825 -135871
  2. package/package.json +78 -9
  3. package/src/AlignmentTool/index.js +16 -0
  4. package/src/AlignmentView/AlignmentVisibilityTool.js +105 -0
  5. package/src/AlignmentView/EditTrackNameDialog.js +34 -0
  6. package/src/AlignmentView/HorizontalPanelDragHandle.js +35 -0
  7. package/src/AlignmentView/Minimap.js +520 -0
  8. package/src/AlignmentView/Mismatches.js +134 -0
  9. package/src/AlignmentView/PairwiseAlignmentView.js +68 -0
  10. package/src/AlignmentView/PerformantSelectionLayer.js +32 -0
  11. package/src/AlignmentView/coerceInitialValue.js +7 -0
  12. package/src/AlignmentView/getGapMap.js +12 -0
  13. package/src/AlignmentView/getGaps.js +27 -0
  14. package/src/AlignmentView/getPairwiseOverviewLinearViewOptions.js +38 -0
  15. package/src/AlignmentView/getTrackFromEvent.js +25 -0
  16. package/src/AlignmentView/index.js +2058 -0
  17. package/src/AlignmentView/isTargetWithinEl.js +6 -0
  18. package/src/AlignmentView/style.css +100 -0
  19. package/src/AlignmentView/updateTrackHelper.js +58 -0
  20. package/src/AutoAnnotate.js +500 -0
  21. package/src/AutoAnnotateBpMatchingDialog.js +208 -0
  22. package/src/CircularView/Axis.js +40 -0
  23. package/src/CircularView/AxisNumbers.js +35 -0
  24. package/src/CircularView/Caret.js +63 -0
  25. package/src/CircularView/CircularDnaSequence.js +73 -0
  26. package/src/CircularView/CircularZoomMinimap.js +16 -0
  27. package/src/CircularView/Cutsite.js +18 -0
  28. package/src/CircularView/Cutsites.js +113 -0
  29. package/src/CircularView/DeletionLayer.js +28 -0
  30. package/src/CircularView/Feature.js +83 -0
  31. package/src/CircularView/Labels/index.js +536 -0
  32. package/src/CircularView/Labels/relaxLabelAngles.js +157 -0
  33. package/src/CircularView/Labels/relaxLabels_DEPRECATED.js +105 -0
  34. package/src/CircularView/Labels/style.css +55 -0
  35. package/src/CircularView/Orf.js +25 -0
  36. package/src/CircularView/Part.js +34 -0
  37. package/src/CircularView/PositionAnnotationOnCircle.js +26 -0
  38. package/src/CircularView/Primer.js +41 -0
  39. package/src/CircularView/RotateCircularViewSlider.js +82 -0
  40. package/src/CircularView/SelectionLayer.js +132 -0
  41. package/src/CircularView/VeTopRightContainer.js +12 -0
  42. package/src/CircularView/ZoomCircularViewSlider.js +62 -0
  43. package/src/CircularView/drawAnnotations.js +433 -0
  44. package/src/CircularView/drawDirectedPiePiece.js +142 -0
  45. package/src/CircularView/getAngleForPositionMidpoint.js +3 -0
  46. package/src/CircularView/getInternalLabel.js +40 -0
  47. package/src/CircularView/getRangeAnglesSpecial.js +12 -0
  48. package/src/CircularView/getYOffset.js +15 -0
  49. package/src/CircularView/index.d.ts +20 -0
  50. package/src/CircularView/index.js +930 -0
  51. package/src/CircularView/normalizeAngle.js +3 -0
  52. package/src/CircularView/normalizeAngleRange.js +9 -0
  53. package/src/CircularView/positionCutsites.js +6 -0
  54. package/src/CircularView/shouldFlipText.js +4 -0
  55. package/src/CircularView/style.css +47 -0
  56. package/src/CircularView/utils/polarToSpecialCartesian.js +7 -0
  57. package/src/CreateAnnotationsPage.js +96 -0
  58. package/src/CreateCustomEnzyme/index.js +337 -0
  59. package/src/CreateCustomEnzyme/style.css +100 -0
  60. package/src/CutsiteFilter/AdditionalCutsiteInfoDialog.js +599 -0
  61. package/src/CutsiteFilter/index.js +408 -0
  62. package/src/CutsiteFilter/style.css +23 -0
  63. package/src/CutsiteFilter/withRestrictionEnzymes.js +15 -0
  64. package/src/DigestTool/AddLaddersDialog.js +82 -0
  65. package/src/DigestTool/DigestTool.js +223 -0
  66. package/src/DigestTool/Ladder.css +20 -0
  67. package/src/DigestTool/Ladder.js +303 -0
  68. package/src/DigestTool/createFragmentLines.js +120 -0
  69. package/src/DigestTool/ladderDefaults.js +26 -0
  70. package/src/DigestTool/ruler.css +89 -0
  71. package/src/Editor/CommandHotkeyHandler.js +44 -0
  72. package/src/Editor/DropHandler.css +21 -0
  73. package/src/Editor/DropHandler.js +64 -0
  74. package/src/Editor/FillWindow.js +46 -0
  75. package/src/Editor/darkmode.css +98 -0
  76. package/src/Editor/index.js +1005 -0
  77. package/src/Editor/style.css +235 -0
  78. package/src/Editor/userDefinedHandlersAndOpts.js +56 -0
  79. package/src/EnzymeViewer/index.js +81 -0
  80. package/src/EnzymeViewer/style.css +6 -0
  81. package/src/FindBar/index.js +411 -0
  82. package/src/FindBar/style.css +46 -0
  83. package/src/GlobalDialog.js +66 -0
  84. package/src/GlobalDialogUtils.js +85 -0
  85. package/src/LinearView/SequenceName.js +15 -0
  86. package/src/LinearView/ZoomLinearView.js +47 -0
  87. package/src/LinearView/index.js +374 -0
  88. package/src/LinearView/style.css +12 -0
  89. package/src/ManageEnzymes/index.js +326 -0
  90. package/src/ManageEnzymes/style.css +100 -0
  91. package/src/MenuBar/defaultConfig.js +149 -0
  92. package/src/MenuBar/index.js +98 -0
  93. package/src/MenuBar/viewSubmenu.js +479 -0
  94. package/src/PCRTool/PCRTool.js +173 -0
  95. package/src/Reflex/Browser.js +107 -0
  96. package/src/Reflex/ReflexContainer.js +802 -0
  97. package/src/Reflex/ReflexElement.js +160 -0
  98. package/src/Reflex/ReflexEvents.js +77 -0
  99. package/src/Reflex/ReflexSplitter.js +205 -0
  100. package/src/Reflex/index.js +5 -0
  101. package/src/Reflex/reflex-styles.css +128 -0
  102. package/src/Reflex/reflex-styles.css.map +9 -0
  103. package/src/RowItem/AnnotationContainerHolder.js +20 -0
  104. package/src/RowItem/AnnotationPositioner.js +27 -0
  105. package/src/RowItem/Axis.js +149 -0
  106. package/src/RowItem/Caret/index.js +64 -0
  107. package/src/RowItem/Caret/style.css +8 -0
  108. package/src/RowItem/Chromatograms/Chromatogram.js +289 -0
  109. package/src/RowItem/CutsiteSelectionLayers.js +47 -0
  110. package/src/RowItem/Cutsites.js +271 -0
  111. package/src/RowItem/DeletionLayers/index.js +113 -0
  112. package/src/RowItem/DeletionLayers/style.css +5 -0
  113. package/src/RowItem/Labels.js +327 -0
  114. package/src/RowItem/Orf.js +109 -0
  115. package/src/RowItem/Orfs.js +35 -0
  116. package/src/RowItem/ReplacementLayers/style.css +5 -0
  117. package/src/RowItem/SelectionLayer/index.js +184 -0
  118. package/src/RowItem/SelectionLayer/style.css +21 -0
  119. package/src/RowItem/Sequence.js +269 -0
  120. package/src/RowItem/StackedAnnotations/PointedAnnotation.js +347 -0
  121. package/src/RowItem/StackedAnnotations/getStructuredBases.js +97 -0
  122. package/src/RowItem/StackedAnnotations/index.js +182 -0
  123. package/src/RowItem/StackedAnnotations/primerBases.js +218 -0
  124. package/src/RowItem/StackedAnnotations/style.css +14 -0
  125. package/src/RowItem/Translations/AASliver.js +190 -0
  126. package/src/RowItem/Translations/Translation.js +162 -0
  127. package/src/RowItem/Translations/index.js +54 -0
  128. package/src/RowItem/Translations/style.css +3 -0
  129. package/src/RowItem/constants.js +3 -0
  130. package/src/RowItem/getCutsiteLabelHeights.js +56 -0
  131. package/src/RowItem/getXStartAndWidthFromNonCircularRange.js +12 -0
  132. package/src/RowItem/getXStartAndWidthOfRangeWrtRow.js +27 -0
  133. package/src/RowItem/getXStartAndWidthOfRowAnnotation.js +19 -0
  134. package/src/RowItem/index.js +647 -0
  135. package/src/RowItem/partOverhangs.js +6 -0
  136. package/src/RowItem/style.css +103 -0
  137. package/src/RowItem/utils.js +32 -0
  138. package/src/RowView/estimateRowHeight.js +184 -0
  139. package/src/RowView/index.d.ts +10 -0
  140. package/src/RowView/index.js +554 -0
  141. package/src/RowView/style.css +12 -0
  142. package/src/SimpleCircularOrLinearView.js +379 -0
  143. package/src/SimpleOligoPreview.js +39 -0
  144. package/src/StatusBar/MeltingTemp.js +81 -0
  145. package/src/StatusBar/index.js +275 -0
  146. package/src/StatusBar/style.css +38 -0
  147. package/src/ToolBar/ToolbarItem.js +194 -0
  148. package/src/ToolBar/alignmentTool.js +503 -0
  149. package/src/ToolBar/array_move.js +10 -0
  150. package/src/ToolBar/cutsiteTool.js +88 -0
  151. package/src/ToolBar/downloadTool.js +38 -0
  152. package/src/ToolBar/editTool.js +26 -0
  153. package/src/ToolBar/featureTool.js +34 -0
  154. package/src/ToolBar/findTool.js +2 -0
  155. package/src/ToolBar/importTool.js +27 -0
  156. package/src/ToolBar/index.js +231 -0
  157. package/src/ToolBar/inlineFindTool.js +38 -0
  158. package/src/ToolBar/oligoTool.js +30 -0
  159. package/src/ToolBar/orfTool.js +141 -0
  160. package/src/ToolBar/partTool.js +47 -0
  161. package/src/ToolBar/printTool.js +31 -0
  162. package/src/ToolBar/redoTool.js +30 -0
  163. package/src/ToolBar/saveTool.js +48 -0
  164. package/src/ToolBar/style.css +138 -0
  165. package/src/ToolBar/undoTool.js +30 -0
  166. package/src/ToolBar/veToolbarIcons/find.png +0 -0
  167. package/src/ToolBar/veToolbarIcons/fullscreen.png +0 -0
  168. package/src/ToolBar/veToolbarIcons/linear.png +0 -0
  169. package/src/ToolBar/veToolbarIcons/pie.png +0 -0
  170. package/src/ToolBar/veToolbarIcons/print.png +0 -0
  171. package/src/ToolBar/veToolbarIcons/save.png +0 -0
  172. package/src/ToolBar/veToolbarIcons/show_cut_sites.png +0 -0
  173. package/src/ToolBar/veToolbarIcons/show_features.png +0 -0
  174. package/src/ToolBar/veToolbarIcons/show_orfs.png +0 -0
  175. package/src/ToolBar/veToolbarIcons/show_primers.png +0 -0
  176. package/src/ToolBar/veToolbarIcons/toggle_views.svg +1 -0
  177. package/src/ToolBar/versionHistoryTool.js +20 -0
  178. package/src/ToolBar/visibilityTool.js +39 -0
  179. package/src/VersionHistoryView/index.js +215 -0
  180. package/src/addAlignment.js +6 -0
  181. package/src/commands/getOveHotkeyDefs.js +12 -0
  182. package/src/commands/index.js +1585 -0
  183. package/src/constants/constants.js +2 -0
  184. package/src/constants/dnaToColor.js +17 -0
  185. package/src/constants/draggableClassnames.js +5 -0
  186. package/src/constants/findToolConstants.js +1 -0
  187. package/src/constants/orfFrameToColorMap.js +10 -0
  188. package/src/constants/rowviewContants.js +3 -0
  189. package/src/constants/specialCutsiteFilterOptions.js +22 -0
  190. package/src/constants.js +1 -0
  191. package/src/createVectorEditor/index.js +138 -0
  192. package/src/createVectorEditor/makeStore.js +34 -0
  193. package/src/fileUtils.js +103 -0
  194. package/src/helperComponents/AddOrEditAnnotationDialog/index.js +711 -0
  195. package/src/helperComponents/AddOrEditAnnotationDialog/style.css +11 -0
  196. package/src/helperComponents/AddOrEditFeatureDialog/index.js +58 -0
  197. package/src/helperComponents/AddOrEditPartDialog/index.js +101 -0
  198. package/src/helperComponents/AddOrEditPrimerDialog/EditCaretPosition.js +234 -0
  199. package/src/helperComponents/AddOrEditPrimerDialog/index.js +329 -0
  200. package/src/helperComponents/AddOrEditPrimerDialog/style.css +41 -0
  201. package/src/helperComponents/EnzymesDialog/index.js +904 -0
  202. package/src/helperComponents/EnzymesDialog/style.css +21 -0
  203. package/src/helperComponents/GoToDialog.js +21 -0
  204. package/src/helperComponents/MergeFeaturesDialog/index.js +253 -0
  205. package/src/helperComponents/MergeFeaturesDialog/style.css +3 -0
  206. package/src/helperComponents/MultipleSeqsDetectedOnImportDialog.js +74 -0
  207. package/src/helperComponents/PinchHelper/PinchHelper.js +24 -0
  208. package/src/helperComponents/PrintDialog/index.js +396 -0
  209. package/src/helperComponents/PrintDialog/style.css +4 -0
  210. package/src/helperComponents/PropertiesDialog/ColorPicker.js +30 -0
  211. package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +185 -0
  212. package/src/helperComponents/PropertiesDialog/FeatureProperties.js +6 -0
  213. package/src/helperComponents/PropertiesDialog/GenbankView.js +74 -0
  214. package/src/helperComponents/PropertiesDialog/GeneralProperties.js +140 -0
  215. package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +406 -0
  216. package/src/helperComponents/PropertiesDialog/OrfProperties.js +117 -0
  217. package/src/helperComponents/PropertiesDialog/PartProperties.js +9 -0
  218. package/src/helperComponents/PropertiesDialog/PrimerProperties.js +19 -0
  219. package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +131 -0
  220. package/src/helperComponents/PropertiesDialog/TranslationProperties.js +149 -0
  221. package/src/helperComponents/PropertiesDialog/index.js +166 -0
  222. package/src/helperComponents/PropertiesDialog/style.css +68 -0
  223. package/src/helperComponents/PropertiesDialog/typeField.js +24 -0
  224. package/src/helperComponents/PropertiesDialog/utils.js +37 -0
  225. package/src/helperComponents/RemoveDuplicates/index.js +194 -0
  226. package/src/helperComponents/RenameSequenceDialog.js +7 -0
  227. package/src/helperComponents/SelectDialog.js +150 -0
  228. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.css +5 -0
  229. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.js +134 -0
  230. package/src/helperComponents/VeWarning/index.js +22 -0
  231. package/src/helperComponents/VeWarning/style.css +10 -0
  232. package/src/helperComponents/createSimpleDialog.js +89 -0
  233. package/src/helperComponents/partTagSearch.js +72 -0
  234. package/src/helperComponents/simpleDialog.css +13 -0
  235. package/src/helperComponents/withHover.js +90 -0
  236. package/src/index.js +60 -0
  237. package/src/redux/alignments.js +373 -0
  238. package/src/redux/annotationLabelVisibility.js +53 -0
  239. package/src/redux/annotationVisibility.js +196 -0
  240. package/src/redux/annotationsToSupport.js +104 -0
  241. package/src/redux/caretPosition.js +27 -0
  242. package/src/redux/charWidth.js +22 -0
  243. package/src/redux/copyOptions.js +34 -0
  244. package/src/redux/createYourOwnEnzyme.js +39 -0
  245. package/src/redux/deletionLayers.js +36 -0
  246. package/src/redux/digestTool.js +34 -0
  247. package/src/redux/featureLengthsToHide.js +27 -0
  248. package/src/redux/findTool.js +79 -0
  249. package/src/redux/frameTranslations.js +52 -0
  250. package/src/redux/hoveredAnnotation.js +24 -0
  251. package/src/redux/index.js +196 -0
  252. package/src/redux/labelLineIntensity.js +25 -0
  253. package/src/redux/labelSize.js +23 -0
  254. package/src/redux/lastSavedId.js +20 -0
  255. package/src/redux/middleware.js +112 -0
  256. package/src/redux/minimumOrfSize.js +24 -0
  257. package/src/redux/modalActions.js +3 -0
  258. package/src/redux/panelsShown.js +273 -0
  259. package/src/redux/partLengthsToHide.js +23 -0
  260. package/src/redux/primerLengthsToHide.js +27 -0
  261. package/src/redux/propertiesTool.js +40 -0
  262. package/src/redux/readOnly.js +28 -0
  263. package/src/redux/replacementLayers.js +36 -0
  264. package/src/redux/restrictionEnzymes.js +52 -0
  265. package/src/redux/selectedAnnotations.js +89 -0
  266. package/src/redux/selectedPartTags.js +21 -0
  267. package/src/redux/selectionLayer.js +46 -0
  268. package/src/redux/sequenceData/circular.js +19 -0
  269. package/src/redux/sequenceData/description.js +21 -0
  270. package/src/redux/sequenceData/features.js +19 -0
  271. package/src/redux/sequenceData/index.js +81 -0
  272. package/src/redux/sequenceData/lineageLines.js +11 -0
  273. package/src/redux/sequenceData/materiallyAvailable.js +19 -0
  274. package/src/redux/sequenceData/name.js +19 -0
  275. package/src/redux/sequenceData/parts.js +19 -0
  276. package/src/redux/sequenceData/primers.js +19 -0
  277. package/src/redux/sequenceData/sequence.js +12 -0
  278. package/src/redux/sequenceData/sharedActionCreators.js +0 -0
  279. package/src/redux/sequenceData/translations.js +20 -0
  280. package/src/redux/sequenceData/upsertDeleteActionGenerator.js +31 -0
  281. package/src/redux/sequenceDataHistory.js +43 -0
  282. package/src/redux/showGCContent.js +23 -0
  283. package/src/redux/toolBar.js +25 -0
  284. package/src/redux/uppercaseSequenceMapFont.js +25 -0
  285. package/src/redux/useAdditionalOrfStartCodons.js +24 -0
  286. package/src/redux/utils/addDashesForMatchStartAndEndForTracks/index.js +71 -0
  287. package/src/redux/utils/addMetaToActionCreators.js +12 -0
  288. package/src/redux/utils/createMergedDefaultStateReducer.js +30 -0
  289. package/src/redux/utils/createMetaAction.js +12 -0
  290. package/src/redux/versionHistory.js +27 -0
  291. package/src/selectors/annotationLabelVisibility.js +2 -0
  292. package/src/selectors/annotationSearchSelector.js +24 -0
  293. package/src/selectors/cdsFeaturesSelector.js +9 -0
  294. package/src/selectors/circularSelector.js +4 -0
  295. package/src/selectors/cutsiteLabelColorSelector.js +6 -0
  296. package/src/selectors/cutsitesByRangeSelector.js +5 -0
  297. package/src/selectors/cutsitesSelector.js +61 -0
  298. package/src/selectors/editorSelector.js +2 -0
  299. package/src/selectors/featuresSelector.js +8 -0
  300. package/src/selectors/filteredCutsitesSelector.js +137 -0
  301. package/src/selectors/filteredFeaturesSelector.js +32 -0
  302. package/src/selectors/filteredPartsSelector.js +57 -0
  303. package/src/selectors/filteredPrimersSelector.js +27 -0
  304. package/src/selectors/filteredRestrictionEnzymesSelector.js +1 -0
  305. package/src/selectors/getAdditionalEnzymesSelector.js +46 -0
  306. package/src/selectors/index.js +41 -0
  307. package/src/selectors/isEnzymeFilterAndSelector.js +1 -0
  308. package/src/selectors/minimumOrfSizeSelector.js +2 -0
  309. package/src/selectors/orfsSelector.js +15 -0
  310. package/src/selectors/partsSelector.js +8 -0
  311. package/src/selectors/primersSelector.js +8 -0
  312. package/src/selectors/restrictionEnzymesSelector.js +34 -0
  313. package/src/selectors/searchLayersSelector.js +71 -0
  314. package/src/selectors/selectedAnnotationsSelector.js +1 -0
  315. package/src/selectors/selectedCutsitesSelector.js +21 -0
  316. package/src/selectors/sequenceDataSelector.js +2 -0
  317. package/src/selectors/sequenceLengthSelector.js +5 -0
  318. package/src/selectors/sequenceSelector.js +4 -0
  319. package/src/selectors/tagsToBoldSelector.js +2 -0
  320. package/src/selectors/translationSearchMatchesSelector.js +14 -0
  321. package/src/selectors/translationsRawSelector.js +8 -0
  322. package/src/selectors/translationsSelector.js +137 -0
  323. package/src/style.css +82 -0
  324. package/src/updateEditor.js +198 -0
  325. package/src/utils/PassThrough.js +3 -0
  326. package/src/utils/addWrappedAddons.js +20 -0
  327. package/src/utils/annotationTypes.js +37 -0
  328. package/src/utils/arrayUtils.js +19 -0
  329. package/src/utils/calculateTickMarkPositionsForGivenRange.js +47 -0
  330. package/src/utils/cleanSequenceData_DEPRECATED/arrayToObjWithIds.js +17 -0
  331. package/src/utils/combineReducersDontIgnoreKeys.js +12 -0
  332. package/src/utils/commandUtils.js +18 -0
  333. package/src/utils/editorUtils.js +223 -0
  334. package/src/utils/getAnnotationClassnames.js +12 -0
  335. package/src/utils/getAnnotationNameAndStartStopString.js +61 -0
  336. package/src/utils/getVisibleStartEnd.js +7 -0
  337. package/src/utils/massageTickSpacing.js +19 -0
  338. package/src/utils/onlyUpdateForKeysDeep.js +31 -0
  339. package/src/utils/prepareRowData.js +64 -0
  340. package/src/utils/proteinUtils.js +3 -0
  341. package/src/utils/pureNoFunc.js +18 -0
  342. package/src/utils/selectionLayer.js +25 -0
  343. package/src/utils/shouldRerender.js +27 -0
  344. package/src/utils/showFileDialog.js +26 -0
  345. package/src/utils/updateLabelsForInViewFeatures.js +55 -0
  346. package/src/utils/updateLabelsForInViewFeaturesCircView.js +41 -0
  347. package/src/utils/useAAColorType.js +8 -0
  348. package/src/utils/useAnnotationLimits.js +42 -0
  349. package/src/utils/useChromatogramPrefs.js +31 -0
  350. package/src/utils/useLadders.js +6 -0
  351. package/src/utils/useMeltingTemp.js +7 -0
  352. package/src/utils/useTmType.js +10 -0
  353. package/src/withEditorInteractions/Keyboard.js +86 -0
  354. package/src/withEditorInteractions/clickAndDragUtils.js +576 -0
  355. package/src/withEditorInteractions/createSequenceInputPopup.js +296 -0
  356. package/src/withEditorInteractions/createSequenceInputPopupStyle.css +85 -0
  357. package/src/withEditorInteractions/getBpsPerRow.js +19 -0
  358. package/src/withEditorInteractions/index.js +1252 -0
  359. package/src/withEditorInteractions/isElementInViewport.js +29 -0
  360. package/src/withEditorInteractions/moveCaret.js +58 -0
  361. package/src/withEditorProps/index.js +1010 -0
  362. package/index.mjs +0 -193228
@@ -0,0 +1,198 @@
1
+ import { set } from "lodash";
2
+ import { tidyUpSequenceData } from "@teselagen/sequence-utils";
3
+ import { annotationTypes } from "@teselagen/sequence-utils";
4
+
5
+ export default function updateEditor(
6
+ store,
7
+ editorName,
8
+ initialValues = {},
9
+ extraMeta = {},
10
+ { convertAnnotationsFromAAIndices } = {}
11
+ ) {
12
+ const {
13
+ sequenceData,
14
+ annotationVisibility,
15
+ annotationsToSupport,
16
+ findTool,
17
+ justPassingPartialSeqData
18
+ } = initialValues;
19
+ const currentEditor = store.getState().VectorEditor[editorName] || {};
20
+ const isAlreadyProteinEditor =
21
+ currentEditor.sequenceData && currentEditor.sequenceData.isProtein;
22
+ const isAlreadyRnaEditor =
23
+ currentEditor.sequenceData && currentEditor.sequenceData.isRna;
24
+ const isAlreadyOligoEditor =
25
+ currentEditor.sequenceData && currentEditor.sequenceData.isOligo;
26
+ const reverseSequenceShouldBeUpdate =
27
+ currentEditor.sequenceData?.isSingleStrandedDNA !==
28
+ sequenceData?.isSingleStrandedDNA;
29
+
30
+ const isAlreadySpecialEditor =
31
+ isAlreadyProteinEditor ||
32
+ isAlreadyRnaEditor ||
33
+ isAlreadyOligoEditor ||
34
+ reverseSequenceShouldBeUpdate;
35
+
36
+ let toSpread = {};
37
+ let payload;
38
+ if (justPassingPartialSeqData) {
39
+ payload = {
40
+ sequenceData: tidyUpSequenceData(
41
+ { ...currentEditor.sequenceData, ...sequenceData },
42
+ {
43
+ convertAnnotationsFromAAIndices,
44
+ //if we have sequence data coming in make sure to tidy it up for the user :)
45
+ annotationsAsObjects: true
46
+ }
47
+ )
48
+ };
49
+ } else {
50
+ if (sequenceData) {
51
+ const isDna =
52
+ !sequenceData.isOligo && !sequenceData.isRna && !sequenceData.isProtein;
53
+ if (sequenceData.isProtein && !isAlreadyProteinEditor) {
54
+ //we're editing a protein but haven't initialized the protein editor yet
55
+ toSpread = {
56
+ findTool: {
57
+ dnaOrAA: "AA",
58
+ ...findTool //we spread this here to allow the user to override this .. if they must!
59
+ },
60
+
61
+ annotationVisibility: {
62
+ caret: true,
63
+ ...annotationVisibility, //we spread this here to allow the user to override this .. if they must!
64
+ sequence: false,
65
+ reverseSequence: false,
66
+ cutsites: false,
67
+ translations: false,
68
+ aminoAcidNumbers: false,
69
+ primaryProteinSequence: true
70
+ },
71
+ annotationsToSupport: {
72
+ features: true,
73
+ translations: false,
74
+ primaryProteinSequence: true,
75
+ parts: true,
76
+ orfs: false,
77
+ cutsites: false,
78
+ primers: false,
79
+ ...annotationsToSupport
80
+ }
81
+ };
82
+ } else if (sequenceData.isOligo && !isAlreadyOligoEditor) {
83
+ toSpread = {
84
+ findTool: {
85
+ dnaOrAA: "DNA",
86
+ ...findTool //we spread this here to allow the user to override this .. if they must!
87
+ },
88
+ annotationVisibility: {
89
+ caret: true,
90
+ ...annotationVisibility, //we spread this here to allow the user to override this .. if they must!
91
+ sequence: true,
92
+ cutsites: false,
93
+ reverseSequence: false,
94
+ translations: false,
95
+ aminoAcidNumbers: false,
96
+ primaryProteinSequence: false
97
+ },
98
+ annotationsToSupport: {
99
+ features: true,
100
+ translations: true,
101
+ primaryProteinSequence: false,
102
+ parts: true,
103
+ orfs: false,
104
+ cutsites: true,
105
+ primers: false,
106
+ ...annotationsToSupport //we spread this here to allow the user to override this .. if they must!
107
+ }
108
+ };
109
+ } else if (sequenceData.isRna && !isAlreadyRnaEditor) {
110
+ toSpread = {
111
+ findTool: {
112
+ dnaOrAA: "DNA",
113
+ ...findTool //we spread this here to allow the user to override this .. if they must!
114
+ },
115
+ annotationVisibility: {
116
+ caret: true,
117
+ ...annotationVisibility, //we spread this here to allow the user to override this .. if they must!
118
+ sequence: true,
119
+ cutsites: false,
120
+ reverseSequence: false,
121
+ translations: false,
122
+ aminoAcidNumbers: false,
123
+ primaryProteinSequence: false
124
+ },
125
+ annotationsToSupport: {
126
+ features: true,
127
+ translations: true,
128
+ primaryProteinSequence: false,
129
+ parts: true,
130
+ orfs: true,
131
+ cutsites: true,
132
+ primers: true,
133
+ ...annotationsToSupport //we spread this here to allow the user to override this .. if they must!
134
+ }
135
+ };
136
+ } else if (isAlreadySpecialEditor && isDna) {
137
+ //we're editing dna but haven't initialized the dna editor yet
138
+ sequenceData.isProtein = false;
139
+ toSpread = {
140
+ findTool: {
141
+ dnaOrAA: "DNA",
142
+ ...findTool //we spread this here to allow the user to override this .. if they must!
143
+ },
144
+ annotationVisibility: {
145
+ caret: true,
146
+ ...annotationVisibility, //we spread this here to allow the user to override this .. if they must!
147
+ sequence: true,
148
+ reverseSequence: !sequenceData?.isSingleStrandedDNA,
149
+ translations: false,
150
+ aminoAcidNumbers: false,
151
+ primaryProteinSequence: false
152
+ },
153
+ annotationsToSupport: {
154
+ features: true,
155
+ translations: true,
156
+ primaryProteinSequence: false,
157
+ parts: true,
158
+ orfs: true,
159
+ cutsites: true,
160
+ primers: true,
161
+ ...annotationsToSupport //we spread this here to allow the user to override this .. if they must!
162
+ }
163
+ };
164
+ }
165
+ }
166
+ payload = {
167
+ ...initialValues,
168
+ ...toSpread,
169
+ ...(sequenceData && {
170
+ sequenceData: tidyUpSequenceData(sequenceData, {
171
+ convertAnnotationsFromAAIndices,
172
+ //if we have sequence data coming in make sure to tidy it up for the user :)
173
+ annotationsAsObjects: true
174
+ })
175
+ })
176
+ };
177
+ }
178
+ annotationTypes.forEach((t) => {
179
+ if (Object.keys(sequenceData?.[t] || {}).length > 100) {
180
+ set(payload, `annotationLabelVisibility.${t}`, false);
181
+ }
182
+ });
183
+ if (sequenceData && sequenceData.size > 20000) {
184
+ set(payload, "annotationVisibility.translations", false);
185
+ set(payload, "annotationVisibility.cutsites", false);
186
+ }
187
+
188
+ store.dispatch({
189
+ type: "VECTOR_EDITOR_UPDATE",
190
+ payload,
191
+ meta: {
192
+ mergeStateDeep: true,
193
+ editorName,
194
+ disregardUndo: true,
195
+ ...extraMeta
196
+ }
197
+ });
198
+ }
@@ -0,0 +1,3 @@
1
+ export default function({ children }) {
2
+ return children;
3
+ }
@@ -0,0 +1,20 @@
1
+ import { flatMap } from "lodash";
2
+ import { normalizePositionByRangeLength } from "@teselagen/range-utils";
3
+
4
+ export function addWrappedAddons(anns, seqLen) {
5
+ return flatMap(anns, (ann) => {
6
+ if (ann.overlapsSelf) {
7
+ return [
8
+ ann,
9
+ {
10
+ ...ann,
11
+ start: normalizePositionByRangeLength(ann.end + 1, seqLen),
12
+ end: normalizePositionByRangeLength(ann.start - 1, seqLen),
13
+ isWrappedAddon: true,
14
+ rangeTypeOverride: "middle" //we add this rangeTypeOverride here to get the wrapping piece to draw differently than normal
15
+ }
16
+ ];
17
+ }
18
+ return [ann];
19
+ });
20
+ }
@@ -0,0 +1,37 @@
1
+ export const userDefinedTypes = [
2
+ "parts",
3
+ "features",
4
+ "translations",
5
+ "primers"
6
+ ];
7
+
8
+ export const userDefinedTypesMap = userDefinedTypes.reduce(function(
9
+ nextVal,
10
+ key
11
+ ) {
12
+ nextVal[key] = key;
13
+ return nextVal;
14
+ // looks like this:
15
+ //{
16
+ // parts: 'parts',
17
+ // features: 'features',
18
+ // translations: 'translations',
19
+ // primers: 'primers',
20
+ // }
21
+ },
22
+ {});
23
+
24
+ export const derivedDataTypes = ["cutsites", "orfs"];
25
+ export const derivedDataTypesMap = derivedDataTypes.reduce(function(
26
+ nextVal,
27
+ key
28
+ ) {
29
+ nextVal[key] = key;
30
+ return nextVal;
31
+ },
32
+ {});
33
+ export function getSingular(type) {
34
+ return type.slice(0, -1);
35
+ }
36
+
37
+ export const allTypes = [...userDefinedTypes, ...derivedDataTypes];
@@ -0,0 +1,19 @@
1
+ export function insertItem(array, item, index) {
2
+ return [...array.slice(0, index), item, ...array.slice(index)];
3
+ }
4
+
5
+ export function removeItem(array, i) {
6
+ return array.filter((_, j) => j !== Number(i));
7
+ }
8
+
9
+ export function getLowerCaseObj(obj = {}) {
10
+ let key;
11
+ const keys = Object.keys(obj);
12
+ let n = keys.length;
13
+ const newobj = {};
14
+ while (n--) {
15
+ key = keys[n];
16
+ newobj[key.toLowerCase()] = obj[key];
17
+ }
18
+ return newobj;
19
+ }
@@ -0,0 +1,47 @@
1
+ import { normalizePositionByRangeLength as norm } from "@teselagen/range-utils";
2
+ import { getRangeLength } from "@teselagen/range-utils";
3
+
4
+ export default function calculateTickMarkPositionsForGivenRange({
5
+ tickSpacing: _tickSpacing = 10,
6
+ range,
7
+ sequenceLength,
8
+ isProtein,
9
+ increaseOffset
10
+ }) {
11
+ if (sequenceLength === 0) {
12
+ return [];
13
+ }
14
+ let tickSpacing = _tickSpacing;
15
+ if (isProtein) {
16
+ tickSpacing = Math.floor((_tickSpacing / 2) * 3);
17
+ }
18
+
19
+ const rangeLength = getRangeLength(range, sequenceLength);
20
+
21
+ let spacer = 0;
22
+ if (increaseOffset) {
23
+ spacer = range.start;
24
+ }
25
+ const firstTickOffsetFromRangeStart =
26
+ spacer + tickSpacing - (range.start % tickSpacing);
27
+
28
+ const tickMarks = [];
29
+ if (range.start === 0) tickMarks.push(isProtein ? 2 : 0);
30
+ let hasCrossedOrigin;
31
+ for (
32
+ let tick = firstTickOffsetFromRangeStart - 1;
33
+ tick < spacer + rangeLength;
34
+ tick += tickSpacing
35
+ ) {
36
+ let normed = norm(tick, sequenceLength);
37
+ if (!hasCrossedOrigin && normed < tick) {
38
+ if (!(normed % 10) && normed !== 0) {
39
+ tick = tick - 1;
40
+ normed = normed - 1;
41
+ }
42
+ if (normed !== 0) hasCrossedOrigin = true;
43
+ }
44
+ tickMarks.push(normed);
45
+ }
46
+ return tickMarks;
47
+ }
@@ -0,0 +1,17 @@
1
+ //helper function to make sure any arrays coming in
2
+
3
+ import shortid from "shortid";
4
+
5
+ //get converted to objects with unique ids
6
+ export default function arrayToObjWithIds(array) {
7
+ const newObj = {};
8
+ array.forEach(function (item) {
9
+ const newItem = {
10
+ ...item,
11
+ id: item.id || shortid()
12
+ };
13
+ newObj[newItem.id] = newItem;
14
+ });
15
+
16
+ return newObj;
17
+ }
@@ -0,0 +1,12 @@
1
+ export default function combineReducersDontIgnoreKeys(reducers) {
2
+ return function(state = {}, action) {
3
+ const newState = Object.keys(reducers).reduce((acc, key) => {
4
+ acc[key] = reducers[key](state[key], action);
5
+ return acc;
6
+ }, {});
7
+ return {
8
+ ...state,
9
+ ...newState
10
+ };
11
+ };
12
+ }
@@ -0,0 +1,18 @@
1
+ import { genericCommandFactory } from "@teselagen/ui";
2
+ import { noop } from "lodash";
3
+
4
+ export function oveCommandFactory(instance, commandDefs) {
5
+ return genericCommandFactory({
6
+ getArguments(cmdId, [ctxInfo]) {
7
+ const args = [instance.props];
8
+ const { store, editorName } = instance.props;
9
+ if (store && editorName) {
10
+ args.push(store.getState().VectorEditor[editorName]);
11
+ }
12
+ args.push(ctxInfo);
13
+ return args;
14
+ },
15
+ handleReturn: noop,
16
+ commandDefs
17
+ });
18
+ }
@@ -0,0 +1,223 @@
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
+ bioData,
8
+ aliasedEnzymesByName
9
+ } from "@teselagen/sequence-utils";
10
+ import { get, sortBy } from "lodash";
11
+ import VeWarning from "../helperComponents/VeWarning";
12
+ import { normalizePositionByRangeLength } from "@teselagen/range-utils";
13
+ import { filter } from "lodash";
14
+
15
+ export function getSelectionMessage({
16
+ caretPosition = -1,
17
+ selectionLayer = { start: -1, end: -1 },
18
+ customTitle,
19
+ sequenceLength,
20
+ sequenceData,
21
+ showGCContent, //these are only passed in for the status bar
22
+ GCDecimalDigits, //these are only passed in for the status bar
23
+ isProtein
24
+ }) {
25
+ let _selectionLayer = selectionLayer;
26
+ const isSelecting = selectionLayer.start > -1;
27
+ if (isSelecting) {
28
+ _selectionLayer = getSelFromWrappedAddon(selectionLayer, sequenceLength);
29
+ const length = getRangeLength(_selectionLayer, sequenceLength);
30
+ const GCContent = (numDecimalDigits = 0) =>
31
+ calculatePercentGC(
32
+ getSequenceWithinRange(_selectionLayer, sequenceData.sequence)
33
+ ).toFixed(numDecimalDigits);
34
+ const seqLen = divideBy3(length, isProtein);
35
+ return `${customTitle || "Selecting"} ${seqLen} ${
36
+ (isProtein ? "AA" : "bp") + (seqLen === 1 ? "" : "s")
37
+ } from ${divideBy3(_selectionLayer.start, isProtein) + 1} to ${divideBy3(
38
+ _selectionLayer.end + 1,
39
+ isProtein
40
+ )}${
41
+ showGCContent && !isProtein ? ` (${GCContent(GCDecimalDigits)}% GC)` : ""
42
+ }`;
43
+ } else if (caretPosition > -1) {
44
+ const insertBetween = getInsertBetweenVals(
45
+ caretPosition,
46
+ _selectionLayer,
47
+ sequenceLength
48
+ );
49
+ return (
50
+ `Caret Between ` +
51
+ (isProtein
52
+ ? `AAs ${divideBy3(insertBetween[0], true)} and ${divideBy3(
53
+ insertBetween[1] + 2,
54
+ true
55
+ )}`
56
+ : `Bases ${insertBetween[0]} and ${insertBetween[1]}`)
57
+ );
58
+ } else {
59
+ return "No Selection";
60
+ }
61
+ }
62
+
63
+ export function preventDefaultStopPropagation(e) {
64
+ if (e) {
65
+ e.stopPropagation();
66
+ e.preventDefault();
67
+ }
68
+ }
69
+
70
+ export function getNodeToRefocus(caretEl) {
71
+ let nodeToReFocus;
72
+ if (
73
+ caretEl &&
74
+ caretEl.closest &&
75
+ caretEl.closest(".veVectorInteractionWrapper")
76
+ ) {
77
+ nodeToReFocus = caretEl.closest(".veVectorInteractionWrapper");
78
+ }
79
+ return nodeToReFocus;
80
+ }
81
+
82
+ export function getEmptyText({ sequenceData, caretPosition }) {
83
+ return sequenceData.sequence.length === 0 && caretPosition === -1 ? (
84
+ <div className="veEmptySeqText">Insert Sequence Here</div>
85
+ ) : null;
86
+ }
87
+
88
+ export function tryToRefocusEditor() {
89
+ const ed = document.querySelector(".veVectorInteractionWrapper");
90
+ ed && ed.focus();
91
+ }
92
+ export function getCustomEnzymes() {
93
+ try {
94
+ const customEnzymes = JSON.parse(
95
+ window.localStorage.getItem("customEnzymes") || "{}"
96
+ );
97
+ return customEnzymes;
98
+ } catch (error) {
99
+ return {};
100
+ }
101
+ }
102
+ export function addCustomEnzyme(newEnz) {
103
+ const customEnzymes = getCustomEnzymes();
104
+ window.localStorage.setItem(
105
+ "customEnzymes",
106
+ JSON.stringify({
107
+ ...customEnzymes,
108
+ [newEnz.name.toLowerCase()]: newEnz
109
+ })
110
+ );
111
+ }
112
+
113
+ export function pareDownAnnotations(annotations, max) {
114
+ let annotationsToPass = annotations;
115
+ let paredDown = false;
116
+ if (Object.keys(annotations).length > max) {
117
+ paredDown = true;
118
+ const sortedAnnotations = sortBy(annotations, function (annotation) {
119
+ return -getRangeLength(annotation);
120
+ });
121
+ annotationsToPass = sortedAnnotations
122
+ .slice(0, max)
123
+ .reduce(function (obj, item) {
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 getAcceptedChars({
175
+ isOligo,
176
+ isProtein,
177
+ isRna,
178
+ isMixedRnaAndDna
179
+ } = {}) {
180
+ return isProtein
181
+ ? bioData.extended_protein_letters.toLowerCase()
182
+ : isOligo
183
+ ? bioData.ambiguous_rna_letters.toLowerCase() + "t"
184
+ : isRna
185
+ ? bioData.ambiguous_rna_letters.toLowerCase()
186
+ : isMixedRnaAndDna
187
+ ? bioData.ambiguous_rna_letters.toLowerCase() +
188
+ bioData.ambiguous_dna_letters.toLowerCase()
189
+ : //just plain old dna
190
+ bioData.ambiguous_dna_letters.toLowerCase();
191
+ }
192
+ export function getStripedPattern({ color }) {
193
+ return (
194
+ <pattern
195
+ id="diagonalHatch"
196
+ patternUnits="userSpaceOnUse"
197
+ width="4"
198
+ height="4"
199
+ >
200
+ <path
201
+ d="M-1,1 l2,-2
202
+ M0,4 l4,-4
203
+ M3,5 l2,-2"
204
+ style={{
205
+ stroke: color,
206
+ strokeWidth: 2,
207
+ fill: "blue",
208
+ opacity: 0.4
209
+ }}
210
+ />
211
+ </pattern>
212
+ );
213
+ }
214
+ export const getEnzymeAliases = (enzyme) => {
215
+ let lowerName = (enzyme.name && enzyme.name.toLowerCase()) || "";
216
+ if (typeof enzyme === "string") {
217
+ lowerName = enzyme.toLowerCase();
218
+ }
219
+ return filter(
220
+ (aliasedEnzymesByName[lowerName] || {}).aliases,
221
+ (n) => n.toLowerCase() !== lowerName //filter out current enzyme
222
+ );
223
+ };
@@ -0,0 +1,12 @@
1
+ import classnames from "classnames";
2
+ import { upperFirst } from "lodash";
3
+
4
+ export default function getAnnotationClassnames(
5
+ { overlapsSelf },
6
+ { viewName, type }
7
+ ) {
8
+ const Type = upperFirst(type);
9
+ return classnames(`ve${Type}`, `ve${viewName}${Type}`, {
10
+ overlapsSelf
11
+ });
12
+ }
@@ -0,0 +1,61 @@
1
+ import { upperFirst } from "lodash";
2
+ import { getSingular } from "./annotationTypes";
3
+
4
+ export default function getAnnotationNameAndStartStopString(
5
+ {
6
+ name,
7
+ start,
8
+ end,
9
+ type,
10
+ message,
11
+ annotationTypePlural,
12
+ overlapsSelf,
13
+ isWrappedAddon
14
+ },
15
+ { startText, isProtein, readOnly } = {}
16
+ ) {
17
+ const typeToUse = (() => {
18
+ if (annotationTypePlural) {
19
+ const singularKey = getSingular(annotationTypePlural);
20
+ if (singularKey === "cutsite") {
21
+ return (
22
+ "Cut site" + (annotationTypePlural === "features" ? ` (${type})` : "")
23
+ );
24
+ }
25
+ if (singularKey === "orf") {
26
+ return (
27
+ "ORF" + (annotationTypePlural === "features" ? ` (${type})` : "")
28
+ );
29
+ }
30
+ return (
31
+ upperFirst(getSingular(annotationTypePlural)) +
32
+ (annotationTypePlural === "features" ? ` (${type})` : "")
33
+ );
34
+ }
35
+ return "";
36
+ })();
37
+
38
+ if (isWrappedAddon) {
39
+ const oldEnd = end;
40
+ end = start - 1;
41
+ start = oldEnd + 1;
42
+ }
43
+ return `${startText ? startText : ""} ${typeToUse ? typeToUse + " -" : ""} ${
44
+ name ? name : ""
45
+ } - Start: ${isProtein ? (start + 3) / 3 : start + 1} End: ${
46
+ isProtein ? (end + 1) / 3 : end + 1
47
+ } ${overlapsSelf ? "(Overlaps Self) " : ""}${message ? "\n" + message : ""} ${
48
+ readOnly
49
+ ? ""
50
+ : annotationTypePlural === "cutsites"
51
+ ? `
52
+
53
+ click --> top cut position
54
+ alt/option+click --> bottom cut position
55
+ cmd/ctrl+click --> recognition range`
56
+ : `
57
+
58
+ alt/option+click --> jump row view to start/end
59
+ double click --> edit`
60
+ }`;
61
+ }
@@ -0,0 +1,7 @@
1
+ export function getVisibleStartEnd({ scrollData, width }) {
2
+ const { percentScrolled, viewportWidth } = scrollData;
3
+
4
+ const visibleStart = percentScrolled * (width - viewportWidth);
5
+ const visibleEnd = visibleStart + viewportWidth;
6
+ return { visibleEnd, visibleStart };
7
+ }