@@ -166,6 +166,22 @@ function SvgIcon({ svg }: { svg: string }) {
166166 return < span class = "toolbar-item-icon" dangerouslySetInnerHTML = { { __html : svg } } /> ;
167167}
168168
169+ /** Stable list key for a toolbar item. Commands are unique, so the name alone suffices;
170+ * separators and groups include the index to handle multiples. */
171+ function itemKey ( item : ToolbarItem , idx : number ) : string {
172+ if ( item === "|" ) return `sep_${ idx } ` ;
173+ if ( typeof item === "object" ) return `grp_${ ( item as ToolbarGroup ) . label } _${ idx } ` ;
174+ return item ; // command names are guaranteed unique in the toolbar
175+ }
176+
177+ /** Returns a copy of `group` with `item` inserted at `insertAt`, or appended if undefined. */
178+ function insertIntoGroup ( group : ToolbarGroup , item : string , insertAt : number | undefined ) : ToolbarGroup {
179+ const sub = [ ...group . items ] ;
180+ if ( insertAt === undefined ) sub . push ( item ) ;
181+ else sub . splice ( insertAt , 0 , item ) ;
182+ return { ...group , items : sub } ;
183+ }
184+
169185function parseConfig ( configStr : string ) : ToolbarItem [ ] {
170186 if ( ! configStr ) return [ ...DEFAULT_CLASSIC_TOOLBAR_ITEMS ] ;
171187 try {
@@ -392,13 +408,9 @@ export default function ToolbarCustomization() {
392408 const withoutItem = pending . filter ( ( _ , i ) => i !== topIdx ) ;
393409 const adjGroup = topIdx < groupIdx ? groupIdx - 1 : groupIdx ;
394410
395- const result = withoutItem . map ( ( g , i ) => {
396- if ( i !== adjGroup || typeof g !== "object" ) return g ;
397- const sub = [ ...( g as ToolbarGroup ) . items ] ;
398- if ( insertAt === undefined ) sub . push ( item as string ) ;
399- else sub . splice ( insertAt , 0 , item as string ) ;
400- return { ...( g as ToolbarGroup ) , items : sub } ;
401- } ) ;
411+ const result = withoutItem . map ( ( g , i ) =>
412+ i === adjGroup && typeof g === "object" ? insertIntoGroup ( g as ToolbarGroup , item as string , insertAt ) : g
413+ ) ;
402414
403415 setExpandedGroup ( adjGroup ) ;
404416 update ( result ) ;
@@ -437,12 +449,7 @@ export default function ToolbarCustomization() {
437449 const result = pending . map ( ( g , i ) => {
438450 if ( typeof g !== "object" ) return g ;
439451 if ( i === fromGroupIdx ) return { ...( g as ToolbarGroup ) , items : ( g as ToolbarGroup ) . items . filter ( ( _ , j ) => j !== itemIdx ) } ;
440- if ( i === toGroupIdx ) {
441- const sub = [ ...( g as ToolbarGroup ) . items ] ;
442- if ( insertAt === undefined ) sub . push ( item ) ;
443- else sub . splice ( insertAt , 0 , item ) ;
444- return { ...( g as ToolbarGroup ) , items : sub } ;
445- }
452+ if ( i === toGroupIdx ) return insertIntoGroup ( g as ToolbarGroup , item , insertAt ) ;
446453 return g ;
447454 } ) ;
448455 setExpandedGroup ( toGroupIdx ) ;
@@ -495,7 +502,7 @@ export default function ToolbarCustomization() {
495502 ) }
496503 { pending . map ( ( item , idx ) => (
497504 < ToolbarRow
498- key = { idx }
505+ key = { itemKey ( item , idx ) }
499506 item = { item }
500507 isExpanded = { expandedGroup === idx }
501508 isDropTarget = { dropTarget ?. kind === "top" && dropTarget . index === idx }
0 commit comments