higlass 2.2.3 → 2.3.1

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 (37) hide show
  1. package/app/scripts/Autocomplete.jsx +12 -3
  2. package/app/scripts/Button.jsx +20 -24
  3. package/app/scripts/ContextMenuContainer.jsx +1 -3
  4. package/app/scripts/ContextMenuItem.jsx +15 -16
  5. package/app/scripts/Dialog.jsx +30 -29
  6. package/app/scripts/HiGlassComponent.jsx +74 -40
  7. package/app/scripts/HorizontalItem.jsx +50 -21
  8. package/app/scripts/HorizontalTrack.jsx +1 -0
  9. package/app/scripts/ListWrapper.jsx +6 -17
  10. package/app/scripts/Modal.jsx +14 -13
  11. package/app/scripts/PopupMenu.jsx +6 -12
  12. package/app/scripts/SortableList.jsx +119 -64
  13. package/app/scripts/TrackArea.jsx +19 -24
  14. package/app/scripts/TrackControl.jsx +16 -27
  15. package/app/scripts/VerticalItem.jsx +53 -22
  16. package/app/scripts/VerticalTrack.jsx +1 -0
  17. package/app/scripts/api.js +5 -4
  18. package/app/scripts/hglib.jsx +34 -4
  19. package/app/scripts/test-helpers/test-helpers.jsx +2 -2
  20. package/app/scripts/utils/get-higlass-components.js +2 -2
  21. package/app/scripts/utils/react-dom-compat.js +100 -0
  22. package/app/styles/HiGlass.scss +1 -0
  23. package/dist/app/scripts/Autocomplete.d.ts +3 -1
  24. package/dist/app/scripts/ContextMenuContainer.d.ts +0 -1
  25. package/dist/app/scripts/ContextMenuItem.d.ts +9 -15
  26. package/dist/app/scripts/HiGlassComponent.d.ts +0 -3
  27. package/dist/app/scripts/HorizontalItem.d.ts +1 -1
  28. package/dist/app/scripts/ListWrapper.d.ts +2 -7
  29. package/dist/app/scripts/PopupMenu.d.ts +2 -4
  30. package/dist/app/scripts/SortableList.d.ts +6 -2
  31. package/dist/app/scripts/VerticalItem.d.ts +1 -1
  32. package/dist/app/scripts/utils/react-dom-compat.d.ts +27 -0
  33. package/dist/hglib.js +13142 -11160
  34. package/dist/hglib.min.js +89 -89
  35. package/dist/higlass.mjs +13150 -11168
  36. package/dist/package.json +7 -5
  37. package/package.json +7 -5
@@ -17,6 +17,9 @@ class Autocomplete extends React.Component {
17
17
  isOpen: false,
18
18
  };
19
19
 
20
+ this.itemRefs = {};
21
+ this.menuRef = null;
22
+
20
23
  this.keyDownHandlers = {
21
24
  ArrowDown(event) {
22
25
  event.preventDefault();
@@ -139,7 +142,7 @@ class Autocomplete extends React.Component {
139
142
 
140
143
  maybeScrollItemIntoView() {
141
144
  if (this.state.isOpen === true && this.state.highlightedIndex !== null) {
142
- const itemNode = this.refs[`item-${this.state.highlightedIndex}`];
145
+ const itemNode = this.itemRefs[this.state.highlightedIndex];
143
146
  itemNode?.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
144
147
  }
145
148
  }
@@ -250,7 +253,9 @@ class Autocomplete extends React.Component {
250
253
  // Ignore blur to prevent menu from de-rendering before we can process click
251
254
  onMouseEnter: () => this.highlightItemFromMouse(index),
252
255
  onClick: () => this.selectItemFromMouse(item),
253
- ref: `item-${index}`,
256
+ ref: (el) => {
257
+ this.itemRefs[index] = el;
258
+ },
254
259
  });
255
260
  });
