@@ -60,6 +60,9 @@ export default {
6060 // The computed height for auto resize.
6161 // We avoid setting the style to null, which can override user manual resize.
6262 styles . height = this . computedHeight
63+ // We always add a vertical scrollbar to the textarea when auto-resize is
64+ // enabled so that the computed height calcaultion returns a stable value.
65+ styles . overflowY = 'scroll'
6366 }
6467 return styles
6568 } ,
@@ -77,9 +80,10 @@ export default {
7780 // If auto-resize is enabled, then we return null as we use CSS to control height.
7881 return this . computedMinRows === this . computedMaxRows ? this . computedMinRows : null
7982 } ,
80- computedHeight ( ) /* istanbul ignore next: can't test getComputedProperties */ {
83+ computedHeight ( ) /* istanbul ignore next: can't test getComputedStyle in JSDOM */ {
8184 // We compare `computedRows` and `localValue` to `true`, a value
82- // they both can't have at any time, to ensure reactivity
85+ // they both can't have at any time, to ensure reactivity of this
86+ // computed property.
8387 if (
8488 this . $isServer ||
8589 this . dontResize ||
@@ -91,48 +95,50 @@ export default {
9195
9296 const el = this . $el
9397
94- // Element must be visible (not hidden) and in document
95- // * Must* be checked after above checks
98+ // Element must be visible (not hidden) and in document.
99+ // Must be checked after above checks
96100 if ( ! isVisible ( el ) ) {
97101 return null
98102 }
99103
100- // Remember old height (includes `px` units) and reset it temporarily to `auto`
101- const oldHeight = el . style . height
102- el . style . height = 'auto'
103-
104104 // Get current computed styles
105105 const computedStyle = getCS ( el )
106106 // Height of one line of text in px
107107 const lineHeight = parseFloat ( computedStyle . lineHeight )
108- // Minimum height for min rows (browser dependant)
109- const minHeight = parseInt ( computedStyle . height , 10 ) || lineHeight * this . computedMinRows
110- // Calculate height of content
111- const offset =
108+ // Calculate height of border and padding
109+ const border =
112110 ( parseFloat ( computedStyle . borderTopWidth ) || 0 ) +
113- ( parseFloat ( computedStyle . borderBottomWidth ) || 0 ) +
114- ( parseFloat ( computedStyle . paddingTop ) || 0 ) +
115- ( parseFloat ( computedStyle . paddingBottom ) || 0 )
116- // Calculate content height in "rows"
117- const contentRows = Math . max ( ( el . scrollHeight - offset ) / lineHeight , 2 )
111+ ( parseFloat ( computedStyle . borderBottomWidth ) || 0 )
112+ const padding =
113+ ( parseFloat ( computedStyle . paddingTop ) || 0 ) + ( parseFloat ( computedStyle . paddingBottom ) || 0 )
114+ // Calculate offset
115+ const offset = border + padding
116+ // Minimum height for min rows (which must be 2 rows or greater for cross-browser support)
117+ const minHeight = lineHeight * this . computedMinRows + offset
118+
119+ // Get the current style height (with `px` units)
120+ const oldHeight = el . style . height || computedStyle . height
121+ // Probe scrollHeight by temporarily changing the height to `auto`
122+ el . style . height = 'auto'
123+ const scrollHeight = el . scrollHeight
124+ // Place the original old height back on the element, just in case this computedProp
125+ // returns the same value as before.
126+ el . style . height = oldHeight
127+
128+ // Calculate content height in "rows" (scrollHeight includes padding but not border)
129+ const contentRows = Math . max ( ( scrollHeight - padding ) / lineHeight , 2 )
118130 // Calculate number of rows to display (limited within min/max rows)
119131 const rows = Math . min ( Math . max ( contentRows , this . computedMinRows ) , this . computedMaxRows )
120132 // Calculate the required height of the textarea including border and padding (in pixels)
121133 const height = Math . max ( Math . ceil ( rows * lineHeight + offset ) , minHeight )
122134
123- // Place old height back on element, just in case this computed prop returns the same value
124- el . style . height = oldHeight
125-
126- // Value of previous height (without px units appended)
127- const oldHeightPx = parseFloat ( oldHeight ) || 0
128-
129- if ( this . noAutoShrink && oldHeightPx > height ) {
130- // Computed height remains the larger of oldHeight and new height
131- // When height is `sticky` (no-auto-shrink is true)
135+ // Computed height remains the larger of oldHeight and new height,
136+ // when height is in `sticky` mode (prop `no-auto-shrink` is true)
137+ if ( this . noAutoShrink && ( parseFloat ( oldHeight ) || 0 ) > height ) {
132138 return oldHeight
133139 }
134140
135- // Return the new computed height in px units
141+ // Return the new computed CSS height in px units
136142 return `${ height } px`
137143 }
138144 } ,
0 commit comments