diff --git a/packages/api-generator/src/locale/en/VTextarea.json b/packages/api-generator/src/locale/en/VTextarea.json index 05348794645..ee53b82fee5 100644 --- a/packages/api-generator/src/locale/en/VTextarea.json +++ b/packages/api-generator/src/locale/en/VTextarea.json @@ -12,7 +12,8 @@ }, "events": { "keydown": "Emitted when **any** key is pressed, textarea must be focused.", - "mousedown:control": "Event that is emitted when using mousedown on the main control area." + "mousedown:control": "Event that is emitted when using mousedown on the main control area.", + "update:rows": "Emitted when the number of rows changes." }, "slots": { "counter": "Slot for the input’s counter text." diff --git a/packages/vuetify/src/components/VTextarea/VTextarea.tsx b/packages/vuetify/src/components/VTextarea/VTextarea.tsx index 41a3786071a..e9562553ddb 100644 --- a/packages/vuetify/src/components/VTextarea/VTextarea.tsx +++ b/packages/vuetify/src/components/VTextarea/VTextarea.tsx @@ -70,6 +70,7 @@ export const VTextarea = genericComponent()({ 'mousedown:control': (e: MouseEvent) => true, 'update:focused': (focused: boolean) => true, 'update:modelValue': (val: string) => true, + 'update:rows': (rows: number) => true, }, setup (props, { attrs, emit, slots }) { @@ -187,6 +188,9 @@ export const VTextarea = genericComponent()({ watch(() => props.rows, calculateInputHeight) watch(() => props.maxRows, calculateInputHeight) watch(() => props.density, calculateInputHeight) + watch(rows, val => { + emit('update:rows', val) + }) let observer: ResizeObserver | undefined watch(sizerRef, val => { diff --git a/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.browser.tsx b/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.browser.tsx index 8bdd0dd4d54..4f20ec22296 100644 --- a/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.browser.tsx +++ b/packages/vuetify/src/components/VTextarea/__tests__/VTextarea.spec.browser.tsx @@ -54,4 +54,20 @@ describe('VTextarea', () => { await userEvent.keyboard('Lorem ipsum dolor sit amet consectetur adipisicing elit. ') await expect.poll(() => el.offsetHeight).toBe(80) }) + + it('should emit update rows', async () => { + await page.viewport(500, 500) + const model = ref('Lorem ipsum dolor sit amet, consectetur adipiscing elit') + const rows = ref(1) + render(() => ( + +
+ { rows.value = val } } /> +
+
+ )) + await userEvent.tab() + await userEvent.keyboard('Lorem ipsum dolor') + expect(rows.value).toBe(2) + }) }) diff --git a/packages/vuetify/src/composables/virtual.ts b/packages/vuetify/src/composables/virtual.ts index 4cc3344bce4..9b67a42ce14 100644 --- a/packages/vuetify/src/composables/virtual.ts +++ b/packages/vuetify/src/composables/virtual.ts @@ -132,7 +132,12 @@ export function useVirtual (props: VirtualProps, items: Ref) { function calculateOffset (index: number) { index = clamp(index, 0, items.value.length - 1) - return offsets[index] || 0 + const whole = Math.floor(index) + const fraction = index % 1 + const next = whole + 1 + const wholeOffset = offsets[whole] || 0 + const nextOffset = offsets[next] || wholeOffset + return wholeOffset + (nextOffset - wholeOffset) * fraction } function calculateIndex (scrollTop: number) {