mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): more memoization
This commit is contained in:
parent
10fd4f6a61
commit
3ce8f3d6fe
@ -30,6 +30,8 @@ module.exports = {
|
|||||||
'unused-imports',
|
'unused-imports',
|
||||||
'simple-import-sort',
|
'simple-import-sort',
|
||||||
'eslint-plugin-import',
|
'eslint-plugin-import',
|
||||||
|
// These rules are too strict for normal usage, but are useful for optimizing rerenders
|
||||||
|
// '@arthurgeron/react-usememo',
|
||||||
],
|
],
|
||||||
root: true,
|
root: true,
|
||||||
rules: {
|
rules: {
|
||||||
@ -60,6 +62,18 @@ module.exports = {
|
|||||||
argsIgnorePattern: '^_',
|
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/ban-ts-comment': 'warn',
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
'@typescript-eslint/no-empty-interface': [
|
'@typescript-eslint/no-empty-interface': [
|
||||||
|
@ -120,6 +120,7 @@
|
|||||||
"ts-toolbelt": "^9.6.0"
|
"ts-toolbelt": "^9.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@arthurgeron/eslint-plugin-react-usememo": "^2.2.1",
|
||||||
"@chakra-ui/cli": "^2.4.1",
|
"@chakra-ui/cli": "^2.4.1",
|
||||||
"@storybook/addon-docs": "^7.6.6",
|
"@storybook/addon-docs": "^7.6.6",
|
||||||
"@storybook/addon-essentials": "^7.6.6",
|
"@storybook/addon-essentials": "^7.6.6",
|
||||||
|
10
invokeai/frontend/web/pnpm-lock.yaml
generated
10
invokeai/frontend/web/pnpm-lock.yaml
generated
@ -184,6 +184,9 @@ dependencies:
|
|||||||
version: 2.1.0(zod@3.22.4)
|
version: 2.1.0(zod@3.22.4)
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@arthurgeron/eslint-plugin-react-usememo':
|
||||||
|
specifier: ^2.2.1
|
||||||
|
version: 2.2.1
|
||||||
'@chakra-ui/cli':
|
'@chakra-ui/cli':
|
||||||
specifier: ^2.4.1
|
specifier: ^2.4.1
|
||||||
version: 2.4.1
|
version: 2.4.1
|
||||||
@ -339,6 +342,13 @@ packages:
|
|||||||
'@jridgewell/trace-mapping': 0.3.20
|
'@jridgewell/trace-mapping': 0.3.20
|
||||||
dev: true
|
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:
|
/@aw-web-design/x-default-browser@1.4.126:
|
||||||
resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
|
resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -12,7 +12,12 @@
|
|||||||
* - increment it in `onPaneClick` (and wherever else we want to close the menu)
|
* - increment it in `onPaneClick` (and wherever else we want to close the menu)
|
||||||
* - `useEffect()` to close the menu when `globalContextMenuCloseTrigger` changes
|
* - `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 { Portal, useEventListener } from '@chakra-ui/react';
|
||||||
import { InvMenu, InvMenuButton } from 'common/components/InvMenu/wrapper';
|
import { InvMenu, InvMenuButton } from 'common/components/InvMenu/wrapper';
|
||||||
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
|
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
|
||||||
@ -102,7 +107,7 @@ export const InvContextMenu = typedMemo(
|
|||||||
cursor="default"
|
cursor="default"
|
||||||
bg="transparent"
|
bg="transparent"
|
||||||
size="sm"
|
size="sm"
|
||||||
_hover={{ bg: 'transparent' }}
|
_hover={_hover}
|
||||||
{...props.menuButtonProps}
|
{...props.menuButtonProps}
|
||||||
/>
|
/>
|
||||||
{props.renderMenu()}
|
{props.renderMenu()}
|
||||||
@ -114,6 +119,8 @@ export const InvContextMenu = typedMemo(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const _hover: ChakraProps['_hover'] = { bg: 'transparent' };
|
||||||
|
|
||||||
Object.assign(InvContextMenu, {
|
Object.assign(InvContextMenu, {
|
||||||
displayName: 'InvContextMenu',
|
displayName: 'InvContextMenu',
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// https://stackoverflow.com/a/73731908
|
// https://stackoverflow.com/a/73731908
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function useSingleAndDoubleClick(
|
export function useSingleAndDoubleClick(
|
||||||
handleSingleClick: () => void,
|
handleSingleClick: () => void,
|
||||||
@ -23,5 +23,7 @@ export function useSingleAndDoubleClick(
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [click, handleSingleClick, handleDoubleClick, delay]);
|
}, [click, handleSingleClick, handleDoubleClick, delay]);
|
||||||
|
|
||||||
return () => setClick((prev) => prev + 1);
|
const onClick = useCallback(() => setClick((prev) => prev + 1), []);
|
||||||
|
|
||||||
|
return onClick;
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,8 @@ const IAICanvas = () => {
|
|||||||
[stageCursor]
|
[stageCursor]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const scale= useMemo(()=>({x: stageScale, y: stageScale}),[stageScale])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
id="canvas-container"
|
id="canvas-container"
|
||||||
@ -193,7 +195,7 @@ const IAICanvas = () => {
|
|||||||
y={stageCoordinates.y}
|
y={stageCoordinates.y}
|
||||||
width={stageDimensions.width}
|
width={stageDimensions.width}
|
||||||
height={stageDimensions.height}
|
height={stageDimensions.height}
|
||||||
scale={{ x: stageScale, y: stageScale }}
|
scale={scale}
|
||||||
onTouchStart={handleMouseDown}
|
onTouchStart={handleMouseDown}
|
||||||
onTouchMove={handleMouseMove}
|
onTouchMove={handleMouseMove}
|
||||||
onTouchEnd={handleMouseUp}
|
onTouchEnd={handleMouseUp}
|
||||||
|
@ -5,7 +5,7 @@ import { rgbaColorToString } from 'features/canvas/util/colorToString';
|
|||||||
import type Konva from 'konva';
|
import type Konva from 'konva';
|
||||||
import type { RectConfig } from 'konva/lib/shapes/Rect';
|
import type { RectConfig } from 'konva/lib/shapes/Rect';
|
||||||
import { isNumber } from 'lodash-es';
|
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';
|
import { Rect } from 'react-konva';
|
||||||
|
|
||||||
export const canvasMaskCompositerSelector = createMemoizedSelector(
|
export const canvasMaskCompositerSelector = createMemoizedSelector(
|
||||||
@ -147,6 +147,11 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
|||||||
return () => clearInterval(timer);
|
return () => clearInterval(timer);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const fillPatternScale = useMemo(
|
||||||
|
() => ({ x: 1 / stageScale, y: 1 / stageScale }),
|
||||||
|
[stageScale]
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!fillPatternImage ||
|
!fillPatternImage ||
|
||||||
!isNumber(stageCoordinates.x) ||
|
!isNumber(stageCoordinates.x) ||
|
||||||
@ -168,7 +173,7 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
|||||||
fillPatternImage={fillPatternImage}
|
fillPatternImage={fillPatternImage}
|
||||||
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
|
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
|
||||||
fillPatternRepeat="repeat"
|
fillPatternRepeat="repeat"
|
||||||
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
fillPatternScale={fillPatternScale}
|
||||||
listening={true}
|
listening={true}
|
||||||
globalCompositeOperation="source-in"
|
globalCompositeOperation="source-in"
|
||||||
{...rest}
|
{...rest}
|
||||||
|
@ -7,6 +7,8 @@ import { Group, Rect } from 'react-konva';
|
|||||||
|
|
||||||
import IAICanvasImage from './IAICanvasImage';
|
import IAICanvasImage from './IAICanvasImage';
|
||||||
|
|
||||||
|
const dash = [4, 4]
|
||||||
|
|
||||||
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => {
|
||||||
const {
|
const {
|
||||||
layerState,
|
layerState,
|
||||||
@ -69,7 +71,7 @@ const IAICanvasStagingArea = (props: Props) => {
|
|||||||
y={y}
|
y={y}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
dash={[4, 4]}
|
dash={dash}
|
||||||
strokeWidth={1}
|
strokeWidth={1}
|
||||||
stroke="black"
|
stroke="black"
|
||||||
strokeScaleEnabled={false}
|
strokeScaleEnabled={false}
|
||||||
|
@ -21,6 +21,8 @@ import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
|||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { Group, Rect, Transformer } from 'react-konva';
|
import { Group, Rect, Transformer } from 'react-konva';
|
||||||
|
|
||||||
|
const borderDash = [4, 4];
|
||||||
|
|
||||||
const boundingBoxPreviewSelector = createMemoizedSelector(
|
const boundingBoxPreviewSelector = createMemoizedSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ canvas, generation }) => {
|
({ canvas, generation }) => {
|
||||||
@ -289,11 +291,11 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
anchorFill="rgba(212,216,234,1)"
|
anchorFill="rgba(212,216,234,1)"
|
||||||
anchorSize={15}
|
anchorSize={15}
|
||||||
anchorStroke="rgb(42,42,42)"
|
anchorStroke="rgb(42,42,42)"
|
||||||
borderDash={[4, 4]}
|
borderDash={borderDash}
|
||||||
borderEnabled={true}
|
borderEnabled={true}
|
||||||
borderStroke="black"
|
borderStroke="black"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
enabledAnchors={tool === 'move' ? undefined : []}
|
enabledAnchors={tool === 'move' ? undefined : emptyArray}
|
||||||
flipEnabled={false}
|
flipEnabled={false}
|
||||||
ignoreStroke={true}
|
ignoreStroke={true}
|
||||||
keepRatio={false}
|
keepRatio={false}
|
||||||
@ -311,3 +313,5 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(IAICanvasBoundingBox);
|
export default memo(IAICanvasBoundingBox);
|
||||||
|
|
||||||
|
const emptyArray: string[] = []
|
@ -261,7 +261,7 @@ const IAICanvasToolChooserOptions = () => {
|
|||||||
max={100}
|
max={100}
|
||||||
step={1}
|
step={1}
|
||||||
onChange={handleChangeBrushSize}
|
onChange={handleChangeBrushSize}
|
||||||
marks={[1, 25, 50, 75, 100]}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
<InvNumberInput
|
<InvNumberInput
|
||||||
value={brushSize}
|
value={brushSize}
|
||||||
@ -288,3 +288,5 @@ const IAICanvasToolChooserOptions = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(IAICanvasToolChooserOptions);
|
export default memo(IAICanvasToolChooserOptions);
|
||||||
|
|
||||||
|
const marks = [1, 25, 50, 75, 100];
|
||||||
|
@ -8,50 +8,52 @@ import {
|
|||||||
getCanvasStage,
|
getCanvasStage,
|
||||||
} from 'features/canvas/util/konvaInstanceProvider';
|
} from 'features/canvas/util/konvaInstanceProvider';
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
const useColorPicker = () => {
|
const useColorPicker = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
const canvasBaseLayer = getCanvasBaseLayer();
|
||||||
const stage = getCanvasStage();
|
const stage = getCanvasStage();
|
||||||
|
|
||||||
return {
|
const updateColorUnderCursor = useCallback(() => {
|
||||||
updateColorUnderCursor: () => {
|
if (!stage || !canvasBaseLayer) {
|
||||||
if (!stage || !canvasBaseLayer) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const position = stage.getPointerPosition();
|
const position = stage.getPointerPosition();
|
||||||
|
|
||||||
if (!position) {
|
if (!position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pixelRatio = Konva.pixelRatio;
|
const pixelRatio = Konva.pixelRatio;
|
||||||
|
|
||||||
const [r, g, b, a] = canvasBaseLayer
|
const [r, g, b, a] = canvasBaseLayer
|
||||||
.getContext()
|
.getContext()
|
||||||
.getImageData(
|
.getImageData(
|
||||||
position.x * pixelRatio,
|
position.x * pixelRatio,
|
||||||
position.y * pixelRatio,
|
position.y * pixelRatio,
|
||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
r === undefined ||
|
r === undefined ||
|
||||||
g === undefined ||
|
g === undefined ||
|
||||||
b === undefined ||
|
b === undefined ||
|
||||||
a === undefined
|
a === undefined
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(setColorPickerColor({ r, g, b, a }));
|
dispatch(setColorPickerColor({ r, g, b, a }));
|
||||||
},
|
}, [canvasBaseLayer, dispatch, stage]);
|
||||||
commitColorUnderCursor: () => {
|
|
||||||
dispatch(commitColorPickerColor());
|
const commitColorUnderCursor = useCallback(() => {
|
||||||
},
|
dispatch(commitColorPickerColor());
|
||||||
};
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return { updateColorUnderCursor, commitColorUnderCursor };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useColorPicker;
|
export default useColorPicker;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import type { SystemStyleObject } from '@chakra-ui/react';
|
||||||
import { Box, Flex, Spinner } from '@chakra-ui/react';
|
import { Box, Flex, Spinner } from '@chakra-ui/react';
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
@ -220,13 +221,13 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
|||||||
onClick={handleSaveControlImage}
|
onClick={handleSaveControlImage}
|
||||||
icon={controlImage ? <FaSave size={16} /> : undefined}
|
icon={controlImage ? <FaSave size={16} /> : undefined}
|
||||||
tooltip={t('controlnet.saveControlImage')}
|
tooltip={t('controlnet.saveControlImage')}
|
||||||
styleOverrides={{ marginTop: 6 }}
|
styleOverrides={saveControlImageStyleOverrides}
|
||||||
/>
|
/>
|
||||||
<IAIDndImageIcon
|
<IAIDndImageIcon
|
||||||
onClick={handleSetControlImageToDimensions}
|
onClick={handleSetControlImageToDimensions}
|
||||||
icon={controlImage ? <FaRulerVertical size={16} /> : undefined}
|
icon={controlImage ? <FaRulerVertical size={16} /> : undefined}
|
||||||
tooltip={t('controlnet.setControlImageDimensions')}
|
tooltip={t('controlnet.setControlImageDimensions')}
|
||||||
styleOverrides={{ marginTop: 12 }}
|
styleOverrides={setControlImageDimensionsStyleOverrides}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
@ -251,3 +252,6 @@ const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(ControlAdapterImagePreview);
|
export default memo(ControlAdapterImagePreview);
|
||||||
|
|
||||||
|
const saveControlImageStyleOverrides: SystemStyleObject = { mt: 6 };
|
||||||
|
const setControlImageDimensionsStyleOverrides: SystemStyleObject = { mt: 12 };
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
controlAdapterBeginStepPctChanged,
|
controlAdapterBeginStepPctChanged,
|
||||||
controlAdapterEndStepPctChanged,
|
controlAdapterEndStepPctChanged,
|
||||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -55,6 +55,11 @@ export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
|
|||||||
);
|
);
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
|
const value = useMemo<[number, number]>(
|
||||||
|
() => [stepPcts?.beginStepPct ?? 0, stepPcts?.endStepPct ?? 1],
|
||||||
|
[stepPcts]
|
||||||
|
);
|
||||||
|
|
||||||
if (!stepPcts) {
|
if (!stepPcts) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -67,8 +72,8 @@ export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
|
|||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
>
|
>
|
||||||
<InvRangeSlider
|
<InvRangeSlider
|
||||||
aria-label={['Begin Step %', 'End Step %']}
|
aria-label={ariaLabel}
|
||||||
value={[stepPcts.beginStepPct, stepPcts.endStepPct]}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onReset={onReset}
|
onReset={onReset}
|
||||||
min={0}
|
min={0}
|
||||||
@ -83,3 +88,5 @@ export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ParamControlAdapterBeginEnd.displayName = 'ParamControlAdapterBeginEnd';
|
ParamControlAdapterBeginEnd.displayName = 'ParamControlAdapterBeginEnd';
|
||||||
|
|
||||||
|
const ariaLabel = ['Begin Step %', 'End Step %'];
|
||||||
|
@ -42,10 +42,12 @@ const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
|
|||||||
min={0}
|
min={0}
|
||||||
max={2}
|
max={2}
|
||||||
step={0.01}
|
step={0.01}
|
||||||
marks={[0, 1, 2]}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(ParamControlAdapterWeight);
|
export default memo(ParamControlAdapterWeight);
|
||||||
|
|
||||||
|
const marks = [0, 1, 2];
|
||||||
|
@ -83,7 +83,7 @@ const MlsdImageProcessor = (props: Props) => {
|
|||||||
onReset={handleDetectResolutionReset}
|
onReset={handleDetectResolutionReset}
|
||||||
min={0}
|
min={0}
|
||||||
max={4096}
|
max={4096}
|
||||||
marks={[0, 4096]}
|
marks={marks0to4096}
|
||||||
withNumberInput
|
withNumberInput
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
@ -97,7 +97,7 @@ const MlsdImageProcessor = (props: Props) => {
|
|||||||
onReset={handleImageResolutionReset}
|
onReset={handleImageResolutionReset}
|
||||||
min={0}
|
min={0}
|
||||||
max={4096}
|
max={4096}
|
||||||
marks={[0, 4096]}
|
marks={marks0to4096}
|
||||||
withNumberInput
|
withNumberInput
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
@ -109,7 +109,7 @@ const MlsdImageProcessor = (props: Props) => {
|
|||||||
min={0}
|
min={0}
|
||||||
max={1}
|
max={1}
|
||||||
step={0.01}
|
step={0.01}
|
||||||
marks={[0, 1]}
|
marks={marks0to1}
|
||||||
withNumberInput
|
withNumberInput
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
@ -121,7 +121,7 @@ const MlsdImageProcessor = (props: Props) => {
|
|||||||
min={0}
|
min={0}
|
||||||
max={1}
|
max={1}
|
||||||
step={0.01}
|
step={0.01}
|
||||||
marks={[0, 1]}
|
marks={marks0to1}
|
||||||
withNumberInput
|
withNumberInput
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
@ -130,3 +130,6 @@ const MlsdImageProcessor = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(MlsdImageProcessor);
|
export default memo(MlsdImageProcessor);
|
||||||
|
|
||||||
|
const marks0to4096 = [0, 4096];
|
||||||
|
const marks0to1 = [0, 1];
|
@ -19,7 +19,7 @@ import { customPointerWithin } from 'features/dnd/util/customPointerWithin';
|
|||||||
import type { AnimationProps } from 'framer-motion';
|
import type { AnimationProps } from 'framer-motion';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import type { CSSProperties, PropsWithChildren } from 'react';
|
import type { CSSProperties, PropsWithChildren } from 'react';
|
||||||
import { memo, useCallback, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { DndContextTypesafe } from './DndContextTypesafe';
|
import { DndContextTypesafe } from './DndContextTypesafe';
|
||||||
import DragPreview from './DragPreview';
|
import DragPreview from './DragPreview';
|
||||||
@ -78,6 +78,7 @@ const AppDndContext = (props: PropsWithChildren) => {
|
|||||||
const sensors = useSensors(mouseSensor, touchSensor);
|
const sensors = useSensors(mouseSensor, touchSensor);
|
||||||
|
|
||||||
const scaledModifier = useScaledModifer();
|
const scaledModifier = useScaledModifer();
|
||||||
|
const modifiers = useMemo(() => [scaledModifier], [scaledModifier]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContextTypesafe
|
<DndContextTypesafe
|
||||||
@ -90,7 +91,7 @@ const AppDndContext = (props: PropsWithChildren) => {
|
|||||||
{props.children}
|
{props.children}
|
||||||
<DragOverlay
|
<DragOverlay
|
||||||
dropAnimation={null}
|
dropAnimation={null}
|
||||||
modifiers={[scaledModifier]}
|
modifiers={modifiers}
|
||||||
style={dragOverlayStyles}
|
style={dragOverlayStyles}
|
||||||
>
|
>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
|
import type { InvLabelProps } from 'common/components/InvControl/types';
|
||||||
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
|
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
|
||||||
import { setHrfEnabled } from 'features/hrf/store/hrfSlice';
|
import { setHrfEnabled } from 'features/hrf/store/hrfSlice';
|
||||||
import type { ChangeEvent } from 'react';
|
import type { ChangeEvent } from 'react';
|
||||||
@ -22,10 +23,12 @@ export default function ParamHrfToggle() {
|
|||||||
return (
|
return (
|
||||||
<InvControl
|
<InvControl
|
||||||
label={t('hrf.enableHrf')}
|
label={t('hrf.enableHrf')}
|
||||||
labelProps={{ flexGrow: 1 }}
|
labelProps={labelProps}
|
||||||
w="full"
|
w="full"
|
||||||
>
|
>
|
||||||
<InvSwitch isChecked={hrfEnabled} onChange={handleHrfEnabled} />
|
<InvSwitch isChecked={hrfEnabled} onChange={handleHrfEnabled} />
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const labelProps: InvLabelProps = { flexGrow: 1 };
|
@ -62,7 +62,7 @@ export const LoRACard = memo((props: LoRACardProps) => {
|
|||||||
max={2}
|
max={2}
|
||||||
step={0.01}
|
step={0.01}
|
||||||
onReset={onReset}
|
onReset={onReset}
|
||||||
marks={[-1, 0, 1, 2]}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
<InvNumberInput
|
<InvNumberInput
|
||||||
value={lora.weight}
|
value={lora.weight}
|
||||||
@ -79,3 +79,5 @@ export const LoRACard = memo((props: LoRACardProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
LoRACard.displayName = 'LoRACard';
|
LoRACard.displayName = 'LoRACard';
|
||||||
|
|
||||||
|
const marks = [-1, 0, 1, 2];
|
||||||
|
@ -55,10 +55,7 @@ const EditableNodeTitle = ({ nodeId, title }: Props) => {
|
|||||||
fontWeight="semibold"
|
fontWeight="semibold"
|
||||||
>
|
>
|
||||||
<EditablePreview noOfLines={1} />
|
<EditablePreview noOfLines={1} />
|
||||||
<EditableInput
|
<EditableInput className="nodrag" />
|
||||||
className="nodrag"
|
|
||||||
_focusVisible={{ boxShadow: 'none' }}
|
|
||||||
/>
|
|
||||||
</Editable>
|
</Editable>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -5,7 +5,7 @@ import { InvControl } from 'common/components/InvControl/InvControl';
|
|||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { heightChanged } from 'features/parameters/store/generationSlice';
|
import { heightChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selector = createMemoizedSelector(
|
||||||
@ -49,6 +49,8 @@ export const ParamHeight = memo(() => {
|
|||||||
dispatch(heightChanged(initial));
|
dispatch(heightChanged(initial));
|
||||||
}, [dispatch, initial]);
|
}, [dispatch, initial]);
|
||||||
|
|
||||||
|
const marks = useMemo(()=>[min, initial, max], [min, initial, max])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvControl label={t('parameters.height')}>
|
<InvControl label={t('parameters.height')}>
|
||||||
<InvSlider
|
<InvSlider
|
||||||
@ -59,7 +61,7 @@ export const ParamHeight = memo(() => {
|
|||||||
max={max}
|
max={max}
|
||||||
step={step}
|
step={step}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
marks={[min, initial, max]}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
<InvNumberInput
|
<InvNumberInput
|
||||||
value={height}
|
value={height}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
|
import type { InvNumberInputFieldProps } from 'common/components/InvNumberInput/types';
|
||||||
import { setIterations } from 'features/parameters/store/generationSlice';
|
import { setIterations } from 'features/parameters/store/generationSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
|
|
||||||
@ -23,14 +24,16 @@ const ParamIterations = () => {
|
|||||||
value={iterations}
|
value={iterations}
|
||||||
h="full"
|
h="full"
|
||||||
w="216px"
|
w="216px"
|
||||||
numberInputFieldProps={{
|
numberInputFieldProps={numberInputFieldProps}
|
||||||
ps: '144px',
|
|
||||||
borderInlineStartRadius: 'base',
|
|
||||||
h: 'full',
|
|
||||||
textAlign: 'center',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(ParamIterations);
|
export default memo(ParamIterations);
|
||||||
|
|
||||||
|
const numberInputFieldProps: InvNumberInputFieldProps = {
|
||||||
|
ps: '144px',
|
||||||
|
borderInlineStartRadius: 'base',
|
||||||
|
h: 'full',
|
||||||
|
textAlign: 'center',
|
||||||
|
};
|
||||||
|
@ -5,7 +5,7 @@ import { InvControl } from 'common/components/InvControl/InvControl';
|
|||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { widthChanged } from 'features/parameters/store/generationSlice';
|
import { widthChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selector = createMemoizedSelector(
|
||||||
@ -48,6 +48,8 @@ export const ParamWidth = memo(() => {
|
|||||||
dispatch(widthChanged(initial));
|
dispatch(widthChanged(initial));
|
||||||
}, [dispatch, initial]);
|
}, [dispatch, initial]);
|
||||||
|
|
||||||
|
const marks = useMemo(() => [min, initial, max], [min, initial, max]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvControl label={t('parameters.width')}>
|
<InvControl label={t('parameters.width')}>
|
||||||
<InvSlider
|
<InvSlider
|
||||||
@ -58,7 +60,7 @@ export const ParamWidth = memo(() => {
|
|||||||
max={max}
|
max={max}
|
||||||
step={step}
|
step={step}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
marks={[min, initial, max]}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
<InvNumberInput
|
<InvNumberInput
|
||||||
value={width}
|
value={width}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
|
import type { InvLabelProps } from 'common/components/InvControl/types';
|
||||||
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
|
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
|
||||||
import { setShouldFitToWidthHeight } from 'features/parameters/store/generationSlice';
|
import { setShouldFitToWidthHeight } from 'features/parameters/store/generationSlice';
|
||||||
import type { ChangeEvent } from 'react';
|
import type { ChangeEvent } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const labelProps: InvLabelProps = { flexGrow: 1 };
|
||||||
|
|
||||||
export default function ImageToImageFit() {
|
export default function ImageToImageFit() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ export default function ImageToImageFit() {
|
|||||||
return (
|
return (
|
||||||
<InvControl
|
<InvControl
|
||||||
label={t('parameters.imageFit')}
|
label={t('parameters.imageFit')}
|
||||||
labelProps={{ flexGrow: 1 }}
|
labelProps={labelProps}
|
||||||
w="full"
|
w="full"
|
||||||
>
|
>
|
||||||
<InvSwitch
|
<InvSwitch
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ChakraProps } from '@chakra-ui/react';
|
import type { ChakraProps, CollapseProps } from '@chakra-ui/react';
|
||||||
import { Collapse, Flex } from '@chakra-ui/react';
|
import { Collapse, Flex } from '@chakra-ui/react';
|
||||||
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
|
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
|
||||||
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
|
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
|
||||||
@ -63,6 +63,7 @@ const QueueItemComponent = ({ index, item, context }: InnerItemProps) => {
|
|||||||
[item.status]
|
[item.status]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const icon = useMemo(() => (<FaTimes />), []);
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
flexDir="column"
|
flexDir="column"
|
||||||
@ -137,21 +138,22 @@ const QueueItemComponent = ({ index, item, context }: InnerItemProps) => {
|
|||||||
isDisabled={isCanceled}
|
isDisabled={isCanceled}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
aria-label={t('queue.cancelItem')}
|
aria-label={t('queue.cancelItem')}
|
||||||
icon={<FaTimes />}
|
icon={icon}
|
||||||
/>
|
/>
|
||||||
</InvButtonGroup>
|
</InvButtonGroup>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Collapse
|
<Collapse in={isOpen} transition={transition} unmountOnExit={true}>
|
||||||
in={isOpen}
|
|
||||||
transition={{ enter: { duration: 0.1 }, exit: { duration: 0.1 } }}
|
|
||||||
unmountOnExit={true}
|
|
||||||
>
|
|
||||||
<QueueItemDetail queueItemDTO={item} />
|
<QueueItemDetail queueItemDTO={item} />
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const transition: CollapseProps['transition'] = {
|
||||||
|
enter: { duration: 0.1 },
|
||||||
|
exit: { duration: 0.1 },
|
||||||
|
};
|
||||||
|
|
||||||
export default memo(QueueItemComponent);
|
export default memo(QueueItemComponent);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user