Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions packages/react-core/src/components/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
'aria-label': null as string
};

inputRef = React.createRef<HTMLTextAreaElement>();

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']) {
Expand All @@ -62,20 +77,19 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
}
}

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<HTMLTextAreaElement>) => {
// 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);
Expand Down Expand Up @@ -118,14 +132,14 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
required={isRequired}
disabled={isDisabled || disabled}
readOnly={isReadOnly || readOnly}
ref={innerRef}
ref={innerRef || this.inputRef}
{...props}
/>
);
}
}

export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>((props, ref) => (
export const TextArea = React.forwardRef((props: TextAreaProps, ref: React.Ref<HTMLTextAreaElement>) => (
<TextAreaBase {...props} innerRef={ref as React.MutableRefObject<any>} />
));
TextArea.displayName = 'TextArea';
68 changes: 47 additions & 21 deletions packages/react-core/src/components/TextArea/examples/TextArea.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ propComponents: ['TextArea']
---

## Examples

### Basic

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';
Expand All @@ -32,6 +34,7 @@ class SimpleTextArea extends React.Component {
```

### Invalid

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';
Expand All @@ -42,7 +45,7 @@ class InvalidTextArea extends React.Component {
this.state = {
value: ''
};

this.handleInvalidTextAreaChange = value => {
this.setState({ value });
};
Expand All @@ -65,6 +68,7 @@ class InvalidTextArea extends React.Component {
```

### Validated

```js
import React from 'react';
import { Form, FormGroup, TextArea } from '@patternfly/react-core';
Expand All @@ -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' });
}
})
);
Expand Down Expand Up @@ -134,6 +140,7 @@ class InvalidTextArea extends React.Component {
```

### Vertically resizable text area

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';
Expand All @@ -153,12 +160,20 @@ class VerticalResizeTextArea extends React.Component {
render() {
const { value } = this.state;

return <TextArea value={value} onChange={this.handleTextAreaChange} resizeOrientation='vertical' aria-label="text vertical resize example" />;
return (
<TextArea
value={value}
onChange={this.handleTextAreaChange}
resizeOrientation="vertical"
aria-label="text vertical resize example"
/>
);
}
}
```

### Horizontally resizable text area

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';
Expand All @@ -178,33 +193,43 @@ class HorizontalResizeTextArea extends React.Component {
render() {
const { value } = this.state;

return <TextArea value={value} onChange={this.handleTextAreaChange} resizeOrientation='horizontal' aria-label="text horizontal resize example" />;
return (
<TextArea
value={value}
onChange={this.handleTextAreaChange}
resizeOrientation="horizontal"
aria-label="text horizontal resize example"
/>
);
}
}
```

### Uncontrolled

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';

<TextArea defaultValue="default value" aria-label="uncontrolled text area example" />
<TextArea defaultValue="default value" aria-label="uncontrolled text area example" />;
```

### Disabled

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';

<TextArea aria-label="disabled text area example" isDisabled />
<TextArea aria-label="disabled text area example" isDisabled />;
```

### Auto resizing

```js
import React from 'react';
import { TextArea } from '@patternfly/react-core';

<TextArea aria-label="auto resizing text area example" autoResize />
<TextArea aria-label="auto resizing text area example" autoResize />;
```

### Icon sprite variants
Expand Down Expand Up @@ -249,4 +274,5 @@ IconSpriteTextArea = () => {
/>
</>
);
};
};
```