@teselagen/ove 0.8.25 → 0.8.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.8.25",
3
+ "version": "0.8.27",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/TeselaGen/tg-oss",
@@ -16,11 +16,11 @@
16
16
  "@hello-pangea/dnd": "16.2.0",
17
17
  "@risingstack/react-easy-state": "^6.3.0",
18
18
  "@teselagen/bio-parsers": "0.4.33",
19
- "@teselagen/file-utils": "0.3.20",
20
- "@teselagen/range-utils": "0.3.19",
19
+ "@teselagen/file-utils": "0.3.23",
20
+ "@teselagen/range-utils": "0.3.20",
21
21
  "@teselagen/react-list": "0.8.18",
22
22
  "@teselagen/sequence-utils": "0.3.41",
23
- "@teselagen/ui": "0.10.16",
23
+ "@teselagen/ui": "0.10.17",
24
24
  "@use-gesture/react": "10.3.0",
25
25
  "biomsa": "^0.2.4",
26
26
  "classnames": "^2.3.2",
@@ -14,7 +14,7 @@ const makeStore = () => {
14
14
  // replacer: (key, value) => {
15
15
  // }
16
16
  // },
17
- actionsDenylist: ["HOVEREDANNOTATIONUPDATE", "HOVEREDANNOTATIONCLEAR"]
17
+ actionsDenylist: []
18
18
  })) ||
19
19
  compose;
20
20
 
@@ -1,10 +1,6 @@
1
1
  import classnames from "classnames";
2
- import { compose } from "redux";
3
- import { connect } from "react-redux";
4
2
  import React from "react";
5
- import { store } from "@risingstack/react-easy-state";
6
- import * as hoveredAnnotationActions from "../redux/hoveredAnnotation";
7
- import { withHandlers, branch } from "recompose";
3
+ import { store, view } from "@risingstack/react-easy-state";
8
4
  import { modifiableTypes } from "@teselagen/sequence-utils";
9
5
 
10
6
  export const HoveredIdContext = React.createContext({
@@ -20,57 +16,37 @@ export function withHoveredIdFromContext(Component) {
20
16
  );
21
17
  };
22
18
  }
19
+
20
+ // Easy state store for hover state management (replaces Redux)
23
21
  export const hoveredAnnEasyStore = store({
24
22
  hoveredAnn: undefined,
25
- selectedAnn: undefined
23
+ selectedAnn: undefined,
24
+ // Per-editor hovered annotation IDs
25
+ hoveredIds: {}
26
26
  });
27
27
 
