diff --git a/src/overridable.js b/src/overridable.js index 24be219..42a4ff6 100644 --- a/src/overridable.js +++ b/src/overridable.js @@ -36,7 +36,7 @@ export function parametrize(Component, extraProps) { /** * React component to enable overriding children when rendering. */ -function Overridable({id, children, ...restProps}) { +const Overridable = React.forwardRef(({id, children, ...restProps}, ref) => { const overriddenComponents = useContext(OverridableContext); const child = children ? React.Children.only(children) : null; const childProps = child ? child.props : {}; @@ -44,16 +44,22 @@ function Overridable({id, children, ...restProps}) { if (id in overriddenComponents) { // If there's an override, we replace the component's content with the override + props const Overridden = overriddenComponents[id]; - const element = React.createElement(Overridden, {...childProps, ...restProps}); + const props = {...childProps, ...restProps}; + if (ref) { + props.ref = ref; + } + const element = React.createElement(Overridden, props); return {element}; } else if (child) { // No override? Clone the Overridable component's original children - const element = React.cloneElement(child, childProps); + const element = ref ? React.cloneElement(child, {ref}) : React.cloneElement(child, childProps); return {element}; } else { return null; } -} +}); + +Overridable.displayName = 'Overridable'; Overridable.propTypes = { /** The children of the component */ diff --git a/src/overridable.test.js b/src/overridable.test.js index b7a1f4b..7be8562 100644 --- a/src/overridable.test.js +++ b/src/overridable.test.js @@ -221,3 +221,42 @@ describe('Tests for Overridable.component', () => { expect(NewCmp.find('ul')).toHaveLength(0); }); }); + +describe('Tests for ref forwarding', () => { + class RefChild extends Component { + render() { + return
; + } + } + + test('it should forward a ref to the cloned child', () => { + const ref = React.createRef(); + mount( + + + + ); + expect(ref.current).toBeInstanceOf(RefChild); + }); + + test('it should forward a ref to the overridden component', () => { + const ref = React.createRef(); + mount( + + +
+ + + ); + expect(ref.current).toBeInstanceOf(RefChild); + }); + + test('it should render normally when no ref is given', () => { + const mounted = mount( + + + + ); + expect(mounted.find('.ref-child')).toHaveLength(1); + }); +});