Skip to content

Commit 696c305

Browse files
committed
Refactor Textarea autosize to handle single line wrapping multiple rows
1 parent 6d6ac9a commit 696c305

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

packages/ui/src/components/va-textarea/VaTextarea.vue

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
v-model="valueComputed"
1313
v-bind="{ ...computedProps, ...listeners, ...validationAriaAttributes }"
1414
:style="computedStyle"
15-
:rows="computedRowsCount"
1615
:loading="isLoading"
1716
ref="textarea"
1817
:ariaLabel="$props.label"
@@ -25,7 +24,7 @@
2524
</template>
2625

2726
<script lang="ts">
28-
import { computed, defineComponent, CSSProperties, shallowRef } from 'vue'
27+
import { computed, defineComponent, CSSProperties, shallowRef, ref, watch } from 'vue'
2928
import pick from 'lodash/pick.js'
3029
import { VaInputWrapper } from '../va-input-wrapper'
3130
@@ -117,24 +116,53 @@ export default defineComponent({
117116
const isResizable = computed(() => {
118117
return props.resize && !props.autosize
119118
})
119+
const textareaHeight = ref('auto')
120120
121-
const computedRowsCount = computed<number | undefined>(() => {
122-
if (!props.autosize) {
123-
return undefined
121+
const updateTextareaHeight = () => {
122+
if (!textarea.value) {
123+
return false
124+
}
125+
console.log('updateTextareaHeight')
126+
textarea.value.style.height = '0'
127+
const scrollHeight = textarea.value?.scrollHeight
128+
const lineHeight = parseInt(
129+
window.getComputedStyle(textarea.value)?.lineHeight,
130+
10,
131+
)
132+
let rows = scrollHeight / lineHeight
133+
134+
console.log('scrollHeight', scrollHeight)
135+
console.log('lineHeight', lineHeight)
136+
console.log('rows', rows)
137+
console.log('Rounded Rows = ', Math.round(scrollHeight / lineHeight))
138+
139+
if (props.maxRows) {
140+
rows = Math.max(props.minRows, Math.min(rows, props.maxRows))
124141
}
125142
126-
const rows = valueComputed.value ? valueComputed.value.toString().split('\n').length : 1
127-
128-
if (!props.maxRows) {
129-
return rows
143+
if (props.minRows) {
144+
rows = Math.max(props.minRows, rows)
130145
}
131146
132-
return Math.max(props.minRows, Math.min(rows, props.maxRows))
133-
})
147+
const height = rows * lineHeight + 'px'
148+
149+
console.log('height = ', height)
150+
151+
textareaHeight.value = '' + height
152+
}
153+
154+
watch([valueComputed, textarea], updateTextareaHeight, { immediate: true })
134155
135-
const computedStyle = computed(() => ({
136-
resize: isResizable.value ? undefined : 'none',
137-
}) as CSSProperties)
156+
const computedStyle = computed(
157+
() =>
158+
({
159+
resize: isResizable.value ? undefined : 'none',
160+
height:
161+
props.autosize && textareaHeight.value
162+
? textareaHeight.value
163+
: undefined,
164+
} as CSSProperties),
165+
)
138166
139167
const computedProps = computed(() => ({
140168
...pick(props, ['disabled', 'readonly', 'placeholder', 'ariaLabel']),
@@ -147,13 +175,13 @@ export default defineComponent({
147175
computedError,
148176
computedErrorMessages,
149177
isLoading,
150-
computedRowsCount,
151178
valueComputed,
152179
vaInputWrapperProps: filterComponentProps(VaInputWrapperProps),
153180
textarea,
154181
computedStyle,
155182
listeners: createListeners(emit),
156183
computedProps,
184+
textareaHeight,
157185
focus,
158186
blur,
159187
}

0 commit comments

Comments
 (0)