Skip to content

Commit 2fa8d0c

Browse files
authored
Merge pull request microsoft#209604 from microsoft/benibenj/governing-caterpillar
Add customizable colors for tree sticky scroll
2 parents 884c8a6 + ab4e8b5 commit 2fa8d0c

File tree

23 files changed

+148
-69
lines changed

23 files changed

+148
-69
lines changed

build/lib/stylelint/vscode-known-variables.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,9 @@
491491
"--vscode-panelTitle-activeBorder",
492492
"--vscode-panelTitle-activeForeground",
493493
"--vscode-panelTitle-inactiveForeground",
494+
"--vscode-panelStickyScroll-background",
495+
"--vscode-panelStickyScroll-border",
496+
"--vscode-panelStickyScroll-shadow",
494497
"--vscode-peekView-border",
495498
"--vscode-peekViewEditor-background",
496499
"--vscode-peekViewEditor-matchHighlightBackground",
@@ -567,6 +570,9 @@
567570
"--vscode-sideBarSectionHeader-foreground",
568571
"--vscode-sideBarTitle-background",
569572
"--vscode-sideBarTitle-foreground",
573+
"--vscode-sideBarStickyScroll-background",
574+
"--vscode-sideBarStickyScroll-border",
575+
"--vscode-sideBarStickyScroll-shadow",
570576
"--vscode-sideBySideEditor-horizontalBorder",
571577
"--vscode-sideBySideEditor-verticalBorder",
572578
"--vscode-simpleFindWidget-sashBorder",

src/vs/base/browser/ui/list/listWidget.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,9 @@ export interface IListStyles {
10941094
listHoverOutline: string | undefined;
10951095
treeIndentGuidesStroke: string | undefined;
10961096
treeInactiveIndentGuidesStroke: string | undefined;
1097+
treeStickyScrollBackground: string | undefined;
1098+
treeStickyScrollBorder: string | undefined;
1099+
treeStickyScrollShadow: string | undefined;
10971100
tableColumnsBorder: string | undefined;
10981101
tableOddRowsBackgroundColor: string | undefined;
10991102
}
@@ -1124,7 +1127,10 @@ export const unthemedListStyles: IListStyles = {
11241127
listFocusOutline: undefined,
11251128
listInactiveFocusOutline: undefined,
11261129
listSelectionOutline: undefined,
1127-
listHoverOutline: undefined
1130+
listHoverOutline: undefined,
1131+
treeStickyScrollBackground: undefined,
1132+
treeStickyScrollBorder: undefined,
1133+
treeStickyScrollShadow: undefined
11281134
};
11291135

11301136
const DefaultOptions: IListOptions<any> = {

src/vs/base/browser/ui/tree/abstractTree.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,9 +2772,20 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
27722772
}
27732773

27742774
// Sticky Scroll Background
2775-
if (styles.listBackground) {
2776-
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { background-color: ${styles.listBackground}; }`);
2777-
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row { background-color: ${styles.listBackground}; }`);
2775+
const stickyScrollBackground = styles.treeStickyScrollBackground ?? styles.listBackground;
2776+
if (stickyScrollBackground) {
2777+
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { background-color: ${stickyScrollBackground}; }`);
2778+
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row { background-color: ${stickyScrollBackground}; }`);
2779+
}
2780+
2781+
// Sticky Scroll Border
2782+
if (styles.treeStickyScrollBorder) {
2783+
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { border-bottom: 1px solid ${styles.treeStickyScrollBorder}; }`);
2784+
}
2785+
2786+
// Sticky Scroll Shadow
2787+
if (styles.treeStickyScrollShadow) {
2788+
content.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow { box-shadow: ${styles.treeStickyScrollShadow} 0 6px 6px -6px inset; height: 3px; }`);
27782789
}
27792790

27802791
// Sticky Scroll Focus

src/vs/base/browser/ui/tree/media/tree.css

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
height: 0;
138138
z-index: 13; /* Settings editor uses z-index: 12 */
139139

140-
/* TODO@benibenj temporary solution, all lists should provide their background */
140+
/* Backup color in case the tree does not provide the background color */
141141
background-color: var(--vscode-sideBar-background);
142142
}
143143

@@ -147,7 +147,7 @@
147147
opacity: 1 !important; /* Settings editor uses opacity < 1 */
148148
overflow: hidden;
149149

150-
/* TODO@benibenj temporary solution, all lists should provide their background */
150+
/* Backup color in case the tree does not provide the background color */
151151
background-color: var(--vscode-sideBar-background);
152152
}
153153

