optimizely-oui
Version:
Optimizely's Component Library.
110 lines (99 loc) • 3.23 kB
JavaScript
import PropTypes from "prop-types";
import React, { useCallback } from "react";
import { DragDropContext, Droppable } from "react-beautiful-dnd";
import classNames from "classnames";
import DraggableItem from "./DraggableItem";
/**
*
* @param {Object} props - Properties passed to component
* @returns {ReactElement}
*/
const DragAndDrop = ({
className,
idForDroppableRegion,
items,
onBeforeCapture,
onDragEnd,
renderItem,
useCustomDragHandle,
...props
}) => {
const updateOrderOfItems = useCallback(
result => {
const { destination, source } = result;
if (!destination) {
return;
}
if (destination.droppableId === source.droppableId && destination.index === source.index) {
return;
}
const currentItems = items;
const newOrderOfItems = Array.from(currentItems);
const [removedItem] = newOrderOfItems.splice(source.index, 1);
newOrderOfItems.splice(destination.index, 0, removedItem);
onDragEnd(newOrderOfItems);
},
[onDragEnd]
);
return (
<DragDropContext onBeforeCapture={onBeforeCapture} onDragEnd={updateOrderOfItems}>
<Droppable droppableId={idForDroppableRegion}>
{provided => (
<div className={classNames("oui-sortable", className)} ref={provided.innerRef} {...provided.droppableProps} {...props}>
<ul>
{items.map((item, index) => (
<DraggableItem
key={item.id}
item={item}
id={item.id}
index={index}
renderFunc={renderItem}
useCustomDragHandle={useCustomDragHandle}
/>
))}
</ul>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
};
DragAndDrop.propTypes = {
/** CSS class names. */
className: PropTypes.string,
/**
* ID used for this Droppable region
*/
idForDroppableRegion: PropTypes.string.isRequired,
/**
* Array of items to render as DraggableItems
*/
items: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number,
})
).isRequired,
/**
* Function to perform an action before item dimensions are captured
*/
onBeforeCapture: PropTypes.func,
/**
* Function to perform an action after dragging has finished
*/
onDragEnd: PropTypes.func,
/**
* Function used to render each draggable item
*/
renderItem: PropTypes.func.isRequired,
/**
* Whether or not items themselves will make use of the drag handle
*/
useCustomDragHandle: PropTypes.bool,
};
DragAndDrop.defaultProps = {
onBeforeCapture: () => null,
onDragEnd: () => null,
useCustomDragHandle: false,
};
export default DragAndDrop;