Commit de4e1a91 by Dominik Prokop

Refactored withPoper HOC to PopperController using render prop

parent 8e8b759b
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import * as PopperJS from 'popper.js';
import { Manager, Popper as ReactPopper } from 'react-popper';
import Portal from 'app/core/components/Portal/Portal'; import Portal from 'app/core/components/Portal/Portal';
import { Manager, Popper as ReactPopper, Reference } from 'react-popper';
import Transition from 'react-transition-group/Transition'; import Transition from 'react-transition-group/Transition';
const defaultTransitionStyles = { const defaultTransitionStyles = {
...@@ -18,29 +19,23 @@ const transitionStyles = { ...@@ -18,29 +19,23 @@ const transitionStyles = {
interface Props { interface Props {
renderContent: (content: any) => any; renderContent: (content: any) => any;
show: boolean; show: boolean;
placement?: any; placement?: PopperJS.Placement;
content: string | ((props: any) => JSX.Element); content: string | ((props: any) => JSX.Element);
refClassName?: string; refClassName?: string;
referenceElement: PopperJS.ReferenceObject;
} }
class Popper extends PureComponent<Props> { class Popper extends PureComponent<Props> {
render() { render() {
const { children, renderContent, show, placement, refClassName } = this.props; const { renderContent, show, placement } = this.props;
const { content } = this.props; const { content } = this.props;
return ( return (
<Manager> <Manager>
<Reference>
{({ ref }) => (
<div className={`popper_ref ${refClassName || ''}`} ref={ref}>
{children}
</div>
)}
</Reference>
<Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}> <Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}>
{transitionState => ( {transitionState => (
<Portal> <Portal>
<ReactPopper placement={placement}> <ReactPopper placement={placement} referenceElement={this.props.referenceElement}>
{({ ref, style, placement, arrowProps }) => { {({ ref, style, placement, arrowProps }) => {
return ( return (
<div <div
......
import React from 'react'; import React from 'react';
import * as PopperJS from 'popper.js';
type PopperContent = string | (() => JSX.Element);
export interface UsingPopperProps { export interface UsingPopperProps {
showPopper: (prevState: object) => void; show?: boolean;
hidePopper: (prevState: object) => void; placement?: PopperJS.Placement;
renderContent: (content: any) => any; content: PopperContent;
children: JSX.Element;
renderContent?: (content: PopperContent) => JSX.Element;
}
type PopperControllerRenderProp = (
showPopper: () => void,
hidePopper: () => void,
popperProps: {
show: boolean; show: boolean;
placement?: string; placement: PopperJS.Placement;
content: string | ((props: any) => JSX.Element); content: string | ((props: any) => JSX.Element);
className?: string; renderContent: (content: any) => any;
refClassName?: string; }
} ) => JSX.Element;
interface Props { interface Props {
placement?: string; placement?: PopperJS.Placement;
content: PopperContent;
className?: string; className?: string;
refClassName?: string; children: PopperControllerRenderProp;
content: string | ((props: any) => JSX.Element);
} }
interface State { interface State {
placement: string; placement: PopperJS.Placement;
show: boolean; show: boolean;
} }
export default function withPopper(WrappedComponent) { class PopperController extends React.Component<Props, State> {
return class extends React.Component<Props, State> { constructor(props: Props) {
constructor(props) {
super(props); super(props);
this.setState = this.setState.bind(this);
this.state = { this.state = {
placement: this.props.placement || 'auto', placement: this.props.placement || 'auto',
show: false, show: false,
}; };
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps: Props) {
if (nextProps.placement && nextProps.placement !== this.state.placement) { if (nextProps.placement && nextProps.placement !== this.state.placement) {
this.setState(prevState => { this.setState(prevState => {
return { return {
...@@ -59,7 +69,7 @@ export default function withPopper(WrappedComponent) { ...@@ -59,7 +69,7 @@ export default function withPopper(WrappedComponent) {
})); }));
}; };
renderContent(content) { renderContent(content: PopperContent) {
if (typeof content === 'function') { if (typeof content === 'function') {
// If it's a function we assume it's a React component // If it's a function we assume it's a React component
const ReactComponent = content; const ReactComponent = content;
...@@ -69,20 +79,16 @@ export default function withPopper(WrappedComponent) { ...@@ -69,20 +79,16 @@ export default function withPopper(WrappedComponent) {
} }
render() { render() {
const { children, content } = this.props;
const { show, placement } = this.state; const { show, placement } = this.state;
const className = this.props.className || '';
return ( return children(this.showPopper, this.hidePopper, {
<WrappedComponent show,
{...this.props} placement,
showPopper={this.showPopper} content,
hidePopper={this.hidePopper} renderContent: this.renderContent,
renderContent={this.renderContent} });
show={show}
placement={placement}
className={className}
/>
);
} }
};
} }
export default PopperController;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment