UNPKG

@instructure/ui-react-utils

Version:

A React utility library made by Instructure Inc.

147 lines (146 loc) 6.35 kB
/* * The MIT License (MIT) * * Copyright (c) 2015 - present Instructure, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import { decorator } from '@instructure/ui-decorator'; import { logWarnDeprecated as warnDeprecated } from '@instructure/console'; /** * --- * category: utilities/react * --- * Deprecate React component props. Warnings will display in the console when deprecated * props are used. Include the version number when the deprecated component will be removed. * * ```js-code * class Example extends Component { * static propTypes = { * currentProp: PropTypes.func * } * } * export default deprecated('7.0.0', { * deprecatedProp: 'currentProp', * nowNonExistentProp: true * })(Example) * ``` * * @param {string} version * @param {object} oldProps (if this argument is null or undefined, the entire component is deprecated) * @param {string} message * @return {function} React component with deprecated props behavior * @module deprecated */ const deprecated = (() => { if (process.env.NODE_ENV === 'production') { const deprecated = function () { return ComposedComponent => ComposedComponent; }; deprecated.deprecatePropValues = () => () => null; deprecated.warnDeprecatedProps = () => {}; deprecated.warnDeprecatedComponent = () => {}; deprecated.changedPackageWarning = () => ''; return deprecated; } const deprecated = decorator((ComposedComponent, version, oldProps, message = '') => { class DeprecatedComponent extends ComposedComponent {} DeprecatedComponent.prototype.componentDidMount = function () { if (oldProps) { warnDeprecatedProps(ComposedComponent.name, version, this.props, oldProps, message); } else { warnDeprecatedComponent(version, ComposedComponent.name, message); } if (ComposedComponent.prototype.componentDidMount) { ComposedComponent.prototype.componentDidMount.call(this); } }; DeprecatedComponent.prototype.componentDidUpdate = function (prevProps, prevState, prevContext) { if (oldProps) { warnDeprecatedProps(ComposedComponent.name, version, this.props, oldProps, message); } else { warnDeprecatedComponent(version, ComposedComponent.name, message); } if (ComposedComponent.prototype.componentDidUpdate) { ComposedComponent.prototype.componentDidUpdate.call(this, prevProps, prevState, prevContext); } }; return DeprecatedComponent; }) /** * --- * category: utilities * --- * Trigger a console warning if the specified prop variant is deprecated * * @param {function} propType - validates the prop type. Returns null if valid, error otherwise * @param {array} deprecated - an array of the deprecated variant names * @param {string|function} message - a string with additional information (like the version the prop will be removed) or a function returning a string */; deprecated.deprecatePropValues = (propType, deprecated = [], message) => { return (props, propName, componentName, ...rest) => { const isDeprecatedValue = deprecated.includes(props[propName]); const warningMessage = message && typeof message === 'function' ? message({ props, propName, propValue: props[propName] }) : `The '${props[propName]}' value for the \`${propName}\` prop is deprecated. ${message || ''}`; warnDeprecated(!isDeprecatedValue, `[${componentName}] ${warningMessage}`); return isDeprecatedValue ? null : propType(props, propName, componentName, ...rest); }; }; function warnDeprecatedProps(componentName, version, props, oldProps, message = '') { Object.keys(oldProps).forEach(oldProp => { if (typeof props[oldProp] !== 'undefined') { const newProp = typeof oldProps[oldProp] === 'string' ? oldProps[oldProp] : null; const newPropMessage = newProp ? `. Use \`${newProp}\` instead` : ''; warnDeprecated(false, `[${componentName}] \`${oldProp}\` is deprecated and will be removed in version ${version}${newPropMessage}. ${message}`); } }); } ; deprecated.warnDeprecatedProps = warnDeprecatedProps; function warnDeprecatedComponent(version, componentName, message) { warnDeprecated(false, `[${componentName}] is deprecated and will be removed in version ${version}. ${message || ''}`); } /** * --- * category: utilities * --- * @param {String} version the version of the package in which the component or function was deprecated * @param {String} componentName the name of the component or Function.name of the utility function * @param {String} message a message to display as a console error in DEV env when condition is false */ ; deprecated.warnDeprecatedComponent = warnDeprecatedComponent /** * --- * category: utilities * --- * @param {String} prevPackage the previous name of the package * @param {String} newPackage the new version of the package * @return {String} the formatted warning string */; deprecated.changedPackageWarning = (prevPackage, newPackage) => { return `It has been moved from @instructure/${prevPackage} to @instructure/${newPackage}.`; }; return deprecated; })(); export default deprecated; export { deprecated };