@@ -161,13 +161,12 @@
161161
display: none;
162162
}
163163

164-
.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow{
164+
.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow {
165165
position: absolute;
166166
bottom: -3px;
167167
left: 0px;
168-
height: 3px;
168+
height: 0px; /* heigt is 3px and only set when there is a treeStickyScrollShadow color */
169169
width: 100%;
170-
box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;
171170
}
172171

173172
.monaco-list .monaco-scrollable-element .monaco-tree-sticky-container[tabindex="0"]:focus{

src/vs/base/common/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,8 @@ export type DeepRequiredNonNullable<T> = {
243243
export type DeepPartial<T> = {
244244
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : Partial<T[P]>;
245245
};
246+
247+
/**
248+
* Represents a type that is a partial version of a given type `T`, except a subset.
249+
*/
250+
export type PartialExcept<T, K extends keyof T> = Partial<Omit<T, K>> & Pick<T, K>;

src/vs/platform/theme/browser/defaultStyles.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ export const defaultListStyles: IListStyles = {
174174
listHoverOutline: asCssVariable(activeContrastBorder),
175175
treeIndentGuidesStroke: asCssVariable(treeIndentGuidesStroke),
176176
treeInactiveIndentGuidesStroke: asCssVariable(treeInactiveIndentGuidesStroke),
177+
treeStickyScrollBackground: undefined,
178+
treeStickyScrollBorder: undefined,
179+
treeStickyScrollShadow: undefined,
177180
tableColumnsBorder: asCssVariable(tableColumnsBorder),
178181
tableOddRowsBackgroundColor: asCssVariable(tableOddRowsBackgroundColor),
179182
};
@@ -216,6 +219,9 @@ export const defaultSelectBoxStyles: ISelectBoxStyles = {
216219
tableOddRowsBackgroundColor: undefined,
217220
treeIndentGuidesStroke: undefined,
218221
treeInactiveIndentGuidesStroke: undefined,
222+
treeStickyScrollBackground: undefined,
223+
treeStickyScrollBorder: undefined,
224+
treeStickyScrollShadow: undefined
219225
};
220226

221227
export function getSelectBoxStyles(override: IStyleOverride<ISelectBoxStyles>): ISelectBoxStyles {

src/vs/workbench/browser/parts/views/treeView.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,8 @@ import { ThemeIcon } from 'vs/base/common/themables';
5555
import { fillEditorsDragData } from 'vs/workbench/browser/dnd';
5656
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
5757
import { API_OPEN_DIFF_EDITOR_COMMAND_ID, API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
58-
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
58+
import { getLocationBasedViewColors, IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
5959
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
60-
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
6160
import { Extensions, ITreeItem, ITreeItemLabel, ITreeView, ITreeViewDataProvider, ITreeViewDescriptor, ITreeViewDragAndDropController, IViewBadge, IViewDescriptorService, IViewsRegistry, ResolvableTreeItem, TreeCommand, TreeItemCollapsibleState, TreeViewItemHandleArg, TreeViewPaneHandleArg, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
6261
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
6362
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -306,7 +305,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
306305
}));
307306
this._register(this.viewDescriptorService.onDidChangeLocation(({ views, from, to }) => {
308307
if (views.some(v => v.id === this.id)) {
309-
this.tree?.updateOptions({ overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Panel ? PANEL_BACKGROUND : SIDE_BAR_BACKGROUND } });
308+
this.tree?.updateOptions({ overrideStyles: getLocationBasedViewColors(this.viewLocation).listOverrideStyles });
310309
}
311310
}));
312311
this.registerActions();
@@ -691,9 +690,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
691690
},
692691
multipleSelectionSupport: this.canSelectMany,
693692
dnd: this.treeViewDnd,
694-
overrideStyles: {
695-
listBackground: this.viewLocation === ViewContainerLocation.Panel ? PANEL_BACKGROUND : SIDE_BAR_BACKGROUND
696-
}
693+
overrideStyles: getLocationBasedViewColors(this.viewLocation).listOverrideStyles
697694
}) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>);
698695
treeMenus.setContextKeyService(this.tree.contextKeyService);
699696
aligner.tree = this.tree;

