add comments in MultipleContainers

pull/5370/head
drafish 5 months ago committed by yann300
parent 8348dc0e11
commit 5cac56ccc9
  1. 11
      apps/quick-dapp/src/components/MultipleContainers/index.tsx
  2. 39
      apps/quick-dapp/src/components/MultipleContainers/multipleContainersKeyboardCoordinates.ts

@ -42,9 +42,11 @@ export default {
title: 'Presets/Sortable/Multiple Containers', title: 'Presets/Sortable/Multiple Containers',
}; };
// This function is used to animate layout changes.
const animateLayoutChanges: AnimateLayoutChanges = (args) => const animateLayoutChanges: AnimateLayoutChanges = (args) =>
defaultAnimateLayoutChanges({ ...args, wasDragging: true }); defaultAnimateLayoutChanges({ ...args, wasDragging: true });
// This is a container component that can be dragged and dropped.
function DroppableContainer({ function DroppableContainer({
children, children,
columns = 1, columns = 1,
@ -81,6 +83,7 @@ function DroppableContainer({
items.includes(over.id) items.includes(over.id)
: false; : false;
// Return the container.
return ( return (
<Container <Container
ref={disabled ? undefined : setNodeRef} ref={disabled ? undefined : setNodeRef}
@ -103,6 +106,7 @@ function DroppableContainer({
); );
} }
// This setting is used for drop animation.
const dropAnimation: DropAnimation = { const dropAnimation: DropAnimation = {
sideEffects: defaultDropAnimationSideEffects({ sideEffects: defaultDropAnimationSideEffects({
styles: { styles: {
@ -113,8 +117,10 @@ const dropAnimation: DropAnimation = {
}), }),
}; };
// This type is used to define the items.
type Items = Record<UniqueIdentifier, UniqueIdentifier[]>; type Items = Record<UniqueIdentifier, UniqueIdentifier[]>;
// This interface is used to define the props for the MultipleContainers component.
interface Props { interface Props {
adjustScale?: boolean; adjustScale?: boolean;
cancelDrop?: CancelDrop; cancelDrop?: CancelDrop;
@ -146,6 +152,9 @@ interface Props {
const PLACEHOLDER_ID = 'placeholder'; const PLACEHOLDER_ID = 'placeholder';
const empty: UniqueIdentifier[] = []; const empty: UniqueIdentifier[] = [];
// This is a complex component. It allows items in multiple containers to be sorted using drag and drop.
// The containers themselves can also be sorted. The DndContext component from the @dnd-kit/core package provides the drag and drop context.
// The MultipleContainers component is the main component, it handles the sorting logic when an item is dragged over another item or when an item is dropped.
export function MultipleContainers({ export function MultipleContainers({
adjustScale = false, adjustScale = false,
cancelDrop, cancelDrop,
@ -584,6 +593,7 @@ interface SortableItemProps {
onRemove?: () => void; onRemove?: () => void;
} }
// The SortableItem component represents an individual item that can be dragged and dropped.
function SortableItem({ function SortableItem({
disabled, disabled,
id, id,
@ -640,6 +650,7 @@ function SortableItem({
); );
} }
// The useMountStatus function is used to track the mount status of a component.
function useMountStatus() { function useMountStatus() {
const [isMounted, setIsMounted] = useState(false); const [isMounted, setIsMounted] = useState(false);

@ -6,6 +6,7 @@ import {
KeyboardCoordinateGetter, KeyboardCoordinateGetter,
} from '@dnd-kit/core'; } from '@dnd-kit/core';
// Define the directions that can be used with the keyboard
const directions: string[] = [ const directions: string[] = [
KeyboardCode.Down, KeyboardCode.Down,
KeyboardCode.Right, KeyboardCode.Right,
@ -13,66 +14,93 @@ const directions: string[] = [
KeyboardCode.Left, KeyboardCode.Left,
]; ];
// This is a custom coordinate getter for keyboard events.
// It's used to handle keyboard navigation when moving items around in a drag and drop context.
// It determines the next position of an item based on the direction of the keyboard event.
// The function filters droppable containers based on their position relative to the currently dragged item,
// then finds the closest container in the direction of the keyboard event and returns its coordinates.
export const coordinateGetter: KeyboardCoordinateGetter = ( export const coordinateGetter: KeyboardCoordinateGetter = (
event, event,
{ context: { active, droppableRects, droppableContainers, collisionRect } } { context: { active, droppableRects, droppableContainers, collisionRect } }
) => { ) => {
// If the key pressed is one of the defined directions
if (directions.includes(event.code)) { if (directions.includes(event.code)) {
// Prevent the default browser behaviour
event.preventDefault(); event.preventDefault();
// If there is no active draggable or collision rectangle, return
if (!active || !collisionRect) { if (!active || !collisionRect) {
return; return;
} }
// Create an array to store the droppable containers that meet the criteria
const filteredContainers: DroppableContainer[] = []; const filteredContainers: DroppableContainer[] = [];
// For each enabled droppable container
droppableContainers.getEnabled().forEach((entry) => { droppableContainers.getEnabled().forEach((entry) => {
// If the container is not defined or it is disabled, return
if (!entry || entry?.disabled) { if (!entry || entry?.disabled) {
return; return;
} }
// Get the rectangle of the droppable container
const rect = droppableRects.get(entry.id); const rect = droppableRects.get(entry.id);
// If the rectangle is not defined, return
if (!rect) { if (!rect) {
return; return;
} }
// Get the data of the droppable container
const data = entry.data.current; const data = entry.data.current;
// If the data is defined
if (data) { if (data) {
const { type, children } = data; const { type, children } = data;
// If the droppable container is of type 'container' and it has children
if (type === 'container' && children?.length > 0) { if (type === 'container' && children?.length > 0) {
// If the active draggable is not of type 'container', return
if (active.data.current?.type !== 'container') { if (active.data.current?.type !== 'container') {
return; return;
} }
} }
} }
// Depending on the direction of the keyboard event
switch (event.code) { switch (event.code) {
// If the direction is down and the top of the collision rectangle is above the top of the container rectangle
case KeyboardCode.Down: case KeyboardCode.Down:
if (collisionRect.top < rect.top) { if (collisionRect.top < rect.top) {
// Add the container to the array of filtered containers
filteredContainers.push(entry); filteredContainers.push(entry);
} }
break; break;
// If the direction is up and the top of the collision rectangle is below the top of the container rectangle
case KeyboardCode.Up: case KeyboardCode.Up:
if (collisionRect.top > rect.top) { if (collisionRect.top > rect.top) {
// Add the container to the array of filtered containers
filteredContainers.push(entry); filteredContainers.push(entry);
} }
break; break;
// If the direction is left and the left of the collision rectangle is to the right of the right of the container rectangle
case KeyboardCode.Left: case KeyboardCode.Left:
if (collisionRect.left >= rect.left + rect.width) { if (collisionRect.left >= rect.left + rect.width) {
// Add the container to the array of filtered containers
filteredContainers.push(entry); filteredContainers.push(entry);
} }
break; break;
// If the direction is right and the right of the collision rectangle is to the left of the left of the container rectangle
case KeyboardCode.Right: case KeyboardCode.Right:
if (collisionRect.left + collisionRect.width <= rect.left) { if (collisionRect.left + collisionRect.width <= rect.left) {
// Add the container to the array of filtered containers
filteredContainers.push(entry); filteredContainers.push(entry);
} }
break; break;
} }
}); });
// Get the closest corners of the collision rectangle and the filtered containers
const collisions = closestCorners({ const collisions = closestCorners({
active, active,
collisionRect: collisionRect, collisionRect: collisionRect,
@ -80,28 +108,38 @@ export const coordinateGetter: KeyboardCoordinateGetter = (
droppableContainers: filteredContainers, droppableContainers: filteredContainers,
pointerCoordinates: null, pointerCoordinates: null,
}); });
// Get the id of the first collision
const closestId = getFirstCollision(collisions, 'id'); const closestId = getFirstCollision(collisions, 'id');
// If there is a closest id
if (closestId != null) { if (closestId != null) {
// Get the droppable container with the closest id
const newDroppable = droppableContainers.get(closestId); const newDroppable = droppableContainers.get(closestId);
// Get the node and rectangle of the droppable container
const newNode = newDroppable?.node.current; const newNode = newDroppable?.node.current;
const newRect = newDroppable?.rect.current; const newRect = newDroppable?.rect.current;
// If there is a node and rectangle
if (newNode && newRect) { if (newNode && newRect) {
// If the droppable container is the placeholder
if (newDroppable.id === 'placeholder') { if (newDroppable.id === 'placeholder') {
// Return the center coordinates of the droppable container
return { return {
x: newRect.left + (newRect.width - collisionRect.width) / 2, x: newRect.left + (newRect.width - collisionRect.width) / 2,
y: newRect.top + (newRect.height - collisionRect.height) / 2, y: newRect.top + (newRect.height - collisionRect.height) / 2,
}; };
} }
// If the droppable container is of type 'container'
if (newDroppable.data.current?.type === 'container') { if (newDroppable.data.current?.type === 'container') {
// Return specific coordinates within the droppable container
return { return {
x: newRect.left + 20, x: newRect.left + 20,
y: newRect.top + 74, y: newRect.top + 74,
}; };
} }
// Otherwise, return the top left coordinates of the droppable container
return { return {
x: newRect.left, x: newRect.left,
y: newRect.top, y: newRect.top,
@ -110,5 +148,6 @@ export const coordinateGetter: KeyboardCoordinateGetter = (
} }
} }
// If none of the above conditions are met, return undefined
return undefined; return undefined;
}; };

Loading…
Cancel
Save