higlass 2.2.3 → 2.3.0
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/app/scripts/Autocomplete.jsx +12 -3
- package/app/scripts/Button.jsx +20 -24
- package/app/scripts/ContextMenuContainer.jsx +1 -3
- package/app/scripts/ContextMenuItem.jsx +15 -16
- package/app/scripts/Dialog.jsx +30 -29
- package/app/scripts/HiGlassComponent.jsx +54 -36
- package/app/scripts/HorizontalItem.jsx +50 -21
- package/app/scripts/HorizontalTrack.jsx +1 -0
- package/app/scripts/ListWrapper.jsx +6 -17
- package/app/scripts/Modal.jsx +14 -13
- package/app/scripts/PopupMenu.jsx +6 -12
- package/app/scripts/SortableList.jsx +119 -64
- package/app/scripts/TrackArea.jsx +19 -24
- package/app/scripts/TrackControl.jsx +16 -27
- package/app/scripts/VerticalItem.jsx +53 -22
- package/app/scripts/VerticalTrack.jsx +1 -0
- package/app/scripts/api.js +5 -4
- package/app/scripts/hglib.jsx +34 -4
- package/app/scripts/test-helpers/test-helpers.jsx +2 -2
- package/app/scripts/utils/get-higlass-components.js +2 -2
- package/app/scripts/utils/react-dom-compat.js +100 -0
- package/app/styles/HiGlass.scss +1 -0
- package/dist/app/scripts/Autocomplete.d.ts +3 -1
- package/dist/app/scripts/ContextMenuContainer.d.ts +0 -1
- package/dist/app/scripts/ContextMenuItem.d.ts +9 -15
- package/dist/app/scripts/HiGlassComponent.d.ts +0 -3
- package/dist/app/scripts/HorizontalItem.d.ts +1 -1
- package/dist/app/scripts/ListWrapper.d.ts +2 -7
- package/dist/app/scripts/PopupMenu.d.ts +2 -4
- package/dist/app/scripts/SortableList.d.ts +6 -2
- package/dist/app/scripts/VerticalItem.d.ts +1 -1
- package/dist/app/scripts/utils/react-dom-compat.d.ts +27 -0
- package/dist/hglib.js +13135 -11155
- package/dist/hglib.min.js +89 -89
- package/dist/higlass.mjs +13143 -11163
- package/dist/package.json +17 -7
- package/package.json +17 -7
|
@@ -9,6 +9,7 @@ class PopupMenu extends React.Component {
|
|
|
9
9
|
constructor(props) {
|
|
10
10
|
super(props);
|
|
11
11
|
|
|
12
|
+
this.popup = null;
|
|
12
13
|
this.clickHandlerBound = this.clickHandler.bind(this);
|
|
13
14
|
this.contextMenuHandlerBound = this.contextMenuHandler.bind(this);
|
|
14
15
|
this.resizeHandlerBound = this.resizeHandler.bind(this);
|
|
@@ -30,11 +31,8 @@ class PopupMenu extends React.Component {
|
|
|
30
31
|
);
|
|
31
32
|
window.addEventListener('resize', this.resizeHandlerBound, true);
|
|
32
33
|
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
componentDidUpdate() {
|
|
37
|
-
this._renderLayer();
|
|
34
|
+
// Re-render now that this.popup is ready for the portal
|
|
35
|
+
this.forceUpdate();
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
componentWillUnmount() {
|
|
@@ -45,14 +43,10 @@ class PopupMenu extends React.Component {
|
|
|
45
43
|
true,
|
|
46
44
|
);
|
|
47
45
|
window.removeEventListener('resize', this.resizeHandlerBound, true);
|
|
48
|
-
|
|
46
|
+
// React automatically cleans up the portal contents
|
|
49
47
|
document.body.removeChild(this.popup);
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
_renderLayer() {
|
|
53
|
-
ReactDOM.render(this.props.children, this.popup);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
50
|
clickHandler(event) {
|
|
57
51
|
if (!this.popup.contains(event.target)) {
|
|
58
52
|
if (this.props.onMenuClosed) this.props.onMenuClosed(event);
|
|
@@ -70,8 +64,8 @@ class PopupMenu extends React.Component {
|
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
render() {
|
|
73
|
-
|
|
74
|
-
return
|
|
67
|
+
if (!this.popup) return null;
|
|
68
|
+
return ReactDOM.createPortal(this.props.children, this.popup);
|
|
75
69
|
}
|
|
76
70
|
}
|
|
77
71
|
|
|
@@ -1,71 +1,126 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
DndContext,
|
|
5
|
+
PointerSensor,
|
|
6
|
+
closestCenter,
|
|
7
|
+
useSensor,
|
|
8
|
+
useSensors,
|
|
9
|
+
} from '@dnd-kit/core';
|
|
10
|
+
import {
|
|
11
|
+
SortableContext,
|
|
12
|
+
horizontalListSortingStrategy,
|
|
13
|
+
verticalListSortingStrategy,
|
|
14
|
+
} from '@dnd-kit/sortable';
|
|
3
15
|
import React from 'react';
|
|
4
|
-
import { SortableContainer } from 'react-sortable-hoc';
|
|
5
16
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
height: item.height,
|
|
38
|
-
width: item.width,
|
|
39
|
-
isCollapsed: item.isCollapsed,
|
|
40
|
-
item,
|
|
41
|
-
useDragHandle,
|
|
42
|
-
onCloseTrack,
|
|
43
|
-
onCollapseTrack,
|
|
44
|
-
onExpandTrack,
|
|
45
|
-
onCloseTrackMenuOpened,
|
|
46
|
-
onConfigTrackMenuOpened,
|
|
47
|
-
onAddSeries,
|
|
48
|
-
handleConfigTrack,
|
|
49
|
-
editable,
|
|
50
|
-
handleResizeTrack,
|
|
51
|
-
resizeHandles,
|
|
52
|
-
}),
|
|
53
|
-
);
|
|
17
|
+
function SortableList({
|
|
18
|
+
className,
|
|
19
|
+
items,
|
|
20
|
+
itemClass,
|
|
21
|
+
itemControlAlignLeft,
|
|
22
|
+
sortingIndex,
|
|
23
|
+
useDragHandle,
|
|
24
|
+
sortableHandlers,
|
|
25
|
+
height,
|
|
26
|
+
width,
|
|
27
|
+
onCloseTrack,
|
|
28
|
+
onCollapseTrack,
|
|
29
|
+
onExpandTrack,
|
|
30
|
+
onCloseTrackMenuOpened,
|
|
31
|
+
onConfigTrackMenuOpened,
|
|
32
|
+
onAddSeries,
|
|
33
|
+
handleConfigTrack,
|
|
34
|
+
editable,
|
|
35
|
+
itemReactClass,
|
|
36
|
+
handleResizeTrack,
|
|
37
|
+
resizeHandles,
|
|
38
|
+
onSortEnd,
|
|
39
|
+
onSortStart,
|
|
40
|
+
onSortMove,
|
|
41
|
+
axis,
|
|
42
|
+
}) {
|
|
43
|
+
const sensors = useSensors(
|
|
44
|
+
useSensor(PointerSensor, {
|
|
45
|
+
activationConstraint: { distance: 5 },
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
|
|
49
|
+
const handleDragStart = (event) => {
|
|
50
|
+
const { active } = event;
|
|
51
|
+
const index = items.findIndex((item) => item.uid === active.id);
|
|
52
|
+
if (onSortStart) {
|
|
53
|
+
onSortStart({ index });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleDragOver = (event) => {
|
|
58
|
+
const { active, over } = event;
|
|
59
|
+
if (!over || active.id === over.id) return;
|
|
60
|
+
|
|
61
|
+
const oldIndex = items.findIndex((item) => item.uid === active.id);
|
|
62
|
+
const newIndex = items.findIndex((item) => item.uid === over.id);
|
|
63
|
+
|
|
64
|
+
if (oldIndex !== -1 && newIndex !== -1) {
|
|
65
|
+
onSortEnd({ oldIndex, newIndex });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const isHorizontalAxis = axis === 'x';
|
|
70
|
+
const strategy = isHorizontalAxis
|
|
71
|
+
? horizontalListSortingStrategy
|
|
72
|
+
: verticalListSortingStrategy;
|
|
73
|
+
|
|
74
|
+
const itemIds = items.map((item) => item.uid);
|
|
75
|
+
|
|
76
|
+
const itemElements = items.map((item, index) =>
|
|
77
|
+
React.createElement(itemReactClass, {
|
|
78
|
+
key: `sci-${item.uid}`,
|
|
79
|
+
className: itemClass,
|
|
80
|
+
controlAlignLeft: itemControlAlignLeft,
|
|
81
|
+
sortingIndex,
|
|
82
|
+
index,
|
|
83
|
+
uid: item.uid,
|
|
84
|
+
height: item.height,
|
|
85
|
+
width: item.width,
|
|
86
|
+
isCollapsed: item.isCollapsed,
|
|
87
|
+
item,
|
|
88
|
+
useDragHandle,
|
|
89
|
+
onCloseTrack,
|
|
90
|
+
onCollapseTrack,
|
|
91
|
+
onExpandTrack,
|
|
92
|
+
onCloseTrackMenuOpened,
|
|
93
|
+
onConfigTrackMenuOpened,
|
|
94
|
+
onAddSeries,
|
|
95
|
+
handleConfigTrack,
|
|
96
|
+
editable,
|
|
97
|
+
handleResizeTrack,
|
|
98
|
+
resizeHandles,
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<DndContext
|
|
104
|
+
sensors={sensors}
|
|
105
|
+
collisionDetection={closestCenter}
|
|
106
|
+
onDragStart={handleDragStart}
|
|
107
|
+
onDragOver={handleDragOver}
|
|
108
|
+
onDragEnd={() => {}}
|
|
109
|
+
>
|
|
110
|
+
<SortableContext items={itemIds} strategy={strategy}>
|
|
111
|
+
<div
|
|
112
|
+
className={className}
|
|
113
|
+
style={{
|
|
114
|
+
height,
|
|
115
|
+
width,
|
|
116
|
+
background: 'transparent',
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
{itemElements}
|
|
120
|
+
</div>
|
|
121
|
+
</SortableContext>
|
|
122
|
+
</DndContext>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
70
125
|
|
|
71
126
|
export default SortableList;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import ReactDOM from 'react-dom';
|
|
5
|
-
import { SortableHandle } from 'react-sortable-hoc';
|
|
6
4
|
|
|
7
5
|
class TrackArea extends React.Component {
|
|
8
6
|
constructor(props) {
|
|
@@ -36,24 +34,23 @@ class TrackArea extends React.Component {
|
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
getControls() {
|
|
39
|
-
|
|
37
|
+
const { dragHandleProps } = this.props;
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
39
|
+
const handle = this.moveable ? (
|
|
40
|
+
<svg
|
|
41
|
+
className="no-zoom"
|
|
42
|
+
height="10px"
|
|
43
|
+
onClick={() => {}}
|
|
44
|
+
style={this.getMoveImgStyle()}
|
|
45
|
+
width="10px"
|
|
46
|
+
{...dragHandleProps}
|
|
47
|
+
>
|
|
48
|
+
<title>Move</title>
|
|
49
|
+
<use xlinkHref="#move" />
|
|
50
|
+
</svg>
|
|
51
|
+
) : (
|
|
52
|
+
<div />
|
|
53
|
+
);
|
|
57
54
|
|
|
58
55
|
return (
|
|
59
56
|
<div
|
|
@@ -69,7 +66,7 @@ class TrackArea extends React.Component {
|
|
|
69
66
|
border: '1px solid #dddddd',
|
|
70
67
|
}}
|
|
71
68
|
>
|
|
72
|
-
|
|
69
|
+
{handle}
|
|
73
70
|
|
|
74
71
|
<svg
|
|
75
72
|
ref={(c) => {
|
|
@@ -78,8 +75,7 @@ class TrackArea extends React.Component {
|
|
|
78
75
|
className="no-zoom"
|
|
79
76
|
height="10px"
|
|
80
77
|
onClick={() => {
|
|
81
|
-
const
|
|
82
|
-
const bbox = imgDom.getBoundingClientRect();
|
|
78
|
+
const bbox = this.imgConfig.getBoundingClientRect();
|
|
83
79
|
this.props.onConfigTrackMenuOpened(this.props.uid, bbox);
|
|
84
80
|
}}
|
|
85
81
|
style={this.getSettingsImgStyle()}
|
|
@@ -110,8 +106,7 @@ class TrackArea extends React.Component {
|
|
|
110
106
|
className="no-zoom"
|
|
111
107
|
height="10px"
|
|
112
108
|
onClick={() => {
|
|
113
|
-
const
|
|
114
|
-
const bbox = imgDom.getBoundingClientRect();
|
|
109
|
+
const bbox = this.imgClose.getBoundingClientRect();
|
|
115
110
|
this.props.onCloseTrackMenuOpened(this.props.uid, bbox);
|
|
116
111
|
}}
|
|
117
112
|
style={this.getCloseImgStyle()}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import { SortableHandle } from 'react-sortable-hoc';
|
|
6
5
|
|
|
7
6
|
import { THEME_DARK } from './configs';
|
|
8
7
|
import withTheme from './hocs/with-theme';
|
|
@@ -25,39 +24,29 @@ const getButtonClassName = (props) =>
|
|
|
25
24
|
[classes['track-control-button-vertical']]: props.isVertical,
|
|
26
25
|
});
|
|
27
26
|
|
|
28
|
-
let oldProps = null;
|
|
29
|
-
let DragHandle = null;
|
|
30
|
-
|
|
31
27
|
function TrackControl(props) {
|
|
32
|
-
|
|
33
|
-
// Damn React could be a little smarter here...
|
|
34
|
-
if (
|
|
35
|
-
!props ||
|
|
36
|
-
!oldProps ||
|
|
37
|
-
Object.keys(props).some((key) => oldProps[key] !== props[key])
|
|
38
|
-
) {
|
|
39
|
-
oldProps = props;
|
|
40
|
-
DragHandle = SortableHandle(() => (
|
|
41
|
-
<svg
|
|
42
|
-
className={getButtonClassName(props)}
|
|
43
|
-
style={{
|
|
44
|
-
height: '20px',
|
|
45
|
-
width: '20px',
|
|
46
|
-
...props.imgStyleMove,
|
|
47
|
-
}}
|
|
48
|
-
>
|
|
49
|
-
<title>Move track</title>
|
|
50
|
-
<use xlinkHref="#move" />
|
|
51
|
-
</svg>
|
|
52
|
-
));
|
|
53
|
-
}
|
|
28
|
+
const { dragHandleProps } = props;
|
|
54
29
|
|
|
55
30
|
let imgConfig;
|
|
56
31
|
let imgClose;
|
|
57
32
|
|
|
58
33
|
return (
|
|
59
34
|
<div className={getClassName(props)}>
|
|
60
|
-
{props.isMoveable &&
|
|
35
|
+
{props.isMoveable && (
|
|
36
|
+
<svg
|
|
37
|
+
className={getButtonClassName(props)}
|
|
38
|
+
draggable={false}
|
|
39
|
+
style={{
|
|
40
|
+
height: '20px',
|
|
41
|
+
width: '20px',
|
|
42
|
+
...props.imgStyleMove,
|
|
43
|
+
}}
|
|
44
|
+
{...dragHandleProps}
|
|
45
|
+
>
|
|
46
|
+
<title>Move track</title>
|
|
47
|
+
<use xlinkHref="#move" />
|
|
48
|
+
</svg>
|
|
49
|
+
)}
|
|
61
50
|
|
|
62
51
|
{/* Show collapse button */}
|
|
63
52
|
{props.expandCollapseAvailable && !props.isCollapsed && (
|
|
@@ -1,29 +1,60 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
import { useSortable } from '@dnd-kit/sortable';
|
|
4
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
2
5
|
import React from 'react';
|
|
3
|
-
import { SortableElement } from 'react-sortable-hoc';
|
|
4
6
|
|
|
5
7
|
import VerticalTrack from './VerticalTrack';
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
9
|
+
function VerticalItem(props) {
|
|
10
|
+
const {
|
|
11
|
+
attributes,
|
|
12
|
+
listeners,
|
|
13
|
+
setNodeRef,
|
|
14
|
+
transform,
|
|
15
|
+
transition,
|
|
16
|
+
isDragging,
|
|
17
|
+
} = useSortable({ id: props.uid });
|
|
18
|
+
|
|
19
|
+
const adjustedTransform = transform ? { ...transform, y: 0 } : transform;
|
|
20
|
+
|
|
21
|
+
const style = {
|
|
22
|
+
transform: CSS.Transform.toString(adjustedTransform),
|
|
23
|
+
transition,
|
|
24
|
+
...(isDragging
|
|
25
|
+
? {
|
|
26
|
+
zIndex: 10,
|
|
27
|
+
background: 'rgba(0, 0, 0, 0.1)',
|
|
28
|
+
border: '2px dashed rgba(0, 0, 0, 0.3)',
|
|
29
|
+
borderRadius: 4,
|
|
30
|
+
}
|
|
31
|
+
: {}),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div ref={setNodeRef} style={style}>
|
|
36
|
+
<VerticalTrack
|
|
37
|
+
className={props.className}
|
|
38
|
+
controlAlignLeft={props.controlAlignLeft}
|
|
39
|
+
dragHandleProps={{ ...attributes, ...listeners }}
|
|
40
|
+
editable={props.editable}
|
|
41
|
+
handleConfigTrack={props.handleConfigTrack}
|
|
42
|
+
handleResizeTrack={props.handleResizeTrack}
|
|
43
|
+
height={props.height}
|
|
44
|
+
isCollapsed={props.isCollapsed}
|
|
45
|
+
item={props.item}
|
|
46
|
+
onAddSeries={props.onAddSeries}
|
|
47
|
+
onCollapseTrack={props.onCollapseTrack}
|
|
48
|
+
onExpandTrack={props.onExpandTrack}
|
|
49
|
+
onCloseTrack={props.onCloseTrack}
|
|
50
|
+
onCloseTrackMenuOpened={props.onCloseTrackMenuOpened}
|
|
51
|
+
onConfigTrackMenuOpened={props.onConfigTrackMenuOpened}
|
|
52
|
+
resizeHandles={props.resizeHandles}
|
|
53
|
+
uid={props.uid}
|
|
54
|
+
width={props.width}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
28
59
|
|
|
29
60
|
export default VerticalItem;
|
|
@@ -16,6 +16,7 @@ class VerticalTrack extends MoveableTrack {
|
|
|
16
16
|
// for use. Only available in horizontal and vertical tracks and not
|
|
17
17
|
// center.
|
|
18
18
|
expandCollapseAvailable={true}
|
|
19
|
+
dragHandleProps={this.props.dragHandleProps}
|
|
19
20
|
imgStyleAdd={STYLES}
|
|
20
21
|
imgStyleClose={STYLES}
|
|
21
22
|
imgStyleMove={STYLES}
|
package/app/scripts/api.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import Ajv from 'ajv';
|
|
3
3
|
import createPubSub from 'pub-sub-es';
|
|
4
|
-
import ReactDOM from 'react-dom';
|
|
5
|
-
|
|
6
4
|
import schema from '../schema.json';
|
|
7
5
|
|
|
6
|
+
import { unmountFromContainer } from './utils/react-dom-compat';
|
|
7
|
+
|
|
8
8
|
import { getTileProxyAuthHeader, setTileProxyAuthHeader } from './services';
|
|
9
9
|
|
|
10
10
|
import { getTrackObjectFromHGC } from './utils';
|
|
@@ -162,8 +162,9 @@ const createApi = function api(context, pubSub) {
|
|
|
162
162
|
*/
|
|
163
163
|
destroy() {
|
|
164
164
|
destroy();
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
const container = self.topDivRef.current?.parentNode;
|
|
166
|
+
if (container) {
|
|
167
|
+
unmountFromContainer(container);
|
|
167
168
|
}
|
|
168
169
|
},
|
|
169
170
|
|
package/app/scripts/hglib.jsx
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
2
|
import HiGlassComponent from './HiGlassComponent';
|
|
3
|
+
import {
|
|
4
|
+
ensureReady,
|
|
5
|
+
renderToContainer,
|
|
6
|
+
unmountFromContainer,
|
|
7
|
+
} from './utils/react-dom-compat';
|
|
4
8
|
|
|
5
9
|
import HorizontalGeneAnnotationsTrack from './HorizontalGeneAnnotationsTrack';
|
|
6
10
|
// these exports can be used to create new tracks in outside environments (e.g. Observable)
|
|
@@ -77,8 +81,10 @@ export { OPTIONS_INFO } from './options-info';
|
|
|
77
81
|
* @returns {Promise<HiGlassComponent>}
|
|
78
82
|
*/
|
|
79
83
|
const launch = async (element, config, options = {}) => {
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
await ensureReady();
|
|
85
|
+
const hgc = await new Promise((resolve) => {
|
|
86
|
+
renderToContainer(
|
|
87
|
+
element,
|
|
82
88
|
<HiGlassComponent
|
|
83
89
|
ref={(/** @type {HiGlassComponent | null} */ ref) => {
|
|
84
90
|
// Wait to resolve until React gives us a ref
|
|
@@ -87,9 +93,33 @@ const launch = async (element, config, options = {}) => {
|
|
|
87
93
|
options={options}
|
|
88
94
|
viewConfig={config}
|
|
89
95
|
/>,
|
|
90
|
-
element,
|
|
91
96
|
);
|
|
92
97
|
});
|
|
98
|
+
|
|
99
|
+
// react-grid-layout v2 uses async useEffect for layout synchronization.
|
|
100
|
+
// Wait until TiledPlots are rendered (trackRenderer is populated) before
|
|
101
|
+
// returning, so the component is truly ready to use.
|
|
102
|
+
const viewUids = Object.keys(hgc.state.views);
|
|
103
|
+
if (viewUids.length > 0) {
|
|
104
|
+
await /** @type {Promise<void>} */ (
|
|
105
|
+
new Promise((resolve) => {
|
|
106
|
+
const start = performance.now();
|
|
107
|
+
const check = () => {
|
|
108
|
+
const allReady = viewUids.every(
|
|
109
|
+
(uid) => hgc.tiledPlots[uid]?.trackRenderer,
|
|
110
|
+
);
|
|
111
|
+
if (allReady || performance.now() - start > 5000) {
|
|
112
|
+
resolve();
|
|
113
|
+
} else {
|
|
114
|
+
setTimeout(check, 16);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
check();
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return hgc;
|
|
93
123
|
};
|
|
94
124
|
|
|
95
125
|
/**
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
2
|
|
|
4
3
|
import { mount } from 'enzyme';
|
|
5
4
|
|
|
6
5
|
import { requestsInFlight } from '../services';
|
|
6
|
+
import { unmountFromContainer } from '../utils/react-dom-compat';
|
|
7
7
|
|
|
8
8
|
import { getTrackObjectFromHGC, getTrackRenderer } from '../utils';
|
|
9
9
|
|
|
@@ -323,7 +323,7 @@ export const waitForComponentReady = async (div) => {
|
|
|
323
323
|
export const removeHGComponent = (div) => {
|
|
324
324
|
if (!div) return;
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
unmountFromContainer(div);
|
|
327
327
|
document.body.removeChild(div);
|
|
328
328
|
};
|
|
329
329
|
|
|
@@ -24,7 +24,7 @@ export const getTrackObjectFromHGC = (hgc, viewUid, trackUid) => {
|
|
|
24
24
|
newTrackUid = trackUid;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
return hgc.tiledPlots[newViewUid]
|
|
27
|
+
return hgc.tiledPlots[newViewUid]?.trackRenderer?.getTrackObject(newTrackUid);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -33,7 +33,7 @@ export const getTrackObjectFromHGC = (hgc, viewUid, trackUid) => {
|
|
|
33
33
|
* @returns {TrackRenderer | null}
|
|
34
34
|
*/
|
|
35
35
|
export const getTrackRenderer = (hgc, viewUid) =>
|
|
36
|
-
hgc.tiledPlots[viewUid]
|
|
36
|
+
hgc.tiledPlots[viewUid]?.trackRenderer;
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* @param {HiGlassComponent} hgc
|