256
261
  const style = {
@@ -260,7 +265,11 @@ class Autocomplete extends React.Component {
260
265
  };
261
266
  if (!items.length) return null;
262
267
  const menu = this.props.renderMenu(items, this.props.value, style);
263
- return React.cloneElement(menu, { ref: 'menu' });
268
+ return React.cloneElement(menu, {
269
+ ref: (el) => {
270
+ this.menuRef = el;
271
+ },
272
+ });
264
273
  }
265
274
 
266
275
  handleInputBlur() {
@@ -4,30 +4,26 @@ import React from 'react';
4
4
 
5
5
  import classes from '../styles/Button.module.scss';
6
6
 
7
- const Button = React.forwardRef((props, ref) => (
8
- <button
9
- ref={ref}
10
- className={classes[props.styleName] ?? classes.button}
11
- disabled={props.disable}
12
- onBlur={props.onBlur}
13
- onClick={props.onClick}
14
- onMouseDown={props.onMouseDown}
15
- onMouseOut={props.onMouseOut}
16
- onMouseUp={props.onMouseUp}
17
- type="button"
18
- >
19
- {props.children}
20
- {props.shortcut && (
21
- <span className={classes['button-shortcut']}>{props.shortcut}</span>
22
- )}
23
- </button>
24
- ));
25
-
26
- Button.defaultProps = {
27
- onClick: () => {},
28
- styleName: '',
29
- type: 'button',
30
- };
7
+ const Button = React.forwardRef(
8
+ ({ onClick = () => {}, styleName = '', children, ...props }, ref) => (
9
+ <button
10
+ ref={ref}
11
+ className={classes[styleName] ?? classes.button}
12
+ disabled={props.disable}
13
+ onBlur={props.onBlur}
14
+ onClick={onClick}
15
+ onMouseDown={props.onMouseDown}
16
+ onMouseOut={props.onMouseOut}
17
+ onMouseUp={props.onMouseUp}
18
+ type="button"
19
+ >
20
+ {children}
21
+ {props.shortcut && (
22
+ <span className={classes['button-shortcut']}>{props.shortcut}</span>
23
+ )}
24
+ </button>
25
+ ),
26
+ );
31
27
 
32
28
  Button.propTypes = {
33
29
  children: PropTypes.any,
@@ -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 ReactDOM from 'react-dom';
6
5
 
7
6
  import { THEME_DARK } from './configs';
8
7
 
@@ -101,8 +100,7 @@ class ContextMenuContainer extends React.Component {
101
100
  if (this.adjusted) return;
102
101
 
103
102
  this.adjusted = true;
104
- this.divDom = ReactDOM.findDOMNode(this.div);
105
- const bbox = this.divDom.getBoundingClientRect();
103
+ const bbox = this.div.getBoundingClientRect();
106
104
 
107
105
  const parentBbox = this.props.parentBbox
108
106
  ? this.props.parentBbox
@@ -9,37 +9,36 @@ import classes from '../styles/ContextMenu.module.scss';
9
9
  * @typedef ContextMenuItemProps
10
10
  * @prop {string} [className]
11
11
  * @prop {(evt: React.MouseEvent) => void} onClick
12
- * @prop {(evt: React.MouseEvent) => void} onMouseEnter
13
- * @prop {(evt: React.MouseEvent) => void} onMouseLeave
12
+ * @prop {(evt: React.MouseEvent) => void} [onMouseEnter]
13
+ * @prop {(evt: React.MouseEvent) => void} [onMouseLeave]
14
14
  */
15
15
 
16
16
  /**
17
17
  * @param {React.PropsWithChildren<ContextMenuItemProps>} props
18
18
  */
19
- function ContextMenuItem(props) {
19
+ function ContextMenuItem({
20
+ onMouseEnter = () => undefined,
21
+ onMouseLeave = () => undefined,
22
+ onClick,
23
+ className,
24
+ children,
25
+ }) {
20
26
  return (
21
27
  <div
22
- data-menu-item-for={
23
- typeof props.children === 'string' ? props.children : null
24
- }
25
- className={clsx(classes['context-menu-item'], props.className)}
26
- onClick={(e) => props.onClick(e)}
27
- onMouseEnter={(e) => props.onMouseEnter(e)}
28
- onMouseLeave={(e) => props.onMouseLeave(e)}
28
+ data-menu-item-for={typeof children === 'string' ? children : null}
29
+ className={clsx(classes['context-menu-item'], className)}
30
+ onClick={(e) => onClick(e)}
31
+ onMouseEnter={(e) => onMouseEnter(e)}
32
+ onMouseLeave={(e) => onMouseLeave(e)}
29
33
  // biome-ignore lint/a11y/useSemanticElements:
30
34
  role="button"
31
35
  tabIndex={0}
32
36
  >
33
- <span className={classes['context-menu-span']}>{props.children}</span>
37
+ <span className={classes['context-menu-span']}>{children}</span>
34
38
  </div>
35
39
  );
36
40
  }
37
41
 
38
- ContextMenuItem.defaultProps = {
39
- onMouseEnter: () => undefined,
40
- onMouseLeave: () => undefined,
41
- };
42
-
43
42
  ContextMenuItem.propTypes = {
44
43
  children: PropTypes.node.isRequired,
45
44
  onClick: PropTypes.func.isRequired,
@@ -10,53 +10,62 @@ import withModal from './hocs/with-modal';
10
10
 
11
11
  import classes from '../styles/Dialog.module.scss';
12
12
 
13
- function Dialog(props) {
13
+ function Dialog({
14
+ cancelTitle = 'Cancel',
15
+ hide = false,
16
+ maxHeight = false,
17
+ okayOnly = false,
18
+ okayTitle = 'Ok',
19
+ modal,
20
+ onCancel,
21
+ onOkay,
22
+ title,
23
+ cancelShortcut,
24
+ okayShortcut,
25
+ children,
26
+ }) {
14
27
  const handleCancel = () => {
15
- props.modal.close();
16
- if (props.onCancel) props.onCancel();
28
+ modal.close();
29
+ if (onCancel) onCancel();
17
30
  };
18
31
 
19
32
  const handleOkay = () => {
20
- props.modal.close();
21
- if (props.onOkay) props.onOkay();
33
+ modal.close();
34
+ if (onOkay) onOkay();
22
35
  };
23
36
 
24
37
  return (
25
- <Modal closeButton={false} hide={props.hide} maxHeight={props.maxHeight}>
38
+ <Modal closeButton={false} hide={hide} maxHeight={maxHeight}>
26
39
  <>
27
40
  <header className={classes['dialog-header']}>
28
- <h3>{props.title}</h3>
41
+ <h3>{title}</h3>
29
42
  <Button onClick={handleCancel}>
30
43
  <Cross />
31
44
  </Button>
32
45
  </header>
33
- {props.maxHeight ? (
46
+ {maxHeight ? (
34
47
  <main
35
- className={clsx(
36
- props.maxHeight && classes['dialog-main-max-height'],
37
- )}
48
+ className={clsx(maxHeight && classes['dialog-main-max-height'])}
38
49
  >
39
- {props.children}
50
+ {children}
40
51
  </main>
41
52
  ) : (
42
- <main>{props.children}</main>
53
+ <main>{children}</main>
43
54
  )}
44
55
  <footer
45
56
  className={
46
- classes[
47
- props.maxHeight ? 'dialog-footer-max-height' : 'dialog-footer'
48
- ]
57
+ classes[maxHeight ? 'dialog-footer-max-height' : 'dialog-footer']
49
58
  }
50
59
  >
51
- {props.okayOnly ? (
60
+ {okayOnly ? (
52
61
  <div />
53
62
  ) : (
54
- <Button onClick={handleCancel} shortcut={props.cancelShortcut}>
55
- {props.cancelTitle}
63
+ <Button onClick={handleCancel} shortcut={cancelShortcut}>
64
+ {cancelTitle}
56
65
  </Button>
57
66
  )}
58
- <Button onClick={handleOkay} shortcut={props.okayShortcut}>
59
- {props.okayTitle}
67
+ <Button onClick={handleOkay} shortcut={okayShortcut}>
68
+ {okayTitle}
60
69
  </Button>
61
70
  </footer>
62
71
  </>
@@ -64,14 +73,6 @@ function Dialog(props) {
64
73
  );
65
74
  }
66
75
 
67
- Dialog.defaultProps = {
68
- cancelTitle: 'Cancel',
69
- hide: false,
70
- maxHeight: false,
71
- okayOnly: false,
72
- okayTitle: 'Ok',
73
- };
74
-
75
76
  Dialog.propTypes = {
76
77
  cancelShortcut: PropTypes.string,
77
78
  cancelTitle: PropTypes.string,
@@ -7,9 +7,8 @@ import * as PIXI from 'pixi.js';
7
7
  import PropTypes from 'prop-types';
8
8
  import createPubSub, { globalPubSub } from 'pub-sub-es';
9
9
  import React from 'react';
10
- import ReactGridLayout from 'react-grid-layout';
10
+ import ReactGridLayout, { getCompactor } from 'react-grid-layout';
11
11
  import slugid from 'slugid';
12
- import parse from 'url-parse';
13
12
  import vkbeautify from 'vkbeautify';
14
13
 
15
14
  import ChromosomeInfo from './ChromosomeInfo';
@@ -290,7 +289,6 @@ class HiGlassComponent extends React.Component {
290
289
  this.pluginDataFetchers = pluginDataFetchers;
291
290
 
292
291
  this.state = {
293
- currentBreakpoint: 'lg',
294
292
  width: 0,
295
293
  height: 0,
296
294
  rowHeight,
@@ -555,10 +553,18 @@ class HiGlassComponent extends React.Component {
555
553
  this.fitPixiToParentContainer();
556
554
 
557
555
  // keep track of the width and height of this element, because it
558
- // needs to be reflected in the size of our drawing surface
556
+ // needs to be reflected in the size of our drawing surface.
557
+ // Also measure initial width so that ReactGridLayout renders grid items
558
+ // with valid dimensions on the first mounted render. Without this,
559
+ // width=0 causes react-grid-layout v2 to calculate negative column
560
+ // widths, and TiledPlot's ResizeSensor fails to detect the subsequent
561
+ // resize from zero to the actual size.
562
+ const [initialWidth, initialHeight] = getElementDim(this.element);
559
563
  this.setState({
560
564
  svgElement: this.svgElement,
561
565
  canvasElement: this.canvasElement,
566
+ ...(initialWidth > 0 ? { width: initialWidth } : {}),
567
+ ...(initialHeight > 0 ? { height: initialHeight } : {}),
562
568
  });
563
569
 
564
570
  this.waitForDOMAttachment(() => {
@@ -588,11 +594,11 @@ class HiGlassComponent extends React.Component {
588
594
  }
589
595
 
590
596
  getTrackObject(viewUid, trackUid) {
591
- return this.tiledPlots[viewUid].trackRenderer.getTrackObject(trackUid);
597
+ return this.tiledPlots[viewUid]?.trackRenderer?.getTrackObject(trackUid);
592
598
  }
593
599
 
594
600
  getTrackRenderer(viewUid) {
595
- return this.tiledPlots[viewUid].trackRenderer;
601
+ return this.tiledPlots[viewUid]?.trackRenderer;
596
602
  }
597
603
 
598
604
  UNSAFE_componentWillReceiveProps(newProps) {
@@ -985,12 +991,6 @@ class HiGlassComponent extends React.Component {
985
991
  this.resizeHandler();
986
992
  }
987
993
 
988
- onBreakpointChange(breakpoint) {
989
- this.setState({
990
- currentBreakpoint: breakpoint,
991
- });
992
- }
993
-
994
994
  handleOverlayMouseEnter(uid) {
995
995
  this.setState({
996
996
  mouseOverOverlayUid: uid,
@@ -1316,7 +1316,7 @@ class HiGlassComponent extends React.Component {
1316
1316
  ) > epsilon;
1317
1317
 
1318
1318
  const hasBrushMoved =
1319
- sourceTrack.options &&
1319
+ sourceTrack?.options &&
1320
1320
  lockedTrack.options &&
1321
1321
  typeof sourceTrack.options.scaleStartPercent !== 'undefined' &&
1322
1322
  typeof sourceTrack.options.scaleEndPercent !== 'undefined' &&
@@ -4196,6 +4196,7 @@ class HiGlassComponent extends React.Component {
4196
4196
  }
4197
4197
 
4198
4198
  triggerViewChange() {
4199
+ if (!this.mounted) return;
4199
4200
  const viewsString = this.getViewsAsString();
4200
4201
  this.viewChangeListener.forEach((callback) => callback(viewsString));
4201
4202
  }
@@ -5186,6 +5187,12 @@ class HiGlassComponent extends React.Component {
5186
5187
  x.type === 'vertical-chromosome-labels' ||
5187
5188
  x.type === 'chromosome-labels',
5188
5189
  );
5190
+ const uniqueAnnotationTilesets = new Set(
5191
+ annotationTracks.map((x) => x.tilesetUid),
5192
+ );
5193
+ const uniqueChromSizesTilesets = new Set(
5194
+ chromSizesTracks.map((x) => x.tilesetUid),
5195
+ );
5189
5196
 
5190
5197
  const getGenomePositionSearchBox = (isFocused, onFocus) => (
5191
5198
  <GenomePositionSearchBox
@@ -5196,18 +5203,26 @@ class HiGlassComponent extends React.Component {
5196
5203
  }}
5197
5204
  // Custom props
5198
5205
  autocompleteId={
5199
- annotationTracks.length === 1
5206
+ annotationTracks.length >= 1 &&
5207
+ uniqueAnnotationTilesets.size === 1
5200
5208
  ? annotationTracks[0].tilesetUid
5201
5209
  : null
5202
5210
  }
5203
5211
  autocompleteServer={
5204
- annotationTracks.length === 1 ? annotationTracks[0].server : null
5212
+ annotationTracks.length >= 1 &&
5213
+ uniqueAnnotationTilesets.size === 1
5214
+ ? annotationTracks[0].server
5215
+ : null
5205
5216
  }
5206
5217
  chromInfoId={
5207
- chromSizesTracks.length ? chromSizesTracks[0].tilesetUid : null
5218
+ (chromSizesTracks.length && chromSizesTracks[0].tilesetUid) ||
5219
+ view.genomePositionSearchBox?.chromInfoId ||
5220
+ null
5208
5221
  }
5209
5222
  chromInfoServer={
5210
- chromSizesTracks.length ? chromSizesTracks[0].server : null
5223
+ (chromSizesTracks.length && chromSizesTracks[0].server) ||
5224
+ view.genomePositionSearchBox?.chromInfoServer ||
5225
+ null
5211
5226
  }
5212
5227
  isFocused={isFocused}
5213
5228
  // the chromInfoId is either specified in the viewconfig or guessed based on
@@ -5228,8 +5243,10 @@ class HiGlassComponent extends React.Component {
5228
5243
  (chromSizesTracks.length === 0 &&
5229
5244
  'no chromosome track present') ||
5230
5245
  (chromSizesTracks.length >= 2 &&
5246
+ uniqueChromSizesTilesets.size > 1 &&
5231
5247
  'multiple chromosome tracks present') ||
5232
5248
  (annotationTracks.length >= 2 &&
5249
+ uniqueAnnotationTilesets.size > 1 &&
5233
5250
  'multiple annotation tracks present')
5234
5251
  }
5235
5252
  />
@@ -5317,8 +5334,29 @@ class HiGlassComponent extends React.Component {
5317
5334
  />
5318
5335
  ) : null;
5319
5336
 
5337
+ // Constrain the grid item child to the expected pixel height
5338
+ // derived from view.layout.h. react-grid-layout v2 syncs its
5339
+ // internal layout state via useEffect (async), so after a layout
5340
+ // change (e.g. track removal) the grid item's DOM dimensions can
5341
+ // be stale (too large). maxHeight ensures TiledPlot.measureSize()
5342
+ // reads the correct (new) height even before the grid re-syncs.
5343
+ const marginY = this.isEditable() ? 10 : 0;
5344
+ const expectedPixelHeight = view.layout
5345
+ ? Math.round(
5346
+ this.state.rowHeight * view.layout.h +
5347
+ Math.max(0, view.layout.h - 1) * marginY,
5348
+ )
5349
+ : undefined;
5350
+
5320
5351
  return (
5321
- <div key={view.uid}>
5352
+ <div
5353
+ key={view.uid}
5354
+ style={
5355
+ expectedPixelHeight !== undefined
5356
+ ? { maxHeight: expectedPixelHeight, overflow: 'hidden' }
5357
+ : undefined
5358
+ }
5359
+ >
5322
5360
  <div
5323
5361
  ref={(c) => {
5324
5362
  this.tiledAreasDivs[view.uid] = c;
@@ -5360,34 +5398,30 @@ class HiGlassComponent extends React.Component {
5360
5398
 
5361
5399
  const gridLayout = (
5362
5400
  <ReactGridLayout
5363
- // Reserved props
5364
- ref={(c) => {
5365
- this.gridLayout = c;
5401
+ gridConfig={{
5402
+ cols: 12,
5403
+ rowHeight: this.state.rowHeight,
5404
+ // for some reason, this becomes 40 within the react-grid component
5405
+ // (try resizing the component to see how much the height changes)
5406
+ // Programming by coincidence FTW :-/
5407
+ margin: this.isEditable() ? [10, 10] : [0, 0],
5408
+ containerPadding: [containerPaddingX, containerPaddingY],
5409
+ }}
5410
+ dragConfig={{
5411
+ enabled: this.isEditable(),
5412
+ handle: `.${stylesMTHeader['multitrack-header-grabber']}`,
5413
+ }}
5414
+ resizeConfig={{
5415
+ enabled: this.isEditable(),
5366
5416
  }}
5367
- // Custom props
5368
- cols={12}
5369
- containerPadding={[containerPaddingX, containerPaddingY]}
5370
- draggableHandle={`.${stylesMTHeader['multitrack-header-grabber']}`}
5371
- isDraggable={this.isEditable()}
5372
- isResizable={this.isEditable()}
5417
+ compactor={getCompactor(
5418
+ this.state.viewConfig.compactLayout === false ? null : 'vertical',
5419
+ )}
5373
5420
  layout={layouts}
5374
- margin={this.isEditable() ? [10, 10] : [0, 0]}
5375
- measureBeforeMount={false}
5376
- onBreakpointChange={this.onBreakpointChange.bind(this)}
5377
5421
  onDragStart={this.handleDragStart.bind(this)}
5378
5422
  onDragStop={this.handleDragStop.bind(this)}
5379
5423
  onLayoutChange={this.handleLayoutChange.bind(this)}
5380
5424
  onResize={this.resizeHandler.bind(this)}
5381
- rowHeight={this.state.rowHeight}
5382
- // for some reason, this becomes 40 within the react-grid component
5383
- // (try resizing the component to see how much the height changes)
5384
- // Programming by coincidence FTW :-/
5385
- // WidthProvider option
5386
- // I like to have it animate on mount. If you don't, delete
5387
- // `useCSSTransforms` (it's default `true`)
5388
- // and set `measureBeforeMount={true}`.
5389
- useCSSTransforms={this.mounted}
5390
- verticalCompact={this.state.viewConfig.compactLayout}
5391
5425
  width={this.state.width}
5392
5426
  >
5393
5427
  {this.tiledAreas}
@@ -1,30 +1,59 @@
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 HorizontalTrack from './HorizontalTrack';
6
8
 
7
- const HorizontalItem = SortableElement((props) => {
9
+ function HorizontalItem(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, x: 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
+
8
34
  return (
9
- <HorizontalTrack
10
- className={props.className}
11
- editable={props.editable}
12
- handleConfigTrack={props.handleConfigTrack}
13
- handleResizeTrack={props.handleResizeTrack}
14
- height={props.height}
15
- isCollapsed={props.isCollapsed}
16
- item={props.item}
17
- onAddSeries={props.onAddSeries}
18
- onCollapseTrack={props.onCollapseTrack}
19
- onExpandTrack={props.onExpandTrack}
20
- onCloseTrack={props.onCloseTrack}
21
- onCloseTrackMenuOpened={props.onCloseTrackMenuOpened}
22
- onConfigTrackMenuOpened={props.onConfigTrackMenuOpened}
23
- resizeHandles={props.resizeHandles}
24
- uid={props.uid}
25
- width={props.width}
26
- />
35
+ <div ref={setNodeRef} style={style}>
36
+ <HorizontalTrack
37
+ className={props.className}
38
+ dragHandleProps={{ ...attributes, ...listeners }}
39
+ editable={props.editable}
40
+ handleConfigTrack={props.handleConfigTrack}
41
+ handleResizeTrack={props.handleResizeTrack}
42
+ height={props.height}
43
+ isCollapsed={props.isCollapsed}
44
+ item={props.item}
45
+ onAddSeries={props.onAddSeries}
46
+ onCollapseTrack={props.onCollapseTrack}
47
+ onExpandTrack={props.onExpandTrack}
48
+ onCloseTrack={props.onCloseTrack}
49
+ onCloseTrackMenuOpened={props.onCloseTrackMenuOpened}
50
+ onConfigTrackMenuOpened={props.onConfigTrackMenuOpened}
51
+ resizeHandles={props.resizeHandles}
52
+ uid={props.uid}
53
+ width={props.width}
54
+ />
55
+ </div>
27
56
  );
28
- });
57
+ }
29
58
 
30
59
  export default HorizontalItem;
@@ -17,6 +17,7 @@ class HorizontalTrack extends MoveableTrack {
17
17
  // center.
18
18
  expandCollapseAvailable={true}
19
19
  configMenuVisible={this.props.item.configMenuVisible}
20
+ dragHandleProps={this.props.dragHandleProps}
20
21
  imgStyleAdd={STYLES}
21
22
  imgStyleClose={STYLES}
22
23
  imgStyleMove={STYLES}
@@ -1,8 +1,8 @@
1
1
  // @ts-nocheck
2
2
 
3
+ import { arrayMove } from '@dnd-kit/sortable';
3
4
  import PropTypes from 'prop-types';
4
5
  import React from 'react';
5
- import { arrayMove } from 'react-sortable-hoc';
6
6
 
7
7
  class ListWrapper extends React.Component {
8
8
  constructor({ items }) {
@@ -19,8 +19,7 @@ class ListWrapper extends React.Component {
19
19
  });
20
20
  }
21
21
 
22
- onSortStart({ node, index, collection }, e) {
23
- e.stopImmediatePropagation();
22
+ onSortStart({ index }) {
24
23
  const { onSortStart } = this.props;
25
24
  this.setState({ isSorting: true });
26
25
 
@@ -29,9 +28,6 @@ class ListWrapper extends React.Component {
29
28
  }
30
29
 
31
30
  this.sortingIndex = index;
32
-
33
- this.sortStartTop = e.offsetTop;
34
- this.sortStartLeft = e.offsetLeft;
35
31
  }
36
32
 
37
33
  onSortMove() {}
@@ -39,14 +35,15 @@ class ListWrapper extends React.Component {
39
35
  onSortEnd({ oldIndex, newIndex }) {
40
36
  const { onSortEnd } = this.props;
41
37
  const { items } = this.state;
38
+ const sortedItems = arrayMove(items, oldIndex, newIndex);
42
39
 
43
40
  this.setState({
44
- items: arrayMove(items, oldIndex, newIndex),
41
+ items: sortedItems,
45
42
  isSorting: false,
46
43
  });
47
44
 
48
45
  if (onSortEnd) {
49
- onSortEnd(this.state.items);
46
+ onSortEnd(sortedItems);
50
47
  }
51
48
 
52
49
  this.sortingIndex = null;
@@ -63,15 +60,7 @@ class ListWrapper extends React.Component {
63
60
  onSortMove: this.onSortMove.bind(this),
64
61
  };
65
62
 
66
- return (
67
- <Component
68
- {...this.props}
69
- {...props}
70
- ref={(element) => {
71
- this.ref = element;
72
- }}
73
- />
74
- );
63
+ return <Component {...this.props} {...props} />;
75
64
  }
76
65
  }
77
66