mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
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
This commit is contained in:
parent
ffa05a0bb3
commit
75c1c4ce5a
@ -3,17 +3,15 @@ import { Box, forwardRef } from '@chakra-ui/react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
// This is exported so that we can use it to calculate the number of images per row
|
||||
// for the directional gallery navigation.
|
||||
export const GALLERY_IMAGE_PADDING_PX = 6;
|
||||
export const imageItemContainerTestId = 'image-item-container';
|
||||
|
||||
type ItemContainerProps = PropsWithChildren & FlexProps;
|
||||
const ItemContainer = forwardRef((props: ItemContainerProps, ref) => (
|
||||
<Box
|
||||
className="item-container"
|
||||
ref={ref}
|
||||
p={`${GALLERY_IMAGE_PADDING_PX}px`}
|
||||
data-testid="image-item-container"
|
||||
p={1.5}
|
||||
data-testid={imageItemContainerTestId}
|
||||
>
|
||||
{props.children}
|
||||
</Box>
|
||||
|
@ -4,6 +4,8 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const imageListContainerTestId = 'image-list-container';
|
||||
|
||||
type ListContainerProps = PropsWithChildren & FlexProps;
|
||||
const ListContainer = forwardRef((props: ListContainerProps, ref) => {
|
||||
const galleryImageMinimumWidth = useAppSelector(
|
||||
@ -16,7 +18,7 @@ const ListContainer = forwardRef((props: ListContainerProps, ref) => {
|
||||
className="list-container"
|
||||
ref={ref}
|
||||
gridTemplateColumns={`repeat(auto-fill, minmax(${galleryImageMinimumWidth}px, 1fr))`}
|
||||
data-testid="image-list-container"
|
||||
data-testid={imageListContainerTestId}
|
||||
>
|
||||
{props.children}
|
||||
</Grid>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { getGalleryImageDataTestId } from 'features/gallery/components/ImageGrid/getGalleryImageDataTestId';
|
||||
import { GALLERY_IMAGE_PADDING_PX } from 'features/gallery/components/ImageGrid/ImageGridItemContainer';
|
||||
import { imageItemContainerTestId } from 'features/gallery/components/ImageGrid/ImageGridItemContainer';
|
||||
import { imageListContainerTestId } from 'features/gallery/components/ImageGrid/ImageGridListContainer';
|
||||
import { virtuosoGridRefs } from 'features/gallery/components/ImageGrid/types';
|
||||
import { useGalleryImages } from 'features/gallery/hooks/useGalleryImages';
|
||||
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
||||
@ -27,23 +28,17 @@ import { imagesSelectors } from 'services/api/util';
|
||||
* Gets the number of images per row in the gallery by grabbing their DOM elements.
|
||||
*/
|
||||
const getImagesPerRow = (): number => {
|
||||
const imageRect = Object.values(
|
||||
document.getElementsByClassName('gallerygrid-image')
|
||||
)[0]?.getBoundingClientRect();
|
||||
const widthOfGalleryImage =
|
||||
document
|
||||
.querySelector(`[data-testid="${imageItemContainerTestId}"]`)
|
||||
?.getBoundingClientRect().width ?? 1;
|
||||
|
||||
// We have to manually take into account the padding of the image container, else
|
||||
// imagesPerRow will be wrong when the gallery is large or images are very small.
|
||||
const widthOfGalleryImage = imageRect
|
||||
? imageRect.width + GALLERY_IMAGE_PADDING_PX * 2
|
||||
: 0;
|
||||
const widthOfGalleryGrid =
|
||||
document
|
||||
.querySelector(`[data-testid="${imageListContainerTestId}"]`)
|
||||
?.getBoundingClientRect().width ?? 0;
|
||||
|
||||
const galleryGridRect = document
|
||||
.getElementById('gallery-grid')
|
||||
?.getBoundingClientRect();
|
||||
|
||||
const widthOfGalleryGrid = galleryGridRect?.width ?? 0;
|
||||
|
||||
const imagesPerRow = Math.floor(widthOfGalleryGrid / widthOfGalleryImage);
|
||||
const imagesPerRow = Math.round(widthOfGalleryGrid / widthOfGalleryImage);
|
||||
|
||||
return imagesPerRow;
|
||||
};
|
||||
@ -104,11 +99,11 @@ const getUpImage = (images: ImageDTO[], currentIndex: number) => {
|
||||
|
||||
const getDownImage = (images: ImageDTO[], currentIndex: number) => {
|
||||
const imagesPerRow = getImagesPerRow();
|
||||
// If we are on the first row, we want to stay on the first row, not go to last image
|
||||
const isOnLastRow = currentIndex >= images.length - imagesPerRow;
|
||||
const index = isOnLastRow
|
||||
? currentIndex
|
||||
: clamp(currentIndex + imagesPerRow, 0, images.length - 1);
|
||||
// If there are no images below the current image, we want to stay where we are
|
||||
const areImagesBelow = currentIndex < images.length - imagesPerRow;
|
||||
const index = areImagesBelow
|
||||
? clamp(currentIndex + imagesPerRow, 0, images.length - 1)
|
||||
: currentIndex;
|
||||
const image = images[index];
|
||||
return { index, image };
|
||||
};
|
||||
@ -164,7 +159,7 @@ export const useGalleryNavigation = (): UseGalleryNavigationReturn => {
|
||||
imagesSelectors.selectAll(data),
|
||||
lastSelectedImageIndex
|
||||
);
|
||||
if (!image) {
|
||||
if (!image || index === lastSelectedImageIndex) {
|
||||
return;
|
||||
}
|
||||
dispatch(imageSelected(image));
|
||||
|
Loading…
Reference in New Issue
Block a user