Skip to content

Commit 5517611

Browse files
jeffmozpao
authored andcommitted
Implement ReactDOMTextarea
This changes `ReactDOMTextarea` to accept `defaultValue` and `value`. It will warn people about using children (but allow it and treat it as `defaultValue`, which is the current behavior).
1 parent 738de8c commit 5517611

File tree

5 files changed

+224
-162
lines changed

5 files changed

+224
-162
lines changed

src/core/ReactDOM.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ var ReactDOM = objMapKeyVal({
8080
embed: true,
8181
fieldset: false,
8282
footer: false,
83-
// Danger: this gets monkeypatched! See ReactDOMForm for more info.
84-
form: false,
83+
form: false, // NOTE: Injected, see `ReactDOMForm`.
8584
h1: false,
8685
h2: false,
8786
h3: false,
@@ -116,8 +115,7 @@ var ReactDOM = objMapKeyVal({
116115
table: false,
117116
tbody: false,
118117
td: false,
119-
// Danger: this gets monkeypatched! See ReactDOMTextarea for more info.
120-
textarea: false,
118+
textarea: false, // NOTE: Injected, see `ReactDOMTextarea`.
121119
tfoot: false,
122120
th: false,
123121
thead: false,

src/core/ReactDOMTextarea.js

Lines changed: 0 additions & 92 deletions
This file was deleted.

src/core/__tests__/ReactDOMTextarea-test.js

Lines changed: 0 additions & 66 deletions
This file was deleted.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Copyright 2013 Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* @providesModule ReactDOMTextarea
17+
*/
18+
19+
"use strict";
20+
21+
var DOMPropertyOperations = require('DOMPropertyOperations');
22+
var ReactCompositeComponent = require('ReactCompositeComponent');
23+
var ReactDOM = require('ReactDOM');
24+
25+
var invariant = require('invariant');
26+
var merge = require('merge');
27+
28+
// Store a reference to the <textarea> `ReactNativeComponent`.
29+
var textarea = ReactDOM.textarea;
30+
31+
// For quickly matching children type, to test if can be treated as content.
32+
var CONTENT_TYPES = {'string': true, 'number': true};
33+
34+
/**
35+
* Implements a <textarea> native component that allows setting `value`, and
36+
* `defaultValue`. This differs from the traditional DOM API because value is
37+
* usually set as PCDATA children.
38+
*
39+
* If `value` is not supplied (or null/undefined), user actions that affect the
40+
* value will trigger updates to the element.
41+
*
42+
* If `value` is supplied (and not null/undefined), the rendered element will
43+
* not trigger updates to the element. Instead, the `value` prop must change in
44+
* order for the rendered element to be updated.
45+
*
46+
* The rendered element will be initialized with an empty value, the prop
47+
* `defaultValue` if specified, or the children content (deprecated).
48+
*/
49+
var ReactDOMTextarea = ReactCompositeComponent.createClass({
50+
51+
getInitialState: function() {
52+
var defaultValue = this.props.defaultValue;
53+
// TODO (yungsters): Remove support for children content in <textarea>.
54+
var children = this.props.children;
55+
if (children != null) {
56+
global.console && console.warn && console.warn(
57+
'Use the `defaultValue` or `value` props instead of setting children ' +
58+
'on <textarea>.'
59+
);
60+
invariant(
61+
defaultValue == null,
62+
'If you supply `defaultValue` on a <textarea>, do not pass children.'
63+
);
64+
if (Array.isArray(children)) {
65+
invariant(
66+
children.length <= 1,
67+
'<textarea> can only have at most one child.'
68+
);
69+
children = children[0];
70+
}
71+
invariant(
72+
CONTENT_TYPES[typeof children],
73+
'If you specify children to <textarea>, it must be a single string ' +
74+
'or number., not an array or object.'
75+
);
76+
defaultValue = '' + children;
77+
}
78+
defaultValue = defaultValue || '';
79+
return {
80+
// We save the initial value so that `ReactNativeComponent` doesn't update
81+
// `textContent` (unnecessary since we update value).
82+
initialValue: this.props.value != null ? this.props.value : defaultValue,
83+
value: defaultValue
84+
};
85+
},
86+
87+
getValue: function() {
88+
return this.props.value != null ? this.props.value : this.state.value;
89+
},
90+
91+
render: function() {
92+
// Clone `this.props` so we don't mutate the input.
93+
var props = merge(this.props);
94+
95+
invariant(
96+
props.dangerouslySetInnerHTML == null,
97+
'`dangerouslySetInnerHTML` does not make sense on <textarea>.'
98+
);
99+
100+
props.value = this.getValue();
101+
props.onChange = this.handleChange;
102+
103+
// Always set children to the same thing. In IE9, the selection range will
104+
// get reset if `textContent` is mutated.
105+
return textarea(props, this.state.initialValue);
106+
},
107+
108+
componentDidUpdate: function(prevProps, prevState, rootNode) {
109+
if (this.props.value != null) {
110+
DOMPropertyOperations.setValueForProperty(
111+
rootNode,
112+
'value',
113+
this.props.value || ''
114+
);
115+
}
116+
},
117+
118+
handleChange: ReactCompositeComponent.autoBind(function(event) {
119+
var returnValue;
120+
if (this.props.onChange) {
121+
returnValue = this.props.onChange(event);
122+
}
123+
this.setState({value: event.target.value});
124+
return returnValue;
125+
})
126+
127+
});
128+
129+
module.exports = ReactDOMTextarea;

0 commit comments

Comments
 (0)