@jbrowse/plugin-linear-comparative-view 3.5.1 → 3.6.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.
Files changed (69) hide show
  1. package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +4 -0
  2. package/dist/LinearComparativeDisplay/stateModelFactory.js +14 -7
  3. package/dist/LinearComparativeView/components/Rubberband.d.ts +2 -2
  4. package/dist/LinearComparativeView/components/Rubberband.js +16 -154
  5. package/dist/LinearComparativeView/components/RubberbandSpan.d.ts +15 -0
  6. package/dist/LinearComparativeView/components/RubberbandSpan.js +38 -0
  7. package/dist/LinearComparativeView/components/RubberbandTooltip.d.ts +5 -0
  8. package/dist/LinearComparativeView/components/RubberbandTooltip.js +20 -0
  9. package/dist/LinearComparativeView/components/useRangeSelect.d.ts +59 -0
  10. package/dist/LinearComparativeView/components/useRangeSelect.js +128 -0
  11. package/dist/LinearComparativeView/components/util.d.ts +4 -0
  12. package/dist/LinearComparativeView/components/util.js +6 -0
  13. package/dist/LinearSyntenyDisplay/components/BlockError.d.ts +3 -0
  14. package/dist/LinearSyntenyDisplay/components/BlockError.js +16 -0
  15. package/dist/LinearSyntenyDisplay/components/BlockMessage.d.ts +3 -0
  16. package/dist/LinearSyntenyDisplay/components/BlockMessage.js +24 -0
  17. package/dist/LinearSyntenyDisplay/components/Component.js +11 -50
  18. package/dist/LinearSyntenyDisplay/components/LoadingMessage.d.ts +3 -0
  19. package/dist/LinearSyntenyDisplay/components/LoadingMessage.js +21 -0
  20. package/dist/LinearSyntenyDisplay/model.d.ts +4 -0
  21. package/dist/LinearSyntenyView/components/ImportForm/ImportSyntenyOpenCustomTrack.js +2 -51
  22. package/dist/LinearSyntenyView/components/ImportForm/selectors/AnchorsSelector.d.ts +3 -0
  23. package/dist/LinearSyntenyView/components/ImportForm/selectors/AnchorsSelector.js +13 -0
  24. package/dist/LinearSyntenyView/components/ImportForm/selectors/PifGzSelector.d.ts +3 -0
  25. package/dist/LinearSyntenyView/components/ImportForm/selectors/PifGzSelector.js +13 -0
  26. package/dist/LinearSyntenyView/components/ImportForm/selectors/SelectorTypes.d.ts +19 -0
  27. package/dist/LinearSyntenyView/components/ImportForm/selectors/SelectorTypes.js +10 -0
  28. package/dist/LinearSyntenyView/components/ImportForm/selectors/StandardFormatSelector.d.ts +3 -0
  29. package/dist/LinearSyntenyView/components/ImportForm/selectors/StandardFormatSelector.js +20 -0
  30. package/dist/LinearSyntenyView/components/ImportForm/selectors/SwapAssemblies.d.ts +13 -0
  31. package/dist/LinearSyntenyView/components/ImportForm/selectors/SwapAssemblies.js +32 -0
  32. package/dist/LinearSyntenyView/components/ImportForm/selectors/index.d.ts +4 -0
  33. package/dist/LinearSyntenyView/components/ImportForm/selectors/index.js +27 -0
  34. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +1 -1
  35. package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +4 -0
  36. package/esm/LinearComparativeDisplay/stateModelFactory.js +14 -7
  37. package/esm/LinearComparativeView/components/Rubberband.d.ts +2 -2
  38. package/esm/LinearComparativeView/components/Rubberband.js +17 -155
  39. package/esm/LinearComparativeView/components/RubberbandSpan.d.ts +15 -0
  40. package/esm/LinearComparativeView/components/RubberbandSpan.js +32 -0
  41. package/esm/LinearComparativeView/components/RubberbandTooltip.d.ts +5 -0
  42. package/esm/LinearComparativeView/components/RubberbandTooltip.js +17 -0
  43. package/esm/LinearComparativeView/components/useRangeSelect.d.ts +59 -0
  44. package/esm/LinearComparativeView/components/useRangeSelect.js +125 -0
  45. package/esm/LinearComparativeView/components/util.d.ts +4 -0
  46. package/esm/LinearComparativeView/components/util.js +3 -0
  47. package/esm/LinearSyntenyDisplay/components/BlockError.d.ts +3 -0
  48. package/esm/LinearSyntenyDisplay/components/BlockError.js +13 -0
  49. package/esm/LinearSyntenyDisplay/components/BlockMessage.d.ts +3 -0
  50. package/esm/LinearSyntenyDisplay/components/BlockMessage.js +21 -0
  51. package/esm/LinearSyntenyDisplay/components/Component.js +9 -48
  52. package/esm/LinearSyntenyDisplay/components/LoadingMessage.d.ts +3 -0
  53. package/esm/LinearSyntenyDisplay/components/LoadingMessage.js +18 -0
  54. package/esm/LinearSyntenyDisplay/model.d.ts +4 -0
  55. package/esm/LinearSyntenyView/components/ImportForm/ImportSyntenyOpenCustomTrack.js +3 -49
  56. package/esm/LinearSyntenyView/components/ImportForm/selectors/AnchorsSelector.d.ts +3 -0
  57. package/esm/LinearSyntenyView/components/ImportForm/selectors/AnchorsSelector.js +8 -0
  58. package/esm/LinearSyntenyView/components/ImportForm/selectors/PifGzSelector.d.ts +3 -0
  59. package/esm/LinearSyntenyView/components/ImportForm/selectors/PifGzSelector.js +8 -0
  60. package/esm/LinearSyntenyView/components/ImportForm/selectors/SelectorTypes.d.ts +19 -0
  61. package/esm/LinearSyntenyView/components/ImportForm/selectors/SelectorTypes.js +7 -0
  62. package/esm/LinearSyntenyView/components/ImportForm/selectors/StandardFormatSelector.d.ts +3 -0
  63. package/esm/LinearSyntenyView/components/ImportForm/selectors/StandardFormatSelector.js +15 -0
  64. package/esm/LinearSyntenyView/components/ImportForm/selectors/SwapAssemblies.d.ts +13 -0
  65. package/esm/LinearSyntenyView/components/ImportForm/selectors/SwapAssemblies.js +27 -0
  66. package/esm/LinearSyntenyView/components/ImportForm/selectors/index.d.ts +4 -0
  67. package/esm/LinearSyntenyView/components/ImportForm/selectors/index.js +4 -0
  68. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +1 -1
  69. package/package.json +5 -5
