import { isValidElement } from 'react'; import { cloneWithRef } from '../utils/cloneWithRef'; function throwIfCompositeComponentElement(element) { // Custom components can no longer be wrapped directly in React DnD 2.0 // so that we don't need to depend on findDOMNode() from react-dom. if (typeof element.type === 'string') { return; } const displayName = element.type.displayName || element.type.name || 'the component'; throw new Error('Only native element nodes can now be passed to React DnD connectors.' + `You can either wrap ${displayName} into a
, or turn it into a ` + 'drag source or a drop target itself.'); } function wrapHookToRecognizeElement(hook) { return (elementOrNode = null, options = null) => { // When passed a node, call the hook straight away. if (!isValidElement(elementOrNode)) { const node = elementOrNode; hook(node, options); // return the node so it can be chained (e.g. when within callback refs //
connectDragSource(connectDropTarget(node))}/> return node; } // If passed a ReactElement, clone it and attach this function as a ref. // This helps us achieve a neat API where user doesn't even know that refs // are being used under the hood. const element = elementOrNode; throwIfCompositeComponentElement(element); // When no options are passed, use the hook directly const ref = options ? (node) => hook(node, options) : hook; return cloneWithRef(element, ref); }; } export default function wrapConnectorHooks(hooks) { const wrappedHooks = {}; Object.keys(hooks).forEach(key => { const hook = hooks[key]; // ref objects should be passed straight through without wrapping if (key.endsWith('Ref')) { wrappedHooks[key] = hooks[key]; } else { const wrappedHook = wrapHookToRecognizeElement(hook); wrappedHooks[key] = () => wrappedHook; } }); return wrappedHooks; }