UNPKG

react-addons

Version:

Simple packaging of react addons to avoid fiddly 'react/addons' npm module.

360 lines (333 loc) 10.4 kB
/** * Copyright 2013-2014 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 ReactPropTypes */ "use strict"; var ReactComponent = require("./ReactComponent"); var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames"); var warning = require("./warning"); var createObjectFrom = require("./createObjectFrom"); /** * Collection of methods that allow declaration and validation of props that are * supplied to React components. Example usage: * * var Props = require('ReactPropTypes'); * var MyArticle = React.createClass({ * propTypes: { * // An optional string prop named "description". * description: Props.string, * * // A required enum prop named "category". * category: Props.oneOf(['News','Photos']).isRequired, * * // A prop named "dialog" that requires an instance of Dialog. * dialog: Props.instanceOf(Dialog).isRequired * }, * render: function() { ... } * }); * * A more formal specification of how these methods are used: * * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) * decl := ReactPropTypes.{type}(.isRequired)? * * Each and every declaration produces a function with the same signature. This * allows the creation of custom validation functions. For example: * * var Props = require('ReactPropTypes'); * var MyLink = React.createClass({ * propTypes: { * // An optional string or URI prop named "href". * href: function(props, propName, componentName) { * var propValue = props[propName]; * warning( * propValue == null || * typeof propValue === 'string' || * propValue instanceof URI, * 'Invalid `%s` supplied to `%s`, expected string or URI.', * propName, * componentName * ); * } * }, * render: function() { ... } * }); * * @internal */ var Props = { array: createPrimitiveTypeChecker('array'), bool: createPrimitiveTypeChecker('boolean'), func: createPrimitiveTypeChecker('function'), number: createPrimitiveTypeChecker('number'), object: createPrimitiveTypeChecker('object'), string: createPrimitiveTypeChecker('string'), shape: createShapeTypeChecker, oneOf: createEnumTypeChecker, oneOfType: createUnionTypeChecker, arrayOf: createArrayOfTypeChecker, instanceOf: createInstanceTypeChecker, renderable: createRenderableTypeChecker(), component: createComponentTypeChecker(), any: createAnyTypeChecker() }; var ANONYMOUS = '<<anonymous>>'; function isRenderable(propValue) { switch(typeof propValue) { case 'number': case 'string': return true; case 'object': if (Array.isArray(propValue)) { return propValue.every(isRenderable); } if (ReactComponent.isValidComponent(propValue)) { return true; } for (var k in propValue) { if (!isRenderable(propValue[k])) { return false; } } return true; default: return false; } } // Equivalent of typeof but with special handling for arrays function getPropType(propValue) { var propType = typeof propValue; if (propType === 'object' && Array.isArray(propValue)) { return 'array'; } return propType; } function createAnyTypeChecker() { function validateAnyType( shouldWarn, propValue, propName, componentName, location ) { return true; // is always valid } return createChainableTypeChecker(validateAnyType); } function createPrimitiveTypeChecker(expectedType) { function validatePrimitiveType( shouldWarn, propValue, propName, componentName, location ) { var propType = getPropType(propValue); var isValid = propType === expectedType; if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` of type `%s` supplied to `%s`, expected `%s`.', ReactPropTypeLocationNames[location], propName, propType, componentName, expectedType ) : null); } return isValid; } return createChainableTypeChecker(validatePrimitiveType); } function createEnumTypeChecker(expectedValues) { var expectedEnum = createObjectFrom(expectedValues); function validateEnumType( shouldWarn, propValue, propName, componentName, location ) { var isValid = expectedEnum[propValue]; if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`, expected one of %s.', ReactPropTypeLocationNames[location], propName, componentName, JSON.stringify(Object.keys(expectedEnum)) ) : null); } return isValid; } return createChainableTypeChecker(validateEnumType); } function createShapeTypeChecker(shapeTypes) { function validateShapeType( shouldWarn, propValue, propName, componentName, location ) { var propType = getPropType(propValue); var isValid = propType === 'object'; if (isValid) { for (var key in shapeTypes) { var checker = shapeTypes[key]; if (checker && !checker(propValue, key, componentName, location)) { return false; } } } if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` of type `%s` supplied to `%s`, expected `object`.', ReactPropTypeLocationNames[location], propName, propType, componentName ) : null); } return isValid; } return createChainableTypeChecker(validateShapeType); } function createInstanceTypeChecker(expectedClass) { function validateInstanceType( shouldWarn, propValue, propName, componentName, location ) { var isValid = propValue instanceof expectedClass; if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`, expected instance of `%s`.', ReactPropTypeLocationNames[location], propName, componentName, expectedClass.name || ANONYMOUS ) : null); } return isValid; } return createChainableTypeChecker(validateInstanceType); } function createArrayOfTypeChecker(propTypeChecker) { function validateArrayType( shouldWarn, propValue, propName, componentName, location ) { var isValid = Array.isArray(propValue); if (isValid) { for (var i = 0; i < propValue.length; i++) { if (!propTypeChecker(propValue, i, componentName, location)) { return false; } } } if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`, expected an array.', ReactPropTypeLocationNames[location], propName, componentName ) : null); } return isValid; } return createChainableTypeChecker(validateArrayType); } function createRenderableTypeChecker() { function validateRenderableType( shouldWarn, propValue, propName, componentName, location ) { var isValid = isRenderable(propValue); if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`, expected a renderable prop.', ReactPropTypeLocationNames[location], propName, componentName ) : null); } return isValid; } return createChainableTypeChecker(validateRenderableType); } function createComponentTypeChecker() { function validateComponentType( shouldWarn, propValue, propName, componentName, location ) { var isValid = ReactComponent.isValidComponent(propValue); if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`, expected a React component.', ReactPropTypeLocationNames[location], propName, componentName ) : null); } return isValid; } return createChainableTypeChecker(validateComponentType); } function createUnionTypeChecker(arrayOfValidators) { return function(props, propName, componentName, location) { var isValid = false; for (var ii = 0; ii < arrayOfValidators.length; ii++) { var validate = arrayOfValidators[ii]; if (typeof validate.weak === 'function') { validate = validate.weak; } if (validate(props, propName, componentName, location)) { isValid = true; break; } } ("production" !== process.env.NODE_ENV ? warning( isValid, 'Invalid %s `%s` supplied to `%s`.', ReactPropTypeLocationNames[location], propName, componentName || ANONYMOUS ) : null); return isValid; }; } function createChainableTypeChecker(validate) { function checkType( isRequired, shouldWarn, props, propName, componentName, location ) { var propValue = props[propName]; if (propValue != null) { // Only validate if there is a value to check. return validate( shouldWarn, propValue, propName, componentName || ANONYMOUS, location ); } else { var isValid = !isRequired; if (shouldWarn) { ("production" !== process.env.NODE_ENV ? warning( isValid, 'Required %s `%s` was not specified in `%s`.', ReactPropTypeLocationNames[location], propName, componentName || ANONYMOUS ) : null); } return isValid; } } var checker = checkType.bind(null, false, true); checker.weak = checkType.bind(null, false, false); checker.isRequired = checkType.bind(null, true, true); checker.weak.isRequired = checkType.bind(null, true, false); checker.isRequired.weak = checker.weak.isRequired; return checker; } module.exports = Props;