@@ -1,165 +1,27 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
2
+ import { useRef } from 'react';
3
3
  import { Menu } from '@jbrowse/core/ui';
4
- import { stringify } from '@jbrowse/core/util';
5
- import { Popover, Typography, alpha } from '@mui/material';
6
- import { transaction } from 'mobx';
7
4
  import { observer } from 'mobx-react';
8
5
  import { makeStyles } from 'tss-react/mui';
6
+ import RubberbandSpan from './RubberbandSpan';
9
7
  import VerticalGuide from './VerticalGuide';
10
- const useStyles = makeStyles()(theme => {
11
- return {
12
- rubberband: {
13
- height: '100%',
14
- background: alpha(theme.palette.tertiary.main, 0.7),
15
- position: 'absolute',
16
- zIndex: 900,
17
- textAlign: 'center',
18
- overflow: 'hidden',
19
- },
20
- rubberbandControl: {
21
- cursor: 'crosshair',
22
- width: '100%',
23
- minHeight: 8,
24
- },
25
- rubberbandText: {
26
- color: theme.palette.tertiary.contrastText,
27
- },
28
- popover: {
29
- mouseEvents: 'none',
30
- cursor: 'crosshair',
31
- },
32
- paper: {
33
- paddingLeft: theme.spacing(1),
34
- paddingRight: theme.spacing(1),
35
- },
36
- };
8
+ import { useRangeSelect } from './useRangeSelect';
9
+ const useStyles = makeStyles()({
10
+ rubberbandControl: {
11
+ cursor: 'crosshair',
12
+ width: '100%',
13
+ minHeight: 8,
14
+ position: 'relative',
15
+ zIndex: 900,
16
+ },
37
17
  });
38
- const LinearComparativeRubberband = observer(function Rubberband({ model, ControlComponent = _jsx("div", {}), }) {
39
- const [startX, setStartX] = useState();
40
- const [currentX, setCurrentX] = useState();
41
- const [anchorPosition, setAnchorPosition] = useState();
42
- const [guideX, setGuideX] = useState();
43
- const controlsRef = useRef(null);
44
- const rubberbandRef = useRef(null);
18
+ const Rubberband = observer(function ({ model, ControlComponent = _jsx("div", {}), }) {
19
+ const ref = useRef(null);
45
20
  const { classes } = useStyles();
46
- const mouseDragging = startX !== undefined && anchorPosition === undefined;
47
- useEffect(() => {
48
- function computeOffsets(offsetX, view) {
49
- if (startX === undefined) {
50
- return;
51
- }
52
- let leftPx = startX;
53
- let rightPx = offsetX;
54
- if (rightPx < leftPx) {
55
- ;
56
- [leftPx, rightPx] = [rightPx, leftPx];
57
- }
58
- const leftOffset = view.pxToBp(leftPx);
59
- const rightOffset = view.pxToBp(rightPx);
60
- return { leftOffset, rightOffset };
61
- }
62
- function globalMouseMove(event) {
63
- if (controlsRef.current && mouseDragging) {
64
- const relativeX = event.clientX - controlsRef.current.getBoundingClientRect().left;
65
- setCurrentX(relativeX);
66
- }
67
- }
68
- function globalMouseUp(event) {
69
- if (startX !== undefined && controlsRef.current) {
70
- const { clientX, clientY } = event;
71
- const ref = controlsRef.current;
72
- const offsetX = clientX - ref.getBoundingClientRect().left;
73
- setAnchorPosition({
74
- offsetX,
75
- clientX,
76
- clientY,
77
- });
78
- transaction(() => {
79
- for (const view of model.views) {
80
- const args = computeOffsets(offsetX, view);
81
- if (args) {
82
- const { leftOffset, rightOffset } = args;
83
- view.setOffsets(leftOffset, rightOffset);
84
- }
85
- }
86
- });
87
- setGuideX(undefined);
88
- }
89
- }
90
- if (mouseDragging) {
91
- window.addEventListener('mousemove', globalMouseMove);
92
- window.addEventListener('mouseup', globalMouseUp);
93
- return () => {
94
- window.removeEventListener('mousemove', globalMouseMove);
95
- window.removeEventListener('mouseup', globalMouseUp);
96
- };
97
- }
98
- return () => { };
99
- }, [startX, mouseDragging, model]);
100
- useEffect(() => {
101
- if (!mouseDragging &&
102
- currentX !== undefined &&
103
- startX !== undefined &&
104
- Math.abs(currentX - startX) <= 3) {
105
- handleClose();
106
- }
107
- }, [mouseDragging, currentX, startX]);
108
- function mouseDown(event) {
109
- event.preventDefault();
110
- event.stopPropagation();
111
- const relativeX = event.clientX -
112
- event.target.getBoundingClientRect().left;
113
- setStartX(relativeX);
114
- setCurrentX(relativeX);
115
- }
116
- function mouseMove(event) {
117
- const target = event.target;
118
- setGuideX(event.clientX - target.getBoundingClientRect().left);
119
- }
120
- function mouseOut() {
121
- setGuideX(undefined);
122
- transaction(() => {
123
- for (const view of model.views) {
124
- view.setOffsets(undefined, undefined);
125
- }
126
- });
127
- }
128
- function handleClose() {
129
- setAnchorPosition(undefined);
130
- setStartX(undefined);
131
- setCurrentX(undefined);
132
- }
133
- const open = Boolean(anchorPosition);
134
- function handleMenuItemClick(_, callback) {
135
- callback();
136
- handleClose();
137
- }
138
- if (startX === undefined) {
139
- return (_jsxs(_Fragment, { children: [guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : null, _jsx("div", { ref: controlsRef, className: classes.rubberbandControl, onMouseDown: mouseDown, onMouseOut: mouseOut, onMouseMove: mouseMove, children: ControlComponent })] }));
140
- }
141
- const right = anchorPosition ? anchorPosition.offsetX : currentX || 0;
142
- const left = Math.min(right, startX);
143
- const width = Math.abs(right - startX);
144
- const { views } = model;
145
- const leftBpOffset = views.map(view => view.pxToBp(left));
146
- const rightBpOffset = views.map(view => view.pxToBp(left + width));
147
- const numOfBpSelected = views.map(view => Math.ceil(width * view.bpPerPx));
148
- return (_jsxs(_Fragment, { children: [rubberbandRef.current ? (_jsxs(_Fragment, { children: [_jsx(Popover, { className: classes.popover, classes: { paper: classes.paper }, open: true, anchorEl: rubberbandRef.current, anchorOrigin: {
149
- vertical: 'top',
150
- horizontal: 'left',
151
- }, transformOrigin: {
152
- vertical: 'bottom',
153
- horizontal: 'right',
154
- }, keepMounted: true, disableRestoreFocus: true, children: leftBpOffset.map((l, idx) => (_jsx(Typography, { children: stringify(l, true) }, [JSON.stringify(l), idx, 'left'].join('-')))) }), _jsx(Popover, { className: classes.popover, classes: { paper: classes.paper }, open: true, anchorEl: rubberbandRef.current, anchorOrigin: {
155
- vertical: 'top',
156
- horizontal: 'right',
157
- }, transformOrigin: {
158
- vertical: 'bottom',
159
- horizontal: 'left',
160
- }, keepMounted: true, disableRestoreFocus: true, children: rightBpOffset.map((l, idx) => (_jsx(Typography, { children: stringify(l, true) }, [JSON.stringify(l), idx, 'right'].join('-')))) })] })) : null, _jsx("div", { ref: rubberbandRef, className: classes.rubberband, style: { left, width }, children: _jsx(Typography, { variant: "h6", className: classes.rubberbandText, children: numOfBpSelected.map((n, i) => (_jsx(Typography, { children: `${n.toLocaleString('en-US')}bp` }, `${n}_${i}`))) }) }), _jsx("div", { className: classes.rubberbandControl, ref: controlsRef, onMouseDown: mouseDown, onMouseOut: mouseOut, onMouseMove: mouseMove, children: ControlComponent }), anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
21
+ const { guideX, rubberbandOn, leftBpOffset, rightBpOffset, numOfBpSelected, width, left, anchorPosition, open, handleMenuItemClick, handleClose, mouseMove, mouseDown, mouseOut, } = useRangeSelect(ref, model);
22
+ return (_jsxs(_Fragment, { children: [guideX !== undefined ? (_jsx(VerticalGuide, { model: model, coordX: guideX })) : rubberbandOn ? (_jsx(RubberbandSpan, { leftBpOffset: leftBpOffset, rightBpOffset: rightBpOffset, numOfBpSelected: numOfBpSelected, width: width, left: left })) : null, anchorPosition ? (_jsx(Menu, { anchorReference: "anchorPosition", anchorPosition: {
161
23
  left: anchorPosition.clientX,
162
24
  top: anchorPosition.clientY,
163
- }, onMenuItemClick: handleMenuItemClick, open: open, onClose: handleClose, menuItems: model.rubberBandMenuItems() })) : null] }));
25
+ }, onMenuItemClick: handleMenuItemClick, open: open, onClose: handleClose, menuItems: model.rubberBandMenuItems() })) : null, _jsx("div", { "data-testid": "rubberband_controls", className: classes.rubberbandControl, ref: ref, onMouseDown: mouseDown, onMouseMove: mouseMove, onMouseOut: mouseOut, children: ControlComponent })] }));
164
26
  });
