Skip to content

Commit

Permalink
feat: add textarea-autosize
Browse files Browse the repository at this point in the history
  • Loading branch information
satazor committed Oct 3, 2018
1 parent 6f03a30 commit e246d23
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 0 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"dependencies": {
"classnames": "^2.2.6",
"date-is-invalid": "^1.0.10",
"grow-element-fn": "^1.0.3",
"lodash": "^4.17.10",
"normalize.css": "^8.0.0",
"prop-types": "^15.6.2",
Expand Down
19 changes: 19 additions & 0 deletions src/components/textarea-autosize/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# TextareaAutosize

A textarea component that auto-resizes.

## Usage

```jsx
import { TextareaAutosize } from '@discussify/styleguide';

<TextareaAutosize />
```

## Props

| name | type | default | description |
| ---- | ---- | ------- | ----------- |
| maxRows | number | | The number of max rows of the textarea |

Any other properties supplied will be spread to the root element. One useful textarea property is `rows`, which defines the minimum number of rows within the textarea.
5 changes: 5 additions & 0 deletions src/components/textarea-autosize/TextareaAutosize.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.textareaAutosize {
overflow: hidden;
resize: none;
transition: height 0.2s ease, max-height 0.2s ease;
}
80 changes: 80 additions & 0 deletions src/components/textarea-autosize/TextareaAutosize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { Component } from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import growElementFn from 'grow-element-fn';
import { debounce } from 'lodash';
import styles from './TextareaAutosize.css';

export default class TextareaAutosize extends Component {
static propTypes = {
rows: PropTypes.number,
maxRows: PropTypes.number,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
className: PropTypes.string,
};

static defaultProps = {
rows: 1,
};

componentDidMount() {
this.updateSize();
window.addEventListener('resize', this.handleResize);
}

componentDidUpdate() {
this.updateSize();
}

componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}

render() {
const { className, rest } = this.props;

return (
<textarea
ref={ this.storeNode }
onFocus={ this.handleFocus }
onBlur={ this.handleBlur }
{ ...rest }
className={ classNames(styles.textareaAutosize, className) } />
);
}

storeNode = (ref) => {
this.node = findDOMNode(ref);

if (this.node) {
this.node.addEventListener('focus', this.updateSize);
this.node.addEventListener('blur', this.updateSize);
this.node.addEventListener('input', this.updateSize);
}
};

updateSize = () => {
growElementFn({
el: this.node,
minLines: this.props.rows,
maxLines: this.props.maxRows,
extraLine: this.focused,
});
};

handleFocus = () => {
this.focused = true;
this.updateSize();
this.props.onFocus && this.props.onFocus();
};

handleBlur = () => {
this.focused = false;
this.updateSize();
this.props.onBlur && this.props.onBlur();
};

handleResize = debounce(() => this.updateSize(), 500);
}
1 change: 1 addition & 0 deletions src/components/textarea-autosize/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './TextareaAutosize.js';
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export * from './components/icon';
export * from './components/modal';
export * from './components/popover';
export { default as TextButton } from './components/text-button';
export { default as TextareaAutosize } from './components/textarea-autosize';
export { default as TimeAgo } from './components/time-ago';
13 changes: 13 additions & 0 deletions src/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ body {
overflow-wrap: break-word; /* Break long words by default */
}

input,
select {
@mixin typography-body-1 rem;
color: var(--color-black);
}

textarea {
@mixin typography-body-1 rem;
color: var(--color-black);
white-space: pre-line;
overflow-wrap: break-word; /* Break long words by default */
}

::selection {
background: var(--color-science-blue);
color: var(--color-seashell);
Expand Down
1 change: 1 addition & 0 deletions stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ import './icon';
import './modal';
import './popover';
import './text-button';
import './textarea-autosize';
import './time-ago';
import './typing-indicator';
33 changes: 33 additions & 0 deletions stories/textarea-autosize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withKnobs, boolean, number } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import { withReadme } from 'storybook-readme';
import { TextareaAutosize } from '../src';
import readme from '../src/components/textarea-autosize/README.md';

storiesOf('TextareaAutosize', module)
.addDecorator(withReadme(readme))
.addDecorator(withKnobs)
.add('Default', () => (
<TextareaAutosize />
))
.add('5 max rows ', () => (
<TextareaAutosize maxRows={ 5 } />
))
.add('2 rows, 5 max rows ', () => (
<TextareaAutosize rows={ 2 } maxRows={ 5 } />
))
.add('Knobs playground ⚽', () => {
const rows = number('rows', 1);
const maxRows = number('maxRows', 5);
const disabled = boolean('disabled');

return (
<TextareaAutosize
rows={ rows }
maxRows={ maxRows }
disabled={ disabled }
onHeightChange={ action('height changed') } />
);
});

0 comments on commit e246d23

Please sign in to comment.