import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; import React, { ReactElement, useCallback, useState } from 'react'; import { areEqual } from 'react-window'; /* * Ctrl + f dragHandleProps on PopupCourseBlock.tsx for example implementation of drag handle (two lines of code) * */ /** * Props for the List component. */ export interface ListProps { draggableElements: any[]; // Will later define draggableElements based on what types // of components are draggable. itemHeight: number; listHeight: number; listWidth: number; gap: number; // Impacts the spacing between items in the list } function initial(draggableElements: any[] = []) { return draggableElements.map((element, index) => ({ id: `id:${index}`, content: element as ReactElement, })); } function reorder(list: { id: string; content: ReactElement }[], startIndex: number, endIndex: number) { const result = Array.from(list); const [removed] = result.splice(startIndex, 1); result.splice(endIndex, 0, removed); return result; } function getStyle({ provided, style /* , isDragging, gap */ }) { const combined = { ...style, ...provided.draggableProps.style, }; return combined; } function Item({ provided, item, style, isDragging /* , gap */ }) { return (
{React.cloneElement(item.content, { dragHandleProps: provided.dragHandleProps })}
); } interface RowProps { data: any; // DraggableElements[]; Need to define DraggableElements interface once those components are ready index: number; style: React.CSSProperties; } const Row: React.FC = React.memo(({ data: { items, gap }, index, style }) => { const item = items[index]; const adjustedStyle = { ...style, height: `calc(${style.height}px - ${gap}px)`, // Reduce the height by gap to accommodate the margin marginBottom: `${gap}px`, // Add gap as bottom margin }; return ( {/* @ts-ignore */} {provided => } ); }, areEqual); /** * `List` is a functional component that displays a course meeting. * * @example * */ const List: React.FC = ({ draggableElements, itemHeight, listHeight, listWidth, gap = 12 }: ListProps) => { const [items, setItems] = useState(() => initial(draggableElements)); const onDragEnd = useCallback( result => { if (!result.destination) { return; } if (result.source.index === result.destination.index) { return; } const newItems = reorder(items, result.source.index, result.destination.index); setItems(newItems as { id: string; content: React.ReactElement }[]); }, [items] ); return (
{ let { style } = provided.draggableProps; const transform = style?.transform; if (snapshot.isDragging && transform) { console.log(transform); let [, _x, y] = transform.match(/translate\(([-\d]+)px, ([-\d]+)px\)/) || []; style.transform = `translate3d(0px, ${y}px, 0px)`; // Apply constrained y value } return ( ); }} > {provided => (
{items.map((item, index) => ( {draggableProvided => (
{item.content}
)}
))} {provided.placeholder}
)}
); }; export default List;