Skip to content

Instantly share code, notes, and snippets.

@amcdnl
Created September 26, 2019 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amcdnl/47f97393e159c91518d9e577a506e2da to your computer and use it in GitHub Desktop.
Save amcdnl/47f97393e159c91518d9e577a506e2da to your computer and use it in GitHub Desktop.
import { cloneElement, useMemo } from 'react';
import classNames from 'classnames';
interface CloneElementProps {
element: any | null;
children?: any;
}
/**
* CloneElement is a wrapper component for createElement function.
* This allows you to describe your cloning element declaratively
* which is a more natural API for React.
*/
export function CloneElement<T = any>({ element, children, ...rest }: CloneElementProps & Partial<T>) {
const getProjectedProps = useMemo(() => props => {
const childProps = element.props;
return Object.keys(props).reduce((acc, key) => {
const prop = props[key];
const childProp = childProps[key];
if (typeof prop === 'function' && typeof childProp === 'function') {
acc[key] = args => {
prop(args);
childProp(args);
};
} else if (key === 'className') {
acc[key] = classNames(prop, childProp);
} else {
acc[key] = prop;
}
return acc;
}, {});
}, [rest]);
if (element === null) {
return children;
}
const newProps = getProjectedProps(rest);
return cloneElement(element, {
...element.props,
...newProps,
children
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment