mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [input] textarea supports clearing effects (#23723)
* feat(components): [input] textarea supports clearing effects * Update packages/components/input/__tests__/input.test.tsx Co-authored-by: rzzf <cszhjh@gmail.com> * feat: update * Apply suggestions from code review Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * style: update * Update packages/components/input/src/input.vue Co-authored-by: rzzf <cszhjh@gmail.com> --------- Co-authored-by: rzzf <cszhjh@gmail.com> Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>
This commit is contained in:
@@ -25,7 +25,7 @@ input/disabled
|
||||
|
||||
## Clearable
|
||||
|
||||
:::demo Make the Input clearable with the `clearable` attribute.
|
||||
:::demo Make the Input clearable with the `clearable` attribute. After version ^(2.13.4), the clearable feature is also available for textarea type of Input.
|
||||
|
||||
input/clearable
|
||||
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
<template>
|
||||
<el-input
|
||||
v-model="input"
|
||||
clearable
|
||||
:clear-icon="CloseBold"
|
||||
placeholder="Custom clear icon"
|
||||
/>
|
||||
<div class="input-group">
|
||||
<el-input
|
||||
v-model="input"
|
||||
clearable
|
||||
:clear-icon="CloseBold"
|
||||
placeholder="Custom clear icon"
|
||||
/>
|
||||
<el-input
|
||||
v-model="textareaInput"
|
||||
clearable
|
||||
:clear-icon="CloseBold"
|
||||
placeholder="Custom clear icon"
|
||||
type="textarea"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -12,4 +21,13 @@ import { ref } from 'vue'
|
||||
import { CloseBold } from '@element-plus/icons-vue'
|
||||
|
||||
const input = ref('Custom clear icon')
|
||||
const textareaInput = ref('Custom clear icon')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
<template>
|
||||
<el-input
|
||||
v-model="input"
|
||||
style="width: 240px"
|
||||
placeholder="Please input"
|
||||
clearable
|
||||
/>
|
||||
<div class="input-group">
|
||||
<el-input
|
||||
v-model="input"
|
||||
style="width: 240px"
|
||||
placeholder="Please input"
|
||||
clearable
|
||||
/>
|
||||
<el-input
|
||||
v-model="textareaInput"
|
||||
style="width: 240px"
|
||||
placeholder="Please input"
|
||||
type="textarea"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const input = ref('')
|
||||
const textareaInput = ref('')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -457,28 +457,49 @@ describe('Input.vue', () => {
|
||||
const handleClear = vi.fn()
|
||||
const handleInput = vi.fn()
|
||||
const content = ref('a')
|
||||
const handleTextareaClear = vi.fn()
|
||||
const handleTextareaInput = vi.fn()
|
||||
const textareaContent = ref('a')
|
||||
|
||||
const wrapper = mount(() => (
|
||||
<Input
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
v-model={content.value}
|
||||
onClear={handleClear}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<>
|
||||
<Input
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
v-model={content.value}
|
||||
onClear={handleClear}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<Input
|
||||
type="textarea"
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
v-model={textareaContent.value}
|
||||
onClear={handleTextareaClear}
|
||||
onInput={handleTextareaInput}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
|
||||
const input = wrapper.find('input')
|
||||
const vm = wrapper.vm
|
||||
const textarea = wrapper.find('textarea')
|
||||
// focus to show clear button
|
||||
await input.trigger('focus')
|
||||
await nextTick()
|
||||
vm.$el.querySelector('.el-input__clear').click()
|
||||
wrapper.find('.el-input__clear').trigger('click')
|
||||
await nextTick()
|
||||
expect(content.value).toEqual('')
|
||||
expect(handleClear).toBeCalled()
|
||||
expect(handleClear).toBeCalledWith(expect.any(MouseEvent))
|
||||
expect(handleInput).toBeCalled()
|
||||
// textarea
|
||||
await textarea.trigger('focus')
|
||||
await nextTick()
|
||||
wrapper.find('.el-textarea__clear').trigger('click')
|
||||
await nextTick()
|
||||
expect(textareaContent.value).toEqual('')
|
||||
expect(handleTextareaClear).toBeCalled()
|
||||
expect(handleTextareaInput).toBeCalled()
|
||||
})
|
||||
|
||||
test('event:input', async () => {
|
||||
|
||||
@@ -121,7 +121,11 @@
|
||||
<textarea
|
||||
:id="inputId"
|
||||
ref="textarea"
|
||||
:class="[nsTextarea.e('inner'), nsInput.is('focus', isFocused)]"
|
||||
:class="[
|
||||
nsTextarea.e('inner'),
|
||||
nsInput.is('focus', isFocused),
|
||||
nsTextarea.is('clearable', clearable),
|
||||
]"
|
||||
v-bind="attrs"
|
||||
:name="name"
|
||||
:minlength="minlength"
|
||||
@@ -146,6 +150,14 @@
|
||||
@change="handleChange"
|
||||
@keydown="handleKeydown"
|
||||
/>
|
||||
<el-icon
|
||||
v-if="showClear"
|
||||
:class="[nsTextarea.e('icon'), nsTextarea.e('clear')]"
|
||||
@mousedown.prevent="NOOP"
|
||||
@click="clear"
|
||||
>
|
||||
<component :is="clearIcon" />
|
||||
</el-icon>
|
||||
<span
|
||||
v-if="isWordLimitVisible"
|
||||
:style="countStyle"
|
||||
|
||||
@@ -82,6 +82,11 @@
|
||||
transition: getCssVar('transition-box-shadow');
|
||||
border: none;
|
||||
|
||||
@include when(clearable) {
|
||||
padding: 5px map.get($input-padding-horizontal, 'default') + 14px 5px
|
||||
map.get($input-padding-horizontal, 'default')-$border-width;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: getCssVarWithDefault(
|
||||
'input-placeholder-color',
|
||||
@@ -99,6 +104,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include e(clear) {
|
||||
position: absolute;
|
||||
right: 11px;
|
||||
top: 15px;
|
||||
transform: translateY(-50%);
|
||||
color: getCssVar('input-icon-color');
|
||||
font-size: map.get($input-font-size, 'default');
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: getCssVar('input-clear-hover-color');
|
||||
}
|
||||
}
|
||||
|
||||
& .#{$namespace}-input__count {
|
||||
color: getCssVar('color-info');
|
||||
background: getCssVar('fill-color', 'blank');
|
||||
@@ -107,6 +126,7 @@
|
||||
line-height: 14px;
|
||||
bottom: 5px;
|
||||
right: 10px;
|
||||
|
||||
@include when(outside) {
|
||||
position: absolute;
|
||||
background: transparent;
|
||||
@@ -182,12 +202,14 @@
|
||||
display: inline-block;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
@include when(outside) {
|
||||
height: unset;
|
||||
position: absolute;
|
||||
padding-top: 2px;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
|
||||
.#{$namespace}-input__count-inner {
|
||||
background: transparent;
|
||||
padding-left: 0px;
|
||||
@@ -401,6 +423,7 @@
|
||||
padding: $border-width
|
||||
map.get($input-padding-horizontal, $size)-$border-width;
|
||||
}
|
||||
|
||||
& {
|
||||
@include set-css-var-value(
|
||||
'input-inner-height',
|
||||
|
||||
Reference in New Issue
Block a user