fix: non-virtual dnd
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import React, { useState, ReactElement, useCallback } from 'react';
|
||||
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
|
||||
import { FixedSizeList, areEqual } from 'react-window';
|
||||
|
||||
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)
|
||||
@@ -9,16 +8,15 @@ import { FixedSizeList, areEqual } from 'react-window';
|
||||
*/
|
||||
|
||||
/**
|
||||
* Props for the List component.
|
||||
* Props for the List component.
|
||||
*/
|
||||
export interface ListProps {
|
||||
draggableElements: any[]; // Will later define draggableElements based on what types
|
||||
// of components are draggable.
|
||||
itemHeight: number;
|
||||
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[] = []) {
|
||||
@@ -28,7 +26,7 @@ function initial(draggableElements: any[] = []) {
|
||||
}));
|
||||
}
|
||||
|
||||
function reorder(list: { id: string, content: ReactElement }[], startIndex: number, endIndex: number) {
|
||||
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);
|
||||
@@ -38,29 +36,29 @@ function reorder(list: { id: string, content: ReactElement }[], startIndex: numb
|
||||
function getStyle({ provided, style /* , isDragging, gap */ }) {
|
||||
const combined = {
|
||||
...style,
|
||||
...provided.draggableProps.style
|
||||
...provided.draggableProps.style,
|
||||
};
|
||||
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
function Item({ provided, item, style, isDragging/* , gap */ }) {
|
||||
function Item({ provided, item, style, isDragging /* , gap */ }) {
|
||||
return (
|
||||
<div
|
||||
{...provided.draggableProps}
|
||||
ref={provided.innerRef}
|
||||
style={getStyle({ provided, style/* , isDragging, gap */ })}
|
||||
className={`item ${isDragging ? "is-dragging" : ""}`}
|
||||
style={getStyle({ provided, style /* , isDragging, gap */ })}
|
||||
className={`item ${isDragging ? 'is-dragging' : ''}`}
|
||||
>
|
||||
{React.cloneElement(item.content, {dragHandleProps: provided.dragHandleProps})}
|
||||
{React.cloneElement(item.content, { dragHandleProps: provided.dragHandleProps })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface RowProps {
|
||||
data: any, // DraggableElements[]; Need to define DraggableElements interface once those components are ready
|
||||
index: number,
|
||||
style: React.CSSProperties,
|
||||
interface RowProps {
|
||||
data: any; // DraggableElements[]; Need to define DraggableElements interface once those components are ready
|
||||
index: number;
|
||||
style: React.CSSProperties;
|
||||
}
|
||||
|
||||
const Row: React.FC<RowProps> = React.memo(({ data: { items, gap }, index, style }) => {
|
||||
@@ -68,12 +66,12 @@ const Row: React.FC<RowProps> = React.memo(({ data: { items, gap }, index, style
|
||||
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
|
||||
};
|
||||
marginBottom: `${gap}px`, // Add gap as bottom margin
|
||||
};
|
||||
return (
|
||||
<Draggable draggableId={item.id} index={index} key={item.id}>
|
||||
{/* @ts-ignore */}
|
||||
{provided => <Item provided={provided} item={item} style={adjustedStyle} gap={gap}/>}
|
||||
{/* @ts-ignore */}
|
||||
{provided => <Item provided={provided} item={item} style={adjustedStyle} gap={gap} />}
|
||||
</Draggable>
|
||||
);
|
||||
}, areEqual);
|
||||
@@ -84,116 +82,87 @@ const Row: React.FC<RowProps> = React.memo(({ data: { items, gap }, index, style
|
||||
* @example
|
||||
* <List draggableElements={elements} />
|
||||
*/
|
||||
const List: React.FC<ListProps> = ( { draggableElements, itemHeight, listHeight, listWidth, gap=8 }: ListProps) => {
|
||||
const List: React.FC<ListProps> = ({ 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]);
|
||||
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 (
|
||||
<div style={{ overflow: 'hidden', width: listWidth }}>
|
||||
<DragDropContext onDragEnd = {onDragEnd}>
|
||||
<div style = {{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center"
|
||||
}}>
|
||||
<Droppable
|
||||
droppableId="droppable"
|
||||
/* mode="virtual" */
|
||||
direction="vertical"
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Droppable
|
||||
droppableId='droppable'
|
||||
direction='vertical'
|
||||
renderClone={(provided, snapshot, rubric) => {
|
||||
let { style } = provided.draggableProps;
|
||||
const transform = style?.transform;
|
||||
|
||||
if (snapshot.isDragging && transform) {
|
||||
let [, y] = transform
|
||||
.replace('translate(', '')
|
||||
.replace(')', '')
|
||||
.split(',')
|
||||
.map((v) => parseInt(v, 10));
|
||||
|
||||
/*
|
||||
const minTranslateY = -1 * rubric.source.index * itemHeight;
|
||||
const maxTranslateY = (items.length - rubric.source.index - 1) * itemHeight;
|
||||
|
||||
if (y < minTranslateY) {
|
||||
|
||||
}
|
||||
else if (y > maxTranslateY) {
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
*/
|
||||
let { style } = provided.draggableProps;
|
||||
const transform = style?.transform;
|
||||
|
||||
style.transform = `translate(0px, ${y}px)`; // Apply constrained y value
|
||||
}
|
||||
|
||||
return (
|
||||
<Item
|
||||
provided={provided}
|
||||
isDragging={snapshot.isDragging}
|
||||
item={items[rubric.source.index]}
|
||||
style = {{
|
||||
style
|
||||
}}
|
||||
/* gap = {gap} */
|
||||
/>
|
||||
)}
|
||||
}
|
||||
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 (
|
||||
<Item
|
||||
provided={provided}
|
||||
isDragging={snapshot.isDragging}
|
||||
item={items[rubric.source.index]}
|
||||
style={{
|
||||
style,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(provided) => (
|
||||
{provided => (
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
style={{ width: `${listWidth}px` }}
|
||||
className="space-y-2"
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<Draggable key={item.id} draggableId={item.id} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
key={item.id}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
style={{
|
||||
...provided.draggableProps.style,
|
||||
marginBottom: '8px',
|
||||
background: snapshot.isDragging ? '#f4f4f4' : 'transparent',
|
||||
}}
|
||||
className="p-2"
|
||||
>
|
||||
{item.content}
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
ref={provided.innerRef}
|
||||
style={{ width: `${listWidth}px` }}
|
||||
className=''
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<Draggable key={item.id} draggableId={item.id} index={index}>
|
||||
{draggableProvided => (
|
||||
<div
|
||||
ref={draggableProvided.innerRef}
|
||||
{...draggableProvided.draggableProps}
|
||||
{...draggableProvided.dragHandleProps}
|
||||
style={{
|
||||
...draggableProvided.draggableProps.style,
|
||||
// if last item, don't add margin
|
||||
marginBottom: index === items.length - 1 ? '0px' : `${gap}px`,
|
||||
}}
|
||||
>
|
||||
{item.content}
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</div>
|
||||
</DragDropContext>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default List;
|
||||
export default List;
|
||||
|
||||
Reference in New Issue
Block a user