diff --git a/package.json b/package.json index 96cb6ecfdd..28efdbc078 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,8 @@ "intl-messageformat": "^2.1.0", "intl-relativeformat": "^2.1.0", "invariant": "^2.1.1", - "react-display-name": "^0.2.4" + "react-display-name": "^0.2.4", + "react-is": "^16.3.1" }, "peerDependencies": { "prop-types": "^15.5.4", diff --git a/rollup.config.dist.js b/rollup.config.dist.js index f96ca1dff6..e95e114249 100644 --- a/rollup.config.dist.js +++ b/rollup.config.dist.js @@ -41,6 +41,7 @@ export default { }), commonjs({ sourcemap: true, + namedExports: {'react-is': ['isValidElementType']}, }), replace({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), diff --git a/rollup.config.lib.js b/rollup.config.lib.js index 2495207e76..d3966bbc77 100644 --- a/rollup.config.lib.js +++ b/rollup.config.lib.js @@ -27,7 +27,7 @@ export default { ], plugins: [ babel(), - commonjs(), + commonjs({namedExports: {'react-is': ['isValidElementType']}}), nodeResolve({ jsnext: true }) diff --git a/src/components/withIntl.js b/src/components/withIntl.js index 2eff0e6dfd..09148f1e6f 100644 --- a/src/components/withIntl.js +++ b/src/components/withIntl.js @@ -1,4 +1,5 @@ import React, {Component, createContext} from 'react'; +import {isValidElementType} from 'react-is'; import hoistNonReactStatics from 'hoist-non-react-statics'; import invariant from 'invariant'; import {invariantIntlContext} from '../utils'; @@ -13,7 +14,17 @@ const {Consumer: IntlConsumer, Provider: IntlProvider} = IntlContext; export const Provider = IntlProvider; export const Context = IntlContext; -export default function withIntl(WrappedComponent, options = {}) { +export default function withIntl(componentOrOptions, options) { + if (isValidElementType(componentOrOptions)) { + // use call to make `options` available on `this` + return createWrapper.call({options}, componentOrOptions); + } + // return a function with `options` bound to `this` + return createWrapper.bind({options: componentOrOptions}); +} + +function createWrapper(WrappedComponent) { + let options = (this && this.options) || {}; const { intlPropName = 'intl', forwardRef = false, diff --git a/test/unit/components/withIntl.js b/test/unit/components/withIntl.js index f224e1abac..62aaa2b853 100644 --- a/test/unit/components/withIntl.js +++ b/test/unit/components/withIntl.js @@ -140,5 +140,29 @@ describe('withIntl()', () => { expect(wrapperRef.current).toBe(wrapped.instance()); }); }); + + it('can also be used with a bound function', () => { + Wrapped = class extends React.Component { + render() { + return null; + } + }; + const propName = 'myPropName'; + const customWithIntl = withIntl({ + forwardRef: true, + intlPropName: propName, + }); + const wrapperRef = React.createRef(); + const Injected = customWithIntl(Wrapped); + + rendered = mountWithProvider(); + const wrapped = rendered.find(Wrapped); + + expect(wrapperRef.current).toBe(wrapped.instance()); + + const intlProvider = rendered.find(IntlProvider).childAt(0); + + expect(wrapped.prop(propName)).toBe(intlProvider.instance().getContext()); + }); }); }); diff --git a/yarn.lock b/yarn.lock index e25309ad64..ad24e87642 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5954,7 +5954,7 @@ react-dom@^16.3.3: prop-types "^15.6.2" scheduler "^0.13.6" -react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: +react-is@^16.3.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==