src/vs/workbench/browser/parts/views/viewPane.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'vs/css!./media/paneviewlet';
77
import * as nls from 'vs/nls';
88
import { Event, Emitter } from 'vs/base/common/event';
99
import { asCssVariable, foreground } from 'vs/platform/theme/common/colorRegistry';
10-
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
1110
import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl, Dimension, reset, asCssValueWithDefault } from 'vs/base/browser/dom';
1211
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
1312
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
@@ -23,7 +22,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
2322
import { Extensions as ViewContainerExtensions, IView, IViewDescriptorService, ViewContainerLocation, IViewsRegistry, IViewContentDescriptor, defaultViewIcon, ViewContainerLocationToString } from 'vs/workbench/common/views';
2423
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
2524
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
26-
import { assertIsDefined } from 'vs/base/common/types';
25+
import { assertIsDefined, PartialExcept } from 'vs/base/common/types';
2726
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
2827
import { MenuId, Action2, IAction2Options, SubmenuItemAction } from 'vs/platform/actions/common/actions';
2928
import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
@@ -51,6 +50,8 @@ import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateF
5150
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
5251
import type { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';
5352
import { IHoverService } from 'vs/platform/hover/browser/hover';
53+
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
54+
import { PANEL_BACKGROUND, PANEL_STICKY_SCROLL_BACKGROUND, PANEL_STICKY_SCROLL_BORDER, PANEL_STICKY_SCROLL_SHADOW, SIDE_BAR_BACKGROUND, SIDE_BAR_STICKY_SCROLL_BACKGROUND, SIDE_BAR_STICKY_SCROLL_BORDER, SIDE_BAR_STICKY_SCROLL_SHADOW } from 'vs/workbench/common/theme';
5455

5556
export enum ViewPaneShowActions {
5657
/** Show the actions when the view is hovered. This is the default behavior. */
@@ -629,16 +630,8 @@ export abstract class ViewPane extends Pane implements IView {
629630
return this.viewDescriptorService.getViewContainerByViewId(this.id)!.id;
630631
}
631632

632-
protected getBackgroundColor(): string {
633-
switch (this.viewDescriptorService.getViewLocationById(this.id)) {
634-
case ViewContainerLocation.Panel:
635-
return PANEL_BACKGROUND;
636-
case ViewContainerLocation.Sidebar:
637-
case ViewContainerLocation.AuxiliaryBar:
638-
return SIDE_BAR_BACKGROUND;
639-
}
640-
641-
return SIDE_BAR_BACKGROUND;
633+
protected getLocationBasedColors(): IViewPaneLocationColors {
634+
return getLocationBasedViewColors(this.viewDescriptorService.getViewLocationById(this.id));
642635
}
643636

644637
focus(): void {
@@ -781,6 +774,42 @@ export abstract class FilterViewPane extends ViewPane {
781774

782775
}
783776

777+
export interface IViewPaneLocationColors {
778+
background: string;
779+
listOverrideStyles: PartialExcept<IListStyles, 'listBackground' | 'treeStickyScrollBackground'>;
780+
}
781+
782+
export function getLocationBasedViewColors(location: ViewContainerLocation | null): IViewPaneLocationColors {
783+
let background, stickyScrollBackground, stickyScrollBorder, stickyScrollShadow;
784+
785+
switch (location) {
786+
case ViewContainerLocation.Panel:
787+
background = PANEL_BACKGROUND;
788+
stickyScrollBackground = PANEL_STICKY_SCROLL_BACKGROUND;
789+
stickyScrollBorder = PANEL_STICKY_SCROLL_BORDER;
790+
stickyScrollShadow = PANEL_STICKY_SCROLL_SHADOW;
791+
break;
792+
793+
case ViewContainerLocation.Sidebar:
794+
case ViewContainerLocation.AuxiliaryBar:
795+
default:
796+
background = SIDE_BAR_BACKGROUND;
797+
stickyScrollBackground = SIDE_BAR_STICKY_SCROLL_BACKGROUND;
798+
stickyScrollBorder = SIDE_BAR_STICKY_SCROLL_BORDER;
799+
stickyScrollShadow = SIDE_BAR_STICKY_SCROLL_SHADOW;
800+
}
801+
802+
return {
803+
background,
804+
listOverrideStyles: {
805+
listBackground: background,
806+
treeStickyScrollBackground: stickyScrollBackground,
807+
treeStickyScrollBorder: stickyScrollBorder,
808+
treeStickyScrollShadow: stickyScrollShadow
809+
}
810+
};
811+
}
812+
784813
export abstract class ViewAction<T extends IView> extends Action2 {
785814
override readonly desc: Readonly<IAction2Options> & { viewId: string };
786815
constructor(desc: Readonly<IAction2Options> & { viewId: string }) {

src/vs/workbench/common/theme.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { localize } from 'vs/nls';
7-
import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground, listActiveSelectionBackground, listActiveSelectionForeground, editorForeground, toolbarHoverBackground, inputBorder, widgetBorder } from 'vs/platform/theme/common/colorRegistry';
7+
import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground, listActiveSelectionBackground, listActiveSelectionForeground, editorForeground, toolbarHoverBackground, inputBorder, widgetBorder, scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
88
import { IColorTheme } from 'vs/platform/theme/common/themeService';
99
import { Color } from 'vs/base/common/color';
1010
import { ColorScheme } from 'vs/platform/theme/common/theme';
@@ -411,6 +411,27 @@ export const PANEL_SECTION_BORDER = registerColor('panelSection.border', {
411411
hcLight: PANEL_BORDER
412412
}, localize('panelSectionBorder', "Panel section border color used when multiple views are stacked horizontally in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels."));
413413

414+
export const PANEL_STICKY_SCROLL_BACKGROUND = registerColor('panelStickyScroll.background', {
415+
dark: PANEL_BACKGROUND,
416+
light: PANEL_BACKGROUND,
417+
hcDark: PANEL_BACKGROUND,
418+
hcLight: PANEL_BACKGROUND
419+
}, localize('panelStickyScrollBackground', "Background color of sticky scroll in the panel."));
420+
421+
export const PANEL_STICKY_SCROLL_BORDER = registerColor('panelStickyScroll.border', {
422+
dark: null,
423+
light: null,
424+
hcDark: null,
425+
hcLight: null
426+
}, localize('panelStickyScrollBorder', "Border color of sticky scroll in the panel."));
427+
428+
export const PANEL_STICKY_SCROLL_SHADOW = registerColor('panelStickyScroll.shadow', {
429+
dark: scrollbarShadow,
430+
light: scrollbarShadow,
431+
hcDark: scrollbarShadow,
432+
hcLight: scrollbarShadow
433+
}, localize('panelStickyScrollShadow', "Shadow color of sticky scroll in the panel."));
434+
414435
// < --- Output Editor -->
415436

416437
const OUTPUT_VIEW_BACKGROUND = registerColor('outputView.background', {
@@ -899,6 +920,27 @@ export const ACTIVITY_BAR_TOP_BORDER = registerColor('sideBarActivityBarTop.bord
899920
hcLight: SIDE_BAR_SECTION_HEADER_BORDER
900921
}, localize('sideBarActivityBarTopBorder', "Border color between the activity bar at the top/bottom and the views."));
901922

923+
export const SIDE_BAR_STICKY_SCROLL_BACKGROUND = registerColor('sideBarStickyScroll.background', {
924+
dark: SIDE_BAR_BACKGROUND,
925+
light: SIDE_BAR_BACKGROUND,
926+
hcDark: SIDE_BAR_BACKGROUND,
927+
hcLight: SIDE_BAR_BACKGROUND
928+
}, localize('sideBarStickyScrollBackground', "Background color of sticky scroll in the side bar."));
929+
930+
export const SIDE_BAR_STICKY_SCROLL_BORDER = registerColor('sideBarStickyScroll.border', {
931+
dark: null,
932+
light: null,
933+
hcDark: null,
934+
hcLight: null
935+
}, localize('sideBarStickyScrollBorder', "Border color of sticky scroll in the side bar."));
936+
937+
export const SIDE_BAR_STICKY_SCROLL_SHADOW = registerColor('sideBarStickyScroll.shadow', {
938+
dark: scrollbarShadow,
939+
light: scrollbarShadow,
940+
hcDark: scrollbarShadow,
941+
hcLight: scrollbarShadow
942+
}, localize('sideBarStickyScrollShadow', "Shadow color of sticky scroll in the side bar."));
943+
902944
// < --- Title Bar --- >
903945

904946
export const TITLE_BAR_ACTIVE_FOREGROUND = registerColor('titleBar.activeForeground', {

src/vs/workbench/contrib/chat/browser/chatViewPane.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,16 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
133133
super.renderBody(parent);
134134

135135
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
136-
136+
const locationBasedColors = this.getLocationBasedColors();
137137
this._widget = this._register(scopedInstantiationService.createInstance(
138138
ChatWidget,
139139
ChatAgentLocation.Panel,
140140
{ viewId: this.id },
141141
{ supportsFileReferences: true },
142142
{
143143
listForeground: SIDE_BAR_FOREGROUND,
144-
listBackground: this.getBackgroundColor(),
145-
inputEditorBackground: this.getBackgroundColor(),
144+
listBackground: locationBasedColors.background,
145+
inputEditorBackground: locationBasedColors.background,
146146
resultEditorBackground: editorBackground
147147
}));
148148
this._register(this.onDidChangeBodyVisibility(visible => {

0 commit comments

Comments
 (0)