165
- export default LinearComparativeRubberband;
27
+ export default Rubberband;
@@ -0,0 +1,15 @@
1
+ interface Offset {
2
+ coord: number;
3
+ refName?: string;
4
+ oob?: boolean;
5
+ }
6
+ export default function RubberbandSpan({ leftBpOffset, rightBpOffset, numOfBpSelected, left, width, top, sticky, }: {
7
+ leftBpOffset: Offset[];
8
+ rightBpOffset: Offset[];
9
+ numOfBpSelected?: number[];
10
+ left: number;
11
+ width: number;
12
+ top?: number;
13
+ sticky?: boolean;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ export {};
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { getBpDisplayStr, stringify } from '@jbrowse/core/util';
4
+ import { Typography, alpha } from '@mui/material';
5
+ import { makeStyles } from 'tss-react/mui';
6
+ import RubberbandTooltip from './RubberbandTooltip';
7
+ const useStyles = makeStyles()(theme => {
8
+ const { tertiary } = theme.palette;
9
+ const background = alpha(tertiary.light, 0.7);
10
+ return {
11
+ rubberband: {
12
+ height: '100%',
13
+ background,
14
+ position: 'absolute',
15
+ zIndex: 830,
16
+ textAlign: 'center',
17
+ },
18
+ rubberbandText: {
19
+ color: theme.palette.tertiary.contrastText,
20
+ },
21
+ };
22
+ });
23
+ export default function RubberbandSpan({ leftBpOffset, rightBpOffset, numOfBpSelected, left, width, top = 0, sticky = false, }) {
24
+ const { classes } = useStyles();
25
+ const [anchorEl, setAnchorEl] = useState(null);
26
+ return (_jsxs(_Fragment, { children: [anchorEl ? (_jsxs(_Fragment, { children: [_jsx(RubberbandTooltip, { side: "left", anchorEl: anchorEl, text: leftBpOffset.map((l, idx) => (_jsx("div", { children: stringify(l, true) }, `JSON.stringify(l)-${idx}`))) }), _jsx(RubberbandTooltip, { side: "right", anchorEl: anchorEl, text: rightBpOffset.map((l, idx) => (_jsx("div", { children: stringify(l, true) }, `JSON.stringify(l)-${idx}`))) })] })) : null, _jsx("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? (_jsx(Typography, { ref: el => {
27
+ setAnchorEl(el);
28
+ }, variant: "h6", className: classes.rubberbandText, style: {
29
+ top,
30
+ position: sticky ? 'sticky' : undefined,
31
+ }, children: numOfBpSelected.map((n, i) => (_jsx("div", { children: getBpDisplayStr(n) }, i))) })) : null })] }));
32
+ }
@@ -0,0 +1,5 @@
1
+ export default function RubberbandTooltip({ anchorEl, side, text, }: {
2
+ anchorEl: HTMLSpanElement;
3
+ side: string;
4
+ text: React.ReactNode;
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Tooltip } from '@mui/material';
3
+ export default function RubberbandTooltip({ anchorEl, side, text, }) {
4
+ return (_jsx(Tooltip, { title: text, open: true, placement: side === 'left' ? 'left-start' : 'right-start', slotProps: {
5
+ popper: {
6
+ anchorEl,
7
+ modifiers: [
8
+ {
9
+ name: 'offset',
10
+ options: {
11
+ offset: [-30, -10],
12
+ },
13
+ },
14
+ ],
15
+ },
16
+ }, children: _jsx("span", {}) }));
17
+ }
@@ -0,0 +1,59 @@
1
+ import type React from 'react';
2
+ import type { LinearComparativeViewModel } from '../model';
3
+ interface AnchorPosition {
4
+ offsetX: number;
5
+ clientX: number;
6
+ clientY: number;
7
+ }
8
+ export declare function useRangeSelect(ref: React.RefObject<HTMLDivElement | null>, model: LinearComparativeViewModel): {
9
+ open: boolean;
10
+ guideX: number | undefined;
11
+ mouseDown: (event: React.MouseEvent<HTMLDivElement>) => void;
12
+ mouseMove: (event: React.MouseEvent<HTMLDivElement>) => void;
13
+ mouseOut: () => void;
14
+ handleMenuItemClick: (_: unknown, callback: () => void) => void;
15
+ rubberbandOn?: undefined;
16
+ handleClose?: undefined;
17
+ leftBpOffset?: undefined;
18
+ rightBpOffset?: undefined;
19
+ anchorPosition?: undefined;
20
+ numOfBpSelected?: undefined;
21
+ width?: undefined;
22
+ left?: undefined;
23
+ } | {
24
+ open: boolean;
25
+ rubberbandOn: boolean;
26
+ mouseDown: (event: React.MouseEvent<HTMLDivElement>) => void;
27
+ mouseMove: (event: React.MouseEvent<HTMLDivElement>) => void;
28
+ mouseOut: () => void;
29
+ handleClose: () => void;
30
+ handleMenuItemClick: (_: unknown, callback: () => void) => void;
31
+ leftBpOffset: {
32
+ coord: number;
33
+ index: number;
34
+ refName: string;
35
+ oob: boolean;
36
+ assemblyName: string;
37
+ offset: number;
38
+ start: number;
39
+ end: number;
40
+ reversed?: boolean;
41
+ }[];
42
+ rightBpOffset: {
43
+ coord: number;
44
+ index: number;
45
+ refName: string;
46
+ oob: boolean;
47
+ assemblyName: string;
48
+ offset: number;
49
+ start: number;
50
+ end: number;
51
+ reversed?: boolean;
52
+ }[];
53
+ anchorPosition: AnchorPosition | undefined;
54
+ numOfBpSelected: number[];
55
+ width: number;
56
+ left: number;
57
+ guideX?: undefined;
58
+ };
59
+ export {};
@@ -0,0 +1,125 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { transaction } from 'mobx';
3
+ import { getRelativeX } from './util';
4
+ export function useRangeSelect(ref, model) {
5
+ const [startX, setStartX] = useState();
6
+ const [currentX, setCurrentX] = useState();
7
+ const [anchorPosition, setAnchorPosition] = useState();
8
+ const [guideX, setGuideX] = useState();
9
+ const mouseDragging = startX !== undefined && anchorPosition === undefined;
10
+ useEffect(() => {
11
+ function computeOffsets(offsetX) {
12
+ if (startX === undefined) {
13
+ return;
14
+ }
15
+ const leftPx = Math.min(startX, offsetX);
16
+ const rightPx = Math.max(startX, offsetX);
17
+ return model.views.map(view => ({
18
+ leftOffset: view.pxToBp(leftPx),
19
+ rightOffset: view.pxToBp(rightPx),
20
+ }));
21
+ }
22
+ function globalMouseMove(event) {
23
+ if (ref.current && mouseDragging) {
24
+ const relativeX = getRelativeX(event, ref.current);
25
+ setCurrentX(relativeX);
26
+ }
27
+ }
28
+ function globalMouseUp(event) {
29
+ if (startX !== undefined && ref.current) {
30
+ const { clientX, clientY } = event;
31
+ const offsetX = getRelativeX(event, ref.current);
32
+ setAnchorPosition({
33
+ offsetX,
34
+ clientX,
35
+ clientY,
36
+ });
37
+ const offsets = computeOffsets(offsetX);
38
+ if (offsets) {
39
+ transaction(() => {
40
+ for (const [idx, elt] of offsets.entries()) {
41
+ model.views[idx].setOffsets(elt.leftOffset, elt.rightOffset);
42
+ }
43
+ });
44
+ }
45
+ setGuideX(undefined);
46
+ }
47
+ }
48
+ if (mouseDragging) {
49
+ window.addEventListener('mousemove', globalMouseMove);
50
+ window.addEventListener('mouseup', globalMouseUp);
51
+ return () => {
52
+ window.removeEventListener('mousemove', globalMouseMove);
53
+ window.removeEventListener('mouseup', globalMouseUp);
54
+ };
55
+ }
56
+ return () => { };
57
+ }, [startX, mouseDragging, model, ref]);
58
+ useEffect(() => {
59
+ if (!mouseDragging &&
60
+ currentX !== undefined &&
61
+ startX !== undefined &&
62
+ Math.abs(currentX - startX) <= 3) {
63
+ handleClose();
64
+ }
65
+ }, [mouseDragging, currentX, startX]);
66
+ function mouseDown(event) {
67
+ event.preventDefault();
68
+ event.stopPropagation();
69
+ const relativeX = getRelativeX(event, ref.current);
70
+ setStartX(relativeX);
71
+ setCurrentX(relativeX);
72
+ }
73
+ function mouseMove(event) {
74
+ setGuideX(getRelativeX(event, ref.current));
75
+ }
76
+ function mouseOut() {
77
+ setGuideX(undefined);
78
+ transaction(() => {
79
+ for (const view of model.views) {
80
+ view.setOffsets(undefined, undefined);
81
+ }
82
+ });
83
+ }
84
+ function handleClose() {
85
+ setAnchorPosition(undefined);
86
+ setStartX(undefined);
87
+ setCurrentX(undefined);
88
+ }
89
+ function handleMenuItemClick(_, callback) {
90
+ callback();
91
+ handleClose();
92
+ }
93
+ const open = Boolean(anchorPosition);
94
+ if (startX === undefined) {
95
+ return {
96
+ open,
97
+ guideX,
98
+ mouseDown,
99
+ mouseMove,
100
+ mouseOut,
101
+ handleMenuItemClick,
102
+ };
103
+ }
104
+ const right = anchorPosition ? anchorPosition.offsetX : currentX || 0;
105
+ const left = Math.min(right, startX);
106
+ const width = Math.abs(right - startX);
107
+ const leftBpOffset = model.views.map(view => view.pxToBp(left));
108
+ const rightBpOffset = model.views.map(view => view.pxToBp(left + width));
109
+ const numOfBpSelected = model.views.map(view => Math.ceil(width * view.bpPerPx));
110
+ return {
111
+ open,
112
+ rubberbandOn: true,
113
+ mouseDown,
114
+ mouseMove,
115
+ mouseOut,
116
+ handleClose,
117
+ handleMenuItemClick,
118
+ leftBpOffset,
119
+ rightBpOffset,
120
+ anchorPosition,
121
+ numOfBpSelected,
122
+ width,
123
+ left,
124
+ };
125
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getRelativeX(event: {
2
+ clientX: number;
3
+ target: EventTarget | null;
4
+ }, element: HTMLElement | null): number;
@@ -0,0 +1,3 @@
1
+ export function getRelativeX(event, element) {
2
+ return event.clientX - ((element === null || element === void 0 ? void 0 : element.getBoundingClientRect().left) || 0);
3
+ }
@@ -0,0 +1,3 @@
1
+ export default function BlockError({ error }: {
2
+ error: unknown;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { makeStyles } from 'tss-react/mui';
3
+ const useStyles = makeStyles()({
4
+ blockError: {
5
+ background: '#f1f1f1',
6
+ padding: 10,
7
+ color: 'red',
8
+ },
9
+ });
10
+ export default function BlockError({ error }) {
11
+ const { classes } = useStyles();
12
+ return _jsx("div", { className: classes.blockError, children: `${error}` });
13
+ }
@@ -0,0 +1,3 @@
1
+ export default function BlockMessage({ messageText }: {
2
+ messageText: string;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { makeStyles } from 'tss-react/mui';
3
+ const useStyles = makeStyles()(theme => {
4
+ const bg = theme.palette.action.disabledBackground;
5
+ return {
6
+ loading: {
7
+ paddingLeft: '0.6em',
8
+ backgroundColor: theme.palette.background.default,
9
+ backgroundImage: `repeating-linear-gradient(45deg, transparent, transparent 5px, ${bg} 5px, ${bg} 10px)`,
10
+ textAlign: 'center',
11
+ },
12
+ blockMessage: {
13
+ background: '#f1f1f1',
14
+ padding: 10,
15
+ },
16
+ };
17
+ });
18
+ export default function BlockMessage({ messageText }) {
19
+ const { classes } = useStyles();
20
+ return _jsx("div", { className: classes.blockMessage, children: messageText });
21
+ }
@@ -1,60 +1,21 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { LoadingEllipses } from '@jbrowse/core/ui';
4
2
  import { observer } from 'mobx-react';
5
- import { makeStyles } from 'tss-react/mui';
3
+ import BlockError from './BlockError';
4
+ import BlockMessage from './BlockMessage';
6
5
  import LinearSyntenyRendering from './LinearSyntenyRendering';
7
- const useStyles = makeStyles()(theme => {
8
- const bg = theme.palette.action.disabledBackground;
9
- return {
10
- loading: {
11
- paddingLeft: '0.6em',
12
- backgroundColor: theme.palette.background.default,
13
- backgroundImage: `repeating-linear-gradient(45deg, transparent, transparent 5px, ${bg} 5px, ${bg} 10px)`,
14
- textAlign: 'center',
15
- },
16
- blockMessage: {
17
- background: '#f1f1f1',
18
- padding: 10,
19
- },
20
- blockError: {
21
- background: '#f1f1f1',
22
- padding: 10,
23
- color: 'red',
24
- },
25
- };
26
- });
27
- function LoadingMessage() {
28
- const [shown, setShown] = useState(false);
29
- const { classes } = useStyles();
30
- useEffect(() => {
31
- const timeout = setTimeout(() => {
32
- setShown(true);
33
- }, 300);
34
- return () => {
35
- clearTimeout(timeout);
36
- };
37
- });
38
- return shown ? (_jsx("div", { className: classes.loading, children: _jsx(LoadingEllipses, {}) })) : null;
39
- }
40
- function BlockMessage({ messageText }) {
41
- const { classes } = useStyles();
42
- return _jsx("div", { className: classes.blockMessage, children: messageText });
43
- }
44
- function BlockError({ error }) {
45
- const { classes } = useStyles();
46
- return _jsx("div", { className: classes.blockError, children: `${error}` });
47
- }
6
+ import LoadingMessage from './LoadingMessage';
48
7
  const ServerSideRenderedBlockContent = observer(function ({ model, }) {
49
8
  if (model.error) {
50
9
  return _jsx(BlockError, { error: model.error });
51
10
  }
52
- if (model.message) {
11
+ else if (model.message) {
53
12
  return _jsx(BlockMessage, { messageText: model.message });
54
13
  }
55
- if (!model.features) {
56
- return _jsx(LoadingMessage, {});
14
+ else if (!model.features) {
15
+ return _jsx(LoadingMessage, { message: model.loadingStatus });
16
+ }
17
+ else {
18
+ return _jsx(LinearSyntenyRendering, { model: model });
57
19
  }
58
- return _jsx(LinearSyntenyRendering, { model: model });
59
20
  });
60
21
  export default ServerSideRenderedBlockContent;
@@ -0,0 +1,3 @@
1
+ export default function LoadingMessage({ message }: {
2
+ message?: string;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { LoadingEllipses } from '@jbrowse/core/ui';
3
+ import { makeStyles } from 'tss-react/mui';
4
+ const useStyles = makeStyles()(theme => {
5
+ const bg = theme.palette.action.disabledBackground;
6
+ return {
7
+ loading: {
8
+ paddingLeft: '0.6em',
9
+ backgroundColor: theme.palette.background.default,
10
+ backgroundImage: `repeating-linear-gradient(45deg, transparent, transparent 5px, ${bg} 5px, ${bg} 10px)`,
11
+ textAlign: 'center',
12
+ },
13
+ };
14
+ });
15
+ export default function LoadingMessage({ message }) {
16
+ const { classes } = useStyles();
17
+ return (_jsx("div", { className: classes.loading, children: _jsx(LoadingEllipses, { message: message }) }));
18
+ }
@@ -84,6 +84,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
84
84
  renderInProgress: string | undefined;
85
85
  features: Feature[] | undefined;
86
86
  message: string | undefined;
87
+ loadingStatus: string | undefined;
87
88
  } & {
88
89
  readonly level: number;
89
90
  readonly height: number;
@@ -166,6 +167,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
166
167
  renderInProgress: string | undefined;
167
168
  features: Feature[] | undefined;
168
169
  message: string | undefined;
170
+ loadingStatus: string | undefined;
169
171
  } & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
170
172
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
171
173
  type: import("mobx-state-tree").ISimpleType<string>;
@@ -235,12 +237,14 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
235
237
  renderInProgress: string | undefined;
236
238
  features: Feature[] | undefined;
237
239
  message: string | undefined;
240
+ loadingStatus: string | undefined;
238
241
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
239
242
  highResolutionScaling: number;
240
243
  };
241
244
  } & {
242
245
  setLoading(newStopToken: string): void;
243
246
  setMessage(messageText: string): void;
247
+ setLoadingStatus(messageText: string): void;
244
248
  setRendered(args?: {
245
249
  features: Feature[];
246
250
  }): void;