From e3699030fc4902cc16a1ed3d6fcdc65a5f226bde Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Fri, 19 Mar 2021 15:04:09 -0600 Subject: [PATCH 1/2] Revert "fix(cdk/text-field): autosize text areas using the placeholder (#22197)" 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; } From 8acf89aeb03930d30111f5f31c79dfeca6361392 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Mar 2021 21:10:04 +0000 Subject: [PATCH 2/2] build: bump @types/autoprefixer from 9.7.2 to 10.2.0 Bumps [@types/autoprefixer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/autoprefixer) from 9.7.2 to 10.2.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/autoprefixer) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 59 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index af8e4ec1f269..a98151a25a55 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "@material/typography": "11.0.0-canary.67d780c79.0", "@octokit/rest": "18.3.5", "@schematics/angular": "^12.0.0-next.4", - "@types/autoprefixer": "^9.7.2", + "@types/autoprefixer": "^10.2.0", "@types/browser-sync": "^2.26.1", "@types/fs-extra": "^9.0.5", "@types/glob": "^7.1.3", diff --git a/yarn.lock b/yarn.lock index 699b10774e03..19617d3ad8e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1861,13 +1861,12 @@ resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== -"@types/autoprefixer@^9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@types/autoprefixer/-/autoprefixer-9.7.2.tgz#64b3251c9675feef5a631b7dd34cfea50a8fdbcc" - integrity sha512-QX7U7YW3zX3ex6MECtWO9folTGsXeP4b8bSjTq3I1ODM+H+sFHwGKuof+T+qBcDClGlCGtDb3SVfiTVfmcxw4g== +"@types/autoprefixer@^10.2.0": + version "10.2.0" + resolved "https://registry.yarnpkg.com/@types/autoprefixer/-/autoprefixer-10.2.0.tgz#cb6cd67f00337607433b17ebf2cee511db957b9e" + integrity sha512-ClU0uw3HhUra890K4xcf2IQxD6w0WOjPIaKb8jrRXYPHvvUW1P5dGufPlDtTo5gtWPWH+4L6tSBAoAKVf93uBQ== dependencies: - "@types/browserslist" "*" - postcss "7.x.x" + autoprefixer "*" "@types/browser-sync@^2.26.1": version "2.26.1" @@ -1879,11 +1878,6 @@ "@types/serve-static" "*" chokidar "^2.1.2" -"@types/browserslist@*": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.8.0.tgz#60489aefdf0fcb56c2d8eb65267ff08dad7a526d" - integrity sha512-4PyO9OM08APvxxo1NmQyQKlJdowPCOQIy5D/NLO3aO0vGC57wsMptvGp3b8IbYnupFZr92l1dlVief1JvS6STQ== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -2811,6 +2805,18 @@ atob@^2.1.1, atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +autoprefixer@*: + version "10.2.5" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.5.tgz#096a0337dbc96c0873526d7fef5de4428d05382d" + integrity sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA== + dependencies: + browserslist "^4.16.3" + caniuse-lite "^1.0.30001196" + colorette "^1.2.2" + fraction.js "^4.0.13" + normalize-range "^0.1.2" + postcss-value-parser "^4.1.0" + autoprefixer@^6.7.6: version "6.7.7" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" @@ -3204,6 +3210,17 @@ browserslist@^4.12.0: escalade "^3.1.0" node-releases "^1.1.61" +browserslist@^4.16.3: + version "4.16.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" + integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== + dependencies: + caniuse-lite "^1.0.30001181" + colorette "^1.2.1" + electron-to-chromium "^1.3.649" + escalade "^3.1.1" + node-releases "^1.1.70" + browserstack-local@^1.3.7: version "1.4.8" resolved "https://registry.yarnpkg.com/browserstack-local/-/browserstack-local-1.4.8.tgz#07f74a19b324cf2de69ffe65f9c2baa3a2dd9a0e" @@ -3451,6 +3468,11 @@ caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001135: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001144.tgz#bca0fffde12f97e1127a351fec3bfc1971aa3b3d" integrity sha512-4GQTEWNMnVZVOFG3BK0xvGeaDAtiPAbG2N8yuMXuXzx/c2Vd4XoMPO8+E918zeXn5IF0FRVtGShBfkfQea2wHQ== +caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001196: + version "1.0.30001203" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001203.tgz#a7a34df21a387d9deffcd56c000b8cf5ab540580" + integrity sha512-/I9tvnzU/PHMH7wBPrfDMSuecDeUKerjCPX7D0xBbaJZPxoT9m+yYxt0zCTkcijCkjTdim3H56Zm0i5Adxch4w== + canonical-path@1.0.0, canonical-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" @@ -5031,6 +5053,11 @@ electron-to-chromium@^1.3.571: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.577.tgz#9885f3f72c6e3367010b461ff6f2d9624a929720" integrity sha512-dSb64JQSFif/pD8mpVAgSFkbVi6YHbK6JeEziwNNmXlr/Ne2rZtseFK5SM7JoWSLf6gP0gVvRGi4/2ZRhSX/rA== +electron-to-chromium@^1.3.649: + version "1.3.693" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.693.tgz#5089c506a925c31f93fcb173a003a22e341115dd" + integrity sha512-vUdsE8yyeu30RecppQtI+XTz2++LWLVEIYmzeCaCRLSdtKZ2eXqdJcrs85KwLiPOPVc6PELgWyXBsfqIvzGZag== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -6013,6 +6040,11 @@ forwarded@~0.1.2: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= +fraction.js@^4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe" + integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA== + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -9391,6 +9423,11 @@ node-releases@^1.1.61: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== +node-releases@^1.1.70: + version "1.1.71" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" + integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== + node-source-walk@^4.0.0, node-source-walk@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-4.2.0.tgz#c2efe731ea8ba9c03c562aa0a9d984e54f27bc2c"