diff --git a/packages/react-core/src/components/TextArea/TextArea.tsx b/packages/react-core/src/components/TextArea/TextArea.tsx index 27599a49fe5..458431d48bd 100644 --- a/packages/react-core/src/components/TextArea/TextArea.tsx +++ b/packages/react-core/src/components/TextArea/TextArea.tsx @@ -54,6 +54,21 @@ export class TextAreaBase extends React.Component { 'aria-label': null as string }; + inputRef = React.createRef(); + + private setAutoHeight = (field: HTMLTextAreaElement) => { + field.style.setProperty(heightToken.name, 'inherit'); + const computed = window.getComputedStyle(field); + // Calculate the height + const height = + parseInt(computed.getPropertyValue('border-top-width')) + + parseInt(computed.getPropertyValue('padding-top')) + + field.scrollHeight + + parseInt(computed.getPropertyValue('padding-bottom')) + + parseInt(computed.getPropertyValue('border-bottom-width')); + field.style.setProperty(heightToken.name, `${height}px`); + }; + constructor(props: TextAreaProps) { super(props); if (!props.id && !props['aria-label']) { @@ -62,20 +77,19 @@ export class TextAreaBase extends React.Component { } } + componentDidMount(): void { + const inputRef = this.props.innerRef || this.inputRef; + if (this.props.autoResize && canUseDOM) { + const field = inputRef.current; + this.setAutoHeight(field); + } + } + private handleChange = (event: React.ChangeEvent) => { // https://gomakethings.com/automatically-expand-a-textarea-as-the-user-types-using-vanilla-javascript/ const field = event.currentTarget; if (this.props.autoResize && canUseDOM) { - field.style.setProperty(heightToken.name, 'inherit'); - const computed = window.getComputedStyle(field); - // Calculate the height - const height = - parseInt(computed.getPropertyValue('border-top-width')) + - parseInt(computed.getPropertyValue('padding-top')) + - field.scrollHeight + - parseInt(computed.getPropertyValue('padding-bottom')) + - parseInt(computed.getPropertyValue('border-bottom-width')); - field.style.setProperty(heightToken.name, `${height}px`); + this.setAutoHeight(field); } if (this.props.onChange) { this.props.onChange(field.value, event); @@ -118,14 +132,14 @@ export class TextAreaBase extends React.Component { required={isRequired} disabled={isDisabled || disabled} readOnly={isReadOnly || readOnly} - ref={innerRef} + ref={innerRef || this.inputRef} {...props} /> ); } } -export const TextArea = React.forwardRef((props, ref) => ( +export const TextArea = React.forwardRef((props: TextAreaProps, ref: React.Ref) => ( } /> )); TextArea.displayName = 'TextArea'; diff --git a/packages/react-core/src/components/TextArea/examples/TextArea.md b/packages/react-core/src/components/TextArea/examples/TextArea.md index b28228c60ba..892606d3d5d 100644 --- a/packages/react-core/src/components/TextArea/examples/TextArea.md +++ b/packages/react-core/src/components/TextArea/examples/TextArea.md @@ -6,7 +6,9 @@ propComponents: ['TextArea'] --- ## Examples + ### Basic + ```js import React from 'react'; import { TextArea } from '@patternfly/react-core'; @@ -32,6 +34,7 @@ class SimpleTextArea extends React.Component { ``` ### Invalid + ```js import React from 'react'; import { TextArea } from '@patternfly/react-core'; @@ -42,7 +45,7 @@ class InvalidTextArea extends React.Component { this.state = { value: '' }; - + this.handleInvalidTextAreaChange = value => { this.setState({ value }); }; @@ -65,6 +68,7 @@ class InvalidTextArea extends React.Component { ``` ### Validated + ```js import React from 'react'; import { Form, FormGroup, TextArea } from '@patternfly/react-core'; @@ -78,28 +82,30 @@ class InvalidTextArea extends React.Component { validated: 'default', helperText: 'Share your thoughts.' }; - + this.simulateNetworkCall = callback => { setTimeout(callback, 2000); - } - - this.handleTextAreaChange = value => { + }; - this.setState({ - value, - validated: 'default', - helperText: 'Validating...', - }, + this.handleTextAreaChange = value => { + this.setState( + { + value, + validated: 'default', + helperText: 'Validating...' + }, this.simulateNetworkCall(() => { if (value && value.length > 0) { if (value.length >= 10) { - this.setState({validated: 'success', helperText: 'Thanks for your comments!'}); + this.setState({ validated: 'success', helperText: 'Thanks for your comments!' }); } else { - this.setState({validated: 'error', invalidText: 'Your being too brief, please enter at least 10 characters.'}); + this.setState({ + validated: 'error', + invalidText: 'Your being too brief, please enter at least 10 characters.' + }); } - } - else { - this.setState({validated: 'warning', helperText: 'You must have something to say'}); + } else { + this.setState({ validated: 'warning', helperText: 'You must have something to say' }); } }) ); @@ -134,6 +140,7 @@ class InvalidTextArea extends React.Component { ``` ### Vertically resizable text area + ```js import React from 'react'; import { TextArea } from '@patternfly/react-core'; @@ -153,12 +160,20 @@ class VerticalResizeTextArea extends React.Component { render() { const { value } = this.state; - return