Skip to content

Commit e8e7234

Browse files
authored
fix(VTextarea): mask should not clip scrollbar (#22001)
fixes #21283 closes #21302
1 parent 1cc009f commit e8e7234

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

packages/vuetify/src/components/VTextarea/VTextarea.sass

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
.v-field__input
1616
$a: calc((var(--v-field-padding-top, 0) + var(--v-input-padding-top, 0)) - 6px)
1717
$b: calc(var(--v-field-padding-top, 0) + var(--v-input-padding-top, 0) + 4px)
18+
$c: calc(100% - var(--v-textarea-scroll-bar-width, 16px))
1819

1920
flex: 1 1 auto
2021
outline: none
21-
-webkit-mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b)
22-
mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b)
22+
23+
-webkit-mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b), linear-gradient(to right, transparent, transparent $c, black $c)
24+
mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b), linear-gradient(to right, transparent, transparent $c, black $c)
2325

2426
&.v-textarea__sizer
2527
visibility: hidden

packages/vuetify/src/components/VTextarea/VTextarea.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { makeVFieldProps } from '@/components/VField/VField'
99
import { makeVInputProps, VInput } from '@/components/VInput/VInput'
1010

1111
// Composables
12+
import { useDisplay } from '@/composables'
1213
import { makeAutocompleteProps, useAutocomplete } from '@/composables/autocomplete'
1314
import { useAutofocus } from '@/composables/autofocus'
1415
import { useFocus } from '@/composables/focus'
@@ -101,6 +102,8 @@ export const VTextarea = genericComponent<VTextareaSlots>()({
101102
const vFieldRef = ref<VInput>()
102103
const controlHeight = shallowRef('')
103104
const textareaRef = ref<HTMLInputElement>()
105+
const scrollbarWidth = ref(0)
106+
const { platform } = useDisplay()
104107
const autocomplete = useAutocomplete(props)
105108
const isActive = computed(() => (
106109
props.persistentPlaceholder ||
@@ -157,6 +160,16 @@ export const VTextarea = genericComponent<VTextareaSlots>()({
157160
if (!props.autoGrow) rows.value = Number(props.rows)
158161
})
159162
function calculateInputHeight () {
163+
nextTick(() => {
164+
if (!textareaRef.value) return
165+
if (platform.value.firefox) {
166+
scrollbarWidth.value = 12
167+
return
168+
}
169+
const { offsetWidth, clientWidth } = textareaRef.value
170+
scrollbarWidth.value = Math.max(0, offsetWidth - clientWidth)
171+
})
172+
160173
if (!props.autoGrow) return
161174

162175
nextTick(() => {
@@ -232,7 +245,12 @@ export const VTextarea = genericComponent<VTextareaSlots>()({
232245
},
233246
props.class,
234247
]}
235-
style={ props.style }
248+
style={[
249+
{
250+
'--v-textarea-scroll-bar-width': convertToUnit(scrollbarWidth.value),
251+
},
252+
props.style,
253+
]}
236254
{ ...rootAttrs }
237255
{ ...inputProps }
238256
centerAffix={ rows.value === 1 && !isPlainOrUnderlined.value }

0 commit comments

Comments
 (0)