/
DragLayer.js
125 lines (105 loc) · 3.82 KB
/
DragLayer.js
1
2
3
4
5
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import React, { Component, PropTypes } from 'react';
import hoistStatics from 'hoist-non-react-statics';
import isPlainObject from 'lodash/isPlainObject';
import invariant from 'invariant';
import shallowEqual from './utils/shallowEqual';
import shallowEqualScalar from './utils/shallowEqualScalar';
import checkDecoratorArguments from './utils/checkDecoratorArguments';
export default function DragLayer(collect, options = {}) {
checkDecoratorArguments('DragLayer', 'collect[, options]', ...arguments); // eslint-disable-line prefer-rest-params
invariant(
typeof collect === 'function',
'Expected "collect" provided as the first argument to DragLayer ' +
'to be a function that collects props to inject into the component. ',
'Instead, received %s. ' +
'Read more: http://react-dnd.github.io/react-dnd/docs-drag-layer.html',
collect,
);
invariant(
isPlainObject(options),
'Expected "options" provided as the second argument to DragLayer to be ' +
'a plain object when specified. ' +
'Instead, received %s. ' +
'Read more: http://react-dnd.github.io/react-dnd/docs-drag-layer.html',
options,
);
return function decorateLayer(DecoratedComponent) {
const { arePropsEqual = shallowEqualScalar } = options;
const displayName =
DecoratedComponent.displayName ||
DecoratedComponent.name ||
'Component';
class DragLayerContainer extends Component {
static DecoratedComponent = DecoratedComponent;
static displayName = `DragLayer(${displayName})`;
static contextTypes = {
dragDropManager: PropTypes.object.isRequired,
}
getDecoratedComponentInstance() {
invariant(
this.child,
'In order to access an instance of the decorated component it can ' +
'not be a stateless component.',
);
return this.child;
}
shouldComponentUpdate(nextProps, nextState) {
return !arePropsEqual(nextProps, this.props) ||
!shallowEqual(nextState, this.state);
}
constructor(props, context) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.manager = context.dragDropManager;
invariant(
typeof this.manager === 'object',
'Could not find the drag and drop manager in the context of %s. ' +
'Make sure to wrap the top-level component of your app with DragDropContext. ' +
'Read more: http://react-dnd.github.io/react-dnd/docs-troubleshooting.html#could-not-find-the-drag-and-drop-manager-in-the-context',
displayName,
displayName,
);
this.state = this.getCurrentState();
}
componentDidMount() {
this.isCurrentlyMounted = true;
const monitor = this.manager.getMonitor();
this.unsubscribeFromOffsetChange = monitor.subscribeToOffsetChange(
this.handleChange,
);
this.unsubscribeFromStateChange = monitor.subscribeToStateChange(
this.handleChange,
);
this.handleChange();
}
componentWillUnmount() {
this.isCurrentlyMounted = false;
this.unsubscribeFromOffsetChange();
this.unsubscribeFromStateChange();
}
handleChange() {
if (!this.isCurrentlyMounted) {
return;
}
const nextState = this.getCurrentState();
if (!shallowEqual(nextState, this.state)) {
this.setState(nextState);
}
}
getCurrentState() {
const monitor = this.manager.getMonitor();
return collect(monitor);
}
render() {
return (
<DecoratedComponent
{...this.props}
{...this.state}
ref={child => (this.child = child)}
/>
);
}
}
return hoistStatics(DragLayerContainer, DecoratedComponent);
};
}