fix: non-virtual dnd

This commit is contained in:
doprz
2024-03-06 10:48:51 -06:00
parent 677aa624d7
commit 837fddf804
3 changed files with 1858 additions and 999 deletions

2538
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,15 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Course, Status } from '@shared/types/Course';
import { CourseMeeting } from '@shared/types/CourseMeeting';
import Instructor from '@shared/types/Instructor';
import { Meta, StoryObj } from '@storybook/react';
import List from '@views/components/common/List/List';
import PopupCourseBlock from '@views/components/common/PopupCourseBlock/PopupCourseBlock';
import { getCourseColors } from 'src/shared/util/colors';
import React from 'react';
import { test_colors } from './PopupCourseBlock.stories';
const numberOfCourses = 5;
const generateCourses = (count) => {
const generateCourses = count => {
const courses = [];
for (let i = 0; i < count; i++) {
@@ -64,14 +62,10 @@ const generateCourses = (count) => {
};
const exampleCourses = generateCourses(numberOfCourses);
const generateCourseBlocks = (exampleCourses, colors) => {
return exampleCourses.map((course, i) => (
<PopupCourseBlock key={course.uniqueId} course={course} colors={colors[i]} />
))
}
const generateCourseBlocks = (exampleCourses, colors) =>
exampleCourses.map((course, i) => <PopupCourseBlock key={course.uniqueId} course={course} colors={colors[i]} />);
const exampleCourseBlocks = generateCourseBlocks(exampleCourses, test_colors);
const meta = {
title: 'Components/Common/List',
component: List,
@@ -97,6 +91,6 @@ export const Default: Story = {
itemHeight: 55,
listHeight: 300,
listWidth: 300,
gap: 8,
gap: 12,
},
};

View File

@@ -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)
@@ -18,7 +17,6 @@ export interface ListProps {
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,7 +36,7 @@ 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;
@@ -50,7 +48,7 @@ function Item({ provided, item, style, isDragging/* , gap */ }) {
{...provided.draggableProps}
ref={provided.innerRef}
style={getStyle({ provided, style /* , isDragging, gap */ })}
className={`item ${isDragging ? "is-dragging" : ""}`}
className={`item ${isDragging ? 'is-dragging' : ''}`}
>
{React.cloneElement(item.content, { dragHandleProps: provided.dragHandleProps })}
</div>
@@ -58,9 +56,9 @@ function Item({ provided, item, style, isDragging/* , gap */ }) {
}
interface RowProps {
data: any, // DraggableElements[]; Need to define DraggableElements interface once those components are ready
index: number,
style: React.CSSProperties,
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,7 +66,7 @@ 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}>
@@ -84,10 +82,11 @@ 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) => {
const onDragEnd = useCallback(
result => {
if (!result.destination) {
return;
}
@@ -96,54 +95,28 @@ const List: React.FC<ListProps> = ( { draggableElements, itemHeight, listHeight,
return;
}
const newItems = reorder(
items,
result.source.index,
result.destination.index
);
const newItems = reorder(items, result.source.index, result.destination.index);
setItems(newItems as { id: string, content: React.ReactElement }[]);
}, [items]);
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"
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));
console.log(transform);
let [, _x, y] = transform.match(/translate\(([-\d]+)px, ([-\d]+)px\)/) || [];
/*
const minTranslateY = -1 * rubric.source.index * itemHeight;
const maxTranslateY = (items.length - rubric.source.index - 1) * itemHeight;
if (y < minTranslateY) {
}
else if (y > maxTranslateY) {
}
else {
}
*/
style.transform = `translate(0px, ${y}px)`; // Apply constrained y value
style.transform = `translate3d(0px, ${y}px, 0px)`; // Apply constrained y value
}
return (
@@ -152,34 +125,31 @@ const List: React.FC<ListProps> = ( { draggableElements, itemHeight, listHeight,
isDragging={snapshot.isDragging}
item={items[rubric.source.index]}
style={{
style
style,
}}
/* gap = {gap} */
/>
)}
}
);
}}
>
{(provided) => (
{provided => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={{ width: `${listWidth}px` }}
className="space-y-2"
className=''
>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => (
{draggableProvided => (
<div
ref={provided.innerRef}
key={item.id}
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={draggableProvided.innerRef}
{...draggableProvided.draggableProps}
{...draggableProvided.dragHandleProps}
style={{
...provided.draggableProps.style,
marginBottom: '8px',
background: snapshot.isDragging ? '#f4f4f4' : 'transparent',
...draggableProvided.draggableProps.style,
// if last item, don't add margin
marginBottom: index === items.length - 1 ? '0px' : `${gap}px`,
}}
className="p-2"
>
{item.content}
</div>
@@ -190,7 +160,6 @@ const List: React.FC<ListProps> = ( { draggableElements, itemHeight, listHeight,
</div>
)}
</Droppable>
</div>
</DragDropContext>
</div>
);