Skip to content

Commit 75c1c4c

Browse files
psychedelicioushipsterusername
authored andcommitted
fix(ui): fix gallery nav math
- Use the virtuoso grid item container and list containers to calculate imagesPerRow, skipping manual compensation for padding of images - Round the imagesPerRow instead of flooring - we often will end up with values like 4.99999 due to floating point precision - Update `getDownImage` comments & logic to be clearer - Use variables for the ids in query selectors, preventing future typos - Only scroll if the new selected image is different from the prev one
1 parent ffa05a0 commit 75c1c4c

File tree

3 files changed

+23
-28
lines changed

3 files changed

+23
-28
lines changed

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@ import { Box, forwardRef } from '@chakra-ui/react';
33
import type { PropsWithChildren } from 'react';
44
import { memo } from 'react';
55

6-
// This is exported so that we can use it to calculate the number of images per row
7-
// for the directional gallery navigation.
8-
export const GALLERY_IMAGE_PADDING_PX = 6;
6+
export const imageItemContainerTestId = 'image-item-container';
97

108
type ItemContainerProps = PropsWithChildren & FlexProps;
119
const ItemContainer = forwardRef((props: ItemContainerProps, ref) => (
1210
<Box
1311
className="item-container"
1412
ref={ref}
15-
p={`${GALLERY_IMAGE_PADDING_PX}px`}
16-
data-testid="image-item-container"
13+
p={1.5}
14+
data-testid={imageItemContainerTestId}
1715
>
1816
{props.children}
1917
</Box>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { useAppSelector } from 'app/store/storeHooks';
44
import type { PropsWithChildren } from 'react';
55
import { memo } from 'react';
66

7+
export const imageListContainerTestId = 'image-list-container';
8+
79
type ListContainerProps = PropsWithChildren & FlexProps;
810
const ListContainer = forwardRef((props: ListContainerProps, ref) => {
911
const galleryImageMinimumWidth = useAppSelector(
@@ -16,7 +18,7 @@ const ListContainer = forwardRef((props: ListContainerProps, ref) => {
1618
className="list-container"
1719
ref={ref}
1820
gridTemplateColumns={`repeat(auto-fill, minmax(${galleryImageMinimumWidth}px, 1fr))`}
19-
data-testid="image-list-container"
21+
data-testid={imageListContainerTestId}
2022
>
2123
{props.children}
2224
</Grid>

invokeai/frontend/web/src/features/gallery/hooks/useGalleryNavigation.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
22
import { getGalleryImageDataTestId } from 'features/gallery/components/ImageGrid/getGalleryImageDataTestId';
3-
import { GALLERY_IMAGE_PADDING_PX } from 'features/gallery/components/ImageGrid/ImageGridItemContainer';
3+
import { imageItemContainerTestId } from 'features/gallery/components/ImageGrid/ImageGridItemContainer';
4+
import { imageListContainerTestId } from 'features/gallery/components/ImageGrid/ImageGridListContainer';
45
import { virtuosoGridRefs } from 'features/gallery/components/ImageGrid/types';
56
import { useGalleryImages } from 'features/gallery/hooks/useGalleryImages';
67
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
@@ -27,23 +28,17 @@ import { imagesSelectors } from 'services/api/util';
2728
* Gets the number of images per row in the gallery by grabbing their DOM elements.
2829
*/
2930
const getImagesPerRow = (): number => {
30-
const imageRect = Object.values(
31-
document.getElementsByClassName('gallerygrid-image')
32-
)[0]?.getBoundingClientRect();
31+
const widthOfGalleryImage =
32+
document
33+
.querySelector(`[data-testid="${imageItemContainerTestId}"]`)
34+
?.getBoundingClientRect().width ?? 1;
3335

34-
// We have to manually take into account the padding of the image container, else
35-
// imagesPerRow will be wrong when the gallery is large or images are very small.
36-
const widthOfGalleryImage = imageRect
37-
? imageRect.width + GALLERY_IMAGE_PADDING_PX * 2
38-
: 0;
36+
const widthOfGalleryGrid =
37+
document
38+
.querySelector(`[data-testid="${imageListContainerTestId}"]`)
39+
?.getBoundingClientRect().width ?? 0;
3940

40-
const galleryGridRect = document
41-
.getElementById('gallery-grid')
42-
?.getBoundingClientRect();
43-
44-
const widthOfGalleryGrid = galleryGridRect?.width ?? 0;
45-
46-
const imagesPerRow = Math.floor(widthOfGalleryGrid / widthOfGalleryImage);
41+
const imagesPerRow = Math.round(widthOfGalleryGrid / widthOfGalleryImage);
4742

4843
return imagesPerRow;
4944
};
@@ -104,11 +99,11 @@ const getUpImage = (images: ImageDTO[], currentIndex: number) => {
10499

105100
const getDownImage = (images: ImageDTO[], currentIndex: number) => {
106101
const imagesPerRow = getImagesPerRow();
107-
// If we are on the first row, we want to stay on the first row, not go to last image
108-
const isOnLastRow = currentIndex >= images.length - imagesPerRow;
109-
const index = isOnLastRow
110-
? currentIndex
111-
: clamp(currentIndex + imagesPerRow, 0, images.length - 1);
102+
// If there are no images below the current image, we want to stay where we are
103+
const areImagesBelow = currentIndex < images.length - imagesPerRow;
104+
const index = areImagesBelow
105+
? clamp(currentIndex + imagesPerRow, 0, images.length - 1)
106+
: currentIndex;
112107
const image = images[index];
113108
return { index, image };
114109
};
@@ -164,7 +159,7 @@ export const useGalleryNavigation = (): UseGalleryNavigationReturn => {
164159
imagesSelectors.selectAll(data),
165160
lastSelectedImageIndex
166161
);
167-
if (!image) {
162+
if (!image || index === lastSelectedImageIndex) {
168163
return;
169164
}
170165
dispatch(imageSelected(image));

0 commit comments

Comments
 (0)