optimizely-oui
Version:
Optimizely's Component Library.
128 lines (113 loc) • 3.98 kB
JavaScript
import classNames from "classnames";
import Immutable from "immutable";
import PropTypes from "prop-types";
import React from "react";
import { DragSource } from "react-dnd";
import { getEmptyImage } from "react-dnd-html5-backend";
import SortTarget from "../SortTarget";
import types from "../draggableTypes";
/**
* handleBeginDrag
* @description Begins drag interaction for the current item
* @param {Object} props - SortableItem props
* @returns {Object} Information passed to item renderer + sort target upon drag
*/
function handleBeginDrag(props) {
const { item, position, id } = props;
return {
data: item,
id,
position,
type: "item",
};
}
/**
* handleEndDrag
* @description Ends drag interaction for the current item
* @param {Object} props - SortableItem props
*/
function handleEndDrag(props) {
props.endDrag();
}
/**
* isItemBeingDragged
* @description Calculates whether the current item is being dragged
* @param {Object} props - SortableItem props
* @param {Object} monitor - Interface to interact with react-dnd state
* @returns {Boolean} Whether or not the current item is being dragged
*/
function isItemBeingDragged(props, monitor) {
return !monitor.didDrop() && monitor.getItem().id === props.id && monitor.getItem().type === "item";
}
class SortableItem extends React.Component {
static propTypes = {
baseTestSection: PropTypes.string.isRequired,
connectDragPreview: PropTypes.func.isRequired,
connectDragSource: PropTypes.func.isRequired,
endDrag: PropTypes.func.isRequired,
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
isDragPreview: PropTypes.bool,
isDragging: PropTypes.bool.isRequired,
item: PropTypes.instanceOf(Immutable.Map).isRequired,
onMove: PropTypes.func.isRequired,
position: PropTypes.arrayOf(PropTypes.number).isRequired,
render: PropTypes.func.isRequired,
};
static defaultProps = {
isDragPreview: false,
};
componentDidMount() {
const { connectDragPreview } = this.props;
connectDragPreview(getEmptyImage(), {
captureDragState: true,
});
}
render() {
const { baseTestSection, connectDragSource, isDragging, isDragPreview, item, position, onMove, render } =
this.props;
const targetPosition = [...position.slice(0, -1), position[position.length - 1] + 1];
const className = classNames({
"oui-sortable__drag-placeholder": !isDragPreview && isDragging,
"oui-sortable__item": true,
"pointer-events--none": !isDragPreview && isDragging,
});
const renderedItem = render({
baseTestSection,
connectDragSource,
item,
isDragging,
isDragPreview,
position,
});
const testSectionName = isDragPreview ? "item-preview" : "item";
const testSectionId = position.join("-");
const testSection = `${baseTestSection}-${testSectionName}-${testSectionId}`;
return (
<React.Fragment>
<li className={className} data-test-section={testSection}>
{renderedItem}
</li>
<SortTarget
baseTestSection={baseTestSection}
onMove={onMove}
ownerId={item.get("id")}
ownerType="item"
position={targetPosition}
/>
</React.Fragment>
);
}
}
export default DragSource(
types.item,
{
beginDrag: handleBeginDrag,
endDrag: handleEndDrag,
isDragging: isItemBeingDragged,
},
(connect, monitor) => ({
connectDragPreview: connect.dragPreview(),
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
})
)(SortableItem);