packageDocumentation module import "./TextareaEditor.scss" ; import classnames from "classnames" ; import * as React from "react" ; import { InputEditorSizeParams , MultilineTextEditorParams , PrimitiveValue , PropertyEditorParams , PropertyEditorParamTypes , PropertyValue , PropertyValueFormat , StandardEditorNames , StandardTypeNames , } from "@itwin/appui-abstract" ; import { Textarea , TextareaProps } from "@itwin/itwinui-react" ; import { TypeConverterManager } from "../converters/TypeConverterManager" ; import { PropertyEditorProps , TypeEditor } from "./EditorContainer" ; import { PropertyEditorBase , PropertyEditorManager } from "./PropertyEditorManager" ; import { PopupButton , PopupContent , PopupOkCancelButtons } from "./PopupButton" ; import { UiComponents } from "../UiComponents" ; internal interface TextareaEditorState { inputValue : string ; readonly : boolean ; isDisabled ? : boolean ; size ? : number ; maxLength ? : number ; rows : number ; } const DEFAULT_ROWS = 3 ; public export class TextareaEditor extends React . PureComponent < PropertyEditorProps , TextareaEditorState > implements TypeEditor { private _isMounted = false ; private _ariaLabel = UiComponents . translate ( "editor.textarea" ) ; private _divElement = React . createRef < HTMLDivElement > ( ) ; internal public override readonly state : Readonly < TextareaEditorState > = { inputValue : "" , readonly : false , rows : DEFAULT_ROWS } ; public async getPropertyValue ( ) { const record = this . props . propertyRecord ; let propertyValue ; if ( record && record . value . valueFormat === PropertyValueFormat . Primitive ) { propertyValue = await TypeConverterManager . getConverter ( record . property . typename ) . convertFromStringToPropertyValue ( this . state . inputValue , record ) ; ( propertyValue as PrimitiveValue ) . displayValue = this . state . inputValue ; } return propertyValue ; } public get htmlElement ( ) : HTMLElement | null { return this . _divElement . current ; } public get hasFocus ( ) : boolean { let containsFocus = false ; if ( this . _divElement . current ) containsFocus = this . _divElement . current . contains ( document . activeElement ) ; return containsFocus ; } private _updateTextareaValue = ( e ) => { if ( this . _isMounted ) this . setState ( { inputValue : e . target . value } ) ; } ; internal public override componentDidMount ( ) { this . _isMounted = true ; this . setStateFromProps ( ) ; } internal public override componentWillUnmount ( ) { this . _isMounted = false ; } internal public override componentDidUpdate ( prevProps ) { if ( this . props . propertyRecord !== prevProps . propertyRecord ) { this . setStateFromProps ( ) ; } } private async setStateFromProps ( ) { const record = this . props . propertyRecord ; let initialValue = "" ; if ( record && record . value . valueFormat === PropertyValueFormat . Primitive ) { const value = record . value . value ; initialValue = await TypeConverterManager . getConverter ( record . property . typename ) . convertPropertyToString ( record . property , value ) ; } const readonly = record && undefined !== record . isReadonly ? record . isReadonly : false ; let size ; let maxLength ; let rows = DEFAULT_ROWS ; const isDisabled = record ? record . isDisabled : undefined ; if ( record && record . property && record . property . editor && record . property . editor . params ) { const editorSizeParams = record . property . editor . params . find ( ( param ) => param . type === PropertyEditorParamTypes . InputEditorSize ) as InputEditorSizeParams ; if ( editorSizeParams ) { if ( editorSizeParams . size ) size = editorSizeParams . size ; if ( editorSizeParams . maxLength ) maxLength = editorSizeParams . maxLength ; } const multilineParams = record . property . editor . params . find ( ( param ) => param . type === PropertyEditorParamTypes . MultilineText ) as MultilineTextEditorParams ; if ( multilineParams ) { rows = multilineParams . rows ; } } if ( this . _isMounted ) this . setState ( { inputValue : initialValue , readonly , size , maxLength , isDisabled , rows } ) ; } private _handleOk = async ( _event ) : Promise < void > => { if ( this . props . propertyRecord && this . props . onCommit ) { const propertyValue = await this . getPropertyValue ( ) ; if ( propertyValue !== undefined ) { this . props . onCommit ( { propertyRecord : this . props . propertyRecord , newValue : propertyValue } ) ; } } } ; private _handleCancel = ( _event ) : void => { if ( this . props . onCancel ) { this . props . onCancel ( ) ; } } ; internal public override render ( ) { const className = classnames ( "components-cell-editor" , "components-textarea-editor" , this . props . className ) ; const minSize = this . state . size ? this . state . size : 8 ; const style = { ... this . props . style , minWidth : `${ minSize * 0.75 }em` } ; const textareaProps = { className : "components-textarea-editor-textarea" , style , rows : this . state . rows , readOnly : this . state . readonly , disabled : this . state . isDisabled , maxLength : this . state . maxLength , value : this . state . inputValue , onChange : this . _updateTextareaValue , setFocus : this . props . setFocus && ! this . state . isDisabled } ; textareaProps [ "aria-label" ] = this . _ariaLabel ; return ( < div className = { className } ref = { this . _divElement } > < PopupButton label = { this . state . inputValue } closeOnEnter = { false } setFocus = { this . props . setFocus } focusTarget = ".uicore-inputs-textarea" > < PopupContent > < Textarea { ... textareaProps } data - testid = "components-textarea-editor" / > < PopupOkCancelButtons onOk = { this . _handleOk } onCancel = { this . _handleCancel } / > < /PopupContent> < /PopupButton> < /div>); } } public export class TextareaPropertyEditor extends PropertyEditorBase { public override get containerHandlesBlur ( ) : boolean { return false ; } public override get containerHandlesEnter ( ) : boolean { return false ; } public override get containerHandlesTab ( ) : boolean { return false ; } public get reactNode ( ) : React . ReactNode { return < TextareaEditor />; } } PropertyEditorManager . registerEditor ( StandardTypeNames . Text , TextareaPropertyEditor , StandardEditorNames . MultiLine ) ; PropertyEditorManager . registerEditor ( StandardTypeNames . String , TextareaPropertyEditor , StandardEditorNames . MultiLine ) ;