@@ -23,7 +23,7 @@ import { imageToCompareChanged, selectGallerySlice, selectionChanged } from 'fea
23
23
import { navigationApi } from 'features/ui/layouts/navigation-api' ;
24
24
import { VIEWER_PANEL_ID } from 'features/ui/layouts/shared' ;
25
25
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' ;
27
27
import { PiImageBold } from 'react-icons/pi' ;
28
28
import { imagesApi } from 'services/api/endpoints/images' ;
29
29
import type { ImageDTO } from 'services/api/types' ;
@@ -42,45 +42,42 @@ const galleryImageContainerSX = {
42
42
'&[data-is-dragging=true]' : {
43
43
opacity : 0.3 ,
44
44
} ,
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)' ,
84
81
} ,
85
82
} satisfies SystemStyleObject ;
86
83
@@ -142,8 +139,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
142
139
const [ dragPreviewState , setDragPreviewState ] = useState <
143
140
DndDragPreviewSingleImageState | DndDragPreviewMultipleImageState | null
144
141
> ( 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 ) ;
147
143
const selectIsSelectedForCompare = useMemo (
148
144
( ) => createSelector ( selectGallerySlice , ( gallery ) => gallery . imageToCompare === imageDTO . image_name ) ,
149
145
[ imageDTO . image_name ]
@@ -156,6 +152,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
156
152
const isSelected = useAppSelector ( selectIsSelected ) ;
157
153
158
154
useEffect ( ( ) => {
155
+ const element = ref . current ;
159
156
if ( ! element ) {
160
157
return ;
161
158
}
@@ -221,7 +218,7 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
221
218
} ,
222
219
} )
223
220
) ;
224
- } , [ element , imageDTO , store ] ) ;
221
+ } , [ imageDTO , store ] ) ;
225
222
226
223
const [ isHovered , setIsHovered ] = useState ( false ) ;
227
224
@@ -240,34 +237,35 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
240
237
navigationApi . focusPanelInActiveTab ( VIEWER_PANEL_ID ) ;
241
238
} , [ store ] ) ;
242
239
243
- useImageContextMenu ( imageDTO , element ) ;
240
+ useImageContextMenu ( imageDTO , ref ) ;
244
241
245
242
return (
246
243
< >
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 >
271
269
{ dragPreviewState ?. type === 'multiple-image' ? createMultipleImageDragPreview ( dragPreviewState ) : null }
272
270
{ dragPreviewState ?. type === 'single-image' ? createSingleImageDragPreview ( dragPreviewState ) : null }
273
271
</ >
0 commit comments