Skip to content

Commit 24f61d2

Browse files
feat(ui): make image field collection scrollable
1 parent eb9a417 commit 24f61d2

File tree

3 files changed

+34
-54
lines changed

3 files changed

+34
-54
lines changed

invokeai/frontend/web/src/common/components/OverlayScrollbars/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { deepClone } from 'common/util/deepClone';
22
import { merge } from 'lodash-es';
33
import { ClickScrollPlugin, OverlayScrollbars } from 'overlayscrollbars';
44
import type { UseOverlayScrollbarsParams } from 'overlayscrollbars-react';
5+
import type { CSSProperties } from 'react';
56

67
OverlayScrollbars.plugin(ClickScrollPlugin);
78

@@ -27,3 +28,8 @@ export const getOverlayScrollbarsParams = (
2728
merge(params, { options: { overflow: { y: overflowY, x: overflowX } } });
2829
return params;
2930
};
31+
32+
export const overlayScrollbarsStyles: CSSProperties = {
33+
height: '100%',
34+
width: '100%',
35+
};

invokeai/frontend/web/src/features/dnd/DndImageFromImageName.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ImageFieldCollectionInputComponent.tsx

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type { SystemStyleObject } from '@invoke-ai/ui-library';
2-
import { Flex, Grid, GridItem } from '@invoke-ai/ui-library';
2+
import { Box, Flex, Grid, GridItem } from '@invoke-ai/ui-library';
33
import { useAppStore } from 'app/store/nanostores/store';
44
import { IAINoContentFallback, IAINoContentFallbackWithSpinner } from 'common/components/IAIImageFallback';
5+
import { getOverlayScrollbarsParams, overlayScrollbarsStyles } from 'common/components/OverlayScrollbars/constants';
56
import { UploadMultipleImageButton } from 'common/hooks/useImageUploadButton';
7+
import { TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL } from 'features/controlLayers/konva/patterns/transparency-checkerboard-pattern';
68
import type { AddImagesToNodeImageFieldCollection } from 'features/dnd/dnd';
79
import { addImagesToNodeImageFieldCollectionDndTarget } from 'features/dnd/dnd';
810
import { DndDropTarget } from 'features/dnd/DndDropTarget';
@@ -12,6 +14,7 @@ import { removeImageFromNodeImageFieldCollectionAction } from 'features/imageAct
1214
import { useFieldIsInvalid } from 'features/nodes/hooks/useFieldIsInvalid';
1315
import { fieldImageCollectionValueChanged } from 'features/nodes/store/nodesSlice';
1416
import type { ImageFieldCollectionInputInstance, ImageFieldCollectionInputTemplate } from 'features/nodes/types/field';
17+
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
1518
import { memo, useCallback, useMemo } from 'react';
1619
import { useTranslation } from 'react-i18next';
1720
import { PiArrowCounterClockwiseBold, PiExclamationMarkBold } from 'react-icons/pi';
@@ -20,6 +23,8 @@ import type { ImageDTO } from 'services/api/types';
2023

2124
import type { FieldComponentProps } from './types';
2225

26+
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
27+
2328
const sx = {
2429
borderWidth: 1,
2530
'&[data-error=true]': {
@@ -68,15 +73,7 @@ export const ImageFieldCollectionInputComponent = memo(
6873
);
6974

7075
return (
71-
<Flex
72-
position="relative"
73-
className="nodrag"
74-
w="full"
75-
h="full"
76-
minH={16}
77-
alignItems="stretch"
78-
justifyContent="center"
79-
>
76+
<Flex position="relative" w="full" h="full" minH={16} maxH={64} alignItems="stretch" justifyContent="center">
8077
{(!field.value || field.value.length === 0) && (
8178
<UploadMultipleImageButton
8279
w="full"
@@ -88,23 +85,17 @@ export const ImageFieldCollectionInputComponent = memo(
8885
/>
8986
)}
9087
{field.value && field.value.length > 0 && (
91-
<Grid
92-
className="nopan"
93-
borderRadius="base"
94-
w="full"
95-
h="full"
96-
templateColumns="repeat(3, 1fr)"
97-
gap={1}
98-
sx={sx}
99-
data-error={isInvalid}
100-
p={1}
101-
>
102-
{field.value.map(({ image_name }) => (
103-
<GridItem key={image_name} position="relative">
104-
<ImageGridItemContent imageName={image_name} onRemoveImage={onRemoveImage} />
105-
</GridItem>
106-
))}
107-
</Grid>
88+
<Box w="full" h="auto" p={1} sx={sx} data-error={isInvalid} borderRadius="base">
89+
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayscrollbarsOptions}>
90+
<Grid className="nopan nowheel" w="full" h="full" templateColumns="repeat(4, 1fr)" gap={1}>
91+
{field.value.map(({ image_name }) => (
92+
<GridItem key={image_name} position="relative" className="nodrag">
93+
<ImageGridItemContent imageName={image_name} onRemoveImage={onRemoveImage} />
94+
</GridItem>
95+
))}
96+
</Grid>
97+
</OverlayScrollbarsComponent>
98+
</Box>
10899
)}
109100
<DndDropTarget
110101
dndTarget={addImagesToNodeImageFieldCollectionDndTarget}
@@ -135,7 +126,16 @@ const ImageGridItemContent = memo(
135126

136127
return (
137128
<>
138-
<DndImage imageDTO={query.data} asThumbnail />
129+
<DndImage
130+
imageDTO={query.data}
131+
asThumbnail
132+
objectFit="contain"
133+
w="full"
134+
h="full"
135+
aspectRatio="1/1"
136+
backgroundSize={8}
137+
backgroundImage={TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL}
138+
/>
139139
<DndImageIcon
140140
onClick={onClickRemove}
141141
icon={<PiArrowCounterClockwiseBold />}

0 commit comments

Comments
 (0)