Change LinkedValueMixin to a util class

This makes it clear that .getValue() is not a public API.
This commit is contained in:
Ben Alpert
2014-01-22 09:57:59 -08:00
parent e3248efe92
commit 95a80591dd
6 changed files with 118 additions and 114 deletions
+1 -1
View File
@@ -39,7 +39,7 @@
* });
*
* We have provided some sugary mixins to make the creation and
* consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin.
* consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
*/
/**
-93
View File
@@ -1,93 +0,0 @@
/**
* Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @providesModule LinkedValueMixin
* @typechecks static-only
*/
"use strict";
var invariant = require('invariant');
var hasReadOnlyValue = {
'checkbox': true,
'hidden': true,
'radio': true
};
/**
* Provide a linked `value` attribute for controlled forms. You should not use
* this outside of the ReactDOM controlled form components.
*/
var LinkedValueMixin = {
propTypes: {
value: function(props, propName, componentName) {
if (__DEV__) {
if (props[propName] &&
!hasReadOnlyValue[props.type] &&
!props.onChange &&
!props.readOnly &&
!props.disabled) {
console.warn(
'You provided a `value` prop to a form field without an ' +
'`onChange` handler. This will render a read-only field. If ' +
'the field should be mutable use `defaultValue`. Otherwise, set ' +
'either `onChange` or `readOnly`.'
);
}
}
}
},
_assertLink: function() {
invariant(
this.props.value == null && this.props.onChange == null,
'Cannot provide a valueLink and a value or onChange event. If you ' +
'want to use value or onChange, you probably don\'t want to use ' +
'valueLink'
);
},
/**
* @return {*} current value of the input either from value prop or link.
*/
getValue: function() {
if (this.props.valueLink) {
this._assertLink();
return this.props.valueLink.value;
}
return this.props.value;
},
/**
* @return {function} change callback either from onChange prop or link.
*/
getOnChange: function() {
if (this.props.valueLink) {
this._assertLink();
return this._handleLinkedValueChange;
}
return this.props.onChange;
},
/**
* @param {SyntheticEvent} e change event to handle
*/
_handleLinkedValueChange: function(e) {
this.props.valueLink.requestChange(e.target.value);
}
};
module.exports = LinkedValueMixin;
+97
View File
@@ -0,0 +1,97 @@
/**
* Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @providesModule LinkedValueUtils
* @typechecks static-only
*/
"use strict";
var invariant = require('invariant');
var hasReadOnlyValue = {
'checkbox': true,
'hidden': true,
'radio': true
};
function _assertLink(input) {
invariant(
input.props.value == null && input.props.onChange == null,
'Cannot provide a valueLink and a value or onChange event. If you want ' +
'to use value or onChange, you probably don\'t want to use valueLink.'
);
}
/**
* @param {SyntheticEvent} e change event to handle
*/
function _handleLinkedValueChange(e) {
/*jshint validthis:true */
this.props.valueLink.requestChange(e.target.value);
}
/**
* Provide a linked `value` attribute for controlled forms. You should not use
* this outside of the ReactDOM controlled form components.
*/
var LinkedValueUtils = {
Mixin: {
propTypes: {
value: function(props, propName, componentName) {
if (__DEV__) {
if (props[propName] &&
!hasReadOnlyValue[props.type] &&
!props.onChange &&
!props.readOnly &&
!props.disabled) {
console.warn(
'You provided a `value` prop to a form field without an ' +
'`onChange` handler. This will render a read-only field. If ' +
'the field should be mutable use `defaultValue`. Otherwise, ' +
'set either `onChange` or `readOnly`.'
);
}
}
}
}
},
/**
* @param {ReactComponent} input Form component
* @return {*} current value of the input either from value prop or link.
*/
getValue: function(input) {
if (input.props.valueLink) {
_assertLink(input);
return input.props.valueLink.value;
}
return input.props.value;
},
/**
* @param {ReactComponent} input Form component
* @return {function} change callback either from onChange prop or link.
*/
getOnChange: function(input) {
if (input.props.valueLink) {
_assertLink(input);
return _handleLinkedValueChange;
}
return input.props.onChange;
}
};
module.exports = LinkedValueUtils;
+7 -7
View File
@@ -18,9 +18,9 @@
"use strict";
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueMixin = require('LinkedValueMixin');
var AutoFocusMixin = require('AutoFocusMixin');
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactDOM = require('ReactDOM');
var ReactMount = require('ReactMount');
@@ -52,7 +52,7 @@ var instancesByReactID = {};
var ReactDOMInput = ReactCompositeComponent.createClass({
displayName: 'ReactDOMInput',
mixins: [LinkedValueMixin, AutoFocusMixin],
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
getInitialState: function() {
var defaultValue = this.props.defaultValue;
@@ -76,7 +76,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
props.checked =
this.props.checked != null ? this.props.checked : this.state.checked;
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
props.value = value != null ? value : this.state.value;
props.onChange = this._handleChange;
@@ -105,7 +105,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
);
}
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
if (value != null) {
// Cast `value` to a string to ensure the value is set correctly. While
// browsers typically do this as necessary, jsdom doesn't.
@@ -115,10 +115,10 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
_handleChange: function(event) {
var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;
}
this.setState({
+5 -5
View File
@@ -18,8 +18,8 @@
"use strict";
var LinkedValueMixin = require('LinkedValueMixin');
var AutoFocusMixin = require('AutoFocusMixin');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactDOM = require('ReactDOM');
@@ -61,7 +61,7 @@ function selectValueType(props, propName, componentName) {
function updateOptions() {
/*jshint validthis:true */
var multiple = this.props.multiple;
var propValue = this.getValue();
var propValue = LinkedValueUtils.getValue(this);
var value = propValue != null ? propValue : this.state.value;
var options = this.getDOMNode().options;
var selectedValue, i, l;
@@ -102,7 +102,7 @@ function updateOptions() {
var ReactDOMSelect = ReactCompositeComponent.createClass({
displayName: 'ReactDOMSelect',
mixins: [LinkedValueMixin, AutoFocusMixin],
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
propTypes: {
defaultValue: selectValueType,
@@ -142,10 +142,10 @@ var ReactDOMSelect = ReactCompositeComponent.createClass({
_handleChange: function(event) {
var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;
}
+8 -8
View File
@@ -18,9 +18,9 @@
"use strict";
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueMixin = require('LinkedValueMixin');
var AutoFocusMixin = require('AutoFocusMixin');
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactDOM = require('ReactDOM');
@@ -48,7 +48,7 @@ var textarea = ReactDOM.textarea;
var ReactDOMTextarea = ReactCompositeComponent.createClass({
displayName: 'ReactDOMTextarea',
mixins: [LinkedValueMixin, AutoFocusMixin],
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
getInitialState: function() {
var defaultValue = this.props.defaultValue;
@@ -78,7 +78,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
if (defaultValue == null) {
defaultValue = '';
}
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
return {
// We save the initial value so that `ReactDOMComponent` doesn't update
// `textContent` (unnecessary since we update value).
@@ -97,7 +97,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
render: function() {
// Clone `this.props` so we don't mutate the input.
var props = merge(this.props);
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
invariant(
props.dangerouslySetInnerHTML == null,
@@ -114,7 +114,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
},
componentDidUpdate: function(prevProps, prevState, prevContext) {
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
if (value != null) {
var rootNode = this.getDOMNode();
// Cast `value` to a string to ensure the value is set correctly. While
@@ -125,10 +125,10 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
_handleChange: function(event) {
var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;
}
this.setState({value: event.target.value});