diff --git a/invokeai/frontend/web/src/app/components/ImageDnd/ImageDndContext.tsx b/invokeai/frontend/web/src/app/components/ImageDnd/ImageDndContext.tsx
index 1b8687bf8e1..3a540083378 100644
--- a/invokeai/frontend/web/src/app/components/ImageDnd/ImageDndContext.tsx
+++ b/invokeai/frontend/web/src/app/components/ImageDnd/ImageDndContext.tsx
@@ -6,18 +6,18 @@ import {
useSensor,
useSensors,
} from '@dnd-kit/core';
-import { PropsWithChildren, memo, useCallback, useState } from 'react';
-import DragPreview from './DragPreview';
import { snapCenterToCursor } from '@dnd-kit/modifiers';
+import { imageDropped } from 'app/store/middleware/listenerMiddleware/listeners/imageDropped';
+import { useAppDispatch } from 'app/store/storeHooks';
import { AnimatePresence, motion } from 'framer-motion';
+import { PropsWithChildren, memo, useCallback, useState } from 'react';
+import DragPreview from './DragPreview';
import {
DndContext,
DragEndEvent,
DragStartEvent,
TypesafeDraggableData,
} from './typesafeDnd';
-import { useAppDispatch } from 'app/store/storeHooks';
-import { imageDropped } from 'app/store/middleware/listenerMiddleware/listeners/imageDropped';
type ImageDndContextProps = PropsWithChildren;
@@ -49,11 +49,11 @@ const ImageDndContext = (props: ImageDndContextProps) => {
);
const mouseSensor = useSensor(MouseSensor, {
- activationConstraint: { delay: 150, tolerance: 5 },
+ activationConstraint: { distance: 10 },
});
const touchSensor = useSensor(TouchSensor, {
- activationConstraint: { delay: 150, tolerance: 5 },
+ activationConstraint: { distance: 10 },
});
// TODO: Use KeyboardSensor - needs composition of multiple collisionDetection algos
diff --git a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
index 7cc4eadc75f..dacef3ee94c 100644
--- a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
@@ -1,5 +1,4 @@
import {
- Box,
ChakraProps,
Flex,
Icon,
@@ -10,9 +9,6 @@ import {
import {
TypesafeDraggableData,
TypesafeDroppableData,
- isValidDrop,
- useDraggable,
- useDroppable,
} from 'app/components/ImageDnd/typesafeDnd';
import IAIIconButton from 'common/components/IAIIconButton';
import {
@@ -21,14 +17,13 @@ import {
} from 'common/components/IAIImageFallback';
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
-import { AnimatePresence } from 'framer-motion';
-import { MouseEvent, ReactElement, SyntheticEvent, memo, useRef } from 'react';
+import { MouseEvent, ReactElement, SyntheticEvent, memo } from 'react';
import { FaImage, FaUndo, FaUpload } from 'react-icons/fa';
import { PostUploadAction } from 'services/api/thunks/image';
import { ImageDTO } from 'services/api/types';
import { mode } from 'theme/util/mode';
-import { v4 as uuidv4 } from 'uuid';
-import IAIDropOverlay from './IAIDropOverlay';
+import IAIDraggable from './IAIDraggable';
+import IAIDroppable from './IAIDroppable';
type IAIDndImageProps = {
imageDTO: ImageDTO | undefined;
@@ -144,30 +139,6 @@ const IAIDndImage = (props: IAIDndImageProps) => {
}}
/>
{withMetadataOverlay && }
- {onClickReset && withResetIcon && (
-
- )}
)}
{!imageDTO && !isUploadDisabled && (
@@ -198,84 +169,44 @@ const IAIDndImage = (props: IAIDndImageProps) => {
>
)}
{!imageDTO && isUploadDisabled && noContentFallback}
-
-
+ {imageDTO && (
+
+ )}
+ {onClickReset && withResetIcon && imageDTO && (
+
+ )}
);
};
export default memo(IAIDndImage);
-
-type DroppableProps = {
- dropLabel?: string;
- disabled?: boolean;
- data?: TypesafeDroppableData;
-};
-
-const Droppable = memo((props: DroppableProps) => {
- const { dropLabel, data, disabled } = props;
- const dndId = useRef(uuidv4());
-
- const { isOver, setNodeRef, active } = useDroppable({
- id: dndId.current,
- disabled,
- data,
- });
-
- return (
-
-
- {isValidDrop(data, active) && (
-
- )}
-
-
- );
-});
-
-Droppable.displayName = 'Droppable';
-
-type DraggableProps = {
- disabled?: boolean;
- data?: TypesafeDraggableData;
- onClick?: (event: MouseEvent) => void;
-};
-
-const Draggable = memo((props: DraggableProps) => {
- const { data, disabled, onClick } = props;
- const dndId = useRef(uuidv4());
-
- const { attributes, listeners, setNodeRef } = useDraggable({
- id: dndId.current,
- disabled,
- data,
- });
-
- return (
-
- );
-});
-
-Draggable.displayName = 'Draggable';
diff --git a/invokeai/frontend/web/src/common/components/IAIDraggable.tsx b/invokeai/frontend/web/src/common/components/IAIDraggable.tsx
new file mode 100644
index 00000000000..a1b8c197739
--- /dev/null
+++ b/invokeai/frontend/web/src/common/components/IAIDraggable.tsx
@@ -0,0 +1,38 @@
+import { Box } from '@chakra-ui/react';
+import {
+ TypesafeDraggableData,
+ useDraggable,
+} from 'app/components/ImageDnd/typesafeDnd';
+import { MouseEvent, memo, useRef } from 'react';
+import { v4 as uuidv4 } from 'uuid';
+
+type IAIDraggableProps = {
+ disabled?: boolean;
+ data?: TypesafeDraggableData;
+ onClick?: (event: MouseEvent) => void;
+};
+
+const IAIDraggable = (props: IAIDraggableProps) => {
+ const { data, disabled, onClick } = props;
+ const dndId = useRef(uuidv4());
+
+ const { attributes, listeners, setNodeRef } = useDraggable({
+ id: dndId.current,
+ disabled,
+ data,
+ });
+
+ return (
+
+ );
+};
+
+export default memo(IAIDraggable);
diff --git a/invokeai/frontend/web/src/common/components/IAIDroppable.tsx b/invokeai/frontend/web/src/common/components/IAIDroppable.tsx
new file mode 100644
index 00000000000..7833a61e286
--- /dev/null
+++ b/invokeai/frontend/web/src/common/components/IAIDroppable.tsx
@@ -0,0 +1,45 @@
+import { Box } from '@chakra-ui/react';
+import {
+ TypesafeDroppableData,
+ isValidDrop,
+ useDroppable,
+} from 'app/components/ImageDnd/typesafeDnd';
+import { AnimatePresence } from 'framer-motion';
+import { memo, useRef } from 'react';
+import { v4 as uuidv4 } from 'uuid';
+import IAIDropOverlay from './IAIDropOverlay';
+
+type IAIDroppableProps = {
+ dropLabel?: string;
+ disabled?: boolean;
+ data?: TypesafeDroppableData;
+};
+
+const IAIDroppable = (props: IAIDroppableProps) => {
+ const { dropLabel, data, disabled } = props;
+ const dndId = useRef(uuidv4());
+
+ const { isOver, setNodeRef, active } = useDroppable({
+ id: dndId.current,
+ disabled,
+ data,
+ });
+
+ return (
+
+
+ {isValidDrop(data, active) && (
+
+ )}
+
+
+ );
+};
+
+export default memo(IAIDroppable);
diff --git a/invokeai/frontend/web/src/features/batch/components/BatchImageContainer.tsx b/invokeai/frontend/web/src/features/batch/components/BatchImageContainer.tsx
index 09e6b8afd74..30b07a5591d 100644
--- a/invokeai/frontend/web/src/features/batch/components/BatchImageContainer.tsx
+++ b/invokeai/frontend/web/src/features/batch/components/BatchImageContainer.tsx
@@ -1,11 +1,7 @@
import { Box } from '@chakra-ui/react';
+import { AddToBatchDropData } from 'app/components/ImageDnd/typesafeDnd';
+import IAIDroppable from 'common/components/IAIDroppable';
import BatchImageGrid from './BatchImageGrid';
-import IAIDropOverlay from 'common/components/IAIDropOverlay';
-import {
- AddToBatchDropData,
- isValidDrop,
- useDroppable,
-} from 'app/components/ImageDnd/typesafeDnd';
const droppableData: AddToBatchDropData = {
id: 'batch',
@@ -13,17 +9,10 @@ const droppableData: AddToBatchDropData = {
};
const BatchImageContainer = () => {
- const { isOver, setNodeRef, active } = useDroppable({
- id: 'batch-manager',
- data: droppableData,
- });
-
return (
-
+
- {isValidDrop(droppableData, active) && (
-
- )}
+
);
};
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/AllImagesBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/AllImagesBoard.tsx
index 918e9390f9e..7dd747c15b6 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/AllImagesBoard.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/AllImagesBoard.tsx
@@ -1,16 +1,11 @@
import { Flex, useColorMode } from '@chakra-ui/react';
-import { FaImages } from 'react-icons/fa';
+import { MoveBoardDropData } from 'app/components/ImageDnd/typesafeDnd';
+import IAIDroppable from 'common/components/IAIDroppable';
+import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
+import { FaImages } from 'react-icons/fa';
import { useDispatch } from 'react-redux';
-import { IAINoContentFallback } from 'common/components/IAIImageFallback';
-import { AnimatePresence } from 'framer-motion';
-import IAIDropOverlay from 'common/components/IAIDropOverlay';
import { mode } from 'theme/util/mode';
-import {
- MoveBoardDropData,
- isValidDrop,
- useDroppable,
-} from 'app/components/ImageDnd/typesafeDnd';
const AllImagesBoard = ({ isSelected }: { isSelected: boolean }) => {
const dispatch = useDispatch();
@@ -26,11 +21,6 @@ const AllImagesBoard = ({ isSelected }: { isSelected: boolean }) => {
context: { boardId: null },
};
- const { isOver, setNodeRef, active } = useDroppable({
- id: `board_droppable_all_images`,
- data: droppableData,
- });
-
return (
{
}}
>
{
_dark: { border: '2px solid var(--invokeai-colors-base-800)' },
}}
/>
-
- {isValidDrop(droppableData, active) && (
-
- )}
-
+
{
onClickDeleteBoardImages(board);
}, [board, onClickDeleteBoardImages]);
- const droppableData: MoveBoardDropData = {
- id: board_id,
- actionType: 'MOVE_BOARD',
- context: { boardId: board_id },
- };
-
- const { isOver, setNodeRef, active } = useDroppable({
- id: `board_droppable_${board_id}`,
- data: droppableData,
- });
+ const droppableData: MoveBoardDropData = useMemo(
+ () => ({
+ id: board_id,
+ actionType: 'MOVE_BOARD',
+ context: { boardId: board_id },
+ }),
+ [board_id]
+ );
return (
@@ -127,7 +120,6 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
}}
>
{
>
{board.image_count}
-
- {isValidDrop(droppableData, active) && (
-
- )}
-
+