From 431678730b1070b194e9b51ad29bb8a506881c9e Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Fri, 19 Mar 2021 15:31:43 -0600 Subject: [PATCH] Revert "fix(cdk/text-field): autosize text areas using the placeholder (#22197)" (#22296) This reverts commit 476a90b083532add4b1343c83e6bf4d105094050. --- scripts/check-mdc-tests-config.ts | 2 +- src/cdk/text-field/autosize.spec.ts | 62 ++-------------------- src/cdk/text-field/autosize.ts | 50 +++++------------ src/material/input/input.spec.ts | 6 +-- tools/public_api_guard/cdk/text-field.d.ts | 4 +- 5 files changed, 21 insertions(+), 103 deletions(-) diff --git a/scripts/check-mdc-tests-config.ts b/scripts/check-mdc-tests-config.ts index 4da723183dcb..bccb7185e851 100644 --- a/scripts/check-mdc-tests-config.ts +++ b/scripts/check-mdc-tests-config.ts @@ -77,7 +77,7 @@ export const config = { 'should calculate the outline gaps inside the shadow DOM', 'should be legacy appearance if no default options provided', 'should be legacy appearance if empty default options provided', - 'should adjust height due to long placeholders', + 'should not calculate wrong content height due to long placeholders', 'should work in a tab', 'should work in a step' ], diff --git a/src/cdk/text-field/autosize.spec.ts b/src/cdk/text-field/autosize.spec.ts index f80350cdcffb..a2a7463c427c 100644 --- a/src/cdk/text-field/autosize.spec.ts +++ b/src/cdk/text-field/autosize.spec.ts @@ -50,7 +50,7 @@ describe('CdkTextareaAutosize', () => { it('should resize the textarea based on its content', () => { let previousHeight = textarea.clientHeight; - textarea.value = ` + fixture.componentInstance.content = ` Once upon a midnight dreary, while I pondered, weak and weary, Over many a quaint and curious volume of forgotten lore— While I nodded, nearly napping, suddenly there came a tapping, @@ -68,7 +68,7 @@ describe('CdkTextareaAutosize', () => { .toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight'); previousHeight = textarea.clientHeight; - textarea.value += ` + fixture.componentInstance.content += ` Ah, distinctly I remember it was in the bleak December; And each separate dying ember wrought its ghost upon the floor. Eagerly I wished the morrow;—vainly I had sought to borrow @@ -85,38 +85,6 @@ describe('CdkTextareaAutosize', () => { .toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight'); }); - it('should keep the placeholder size if the value is shorter than the placeholder', () => { - fixture = TestBed.createComponent(AutosizeTextAreaWithContent); - - textarea = fixture.nativeElement.querySelector('textarea'); - autosize = fixture.debugElement.query(By.css('textarea'))! - .injector.get(CdkTextareaAutosize); - - fixture.componentInstance.placeholder = ` - Once upon a midnight dreary, while I pondered, weak and weary, - Over many a quaint and curious volume of forgotten lore— - While I nodded, nearly napping, suddenly there came a tapping, - As of some one gently rapping, rapping at my chamber door. - “’Tis some visitor,” I muttered, “tapping at my chamber door— - Only this and nothing more.”`; - - fixture.detectChanges(); - - expect(textarea.clientHeight) - .toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight'); - - let previousHeight = textarea.clientHeight; - - textarea.value = 'a'; - - // Manually call resizeToFitContent instead of faking an `input` event. - fixture.detectChanges(); - autosize.resizeToFitContent(); - - expect(textarea.clientHeight) - .toBe(previousHeight, 'Expected textarea height not to have changed'); - }); - it('should set a min-height based on minRows', () => { expect(textarea.style.minHeight).toBeFalsy(); @@ -193,7 +161,7 @@ describe('CdkTextareaAutosize', () => { }); it('should calculate the proper height based on the specified amount of max rows', () => { - textarea.value = [1, 2, 3, 4, 5, 6, 7, 8].join('\n'); + fixture.componentInstance.content = [1, 2, 3, 4, 5, 6, 7, 8].join('\n'); fixture.detectChanges(); autosize.resizeToFitContent(); @@ -228,27 +196,6 @@ describe('CdkTextareaAutosize', () => { .toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight'); }); - it('should properly resize to placeholder on init', () => { - // Manually create the test component in this test, because in this test the first change - // detection should be triggered after a multiline placeholder is set. - fixture = TestBed.createComponent(AutosizeTextAreaWithContent); - textarea = fixture.nativeElement.querySelector('textarea'); - autosize = fixture.debugElement.query(By.css('textarea'))! - .injector.get(CdkTextareaAutosize); - - fixture.componentInstance.placeholder = ` - Line - Line - Line - Line - Line`; - - fixture.detectChanges(); - - expect(textarea.clientHeight) - .toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight'); - }); - it('should resize when an associated form control value changes', fakeAsync(() => { const fixtureWithForms = TestBed.createComponent(AutosizeTextareaWithNgModel); textarea = fixtureWithForms.nativeElement.querySelector('textarea'); @@ -351,7 +298,7 @@ const textareaStyleReset = ` @Component({ template: ` `, + #autosize="cdkTextareaAutosize">{{content}}`, styles: [textareaStyleReset], }) class AutosizeTextAreaWithContent { @@ -359,7 +306,6 @@ class AutosizeTextAreaWithContent { minRows: number | null = null; maxRows: number | null = null; content: string = ''; - placeholder: string = ''; } @Component({ diff --git a/src/cdk/text-field/autosize.ts b/src/cdk/text-field/autosize.ts index 9e2263893ad6..74752924f0b6 100644 --- a/src/cdk/text-field/autosize.ts +++ b/src/cdk/text-field/autosize.ts @@ -88,19 +88,8 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy { } } - @Input() - get placeholder(): string { return this._textareaElement.placeholder; } - set placeholder(value: string) { - this._cachedPlaceholderHeight = undefined; - this._textareaElement.placeholder = value; - this._cacheTextareaPlaceholderHeight(); - } - - /** Cached height of a textarea with a single row. */ private _cachedLineHeight: number; - /** Cached height of a textarea with only the placeholder. */ - private _cachedPlaceholderHeight?: number; /** Used to reference correct document/window */ protected _document?: Document; @@ -206,30 +195,6 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy { this._setMaxHeight(); } - private _measureScrollHeight(): number { - // Reset the textarea height to auto in order to shrink back to its default size. - // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations. - this._textareaElement.classList.add(this._measuringClass); - // The measuring class includes a 2px padding to workaround an issue with Chrome, - // so we account for that extra space here by subtracting 4 (2px top + 2px bottom). - const scrollHeight = this._textareaElement.scrollHeight - 4; - this._textareaElement.classList.remove(this._measuringClass); - - return scrollHeight; - } - - private _cacheTextareaPlaceholderHeight(): void { - if (this._cachedPlaceholderHeight) { - return; - } - - const value = this._textareaElement.value; - - this._textareaElement.value = this._textareaElement.placeholder; - this._cachedPlaceholderHeight = this._measureScrollHeight(); - this._textareaElement.value = value; - } - ngDoCheck() { if (this._platform.isBrowser) { this.resizeToFitContent(); @@ -248,7 +213,6 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy { } this._cacheTextareaLineHeight(); - this._cacheTextareaPlaceholderHeight(); // If we haven't determined the line-height yet, we know we're still hidden and there's no point // in checking the height of the textarea. @@ -264,14 +228,24 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy { return; } - const scrollHeight = this._measureScrollHeight(); + const placeholderText = textarea.placeholder; + + // Reset the textarea height to auto in order to shrink back to its default size. + // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations. + // Long placeholders that are wider than the textarea width may lead to a bigger scrollHeight + // value. To ensure that the scrollHeight is not bigger than the content, the placeholders + // need to be removed temporarily. + textarea.classList.add(this._measuringClass); + textarea.placeholder = ''; // The measuring class includes a 2px padding to workaround an issue with Chrome, // so we account for that extra space here by subtracting 4 (2px top + 2px bottom). - const height = Math.max(scrollHeight, this._cachedPlaceholderHeight || 0); + const height = textarea.scrollHeight - 4; // Use the scrollHeight to know how large the textarea *would* be if fit its entire value. textarea.style.height = `${height}px`; + textarea.classList.remove(this._measuringClass); + textarea.placeholder = placeholderText; this._ngZone.runOutsideAngular(() => { if (typeof requestAnimationFrame !== 'undefined') { diff --git a/src/material/input/input.spec.ts b/src/material/input/input.spec.ts index 032366acfd57..3e89d0efa63e 100644 --- a/src/material/input/input.spec.ts +++ b/src/material/input/input.spec.ts @@ -1719,7 +1719,7 @@ describe('MatFormField default options', () => { }); describe('MatInput with textarea autosize', () => { - it('should adjust height due to long placeholders', () => { + it('should not calculate wrong content height due to long placeholders', () => { const fixture = createComponent(AutosizeTextareaWithLongPlaceholder); fixture.detectChanges(); @@ -1735,8 +1735,8 @@ describe('MatInput with textarea autosize', () => { autosize.resizeToFitContent(true); - expect(textarea.clientHeight).toBeLessThan(heightWithLongPlaceholder, - 'Expected the textarea height to be shorter with a long placeholder.'); + expect(textarea.clientHeight).toBe(heightWithLongPlaceholder, + 'Expected the textarea height to be the same with a long placeholder.'); }); it('should work in a tab', () => { diff --git a/tools/public_api_guard/cdk/text-field.d.ts b/tools/public_api_guard/cdk/text-field.d.ts index 52ccc4947868..57d081ad1ffa 100644 --- a/tools/public_api_guard/cdk/text-field.d.ts +++ b/tools/public_api_guard/cdk/text-field.d.ts @@ -31,8 +31,6 @@ export declare class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDe set maxRows(value: number); get minRows(): number; set minRows(value: number); - get placeholder(): string; - set placeholder(value: string); constructor(_elementRef: ElementRef, _platform: Platform, _ngZone: NgZone, document?: any); _noopInputHandler(): void; @@ -46,7 +44,7 @@ export declare class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDe static ngAcceptInputType_enabled: BooleanInput; static ngAcceptInputType_maxRows: NumberInput; static ngAcceptInputType_minRows: NumberInput; - static ɵdir: i0.ɵɵDirectiveDefWithMeta; + static ɵdir: i0.ɵɵDirectiveDefWithMeta; static ɵfac: i0.ɵɵFactoryDef; }