Skip to content

Commit

Permalink
fix(text-field): unable to undo/redo in autosized text field on firef…
Browse files Browse the repository at this point in the history
…ox (#19238)
  • Loading branch information
crisbeto authored and mmalerba committed May 15, 2020
1 parent de155e2 commit 7e1fd89
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
23 changes: 19 additions & 4 deletions src/cdk/text-field/_text-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,28 @@
// removed when measuring is complete. We use `!important` rules here to make sure user-specified
// rules do not interfere with the measurement.
textarea.cdk-textarea-autosize-measuring {
@include _cdk-textarea-autosize-measuring-base;
height: auto !important;
overflow: hidden !important;
// Having 2px top and bottom padding seems to fix a bug where Chrome gets an incorrect
// measurement. We just have to account for it later and subtract it off the final result.
padding: 2px 0 !important;
box-sizing: content-box !important;
}

// Similar to the `cdk-textarea-autosize-measuring` class, but only applied on Firefox. We need
// to use this class, because Firefox has a bug where changing the `overflow` breaks the user's
// ability to undo/redo what they were typing (see #16629). This class is only scoped to Firefox,
// because the measurements there don't seem to be affected by the `height: 0`, whereas on other
// browsers they are, e.g. Chrome detects longer text and IE does't resize back to normal.
// Identical issue report: https://bugzilla.mozilla.org/show_bug.cgi?id=448784
textarea.cdk-textarea-autosize-measuring-firefox {
@include _cdk-textarea-autosize-measuring-base;
height: 0 !important;
}
}

@mixin _cdk-textarea-autosize-measuring-base {
// Having 2px top and bottom padding seems to fix a bug where Chrome gets an incorrect
// measurement. We just have to account for it later and subtract it off the final result.
padding: 2px 0 !important;
box-sizing: content-box !important;
}

// Used to generate UIDs for keyframes used to change the text field autofill styles.
Expand Down
14 changes: 10 additions & 4 deletions src/cdk/text-field/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
/** Used to reference correct document/window */
protected _document?: Document;

/** Class that should be applied to the textarea while it's being measured. */
private _measuringClass: string;

constructor(private _elementRef: ElementRef<HTMLElement>,
private _platform: Platform,
private _ngZone: NgZone,
Expand All @@ -102,6 +105,9 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
this._document = document;

this._textareaElement = this._elementRef.nativeElement as HTMLTextAreaElement;
this._measuringClass = _platform.FIREFOX ?
'cdk-textarea-autosize-measuring-firefox' :
'cdk-textarea-autosize-measuring';
}

/** Sets the minimum height of the textarea as determined by minRows. */
Expand Down Expand Up @@ -229,16 +235,16 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
// 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('cdk-textarea-autosize-measuring');
textarea.classList.add(this._measuringClass);
textarea.placeholder = '';

// The cdk-textarea-autosize-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).
// 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 = 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('cdk-textarea-autosize-measuring');
textarea.classList.remove(this._measuringClass);
textarea.placeholder = placeholderText;

this._ngZone.runOutsideAngular(() => {
Expand Down

0 comments on commit 7e1fd89

Please sign in to comment.