Replace TagPanel react-dnd with react-beautiful-dnd

This new library handles the simple case of an ordered vertical
(or horizontal) list of items that can be reordered.

It provides animations, handles positioning of items mid-drag
and exposes a much simpler API to react-dnd (with a slight loss
of potential function, but we don't need this flexibility here
anyway).

Apart from this, TagOrderStore had to be changed in a highly
coupled way, but arguably for the better. Instead of being
updated incrementally every time an item is dragged over
another and having a separate "commit" action, the
asyncronous action `moveTag` is used to reposition the tag in
the list and both dispatch an optimistic update and carry out
the request as before. (The MatrixActions.accountData is still
used to indicate a successful reordering of tags).

The view is updated instantly, in an animated way, and this
is handled at the layer "above" React by the DND library.
This commit is contained in:
lukebarnard 2018-01-15 18:12:27 +00:00
parent 952f2c6a21
commit 16c13fb079
6 changed files with 85 additions and 100 deletions

View file

@ -15,71 +15,29 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { DragSource, DropTarget } from 'react-dnd';
import TagTile from './TagTile';
import dis from '../../../dispatcher';
import { findDOMNode } from 'react-dom';
const tagTileSource = {
canDrag: function(props, monitor) {
return true;
},
import { Draggable } from 'react-beautiful-dnd';
beginDrag: function(props) {
// Return the data describing the dragged item
return {
tag: props.tag,
};
},
endDrag: function(props, monitor, component) {
const dropResult = monitor.getDropResult();
if (!monitor.didDrop() || !dropResult) {
return;
}
props.onEndDrag();
},
};
const tagTileTarget = {
canDrop(props, monitor) {
return true;
},
hover(props, monitor, component) {
if (!monitor.canDrop()) return;
const draggedY = monitor.getClientOffset().y;
const {top, bottom} = findDOMNode(component).getBoundingClientRect();
const targetY = (top + bottom) / 2;
dis.dispatch({
action: 'order_tag',
tag: monitor.getItem().tag,
targetTag: props.tag,
// Note: we indicate that the tag should be after the target when
// it's being dragged over the top half of the target.
after: draggedY < targetY,
});
},
drop(props) {
// Return the data to be returned by getDropResult
return {
tag: props.tag,
};
},
};
export default
DropTarget('TagTile', tagTileTarget, (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
}))(DragSource('TagTile', tagTileSource, (connect, monitor) => ({
connectDragSource: connect.dragSource(),
}))((props) => {
const { connectDropTarget, connectDragSource, ...otherProps } = props;
return connectDropTarget(connectDragSource(
<div>
<TagTile {...otherProps} />
</div>,
));
}));
export default function DNDTagTile(props) {
return <div>
<Draggable
key={props.tag}
draggableId={props.tag}
index={props.index}
>
{ (provided, snapshot) => (
<div>
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<TagTile {...props} />
</div>
{ provided.placeholder }
</div>
) }
</Draggable>
</div>;
}