1
1
import Vue from '../../utils/vue'
2
+
import { VBVisible } from '../../directives/visible'
2
3
import idMixin from '../../mixins/id'
3
4
import formMixin from '../../mixins/form'
4
5
import formSizeMixin from '../../mixins/form-size'
5
6
import formStateMixin from '../../mixins/form-state'
6
7
import formTextMixin from '../../mixins/form-text'
7
8
import formSelectionMixin from '../../mixins/form-selection'
8
9
import formValidityMixin from '../../mixins/form-validity'
9
-
import { getCS, isVisible } from '../../utils/dom'
10
+
import listenOnRootMixin from '../../mixins/listen-on-root'
11
+
import { getCS, isVisible, requestAF } from '../../utils/dom'
10
12
import { isNull } from '../../utils/inspect'
11
13
12
14
// @vue/component
13
15
export const BFormTextarea = /*#__PURE__*/ Vue.extend({
14
16
name: 'BFormTextarea',
17
+
directives: {
18
+
'b-visible': VBVisible
19
+
},
15
20
mixins: [
16
21
idMixin,
22
+
listenOnRootMixin,
17
23
formMixin,
18
24
formSizeMixin,
19
25
formStateMixin,
@@ -48,7 +54,6 @@ export const BFormTextarea = /*#__PURE__*/ Vue.extend({
48
54
},
49
55
data() {
50
56
return {
51
-
dontResize: true,
52
57
heightInPx: null
53
58
}
54
59
},
@@ -60,64 +65,52 @@ export const BFormTextarea = /*#__PURE__*/ Vue.extend({
60
65
resize: !this.computedRows || this.noResize ? 'none' : null
61
66
}
62
67
if (!this.computedRows) {
63
-
// Conditionaly set the computed CSS height when auto rows/height is enabled.
64
-
// We avoid setting the style to null, which can override user manual resize handle.
68
+
// Conditionally set the computed CSS height when auto rows/height is enabled
69
+
// We avoid setting the style to `null`, which can override user manual resize handle
65
70
styles.height = this.heightInPx
66
71
// We always add a vertical scrollbar to the textarea when auto-height is
67
-
// enabled so that the computed height calcaultion returns a stable value.
72
+
// enabled so that the computed height calculation returns a stable value
68
73
styles.overflowY = 'scroll'
69
74
}
70
75
return styles
71
76
},
72
77
computedMinRows() {
73
-
// Ensure rows is at least 2 and positive (2 is the native textarea value).
74
-
// A value of 1 can cause issues in some browsers, and most browsers only support
75
-
// 2 as the smallest value.
78
+
// Ensure rows is at least 2 and positive (2 is the native textarea value)
79
+
// A value of 1 can cause issues in some browsers, and most browsers
80
+
// only support 2 as the smallest value
76
81
return Math.max(parseInt(this.rows, 10) || 2, 2)
77
82
},
78
83
computedMaxRows() {
79
84
return Math.max(this.computedMinRows, parseInt(this.maxRows, 10) || 0)
80
85
},
81
86
computedRows() {
82
-
// This is used to set the attribute 'rows' on the textarea.
83
-
// If auto-height is enabled, then we return null as we use CSS to control height.
87
+
// This is used to set the attribute 'rows' on the textarea
88
+
// If auto-height is enabled, then we return `null` as we use CSS to control height
84
89
return this.computedMinRows === this.computedMaxRows ? this.computedMinRows : null
85
90
}
86
91
},
87
92
watch: {
88
-
dontResize(newVal, oldval) {
89
-
if (!newVal) {
90
-
this.setHeight()
91
-
}
92
-
},
93
93
localValue(newVal, oldVal) {
94
94
this.setHeight()
95
95
}
96
96
},
97
97
mounted() {
98
-
// Enable opt-in resizing once mounted
99
-
this.$nextTick(() => {
100
-
this.dontResize = false
101
-
})
102
-
},
103
-
activated() {
104
-
// If we are being re-activated in <keep-alive>, enable opt-in resizing
105
-
this.$nextTick(() => {
106
-
this.dontResize = false
107
-
})
108
-
},
109
-
deactivated() {
110
-
// If we are in a deactivated <keep-alive>, disable opt-in resizing
111
-
this.dontResize = true
112
-
},
113
-
beforeDestroy() {
114
-
/* istanbul ignore next */
115
-
this.dontResize = true
98
+
this.setHeight()
116
99
},
117
100
methods: {
101
+
// Called by intersection observer directive
102
+
visibleCallback(visible) /* istanbul ignore next */ {
103
+
if (visible) {
104
+
// We use a `$nextTick()` here just to make sure any
105
+
// transitions or portalling have completed
106
+
this.$nextTick(this.setHeight)
107
+
}
108
+
},
118
109
setHeight() {
119
110
this.$nextTick(() => {
120
-
this.heightInPx = this.computeHeight()
111
+
requestAF(() => {
112
+
this.heightInPx = this.computeHeight()
113
+
})
121
114
})
122
115
},
123
116
computeHeight() /* istanbul ignore next: can't test getComputedStyle in JSDOM */ {
@@ -127,7 +120,7 @@ export const BFormTextarea = /*#__PURE__*/ Vue.extend({
127
120
128
121
const el = this.$el
129
122
130
-
// Element must be visible (not hidden) and in document.
123
+
// Element must be visible (not hidden) and in document
131
124
// Must be checked after above checks
132
125
if (!isVisible(el)) {
133
126
return null
@@ -153,18 +146,18 @@ export const BFormTextarea = /*#__PURE__*/ Vue.extend({
153
146
// Probe scrollHeight by temporarily changing the height to `auto`
154
147
el.style.height = 'auto'
155
148
const scrollHeight = el.scrollHeight
156
-
// Place the original old height back on the element, just in case this computedProp
157
-
// returns the same value as before.
149
+
// Place the original old height back on the element, just in case `computedProp`
150
+
// returns the same value as before
158
151
el.style.height = oldHeight
159
152
160
-
// Calculate content height in "rows" (scrollHeight includes padding but not border)
153
+
// Calculate content height in 'rows' (scrollHeight includes padding but not border)
161
154
const contentRows = Math.max((scrollHeight - padding) / lineHeight, 2)
162
155
// Calculate number of rows to display (limited within min/max rows)
163
156
const rows = Math.min(Math.max(contentRows, this.computedMinRows), this.computedMaxRows)
164
157
// Calculate the required height of the textarea including border and padding (in pixels)
165
158
const height = Math.max(Math.ceil(rows * lineHeight + offset), minHeight)
166
159
167
-
// Computed height remains the larger of oldHeight and new height,
160
+
// Computed height remains the larger of `oldHeight` and new `height`,
168
161
// when height is in `sticky` mode (prop `no-auto-shrink` is true)
169
162
if (this.noAutoShrink && (parseFloat(oldHeight) || 0) > height) {
170
163
return oldHeight
@@ -184,9 +177,13 @@ export const BFormTextarea = /*#__PURE__*/ Vue.extend({
184
177
directives: [
185
178
{
186
179
name: 'model',
187
-
rawName: 'v-model',
188
-
value: self.localValue,
189
-
expression: 'localValue'
180
+
value: self.localValue
181
+
},
182
+
{
183
+
name: 'b-visible',
184
+
value: this.visibleCallback,
185
+
// If textarea is within 640px of viewport, consider it visible
186
+
modifiers: { '640': true }
190
187
}
191
188
],
192
189
attrs: {
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4