I've successfully implemented Beautiful DnD in a React app where the draggable items are Material UI Expansion Panels. I have the list of items resorting onDragEnd and saving the new sorted list in state.
I'm using React hooks, useState, Material-UI Expansion Panel, and React-Beautiful-DnD.
When this part of the app loads, the first expansion panel is expanded and all others are collapsed.
What I've been trying to get working is how to close the expansion panel [onDragStart | onBeforeDragStart | onDragUpdate] and then open the expansion panel onDragEnd.
I have stored the state of each expansion panel along with other info in an array that loops over and renders each expansion panel: { name: string, expanded: string, ... }
I'm thinking this is an issue where the state is not getting updated to where the expansion panel is not picking up the change.
I've tried using the snapshot.isDragging on the item to change the expansion panels expanded state and even tried targeting the specific expansion panel, finding the corresponding item in the state list and updating the expanded prop onDragStart, onBeforeDragStart, and onDragUpdate. None of these have worked so far.
Here's part of the component handling the DnD
const newArray = ReorderList(srcList, ixSelectedItem, 0);
const panelState: Array<ExpansionState> = [];
// eslint-disable-next-line array-callback-return
newArray.map(item => {
panelState.push({
name: item as string,
expanded: item === selectedItem,
isDragging: false
});
});
const [itemListWithState, setItemListWithState] = useState(panelState);
const handleOnDragEnd = (result: any): void => {
const { destination, draggableId, source } = result;
if (!destination) {
return;
}
if (destination.droppableId === source.droppableId && destination.index === source.index) {
return;
}
const newList = ReorderList(itemListWithState, source.index, destination.index) as Array<ExpansionState>;
const ix = newList.findIndex(item => item.name === draggableId);
newList[ix].isDragging = false;
newList[ix].expanded = !newList[ix].expanded;
setItemListWithState(newList);
};
const handleOnDragUpdate = (result: any): void => {
const { draggableId } = result;
const ix = itemListWithState.findIndex(item => item.name === draggableId);
if (!itemListWithState[ix].isDragging) {
itemListWithState[ix].expanded = !itemListWithState[ix].expanded;
itemListWithState[ix].isDragging = true;
}
};
...
...
return (
<DragDropContext onDragEnd={handleOnDragEnd} onDragUpdate={handleOnDragUpdate}>
<Droppable droppableId="list">
{(provided, snapshot) => {
return (
<div ref={provided.innerRef} {...provided.droppableProps}>
{itemListWithState.map((item: ExpansionState, index: number) => {
return (
<Draggable key={item.name} draggableId={item.name} index={index}>
{(provided, snapshot) => {
return (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<GraphContainer id={item.name} isGraphExpanded={item.expanded} {...props}></GraphContainer>
</div>
);
}}
</Draggable>
);
})}
{provided.placeholder}
</div>
);
}}
</Droppable>
</DragDropContext>
);
Here's the component housing the expansion panel:
return (
<div style={{ margin: '20px 0' }}>
<Panel
expanded={props.isGraphExpanded}
summaryTitle={getResourceString(props.id, Resources.Performance)}
summaryDetail={props.graph}
isDraggable={true}
subPanel={
<Panel
expanded={false}
summaryTitle={getResourceString(props.id, Resources.DataTable)}
summaryDetail={props.table}
isDraggable={false}
></Panel>
}
></Panel>
</div>
);