mand-mobile/components/textarea-item/index.vue

272 lines
5.9 KiB
Vue

<template>
<md-field-item
class="md-textarea-item"
:class="[
isDisabled ? 'is-disabled' : '',
errorInfo ? 'is-error' : ''
]"
:title="title"
:solid="solid"
>
<textarea
class="md-textarea-item__textarea"
ref="textarea"
v-model="inputValue"
:disabled="isDisabled"
:readonly="readonly"
:maxlength="maxLength"
:placeholder="placeholder"
:rows="rows"
@input="$_onInput"
@focus="$_onFocus"
@blur="$_onBlur"
@keyup="$_onKeyup"
@keydown="$_onKeydown"
></textarea>
<slot name="footer"></slot>
<template slot="right">
<div
class="md-textarea-item__clear"
v-if="clearable && !isDisabled && !readonly"
v-show="!isInputEmpty && isInputFocus"
@click="$_clearInput"
>
<md-icon name="clear"></md-icon>
</div>
<slot name="right"></slot>
</template>
<template slot="children">
<div v-if="errorInfo" class="md-textarea-item-msg">
<p>{{ errorInfo }}</p>
</div>
</template>
</md-field-item>
</template>
<script>
import FieldItem from '../field-item'
import Icon from '../icon'
import {noop, randomId} from '../_util'
import {getCursorsPosition, setCursorsPosition} from '../input-item/cursor'
export default {
name: 'md-textarea-item',
components: {
[FieldItem.name]: FieldItem,
[Icon.name]: Icon,
},
props: {
title: {
type: String,
default: '',
},
name: {
type: [String, Number],
default() {
return randomId('input-item')
},
},
placeholder: {
type: String,
default: '',
},
value: {
type: String,
default: '',
},
maxLength: {
type: [String, Number],
default: '',
},
maxHeight: {
type: [String, Number],
default: '',
},
solid: {
type: Boolean,
default: true,
},
readonly: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: false,
},
rows: {
type: [String, Number],
default: '3',
},
autosize: {
type: Boolean,
default: false,
},
error: {
type: String,
defalut: '',
},
formation: {
type: Function,
default: noop,
},
},
data() {
return {
maxHeightInner: this.maxHeight,
inputValue: this.value,
isInputFocus: false,
}
},
computed: {
isDisabled() {
return this.disabled
},
errorInfo() {
return this.error
},
isInputEmpty() {
return !this.inputValue.length
},
},
watch: {
value(val) {
this.inputValue = val
this.$nextTick(() => {
this.resizeTextarea()
})
},
inputValue(val) {
this.$emit('input', val)
this.$emit('change', val)
},
maxHeight(val) {
this.maxHeightInner = val
this.resizeTextarea()
},
},
mounted() {
this.resizeTextarea()
},
methods: {
$_onInput(event) {
const formateValue = this.$_formateValue(event.target.value, getCursorsPosition(event.target))
this.inputValue = formateValue.value
this.$nextTick(() => {
setCursorsPosition(event.target, formateValue.range)
this.resizeTextarea()
})
},
$_formateValue(curValue, curPos = 0) {
// custom format by user
const customValue = this.formation(name, curValue, curPos)
if (customValue) {
return customValue
}
// no format
return {value: curValue, range: curPos}
},
$_clearInput() {
this.inputValue = ''
this.$nextTick(() => {
this.resizeTextarea()
})
this.focus()
},
$_onKeyup(event) {
this.$emit('keyup', event)
},
$_onKeydown(event) {
this.$emit('keydown', event)
},
$_onFocus() {
this.isInputFocus = true
this.$emit('focus')
},
$_onBlur() {
setTimeout(() => {
this.isInputFocus = false
this.$emit('blur')
}, 100)
},
$_calcTextareaHeight(textarea) {
// Triggers the textarea to repaint
textarea.style.height = 'auto'
let scrollHeight = textarea.scrollHeight
// if textarea-item is not displayed, avoid height calculations
if (scrollHeight === 0) {
return
}
if (this.maxHeightInner && scrollHeight > this.maxHeightInner) {
scrollHeight = this.maxHeightInner
}
textarea.style.height = scrollHeight + 'px'
},
// public
resizeTextarea() {
if (this.autosize) {
this.$_calcTextareaHeight(this.$refs.textarea)
}
},
focus() {
this.$refs.textarea.focus()
setTimeout(() => {
this.isInputFocus = true
}, 200)
},
blur() {
this.$refs.textarea.blur()
this.isInputFocus = false
},
getValue() {
return this.inputValue
},
},
}
</script>
<style lang="stylus">
.md-textarea-item
&-msg
color textarea-item-color-error
.md-field-item-content
align-items normal
&.is-disabled
.md-textarea-item__textarea
-webkit-text-fill-color textarea-item-color-disabled
color textarea-item-color-disabled
.md-field-item-right
align-items start
&__clear
padding 6px 0
color textarea-item-icon
.md-icon
display flex
&__textarea
box-sizing border-box
width 100%
font textarea-item-font-weight textarea-item-font-size font-family-normal
line-height textarea-item-line-height
color textarea-item-color
background transparent
border none
outline none
resize none
appearance none
-webkit-tap-highlight-color transparent
&::-webkit-input-placeholder
color textarea-item-placeholder-color
font-weight textarea-item-placeholder-weight
&.is-error
.md-field-item-content
hairline(bottom, textarea-item-color-error, 0, 4px)
</style>