diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx index c6647c6ef3..41d821f4d7 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx @@ -23,7 +23,7 @@ import { imageToCompareChanged, selectGallerySlice, selectionChanged } from 'fea import { navigationApi } from 'features/ui/layouts/navigation-api'; import { VIEWER_PANEL_ID } from 'features/ui/layouts/shared'; import type { MouseEvent, MouseEventHandler } from 'react'; -import { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { PiImageBold } from 'react-icons/pi'; import { imagesApi } from 'services/api/endpoints/images'; import type { ImageDTO } from 'services/api/types'; @@ -42,45 +42,42 @@ const galleryImageContainerSX = { '&[data-is-dragging=true]': { opacity: 0.3, }, - [`.${GALLERY_IMAGE_CLASS}`]: { - touchAction: 'none', - userSelect: 'none', - webkitUserSelect: 'none', - position: 'relative', - justifyContent: 'center', - alignItems: 'center', - aspectRatio: '1/1', - '::before': { - content: '""', - display: 'inline-block', - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - pointerEvents: 'none', - borderRadius: 'base', - }, - '&[data-selected=true]::before': { - boxShadow: - 'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-500), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)', - }, - '&[data-selected-for-compare=true]::before': { - boxShadow: - 'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-300), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)', - }, - '&:hover::before': { - boxShadow: - 'inset 0px 0px 0px 1px var(--invoke-colors-invokeBlue-300), inset 0px 0px 0px 2px var(--invoke-colors-invokeBlue-800)', - }, - '&:hover[data-selected=true]::before': { - boxShadow: - 'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-400), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)', - }, - '&:hover[data-selected-for-compare=true]::before': { - boxShadow: - 'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-200), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)', - }, + userSelect: 'none', + webkitUserSelect: 'none', + position: 'relative', + justifyContent: 'center', + alignItems: 'center', + aspectRatio: '1/1', + '::before': { + content: '""', + display: 'inline-block', + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + pointerEvents: 'none', + borderRadius: 'base', + }, + '&[data-selected=true]::before': { + boxShadow: + 'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-500), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)', + }, + '&[data-selected-for-compare=true]::before': { + boxShadow: + 'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-300), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)', + }, + '&:hover::before': { + boxShadow: + 'inset 0px 0px 0px 1px var(--invoke-colors-invokeBlue-300), inset 0px 0px 0px 2px var(--invoke-colors-invokeBlue-800)', + }, + '&:hover[data-selected=true]::before': { + boxShadow: + 'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-400), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)', + }, + '&:hover[data-selected-for-compare=true]::before': { + boxShadow: + 'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-200), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)', }, } satisfies SystemStyleObject; @@ -142,8 +139,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => { const [dragPreviewState, setDragPreviewState] = useState< DndDragPreviewSingleImageState | DndDragPreviewMultipleImageState | null >(null); - // Must use callback ref - else chakra's Image fallback prop will break the ref & dnd - const [element, ref] = useState(null); + const ref = useRef(null); const selectIsSelectedForCompare = useMemo( () => createSelector(selectGallerySlice, (gallery) => gallery.imageToCompare === imageDTO.image_name), [imageDTO.image_name] @@ -156,6 +152,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => { const isSelected = useAppSelector(selectIsSelected); useEffect(() => { + const element = ref.current; if (!element) { return; } @@ -221,7 +218,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => { }, }) ); - }, [element, imageDTO, store]); + }, [imageDTO, store]); const [isHovered, setIsHovered] = useState(false); @@ -240,34 +237,35 @@ export const GalleryImage = memo(({ imageDTO }: Props) => { navigationApi.focusPanelInActiveTab(VIEWER_PANEL_ID); }, [store]); - useImageContextMenu(imageDTO, element); + useImageContextMenu(imageDTO, ref); return ( <> - - - } - objectFit="contain" - maxW="full" - maxH="full" - borderRadius="base" - /> - - - + + } + objectFit="contain" + maxW="full" + maxH="full" + borderRadius="base" + /> + + {dragPreviewState?.type === 'multiple-image' ? createMultipleImageDragPreview(dragPreviewState) : null} {dragPreviewState?.type === 'single-image' ? createSingleImageDragPreview(dragPreviewState) : null}