diff --git a/docs/src/components/CarbonAd/CarbonAd.js b/docs/src/components/CarbonAd/CarbonAd.js index ca8af59fea..dd6abde02b 100644 --- a/docs/src/components/CarbonAd/CarbonAd.js +++ b/docs/src/components/CarbonAd/CarbonAd.js @@ -35,7 +35,7 @@ const waitForLoad = () => { class CarbonAd extends Component { componentDidMount() { - this.ifRef((ref) => { + this.ifRef(ref => { // always add the script as it is used to insert the ad ref.appendChild(script) @@ -55,13 +55,13 @@ class CarbonAd extends Component { return false } - ifRef = (cb) => { + ifRef = cb => { const ref = document.querySelector('#docs-carbonads') if (ref) cb(ref) } render() { - return
+ return
} } diff --git a/docs/src/components/CarbonAd/CarbonAdNative.js b/docs/src/components/CarbonAd/CarbonAdNative.js index e292551301..0e76172618 100644 --- a/docs/src/components/CarbonAd/CarbonAdNative.js +++ b/docs/src/components/CarbonAd/CarbonAdNative.js @@ -60,7 +60,7 @@ class CarbonAdNative extends Component { document.getElementsByTagName('head')[0].appendChild(this.script) } - handleNativeJSON = (json) => { + handleNativeJSON = json => { debug('handleNativeJSON', { mounted: this.mounted }) try { const sanitizedAd = json.ads @@ -91,28 +91,28 @@ class CarbonAdNative extends Component { const colors = inverted ? { - divider: '#333', - background: '#222', - backgroundHover: '#1d1d1d', - color: '#999', - colorHover: '#ccc', - } + divider: '#333', + background: '#222', + backgroundHover: '#1d1d1d', + color: '#999', + colorHover: '#ccc', + } : { - divider: '#eee', - background: '#fff', - backgroundHover: 'whitesmoke', - color: '#555', - colorHover: '#333', - } + divider: '#eee', + background: '#fff', + backgroundHover: 'whitesmoke', + color: '#555', + colorHover: '#333', + } return ( - + {ad.company} {' — '} {ad.description}
- {_.times(3, i => )} + {_.times(3, i => ( + + ))} - {_.times(4, i => )} + {_.times(4, i => ( + + ))} - {_.times(2, i => )} + {_.times(2, i => ( + + ))} diff --git a/gulp/plugins/gulp-example-source.js b/gulp/plugins/gulp-example-source.js index f524423cfb..6a732a899f 100644 --- a/gulp/plugins/gulp-example-source.js +++ b/gulp/plugins/gulp-example-source.js @@ -23,8 +23,7 @@ export default () => { } try { - const sourceName = _ - .split(file.path, path.sep) + const sourceName = _.split(file.path, path.sep) .slice(-4) .join('/') .slice(0, -3) diff --git a/src/elements/Flag/Flag.js b/src/elements/Flag/Flag.js index 5b6f04eb4f..0b493bf5c0 100644 --- a/src/elements/Flag/Flag.js +++ b/src/elements/Flag/Flag.js @@ -5,6 +5,7 @@ import React, { PureComponent } from 'react' import { createShorthandFactory, customPropTypes, + forwardRefFactory, getElementType, getUnhandledProps, } from '../../lib' @@ -529,10 +530,12 @@ class Flag extends PureComponent { const rest = getUnhandledProps(Flag, this.props) const ElementType = getElementType(Flag, this.props) + console.log('Flag props', rest) + return } } Flag.create = createShorthandFactory(Flag, value => ({ name: value })) -export default Flag +export default forwardRefFactory(Flag) diff --git a/src/lib/componentUtils.js b/src/lib/componentUtils.js new file mode 100644 index 0000000000..55c64b918c --- /dev/null +++ b/src/lib/componentUtils.js @@ -0,0 +1,4 @@ +export const isForwardRef = Component => + (Component && Component.$$typeof && typeof Component.render === 'function') || false + +export const isBasic = Component => typeof Component === 'string' diff --git a/src/lib/forwardRefFactory/forwardFunctionFactory.js b/src/lib/forwardRefFactory/forwardFunctionFactory.js new file mode 100644 index 0000000000..2871d06004 --- /dev/null +++ b/src/lib/forwardRefFactory/forwardFunctionFactory.js @@ -0,0 +1,44 @@ +import React, { createElement } from 'react' + +import Ref from '../../addons/Ref' +import { isBasic, isForwardRef } from '../componentUtils' + +/** + * Use just a string for now (react 16.3), since react doesn't support Symbols in props yet. + * https://github.com/facebook/react/issues/7552 + * @type {String} + */ +export const forwardRefSymbol = '__forwardRef__' + +/** + * Creates a function that will choose how to pass a ref. + * + * @param {Function|Component} Component A Component to wrap + * @return {Function} + */ +const forwardFunctionFactory = Component => (props, ref) => { + console.log('forwardFunctionFactory()', { + element: props.as, + isBasic: isBasic(props.as), + isForwardRef: isForwardRef(props.as), + }) + + // The most simple case when `as='div'` + // This component supports ref forwarding! + // Magic happens there! + if (!props.as || isBasic(props.as) || isForwardRef(props.as)) { + return createElement(Component, { + ...props, + [forwardRefSymbol]: ref, + }) + } + + // Need to get ref manually + return ( + + + + ) +} + +export default forwardFunctionFactory diff --git a/src/lib/forwardRefFactory/forwardRefFactory.js b/src/lib/forwardRefFactory/forwardRefFactory.js new file mode 100644 index 0000000000..c3c902d2fc --- /dev/null +++ b/src/lib/forwardRefFactory/forwardRefFactory.js @@ -0,0 +1,21 @@ +import hoistStatics from 'hoist-non-react-statics' +import { forwardRef } from 'react' + +import forwardFunctionFactory from './forwardFunctionFactory' + +/** + * Wraps passed component with react 'forwardRef' function, which produce new component with type 'object' and structure + * like so: { $$type: Symbol(), render: function }. Assigns (hoists) static methods of passed component to result + * forward component using 'hoist-non-react-statics' module. + * + * @param {Function|Component} Component A Component to wrap with forwardRef() + * @return {Object} + */ +const forwardRefFactory = (Component) => { + const forwarder = forwardRef(forwardFunctionFactory(Component)) + + hoistStatics(forwarder, Component, { $$typeof: true, render: true }) + return forwarder +} + +export default forwardRefFactory diff --git a/src/lib/forwardRefFactory/index.js b/src/lib/forwardRefFactory/index.js new file mode 100644 index 0000000000..6e8c0a49b5 --- /dev/null +++ b/src/lib/forwardRefFactory/index.js @@ -0,0 +1,2 @@ +export { forwardRefSymbol } from './forwardFunctionFactory' +export forwardRefFactory from './forwardRefFactory' diff --git a/src/lib/getUnhandledProps.js b/src/lib/getUnhandledProps.js index 1a4d199541..42f62a964c 100644 --- a/src/lib/getUnhandledProps.js +++ b/src/lib/getUnhandledProps.js @@ -1,3 +1,5 @@ +import { forwardRefSymbol } from './forwardRefFactory' + /** * Returns an object consisting of props beyond the scope of the Component. * Useful for getting and spreading unknown props from the user. @@ -11,6 +13,10 @@ const getUnhandledProps = (Component, props) => { return Object.keys(props).reduce((acc, prop) => { if (prop === 'childKey') return acc + if (prop === forwardRefSymbol) { + acc.ref = props[forwardRefSymbol] + return acc + } if (handledProps.indexOf(prop) === -1) acc[prop] = props[prop] return acc }, {}) diff --git a/src/lib/index.js b/src/lib/index.js index b5c9022501..17ef15716c 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -18,8 +18,9 @@ export { debug, makeDebugger } from './debug' export eventStack from './eventStack' export * from './factories' -export getUnhandledProps from './getUnhandledProps' +export { forwardRefFactory } from './forwardRefFactory' export getElementType from './getElementType' +export getUnhandledProps from './getUnhandledProps' export { htmlInputAttrs,