import { Component , h , ComponentInterface , Prop , State , Event , EventEmitter , Element } from '@stencil/core' ; import { TaroEvent } from '../../../types' ; function fixControlledValue ( value ? ) { return value ?? '' ; } @ Component ( { tag : 'taro-textarea-core' , styleUrl : './style/index.scss' } ) export class Textarea implements ComponentInterface { private textareaRef : HTMLTextAreaElement ; @ Element ( ) el : HTMLElement ; @ Prop ( ) value : string ; @ Prop ( ) placeholder : string ; @ Prop ( ) disabled = false ; @ Prop ( ) maxlength = 140 ; @ Prop ( ) autoFocus = false ; @ Prop ( ) autoHeight = false ; @ Prop ( ) name : string ; @ Prop ( ) nativeProps = { } ; @ State ( ) line = 1 ; @ Event ( { eventName : 'input' } ) onInput : EventEmitter ; @ Event ( { eventName : 'focus' } ) onFocus : EventEmitter ; @ Event ( { eventName : 'blur' } ) onBlur : EventEmitter ; @ Event ( { eventName : 'change' } ) onChange : EventEmitter ; @ Event ( { eventName : 'linechange' } ) onLineChange : EventEmitter ; componentDidLoad ( ) { Object . defineProperty ( this . el , 'value' , { get : ( ) => this . textareaRef . value , set : value => ( this . value = value ) , configurable : true } ) ; this . autoFocus && this . textareaRef . focus ( ) ; } handleInput = ( e ) => { e . stopPropagation ( ) ; this . handleLineChange ( ) ; this . onInput . emit ( { value : e . target . value , cursor : e . target . value . length } ) ; } ; handleFocus = ( e ) => { this . onFocus . emit ( { value : e . target . value } ) ; } ; handleBlur = ( e ) => { this . onBlur . emit ( { value : e . target . value } ) ; } ; handleChange = ( e ) => { e . stopPropagation ( ) ; this . onChange . emit ( { value : e . target . value } ) ; } ; handleLineChange = ( ) => { const line = this . getNumberOfLines ( ) ; if ( line !== this . line ) { this . line = line ; this . onLineChange . emit ( { height : this . textareaRef . clientHeight , lineCount : this . line } ) ; } } ; calculateContentHeight = ( ta , scanAmount ) => { let origHeight = ta . style . height , height = ta . offsetHeight , scrollHeight = ta . scrollHeight , overflow = ta . style . overflow ; if ( height >= scrollHeight ) { ta . style . height = height + scanAmount + 'px' ; ta . style . overflow = 'hidden' ; if ( scrollHeight < ta . scrollHeight ) { while ( ta . offsetHeight >= ta . scrollHeight ) { ta . style . height = ( height -= scanAmount ) + 'px' ; } while ( ta . offsetHeight < ta . scrollHeight ) { ta . style . height = height ++ + 'px' ; } ta . style . height = origHeight ; ta . style . overflow = overflow ; return height ; } } else { return scrollHeight ; } } ; getNumberOfLines = ( ) => { const ta = this . textareaRef , style = window . getComputedStyle ? window . getComputedStyle ( ta ) : ta . style , taLineHeight = parseInt ( style . lineHeight , 10 ) , taHeight = this . calculateContentHeight ( ta , taLineHeight ) , numberOfLines = Math . floor ( taHeight / taLineHeight ) ; return numberOfLines ; } ; render ( ) { const { value , placeholder , disabled , maxlength , autoFocus , autoHeight , name , nativeProps , handleInput , handleFocus , handleBlur , handleChange } = this ; const otherProps = { } ; if ( autoHeight ) { otherProps . rows = this . line ; } return ( < textarea ref = { input => { if ( input ) { this . textareaRef = input ; } } } class = { `taro-textarea ${ autoHeight ? 'auto-height' : '' }` } value = { fixControlledValue ( value ) } placeholder = { placeholder } name = { name } disabled = { disabled } maxlength = { maxlength } autofocus = { autoFocus } onInput = { handleInput } onFocus = { handleFocus } onBlur = { handleBlur } onChange = { handleChange } { ... nativeProps } { ... otherProps } />); } }