This repository was archived by the owner on Sep 25, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathElasticTextarea.js
More file actions
119 lines (95 loc) · 3.38 KB
/
ElasticTextarea.js
File metadata and controls
119 lines (95 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"use strict";
var React = require("react");
var _ = require("lodash");
/**
* Textarea which grows and shrinks automatically when user types text into it
*
* @namespace components
* @class ElasticTextarea
* @constructor
* @param {Object} props
* @param {Function} [props.onResize] Called when the textarea has been resized
* @param {Number} [props.minRows] Minimum rows size for the textarea
*/
var ElasticTextarea = React.createClass({
propTypes: {
onResize: React.PropTypes.func,
minRows: React.PropTypes.number
},
_isTooSmall: function(el) {
return el.scrollHeight > el.clientHeight;
},
getDefaultProps: function() {
return {
minRows: 1,
onKeyDown: function(){},
onResize: function(){}
};
},
_resize: function(reset) {
if (!this.refs.textarea) {
console.warn("ElasticTextarea: Cannot access textarea dom node. Cannot resize");
return;
}
var el = this.refs.textarea;
// Resizing the textarea causes some scrolling glitches when the
// textarea is very large. Workaround it by forcing the scroll position
// back to its original
var currentScrollPosition = [window.scrollX, window.scrollY];
if (el.value === "") {
el.rows = parseInt(this.props.minRows, 10);
return;
}
// If the textarea is not too small it might be too big. Force it to be
// too small.
if (!this._isTooSmall(el)) el.rows = parseInt(this.props.minRows, 10);
// Grow the textarea until it's large enough
while (this._isTooSmall(el)) el.rows++;
window.scrollTo.apply(window, currentScrollPosition);
process.nextTick(this.props.onResize.bind(null, {
target: el,
active: document.activeElement === el
}));
},
componentWillReceiveProps: function(nextProps) {
this.setState({ didChange: nextProps.value !== this.props.value });
},
componentDidMount: function() {
this._throttledResize = _.throttle(this._resize, 500, {
leading: false
});
window.addEventListener("resize", this._throttledResize);
this._resize();
},
componentWillUnmount: function() {
window.removeEventListener("resize", this._throttledResize);
},
componentDidUpdate: function() {
// Resize only if the content has changed
if (this.state.didChange) this._throttledResize();
},
style: {
// Chrome textarea resize tool can mess up this. Disable it.
resize: "none",
// When user holds down the enter key scroll bars might appear for few
// ms as resizing it is throttled. Ensure it stays hidden.
overflow: "hidden"
},
render: function() {
var self = this;
return (
<textarea
{...self.props}
style={this.style}
rows={this.props.minRows}
onKeyDown={function(e) {
// Enter always adds a line break. Resize instantly.
if (e.key === "Enter") setTimeout(self._resize, 0);
self.props.onKeyDown(e);
}}
ref="textarea"
className={"ElasticTextarea " + this.props.className}></textarea>
);
}
});
module.exports = ElasticTextarea;