diff --git a/src/vs/editor/browser/config/elementSizeObserver.ts b/src/vs/editor/browser/config/elementSizeObserver.ts index b78ede941f4780b9f7d30d04a93bc95cb9a7fb9d..09095533d0b0a1b6dd2a9f4987888667dd7eada4 100644 --- a/src/vs/editor/browser/config/elementSizeObserver.ts +++ b/src/vs/editor/browser/config/elementSizeObserver.ts @@ -3,9 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IDimension } from 'vs/editor/common/editorCommon'; -import * as dom from 'vs/base/browser/dom'; + +interface ResizeObserver { + observe(target: Element): void; + unobserve(target: Element): void; + disconnect(): void; +} + +interface ResizeObserverSize { + inlineSize: number; + blockSize: number; +} + +interface ResizeObserverEntry { + readonly target: Element; + readonly contentRect: DOMRectReadOnly; + readonly borderBoxSize: ResizeObserverSize; + readonly contentBoxSize: ResizeObserverSize; +} + +type ResizeObserverCallback = (entries: ReadonlyArray, observer: ResizeObserver) => void; + +declare const ResizeObserver: { + prototype: ResizeObserver; + new(callback: ResizeObserverCallback): ResizeObserver; +}; + export class ElementSizeObserver extends Disposable { @@ -13,8 +38,8 @@ export class ElementSizeObserver extends Disposable { private readonly changeCallback: () => void; private width: number; private height: number; - private mutationObserver: MutationObserver | null; - private windowSizeListener: IDisposable | null; + private resizeObserver: ResizeObserver | null; + private measureReferenceDomElementToken: number; constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) { super(); @@ -22,9 +47,9 @@ export class ElementSizeObserver extends Disposable { this.changeCallback = changeCallback; this.width = -1; this.height = -1; - this.mutationObserver = null; - this.windowSizeListener = null; + this.resizeObserver = null; this.measureReferenceDomElement(false, dimension); + this.measureReferenceDomElementToken = -1; } public dispose(): void { @@ -41,25 +66,33 @@ export class ElementSizeObserver extends Disposable { } public startObserving(): void { - if (!this.mutationObserver && this.referenceDomElement) { - this.mutationObserver = new MutationObserver(() => this._onDidMutate()); - this.mutationObserver.observe(this.referenceDomElement, { - attributes: true, - }); - } - if (!this.windowSizeListener) { - this.windowSizeListener = dom.addDisposableListener(window, 'resize', () => this._onDidResizeWindow()); + if (typeof ResizeObserver !== 'undefined') { + if (!this.resizeObserver && this.referenceDomElement) { + this.resizeObserver = new ResizeObserver((entries) => { + if (entries && entries[0]) { + this.observe({ width: entries[0].contentRect.width, height: entries[0].contentRect.height }); + } else { + this.observe(); + } + }); + this.resizeObserver.observe(this.referenceDomElement); + } + } else { + if (this.measureReferenceDomElementToken === -1) { + // setInterval type defaults to NodeJS.Timeout instead of number, so specify it as a number + this.measureReferenceDomElementToken = setInterval(() => this.observe(), 100) as unknown as number; + } } } public stopObserving(): void { - if (this.mutationObserver) { - this.mutationObserver.disconnect(); - this.mutationObserver = null; + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + this.resizeObserver = null; } - if (this.windowSizeListener) { - this.windowSizeListener.dispose(); - this.windowSizeListener = null; + if (this.measureReferenceDomElementToken !== -1) { + clearInterval(this.measureReferenceDomElementToken); + this.measureReferenceDomElementToken = -1; } } @@ -67,14 +100,6 @@ export class ElementSizeObserver extends Disposable { this.measureReferenceDomElement(true, dimension); } - private _onDidMutate(): void { - this.measureReferenceDomElement(true); - } - - private _onDidResizeWindow(): void { - this.measureReferenceDomElement(true); - } - private measureReferenceDomElement(callChangeCallback: boolean, dimension?: IDimension): void { let observedWidth = 0; let observedHeight = 0;