diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js
index 28177d3de1..955d37ef09 100644
--- a/invokeai/frontend/web/.eslintrc.js
+++ b/invokeai/frontend/web/.eslintrc.js
@@ -30,6 +30,8 @@ module.exports = {
'unused-imports',
'simple-import-sort',
'eslint-plugin-import',
+ // These rules are too strict for normal usage, but are useful for optimizing rerenders
+ // '@arthurgeron/react-usememo',
],
root: true,
rules: {
@@ -60,6 +62,18 @@ module.exports = {
argsIgnorePattern: '^_',
},
],
+ // These rules are too strict for normal usage, but are useful for optimizing rerenders
+ // '@arthurgeron/react-usememo/require-usememo': [
+ // 'warn',
+ // {
+ // strict: false,
+ // checkHookReturnObject: false,
+ // fix: { addImports: true },
+ // checkHookCalls: false,
+
+ // },
+ // ],
+ // '@arthurgeron/react-usememo/require-memo': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-empty-interface': [
diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json
index a37556793f..7b9446b2f3 100644
--- a/invokeai/frontend/web/package.json
+++ b/invokeai/frontend/web/package.json
@@ -120,6 +120,7 @@
"ts-toolbelt": "^9.6.0"
},
"devDependencies": {
+ "@arthurgeron/eslint-plugin-react-usememo": "^2.2.1",
"@chakra-ui/cli": "^2.4.1",
"@storybook/addon-docs": "^7.6.6",
"@storybook/addon-essentials": "^7.6.6",
diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml
index abf5f1def9..8997336b36 100644
--- a/invokeai/frontend/web/pnpm-lock.yaml
+++ b/invokeai/frontend/web/pnpm-lock.yaml
@@ -184,6 +184,9 @@ dependencies:
version: 2.1.0(zod@3.22.4)
devDependencies:
+ '@arthurgeron/eslint-plugin-react-usememo':
+ specifier: ^2.2.1
+ version: 2.2.1
'@chakra-ui/cli':
specifier: ^2.4.1
version: 2.4.1
@@ -339,6 +342,13 @@ packages:
'@jridgewell/trace-mapping': 0.3.20
dev: true
+ /@arthurgeron/eslint-plugin-react-usememo@2.2.1:
+ resolution: {integrity: sha512-XMYGogzqQYR7PC4F4ve+loBTrvsE7AHnhiBjUTBMW5hbFecbg6ReTQwj36WsV4vRXNnDRD3vfwkO4fH8WHcOog==}
+ dependencies:
+ minimatch: 9.0.3
+ uuid: 9.0.1
+ dev: true
+
/@aw-web-design/x-default-browser@1.4.126:
resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
hasBin: true
diff --git a/invokeai/frontend/web/src/common/components/InvContextMenu/InvContextMenu.tsx b/invokeai/frontend/web/src/common/components/InvContextMenu/InvContextMenu.tsx
index 43d51f49fc..3e02b9d2d0 100644
--- a/invokeai/frontend/web/src/common/components/InvContextMenu/InvContextMenu.tsx
+++ b/invokeai/frontend/web/src/common/components/InvContextMenu/InvContextMenu.tsx
@@ -12,7 +12,12 @@
* - increment it in `onPaneClick` (and wherever else we want to close the menu)
* - `useEffect()` to close the menu when `globalContextMenuCloseTrigger` changes
*/
-import type { MenuButtonProps, MenuProps, PortalProps } from '@chakra-ui/react';
+import type {
+ ChakraProps,
+ MenuButtonProps,
+ MenuProps,
+ PortalProps,
+} from '@chakra-ui/react';
import { Portal, useEventListener } from '@chakra-ui/react';
import { InvMenu, InvMenuButton } from 'common/components/InvMenu/wrapper';
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
@@ -102,7 +107,7 @@ export const InvContextMenu = typedMemo(
cursor="default"
bg="transparent"
size="sm"
- _hover={{ bg: 'transparent' }}
+ _hover={_hover}
{...props.menuButtonProps}
/>
{props.renderMenu()}
@@ -114,6 +119,8 @@ export const InvContextMenu = typedMemo(
}
);
+const _hover: ChakraProps['_hover'] = { bg: 'transparent' };
+
Object.assign(InvContextMenu, {
displayName: 'InvContextMenu',
});
diff --git a/invokeai/frontend/web/src/common/hooks/useSingleAndDoubleClick.ts b/invokeai/frontend/web/src/common/hooks/useSingleAndDoubleClick.ts
index 804b403f54..f62c2a095b 100644
--- a/invokeai/frontend/web/src/common/hooks/useSingleAndDoubleClick.ts
+++ b/invokeai/frontend/web/src/common/hooks/useSingleAndDoubleClick.ts
@@ -1,5 +1,5 @@
// https://stackoverflow.com/a/73731908
-import { useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
export function useSingleAndDoubleClick(
handleSingleClick: () => void,
@@ -23,5 +23,7 @@ export function useSingleAndDoubleClick(
return () => clearTimeout(timer);
}, [click, handleSingleClick, handleDoubleClick, delay]);
- return () => setClick((prev) => prev + 1);
+ const onClick = useCallback(() => setClick((prev) => prev + 1), []);
+
+ return onClick;
}
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
index 1f6bf151a6..f21c18aee9 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
@@ -175,6 +175,8 @@ const IAICanvas = () => {
[stageCursor]
);
+ const scale= useMemo(()=>({x: stageScale, y: stageScale}),[stageScale])
+
return (
{
y={stageCoordinates.y}
width={stageDimensions.width}
height={stageDimensions.height}
- scale={{ x: stageScale, y: stageScale }}
+ scale={scale}
onTouchStart={handleMouseDown}
onTouchMove={handleMouseMove}
onTouchEnd={handleMouseUp}
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
index 6bde5f14cc..5998a367ac 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
@@ -5,7 +5,7 @@ import { rgbaColorToString } from 'features/canvas/util/colorToString';
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 { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Rect } from 'react-konva';
export const canvasMaskCompositerSelector = createMemoizedSelector(
@@ -147,6 +147,11 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
return () => clearInterval(timer);
}, []);
+ const fillPatternScale = useMemo(
+ () => ({ x: 1 / stageScale, y: 1 / stageScale }),
+ [stageScale]
+ );
+
if (
!fillPatternImage ||
!isNumber(stageCoordinates.x) ||
@@ -168,7 +173,7 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
fillPatternImage={fillPatternImage}
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
fillPatternRepeat="repeat"
- fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
+ fillPatternScale={fillPatternScale}
listening={true}
globalCompositeOperation="source-in"
{...rest}
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
index 1bc34eef8d..e84395ceb8 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
@@ -7,6 +7,8 @@ import { Group, Rect } from 'react-konva';
import IAICanvasImage from './IAICanvasImage';
+const dash = [4, 4]
+
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
const {
layerState,
@@ -69,7 +71,7 @@ const IAICanvasStagingArea = (props: Props) => {
y={y}
width={width}
height={height}
- dash={[4, 4]}
+ dash={dash}
strokeWidth={1}
stroke="black"
strokeScaleEnabled={false}
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 3ec12a5b96..f969d227fe 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
@@ -21,6 +21,8 @@ import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { Group, Rect, Transformer } from 'react-konva';
+const borderDash = [4, 4];
+
const boundingBoxPreviewSelector = createMemoizedSelector(
[stateSelector],
({ canvas, generation }) => {
@@ -289,11 +291,11 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
anchorFill="rgba(212,216,234,1)"
anchorSize={15}
anchorStroke="rgb(42,42,42)"
- borderDash={[4, 4]}
+ borderDash={borderDash}
borderEnabled={true}
borderStroke="black"
draggable={false}
- enabledAnchors={tool === 'move' ? undefined : []}
+ enabledAnchors={tool === 'move' ? undefined : emptyArray}
flipEnabled={false}
ignoreStroke={true}
keepRatio={false}
@@ -311,3 +313,5 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
};
export default memo(IAICanvasBoundingBox);
+
+const emptyArray: string[] = []
\ No newline at end of file
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 e23dfb389c..257abc927f 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
@@ -261,7 +261,7 @@ const IAICanvasToolChooserOptions = () => {
max={100}
step={1}
onChange={handleChangeBrushSize}
- marks={[1, 25, 50, 75, 100]}
+ marks={marks}
/>
{
};
export default memo(IAICanvasToolChooserOptions);
+
+const marks = [1, 25, 50, 75, 100];
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
index a61e866883..bc110464a6 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
@@ -8,50 +8,52 @@ import {
getCanvasStage,
} from 'features/canvas/util/konvaInstanceProvider';
import Konva from 'konva';
+import { useCallback } from 'react';
const useColorPicker = () => {
const dispatch = useAppDispatch();
const canvasBaseLayer = getCanvasBaseLayer();
const stage = getCanvasStage();
- return {
- updateColorUnderCursor: () => {
- if (!stage || !canvasBaseLayer) {
- return;
- }
+ const updateColorUnderCursor = useCallback(() => {
+ if (!stage || !canvasBaseLayer) {
+ return;
+ }
- const position = stage.getPointerPosition();
+ const position = stage.getPointerPosition();
- if (!position) {
- return;
- }
+ if (!position) {
+ return;
+ }
- const pixelRatio = Konva.pixelRatio;
+ const pixelRatio = Konva.pixelRatio;
- const [r, g, b, a] = canvasBaseLayer
- .getContext()
- .getImageData(
- position.x * pixelRatio,
- position.y * pixelRatio,
- 1,
- 1
- ).data;
+ const [r, g, b, a] = canvasBaseLayer
+ .getContext()
+ .getImageData(
+ position.x * pixelRatio,
+ position.y * pixelRatio,
+ 1,
+ 1
+ ).data;
- if (
- r === undefined ||
- g === undefined ||
- b === undefined ||
- a === undefined
- ) {
- return;
- }
+ if (
+ r === undefined ||
+ g === undefined ||
+ b === undefined ||
+ a === undefined
+ ) {
+ return;
+ }
- dispatch(setColorPickerColor({ r, g, b, a }));
- },
- commitColorUnderCursor: () => {
- dispatch(commitColorPickerColor());
- },
- };
+ dispatch(setColorPickerColor({ r, g, b, a }));
+ }, [canvasBaseLayer, dispatch, stage]);
+
+ const commitColorUnderCursor = useCallback(() => {
+ dispatch(commitColorPickerColor());
+ }, [dispatch]);
+
+ return { updateColorUnderCursor, commitColorUnderCursor };
};
export default useColorPicker;
diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
index f6bcf6d587..e76ea174cb 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterImagePreview.tsx
@@ -1,3 +1,4 @@
+import type { SystemStyleObject } from '@chakra-ui/react';
import { Box, Flex, Spinner } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
@@ -220,13 +221,13 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
onClick={handleSaveControlImage}
icon={controlImage ? : undefined}
tooltip={t('controlnet.saveControlImage')}
- styleOverrides={{ marginTop: 6 }}
+ styleOverrides={saveControlImageStyleOverrides}
/>
: undefined}
tooltip={t('controlnet.setControlImageDimensions')}
- styleOverrides={{ marginTop: 12 }}
+ styleOverrides={setControlImageDimensionsStyleOverrides}
/>
>
@@ -251,3 +252,6 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
};
export default memo(ControlAdapterImagePreview);
+
+const saveControlImageStyleOverrides: SystemStyleObject = { mt: 6 };
+const setControlImageDimensionsStyleOverrides: SystemStyleObject = { mt: 12 };
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 e3b002be2a..edf133974a 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterBeginEnd.tsx
@@ -7,7 +7,7 @@ import {
controlAdapterBeginStepPctChanged,
controlAdapterEndStepPctChanged,
} from 'features/controlAdapters/store/controlAdaptersSlice';
-import { memo, useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type Props = {
@@ -55,6 +55,11 @@ export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
);
}, [dispatch, id]);
+ const value = useMemo<[number, number]>(
+ () => [stepPcts?.beginStepPct ?? 0, stepPcts?.endStepPct ?? 1],
+ [stepPcts]
+ );
+
if (!stepPcts) {
return null;
}
@@ -67,8 +72,8 @@ export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
orientation="vertical"
>
{
});
ParamControlAdapterBeginEnd.displayName = 'ParamControlAdapterBeginEnd';
+
+const ariaLabel = ['Begin Step %', 'End Step %'];
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 f5fa3e6920..65b153062e 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/parameters/ParamControlAdapterWeight.tsx
@@ -42,10 +42,12 @@ const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
min={0}
max={2}
step={0.01}
- marks={[0, 1, 2]}
+ marks={marks}
/>
);
};
export default memo(ParamControlAdapterWeight);
+
+const marks = [0, 1, 2];
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 37e5e871a7..1aca1fd37d 100644
--- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx
+++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/MlsdImageProcessor.tsx
@@ -83,7 +83,7 @@ const MlsdImageProcessor = (props: Props) => {
onReset={handleDetectResolutionReset}
min={0}
max={4096}
- marks={[0, 4096]}
+ marks={marks0to4096}
withNumberInput
/>
@@ -97,7 +97,7 @@ const MlsdImageProcessor = (props: Props) => {
onReset={handleImageResolutionReset}
min={0}
max={4096}
- marks={[0, 4096]}
+ marks={marks0to4096}
withNumberInput
/>
@@ -109,7 +109,7 @@ const MlsdImageProcessor = (props: Props) => {
min={0}
max={1}
step={0.01}
- marks={[0, 1]}
+ marks={marks0to1}
withNumberInput
/>
@@ -121,7 +121,7 @@ const MlsdImageProcessor = (props: Props) => {
min={0}
max={1}
step={0.01}
- marks={[0, 1]}
+ marks={marks0to1}
withNumberInput
/>
@@ -130,3 +130,6 @@ const MlsdImageProcessor = (props: Props) => {
};
export default memo(MlsdImageProcessor);
+
+const marks0to4096 = [0, 4096];
+const marks0to1 = [0, 1];
\ No newline at end of file
diff --git a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
index 79514fdc92..5e5dfecbd4 100644
--- a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
+++ b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx
@@ -19,7 +19,7 @@ import { customPointerWithin } from 'features/dnd/util/customPointerWithin';
import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
import type { CSSProperties, PropsWithChildren } from 'react';
-import { memo, useCallback, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { DndContextTypesafe } from './DndContextTypesafe';
import DragPreview from './DragPreview';
@@ -78,6 +78,7 @@ const AppDndContext = (props: PropsWithChildren) => {
const sensors = useSensors(mouseSensor, touchSensor);
const scaledModifier = useScaledModifer();
+ const modifiers = useMemo(() => [scaledModifier], [scaledModifier]);
return (
{
{props.children}
diff --git a/invokeai/frontend/web/src/features/hrf/components/ParamHrfToggle.tsx b/invokeai/frontend/web/src/features/hrf/components/ParamHrfToggle.tsx
index 2ba45563aa..0491d6323a 100644
--- a/invokeai/frontend/web/src/features/hrf/components/ParamHrfToggle.tsx
+++ b/invokeai/frontend/web/src/features/hrf/components/ParamHrfToggle.tsx
@@ -1,6 +1,7 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
+import type { InvLabelProps } from 'common/components/InvControl/types';
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { setHrfEnabled } from 'features/hrf/store/hrfSlice';
import type { ChangeEvent } from 'react';
@@ -22,10 +23,12 @@ export default function ParamHrfToggle() {
return (
);
}
+
+const labelProps: InvLabelProps = { flexGrow: 1 };
\ No newline at end of file
diff --git a/invokeai/frontend/web/src/features/lora/components/LoRACard.tsx b/invokeai/frontend/web/src/features/lora/components/LoRACard.tsx
index 39869fb556..f5fedcdee3 100644
--- a/invokeai/frontend/web/src/features/lora/components/LoRACard.tsx
+++ b/invokeai/frontend/web/src/features/lora/components/LoRACard.tsx
@@ -62,7 +62,7 @@ export const LoRACard = memo((props: LoRACardProps) => {
max={2}
step={0.01}
onReset={onReset}
- marks={[-1, 0, 1, 2]}
+ marks={marks}
/>
{
});
LoRACard.displayName = 'LoRACard';
+
+const marks = [-1, 0, 1, 2];
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/details/EditableNodeTitle.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/details/EditableNodeTitle.tsx
index ecebafcf6c..8704f290b4 100644
--- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/details/EditableNodeTitle.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/details/EditableNodeTitle.tsx
@@ -55,10 +55,7 @@ const EditableNodeTitle = ({ nodeId, title }: Props) => {
fontWeight="semibold"
>
-
+
);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx
index 9d2e6204af..1205e350e5 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamHeight.tsx
@@ -5,7 +5,7 @@ import { InvControl } from 'common/components/InvControl/InvControl';
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { heightChanged } from 'features/parameters/store/generationSlice';
-import { memo, useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector(
@@ -49,6 +49,8 @@ export const ParamHeight = memo(() => {
dispatch(heightChanged(initial));
}, [dispatch, initial]);
+ const marks = useMemo(()=>[min, initial, max], [min, initial, max])
+
return (
{
max={max}
step={step}
fineStep={fineStep}
- marks={[min, initial, max]}
+ marks={marks}
/>
{
value={iterations}
h="full"
w="216px"
- numberInputFieldProps={{
- ps: '144px',
- borderInlineStartRadius: 'base',
- h: 'full',
- textAlign: 'center',
- }}
+ numberInputFieldProps={numberInputFieldProps}
/>
);
};
export default memo(ParamIterations);
+
+const numberInputFieldProps: InvNumberInputFieldProps = {
+ ps: '144px',
+ borderInlineStartRadius: 'base',
+ h: 'full',
+ textAlign: 'center',
+};
diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx
index ee2da16ae8..88da4e8beb 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamWidth.tsx
@@ -5,7 +5,7 @@ import { InvControl } from 'common/components/InvControl/InvControl';
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { widthChanged } from 'features/parameters/store/generationSlice';
-import { memo, useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector(
@@ -48,6 +48,8 @@ export const ParamWidth = memo(() => {
dispatch(widthChanged(initial));
}, [dispatch, initial]);
+ const marks = useMemo(() => [min, initial, max], [min, initial, max]);
+
return (
{
max={max}
step={step}
fineStep={fineStep}
- marks={[min, initial, max]}
+ marks={marks}
/>
{
[item.status]
);
+ const icon = useMemo(() => (), []);
return (
{
isDisabled={isCanceled}
isLoading={isLoading}
aria-label={t('queue.cancelItem')}
- icon={}
+ icon={icon}
/>
-
+
);
};
+const transition: CollapseProps['transition'] = {
+ enter: { duration: 0.1 },
+ exit: { duration: 0.1 },
+};
+
export default memo(QueueItemComponent);