Skip to content

Commit a589dec

Browse files
Mary Hipppsychedelicious
authored andcommitted
store positive prompt textarea height in redux so it persists across refresh
1 parent bc67d5c commit a589dec

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

invokeai/frontend/web/src/features/parameters/components/Core/ParamPositivePrompt.tsx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import {
1414
selectStylePresetViewMode,
1515
} from 'features/stylePresets/store/stylePresetSlice';
1616
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
17-
import { memo, useCallback, useRef } from 'react';
17+
import { positivePromptBoxHeightChanged, selectPositivePromptBoxHeight } from 'features/ui/store/uiSlice';
18+
import { debounce } from 'lodash-es';
19+
import { memo, useCallback, useEffect, useRef } from 'react';
1820
import type { HotkeyCallback } from 'react-hotkeys-hook';
1921
import { useTranslation } from 'react-i18next';
2022
import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
@@ -25,6 +27,7 @@ export const ParamPositivePrompt = memo(() => {
2527
const baseModel = useAppSelector(selectBase);
2628
const viewMode = useAppSelector(selectStylePresetViewMode);
2729
const activeStylePresetId = useAppSelector(selectStylePresetActivePresetId);
30+
const positivePromptBoxHeight = useAppSelector(selectPositivePromptBoxHeight);
2831

2932
const { activeStylePreset } = useListStylePresetsQuery(undefined, {
3033
selectFromResult: ({ data }) => {
@@ -50,6 +53,45 @@ export const ParamPositivePrompt = memo(() => {
5053
onChange: handleChange,
5154
});
5255

56+
// Add debounced resize observer to detect height changes
57+
useEffect(() => {
58+
const textarea = textareaRef.current;
59+
if (!textarea) {
60+
return;
61+
}
62+
63+
let currentHeight = textarea.offsetHeight;
64+
65+
const debouncedHeightUpdate = debounce((newHeight: number) => {
66+
dispatch(positivePromptBoxHeightChanged(newHeight));
67+
}, 150);
68+
69+
const resizeObserver = new ResizeObserver((entries) => {
70+
for (const entry of entries) {
71+
const newHeight = (entry.target as HTMLTextAreaElement).offsetHeight;
72+
if (newHeight !== currentHeight) {
73+
currentHeight = newHeight;
74+
debouncedHeightUpdate(newHeight);
75+
}
76+
}
77+
});
78+
79+
resizeObserver.observe(textarea);
80+
return () => {
81+
resizeObserver.disconnect();
82+
debouncedHeightUpdate.cancel();
83+
};
84+
}, [dispatch]);
85+
86+
useEffect(() => {
87+
const textarea = textareaRef.current;
88+
if (!textarea) {
89+
return;
90+
}
91+
92+
textarea.style.height = `${positivePromptBoxHeight}px`;
93+
}, [positivePromptBoxHeight]);
94+
5395
const focus: HotkeyCallback = useCallback(
5496
(e) => {
5597
onFocus();
@@ -75,14 +117,14 @@ export const ParamPositivePrompt = memo(() => {
75117
ref={textareaRef}
76118
value={prompt}
77119
onChange={onChange}
78-
minH={40}
79120
onKeyDown={onKeyDown}
80121
variant="darkFilled"
81122
borderTopWidth={24} // This prevents the prompt from being hidden behind the header
82123
paddingInlineEnd={10}
83124
paddingInlineStart={3}
84125
paddingTop={0}
85126
paddingBottom={3}
127+
resize="vertical"
86128
/>
87129
<PromptOverlayButtonWrapper>
88130
<AddPromptTriggerButton isOpen={isOpen} onOpen={onOpen} />

invokeai/frontend/web/src/features/ui/store/uiSlice.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const initialUIState: UIState = {
1616
accordions: {},
1717
expanders: {},
1818
shouldShowNotificationV2: true,
19+
positivePromptBoxHeight: 40,
1920
};
2021

2122
export const uiSlice = createSlice({
@@ -45,6 +46,9 @@ export const uiSlice = createSlice({
4546
shouldShowNotificationChanged: (state, action: PayloadAction<boolean>) => {
4647
state.shouldShowNotificationV2 = action.payload;
4748
},
49+
positivePromptBoxHeightChanged: (state, action: PayloadAction<number>) => {
50+
state.positivePromptBoxHeight = action.payload;
51+
},
4852
},
4953
extraReducers(builder) {
5054
builder.addCase(workflowLoaded, (state) => {
@@ -64,6 +68,7 @@ export const {
6468
accordionStateChanged,
6569
expanderStateChanged,
6670
shouldShowNotificationChanged,
71+
positivePromptBoxHeightChanged,
6772
} = uiSlice.actions;
6873

6974
export const selectUiSlice = (state: RootState) => state.ui;
@@ -100,3 +105,5 @@ const TABS_WITH_RIGHT_PANEL: TabName[] = ['canvas', 'upscaling', 'workflows'] as
100105
export const RIGHT_PANEL_MIN_SIZE_PX = 390;
101106
export const $isRightPanelOpen = atom(true);
102107
export const selectWithRightPanel = createSelector(selectUiSlice, (ui) => TABS_WITH_RIGHT_PANEL.includes(ui.activeTab));
108+
109+
export const selectPositivePromptBoxHeight = createSelector(selectUiSlice, (ui) => ui.positivePromptBoxHeight);

invokeai/frontend/web/src/features/ui/store/uiTypes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ export interface UIState {
3434
* Whether or not to show the user the open notification. Bump version to reset users who may have closed previous version.
3535
*/
3636
shouldShowNotificationV2: boolean;
37+
/**
38+
* The height of the positive prompt box.
39+
*/
40+
positivePromptBoxHeight: number;
3741
}

0 commit comments

Comments
 (0)