({
+ shift: false,
+ ctrl: false,
+ meta: false,
+ alt: false,
+});
+
+const $subscribers = atom(0);
+
+const listener = (e: KeyboardEvent) => {
+ $modifiers.setKey('shift', e.shiftKey);
+ $modifiers.setKey('ctrl', e.ctrlKey);
+ $modifiers.setKey('alt', e.altKey);
+ $modifiers.setKey('meta', e.metaKey);
+};
+
+export const useGlobalModifiersInit = () => {
+ useEffect(() => {
+ $subscribers.set($subscribers.get() + 1);
+
+ if ($subscribers.get() === 1) {
+ window.addEventListener('keydown', listener);
+ window.addEventListener('keyup', listener);
+ }
+
+ return () => {
+ $subscribers.set(Math.max($subscribers.get() - 1, 0));
+ if ($subscribers.get() > 0) {
+ return;
+ }
+ window.removeEventListener('keydown', listener);
+ window.removeEventListener('keyup', listener);
+ };
+ }, []);
+};
+
+export const useGlobalModifiersSetters = () => {
+ const setShift = useCallback((shift: boolean) => {
+ $modifiers.setKey('shift', shift);
+ }, []);
+ const setCtrl = useCallback((shift: boolean) => {
+ $modifiers.setKey('ctrl', shift);
+ }, []);
+ const setAlt = useCallback((shift: boolean) => {
+ $modifiers.setKey('alt', shift);
+ }, []);
+ const setMeta = useCallback((shift: boolean) => {
+ $modifiers.setKey('meta', shift);
+ }, []);
+ return { setShift, setCtrl, setAlt, setMeta };
+};
diff --git a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx
index 135a2ee9e0..fd362d886b 100644
--- a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx
+++ b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx
@@ -2,7 +2,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import { useCallback } from 'react';
import { useDropzone } from 'react-dropzone';
import { useUploadImageMutation } from 'services/api/endpoints/images';
-import { PostUploadAction } from 'services/api/types';
+import type { PostUploadAction } from 'services/api/types';
type UseImageUploadButtonArgs = {
postUploadAction?: PostUploadAction;
diff --git a/invokeai/frontend/web/src/common/util/stopPastePropagation.ts b/invokeai/frontend/web/src/common/util/stopPastePropagation.ts
index b6b237387d..f9195a4f58 100644
--- a/invokeai/frontend/web/src/common/util/stopPastePropagation.ts
+++ b/invokeai/frontend/web/src/common/util/stopPastePropagation.ts
@@ -1,4 +1,4 @@
-import { ClipboardEvent } from 'react';
+import type { ClipboardEvent } from 'react';
export const stopPastePropagation = (e: ClipboardEvent) => {
e.stopPropagation();
diff --git a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
index 72532b555c..28d3fb4024 100644
--- a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
@@ -1,37 +1,45 @@
+import { useDisclosure } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIAlertDialog from 'common/components/IAIAlertDialog';
-import IAIButton from 'common/components/IAIButton';
+import { InvButton } from 'common/components/InvButton/InvButton';
+import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog';
+import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { clearCanvasHistory } from 'features/canvas/store/canvasSlice';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
-import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
-import { memo, useCallback } from 'react';
const ClearCanvasHistoryButtonModal = () => {
const isStaging = useAppSelector(isStagingSelector);
const dispatch = useAppDispatch();
const { t } = useTranslation();
-
+ const { isOpen, onOpen, onClose } = useDisclosure();
const acceptCallback = useCallback(
() => dispatch(clearCanvasHistory()),
[dispatch]
);
return (
- } isDisabled={isStaging}>
- {t('unifiedCanvas.clearCanvasHistory')}
-
- }
- >
- {t('unifiedCanvas.clearCanvasHistoryMessage')}
-
- {t('unifiedCanvas.clearCanvasHistoryConfirm')}
-
+ <>
+ }
+ isDisabled={isStaging}
+ >
+ {t('unifiedCanvas.clearCanvasHistory')}
+
+
+ {t('unifiedCanvas.clearCanvasHistoryMessage')}
+
+ {t('unifiedCanvas.clearCanvasHistoryConfirm')}
+
+ >
);
};
export default memo(ClearCanvasHistoryButtonModal);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
index 2aa7f8e2c9..f62f0836c2 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
@@ -15,11 +15,12 @@ import {
setCanvasBaseLayer,
setCanvasStage,
} from 'features/canvas/util/konvaInstanceProvider';
-import Konva from 'konva';
-import { KonvaEventObject } from 'konva/lib/Node';
-import { Vector2d } from 'konva/lib/types';
+import type Konva from 'konva';
+import type { KonvaEventObject } from 'konva/lib/Node';
+import type { Vector2d } from 'konva/lib/types';
import { memo, useCallback, useEffect, useRef } from 'react';
import { Layer, Stage } from 'react-konva';
+
import IAICanvasBoundingBoxOverlay from './IAICanvasBoundingBoxOverlay';
import IAICanvasGrid from './IAICanvasGrid';
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
index 19c0109691..0e53a3dde4 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
@@ -1,10 +1,11 @@
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
-import { useColorMode, useToken } from '@chakra-ui/react';
+import { useToken } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { range } from 'lodash-es';
-import { ReactNode, memo, useCallback, useLayoutEffect, useState } from 'react';
+import type { ReactNode } from 'react';
+import { memo, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
@@ -15,12 +16,8 @@ const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
const IAICanvasGrid = () => {
const { stageScale, stageCoordinates, stageDimensions } =
useAppSelector(selector);
- const { colorMode } = useColorMode();
const [gridLines, setGridLines] = useState([]);
- const [darkGridLineColor, lightGridLineColor] = useToken('colors', [
- 'base.800',
- 'base.200',
- ]);
+ const [gridLineColor] = useToken('colors', ['base.800']);
const unscale = useCallback(
(value: number) => {
@@ -78,7 +75,7 @@ const IAICanvasGrid = () => {
x={fullRect.x1 + i * 64}
y={fullRect.y1}
points={[0, 0, 0, ySize]}
- stroke={colorMode === 'dark' ? darkGridLineColor : lightGridLineColor}
+ stroke={gridLineColor}
strokeWidth={1}
/>
));
@@ -88,21 +85,13 @@ const IAICanvasGrid = () => {
x={fullRect.x1}
y={fullRect.y1 + i * 64}
points={[0, 0, xSize, 0]}
- stroke={colorMode === 'dark' ? darkGridLineColor : lightGridLineColor}
+ stroke={gridLineColor}
strokeWidth={1}
/>
));
setGridLines(xLines.concat(yLines));
- }, [
- stageScale,
- stageCoordinates,
- stageDimensions,
- unscale,
- colorMode,
- darkGridLineColor,
- lightGridLineColor,
- ]);
+ }, [stageScale, stageCoordinates, stageDimensions, unscale, gridLineColor]);
return {gridLines};
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
index fa3b0ece62..437f1d7d9d 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
@@ -1,10 +1,11 @@
import { skipToken } from '@reduxjs/toolkit/query';
import { $authToken } from 'app/store/nanostores/authToken';
+import type { CanvasImage } from 'features/canvas/store/canvasTypes';
import { memo } from 'react';
import { Image } from 'react-konva';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import useImage from 'use-image';
-import { CanvasImage } from 'features/canvas/store/canvasTypes';
+
import IAICanvasImageErrorFallback from './IAICanvasImageErrorFallback';
type IAICanvasImageProps = {
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImageErrorFallback.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImageErrorFallback.tsx
index b933630ca8..00f4e46f52 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImageErrorFallback.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImageErrorFallback.tsx
@@ -1,8 +1,8 @@
-import { useColorModeValue, useToken } from '@chakra-ui/react';
+import { useToken } from '@chakra-ui/react';
+import type { CanvasImage } from 'features/canvas/store/canvasTypes';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Group, Rect, Text } from 'react-konva';
-import { CanvasImage } from 'features/canvas/store/canvasTypes';
type IAICanvasImageErrorFallbackProps = {
canvasImage: CanvasImage;
@@ -10,10 +10,7 @@ type IAICanvasImageErrorFallbackProps = {
const IAICanvasImageErrorFallback = ({
canvasImage,
}: IAICanvasImageErrorFallbackProps) => {
- const [errorColorLight, errorColorDark, fontColorLight, fontColorDark] =
- useToken('colors', ['base.400', 'base.500', 'base.700', 'base.900']);
- const errorColor = useColorModeValue(errorColorLight, errorColorDark);
- const fontColor = useColorModeValue(fontColorLight, fontColorDark);
+ const [rectFill, textFill] = useToken('colors', ['base.500', 'base.900']);
const { t } = useTranslation();
return (
@@ -22,7 +19,7 @@ const IAICanvasImageErrorFallback = ({
y={canvasImage.y}
width={canvasImage.width}
height={canvasImage.height}
- fill={errorColor}
+ fill={rectFill}
/>
);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
index 4c42189a4e..dd9623b2ce 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
@@ -1,7 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
-import { ImageConfig } from 'konva/lib/shapes/Image';
+import type { ImageConfig } from 'konva/lib/shapes/Image';
import { memo, useEffect, useState } from 'react';
import { Image as KonvaImage } from 'react-konva';
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
index ca869ae0db..6bde5f14cc 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
@@ -2,8 +2,8 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
-import Konva from 'konva';
-import { RectConfig } from 'konva/lib/shapes/Rect';
+import type Konva from 'konva';
+import type { RectConfig } from 'konva/lib/shapes/Rect';
import { isNumber } from 'lodash-es';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { Rect } from 'react-konva';
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
index 42a58579c3..c0ba6ee2b0 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
@@ -2,7 +2,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
-import { GroupConfig } from 'konva/lib/Group';
+import type { GroupConfig } from 'konva/lib/Group';
import { memo } from 'react';
import { Group, Line } from 'react-konva';
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
index 589b22b73f..d41f9de4e6 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
@@ -10,6 +10,7 @@ import {
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { memo } from 'react';
import { Group, Line, Rect } from 'react-konva';
+
import IAICanvasImage from './IAICanvasImage';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
index 3b9f7cc81b..1bc34eef8d 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
@@ -1,9 +1,10 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
-import { GroupConfig } from 'konva/lib/Group';
+import type { GroupConfig } from 'konva/lib/Group';
import { memo } from 'react';
import { Group, Rect } from 'react-konva';
+
import IAICanvasImage from './IAICanvasImage';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
index a297976e17..f1c040af94 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
@@ -1,10 +1,10 @@
-import { ButtonGroup, Flex } from '@chakra-ui/react';
+import { Flex } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIButton from 'common/components/IAIButton';
-import IAIIconButton from 'common/components/IAIIconButton';
+import { InvButton } from 'common/components/InvButton/InvButton';
+import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
import {
commitStagingAreaImage,
@@ -14,6 +14,7 @@ import {
setShouldShowStagingImage,
setShouldShowStagingOutline,
} from 'features/canvas/store/canvasSlice';
+import { InvIconButton } from 'index';
import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
@@ -135,39 +136,39 @@ const IAICanvasStagingAreaToolbar = () => {
onMouseEnter={handleMouseOver}
onMouseLeave={handleMouseOut}
>
-
-
+ }
onClick={handlePrevImage}
- colorScheme="accent"
+ colorScheme="blue"
isDisabled={!shouldShowStagingImage}
/>
- {`${currentIndex + 1}/${total}`}
- {`${currentIndex + 1}/${total}`}
+ }
onClick={handleNextImage}
- colorScheme="accent"
+ colorScheme="blue"
isDisabled={!shouldShowStagingImage}
/>
-
-
-
+
+ }
onClick={handleAccept}
- colorScheme="accent"
+ colorScheme="blue"
/>
- {
data-alert={!shouldShowStagingImage}
icon={shouldShowStagingImage ? : }
onClick={handleToggleShouldShowStagingImage}
- colorScheme="accent"
+ colorScheme="blue"
/>
- }
onClick={handleSaveToGallery}
- colorScheme="accent"
+ colorScheme="blue"
/>
- }
@@ -199,7 +200,7 @@ const IAICanvasStagingAreaToolbar = () => {
colorScheme="error"
fontSize={20}
/>
-
+
);
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
index f97d2504bc..e0c44d64f1 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
@@ -3,9 +3,10 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import roundToHundreth from 'features/canvas/util/roundToHundreth';
-import GenerationModeStatusText from 'features/parameters/components/Parameters/Canvas/GenerationModeStatusText';
+import GenerationModeStatusText from 'features/parameters/components/Canvas/GenerationModeStatusText';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
+
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
const warningColor = 'var(--invokeai-colors-warning-500)';
@@ -96,10 +97,7 @@ const IAICanvasStatusText = () => {
margin: 1,
borderRadius: 'base',
pointerEvents: 'none',
- bg: 'base.200',
- _dark: {
- bg: 'base.800',
- },
+ bg: 'base.800',
}}
>
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
index d237ac8052..b1be23340d 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
@@ -6,7 +6,7 @@ import {
COLOR_PICKER_SIZE,
COLOR_PICKER_STROKE_RADIUS,
} from 'features/canvas/util/constants';
-import { GroupConfig } from 'konva/lib/Group';
+import type { GroupConfig } from 'konva/lib/Group';
import { memo } from 'react';
import { Circle, Group } from 'react-konva';
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
index 5ae78bc924..3ec12a5b96 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
@@ -13,10 +13,10 @@ import {
setIsTransformingBoundingBox,
setShouldSnapToGrid,
} from 'features/canvas/store/canvasSlice';
-import Konva from 'konva';
-import { GroupConfig } from 'konva/lib/Group';
-import { KonvaEventObject } from 'konva/lib/Node';
-import { Vector2d } from 'konva/lib/types';
+import type Konva from 'konva';
+import type { GroupConfig } from 'konva/lib/Group';
+import type { KonvaEventObject } from 'konva/lib/Node';
+import type { Vector2d } from 'konva/lib/types';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { Group, Rect, Transformer } from 'react-konva';
@@ -145,7 +145,7 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
const y = Math.round(rect.y());
if (aspectRatio) {
- const newHeight = roundToMultiple(width / aspectRatio, 64);
+ const newHeight = roundToMultiple(width / aspectRatio.value, 64);
dispatch(
setBoundingBoxDimensions({
width: width,
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
index afc6f6b7b8..d96b434922 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
@@ -1,12 +1,18 @@
-import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
+import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIButton from 'common/components/IAIButton';
import IAIColorPicker from 'common/components/IAIColorPicker';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAIPopover from 'common/components/IAIPopover';
-import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
+import { InvButton } from 'common/components/InvButton/InvButton';
+import { InvCheckbox } from 'common/components/InvCheckbox/wrapper';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
+import {
+ InvPopover,
+ InvPopoverBody,
+ InvPopoverContent,
+ InvPopoverTrigger,
+} from 'common/components/InvPopover/wrapper';
import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import {
@@ -17,8 +23,9 @@ import {
setShouldPreserveMaskedArea,
} from 'features/canvas/store/canvasSlice';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { RgbaColor } from 'react-colorful';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
+import type { RgbaColor } from 'react-colorful';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaMask, FaSave, FaTrash } from 'react-icons/fa';
@@ -118,41 +125,51 @@ const IAICanvasMaskOptions = () => {
);
return (
-
- }
- isChecked={layer === 'mask'}
- isDisabled={isStaging}
- />
-
- }
- >
-
-
+
+ }
+ isChecked={layer === 'mask'}
+ isDisabled={isStaging}
/>
-
-
-
-
- } onClick={handleSaveMask}>
- {t('unifiedCanvas.saveMask')}
-
- } onClick={handleClearMask}>
- {t('unifiedCanvas.clearMask')}
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ } onClick={handleSaveMask}>
+ {t('unifiedCanvas.saveMask')}
+
+ }
+ onClick={handleClearMask}
+ >
+ {t('unifiedCanvas.clearMask')}
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx
index 2f76988801..87c0ca57e2 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx
@@ -1,7 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { redo } from 'features/canvas/store/canvasSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback } from 'react';
@@ -44,7 +44,7 @@ export default function IAICanvasRedoButton() {
);
return (
- }
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
index 6510ef09a6..41d2f1477b 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
@@ -2,9 +2,13 @@ import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAIPopover from 'common/components/IAIPopover';
-import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
+import { InvCheckbox } from 'common/components/InvCheckbox/wrapper';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import {
+ InvPopoverBody,
+ InvPopoverContent,
+ InvPopoverTrigger,
+} from 'common/components/InvPopover/wrapper';
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
import {
setShouldAntialias,
@@ -17,7 +21,9 @@ import {
setShouldShowIntermediates,
setShouldSnapToGrid,
} from 'features/canvas/store/canvasSlice';
-import { ChangeEvent, memo, useCallback } from 'react';
+import { InvIconButton, InvPopover } from 'index';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaWrench } from 'react-icons/fa';
@@ -127,66 +133,76 @@ const IAICanvasSettingsButtonPopover = () => {
);
return (
-
+
+ }
/>
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
index a184f32ab3..f5a3e41a0e 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
@@ -1,11 +1,17 @@
-import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
+import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIColorPicker from 'common/components/IAIColorPicker';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAIPopover from 'common/components/IAIPopover';
-import IAISlider from 'common/components/IAISlider';
+import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
+import {
+ InvPopoverBody,
+ InvPopoverContent,
+ InvPopoverTrigger,
+} from 'common/components/InvPopover/wrapper';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import {
addEraseRect,
@@ -14,9 +20,10 @@ import {
setBrushSize,
setTool,
} from 'features/canvas/store/canvasSlice';
+import { InvIconButton, InvPopover } from 'index';
import { clamp } from 'lodash-es';
import { memo, useCallback } from 'react';
-import { RgbaColor } from 'react-colorful';
+import type { RgbaColor } from 'react-colorful';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import {
@@ -196,8 +203,8 @@ const IAICanvasToolChooserOptions = () => {
);
return (
-
-
+ }
@@ -205,7 +212,7 @@ const IAICanvasToolChooserOptions = () => {
onClick={handleSelectBrushTool}
isDisabled={isStaging}
/>
- }
@@ -213,21 +220,21 @@ const IAICanvasToolChooserOptions = () => {
isDisabled={isStaging}
onClick={handleSelectEraserTool}
/>
- }
isDisabled={isStaging}
onClick={handleFillRect}
/>
- }
isDisabled={isStaging}
onClick={handleEraseBoundingBox}
/>
- }
@@ -235,41 +242,54 @@ const IAICanvasToolChooserOptions = () => {
isDisabled={isStaging}
onClick={handleSelectColorPickerTool}
/>
-
+
+ }
/>
- }
- >
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
index 1fba9c533f..3f597235c4 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
@@ -1,9 +1,12 @@
-import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
+import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAIMantineSelect from 'common/components/IAIMantineSelect';
+import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import type { InvSelectOnChange } from 'common/components/InvSelect/types';
+import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import { useCopyImageToClipboard } from 'common/hooks/useCopyImageToClipboard';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
@@ -21,12 +24,11 @@ import {
setLayer,
setTool,
} from 'features/canvas/store/canvasSlice';
-import {
- CanvasLayer,
- LAYER_NAMES_DICT,
-} from 'features/canvas/store/canvasTypes';
+import type { CanvasLayer } from 'features/canvas/store/canvasTypes';
+import { LAYER_NAMES_DICT } from 'features/canvas/store/canvasTypes';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
-import { memo, useCallback } from 'react';
+import { InvIconButton } from 'index';
+import { memo, useCallback, useMemo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import {
@@ -39,6 +41,7 @@ import {
FaTrash,
FaUpload,
} from 'react-icons/fa';
+
import IAICanvasMaskOptions from './IAICanvasMaskOptions';
import IAICanvasRedoButton from './IAICanvasRedoButton';
import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
@@ -193,17 +196,24 @@ const IAICanvasToolbar = () => {
dispatch(canvasDownloadedAsImage());
}, [dispatch]);
- const handleChangeLayer = useCallback(
- (v: string) => {
- const newLayer = v as CanvasLayer;
- dispatch(setLayer(newLayer));
- if (newLayer === 'mask' && !isMaskEnabled) {
+ const handleChangeLayer = useCallback(
+ (v) => {
+ if (!v) {
+ return;
+ }
+ dispatch(setLayer(v.value as CanvasLayer));
+ if (v.value === 'mask' && !isMaskEnabled) {
dispatch(setIsMaskEnabled(true));
}
},
[dispatch, isMaskEnabled]
);
+ const value = useMemo(
+ () => LAYER_NAMES_DICT.filter((o) => o.value === layer)[0],
+ [layer]
+ );
+
return (
{
}}
>
-
+
+
+
+
+
-
-
+ }
isChecked={tool === 'move' || isStaging}
onClick={handleSelectMoveTool}
/>
- }
onClick={handleClickResetCanvasView}
/>
-
+
-
-
+ }
onClick={handleMergeVisible}
isDisabled={isStaging}
/>
- }
@@ -257,7 +269,7 @@ const IAICanvasToolbar = () => {
isDisabled={isStaging}
/>
{isClipboardAPIAvailable && (
- }
@@ -265,21 +277,21 @@ const IAICanvasToolbar = () => {
isDisabled={isStaging}
/>
)}
- }
onClick={handleDownloadAsImage}
isDisabled={isStaging}
/>
-
-
+
+
-
+
-
-
+ }
@@ -287,7 +299,7 @@ const IAICanvasToolbar = () => {
{...getUploadButtonProps()}
/>
- }
@@ -295,10 +307,10 @@ const IAICanvasToolbar = () => {
colorScheme="error"
isDisabled={isStaging}
/>
-
-
+
+
-
+
);
};
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx
index 2d4fb0bc5a..2ac28a259a 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx
@@ -1,7 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { undo } from 'features/canvas/store/canvasSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback } from 'react';
@@ -45,7 +45,7 @@ export default function IAICanvasUndoButton() {
);
return (
- }
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
index c54e8ea560..ee3eb2f725 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
@@ -6,7 +6,7 @@ import {
setIsMovingStage,
setStageCoordinates,
} from 'features/canvas/store/canvasSlice';
-import { KonvaEventObject } from 'konva/lib/Node';
+import type { KonvaEventObject } from 'konva/lib/Node';
import { useCallback } from 'react';
const selector = createMemoizedSelector(
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasGenerationMode.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasGenerationMode.ts
index 55b04efca4..19d5c7c0e4 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasGenerationMode.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasGenerationMode.ts
@@ -1,5 +1,5 @@
import { useAppSelector } from 'app/store/storeHooks';
-import { GenerationMode } from 'features/canvas/store/canvasTypes';
+import type { GenerationMode } from 'features/canvas/store/canvasTypes';
import { getCanvasData } from 'features/canvas/util/getCanvasData';
import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode';
import { useEffect, useState } from 'react';
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
index c7837423c7..ecdec38af9 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
@@ -10,7 +10,7 @@ import {
setShouldSnapToGrid,
setTool,
} from 'features/canvas/store/canvasSlice';
-import { CanvasTool } from 'features/canvas/store/canvasTypes';
+import type { CanvasTool } from 'features/canvas/store/canvasTypes';
import { getCanvasStage } from 'features/canvas/util/konvaInstanceProvider';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useRef } from 'react';
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
index ff58079bdc..102a015608 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
@@ -9,9 +9,11 @@ import {
} from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import Konva from 'konva';
-import { KonvaEventObject } from 'konva/lib/Node';
-import { MutableRefObject, useCallback } from 'react';
+import type Konva from 'konva';
+import type { KonvaEventObject } from 'konva/lib/Node';
+import type { MutableRefObject } from 'react';
+import { useCallback } from 'react';
+
import useColorPicker from './useColorUnderCursor';
const selector = createMemoizedSelector(
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
index 9d73dab0a7..2ed748bd4b 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
@@ -8,9 +8,11 @@ import {
} from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import Konva from 'konva';
-import { Vector2d } from 'konva/lib/types';
-import { MutableRefObject, useCallback } from 'react';
+import type Konva from 'konva';
+import type { Vector2d } from 'konva/lib/types';
+import type { MutableRefObject } from 'react';
+import { useCallback } from 'react';
+
import useColorPicker from './useColorUnderCursor';
const selector = createMemoizedSelector(
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
index 1fcd81aaab..979f2933dd 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
@@ -10,8 +10,9 @@ import {
} from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import Konva from 'konva';
-import { MutableRefObject, useCallback } from 'react';
+import type Konva from 'konva';
+import type { MutableRefObject } from 'react';
+import { useCallback } from 'react';
const selector = createMemoizedSelector(
[activeTabNameSelector, stateSelector, isStagingSelector],
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
index aa98470dca..d1423730f9 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
@@ -10,10 +10,11 @@ import {
MAX_CANVAS_SCALE,
MIN_CANVAS_SCALE,
} from 'features/canvas/util/constants';
-import Konva from 'konva';
-import { KonvaEventObject } from 'konva/lib/Node';
+import type Konva from 'konva';
+import type { KonvaEventObject } from 'konva/lib/Node';
import { clamp } from 'lodash-es';
-import { MutableRefObject, useCallback } from 'react';
+import type { MutableRefObject } from 'react';
+import { useCallback } from 'react';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
const { isMoveStageKeyHeld, stageScale } = canvas;
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
index 9227dcc22d..a61e866883 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
@@ -1,5 +1,4 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import Konva from 'konva';
import {
commitColorPickerColor,
setColorPickerColor,
@@ -8,6 +7,7 @@ import {
getCanvasBaseLayer,
getCanvasStage,
} from 'features/canvas/util/konvaInstanceProvider';
+import Konva from 'konva';
const useColorPicker = () => {
const dispatch = useAppDispatch();
diff --git a/invokeai/frontend/web/src/features/canvas/store/actions.ts b/invokeai/frontend/web/src/features/canvas/store/actions.ts
index 7bf5ec3241..058f853192 100644
--- a/invokeai/frontend/web/src/features/canvas/store/actions.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/actions.ts
@@ -1,5 +1,5 @@
import { createAction } from '@reduxjs/toolkit';
-import { ImageDTO } from 'services/api/types';
+import type { ImageDTO } from 'services/api/types';
export const canvasSavedToGallery = createAction('canvas/canvasSavedToGallery');
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
index 1990f28516..aa536be2e2 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
@@ -1,4 +1,4 @@
-import { CanvasState } from './canvasTypes';
+import type { CanvasState } from './canvasTypes';
/**
* Canvas slice persist denylist
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts
index 70adcb72ec..3f913233ad 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts
@@ -1,6 +1,9 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
-import { RootState, stateSelector } from 'app/store/store';
-import { CanvasImage, isCanvasBaseImage } from './canvasTypes';
+import type { RootState } from 'app/store/store';
+import { stateSelector } from 'app/store/store';
+
+import type { CanvasImage } from './canvasTypes';
+import { isCanvasBaseImage } from './canvasTypes';
export const isStagingSelector = createMemoizedSelector(
[stateSelector],
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
index 3dfe18b7d2..2cdff33a69 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
@@ -4,19 +4,23 @@ import {
roundDownToMultiple,
roundToMultiple,
} from 'common/util/roundDownToMultiple';
-import { setAspectRatio } from 'features/parameters/store/generationSlice';
-import { IRect, Vector2d } from 'konva/lib/types';
-import { clamp, cloneDeep } from 'lodash-es';
-import { RgbaColor } from 'react-colorful';
-import { ImageDTO } from 'services/api/types';
import calculateCoordinates from 'features/canvas/util/calculateCoordinates';
import calculateScale from 'features/canvas/util/calculateScale';
import { STAGE_PADDING_PERCENTAGE } from 'features/canvas/util/constants';
import floorCoordinates from 'features/canvas/util/floorCoordinates';
import getScaledBoundingBoxDimensions from 'features/canvas/util/getScaledBoundingBoxDimensions';
import roundDimensionsTo64 from 'features/canvas/util/roundDimensionsTo64';
-import {
- BoundingBoxScale,
+import { ASPECT_RATIO_MAP } from 'features/parameters/components/ImageSize/constants';
+import { aspectRatioSelected } from 'features/parameters/store/generationSlice';
+import type { IRect, Vector2d } from 'konva/lib/types';
+import { clamp, cloneDeep } from 'lodash-es';
+import type { RgbaColor } from 'react-colorful';
+import { queueApi } from 'services/api/endpoints/queue';
+import type { ImageDTO } from 'services/api/types';
+import { appSocketQueueItemStatusChanged } from 'services/events/actions';
+
+import type {
+ BoundingBoxScaleMethod,
CanvasBaseLine,
CanvasImage,
CanvasLayer,
@@ -25,12 +29,12 @@ import {
CanvasState,
CanvasTool,
Dimensions,
+} from './canvasTypes';
+import {
isCanvasAnyLine,
isCanvasBaseImage,
isCanvasMaskLine,
} from './canvasTypes';
-import { appSocketQueueItemStatusChanged } from 'services/events/actions';
-import { queueApi } from 'services/api/endpoints/queue';
export const initialLayerState: CanvasLayerState = {
objects: [],
@@ -714,7 +718,7 @@ export const canvasSlice = createSlice({
},
setBoundingBoxScaleMethod: (
state,
- action: PayloadAction
+ action: PayloadAction
) => {
state.boundingBoxScaleMethod = action.payload;
@@ -800,15 +804,17 @@ export const canvasSlice = createSlice({
);
}
});
- builder.addCase(setAspectRatio, (state, action) => {
- const ratio = action.payload;
- if (ratio) {
+ builder.addCase(aspectRatioSelected, (state, action) => {
+ const aspectRatioID = action.payload;
+ if (aspectRatioID !== 'Free') {
state.boundingBoxDimensions.height = roundToMultiple(
- state.boundingBoxDimensions.width / ratio,
+ state.boundingBoxDimensions.width /
+ ASPECT_RATIO_MAP[aspectRatioID].ratio,
64
);
state.scaledBoundingBoxDimensions.height = roundToMultiple(
- state.scaledBoundingBoxDimensions.width / ratio,
+ state.scaledBoundingBoxDimensions.width /
+ ASPECT_RATIO_MAP[aspectRatioID].ratio,
64
);
}
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
index 875157d36a..a4efd796df 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
@@ -1,24 +1,21 @@
-import { IRect, Vector2d } from 'konva/lib/types';
-import { RgbaColor } from 'react-colorful';
+import type { IRect, Vector2d } from 'konva/lib/types';
+import type { RgbaColor } from 'react-colorful';
+import { z } from 'zod';
-export const LAYER_NAMES_DICT = [
+export type CanvasLayer = 'base' | 'mask';
+
+export const LAYER_NAMES_DICT: { label: string; value: CanvasLayer }[] = [
{ label: 'Base', value: 'base' },
{ label: 'Mask', value: 'mask' },
];
export const LAYER_NAMES = ['base', 'mask'] as const;
-export type CanvasLayer = (typeof LAYER_NAMES)[number];
-
-export const BOUNDING_BOX_SCALES_DICT = [
- { label: 'None', value: 'none' },
- { label: 'Auto', value: 'auto' },
- { label: 'Manual', value: 'manual' },
-];
-
-export const BOUNDING_BOX_SCALES = ['none', 'auto', 'manual'] as const;
-
-export type BoundingBoxScale = (typeof BOUNDING_BOX_SCALES)[number];
+export const zBoundingBoxScaleMethod = z.enum(['none', 'auto', 'manual']);
+export type BoundingBoxScaleMethod = z.infer;
+export const isBoundingBoxScaleMethod = (
+ v: unknown
+): v is BoundingBoxScaleMethod => zBoundingBoxScaleMethod.safeParse(v).success;
export type CanvasDrawingTool = 'brush' | 'eraser';
@@ -122,7 +119,7 @@ export interface CanvasState {
boundingBoxCoordinates: Vector2d;
boundingBoxDimensions: Dimensions;
boundingBoxPreviewFill: RgbaColor;
- boundingBoxScaleMethod: BoundingBoxScale;
+ boundingBoxScaleMethod: BoundingBoxScaleMethod;
brushColor: RgbaColor;
brushSize: number;
colorPickerColor: RgbaColor;
diff --git a/invokeai/frontend/web/src/features/canvas/util/calculateCoordinates.ts b/invokeai/frontend/web/src/features/canvas/util/calculateCoordinates.ts
index f9af8b3df8..e6c935c95b 100644
--- a/invokeai/frontend/web/src/features/canvas/util/calculateCoordinates.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/calculateCoordinates.ts
@@ -1,4 +1,4 @@
-import { Vector2d } from 'konva/lib/types';
+import type { Vector2d } from 'konva/lib/types';
const calculateCoordinates = (
containerWidth: number,
diff --git a/invokeai/frontend/web/src/features/canvas/util/colorToString.ts b/invokeai/frontend/web/src/features/canvas/util/colorToString.ts
index 8d503f4cd1..378448dd3f 100644
--- a/invokeai/frontend/web/src/features/canvas/util/colorToString.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/colorToString.ts
@@ -1,4 +1,4 @@
-import { RgbaColor, RgbColor } from 'react-colorful';
+import type { RgbaColor, RgbColor } from 'react-colorful';
export const rgbaColorToString = (color: RgbaColor): string => {
const { r, g, b, a } = color;
diff --git a/invokeai/frontend/web/src/features/canvas/util/createMaskStage.ts b/invokeai/frontend/web/src/features/canvas/util/createMaskStage.ts
index b417b3a786..4a7ceb5d50 100644
--- a/invokeai/frontend/web/src/features/canvas/util/createMaskStage.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/createMaskStage.ts
@@ -1,6 +1,6 @@
-import { CanvasMaskLine } from 'features/canvas/store/canvasTypes';
+import type { CanvasMaskLine } from 'features/canvas/store/canvasTypes';
import Konva from 'konva';
-import { IRect } from 'konva/lib/types';
+import type { IRect } from 'konva/lib/types';
/**
* Creates a stage from array of mask objects.
diff --git a/invokeai/frontend/web/src/features/canvas/util/floorCoordinates.ts b/invokeai/frontend/web/src/features/canvas/util/floorCoordinates.ts
index aa3c96ddb1..4908868332 100644
--- a/invokeai/frontend/web/src/features/canvas/util/floorCoordinates.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/floorCoordinates.ts
@@ -1,4 +1,4 @@
-import { Vector2d } from 'konva/lib/types';
+import type { Vector2d } from 'konva/lib/types';
const floorCoordinates = (coord: Vector2d): Vector2d => {
return {
diff --git a/invokeai/frontend/web/src/features/canvas/util/getBaseLayerBlob.ts b/invokeai/frontend/web/src/features/canvas/util/getBaseLayerBlob.ts
index b67789e07e..047d74d380 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getBaseLayerBlob.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getBaseLayerBlob.ts
@@ -1,4 +1,5 @@
-import { RootState } from 'app/store/store';
+import type { RootState } from 'app/store/store';
+
import { getCanvasBaseLayer } from './konvaInstanceProvider';
import { konvaNodeToBlob } from './konvaNodeToBlob';
diff --git a/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts b/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts
index 949e7b653a..c23d2f9429 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts
@@ -1,10 +1,11 @@
import { logger } from 'app/logging/logger';
-import { Vector2d } from 'konva/lib/types';
-import {
+import type {
CanvasLayerState,
Dimensions,
- isCanvasMaskLine,
} from 'features/canvas/store/canvasTypes';
+import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
+import type { Vector2d } from 'konva/lib/types';
+
import createMaskStage from './createMaskStage';
import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider';
import { konvaNodeToBlob } from './konvaNodeToBlob';
diff --git a/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts b/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts
index b128dbe216..aa3b586869 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts
@@ -2,7 +2,7 @@ import {
areAnyPixelsBlack,
getImageDataTransparency,
} from 'common/util/arrayBuffer';
-import { GenerationMode } from 'features/canvas/store/canvasTypes';
+import type { GenerationMode } from 'features/canvas/store/canvasTypes';
export const getCanvasGenerationMode = (
baseImageData: ImageData,
diff --git a/invokeai/frontend/web/src/features/canvas/util/getScaledBoundingBoxDimensions.ts b/invokeai/frontend/web/src/features/canvas/util/getScaledBoundingBoxDimensions.ts
index 61f896b844..67816ceb5c 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getScaledBoundingBoxDimensions.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getScaledBoundingBoxDimensions.ts
@@ -1,5 +1,5 @@
import { roundToMultiple } from 'common/util/roundDownToMultiple';
-import { Dimensions } from 'features/canvas/store/canvasTypes';
+import type { Dimensions } from 'features/canvas/store/canvasTypes';
const getScaledBoundingBoxDimensions = (dimensions: Dimensions) => {
const { width, height } = dimensions;
diff --git a/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts b/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
index 4cfd7dc8f1..1250f66d52 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
@@ -1,4 +1,4 @@
-import { Stage } from 'konva/lib/Stage';
+import type { Stage } from 'konva/lib/Stage';
const getScaledCursorPosition = (stage: Stage) => {
const pointerPosition = stage.getPointerPosition();
diff --git a/invokeai/frontend/web/src/features/canvas/util/konvaInstanceProvider.ts b/invokeai/frontend/web/src/features/canvas/util/konvaInstanceProvider.ts
index 4a36fb72ac..350f23b2c7 100644
--- a/invokeai/frontend/web/src/features/canvas/util/konvaInstanceProvider.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/konvaInstanceProvider.ts
@@ -1,4 +1,4 @@
-import Konva from 'konva';
+import type Konva from 'konva';
let canvasBaseLayer: Konva.Layer | null = null;
let canvasStage: Konva.Stage | null = null;
diff --git a/invokeai/frontend/web/src/features/canvas/util/konvaNodeToBlob.ts b/invokeai/frontend/web/src/features/canvas/util/konvaNodeToBlob.ts
index 8e47398764..40b9768e5a 100644
--- a/invokeai/frontend/web/src/features/canvas/util/konvaNodeToBlob.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/konvaNodeToBlob.ts
@@ -1,5 +1,6 @@
-import Konva from 'konva';
-import { IRect } from 'konva/lib/types';
+import type Konva from 'konva';
+import type { IRect } from 'konva/lib/types';
+
import { canvasToBlob } from './canvasToBlob';
/**
diff --git a/invokeai/frontend/web/src/features/canvas/util/konvaNodeToImageData.ts b/invokeai/frontend/web/src/features/canvas/util/konvaNodeToImageData.ts
index b8337a0cc0..e3c3c008fa 100644
--- a/invokeai/frontend/web/src/features/canvas/util/konvaNodeToImageData.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/konvaNodeToImageData.ts
@@ -1,5 +1,6 @@
-import Konva from 'konva';
-import { IRect } from 'konva/lib/types';
+import type Konva from 'konva';
+import type { IRect } from 'konva/lib/types';
+
import { dataURLToImageData } from './dataURLToImageData';
/**
diff --git a/invokeai/frontend/web/src/features/canvas/util/roundDimensionsTo64.ts b/invokeai/frontend/web/src/features/canvas/util/roundDimensionsTo64.ts
index 706e7fa255..51d8cd7d70 100644
--- a/invokeai/frontend/web/src/features/canvas/util/roundDimensionsTo64.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/roundDimensionsTo64.ts
@@ -1,5 +1,5 @@
import { roundToMultiple } from 'common/util/roundDownToMultiple';
-import { Dimensions } from 'features/canvas/store/canvasTypes';
+import type { Dimensions } from 'features/canvas/store/canvasTypes';
const roundDimensionsTo64 = (dimensions: Dimensions): Dimensions => {
return {
diff --git a/invokeai/frontend/web/src/features/changeBoardModal/components/ChangeBoardModal.tsx b/invokeai/frontend/web/src/features/changeBoardModal/components/ChangeBoardModal.tsx
index cb73d25a6f..ededec1ec2 100644
--- a/invokeai/frontend/web/src/features/changeBoardModal/components/ChangeBoardModal.tsx
+++ b/invokeai/frontend/web/src/features/changeBoardModal/components/ChangeBoardModal.tsx
@@ -1,23 +1,20 @@
-import {
- AlertDialog,
- AlertDialogBody,
- AlertDialogContent,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogOverlay,
- Flex,
- Text,
-} from '@chakra-ui/react';
+import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIButton from 'common/components/IAIButton';
-import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
+import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import type {
+ InvSelectOnChange,
+ InvSelectOption,
+} from 'common/components/InvSelect/types';
+import { InvText } from 'common/components/InvText/wrapper';
import {
changeBoardReset,
isModalOpenChanged,
} from 'features/changeBoardModal/store/slice';
-import { memo, useCallback, useMemo, useRef, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import {
@@ -46,20 +43,20 @@ const ChangeBoardModal = () => {
const [removeImagesFromBoard] = useRemoveImagesFromBoardMutation();
const { t } = useTranslation();
- const data = useMemo(() => {
- const data: { label: string; value: string }[] = [
- { label: t('boards.uncategorized'), value: 'none' },
- ];
- (boards ?? []).forEach((board) =>
- data.push({
+ const options = useMemo(() => {
+ return [{ label: t('boards.uncategorized'), value: 'none' }].concat(
+ (boards ?? []).map((board) => ({
label: board.board_name,
value: board.board_id,
- })
+ }))
);
-
- return data;
}, [boards, t]);
+ const value = useMemo(
+ () => options.find((o) => o.value === selectedBoard),
+ [options, selectedBoard]
+ );
+
const handleClose = useCallback(() => {
dispatch(changeBoardReset());
dispatch(isModalOpenChanged(false));
@@ -88,56 +85,41 @@ const ChangeBoardModal = () => {
selectedBoard,
]);
- const handleSetSelectedBoard = useCallback(
- (v: string | null) => setSelectedBoard(v),
- []
- );
-
- const cancelRef = useRef(null);
+ const onChange = useCallback((v) => {
+ if (!v) {
+ return;
+ }
+ setSelectedBoard(v.value);
+ }, []);
return (
-
-
-
-
- {t('boards.changeBoard')}
-
-
-
-
-
- {t('boards.movingImagesToBoard', {
- count: imagesToChange.length,
- })}
- :
-
-
-
-
-
-
- {t('boards.cancel')}
-
-
- {t('boards.move')}
-
-
-
-
-
+
+
+ {t('boards.movingImagesToBoard', {
+ count: imagesToChange.length,
+ })}
+ :
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/changeBoardModal/store/initialState.ts b/invokeai/frontend/web/src/features/changeBoardModal/store/initialState.ts
index d737d0cdcd..e129c6f76f 100644
--- a/invokeai/frontend/web/src/features/changeBoardModal/store/initialState.ts
+++ b/invokeai/frontend/web/src/features/changeBoardModal/store/initialState.ts
@@ -1,4 +1,4 @@
-import { ChangeBoardModalState } from './types';
+import type { ChangeBoardModalState } from './types';
export const initialState: ChangeBoardModalState = {
isModalOpen: false,
diff --git a/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts b/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts
index 9855e2d7dd..dde72b263d 100644
--- a/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts
+++ b/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts
@@ -1,5 +1,7 @@
-import { PayloadAction, createSlice } from '@reduxjs/toolkit';
-import { ImageDTO } from 'services/api/types';
+import type { PayloadAction } from '@reduxjs/toolkit';
+import { createSlice } from '@reduxjs/toolkit';
+import type { ImageDTO } from 'services/api/types';
+
import { initialState } from './initialState';
const changeBoardModal = createSlice({
diff --git a/invokeai/frontend/web/src/features/changeBoardModal/store/types.ts b/invokeai/frontend/web/src/features/changeBoardModal/store/types.ts
index 6ce13331d0..f1a825480e 100644
--- a/invokeai/frontend/web/src/features/changeBoardModal/store/types.ts
+++ b/invokeai/frontend/web/src/features/changeBoardModal/store/types.ts
@@ -1,4 +1,4 @@
-import { ImageDTO } from 'services/api/types';
+import type { ImageDTO } from 'services/api/types';
export type ChangeBoardModalState = {
isModalOpen: boolean;
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx
index 278f03fef1..f61ff6f567 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx
@@ -1,30 +1,33 @@
+import { ChevronUpIcon } from '@chakra-ui/icons';
import { Box, Flex } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { FaCopy, FaTrash } from 'react-icons/fa';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
+import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
+import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
import {
controlAdapterDuplicated,
controlAdapterIsEnabledChanged,
controlAdapterRemoved,
} from 'features/controlAdapters/store/controlAdaptersSlice';
-import ParamControlAdapterModel from './parameters/ParamControlAdapterModel';
-import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
-import { ChevronUpIcon } from '@chakra-ui/icons';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAISwitch from 'common/components/IAISwitch';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
+import { FaCopy, FaTrash } from 'react-icons/fa';
import { useToggle } from 'react-use';
-import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
-import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
+
import ControlAdapterImagePreview from './ControlAdapterImagePreview';
import ControlAdapterProcessorComponent from './ControlAdapterProcessorComponent';
import ControlAdapterShouldAutoConfig from './ControlAdapterShouldAutoConfig';
import ControlNetCanvasImageImports from './imports/ControlNetCanvasImageImports';
-import ParamControlAdapterBeginEnd from './parameters/ParamControlAdapterBeginEnd';
+import { ParamControlAdapterBeginEnd } from './parameters/ParamControlAdapterBeginEnd';
import ParamControlAdapterControlMode from './parameters/ParamControlAdapterControlMode';
+import ParamControlAdapterModel from './parameters/ParamControlAdapterModel';
import ParamControlAdapterProcessorSelect from './parameters/ParamControlAdapterProcessorSelect';
import ParamControlAdapterResizeMode from './parameters/ParamControlAdapterResizeMode';
+import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
const ControlAdapterConfig = (props: { id: string; number: number }) => {
const { id, number } = props;
@@ -68,23 +71,19 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => {
p: 2,
borderRadius: 'base',
position: 'relative',
- bg: 'base.250',
- _dark: {
- bg: 'base.750',
- },
+ bg: 'base.750',
}}
>
-
+
+
+
{
{activeTabName === 'unifiedCanvas' && (
)}
- }
/>
- {
onClick={handleDelete}
icon={}
/>
- {
}
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
index 174170d3c7..67034399ba 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
@@ -10,11 +10,14 @@ import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/us
import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage';
import { useControlAdapterProcessorType } from 'features/controlAdapters/hooks/useControlAdapterProcessorType';
import { controlAdapterImageChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import {
+import type {
TypesafeDraggableData,
TypesafeDroppableData,
} from 'features/dnd/types';
-import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
+import {
+ heightChanged,
+ widthChanged,
+} from 'features/parameters/store/generationSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -25,7 +28,7 @@ import {
useGetImageDTOQuery,
useRemoveImageFromBoardMutation,
} from 'services/api/endpoints/images';
-import { PostUploadAction } from 'services/api/types';
+import type { PostUploadAction } from 'services/api/types';
type Props = {
id: string;
@@ -115,8 +118,8 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
})
);
} else {
- dispatch(setWidth(controlImage.width));
- dispatch(setHeight(controlImage.height));
+ dispatch(widthChanged(controlImage.width));
+ dispatch(heightChanged(controlImage.height));
}
}, [controlImage, activeTabName, dispatch]);
@@ -243,16 +246,10 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
justifyContent: 'center',
opacity: 0.8,
borderRadius: 'base',
- bg: 'base.400',
- _dark: {
- bg: 'base.900',
- },
+ bg: 'base.900',
}}
>
-
+
)}
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx
index 64684f74ee..79ef4c0a0a 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx
@@ -1,4 +1,7 @@
+import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
+import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
import { memo } from 'react';
+
import CannyProcessor from './processors/CannyProcessor';
import ColorMapProcessor from './processors/ColorMapProcessor';
import ContentShuffleProcessor from './processors/ContentShuffleProcessor';
@@ -12,8 +15,6 @@ import NormalBaeProcessor from './processors/NormalBaeProcessor';
import OpenposeProcessor from './processors/OpenposeProcessor';
import PidiProcessor from './processors/PidiProcessor';
import ZoeDepthProcessor from './processors/ZoeDepthProcessor';
-import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
-import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
export type Props = {
id: string;
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx
index 2c6b36850c..12c1fa01ae 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterShouldAutoConfig.tsx
@@ -1,11 +1,12 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import IAISwitch from 'common/components/IAISwitch';
-import { controlAdapterAutoConfigToggled } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterShouldAutoConfig } from 'features/controlAdapters/hooks/useControlAdapterShouldAutoConfig';
+import { controlAdapterAutoConfigToggled } from 'features/controlAdapters/store/controlAdaptersSlice';
import { isNil } from 'lodash-es';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
type Props = {
id: string;
@@ -26,13 +27,12 @@ const ControlAdapterShouldAutoConfig = ({ id }: Props) => {
}
return (
-
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/hooks/useProcessorNodeChanged.ts b/invokeai/frontend/web/src/features/controlAdapters/components/hooks/useProcessorNodeChanged.ts
index 80cde897a2..d76717cbf3 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/hooks/useProcessorNodeChanged.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/hooks/useProcessorNodeChanged.ts
@@ -1,6 +1,6 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { controlAdapterProcessorParamsChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { ControlAdapterProcessorNode } from 'features/controlAdapters/store/types';
+import type { ControlAdapterProcessorNode } from 'features/controlAdapters/store/types';
import { useCallback } from 'react';
export const useProcessorNodeChanged = () => {
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/imports/ControlNetCanvasImageImports.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/imports/ControlNetCanvasImageImports.tsx
index a822406d3f..41e1ec35c5 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/imports/ControlNetCanvasImageImports.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/imports/ControlNetCanvasImageImports.tsx
@@ -1,13 +1,13 @@
import { Flex } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import {
canvasImageToControlAdapter,
canvasMaskToControlAdapter,
} from 'features/canvas/store/actions';
import { memo, useCallback } from 'react';
-import { FaImage, FaMask } from 'react-icons/fa';
import { useTranslation } from 'react-i18next';
+import { FaImage, FaMask } from 'react-icons/fa';
type ControlNetCanvasImageImportsProps = {
id: string;
@@ -34,14 +34,14 @@ const ControlNetCanvasImageImports = (
gap: 2,
}}
>
- }
tooltip={t('controlnet.importImageFromCanvas')}
aria-label={t('controlnet.importImageFromCanvas')}
onClick={handleImportImageFromCanvas}
/>
- }
tooltip={t('controlnet.importMaskFromCanvas')}
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx
index eada86609e..8b870b891b 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx
@@ -1,16 +1,6 @@
-import {
- FormControl,
- FormLabel,
- HStack,
- RangeSlider,
- RangeSliderFilledTrack,
- RangeSliderMark,
- RangeSliderThumb,
- RangeSliderTrack,
- Tooltip,
-} from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvRangeSlider } from 'common/components/InvRangeSlider/InvRangeSlider';
import { useControlAdapterBeginEndStepPct } from 'features/controlAdapters/hooks/useControlAdapterBeginEndStepPct';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import {
@@ -26,98 +16,69 @@ type Props = {
const formatPct = (v: number) => `${Math.round(v * 100)}%`;
-const ParamControlAdapterBeginEnd = ({ id }: Props) => {
+export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
const isEnabled = useControlAdapterIsEnabled(id);
const stepPcts = useControlAdapterBeginEndStepPct(id);
const dispatch = useAppDispatch();
const { t } = useTranslation();
- const handleStepPctChanged = useCallback(
- (v: number[]) => {
+ const onChange = useCallback(
+ (v: [number, number]) => {
dispatch(
controlAdapterBeginStepPctChanged({
id,
- beginStepPct: v[0] as number,
+ beginStepPct: v[0],
})
);
dispatch(
controlAdapterEndStepPctChanged({
id,
- endStepPct: v[1] as number,
+ endStepPct: v[1],
})
);
},
[dispatch, id]
);
+ const onReset = useCallback(() => {
+ dispatch(
+ controlAdapterBeginStepPctChanged({
+ id,
+ beginStepPct: 0,
+ })
+ );
+ dispatch(
+ controlAdapterEndStepPctChanged({
+ id,
+ endStepPct: 1,
+ })
+ );
+ }, [dispatch, id]);
+
if (!stepPcts) {
return null;
}
return (
-
-
- {t('controlnet.beginEndStepPercent')}
-
-
-
-
-
-
-
-
-
-
-
-
- 0%
-
-
- 50%
-
-
- 100%
-
-
-
-
-
+
+
+
);
-};
+});
-export default memo(ParamControlAdapterBeginEnd);
+ParamControlAdapterBeginEnd.displayName = 'ParamControlAdapterBeginEnd';
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterControlMode.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterControlMode.tsx
index b1099f30c0..2ca1b3630b 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterControlMode.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterControlMode.tsx
@@ -1,11 +1,12 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
-import IAIMantineSelect from 'common/components/IAIMantineSelect';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import type { InvSelectOnChange } from 'common/components/InvSelect/types';
import { useControlAdapterControlMode } from 'features/controlAdapters/hooks/useControlAdapterControlMode';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { controlAdapterControlModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { ControlMode } from 'features/controlAdapters/store/types';
-import { useCallback } from 'react';
+import type { ControlMode } from 'features/controlAdapters/store/types';
+import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type Props = {
@@ -18,33 +19,51 @@ export default function ParamControlAdapterControlMode({ id }: Props) {
const dispatch = useAppDispatch();
const { t } = useTranslation();
- const CONTROL_MODE_DATA = [
- { label: t('controlnet.balanced'), value: 'balanced' },
- { label: t('controlnet.prompt'), value: 'more_prompt' },
- { label: t('controlnet.control'), value: 'more_control' },
- { label: t('controlnet.megaControl'), value: 'unbalanced' },
- ];
+ const CONTROL_MODE_DATA = useMemo(
+ () => [
+ { label: t('controlnet.balanced'), value: 'balanced' },
+ { label: t('controlnet.prompt'), value: 'more_prompt' },
+ { label: t('controlnet.control'), value: 'more_control' },
+ { label: t('controlnet.megaControl'), value: 'unbalanced' },
+ ],
+ [t]
+ );
- const handleControlModeChange = useCallback(
- (controlMode: ControlMode) => {
- dispatch(controlAdapterControlModeChanged({ id, controlMode }));
+ const handleControlModeChange = useCallback(
+ (v) => {
+ if (!v) {
+ return;
+ }
+ dispatch(
+ controlAdapterControlModeChanged({
+ id,
+ controlMode: v.value as ControlMode,
+ })
+ );
},
[id, dispatch]
);
+ const value = useMemo(
+ () => CONTROL_MODE_DATA.filter((o) => o.value === controlMode)[0],
+ [CONTROL_MODE_DATA, controlMode]
+ );
+
if (!controlMode) {
return null;
}
return (
-
-
+
-
+
);
}
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx
index a5c0b26479..21e2b25764 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterModel.tsx
@@ -1,17 +1,23 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
-import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import { useGroupedModelInvSelect } from 'common/components/InvSelect/useGroupedModelInvSelect';
+import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterModel } from 'features/controlAdapters/hooks/useControlAdapterModel';
-import { useControlAdapterModels } from 'features/controlAdapters/hooks/useControlAdapterModels';
+import { useControlAdapterModelEntities } from 'features/controlAdapters/hooks/useControlAdapterModelEntities';
import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
import { controlAdapterModelChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
-import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
-import { memo, useCallback, useMemo } from 'react';
+import { pick } from 'lodash-es';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
+import type {
+ ControlNetModelConfigEntity,
+ IPAdapterModelConfigEntity,
+ T2IAdapterModelConfigEntity,
+} from 'services/api/endpoints/models';
type ParamControlAdapterModelProps = {
id: string;
@@ -31,88 +37,54 @@ const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
const { mainModel } = useAppSelector(selector);
const { t } = useTranslation();
- const models = useControlAdapterModels(controlAdapterType);
+ const models = useControlAdapterModelEntities(controlAdapterType);
- const data = useMemo(() => {
- if (!models) {
- return [];
- }
-
- const data: {
- value: string;
- label: string;
- group: string;
- disabled: boolean;
- tooltip?: string;
- }[] = [];
-
- models.forEach((model) => {
+ const _onChange = useCallback(
+ (
+ model:
+ | ControlNetModelConfigEntity
+ | IPAdapterModelConfigEntity
+ | T2IAdapterModelConfigEntity
+ | null
+ ) => {
if (!model) {
return;
}
-
- const disabled = model?.base_model !== mainModel?.base_model;
-
- data.push({
- value: model.id,
- label: model.model_name,
- group: MODEL_TYPE_MAP[model.base_model],
- disabled,
- tooltip: disabled
- ? `${t('controlnet.incompatibleBaseModel')} ${model.base_model}`
- : undefined,
- });
- });
-
- data.sort((a, b) =>
- // sort 'none' to the top
- a.disabled ? 1 : b.disabled ? -1 : a.label.localeCompare(b.label)
- );
-
- return data;
- }, [mainModel?.base_model, models, t]);
-
- // grab the full model entity from the RTK Query cache
- const selectedModel = useMemo(
- () =>
- models.find(
- (m) =>
- m?.id ===
- `${model?.base_model}/${controlAdapterType}/${model?.model_name}`
- ),
- [controlAdapterType, model?.base_model, model?.model_name, models]
- );
-
- const handleModelChanged = useCallback(
- (v: string | null) => {
- if (!v) {
- return;
- }
-
- const newControlNetModel = modelIdToControlNetModelParam(v);
-
- if (!newControlNetModel) {
- return;
- }
-
- dispatch(controlAdapterModelChanged({ id, model: newControlNetModel }));
+ dispatch(
+ controlAdapterModelChanged({
+ id,
+ model: pick(model, 'base_model', 'model_name'),
+ })
+ );
},
[dispatch, id]
);
+ const { options, value, onChange, noOptionsMessage } =
+ useGroupedModelInvSelect({
+ modelEntities: models,
+ onChange: _onChange,
+ selectedModel:
+ model && controlAdapterType
+ ? { ...model, model_type: controlAdapterType }
+ : null,
+ });
+
return (
-
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterProcessorSelect.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterProcessorSelect.tsx
index bb89b329a1..a31c25bfbf 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterProcessorSelect.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterProcessorSelect.tsx
@@ -1,16 +1,19 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIMantineSearchableSelect, {
- IAISelectDataType,
-} from 'common/components/IAIMantineSearchableSelect';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import type {
+ InvSelectOnChange,
+ InvSelectOption,
+} from 'common/components/InvSelect/types';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
import { controlAdapterProcessortTypeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
+import type { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
import { configSelector } from 'features/system/store/configSelectors';
import { map } from 'lodash-es';
-import { memo, useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type Props = {
@@ -18,13 +21,10 @@ type Props = {
};
const selector = createMemoizedSelector(configSelector, (config) => {
- const controlNetProcessors: IAISelectDataType[] = map(
- CONTROLNET_PROCESSORS,
- (p) => ({
- value: p.type,
- label: p.label,
- })
- )
+ const options: InvSelectOption[] = map(CONTROLNET_PROCESSORS, (p) => ({
+ value: p.type,
+ label: p.label,
+ }))
.sort((a, b) =>
// sort 'none' to the top
a.value === 'none'
@@ -40,40 +40,42 @@ const selector = createMemoizedSelector(configSelector, (config) => {
)
);
- return controlNetProcessors;
+ return options;
});
const ParamControlAdapterProcessorSelect = ({ id }: Props) => {
const isEnabled = useControlAdapterIsEnabled(id);
const processorNode = useControlAdapterProcessorNode(id);
const dispatch = useAppDispatch();
- const controlNetProcessors = useAppSelector(selector);
+ const options = useAppSelector(selector);
const { t } = useTranslation();
- const handleProcessorTypeChanged = useCallback(
- (v: string | null) => {
+ const onChange = useCallback(
+ (v) => {
+ if (!v) {
+ return;
+ }
dispatch(
controlAdapterProcessortTypeChanged({
id,
- processorType: v as ControlAdapterProcessorType,
+ processorType: v.value as ControlAdapterProcessorType, // TODO: need runtime check...
})
);
},
[id, dispatch]
);
+ const value = useMemo(
+ () => options.find((o) => o.value === processorNode?.type),
+ [options, processorNode]
+ );
if (!processorNode) {
return null;
}
-
return (
-
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterResizeMode.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterResizeMode.tsx
index ad5d25ec28..3bc1a8dd3f 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterResizeMode.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterResizeMode.tsx
@@ -1,11 +1,13 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
-import IAIMantineSelect from 'common/components/IAIMantineSelect';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSelect } from 'common/components/InvSelect/InvSelect';
+import type { InvSelectOnChange } from 'common/components/InvSelect/types';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterResizeMode } from 'features/controlAdapters/hooks/useControlAdapterResizeMode';
import { controlAdapterResizeModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
-import { ResizeMode } from 'features/controlAdapters/store/types';
-import { useCallback } from 'react';
+import type { ResizeMode } from 'features/controlAdapters/store/types';
+import { isResizeMode } from 'features/controlAdapters/store/types';
+import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type Props = {
@@ -18,32 +20,51 @@ export default function ParamControlAdapterResizeMode({ id }: Props) {
const dispatch = useAppDispatch();
const { t } = useTranslation();
- const RESIZE_MODE_DATA = [
- { label: t('controlnet.resize'), value: 'just_resize' },
- { label: t('controlnet.crop'), value: 'crop_resize' },
- { label: t('controlnet.fill'), value: 'fill_resize' },
- ];
+ const options: { label: string; value: ResizeMode }[] = useMemo(
+ () => [
+ { label: t('controlnet.resize'), value: 'just_resize' },
+ { label: t('controlnet.crop'), value: 'crop_resize' },
+ { label: t('controlnet.fill'), value: 'fill_resize' },
+ { label: t('controlnet.resizeSimple'), value: 'just_resize_simple' },
+ ],
+ [t]
+ );
- const handleResizeModeChange = useCallback(
- (resizeMode: ResizeMode) => {
- dispatch(controlAdapterResizeModeChanged({ id, resizeMode }));
+ const handleResizeModeChange = useCallback(
+ (v) => {
+ if (!isResizeMode(v?.value)) {
+ return;
+ }
+ dispatch(
+ controlAdapterResizeModeChanged({
+ id,
+ resizeMode: v.value,
+ })
+ );
},
[id, dispatch]
);
+ const value = useMemo(
+ () => options.find((o) => o.value === resizeMode),
+ [options, resizeMode]
+ );
+
if (!resizeMode) {
return null;
}
return (
-
-
+
-
+
);
}
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx
index 9102a6ad3d..7263990147 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx
@@ -1,6 +1,6 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
import { useControlAdapterWeight } from 'features/controlAdapters/hooks/useControlAdapterWeight';
import { controlAdapterWeightChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
@@ -30,19 +30,20 @@ const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
}
return (
-
-
+
-
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/CannyProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/CannyProcessor.tsx
index 741287987c..70920c95a0 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/CannyProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/CannyProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredCannyImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredCannyImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.canny_image_processor
@@ -49,30 +51,26 @@ const CannyProcessor = (props: CannyProcessorProps) => {
return (
-
-
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ColorMapProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ColorMapProcessor.tsx
index b11cc01470..3b89a5610c 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ColorMapProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ColorMapProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredColorMapImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredColorMapImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.color_map_image_processor
@@ -36,22 +38,22 @@ const ColorMapProcessor = (props: ColorMapProcessorProps) => {
return (
-
+ isDisabled={!isEnabled}
+ >
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ContentShuffleProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ContentShuffleProcessor.tsx
index a5a685ce24..f5aaae5759 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ContentShuffleProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ContentShuffleProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredContentShuffleImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredContentShuffleImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.content_shuffle_image_processor
@@ -88,66 +90,67 @@ const ContentShuffleProcessor = (props: Props) => {
return (
-
-
+
+
+
-
-
-
+ >
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/HedProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/HedProcessor.tsx
index 1c8994fcba..b3c509dbd3 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/HedProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/HedProcessor.tsx
@@ -1,10 +1,13 @@
-import IAISlider from 'common/components/IAISlider';
-import IAISwitch from 'common/components/IAISwitch';
-import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredHedImageProcessorInvocation } from 'features/controlAdapters/store/types';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import type { RequiredHedImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.hed_image_processor
@@ -60,36 +63,37 @@ const HedPreprocessor = (props: HedProcessorProps) => {
return (
-
-
+
+
+
-
+ >
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartAnimeProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartAnimeProcessor.tsx
index d7ae6d361c..387440ebd6 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartAnimeProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartAnimeProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredLineartAnimeImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredLineartAnimeImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.lineart_anime_image_processor
@@ -49,30 +51,34 @@ const LineartAnimeProcessor = (props: Props) => {
return (
-
-
+
+
+
+ >
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartProcessor.tsx
index f8d00c68f3..77ebff4926 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/LineartProcessor.tsx
@@ -1,10 +1,13 @@
-import IAISlider from 'common/components/IAISlider';
-import IAISwitch from 'common/components/IAISwitch';
-import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredLineartImageProcessorInvocation } from 'features/controlAdapters/store/types';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import type { RequiredLineartImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.lineart_image_processor
@@ -57,36 +60,37 @@ const LineartProcessor = (props: LineartProcessorProps) => {
return (
-
-
+
+
+
-
+ >
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MediapipeFaceProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MediapipeFaceProcessor.tsx
index a5979a6eae..c6319407a9 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MediapipeFaceProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MediapipeFaceProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredMediapipeFaceProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredMediapipeFaceProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.mediapipe_face_processor
@@ -45,31 +47,29 @@ const MediapipeFaceProcessor = (props: Props) => {
return (
-
-
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MidasDepthProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MidasDepthProcessor.tsx
index ba5d373478..613fc03a01 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MidasDepthProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MidasDepthProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredMidasDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredMidasDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.midas_depth_image_processor
@@ -45,32 +47,30 @@ const MidasDepthProcessor = (props: Props) => {
return (
-
-
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx
index 6f9d1d415c..37e5e871a7 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredMlsdImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredMlsdImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.mlsd_image_processor
@@ -71,56 +73,58 @@ const MlsdImageProcessor = (props: Props) => {
return (
-
-
+
+
+
-
-
+ >
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/NormalBaeProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/NormalBaeProcessor.tsx
index 2752bf7a30..27167a26f7 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/NormalBaeProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/NormalBaeProcessor.tsx
@@ -1,9 +1,11 @@
-import IAISlider from 'common/components/IAISlider';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredNormalbaeImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredNormalbaeImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.normalbae_image_processor
@@ -49,30 +51,34 @@ const NormalBaeProcessor = (props: Props) => {
return (
-
-
+
+
+
+ >
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/OpenposeProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/OpenposeProcessor.tsx
index 24574941b1..ce74ec80b2 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/OpenposeProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/OpenposeProcessor.tsx
@@ -1,10 +1,13 @@
-import IAISlider from 'common/components/IAISlider';
-import IAISwitch from 'common/components/IAISwitch';
-import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredOpenposeImageProcessorInvocation } from 'features/controlAdapters/store/types';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import type { RequiredOpenposeImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.openpose_image_processor
@@ -57,36 +60,40 @@ const OpenposeProcessor = (props: Props) => {
return (
-
-
+
+
+
-
+ >
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/PidiProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/PidiProcessor.tsx
index e204c7178e..871ade161e 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/PidiProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/PidiProcessor.tsx
@@ -1,10 +1,13 @@
-import IAISlider from 'common/components/IAISlider';
-import IAISwitch from 'common/components/IAISwitch';
-import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
-import { RequiredPidiImageProcessorInvocation } from 'features/controlAdapters/store/types';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSlider } from 'common/components/InvSlider/InvSlider';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
+import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import type { RequiredPidiImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
import ProcessorWrapper from './common/ProcessorWrapper';
const DEFAULTS = CONTROLNET_PROCESSORS.pidi_image_processor
@@ -64,41 +67,40 @@ const PidiProcessor = (props: Props) => {
return (
-
-
+
+
+
-
-
+ >
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ZoeDepthProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ZoeDepthProcessor.tsx
index 7e069e67cb..61897a5d27 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/ZoeDepthProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/ZoeDepthProcessor.tsx
@@ -1,4 +1,4 @@
-import { RequiredZoeDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
+import type { RequiredZoeDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
import { memo } from 'react';
type Props = {
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/common/ProcessorWrapper.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/common/ProcessorWrapper.tsx
index c3e5b2258e..8bfe7afa3d 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/common/ProcessorWrapper.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/common/ProcessorWrapper.tsx
@@ -1,5 +1,5 @@
import { Flex } from '@chakra-ui/react';
-import { PropsWithChildren } from 'react';
+import type { PropsWithChildren } from 'react';
type Props = PropsWithChildren;
diff --git a/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts b/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts
index 7a0a0d655f..42d401c1ab 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/hooks/useAddControlAdapter.ts
@@ -1,7 +1,8 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
+import type { ControlAdapterType } from 'features/controlAdapters/store/types';
import { useCallback, useMemo } from 'react';
-import { ControlAdapterType } from 'features/controlAdapters/store/types';
+
import { useControlAdapterModels } from './useControlAdapterModels';
export const useAddControlAdapter = (type: ControlAdapterType) => {
diff --git a/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModelEntities.ts b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModelEntities.ts
new file mode 100644
index 0000000000..0c8baaacc2
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModelEntities.ts
@@ -0,0 +1,23 @@
+import type { ControlAdapterType } from 'features/controlAdapters/store/types';
+import {
+ useGetControlNetModelsQuery,
+ useGetIPAdapterModelsQuery,
+ useGetT2IAdapterModelsQuery,
+} from 'services/api/endpoints/models';
+
+export const useControlAdapterModelEntities = (type?: ControlAdapterType) => {
+ const { data: controlNetModelsData } = useGetControlNetModelsQuery();
+ const { data: t2iAdapterModelsData } = useGetT2IAdapterModelsQuery();
+ const { data: ipAdapterModelsData } = useGetIPAdapterModelsQuery();
+
+ if (type === 'controlnet') {
+ return controlNetModelsData;
+ }
+ if (type === 't2i_adapter') {
+ return t2iAdapterModelsData;
+ }
+ if (type === 'ip_adapter') {
+ return ipAdapterModelsData;
+ }
+ return;
+};
diff --git a/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModels.ts b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModels.ts
index f6edf6654c..cdd8aad49b 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModels.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/hooks/useControlAdapterModels.ts
@@ -1,3 +1,4 @@
+import type { ControlAdapterType } from 'features/controlAdapters/store/types';
import { useMemo } from 'react';
import {
controlNetModelsAdapter,
@@ -7,7 +8,6 @@ import {
useGetIPAdapterModelsQuery,
useGetT2IAdapterModelsQuery,
} from 'services/api/endpoints/models';
-import { ControlAdapterType } from 'features/controlAdapters/store/types';
export const useControlAdapterModels = (type?: ControlAdapterType) => {
const { data: controlNetModelsData } = useGetControlNetModelsQuery();
diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts
index db2311f3f5..b7647c9f0d 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts
@@ -1,5 +1,6 @@
import i18n from 'i18next';
-import {
+
+import type {
ControlAdapterProcessorType,
RequiredControlAdapterProcessorNode,
} from './types';
diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts
index 69348a9129..0dfd46889f 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts
@@ -1,4 +1,4 @@
-import { ControlAdaptersState } from './types';
+import type { ControlAdaptersState } from './types';
/**
* ControlNet slice persist denylist
diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts
index c46f7a8d7e..d78401507f 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts
@@ -1,11 +1,7 @@
-import {
- PayloadAction,
- Update,
- createEntityAdapter,
- createSlice,
- isAnyOf,
-} from '@reduxjs/toolkit';
-import {
+import type { PayloadAction, Update } from '@reduxjs/toolkit';
+import { createEntityAdapter, createSlice, isAnyOf } from '@reduxjs/toolkit';
+import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter';
+import type {
ParameterControlNetModel,
ParameterIPAdapterModel,
ParameterT2IAdapterModel,
@@ -13,22 +9,24 @@ import {
import { cloneDeep, merge, uniq } from 'lodash-es';
import { appSocketInvocationError } from 'services/events/actions';
import { v4 as uuidv4 } from 'uuid';
-import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter';
+
import { controlAdapterImageProcessed } from './actions';
import {
CONTROLNET_MODEL_DEFAULT_PROCESSORS as CONTROLADAPTER_MODEL_DEFAULT_PROCESSORS,
CONTROLNET_PROCESSORS,
} from './constants';
-import {
+import type {
ControlAdapterConfig,
ControlAdapterProcessorType,
- ControlAdapterType,
ControlAdaptersState,
+ ControlAdapterType,
ControlMode,
ControlNetConfig,
RequiredControlAdapterProcessorNode,
ResizeMode,
T2IAdapterConfig,
+} from './types';
+import {
isControlNet,
isControlNetOrT2IAdapter,
isIPAdapter,
diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts
index 7fe8f4cf25..8d391a9c08 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts
@@ -1,12 +1,12 @@
-import { EntityState } from '@reduxjs/toolkit';
-import {
+import type { EntityState } from '@reduxjs/toolkit';
+import type {
ParameterControlNetModel,
ParameterIPAdapterModel,
ParameterT2IAdapterModel,
} from 'features/parameters/types/parameterSchemas';
import { isObject } from 'lodash-es';
-import { components } from 'services/api/schema';
-import {
+import type { components } from 'services/api/schema';
+import type {
CannyImageProcessorInvocation,
ColorMapImageProcessorInvocation,
ContentShuffleImageProcessorInvocation,
@@ -21,7 +21,8 @@ import {
PidiImageProcessorInvocation,
ZoeDepthImageProcessorInvocation,
} from 'services/api/types';
-import { O } from 'ts-toolbelt';
+import type { O } from 'ts-toolbelt';
+import { z } from 'zod';
/**
* Any ControlNet processor node
@@ -370,9 +371,15 @@ export type ControlMode = NonNullable<
components['schemas']['ControlNetInvocation']['control_mode']
>;
-export type ResizeMode = NonNullable<
- components['schemas']['ControlNetInvocation']['resize_mode']
->;
+export const zResizeMode = z.enum([
+ 'just_resize',
+ 'crop_resize',
+ 'fill_resize',
+ 'just_resize_simple',
+]);
+export type ResizeMode = z.infer;
+export const isResizeMode = (v: unknown): v is ResizeMode =>
+ zResizeMode.safeParse(v).success;
export type ControlNetConfig = {
type: 'controlnet';
diff --git a/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapter.ts b/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapter.ts
index 7133b072ee..fb8a019570 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapter.ts
+++ b/invokeai/frontend/web/src/features/controlAdapters/util/buildControlAdapter.ts
@@ -1,5 +1,5 @@
-import { cloneDeep, merge } from 'lodash-es';
-import {
+import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import type {
ControlAdapterConfig,
ControlAdapterType,
ControlNetConfig,
@@ -7,7 +7,7 @@ import {
RequiredCannyImageProcessorInvocation,
T2IAdapterConfig,
} from 'features/controlAdapters/store/types';
-import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
+import { cloneDeep, merge } from 'lodash-es';
export const initialControlNet: Omit = {
type: 'controlnet',
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageButton.tsx b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageButton.tsx
index 5a98581403..64858b2d2d 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageButton.tsx
+++ b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageButton.tsx
@@ -1,10 +1,10 @@
-import { IconButtonProps } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
+import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
+import type { InvIconButtonProps } from 'common/components/InvIconButton/types';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
-type DeleteImageButtonProps = Omit & {
+type DeleteImageButtonProps = Omit & {
onClick: () => void;
};
@@ -14,7 +14,7 @@ export const DeleteImageButton = (props: DeleteImageButtonProps) => {
const isConnected = useAppSelector((state) => state.system.isConnected);
return (
- }
tooltip={`${t('gallery.deleteImage')} (Del)`}
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx
index c3aa9ed42b..24d35da883 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx
+++ b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx
@@ -1,19 +1,11 @@
-import {
- AlertDialog,
- AlertDialogBody,
- AlertDialogContent,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogOverlay,
- Divider,
- Flex,
- Text,
-} from '@chakra-ui/react';
+import { Divider, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIButton from 'common/components/IAIButton';
-import IAISwitch from 'common/components/IAISwitch';
+import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog';
+import { InvControl } from 'common/components/InvControl/InvControl';
+import { InvSwitch } from 'common/components/InvSwitch/wrapper';
+import { InvText } from 'common/components/InvText/wrapper';
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
import {
getImageUsage,
@@ -23,11 +15,13 @@ import {
imageDeletionCanceled,
isModalOpenChanged,
} from 'features/deleteImageModal/store/slice';
-import { ImageUsage } from 'features/deleteImageModal/store/types';
+import type { ImageUsage } from 'features/deleteImageModal/store/types';
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
import { some } from 'lodash-es';
-import { ChangeEvent, memo, useCallback, useRef } from 'react';
+import type { ChangeEvent } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
+
import ImageUsageMessage from './ImageUsageMessage';
const selector = createMemoizedSelector(
@@ -94,49 +88,32 @@ const DeleteImageModal = () => {
);
}, [dispatch, imagesToDelete, imagesUsage]);
- const cancelRef = useRef(null);
-
return (
-
-
-
-
- {t('gallery.deleteImage')}
-
-
-
-
-
-
-
- {canRestoreDeletedImagesFromBin
- ? t('gallery.deleteImageBin')
- : t('gallery.deleteImagePermanent')}
-
- {t('common.areYouSure')}
-
-
-
-
-
- {t('boards.cancel')}
-
-
- {t('controlnet.delete')}
-
-
-
-
-
+
+
+
+
+ {canRestoreDeletedImagesFromBin
+ ? t('gallery.deleteImageBin')
+ : t('gallery.deleteImagePermanent')}
+
+ {t('common.areYouSure')}
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx b/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx
index 1468384848..14c4ff7dc7 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx
+++ b/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx
@@ -1,8 +1,9 @@
-import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
+import { ListItem, UnorderedList } from '@chakra-ui/react';
+import { InvText } from 'common/components/InvText/wrapper';
+import type { ImageUsage } from 'features/deleteImageModal/store/types';
import { some } from 'lodash-es';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
-import { ImageUsage } from 'features/deleteImageModal/store/types';
type Props = {
imageUsage?: ImageUsage;
@@ -27,7 +28,7 @@ const ImageUsageMessage = (props: Props) => {
return (
<>
- {topMessage}
+ {topMessage}
{imageUsage.isInitialImage && (
{t('common.img2img')}
@@ -42,7 +43,7 @@ const ImageUsageMessage = (props: Props) => {
{t('common.nodeEditor')}
)}
- {bottomMessage}
+ {bottomMessage}
>
);
};
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/actions.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/actions.ts
index def27c9954..7ec2a79bd1 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/store/actions.ts
+++ b/invokeai/frontend/web/src/features/deleteImageModal/store/actions.ts
@@ -1,6 +1,7 @@
import { createAction } from '@reduxjs/toolkit';
-import { ImageDTO } from 'services/api/types';
-import { ImageUsage } from './types';
+import type { ImageDTO } from 'services/api/types';
+
+import type { ImageUsage } from './types';
export const imageDeletionConfirmed = createAction<{
imageDTOs: ImageDTO[];
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/initialState.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/initialState.ts
index 198d4ca51f..112ad6858d 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/store/initialState.ts
+++ b/invokeai/frontend/web/src/features/deleteImageModal/store/initialState.ts
@@ -1,4 +1,4 @@
-import { DeleteImageState } from './types';
+import type { DeleteImageState } from './types';
export const initialDeleteImageState: DeleteImageState = {
imagesToDelete: [],
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts
index 2d9cdeb749..d410e85f41 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts
+++ b/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts
@@ -1,11 +1,12 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
-import { RootState } from 'app/store/store';
+import type { RootState } from 'app/store/store';
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { isImageFieldInputInstance } from 'features/nodes/types/field';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { some } from 'lodash-es';
-import { ImageUsage } from './types';
+
+import type { ImageUsage } from './types';
export const getImageUsage = (state: RootState, image_name: string) => {
const { generation, canvas, nodes, controlAdapters } = state;
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts
index 6569009666..456abb62f3 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts
+++ b/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts
@@ -1,5 +1,7 @@
-import { PayloadAction, createSlice } from '@reduxjs/toolkit';
-import { ImageDTO } from 'services/api/types';
+import type { PayloadAction } from '@reduxjs/toolkit';
+import { createSlice } from '@reduxjs/toolkit';
+import type { ImageDTO } from 'services/api/types';
+
import { initialDeleteImageState } from './initialState';
const deleteImageModal = createSlice({
diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts
index 76e79e2847..cd8f3aa5eb 100644
--- a/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts
+++ b/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts
@@ -1,4 +1,4 @@
-import { ImageDTO } from 'services/api/types';
+import type { ImageDTO } from 'services/api/types';
export type DeleteImageState = {
imagesToDelete: ImageDTO[];
diff --git a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
index 2afb7c435e..3948d5ee66 100644
--- a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
+++ b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
@@ -9,15 +9,17 @@ import { logger } from 'app/logging/logger';
import { dndDropped } from 'app/store/middleware/listenerMiddleware/listeners/imageDropped';
import { useAppDispatch } from 'app/store/storeHooks';
import { parseify } from 'common/util/serialize';
-import { AnimatePresence, motion } from 'framer-motion';
-import { PropsWithChildren, memo, useCallback, useState } from 'react';
import { useScaledModifer } from 'features/dnd/hooks/useScaledCenteredModifer';
-import {
+import type {
DragEndEvent,
DragStartEvent,
TypesafeDraggableData,
} from 'features/dnd/types';
import { customPointerWithin } from 'features/dnd/util/customPointerWithin';
+import { AnimatePresence, motion } from 'framer-motion';
+import type { PropsWithChildren } from 'react';
+import { memo, useCallback, useState } from 'react';
+
import { DndContextTypesafe } from './DndContextTypesafe';
import DragPreview from './DragPreview';
diff --git a/invokeai/frontend/web/src/features/dnd/components/DndContextTypesafe.tsx b/invokeai/frontend/web/src/features/dnd/components/DndContextTypesafe.tsx
index 74a6d00aa9..e278e648a1 100644
--- a/invokeai/frontend/web/src/features/dnd/components/DndContextTypesafe.tsx
+++ b/invokeai/frontend/web/src/features/dnd/components/DndContextTypesafe.tsx
@@ -1,5 +1,5 @@
import { DndContext } from '@dnd-kit/core';
-import { DndContextTypesafeProps } from 'features/dnd/types';
+import type { DndContextTypesafeProps } from 'features/dnd/types';
export function DndContextTypesafe(props: DndContextTypesafeProps) {
return ;
diff --git a/invokeai/frontend/web/src/features/dnd/components/DragPreview.tsx b/invokeai/frontend/web/src/features/dnd/components/DragPreview.tsx
index c9861362d4..22be340aa0 100644
--- a/invokeai/frontend/web/src/features/dnd/components/DragPreview.tsx
+++ b/invokeai/frontend/web/src/features/dnd/components/DragPreview.tsx
@@ -1,6 +1,8 @@
-import { Box, ChakraProps, Flex, Heading, Image, Text } from '@chakra-ui/react';
+import type { ChakraProps } from '@chakra-ui/react';
+import { Box, Flex, Heading, Image } from '@chakra-ui/react';
+import { InvText } from 'common/components/InvText/wrapper';
+import type { TypesafeDraggableData } from 'features/dnd/types';
import { memo } from 'react';
-import { TypesafeDraggableData } from 'features/dnd/types';
import { useTranslation } from 'react-i18next';
type OverlayDragImageProps = {
@@ -17,13 +19,9 @@ const STYLES: ChakraProps['sx'] = {
shadow: 'dark-lg',
borderRadius: 'lg',
opacity: 0.3,
- bg: 'base.800',
- color: 'base.50',
- _dark: {
- borderColor: 'base.200',
- bg: 'base.900',
- color: 'base.100',
- },
+ borderColor: 'base.200',
+ bg: 'base.900',
+ color: 'base.100',
};
const DragPreview = (props: OverlayDragImageProps) => {
@@ -48,7 +46,7 @@ const DragPreview = (props: OverlayDragImageProps) => {
fontSize: 'sm',
}}
>
- {field.label || fieldTemplate.title}
+ {field.label || fieldTemplate.title}