Skip to content

Commit

Permalink
scroll list view on keyboard focus (microsoft#232644)
Browse files Browse the repository at this point in the history
  • Loading branch information
meganrogge authored Jan 10, 2025
1 parent 25a0bb9 commit be8f9a3
Showing 1 changed file with 34 additions and 4 deletions.
38 changes: 34 additions & 4 deletions src/vs/base/browser/ui/list/listView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { DataTransfers, IDragAndDropData } from '../../dnd.js';
import { $, addDisposableListener, animate, Dimension, getContentHeight, getContentWidth, getDocument, getTopLeftOffset, getWindow, isAncestor, isHTMLElement, isSVGElement, scheduleAtNextAnimationFrame } from '../../dom.js';
import { $, addDisposableListener, animate, Dimension, getActiveElement, getContentHeight, getContentWidth, getDocument, getTopLeftOffset, getWindow, isAncestor, isHTMLElement, isSVGElement, scheduleAtNextAnimationFrame } from '../../dom.js';
import { DomEmitter } from '../../event.js';
import { IMouseWheelEvent } from '../../mouseEvent.js';
import { EventType as TouchEventType, Gesture, GestureEvent } from '../../touch.js';
Expand Down Expand Up @@ -324,6 +324,7 @@ export class ListView<T> implements IListView<T> {
private onDragLeaveTimeout: IDisposable = Disposable.None;
private currentSelectionDisposable: IDisposable = Disposable.None;
private currentSelectionBounds: IRange | undefined;
private activeElement: HTMLElement | undefined;

private readonly disposables: DisposableStore = new DisposableStore();

Expand Down Expand Up @@ -439,9 +440,13 @@ export class ListView<T> implements IListView<T> {
this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
this.disposables.add(addDisposableListener(this.rowsContainer, TouchEventType.Change, e => this.onTouchChange(e as GestureEvent)));

// Prevent the monaco-scrollable-element from scrolling
// https://github.com/microsoft/vscode/issues/44181
this.disposables.add(addDisposableListener(this.scrollableElement.getDomNode(), 'scroll', e => (e.target as HTMLElement).scrollTop = 0));
this.disposables.add(addDisposableListener(this.scrollableElement.getDomNode(), 'scroll', e => {
// Make sure the active element is scrolled into view
const element = (e.target as HTMLElement);
const scrollValue = element.scrollTop;
element.scrollTop = 0;
this.setScrollTop(this.scrollTop + scrollValue);
}));

this.disposables.add(addDisposableListener(this.domNode, 'dragover', e => this.onDragOver(this.toDragEvent(e))));
this.disposables.add(addDisposableListener(this.domNode, 'drop', e => this.onDrop(this.toDragEvent(e))));
Expand All @@ -460,6 +465,31 @@ export class ListView<T> implements IListView<T> {
this.dnd = options.dnd ?? this.disposables.add(DefaultOptions.dnd);

this.layout(options.initialSize?.height, options.initialSize?.width);
this._setupFocusObserver(container);
}

private _setupFocusObserver(container: HTMLElement): void {
this.disposables.add(addDisposableListener(container, 'focus', () => {
const element = getActiveElement() as HTMLElement | null;
if (this.activeElement !== element && element !== null) {
this.activeElement = element;
this._scrollToActiveElement(this.activeElement, container);
}
}, true));
}

private _scrollToActiveElement(element: HTMLElement, container: HTMLElement) {
// The scroll event on the list only fires when scrolling down.
// If the active element is above the viewport, we need to scroll up.
const containerRect = container.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();

const topOffset = elementRect.top - containerRect.top;

if (topOffset < 0) {
// Scroll up
this.setScrollTop(this.scrollTop + topOffset);
}
}

updateOptions(options: IListViewOptionsUpdate) {
Expand Down

0 comments on commit be8f9a3

Please sign in to comment.