diff --git a/src/Fade.js b/src/Fade.js index 2936d5dca..e38330c23 100644 --- a/src/Fade.js +++ b/src/Fade.js @@ -3,12 +3,13 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Transition } from 'react-transition-group'; import { + addDefaultProps, mapToCssModules, omit, pick, + tagPropType, TransitionPropTypeKeys, TransitionTimeouts, - tagPropType, } from './utils'; const propTypes = { @@ -50,12 +51,13 @@ function Fade(props) { children, innerRef = ref, ...otherProps - } = props; + } = addDefaultProps(defaultProps, props); const transitionProps = pick( { defaultProps, ...otherProps }, TransitionPropTypeKeys, ); + const childProps = omit(otherProps, TransitionPropTypeKeys); return ( @@ -77,6 +79,5 @@ function Fade(props) { } Fade.propTypes = propTypes; -Fade.defaultProps = defaultProps; export default Fade; diff --git a/src/Tooltip.js b/src/Tooltip.js index 3e21cf657..00d66f12a 100644 --- a/src/Tooltip.js +++ b/src/Tooltip.js @@ -1,6 +1,7 @@ import React from 'react'; import classNames from 'classnames'; import TooltipPopoverWrapper, { propTypes } from './TooltipPopoverWrapper'; +import { addDefaultProps } from './utils'; const defaultProps = { placement: 'top', @@ -14,9 +15,11 @@ function Tooltip(props) { const popperClasses = classNames('tooltip', 'show', props.popperClassName); const classes = classNames('tooltip-inner', props.innerClassName); + const _props = addDefaultProps(defaultProps, props); + return ( { describe('isFunction', () => { it('should return `true` for functions', () => { function test() {} + expect(Utils.isFunction(test)).toBe(true); expect(Utils.isFunction(Array.prototype.slice)).toBe(true); }); it('should return `true` for async functions', () => { async function asyncFunc() {} + expect(Utils.isFunction(asyncFunc)).toEqual( typeof asyncFunc === 'function', ); @@ -247,6 +249,7 @@ describe('Utils', () => { it('should return `true` for generator functions', () => { function* genFunc() {} + expect(Utils.isFunction(genFunc)).toEqual(typeof genFunc === 'function'); }); @@ -256,6 +259,7 @@ describe('Utils', () => { return arguments; }.apply(undefined, array); } + expect(Utils.isFunction(toArgs([1, 2, 3]))).toBe(false); expect(Utils.isFunction([1, 2, 3])).toBe(false); expect(Utils.isFunction(true)).toBe(false); @@ -309,6 +313,52 @@ describe('Utils', () => { }); }); + describe('addDefaultProps', () => { + it('should return an object', () => { + const defaultProps = { + a: 1, + b: 2, + c: 3, + }; + const props = { + a: 4, + b: 5, + }; + expect(Utils.addDefaultProps(defaultProps, props)).toEqual( + expect.any(Object), + ); + }); + + it('should return an object with default props', () => { + const defaultProps = { + a: 1, + b: 2, + c: 3, + d: { + e: 4, + f: 5, + }, + }; + const props = { + a: 4, + b: 5, + d: { + e: 6, + f: 5, + }, + }; + expect(Utils.addDefaultProps(defaultProps, props)).toEqual({ + a: 4, + b: 5, + c: 3, + d: { + e: 6, + f: 5, + }, + }); + }); + }); + // TODO // describe('getScrollbarWidth', () => { // // jsdom workaround https://github.com/tmpvar/jsdom/issues/135#issuecomment-68191941 diff --git a/src/utils.js b/src/utils.js index 72f91c2eb..4678aefac 100644 --- a/src/utils.js +++ b/src/utils.js @@ -264,8 +264,8 @@ export function toNumber(value) { return isBinary || /^0o[0-7]+$/i.test(value) ? parseInt(value.slice(2), isBinary ? 2 : 8) : /^[-+]0x[0-9a-f]+$/i.test(value) - ? NAN - : +value; + ? NAN + : +value; } export function isFunction(value) { @@ -381,3 +381,23 @@ export const focusableElements = [ 'video[controls]', '[contenteditable]:not([contenteditable="false"])', ]; + +export function addDefaultProps(defaultProps, props) { + if (!defaultProps || !props) return props; + + let result = { ...props }; + + Object.keys(defaultProps).forEach((key) => { + if (result[key] === undefined) { + result[key] = defaultProps[key]; + } + if ( + Object.keys(defaultProps[key] || {}).length > 0 && + typeof defaultProps[key] === 'object' + ) { + addDefaultProps(defaultProps[key], result); + } + }); + + return result; +}