@@ -115,14 +115,24 @@ const ModesView = ({ onDone }: ModesViewProps) => {
115115 const [ searchValue , setSearchValue ] = useState ( "" )
116116 const searchInputRef = useRef < HTMLInputElement > ( null )
117117
118- // Local state for all editable fields to allow visual emptying but prevent saving empty values
119- const [ localModeName , setLocalModeName ] = useState < string > ( "" )
120- const [ localModeDescription , setLocalModeDescription ] = useState < string > ( "" )
121- const [ localModeRoleDefinition , setLocalModeRoleDefinition ] = useState < string > ( "" )
122- const [ localModeWhenToUse , setLocalModeWhenToUse ] = useState < string > ( "" )
123- const [ localModeCustomInstructions , setLocalModeCustomInstructions ] = useState < string > ( "" )
124- const [ currentEditingModeSlug , setCurrentEditingModeSlug ] = useState < string | null > ( null )
125- const [ currentEditingField , setCurrentEditingField ] = useState < string | null > ( null )
118+ // Consolidated local state for all editable fields to allow visual emptying but prevent saving empty values
119+ const [ editingState , setEditingState ] = useState < {
120+ modeName : string
121+ modeDescription : string
122+ modeRoleDefinition : string
123+ modeWhenToUse : string
124+ modeCustomInstructions : string
125+ currentEditingModeSlug : string | null
126+ currentEditingField : string | null
127+ } > ( {
128+ modeName : "" ,
129+ modeDescription : "" ,
130+ modeRoleDefinition : "" ,
131+ modeWhenToUse : "" ,
132+ modeCustomInstructions : "" ,
133+ currentEditingModeSlug : null ,
134+ currentEditingField : null ,
135+ } )
126136
127137 // Direct update functions
128138 const updateAgentPrompt = useCallback (
@@ -234,16 +244,33 @@ const ModesView = ({ onDone }: ModesViewProps) => {
234244
235245 // Reset all local state when mode changes
236246 useEffect ( ( ) => {
237- if ( currentEditingModeSlug && currentEditingModeSlug !== visualMode ) {
238- setCurrentEditingModeSlug ( null )
239- setCurrentEditingField ( null )
240- setLocalModeName ( "" )
241- setLocalModeDescription ( "" )
242- setLocalModeRoleDefinition ( "" )
243- setLocalModeWhenToUse ( "" )
244- setLocalModeCustomInstructions ( "" )
247+ if ( editingState . currentEditingModeSlug && editingState . currentEditingModeSlug !== visualMode ) {
248+ setEditingState ( {
249+ modeName : "" ,
250+ modeDescription : "" ,
251+ modeRoleDefinition : "" ,
252+ modeWhenToUse : "" ,
253+ modeCustomInstructions : "" ,
254+ currentEditingModeSlug : null ,
255+ currentEditingField : null ,
256+ } )
257+ }
258+ } , [ visualMode , editingState . currentEditingModeSlug ] )
259+
260+ // Cleanup state on component unmount to prevent memory leaks
261+ useEffect ( ( ) => {
262+ return ( ) => {
263+ setEditingState ( {
264+ modeName : "" ,
265+ modeDescription : "" ,
266+ modeRoleDefinition : "" ,
267+ modeWhenToUse : "" ,
268+ modeCustomInstructions : "" ,
269+ currentEditingModeSlug : null ,
270+ currentEditingField : null ,
271+ } )
245272 }
246- } , [ visualMode , currentEditingModeSlug ] )
273+ } , [ ] )
247274
248275 // Helper function to safely access mode properties
249276 const getModeProperty = < T extends keyof ModeConfig > (
@@ -753,33 +780,42 @@ const ModesView = ({ onDone }: ModesViewProps) => {
753780 < Input
754781 type = "text"
755782 value = {
756- currentEditingModeSlug === visualMode
757- ? localModeName
783+ editingState . currentEditingModeSlug === visualMode
784+ ? editingState . modeName
758785 : ( getModeProperty ( findModeBySlug ( visualMode , customModes ) , "name" ) ??
759786 "" )
760787 }
761788 onFocus = { ( ) => {
762789 const customMode = findModeBySlug ( visualMode , customModes )
763790 if ( customMode ) {
764- setCurrentEditingModeSlug ( visualMode )
765- setLocalModeName ( customMode . name )
791+ setEditingState ( prev => ( {
792+ ...prev ,
793+ currentEditingModeSlug : visualMode ,
794+ modeName : customMode . name
795+ } ) )
766796 }
767797 } }
768798 onChange = { ( e ) => {
769- setLocalModeName ( e . target . value )
799+ setEditingState ( prev => ( {
800+ ...prev ,
801+ modeName : e . target . value
802+ } ) )
770803 } }
771804 onBlur = { ( ) => {
772805 const customMode = findModeBySlug ( visualMode , customModes )
773- if ( customMode && localModeName . trim ( ) ) {
806+ if ( customMode && editingState . modeName . trim ( ) ) {
774807 // Only update if the name is not empty
775808 updateCustomMode ( visualMode , {
776809 ...customMode ,
777- name : localModeName ,
810+ name : editingState . modeName ,
778811 source : customMode . source || "global" ,
779812 } )
780813 }
781814 // Clear the editing state
782- setCurrentEditingModeSlug ( null )
815+ setEditingState ( prev => ( {
816+ ...prev ,
817+ currentEditingModeSlug : null
818+ } ) )
783819 } }
784820 className = "w-full"
785821 />
@@ -842,8 +878,8 @@ const ModesView = ({ onDone }: ModesViewProps) => {
842878 const prompt = customModePrompts ?. [ visualMode ] as PromptComponent
843879
844880 // Use local state if currently editing this field
845- if ( currentEditingField === "roleDefinition" && currentEditingModeSlug === visualMode ) {
846- return localModeRoleDefinition
881+ if ( editingState . currentEditingField === "roleDefinition" && editingState . currentEditingModeSlug === visualMode ) {
882+ return editingState . modeRoleDefinition
847883 }
848884
849885 return (
@@ -859,37 +895,46 @@ const ModesView = ({ onDone }: ModesViewProps) => {
859895 prompt ?. roleDefinition ??
860896 getRoleDefinition ( visualMode )
861897
862- setCurrentEditingModeSlug ( visualMode )
863- setCurrentEditingField ( "roleDefinition" )
864- setLocalModeRoleDefinition ( currentValue )
898+ setEditingState ( prev => ( {
899+ ...prev ,
900+ currentEditingModeSlug : visualMode ,
901+ currentEditingField : "roleDefinition" ,
902+ modeRoleDefinition : currentValue
903+ } ) )
865904 } }
866905 onChange = { ( e ) => {
867906 const value = extractEventValue ( e )
868- setLocalModeRoleDefinition ( value )
907+ setEditingState ( prev => ( {
908+ ...prev ,
909+ modeRoleDefinition : value
910+ } ) )
869911 } }
870912 onBlur = { ( ) => {
871913 const customMode = findModeBySlug ( visualMode , customModes )
872914
873915 // Only save if the value is not empty
874- if ( localModeRoleDefinition . trim ( ) ) {
916+ if ( editingState . modeRoleDefinition . trim ( ) ) {
875917 if ( customMode ) {
876918 // For custom modes, update the JSON file
877919 updateCustomMode ( visualMode , {
878920 ...customMode ,
879- roleDefinition : localModeRoleDefinition . trim ( ) ,
921+ roleDefinition : editingState . modeRoleDefinition . trim ( ) ,
880922 source : customMode . source || "global" ,
881923 } )
882924 } else {
883925 // For built-in modes, update the prompts
884926 updateAgentPrompt ( visualMode , {
885- roleDefinition : localModeRoleDefinition . trim ( ) ,
927+ roleDefinition : editingState . modeRoleDefinition . trim ( ) ,
886928 } )
887929 }
888930 }
889931
890932 // Clear the editing state
891- setCurrentEditingField ( null )
892- setCurrentEditingModeSlug ( null )
933+ setEditingState ( prev => ( {
934+ ...prev ,
935+ currentEditingField : null ,
936+ currentEditingModeSlug : null
937+ } ) )
893938 } }
894939 className = "w-full"
895940 rows = { 5 }
@@ -927,8 +972,8 @@ const ModesView = ({ onDone }: ModesViewProps) => {
927972 const prompt = customModePrompts ?. [ visualMode ] as PromptComponent
928973
929974 // Use local state if currently editing this field
930- if ( currentEditingField === "description" && currentEditingModeSlug === visualMode ) {
931- return localModeDescription
975+ if ( editingState . currentEditingField === "description" && editingState . currentEditingModeSlug === visualMode ) {
976+ return editingState . modeDescription
932977 }
933978
934979 return customMode ?. description ?? prompt ?. description ?? getDescription ( visualMode )
@@ -940,19 +985,25 @@ const ModesView = ({ onDone }: ModesViewProps) => {
940985 prompt ?. description ??
941986 getDescription ( visualMode )
942987
943- setCurrentEditingModeSlug ( visualMode )
944- setCurrentEditingField ( "description" )
945- setLocalModeDescription ( currentValue || "" )
988+ setEditingState ( prev => ( {
989+ ...prev ,
990+ currentEditingModeSlug : visualMode ,
991+ currentEditingField : "description" ,
992+ modeDescription : currentValue || ""
993+ } ) )
946994 } }
947995 onChange = { ( e ) => {
948996 const value = extractEventValue ( e )
949- setLocalModeDescription ( value )
997+ setEditingState ( prev => ( {
998+ ...prev ,
999+ modeDescription : value
1000+ } ) )
9501001 } }
9511002 onBlur = { ( ) => {
9521003 const customMode = findModeBySlug ( visualMode , customModes )
9531004
9541005 // For description, allow empty values (they become undefined)
955- const trimmedValue = localModeDescription . trim ( )
1006+ const trimmedValue = editingState . modeDescription . trim ( )
9561007 const finalValue = trimmedValue || undefined
9571008
9581009 if ( customMode ) {
@@ -970,8 +1021,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
9701021 }
9711022
9721023 // Clear the editing state
973- setCurrentEditingField ( null )
974- setCurrentEditingModeSlug ( null )
1024+ setEditingState ( prev => ( {
1025+ ...prev ,
1026+ currentEditingField : null ,
1027+ currentEditingModeSlug : null
1028+ } ) )
9751029 } }
9761030 className = "w-full"
9771031 data-testid = { `${ getCurrentMode ( ) ?. slug || "code" } -description-textfield` }
@@ -1009,8 +1063,8 @@ const ModesView = ({ onDone }: ModesViewProps) => {
10091063 const prompt = customModePrompts ?. [ visualMode ] as PromptComponent
10101064
10111065 // Use local state if currently editing this field
1012- if ( currentEditingField === "whenToUse" && currentEditingModeSlug === visualMode ) {
1013- return localModeWhenToUse
1066+ if ( editingState . currentEditingField === "whenToUse" && editingState . currentEditingModeSlug === visualMode ) {
1067+ return editingState . modeWhenToUse
10141068 }
10151069
10161070 return customMode ?. whenToUse ?? prompt ?. whenToUse ?? getWhenToUse ( visualMode )
@@ -1022,19 +1076,25 @@ const ModesView = ({ onDone }: ModesViewProps) => {
10221076 prompt ?. whenToUse ??
10231077 getWhenToUse ( visualMode )
10241078
1025- setCurrentEditingModeSlug ( visualMode )
1026- setCurrentEditingField ( "whenToUse" )
1027- setLocalModeWhenToUse ( currentValue || "" )
1079+ setEditingState ( prev => ( {
1080+ ...prev ,
1081+ currentEditingModeSlug : visualMode ,
1082+ currentEditingField : "whenToUse" ,
1083+ modeWhenToUse : currentValue || ""
1084+ } ) )
10281085 } }
10291086 onChange = { ( e ) => {
10301087 const value = extractEventValue ( e )
1031- setLocalModeWhenToUse ( value )
1088+ setEditingState ( prev => ( {
1089+ ...prev ,
1090+ modeWhenToUse : value
1091+ } ) )
10321092 } }
10331093 onBlur = { ( ) => {
10341094 const customMode = findModeBySlug ( visualMode , customModes )
10351095
10361096 // For whenToUse, allow empty values (they become undefined)
1037- const trimmedValue = localModeWhenToUse . trim ( )
1097+ const trimmedValue = editingState . modeWhenToUse . trim ( )
10381098 const finalValue = trimmedValue || undefined
10391099
10401100 if ( customMode ) {
@@ -1052,8 +1112,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
10521112 }
10531113
10541114 // Clear the editing state
1055- setCurrentEditingField ( null )
1056- setCurrentEditingModeSlug ( null )
1115+ setEditingState ( prev => ( {
1116+ ...prev ,
1117+ currentEditingField : null ,
1118+ currentEditingModeSlug : null
1119+ } ) )
10571120 } }
10581121 className = "w-full"
10591122 rows = { 4 }
@@ -1191,8 +1254,8 @@ const ModesView = ({ onDone }: ModesViewProps) => {
11911254 const prompt = customModePrompts ?. [ visualMode ] as PromptComponent
11921255
11931256 // Use local state if currently editing this field
1194- if ( currentEditingField === "customInstructions" && currentEditingModeSlug === visualMode ) {
1195- return localModeCustomInstructions
1257+ if ( editingState . currentEditingField === "customInstructions" && editingState . currentEditingModeSlug === visualMode ) {
1258+ return editingState . modeCustomInstructions
11961259 }
11971260
11981261 return (
@@ -1208,19 +1271,25 @@ const ModesView = ({ onDone }: ModesViewProps) => {
12081271 prompt ?. customInstructions ??
12091272 getCustomInstructions ( mode , customModes )
12101273
1211- setCurrentEditingModeSlug ( visualMode )
1212- setCurrentEditingField ( "customInstructions" )
1213- setLocalModeCustomInstructions ( currentValue || "" )
1274+ setEditingState ( prev => ( {
1275+ ...prev ,
1276+ currentEditingModeSlug : visualMode ,
1277+ currentEditingField : "customInstructions" ,
1278+ modeCustomInstructions : currentValue || ""
1279+ } ) )
12141280 } }
12151281 onChange = { ( e ) => {
12161282 const value = extractEventValue ( e )
1217- setLocalModeCustomInstructions ( value )
1283+ setEditingState ( prev => ( {
1284+ ...prev ,
1285+ modeCustomInstructions : value
1286+ } ) )
12181287 } }
12191288 onBlur = { ( ) => {
12201289 const customMode = findModeBySlug ( visualMode , customModes )
12211290
12221291 // For customInstructions, allow empty values (they become undefined)
1223- const trimmedValue = localModeCustomInstructions . trim ( )
1292+ const trimmedValue = editingState . modeCustomInstructions . trim ( )
12241293 const finalValue = trimmedValue || undefined
12251294
12261295 if ( customMode ) {
@@ -1240,8 +1309,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
12401309 }
12411310
12421311 // Clear the editing state
1243- setCurrentEditingField ( null )
1244- setCurrentEditingModeSlug ( null )
1312+ setEditingState ( prev => ( {
1313+ ...prev ,
1314+ currentEditingField : null ,
1315+ currentEditingModeSlug : null
1316+ } ) )
12451317 } }
12461318 rows = { 10 }
12471319 className = "w-full"
0 commit comments