feat(ui): remove SDXL style prompt from linear UI

This feature added a lot of unexpected complexity in graph building /
metadata recall and is unintuitive user experience. 99% of the time, the
style prompt should be exactly the main prompt.

You can still use style prompts in workflows, but in an effort to reduce
complexity in the linear UI, we are removing this rarely-used feature.
This commit is contained in:
psychedelicious
2025-08-12 15:25:58 +10:00
parent 5259693ed1
commit a89b3efd14
15 changed files with 11 additions and 345 deletions

View File

@@ -181,15 +181,6 @@ const slice = createSlice({
negativePromptChanged: (state, action: PayloadAction<ParameterNegativePrompt>) => {
state.negativePrompt = action.payload;
},
positivePrompt2Changed: (state, action: PayloadAction<string>) => {
state.positivePrompt2 = action.payload;
},
negativePrompt2Changed: (state, action: PayloadAction<string>) => {
state.negativePrompt2 = action.payload;
},
shouldConcatPromptsChanged: (state, action: PayloadAction<boolean>) => {
state.shouldConcatPrompts = action.payload;
},
refinerModelChanged: (state, action: PayloadAction<ParameterSDXLRefinerModel | null>) => {
const result = zParamsState.shape.refinerModel.safeParse(action.payload);
if (!result.success) {
@@ -425,9 +416,6 @@ export const {
shouldUseCpuNoiseChanged,
positivePromptChanged,
negativePromptChanged,
positivePrompt2Changed,
negativePrompt2Changed,
shouldConcatPromptsChanged,
refinerModelChanged,
setRefinerSteps,
setRefinerCFGScale,
@@ -518,9 +506,6 @@ export const selectModelSupportsNegativePrompt = createSelector(
[selectIsFLUX, selectIsChatGPT4o, selectIsFluxKontext],
(isFLUX, isChatGPT4o, isFluxKontext) => !isFLUX && !isChatGPT4o && !isFluxKontext
);
export const selectPositivePrompt2 = createParamsSelector((params) => params.positivePrompt2);
export const selectNegativePrompt2 = createParamsSelector((params) => params.negativePrompt2);
export const selectShouldConcatPrompts = createParamsSelector((params) => params.shouldConcatPrompts);
export const selectScheduler = createParamsSelector((params) => params.scheduler);
export const selectSeamlessXAxis = createParamsSelector((params) => params.seamlessXAxis);
export const selectSeamlessYAxis = createParamsSelector((params) => params.seamlessYAxis);

View File

@@ -14,9 +14,7 @@ import {
zParameterMaskBlurMethod,
zParameterModel,
zParameterNegativePrompt,
zParameterNegativeStylePromptSDXL,
zParameterPositivePrompt,
zParameterPositiveStylePromptSDXL,
zParameterPrecision,
zParameterScheduler,
zParameterSDXLRefinerModel,
@@ -534,9 +532,6 @@ export const zParamsState = z.object({
shouldUseCpuNoise: z.boolean(),
positivePrompt: zParameterPositivePrompt,
negativePrompt: zParameterNegativePrompt,
positivePrompt2: zParameterPositiveStylePromptSDXL,
negativePrompt2: zParameterNegativeStylePromptSDXL,
shouldConcatPrompts: z.boolean(),
refinerModel: zParameterSDXLRefinerModel.nullable(),
refinerSteps: z.number(),
refinerCFGScale: z.number(),
@@ -584,9 +579,6 @@ export const getInitialParamsState = (): ParamsState => ({
shouldUseCpuNoise: true,
positivePrompt: '',
negativePrompt: null,
positivePrompt2: '',
negativePrompt2: '',
shouldConcatPrompts: true,
refinerModel: null,
refinerSteps: 20,
refinerCFGScale: 7.5,

View File

@@ -33,8 +33,6 @@ const ImageMetadataActions = (props: Props) => {
<UnrecallableMetadataDatum metadata={metadata} handler={MetadataHandlers.GenerationMode} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.PositivePrompt} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.NegativePrompt} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.PositiveStylePrompt} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.NegativeStylePrompt} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.MainModel} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.VAEModel} />
<SingleMetadataDatum metadata={metadata} handler={MetadataHandlers.Width} />

View File

@@ -22,12 +22,7 @@ export const useRecallPrompts = (imageDTO: ImageDTO) => {
const parse = async () => {
try {
const result = await MetadataUtils.hasMetadataByHandlers({
handlers: [
MetadataHandlers.PositivePrompt,
MetadataHandlers.NegativePrompt,
MetadataHandlers.PositiveStylePrompt,
MetadataHandlers.NegativeStylePrompt,
],
handlers: [MetadataHandlers.PositivePrompt, MetadataHandlers.NegativePrompt],
metadata,
store,
require: 'some',

View File

@@ -9,9 +9,7 @@ import { bboxHeightChanged, bboxWidthChanged, canvasMetadataRecalled } from 'fea
import { loraAllDeleted, loraRecalled } from 'features/controlLayers/store/lorasSlice';
import {
heightChanged,
negativePrompt2Changed,
negativePromptChanged,
positivePrompt2Changed,
positivePromptChanged,
refinerModelChanged,
selectBase,
@@ -30,7 +28,6 @@ import {
setSeamlessYAxis,
setSeed,
setSteps,
shouldConcatPromptsChanged,
vaeSelected,
widthChanged,
} from 'features/controlLayers/store/paramsSlice';
@@ -49,7 +46,6 @@ import type {
ParameterModel,
ParameterNegativePrompt,
ParameterPositivePrompt,
ParameterPositiveStylePromptSDXL,
ParameterScheduler,
ParameterSDXLRefinerModel,
ParameterSDXLRefinerNegativeAestheticScore,
@@ -70,9 +66,7 @@ import {
zParameterGuidance,
zParameterImageDimension,
zParameterNegativePrompt,
zParameterNegativeStylePromptSDXL,
zParameterPositivePrompt,
zParameterPositiveStylePromptSDXL,
zParameterScheduler,
zParameterSDXLRefinerNegativeAestheticScore,
zParameterSDXLRefinerPositiveAestheticScore,
@@ -289,46 +283,6 @@ const NegativePrompt: SingleMetadataHandler<ParameterNegativePrompt> = {
};
//#endregion Negative Prompt
//#region SDXL Positive Style Prompt
const PositiveStylePrompt: SingleMetadataHandler<ParameterPositiveStylePromptSDXL> = {
[SingleMetadataKey]: true,
type: 'PositiveStylePrompt',
parse: (metadata, _store) => {
const raw = getProperty(metadata, 'positive_style_prompt');
const parsed = zParameterPositiveStylePromptSDXL.parse(raw);
return Promise.resolve(parsed);
},
recall: (value, store) => {
store.dispatch(positivePrompt2Changed(value));
},
i18nKey: 'sdxl.posStylePrompt',
LabelComponent: MetadataLabel,
ValueComponent: ({ value }: SingleMetadataValueProps<ParameterPositiveStylePromptSDXL>) => (
<MetadataPrimitiveValue value={value} />
),
};
//#endregion SDXL Positive Style Prompt
//#region SDXL Negative Style Prompt
const NegativeStylePrompt: SingleMetadataHandler<ParameterPositiveStylePromptSDXL> = {
[SingleMetadataKey]: true,
type: 'NegativeStylePrompt',
parse: (metadata, _store) => {
const raw = getProperty(metadata, 'negative_style_prompt');
const parsed = zParameterNegativeStylePromptSDXL.parse(raw);
return Promise.resolve(parsed);
},
recall: (value, store) => {
store.dispatch(negativePrompt2Changed(value));
},
i18nKey: 'sdxl.negStylePrompt',
LabelComponent: MetadataLabel,
ValueComponent: ({ value }: SingleMetadataValueProps<ParameterPositiveStylePromptSDXL>) => (
<MetadataPrimitiveValue value={value} />
),
};
//#endregion SDXL Negative Style Prompt
//#region CFG Scale
const CFGScale: SingleMetadataHandler<ParameterCFGScale> = {
[SingleMetadataKey]: true,
@@ -927,8 +881,6 @@ export const MetadataHandlers = {
GenerationMode,
PositivePrompt,
NegativePrompt,
PositiveStylePrompt,
NegativeStylePrompt,
CFGScale,
CFGRescaleMultiplier,
Guidance,
@@ -1052,26 +1004,6 @@ const recallByHandlers = async (arg: {
}
}
// We may need to update the prompt concat flag based on the recalled prompts
const positivePrompt = recalled.get(MetadataHandlers.PositivePrompt);
const negativePrompt = recalled.get(MetadataHandlers.NegativePrompt);
const positiveStylePrompt = recalled.get(MetadataHandlers.PositiveStylePrompt);
const negativeStylePrompt = recalled.get(MetadataHandlers.NegativeStylePrompt);
// The values will be undefined if the handler was not recalled
if (
positivePrompt !== undefined ||
negativePrompt !== undefined ||
positiveStylePrompt !== undefined ||
negativeStylePrompt !== undefined
) {
const concat =
(Boolean(positiveStylePrompt) && positiveStylePrompt === positivePrompt) ||
(Boolean(negativeStylePrompt) && negativeStylePrompt === negativePrompt);
store.dispatch(shouldConcatPromptsChanged(concat));
}
if (!silent) {
if (recalled.size > 0) {
toast({
@@ -1094,12 +1026,7 @@ const recallByHandlers = async (arg: {
const recallPrompts = async (metadata: unknown, store: AppStore) => {
const recalled = await recallByHandlers({
metadata,
handlers: [
MetadataHandlers.PositivePrompt,
MetadataHandlers.NegativePrompt,
MetadataHandlers.PositiveStylePrompt,
MetadataHandlers.NegativeStylePrompt,
],
handlers: [MetadataHandlers.PositivePrompt, MetadataHandlers.NegativePrompt],
store,
silent: true,
});

View File

@@ -115,7 +115,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
type: 'sdxl_compel_prompt',
id: getPrefixedId('neg_cond'),
prompt: prompts.negative,
style: prompts.negativeStyle,
style: prompts.negative,
});
modelLoader = g.addNode({
type: 'sdxl_model_loader',
@@ -130,23 +130,14 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
g.addEdge(modelLoader, 'unet', tiledMultidiffusion, 'unet');
g.addEdge(positivePrompt, 'value', posCond, 'prompt');
g.addEdge(positivePrompt, 'value', posCond, 'style');
addSDXLLoRAs(state, g, tiledMultidiffusion, modelLoader, null, posCond, negCond);
g.upsertMetadata({
negative_prompt: prompts.negative,
negative_style_prompt: prompts.negativeStyle,
});
g.addEdgeToMetadata(positivePrompt, 'value', 'positive_prompt');
if (prompts.useMainPromptsForStyle) {
g.addEdge(positivePrompt, 'value', posCond, 'style');
g.addEdgeToMetadata(positivePrompt, 'value', 'positive_style_prompt');
} else {
posCond.style = prompts.positiveStyle;
g.upsertMetadata({ positive_style_prompt: prompts.positiveStyle });
}
} else {
const prompts = selectPresetModifiedPrompts(state);

View File

@@ -78,7 +78,7 @@ export const buildSDXLGraph = async (arg: GraphBuilderArg): Promise<GraphBuilder
type: 'sdxl_compel_prompt',
id: getPrefixedId('neg_cond'),
prompt: prompts.negative,
style: prompts.useMainPromptsForStyle ? prompts.negative : prompts.negativeStyle,
style: prompts.negative,
});
const negCondCollect = g.addNode({
type: 'collect',
@@ -123,6 +123,8 @@ export const buildSDXLGraph = async (arg: GraphBuilderArg): Promise<GraphBuilder
g.addEdge(modelLoader, 'clip2', negCond, 'clip2');
g.addEdge(positivePrompt, 'value', posCond, 'prompt');
g.addEdge(positivePrompt, 'value', posCond, 'style');
g.addEdge(posCond, 'conditioning', posCondCollect, 'item');
g.addEdge(posCondCollect, 'collection', denoise, 'positive_conditioning');
@@ -141,19 +143,12 @@ export const buildSDXLGraph = async (arg: GraphBuilderArg): Promise<GraphBuilder
rand_device: shouldUseCpuNoise ? 'cpu' : 'cuda',
scheduler,
negative_prompt: prompts.negative,
negative_style_prompt: prompts.useMainPromptsForStyle ? prompts.negative : prompts.negativeStyle,
vae: vae ?? undefined,
});
g.addEdgeToMetadata(seed, 'value', 'seed');
g.addEdgeToMetadata(positivePrompt, 'value', 'positive_prompt');
if (prompts.useMainPromptsForStyle) {
g.addEdge(positivePrompt, 'value', posCond, 'style');
g.addEdgeToMetadata(positivePrompt, 'value', 'positive_style_prompt');
} else {
posCond.style = prompts.positiveStyle;
g.upsertMetadata({ positive_style_prompt: prompts.positiveStyle });
}
g.addEdgeToMetadata(positivePrompt, 'value', 'positive_style_prompt');
const seamless = addSeamless(state, g, denoise, modelLoader, vaeLoader);

View File

@@ -85,7 +85,7 @@ export const selectPresetModifiedPrompts = createSelector(
selectListStylePresetsRequestState,
(params, stylePresetSlice, listStylePresetsRequestState) => {
const negativePrompt = params.negativePrompt ?? '';
const { positivePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } = params;
const { positivePrompt } = params;
const { activeStylePresetId } = stylePresetSlice;
if (activeStylePresetId) {
@@ -107,9 +107,6 @@ export const selectPresetModifiedPrompts = createSelector(
return {
positive: presetModifiedPositivePrompt,
negative: presetModifiedNegativePrompt,
positiveStyle: positivePrompt2,
negativeStyle: negativePrompt2,
useMainPromptsForStyle: shouldConcatPrompts,
};
}
}
@@ -117,9 +114,6 @@ export const selectPresetModifiedPrompts = createSelector(
return {
positive: positivePrompt,
negative: negativePrompt,
positiveStyle: positivePrompt2,
negativeStyle: negativePrompt2,
useMainPromptsForStyle: shouldConcatPrompts,
};
}
);

View File

@@ -4,7 +4,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { usePersistedTextAreaSize } from 'common/hooks/usePersistedTextareaSize';
import {
positivePromptChanged,
selectBase,
selectModelSupportsNegativePrompt,
selectPositivePrompt,
} from 'features/controlLayers/store/paramsSlice';
@@ -21,7 +20,6 @@ import { PromptExpansionOverlay } from 'features/prompt/PromptExpansion/PromptEx
import { promptExpansionApi } from 'features/prompt/PromptExpansion/state';
import { PromptPopover } from 'features/prompt/PromptPopover';
import { usePrompt } from 'features/prompt/usePrompt';
import { SDXLConcatButton } from 'features/sdxl/components/SDXLPrompts/SDXLConcatButton';
import {
selectStylePresetActivePresetId,
selectStylePresetViewMode,
@@ -42,7 +40,6 @@ const persistOptions: Parameters<typeof usePersistedTextAreaSize>[2] = {
export const ParamPositivePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector(selectPositivePrompt);
const baseModel = useAppSelector(selectBase);
const viewMode = useAppSelector(selectStylePresetViewMode);
const activeStylePresetId = useAppSelector(selectStylePresetActivePresetId);
const modelSupportsNegativePrompt = useAppSelector(selectModelSupportsNegativePrompt);
@@ -118,7 +115,6 @@ export const ParamPositivePrompt = memo(() => {
<PromptOverlayButtonWrapper>
<Flex flexDir="column" gap={2} justifyContent="flex-start" alignItems="center">
<AddPromptTriggerButton isOpen={isOpen} onOpen={onOpen} />
{baseModel === 'sdxl' && <SDXLConcatButton />}
<ShowDynamicPromptsPreviewButton />
{modelSupportsNegativePrompt && <NegativePromptToggleButton />}
</Flex>

View File

@@ -1,33 +1,18 @@
import { Flex } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { RefImageList } from 'features/controlLayers/components/RefImage/RefImageList';
import {
createParamsSelector,
selectHasNegativePrompt,
selectModelSupportsNegativePrompt,
} from 'features/controlLayers/store/paramsSlice';
import { selectHasNegativePrompt, selectModelSupportsNegativePrompt } from 'features/controlLayers/store/paramsSlice';
import { ParamNegativePrompt } from 'features/parameters/components/Core/ParamNegativePrompt';
import { ParamPositivePrompt } from 'features/parameters/components/Core/ParamPositivePrompt';
import { ParamSDXLNegativeStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt';
import { ParamSDXLPositiveStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt';
import { memo } from 'react';
const selectWithStylePrompts = createParamsSelector((params) => {
const isSDXL = params.model?.base === 'sdxl';
const shouldConcatPrompts = params.shouldConcatPrompts;
return isSDXL && !shouldConcatPrompts;
});
export const Prompts = memo(() => {
const withStylePrompts = useAppSelector(selectWithStylePrompts);
const modelSupportsNegativePrompt = useAppSelector(selectModelSupportsNegativePrompt);
const hasNegativePrompt = useAppSelector(selectHasNegativePrompt);
return (
<Flex flexDir="column" gap={2}>
<ParamPositivePrompt />
{withStylePrompts && <ParamSDXLPositiveStylePrompt />}
{modelSupportsNegativePrompt && hasNegativePrompt && <ParamNegativePrompt />}
{withStylePrompts && <ParamSDXLNegativeStylePrompt />}
<RefImageList />
</Flex>
);

View File

@@ -1,32 +1,17 @@
import { Flex } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import {
createParamsSelector,
selectHasNegativePrompt,
selectModelSupportsNegativePrompt,
} from 'features/controlLayers/store/paramsSlice';
import { selectHasNegativePrompt, selectModelSupportsNegativePrompt } from 'features/controlLayers/store/paramsSlice';
import { ParamNegativePrompt } from 'features/parameters/components/Core/ParamNegativePrompt';
import { ParamPositivePrompt } from 'features/parameters/components/Core/ParamPositivePrompt';
import { ParamSDXLNegativeStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt';
import { ParamSDXLPositiveStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt';
import { memo } from 'react';
const selectWithStylePrompts = createParamsSelector((params) => {
const isSDXL = params.model?.base === 'sdxl';
const shouldConcatPrompts = params.shouldConcatPrompts;
return isSDXL && !shouldConcatPrompts;
});
export const UpscalePrompts = memo(() => {
const withStylePrompts = useAppSelector(selectWithStylePrompts);
const modelSupportsNegativePrompt = useAppSelector(selectModelSupportsNegativePrompt);
const hasNegativePrompt = useAppSelector(selectHasNegativePrompt);
return (
<Flex flexDir="column" gap={2}>
<ParamPositivePrompt />
{withStylePrompts && <ParamSDXLPositiveStylePrompt />}
{modelSupportsNegativePrompt && hasNegativePrompt && <ParamNegativePrompt />}
{withStylePrompts && <ParamSDXLNegativeStylePrompt />}
</Flex>
);
});

View File

@@ -33,16 +33,6 @@ export const [zParameterNegativePrompt, isParameterNegativePrompt] = buildParame
export type ParameterNegativePrompt = z.infer<typeof zParameterNegativePrompt>;
// #endregion
// #region Positive style prompt (SDXL)
export const [zParameterPositiveStylePromptSDXL, isParameterPositiveStylePromptSDXL] = buildParameter(z.string());
export type ParameterPositiveStylePromptSDXL = z.infer<typeof zParameterPositiveStylePromptSDXL>;
// #endregion
// #region Positive style prompt (SDXL)
export const [zParameterNegativeStylePromptSDXL, isParameterNegativeStylePromptSDXL] = buildParameter(z.string());
export type ParameterNegativeStylePromptSDXL = z.infer<typeof zParameterNegativeStylePromptSDXL>;
// #endregion
// #region Steps
export const [zParameterSteps, isParameterSteps] = buildParameter(z.number().int().min(1));
export type ParameterSteps = z.infer<typeof zParameterSteps>;

View File

@@ -1,65 +0,0 @@
import { Box, Textarea } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { usePersistedTextAreaSize } from 'common/hooks/usePersistedTextareaSize';
import { negativePrompt2Changed, selectNegativePrompt2 } from 'features/controlLayers/store/paramsSlice';
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
import { PromptPopover } from 'features/prompt/PromptPopover';
import { usePrompt } from 'features/prompt/usePrompt';
import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
const persistOptions: Parameters<typeof usePersistedTextAreaSize>[2] = {
trackWidth: false,
trackHeight: true,
};
export const ParamSDXLNegativeStylePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector(selectNegativePrompt2);
const textareaRef = useRef<HTMLTextAreaElement>(null);
usePersistedTextAreaSize('negative_style_prompt', textareaRef, persistOptions);
const { t } = useTranslation();
const handleChange = useCallback(
(v: string) => {
dispatch(negativePrompt2Changed(v));
},
[dispatch]
);
const { onChange, isOpen, onClose, onOpen, onSelect, onKeyDown } = usePrompt({
prompt,
textareaRef: textareaRef,
onChange: handleChange,
});
return (
<PromptPopover isOpen={isOpen} onClose={onClose} onSelect={onSelect} width={textareaRef.current?.clientWidth}>
<Box pos="relative">
<Textarea
className="negative-style-prompt-textarea"
name="prompt"
ref={textareaRef}
value={prompt}
onChange={onChange}
onKeyDown={onKeyDown}
fontSize="sm"
variant="darkFilled"
minH={24}
borderTopWidth={24} // This prevents the prompt from being hidden behind the header
paddingInlineEnd={10}
paddingInlineStart={3}
paddingTop={0}
paddingBottom={3}
/>
<PromptOverlayButtonWrapper>
<AddPromptTriggerButton isOpen={isOpen} onOpen={onOpen} />
</PromptOverlayButtonWrapper>
<PromptLabel label={t('sdxl.negStylePrompt')} />
</Box>
</PromptPopover>
);
});
ParamSDXLNegativeStylePrompt.displayName = 'ParamSDXLNegativeStylePrompt';

View File

@@ -1,65 +0,0 @@
import { Box, Textarea } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { usePersistedTextAreaSize } from 'common/hooks/usePersistedTextareaSize';
import { positivePrompt2Changed, selectPositivePrompt2 } from 'features/controlLayers/store/paramsSlice';
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
import { PromptPopover } from 'features/prompt/PromptPopover';
import { usePrompt } from 'features/prompt/usePrompt';
import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
const persistOptions: Parameters<typeof usePersistedTextAreaSize>[2] = {
trackWidth: false,
trackHeight: true,
};
export const ParamSDXLPositiveStylePrompt = memo(() => {
const dispatch = useAppDispatch();
const prompt = useAppSelector(selectPositivePrompt2);
const textareaRef = useRef<HTMLTextAreaElement>(null);
usePersistedTextAreaSize('positive_style_prompt', textareaRef, persistOptions);
const { t } = useTranslation();
const handleChange = useCallback(
(v: string) => {
dispatch(positivePrompt2Changed(v));
},
[dispatch]
);
const { onChange, isOpen, onClose, onOpen, onSelect, onKeyDown } = usePrompt({
prompt,
textareaRef: textareaRef,
onChange: handleChange,
});
return (
<PromptPopover isOpen={isOpen} onClose={onClose} onSelect={onSelect} width={textareaRef.current?.clientWidth}>
<Box pos="relative">
<Textarea
className="positive-style-prompt-textarea"
name="prompt"
ref={textareaRef}
value={prompt}
onChange={onChange}
onKeyDown={onKeyDown}
fontSize="sm"
variant="darkFilled"
minH={24}
borderTopWidth={24} // This prevents the prompt from being hidden behind the header
paddingInlineEnd={10}
paddingInlineStart={3}
paddingTop={0}
paddingBottom={3}
/>
<PromptOverlayButtonWrapper>
<AddPromptTriggerButton isOpen={isOpen} onOpen={onOpen} />
</PromptOverlayButtonWrapper>
<PromptLabel label={t('sdxl.posStylePrompt')} />
</Box>
</PromptPopover>
);
});
ParamSDXLPositiveStylePrompt.displayName = 'ParamSDXLPositiveStylePrompt';

View File

@@ -1,37 +0,0 @@
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { selectShouldConcatPrompts, shouldConcatPromptsChanged } from 'features/controlLayers/store/paramsSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiLinkSimpleBold, PiLinkSimpleBreakBold } from 'react-icons/pi';
export const SDXLConcatButton = memo(() => {
const shouldConcatPrompts = useAppSelector(selectShouldConcatPrompts);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleShouldConcatPromptChange = useCallback(() => {
dispatch(shouldConcatPromptsChanged(!shouldConcatPrompts));
}, [dispatch, shouldConcatPrompts]);
const label = useMemo(
() => (shouldConcatPrompts ? t('sdxl.concatPromptStyle') : t('sdxl.freePromptStyle')),
[shouldConcatPrompts, t]
);
return (
<Tooltip label={label}>
<IconButton
aria-label={label}
onClick={handleShouldConcatPromptChange}
icon={shouldConcatPrompts ? <PiLinkSimpleBold size={14} /> : <PiLinkSimpleBreakBold size={14} />}
variant="promptOverlay"
fontSize={12}
px={0.5}
/>
</Tooltip>
);
});
SDXLConcatButton.displayName = 'SDXLConcatButton';