react-bootstrap
Version:
Bootstrap 3 components build with React
143 lines (125 loc) • 4.33 kB
JavaScript
/**
* Copyright 2013-2014, Facebook, Inc.
* All rights reserved.
*
* This file contains modified versions of:
* https://github.com/facebook/react/blob/v0.12.0/src/utils/cloneWithProps.js
* https://github.com/facebook/react/blob/v0.12.0/src/core/ReactPropTransferer.js
*
* This source code is licensed under the BSD-style license found here:
* https://github.com/facebook/react/blob/v0.12.0/LICENSE
* An additional grant of patent rights can be found here:
* https://github.com/facebook/react/blob/v0.12.0/PATENTS
*
* TODO: This should be replaced as soon as cloneWithProps is available via
* the core React package or a separate package.
* @see https://github.com/facebook/react/issues/1906
*/
var React = require('react');
var joinClasses = require('./joinClasses');
var assign = require("./Object.assign");
/**
* Creates a transfer strategy that will merge prop values using the supplied
* `mergeStrategy`. If a prop was previously unset, this just sets it.
*
* @param {function} mergeStrategy
* @return {function}
*/
function createTransferStrategy(mergeStrategy) {
return function(props, key, value) {
if (!props.hasOwnProperty(key)) {
props[key] = value;
} else {
props[key] = mergeStrategy(props[key], value);
}
};
}
var transferStrategyMerge = createTransferStrategy(function(a, b) {
// `merge` overrides the first object's (`props[key]` above) keys using the
// second object's (`value`) keys. An object's style's existing `propA` would
// get overridden. Flip the order here.
return assign({}, b, a);
});
function emptyFunction() {}
/**
* Transfer strategies dictate how props are transferred by `transferPropsTo`.
* NOTE: if you add any more exceptions to this list you should be sure to
* update `cloneWithProps()` accordingly.
*/
var TransferStrategies = {
/**
* Never transfer `children`.
*/
children: emptyFunction,
/**
* Transfer the `className` prop by merging them.
*/
className: createTransferStrategy(joinClasses),
/**
* Transfer the `style` prop (which is an object) by merging them.
*/
style: transferStrategyMerge
};
/**
* Mutates the first argument by transferring the properties from the second
* argument.
*
* @param {object} props
* @param {object} newProps
* @return {object}
*/
function transferInto(props, newProps) {
for (var thisKey in newProps) {
if (!newProps.hasOwnProperty(thisKey)) {
continue;
}
var transferStrategy = TransferStrategies[thisKey];
if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
transferStrategy(props, thisKey, newProps[thisKey]);
} else if (!props.hasOwnProperty(thisKey)) {
props[thisKey] = newProps[thisKey];
}
}
return props;
}
/**
* Merge two props objects using TransferStrategies.
*
* @param {object} oldProps original props (they take precedence)
* @param {object} newProps new props to merge in
* @return {object} a new object containing both sets of props merged.
*/
function mergeProps(oldProps, newProps) {
return transferInto(assign({}, oldProps), newProps);
}
var ReactPropTransferer = {
mergeProps: mergeProps
};
var CHILDREN_PROP = 'children';
/**
* Sometimes you want to change the props of a child passed to you. Usually
* this is to add a CSS class.
*
* @param {object} child child component you'd like to clone
* @param {object} props props you'd like to modify. They will be merged
* as if you used `transferPropsTo()`.
* @return {object} a clone of child with props merged in.
*/
function cloneWithProps(child, props) {
var newProps = ReactPropTransferer.mergeProps(props, child.props);
// Use `child.props.children` if it is provided.
if (!newProps.hasOwnProperty(CHILDREN_PROP) &&
child.props.hasOwnProperty(CHILDREN_PROP)) {
newProps.children = child.props.children;
}
if (React.version.substr(0, 4) === '0.12'){
var mockLegacyFactory = function(){};
mockLegacyFactory.isReactLegacyFactory = true;
mockLegacyFactory.type = child.type;
return React.createElement(mockLegacyFactory, newProps);
}
// The current API doesn't retain _owner and _context, which is why this
// doesn't use ReactElement.cloneAndReplaceProps.
return React.createElement(child.type, newProps);
}
module.exports = cloneWithProps;