@teselagen/ove 0.8.35 → 0.8.37
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.
- package/RowItem/utils.d.ts +1 -1
- package/StatusBar/index.d.ts +9 -9
- package/helperComponents/PropertiesDialog/utils.d.ts +2 -2
- package/index.cjs.js +222 -166
- package/index.d.ts +1 -1
- package/index.es.js +222 -166
- package/index.umd.js +275 -219
- package/package.json +8 -6
- package/src/Editor/index.js +0 -1
- package/src/RowItem/utils.js +41 -8
- package/src/StatusBar/index.js +1 -1
- package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +7 -3
- package/src/helperComponents/PropertiesDialog/OrfProperties.js +1 -1
- package/src/helperComponents/PropertiesDialog/utils.js +6 -13
- package/src/helperComponents/RemoveDuplicates/index.js +16 -8
- package/src/index.js +1 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/ove",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.37",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/TeselaGen/tg-oss",
|
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
"@teselagen/range-utils": "0.3.20",
|
|
21
21
|
"@teselagen/react-list": "0.8.18",
|
|
22
22
|
"@teselagen/sequence-utils": "0.3.42",
|
|
23
|
-
"@teselagen/ui": "0.10.
|
|
23
|
+
"@teselagen/ui": "0.10.20",
|
|
24
24
|
"@use-gesture/react": "10.3.0",
|
|
25
|
-
"biomsa": "^0.2.4",
|
|
26
25
|
"classnames": "^2.3.2",
|
|
27
26
|
"clipboard": "^2.0.11",
|
|
28
27
|
"color": "^3.2.1",
|
|
@@ -47,7 +46,6 @@
|
|
|
47
46
|
"react-dom": "^18.3.1",
|
|
48
47
|
"react-draggable": "4.4.5",
|
|
49
48
|
"react-dropzone": "^11.4.2",
|
|
50
|
-
"react-markdown": "9.0.1",
|
|
51
49
|
"react-measure": "^2.5.2",
|
|
52
50
|
"react-redux": "^8.0.5",
|
|
53
51
|
"react-sizeme": "^2.6.12",
|
|
@@ -56,12 +54,16 @@
|
|
|
56
54
|
"redux-act": "^1.8.0",
|
|
57
55
|
"redux-form": "^8.3.10",
|
|
58
56
|
"redux-thunk": "2.4.1",
|
|
59
|
-
"remark-gfm": "^4.0.0",
|
|
60
57
|
"reselect": "^4.1.7",
|
|
61
58
|
"shortid": "2.2.16",
|
|
62
59
|
"tg-use-local-storage-state": "^16.0.3",
|
|
63
|
-
"to-regex-range": "5.0.1",
|
|
64
60
|
"use-debounce": "^8.0.4",
|
|
65
61
|
"validate.io-nonnegative-integer-array": "^1.0.1"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"biomsa": "^0.2.4",
|
|
65
|
+
"react-markdown": "9.0.1",
|
|
66
|
+
"remark-gfm": "^4.0.0",
|
|
67
|
+
"to-regex-range": "5.0.1"
|
|
66
68
|
}
|
|
67
69
|
}
|
package/src/Editor/index.js
CHANGED
package/src/RowItem/utils.js
CHANGED
|
@@ -1,16 +1,48 @@
|
|
|
1
1
|
import { ANNOTATION_LABEL_FONT_WIDTH } from "./constants";
|
|
2
2
|
import { getWidth } from "./getXStartAndWidthOfRowAnnotation";
|
|
3
3
|
|
|
4
|
-
// Cache canvas context for text measurement
|
|
4
|
+
// Cache canvas context and computed font size for text measurement
|
|
5
5
|
let measureCanvas;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
let cachedFontSize = null;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the computed font size for the ve-monospace-font class
|
|
10
|
+
*/
|
|
11
|
+
function getVeMonospaceFontSize() {
|
|
12
|
+
if (cachedFontSize !== null) {
|
|
13
|
+
return cachedFontSize;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Create a temporary element to measure the computed font size
|
|
17
|
+
const tempElement = document.createElement("div");
|
|
18
|
+
tempElement.className = "ve-monospace-font";
|
|
19
|
+
tempElement.style.position = "absolute";
|
|
20
|
+
tempElement.style.visibility = "hidden";
|
|
21
|
+
tempElement.style.pointerEvents = "none";
|
|
22
|
+
document.body.appendChild(tempElement);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const computedStyle = window.getComputedStyle(tempElement);
|
|
26
|
+
const fontSize = parseFloat(computedStyle.fontSize);
|
|
27
|
+
cachedFontSize = fontSize || ANNOTATION_LABEL_FONT_WIDTH; // fallback to 10px if parsing fails
|
|
28
|
+
return cachedFontSize;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.warn(
|
|
31
|
+
"Failed to compute ve-monospace-font size, using fallback",
|
|
32
|
+
error
|
|
33
|
+
);
|
|
34
|
+
cachedFontSize = ANNOTATION_LABEL_FONT_WIDTH; // fallback
|
|
35
|
+
return cachedFontSize;
|
|
36
|
+
} finally {
|
|
37
|
+
document.body.removeChild(tempElement);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getAnnotationTextWidth(text, fontFamily = "monospace") {
|
|
11
42
|
if (!measureCanvas) {
|
|
12
43
|
measureCanvas = document.createElement("canvas");
|
|
13
44
|
}
|
|
45
|
+
const fontSize = getVeMonospaceFontSize();
|
|
14
46
|
const ctx = measureCanvas.getContext("2d");
|
|
15
47
|
ctx.font = `${fontSize}px ${fontFamily}`;
|
|
16
48
|
return ctx.measureText(text).width;
|
|
@@ -22,9 +54,10 @@ export const doesLabelFitInAnnotation = (
|
|
|
22
54
|
charWidth
|
|
23
55
|
) => {
|
|
24
56
|
const textLength = getAnnotationTextWidth(text);
|
|
57
|
+
const fontSize = getVeMonospaceFontSize();
|
|
25
58
|
const widthMinusOne = range
|
|
26
|
-
? getWidth(range, charWidth, 0) -
|
|
27
|
-
: width -
|
|
59
|
+
? getWidth(range, charWidth, 0) - fontSize * 2
|
|
60
|
+
: width - fontSize * 2;
|
|
28
61
|
return widthMinusOne > textLength;
|
|
29
62
|
};
|
|
30
63
|
|
package/src/StatusBar/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
removeDuplicatesIcon,
|
|
12
12
|
useMemoDeepEqual
|
|
13
13
|
} from "@teselagen/ui";
|
|
14
|
+
import { convertDnaCaretPositionOrRangeToAA } from "@teselagen/sequence-utils";
|
|
14
15
|
import { map, upperFirst, pick, startCase, isFunction } from "lodash-es";
|
|
15
16
|
import {
|
|
16
17
|
AnchorButton,
|
|
@@ -86,7 +87,10 @@ const genericAnnotationProperties = ({
|
|
|
86
87
|
|
|
87
88
|
const annotationsToUse = React.useMemo(
|
|
88
89
|
() =>
|
|
89
|
-
map(annotations,
|
|
90
|
+
map(annotations, _annotation => {
|
|
91
|
+
const annotation = isProtein
|
|
92
|
+
? convertDnaCaretPositionOrRangeToAA(_annotation)
|
|
93
|
+
: _annotation;
|
|
90
94
|
return {
|
|
91
95
|
...annotation,
|
|
92
96
|
...(annotation.strand === undefined && {
|
|
@@ -95,7 +99,7 @@ const genericAnnotationProperties = ({
|
|
|
95
99
|
size: getRangeLength(annotation, sequenceLength)
|
|
96
100
|
};
|
|
97
101
|
}),
|
|
98
|
-
[annotations, sequenceLength]
|
|
102
|
+
[annotations, sequenceLength, isProtein]
|
|
99
103
|
);
|
|
100
104
|
|
|
101
105
|
const keyedPartTags = getKeyedTagsAndTagOptions(allPartTags) ?? {};
|
|
@@ -180,7 +184,7 @@ const genericAnnotationProperties = ({
|
|
|
180
184
|
}
|
|
181
185
|
}
|
|
182
186
|
]),
|
|
183
|
-
sizeSchema(
|
|
187
|
+
sizeSchema(),
|
|
184
188
|
...(withTags && allPartTags
|
|
185
189
|
? [
|
|
186
190
|
{
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { isEqual } from "lodash-es";
|
|
3
|
-
import { convertDnaCaretPositionOrRangeToAA } from "@teselagen/sequence-utils";
|
|
4
3
|
import { convertRangeTo1Based } from "@teselagen/range-utils";
|
|
5
4
|
import selectors from "../../selectors";
|
|
6
5
|
|
|
7
|
-
export const sizeSchema =
|
|
6
|
+
export const sizeSchema = () => ({
|
|
8
7
|
path: "size",
|
|
9
8
|
type: "number",
|
|
10
|
-
render: (val,
|
|
11
|
-
const record = isProtein
|
|
12
|
-
? convertDnaCaretPositionOrRangeToAA(_record)
|
|
13
|
-
: _record;
|
|
9
|
+
render: (val, record) => {
|
|
14
10
|
const base1Range = convertRangeTo1Based(record);
|
|
15
11
|
const hasJoinedLocations = record.locations && record.locations.length > 1;
|
|
16
12
|
|
|
17
13
|
return (
|
|
18
14
|
<span>
|
|
19
|
-
{
|
|
15
|
+
{val}{" "}
|
|
20
16
|
<span style={{ fontSize: 10 }}>
|
|
21
17
|
{hasJoinedLocations ? (
|
|
22
18
|
record.locations.map((loc, i) => {
|
|
@@ -41,12 +37,9 @@ export const sizeSchema = isProtein => ({
|
|
|
41
37
|
export const getMemoOrfs = (() => {
|
|
42
38
|
let lastDeps;
|
|
43
39
|
let lastResult;
|
|
44
|
-
return
|
|
45
|
-
const {
|
|
46
|
-
|
|
47
|
-
minimumOrfSize,
|
|
48
|
-
useAdditionalOrfStartCodons
|
|
49
|
-
} = editorState;
|
|
40
|
+
return editorState => {
|
|
41
|
+
const { sequenceData, minimumOrfSize, useAdditionalOrfStartCodons } =
|
|
42
|
+
editorState;
|
|
50
43
|
|
|
51
44
|
const { sequence, circular } = sequenceData;
|
|
52
45
|
|
|
@@ -14,6 +14,7 @@ import { forEach, camelCase, startCase } from "lodash-es";
|
|
|
14
14
|
import { sizeSchema } from "../PropertiesDialog/utils";
|
|
15
15
|
import { getRangeLength } from "@teselagen/range-utils";
|
|
16
16
|
import { useFormValue } from "../../utils/useFormValue";
|
|
17
|
+
import { convertDnaCaretPositionOrRangeToAA } from "@teselagen/sequence-utils";
|
|
17
18
|
|
|
18
19
|
const dialogFormName = "RemoveDuplicatesDialog";
|
|
19
20
|
const dataTableFormName = "duplicatesToRemove";
|
|
@@ -33,6 +34,7 @@ const RemoveDuplicatesDialog = props => {
|
|
|
33
34
|
const ignoreName = useFormValue(dialogFormName, "ignoreName");
|
|
34
35
|
const ignoreStartAndEnd = useFormValue(dialogFormName, "ignoreStartAndEnd");
|
|
35
36
|
const ignoreStrand = useFormValue(dialogFormName, "ignoreStrand");
|
|
37
|
+
const isProteinSeq = isProtein || sequenceData.isProtein;
|
|
36
38
|
|
|
37
39
|
const recomputeDups = useCallback(
|
|
38
40
|
values => {
|
|
@@ -42,19 +44,25 @@ const RemoveDuplicatesDialog = props => {
|
|
|
42
44
|
const annotations = sequenceData[type];
|
|
43
45
|
const newDups = [];
|
|
44
46
|
const seqsHashByStartEndStrandName = {};
|
|
45
|
-
forEach(annotations,
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
forEach(annotations, _annotation => {
|
|
48
|
+
const annotation = isProteinSeq
|
|
49
|
+
? convertDnaCaretPositionOrRangeToAA(_annotation)
|
|
50
|
+
: _annotation;
|
|
51
|
+
const hash = `${ignoreStartAndEnd ? "" : annotation.start}&${
|
|
52
|
+
ignoreStartAndEnd ? "" : annotation.end
|
|
53
|
+
}&${ignoreStrand ? "" : annotation.strand}&${ignoreName ? "" : annotation.name}`;
|
|
49
54
|
if (seqsHashByStartEndStrandName[hash]) {
|
|
50
|
-
newDups.push({
|
|
55
|
+
newDups.push({
|
|
56
|
+
...annotation,
|
|
57
|
+
size: getRangeLength(annotation, sequenceLength)
|
|
58
|
+
});
|
|
51
59
|
} else {
|
|
52
60
|
seqsHashByStartEndStrandName[hash] = true;
|
|
53
61
|
}
|
|
54
62
|
});
|
|
55
63
|
return newDups;
|
|
56
64
|
},
|
|
57
|
-
[sequenceData, sequenceLength, type]
|
|
65
|
+
[sequenceData, sequenceLength, type, isProteinSeq]
|
|
58
66
|
);
|
|
59
67
|
|
|
60
68
|
const [dups, setDups] = useState(recomputeDups);
|
|
@@ -79,11 +87,11 @@ const RemoveDuplicatesDialog = props => {
|
|
|
79
87
|
fields: [
|
|
80
88
|
{ path: "name", type: "string" },
|
|
81
89
|
// ...(noType ? [] : [{ path: "type", type: "string" }]),
|
|
82
|
-
sizeSchema(
|
|
90
|
+
sizeSchema(),
|
|
83
91
|
{ path: "strand", type: "string" }
|
|
84
92
|
]
|
|
85
93
|
}),
|
|
86
|
-
[
|
|
94
|
+
[]
|
|
87
95
|
);
|
|
88
96
|
|
|
89
97
|
return (
|
package/src/index.js
CHANGED
|
@@ -28,10 +28,7 @@ export {
|
|
|
28
28
|
default as LinearView,
|
|
29
29
|
LinearView as LinearViewUnconnected
|
|
30
30
|
} from "./LinearView";
|
|
31
|
-
export {
|
|
32
|
-
default as StatusBar,
|
|
33
|
-
StatusBar as StatusBarUnconnected
|
|
34
|
-
} from "./StatusBar";
|
|
31
|
+
export { default as StatusBar } from "./StatusBar";
|
|
35
32
|
export {
|
|
36
33
|
default as DigestTool,
|
|
37
34
|
DigestTool as DigestToolUnconnected
|