28
- export default compose(
29
- withHoveredIdFromContext,
30
- branch(
31
- ({ noRedux }) => !noRedux,
32
- connect(function (
33
- state,
34
- {
35
- id,
36
- editorName = "StandaloneEditor",
37
- className,
38
- hoveredId: hoveredIdFromContext,
39
- passHoveredId
40
- }
41
- ) {
42
- if (!editorName) {
43
- console.warn(
44
- "please pass an editorName to the withHover() wrapped component"
45
- );
46
- }
47
- const editorState = state.VectorEditor[editorName] || {};
48
- const hoveredId = editorState.hoveredAnnotation || hoveredIdFromContext; //we can pass a hoveredId from context in order to still use the hover functionality without being connected to redux! see http://localhost:3344/#/SimpleCircularOrLinearView for an example
49
- const isIdHashmap = typeof id === "object";
50
-
51
- const hovered = !!(isIdHashmap ? id[hoveredId] : hoveredId === id);
52
- const newClassName = classnames(className, "hoverHelper", {
53
- veAnnotationHovered: hovered
54
- });
55
- const toReturn = {
56
- hovered,
57
- className: newClassName
58
- };
59
- if (hovered && passHoveredId) {
60
- //only pass hoveredId if it is hovered
61
- toReturn.hoveredId = hoveredId;
62
- }
63
- return toReturn;
64
- }, hoveredAnnotationActions)
65
- ),
66
- withHandlers({
67
- onMouseOver: props =>
68
- function (e) {
69
- // loop through the target element and the parents and see if any of them have the hoverHelper class
70
- // if they do, then we don't want to trigger the hover event
71
- // if they don't, then we do want to trigger the hover event
72
- // we should stop the loop if the target element is implementing this onMouseOver event
73
- // e.stopPropagation(); //this is important otherwise hovering labels inside circular view label groups won't work
28
+ // Helper functions to update/clear hovered annotation (replaces Redux actions)
29
+ export function hoveredAnnotationUpdate(
30
+ id,
31
+ { editorName = "StandaloneEditor" } = {}
32
+ ) {
33
+ hoveredAnnEasyStore.hoveredIds[editorName] = id;
34
+ }
35
+
36
+ export function hoveredAnnotationClear(
37
+ clear,
38
+ { editorName = "StandaloneEditor" } = {}
39
+ ) {
40
+ hoveredAnnEasyStore.hoveredIds[editorName] = "";
41
+ }
42
+
43
+ // HOC that provides hover functionality using react-easy-state
44
+ export default function withHover(WrappedComponent) {
45
+ const HoverComponent = view(
46
+ class extends React.Component {
47
+ static contextType = HoveredIdContext;
48
+
49
+ handleMouseOver = e => {
74
50
  const target = e.target;
75
51
  let alreadyHandled = false;
76
52
  let currentElement = target;
@@ -78,8 +54,6 @@ export default compose(
78
54
  if (currentElement === e.currentTarget) {
79
55
  break;
80
56
  }
81
- // console.log(`currentElement:`, currentElement)
82
-
83
57
  if (currentElement.classList.contains("hoverHelper")) {
84
58
  alreadyHandled = true;
85
59
  break;
@@ -88,26 +62,76 @@ export default compose(
88
62
  }
89
63
  if (alreadyHandled) return;
90
64
 
91
- // const alreadyHandled = e.target.classList.contains("hoverHelper");
92
- const { editorName, id, hoveredAnnotationUpdate } = props;
65
+ const {
66
+ editorName = "StandaloneEditor",
67
+ id,
68
+ annotation,
69
+ label
70
+ } = this.props;
93
71
  const isIdHashmap = typeof id === "object";
94
72
  const idToPass = isIdHashmap ? Object.keys(id)[0] : id;
95
- const annot = props?.annotation || props?.label?.annotation;
73
+ const annot = annotation || label?.annotation;
96
74
  if (modifiableTypes.includes(annot?.annotationTypePlural)) {
97
75
  hoveredAnnEasyStore.hoveredAnn = annot;
98
76
  }
99
- //because the calling onHover can slow things down, we disable it if dragging or scrolling
77
+ // Disable hover during dragging or scrolling
100
78
  if (window.__veDragging || window.__veScrolling) return;
101
79
 
102
- hoveredAnnotationUpdate &&
103
- hoveredAnnotationUpdate(idToPass, { editorName });
104
- },
105
- onMouseLeave: props => e => {
106
- hoveredAnnEasyStore.hoveredAnn = undefined;
107
- const { editorName, hoveredAnnotationClear } = props;
108
- e.stopPropagation();
109
- if (window.__veDragging || window.__veScrolling) return;
110
- hoveredAnnotationClear && hoveredAnnotationClear(true, { editorName });
80
+ hoveredAnnotationUpdate(idToPass, { editorName });
81
+ };
82
+
83
+ handleMouseLeave = e => {
84
+ hoveredAnnEasyStore.hoveredAnn = undefined;
85
+ const { editorName = "StandaloneEditor" } = this.props;
86
+ e.stopPropagation();
87
+ if (window.__veDragging || window.__veScrolling) return;
88
+ hoveredAnnotationClear(true, { editorName });
89
+ };
90
+
91
+ render() {
92
+ const {
93
+ id,
94
+ editorName = "StandaloneEditor",
95
+ className,
96
+ passHoveredId,
97
+ noRedux, // eslint-disable-line no-unused-vars
98
+ ...restProps
99
+ } = this.props;
100
+
101
+ const hoveredIdFromContext = this.context?.hoveredId;
102
+ const hoveredId =
103
+ hoveredAnnEasyStore.hoveredIds[editorName] ||
104
+ hoveredIdFromContext ||
105
+ "";
106
+ const isIdHashmap = typeof id === "object";
107
+ const hovered = !!(isIdHashmap ? id[hoveredId] : hoveredId === id);
108
+
109
+ const newClassName = classnames(className, "hoverHelper", {
110
+ veAnnotationHovered: hovered
111
+ });
112
+
113
+ const passedProps = {
114
+ ...restProps,
115
+ id,
116
+ editorName,
117
+ hovered,
118
+ className: newClassName,
119
+ onMouseOver: this.handleMouseOver,
120
+ onMouseLeave: this.handleMouseLeave
121
+ };
122
+
123
+ if (hovered && passHoveredId) {
124
+ passedProps.hoveredId = hoveredId;
125
+ }
126
+
127
+ return <WrappedComponent {...passedProps} />;
128
+ }
111
129
  }
112
- })
113
- );
130
+ );
131
+
132
+ HoverComponent.displayName = `withHover(${
133
+ WrappedComponent.displayName || WrappedComponent.name || "Component"
134
+ })`;
135
+
136
+ return HoverComponent;
137
+ }
@@ -11,7 +11,6 @@ import * as digestTool from "./digestTool";
11
11
  import * as findTool from "./findTool";
12
12
  import * as toolBar from "./toolBar";
13
13
  import * as frameTranslations from "./frameTranslations";
14
- import * as hoveredAnnotation from "./hoveredAnnotation";
15
14
  import * as minimumOrfSize from "./minimumOrfSize";
16
15
  import * as alignments from "./alignments";
17
16
  import * as panelsShown from "./panelsShown";
@@ -51,7 +50,6 @@ const subReducers = {
51
50
  toolBar,
52
51
  findTool,
53
52
  frameTranslations,
54
- hoveredAnnotation,
55
53
  minimumOrfSize,
56
54
  panelsShown,
57
55
  propertiesTool,
@@ -1,4 +0,0 @@
1
- export const hoveredAnnotationUpdate: import('redux-act').ComplexActionCreator1<any, any, any>;
2
- export const hoveredAnnotationClear: import('redux-act').ComplexActionCreator1<any, any, any>;
3
- declare const _default: import('redux-act').Reducer<string, import('../../../../node_modules/redux').AnyAction>;
4
- export default _default;
@@ -1,24 +0,0 @@
1
- //./caretPosition.js
2
- import { createReducer } from "redux-act";
3
- import createAction from "./utils/createMetaAction";
4
-
5
- // ------------------------------------
6
- // Actions
7
- // ------------------------------------
8
- export const hoveredAnnotationUpdate = createAction("HOVEREDANNOTATIONUPDATE");
9
- export const hoveredAnnotationClear = createAction("HOVEREDANNOTATIONCLEAR");
10
-
11
- // ------------------------------------
12
- // Reducer
13
- // ------------------------------------
14
- export default createReducer(
15
- {
16
- [hoveredAnnotationUpdate]: (state, payload) => {
17
- return payload || null;
18
- },
19
- [hoveredAnnotationClear]: () => {
20
- return "";
21
- }
22
- },
23
- ""
24
- );