mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Fix Slider not being able to take typed input
This commit is contained in:
parent
884768c39d
commit
5344481809
@ -23,7 +23,7 @@ import {
|
||||
Tooltip,
|
||||
TooltipProps,
|
||||
} from '@chakra-ui/react';
|
||||
import React, { FocusEvent, useEffect, useMemo, useState } from 'react';
|
||||
import React, { FocusEvent, useMemo, useState, useEffect } from 'react';
|
||||
import { BiReset } from 'react-icons/bi';
|
||||
import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton';
|
||||
import _ from 'lodash';
|
||||
@ -81,7 +81,7 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
||||
withInput = false,
|
||||
isInteger = false,
|
||||
inputWidth = '5.5rem',
|
||||
inputReadOnly = true,
|
||||
inputReadOnly = false,
|
||||
withReset = false,
|
||||
hideTooltip = false,
|
||||
isCompact = false,
|
||||
@ -103,32 +103,35 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const [localInputValue, setLocalInputValue] = useState<string>(String(value));
|
||||
const [localInputValue, setLocalInputValue] = useState<
|
||||
string | number | undefined
|
||||
>(String(value));
|
||||
|
||||
useEffect(() => {
|
||||
setLocalInputValue(value);
|
||||
}, [value]);
|
||||
|
||||
const numberInputMax = useMemo(
|
||||
() => (sliderNumberInputProps?.max ? sliderNumberInputProps.max : max),
|
||||
[max, sliderNumberInputProps?.max]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (String(value) !== localInputValue && localInputValue !== '') {
|
||||
setLocalInputValue(String(value));
|
||||
}
|
||||
}, [value, localInputValue, setLocalInputValue]);
|
||||
const handleSliderChange = (v: number) => {
|
||||
onChange(v);
|
||||
};
|
||||
|
||||
const handleInputBlur = (e: FocusEvent<HTMLInputElement>) => {
|
||||
if (e.target.value === '') e.target.value = String(min);
|
||||
const clamped = _.clamp(
|
||||
isInteger ? Math.floor(Number(e.target.value)) : Number(e.target.value),
|
||||
isInteger ? Math.floor(Number(e.target.value)) : Number(localInputValue),
|
||||
min,
|
||||
numberInputMax
|
||||
);
|
||||
setLocalInputValue(String(clamped));
|
||||
onChange(clamped);
|
||||
};
|
||||
|
||||
const handleInputChange = (v: number | string) => {
|
||||
setLocalInputValue(String(v));
|
||||
onChange(Number(v));
|
||||
setLocalInputValue(v);
|
||||
};
|
||||
|
||||
const handleResetDisable = () => {
|
||||
@ -172,7 +175,7 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={handleInputChange}
|
||||
onChange={handleSliderChange}
|
||||
onMouseEnter={() => setShowTooltip(true)}
|
||||
onMouseLeave={() => setShowTooltip(false)}
|
||||
focusThumbOnChange={false}
|
||||
@ -236,13 +239,19 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
||||
<NumberInputField
|
||||
className="invokeai__slider-number-input"
|
||||
width={inputWidth}
|
||||
minWidth={inputWidth}
|
||||
readOnly={inputReadOnly}
|
||||
minWidth={inputWidth}
|
||||
{...sliderNumberInputFieldProps}
|
||||
/>
|
||||
<NumberInputStepper {...sliderNumberInputStepperProps}>
|
||||
<NumberIncrementStepper className="invokeai__slider-number-stepper" />
|
||||
<NumberDecrementStepper className="invokeai__slider-number-stepper" />
|
||||
<NumberIncrementStepper
|
||||
onClick={() => onChange(Number(localInputValue))}
|
||||
className="invokeai__slider-number-stepper"
|
||||
/>
|
||||
<NumberDecrementStepper
|
||||
onClick={() => onChange(Number(localInputValue))}
|
||||
className="invokeai__slider-number-stepper"
|
||||
/>
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
)}
|
||||
|
@ -75,11 +75,12 @@ const BoundingBoxSettings = () => {
|
||||
step={64}
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeWidth}
|
||||
handleReset={handleResetWidth}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetWidth}
|
||||
/>
|
||||
<IAISlider
|
||||
label={t('options:height')}
|
||||
@ -88,11 +89,12 @@ const BoundingBoxSettings = () => {
|
||||
step={64}
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeHeight}
|
||||
handleReset={handleResetHeight}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetHeight}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
|
@ -124,11 +124,12 @@ const InfillAndScalingOptions = () => {
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.width}
|
||||
onChange={handleChangeScaledWidth}
|
||||
handleReset={handleResetScaledWidth}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetScaledWidth}
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!isManual}
|
||||
@ -140,11 +141,12 @@ const InfillAndScalingOptions = () => {
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.height}
|
||||
onChange={handleChangeScaledHeight}
|
||||
handleReset={handleResetScaledHeight}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetScaledHeight}
|
||||
/>
|
||||
<InpaintReplace />
|
||||
<IAISelect
|
||||
@ -166,12 +168,12 @@ const InfillAndScalingOptions = () => {
|
||||
onChange={(v) => {
|
||||
dispatch(setTileSize(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setTileSize(32));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => {
|
||||
dispatch(setTileSize(32));
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
|
@ -1,113 +0,0 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { optionsSelector } from 'features/options/store/optionsSelectors';
|
||||
import {
|
||||
setSeamBlur,
|
||||
setSeamSize,
|
||||
setSeamSteps,
|
||||
setSeamStrength,
|
||||
} from 'features/options/store/optionsSlice';
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
[optionsSelector],
|
||||
(options) => {
|
||||
const { seamSize, seamBlur, seamStrength, seamSteps } = options;
|
||||
|
||||
return {
|
||||
seamSize,
|
||||
seamBlur,
|
||||
seamStrength,
|
||||
seamSteps,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const SeamCorrectionOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { seamSize, seamBlur, seamStrength, seamSteps } =
|
||||
useAppSelector(selector);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-6}
|
||||
label={t('options:seamSize')}
|
||||
min={1}
|
||||
max={256}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
value={seamSize}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamSize(v));
|
||||
}}
|
||||
handleReset={() => dispatch(setSeamSize(96))}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('options:seamBlur')}
|
||||
min={0}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
value={seamBlur}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamBlur(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setSeamBlur(16));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-7}
|
||||
label={t('options:seamStrength')}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.01}
|
||||
value={seamStrength}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamStrength(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setSeamStrength(0.7));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('options:seamSteps')}
|
||||
min={1}
|
||||
max={32}
|
||||
sliderNumberInputProps={{ max: 100 }}
|
||||
value={seamSteps}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamSteps(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setSeamSteps(10));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeamCorrectionOptions;
|
@ -0,0 +1,32 @@
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSeamBlur } from 'features/options/store/optionsSlice';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SeamBlur() {
|
||||
const dispatch = useAppDispatch();
|
||||
const seamBlur = useAppSelector((state: RootState) => state.options.seamBlur);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('options:seamBlur')}
|
||||
min={0}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
value={seamBlur}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamBlur(v));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => {
|
||||
dispatch(setSeamBlur(16));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import SeamBlur from './SeamBlur';
|
||||
import SeamSize from './SeamSize';
|
||||
import SeamSteps from './SeamSteps';
|
||||
import SeamStrength from './SeamStrength';
|
||||
|
||||
const SeamCorrectionOptions = () => {
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<SeamSize />
|
||||
<SeamBlur />
|
||||
<SeamStrength />
|
||||
<SeamSteps />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeamCorrectionOptions;
|
@ -0,0 +1,31 @@
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSeamSize } from 'features/options/store/optionsSlice';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SeamSize() {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const seamSize = useAppSelector((state: RootState) => state.options.seamSize);
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-6}
|
||||
label={t('options:seamSize')}
|
||||
min={1}
|
||||
max={256}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
value={seamSize}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamSize(v));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => dispatch(setSeamSize(96))}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSeamSteps } from 'features/options/store/optionsSlice';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SeamSteps() {
|
||||
const { t } = useTranslation();
|
||||
const seamSteps = useAppSelector(
|
||||
(state: RootState) => state.options.seamSteps
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('options:seamSteps')}
|
||||
min={1}
|
||||
max={32}
|
||||
sliderNumberInputProps={{ max: 999 }}
|
||||
value={seamSteps}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamSteps(v));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => {
|
||||
dispatch(setSeamSteps(10));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSeamStrength } from 'features/options/store/optionsSlice';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SeamStrength() {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const seamStrength = useAppSelector(
|
||||
(state: RootState) => state.options.seamStrength
|
||||
);
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-7}
|
||||
label={t('options:seamStrength')}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.01}
|
||||
value={seamStrength}
|
||||
onChange={(v) => {
|
||||
dispatch(setSeamStrength(v));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
handleReset={() => {
|
||||
dispatch(setSeamStrength(0.7));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -36,9 +36,9 @@ export default function ImageToImageStrength(props: ImageToImageStrengthProps) {
|
||||
isInteger={false}
|
||||
styleClass={styleClass}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
inputWidth={'5.5rem'}
|
||||
withReset
|
||||
handleReset={handleImg2ImgStrengthReset}
|
||||
/>
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
// import { Feature } from 'app/features';
|
||||
import { Feature } from 'app/features';
|
||||
import ImageToImageStrength from 'features/options/components/AdvancedOptions/ImageToImage/ImageToImageStrength';
|
||||
import SeamCorrectionOptions from 'features/options/components/AdvancedOptions/Canvas/SeamCorrectionOptions';
|
||||
import SeamCorrectionOptions from 'features/options/components/AdvancedOptions/Canvas/SeamCorrectionOptions/SeamCorrectionOptions';
|
||||
import SeedOptions from 'features/options/components/AdvancedOptions/Seed/SeedOptions';
|
||||
import GenerateVariationsToggle from 'features/options/components/AdvancedOptions/Variations/GenerateVariations';
|
||||
import VariationsOptions from 'features/options/components/AdvancedOptions/Variations/VariationsOptions';
|
||||
|
Loading…
Reference in New Issue
Block a user