Skip to content

Commit 7bb25ef

Browse files
fix(ui): gallery dnd
1 parent 62f52c7 commit 7bb25ef

File tree

1 file changed

+66
-68
lines changed

1 file changed

+66
-68
lines changed

invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx

Lines changed: 66 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { imageToCompareChanged, selectGallerySlice, selectionChanged } from 'fea
2323
import { navigationApi } from 'features/ui/layouts/navigation-api';
2424
import { VIEWER_PANEL_ID } from 'features/ui/layouts/shared';
2525
import type { MouseEvent, MouseEventHandler } from 'react';
26-
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
26+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2727
import { PiImageBold } from 'react-icons/pi';
2828
import { imagesApi } from 'services/api/endpoints/images';
2929
import type { ImageDTO } from 'services/api/types';
@@ -42,45 +42,42 @@ const galleryImageContainerSX = {
4242
'&[data-is-dragging=true]': {
4343
opacity: 0.3,
4444
},
45-
[`.${GALLERY_IMAGE_CLASS}`]: {
46-
touchAction: 'none',
47-
userSelect: 'none',
48-
webkitUserSelect: 'none',
49-
position: 'relative',
50-
justifyContent: 'center',
51-
alignItems: 'center',
52-
aspectRatio: '1/1',
53-
'::before': {
54-
content: '""',
55-
display: 'inline-block',
56-
position: 'absolute',
57-
top: 0,
58-
left: 0,
59-
right: 0,
60-
bottom: 0,
61-
pointerEvents: 'none',
62-
borderRadius: 'base',
63-
},
64-
'&[data-selected=true]::before': {
65-
boxShadow:
66-
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-500), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
67-
},
68-
'&[data-selected-for-compare=true]::before': {
69-
boxShadow:
70-
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-300), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
71-
},
72-
'&:hover::before': {
73-
boxShadow:
74-
'inset 0px 0px 0px 1px var(--invoke-colors-invokeBlue-300), inset 0px 0px 0px 2px var(--invoke-colors-invokeBlue-800)',
75-
},
76-
'&:hover[data-selected=true]::before': {
77-
boxShadow:
78-
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-400), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
79-
},
80-
'&:hover[data-selected-for-compare=true]::before': {
81-
boxShadow:
82-
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-200), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
83-
},
45+
userSelect: 'none',
46+
webkitUserSelect: 'none',
47+
position: 'relative',
48+
justifyContent: 'center',
49+
alignItems: 'center',
50+
aspectRatio: '1/1',
51+
'::before': {
52+
content: '""',
53+
display: 'inline-block',
54+
position: 'absolute',
55+
top: 0,
56+
left: 0,
57+
right: 0,
58+
bottom: 0,
59+
pointerEvents: 'none',
60+
borderRadius: 'base',
61+
},
62+
'&[data-selected=true]::before': {
63+
boxShadow:
64+
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-500), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
65+
},
66+
'&[data-selected-for-compare=true]::before': {
67+
boxShadow:
68+
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-300), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
69+
},
70+
'&:hover::before': {
71+
boxShadow:
72+
'inset 0px 0px 0px 1px var(--invoke-colors-invokeBlue-300), inset 0px 0px 0px 2px var(--invoke-colors-invokeBlue-800)',
73+
},
74+
'&:hover[data-selected=true]::before': {
75+
boxShadow:
76+
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-400), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
77+
},
78+
'&:hover[data-selected-for-compare=true]::before': {
79+
boxShadow:
80+
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-200), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
8481
},
8582
} satisfies SystemStyleObject;
8683

@@ -142,8 +139,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
142139
const [dragPreviewState, setDragPreviewState] = useState<
143140
DndDragPreviewSingleImageState | DndDragPreviewMultipleImageState | null
144141
>(null);
145-
// Must use callback ref - else chakra's Image fallback prop will break the ref & dnd
146-
const [element, ref] = useState<HTMLDivElement | null>(null);
142+
const ref = useRef<HTMLDivElement>(null);
147143
const selectIsSelectedForCompare = useMemo(
148144
() => createSelector(selectGallerySlice, (gallery) => gallery.imageToCompare === imageDTO.image_name),
149145
[imageDTO.image_name]
@@ -156,6 +152,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
156152
const isSelected = useAppSelector(selectIsSelected);
157153

158154
useEffect(() => {
155+
const element = ref.current;
159156
if (!element) {
160157
return;
161158
}
@@ -221,7 +218,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
221218
},
222219
})
223220
);
224-
}, [element, imageDTO, store]);
221+
}, [imageDTO, store]);
225222

226223
const [isHovered, setIsHovered] = useState(false);
227224

@@ -240,34 +237,35 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
240237
navigationApi.focusPanelInActiveTab(VIEWER_PANEL_ID);
241238
}, [store]);
242239

243-
useImageContextMenu(imageDTO, element);
240+
useImageContextMenu(imageDTO, ref);
244241

245242
return (
246243
<>
247-
<Box sx={galleryImageContainerSX} data-is-dragging={isDragging} data-image-name={imageDTO.image_name}>
248-
<Flex
249-
ref={ref}
250-
role="button"
251-
className={GALLERY_IMAGE_CLASS}
252-
onMouseOver={onMouseOver}
253-
onMouseOut={onMouseOut}
254-
onClick={onClick}
255-
onDoubleClick={onDoubleClick}
256-
data-selected={isSelected}
257-
data-selected-for-compare={isSelectedForCompare}
258-
>
259-
<Image
260-
src={imageDTO.thumbnail_url}
261-
w={imageDTO.width}
262-
fallback={<GalleryImagePlaceholder />}
263-
objectFit="contain"
264-
maxW="full"
265-
maxH="full"
266-
borderRadius="base"
267-
/>
268-
<GalleryImageHoverIcons imageDTO={imageDTO} isHovered={isHovered} />
269-
</Flex>
270-
</Box>
244+
<Flex
245+
ref={ref}
246+
sx={galleryImageContainerSX}
247+
data-is-dragging={isDragging}
248+
data-image-name={imageDTO.image_name}
249+
role="button"
250+
onMouseOver={onMouseOver}
251+
onMouseOut={onMouseOut}
252+
onClick={onClick}
253+
onDoubleClick={onDoubleClick}
254+
data-selected={isSelected}
255+
data-selected-for-compare={isSelectedForCompare}
256+
>
257+
<Image
258+
pointerEvents={'none'}
259+
src={imageDTO.thumbnail_url}
260+
w={imageDTO.width}
261+
fallback={<GalleryImagePlaceholder />}
262+
objectFit="contain"
263+
maxW="full"
264+
maxH="full"
265+
borderRadius="base"
266+
/>
267+
<GalleryImageHoverIcons imageDTO={imageDTO} isHovered={isHovered} />
268+
</Flex>
271269
{dragPreviewState?.type === 'multiple-image' ? createMultipleImageDragPreview(dragPreviewState) : null}
272270
{dragPreviewState?.type === 'single-image' ? createSingleImageDragPreview(dragPreviewState) : null}
273271
</>

0 commit comments

Comments
 (0)