@@ -53,7 +53,8 @@ interface IActionMenuTemplateData {
5353
5454export const enum ActionListItemKind {
5555 Action = 'action' ,
56- Header = 'header'
56+ Header = 'header' ,
57+ Separator = 'separator'
5758}
5859
5960interface IHeaderTemplateData {
@@ -83,6 +84,33 @@ class HeaderRenderer<T> implements IListRenderer<IActionListItem<T>, IHeaderTemp
8384 }
8485}
8586
87+ interface ISeparatorTemplateData {
88+ readonly container : HTMLElement ;
89+ readonly text : HTMLElement ;
90+ }
91+
92+ class SeparatorRenderer < T > implements IListRenderer < IActionListItem < T > , ISeparatorTemplateData > {
93+
94+ get templateId ( ) : string { return ActionListItemKind . Separator ; }
95+
96+ renderTemplate ( container : HTMLElement ) : ISeparatorTemplateData {
97+ container . classList . add ( 'separator' ) ;
98+
99+ const text = document . createElement ( 'span' ) ;
100+ container . append ( text ) ;
101+
102+ return { container, text } ;
103+ }
104+
105+ renderElement ( element : IActionListItem < T > , _index : number , templateData : ISeparatorTemplateData ) : void {
106+ templateData . text . textContent = element . label ?? '' ;
107+ }
108+
109+ disposeTemplate ( _templateData : ISeparatorTemplateData ) : void {
110+ // noop
111+ }
112+ }
113+
86114class ActionItemRenderer < T > implements IListRenderer < IActionListItem < T > , IActionMenuTemplateData > {
87115
88116 get templateId ( ) : string { return ActionListItemKind . Action ; }
@@ -176,7 +204,7 @@ class PreviewSelectedEvent extends UIEvent {
176204}
177205
178206function getKeyboardNavigationLabel < T > ( item : IActionListItem < T > ) : string | undefined {
179- // Filter out header vs. action
207+ // Filter out header vs. action vs. separator
180208 if ( item . kind === 'action' ) {
181209 return item . label ;
182210 }
@@ -191,6 +219,7 @@ export class ActionList<T> extends Disposable {
191219
192220 private readonly _actionLineHeight = 24 ;
193221 private readonly _headerLineHeight = 26 ;
222+ private readonly _separatorLineHeight = 8 ;
194223
195224 private readonly _allMenuItems : readonly IActionListItem < T > [ ] ;
196225
@@ -210,14 +239,24 @@ export class ActionList<T> extends Disposable {
210239 this . domNode = document . createElement ( 'div' ) ;
211240 this . domNode . classList . add ( 'actionList' ) ;
212241 const virtualDelegate : IListVirtualDelegate < IActionListItem < T > > = {
213- getHeight : element => element . kind === ActionListItemKind . Header ? this . _headerLineHeight : this . _actionLineHeight ,
242+ getHeight : element => {
243+ switch ( element . kind ) {
244+ case ActionListItemKind . Header :
245+ return this . _headerLineHeight ;
246+ case ActionListItemKind . Separator :
247+ return this . _separatorLineHeight ;
248+ default :
249+ return this . _actionLineHeight ;
250+ }
251+ } ,
214252 getTemplateId : element => element . kind
215253 } ;
216254
217255
218256 this . _list = this . _register ( new List ( user , this . domNode , virtualDelegate , [
219257 new ActionItemRenderer < IActionListItem < T > > ( preview , this . _keybindingService ) ,
220258 new HeaderRenderer ( ) ,
259+ new SeparatorRenderer ( ) ,
221260 ] , {
222261 keyboardSupport : false ,
223262 typeNavigationEnabled : true ,
@@ -234,7 +273,16 @@ export class ActionList<T> extends Disposable {
234273 return null ;
235274 } ,
236275 getWidgetAriaLabel : ( ) => localize ( { key : 'customQuickFixWidget' , comment : [ `An action widget option` ] } , "Action Widget" ) ,
237- getRole : ( e ) => e . kind === ActionListItemKind . Action ? 'option' : 'separator' ,
276+ getRole : ( e ) => {
277+ switch ( e . kind ) {
278+ case ActionListItemKind . Action :
279+ return 'option' ;
280+ case ActionListItemKind . Separator :
281+ return 'separator' ;
282+ default :
283+ return 'separator' ;
284+ }
285+ } ,
238286 getWidgetRole : ( ) => 'listbox' ,
239287 ...accessibilityProvider
240288 } ,
@@ -268,9 +316,11 @@ export class ActionList<T> extends Disposable {
268316 layout ( minWidth : number ) : number {
269317 // Updating list height, depending on how many separators and headers there are.
270318 const numHeaders = this . _allMenuItems . filter ( item => item . kind === 'header' ) . length ;
319+ const numSeparators = this . _allMenuItems . filter ( item => item . kind === 'separator' ) . length ;
271320 const itemsHeight = this . _allMenuItems . length * this . _actionLineHeight ;
272321 const heightWithHeaders = itemsHeight + numHeaders * this . _headerLineHeight - numHeaders * this . _actionLineHeight ;
273- this . _list . layout ( heightWithHeaders ) ;
322+ const heightWithSeparators = heightWithHeaders + numSeparators * this . _separatorLineHeight - numSeparators * this . _actionLineHeight ;
323+ this . _list . layout ( heightWithSeparators ) ;
274324 let maxWidth = minWidth ;
275325
276326 if ( this . _allMenuItems . length >= 50 ) {
@@ -293,7 +343,7 @@ export class ActionList<T> extends Disposable {
293343 }
294344
295345 const maxVhPrecentage = 0.7 ;
296- const height = Math . min ( heightWithHeaders , this . _layoutService . getContainer ( dom . getWindow ( this . domNode ) ) . clientHeight * maxVhPrecentage ) ;
346+ const height = Math . min ( heightWithSeparators , this . _layoutService . getContainer ( dom . getWindow ( this . domNode ) ) . clientHeight * maxVhPrecentage ) ;
297347 this . _list . layout ( height , maxWidth ) ;
298348
299349 this . domNode . style . height = `${ height } px` ;
0 commit comments