mirror of
https://github.com/grafana/grafana.git
synced 2025-02-03 12:11:09 -06:00
panel-header: Updates for the new react-popper api and make it possible to hover the tooltip popper without it closing
This commit is contained in:
parent
6cd5bca9ab
commit
af859b2f4d
@ -1,34 +1,19 @@
|
||||
import React from 'react';
|
||||
import withTooltip from './withTooltip';
|
||||
import { Target } from 'react-popper';
|
||||
|
||||
interface PopoverProps {
|
||||
tooltipSetState: (prevState: object) => void;
|
||||
}
|
||||
|
||||
class Popover extends React.Component<PopoverProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.toggleTooltip = this.toggleTooltip.bind(this);
|
||||
}
|
||||
|
||||
toggleTooltip() {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: !prevState.show,
|
||||
};
|
||||
});
|
||||
}
|
||||
import React, { PureComponent } from 'react';
|
||||
import Popper from './Popper';
|
||||
import withPopper, { UsingPopperProps } from './withPopper';
|
||||
|
||||
class Popover extends PureComponent<UsingPopperProps> {
|
||||
render() {
|
||||
const { children, hidePopper, showPopper, className, ...restProps } = this.props;
|
||||
|
||||
const togglePopper = restProps.show === true ? hidePopper : showPopper;
|
||||
|
||||
return (
|
||||
<Target className="popper__target" onClick={this.toggleTooltip}>
|
||||
{this.props.children}
|
||||
</Target>
|
||||
<div className={`popper__manager ${className}`} onClick={togglePopper}>
|
||||
<Popper {...restProps}>{children}</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTooltip(Popover);
|
||||
export default withPopper(Popover);
|
||||
|
42
public/app/core/components/Tooltip/Popper.tsx
Normal file
42
public/app/core/components/Tooltip/Popper.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Manager, Popper as ReactPopper, Reference } from 'react-popper';
|
||||
|
||||
interface Props {
|
||||
renderContent: (content: any) => any;
|
||||
show: boolean;
|
||||
placement?: any;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
}
|
||||
|
||||
class Popper extends PureComponent<Props> {
|
||||
render() {
|
||||
const { children, renderContent, show, placement } = this.props;
|
||||
const { content } = this.props;
|
||||
const modifiers = {
|
||||
flip: { enabled: false },
|
||||
preventOverflow: { enabled: false },
|
||||
hide: { enabled: false },
|
||||
};
|
||||
return (
|
||||
<Manager>
|
||||
<Reference>{({ ref }) => <div ref={ref}>{children}</div>}</Reference>
|
||||
{show && (
|
||||
<ReactPopper placement={placement} modifiers={modifiers}>
|
||||
{({ ref, style, placement, arrowProps }) => {
|
||||
return (
|
||||
<div ref={ref} style={style} data-placement={placement} className="popper">
|
||||
<div className="popper__background">
|
||||
{renderContent(content)}
|
||||
<div ref={arrowProps.ref} data-placement={placement} className="popper__arrow" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</ReactPopper>
|
||||
)}
|
||||
</Manager>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Popper;
|
@ -1,36 +1,17 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import withTooltip from './withTooltip';
|
||||
import { Target } from 'react-popper';
|
||||
|
||||
interface Props {
|
||||
tooltipSetState: (prevState: object) => void;
|
||||
}
|
||||
|
||||
class Tooltip extends PureComponent<Props> {
|
||||
showTooltip = () => {
|
||||
const { tooltipSetState } = this.props;
|
||||
|
||||
tooltipSetState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
}));
|
||||
};
|
||||
|
||||
hideTooltip = () => {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
};
|
||||
import Popper from './Popper';
|
||||
import withPopper, { UsingPopperProps } from './withPopper';
|
||||
|
||||
class Tooltip extends PureComponent<UsingPopperProps> {
|
||||
render() {
|
||||
const { children, hidePopper, showPopper, className, ...restProps } = this.props;
|
||||
|
||||
return (
|
||||
<Target className="popper__target" onMouseOver={this.showTooltip} onMouseOut={this.hideTooltip}>
|
||||
{this.props.children}
|
||||
</Target>
|
||||
<div className={`popper__manager ${className}`} onMouseEnter={showPopper} onMouseLeave={hidePopper}>
|
||||
<Popper {...restProps}>{children}</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTooltip(Tooltip);
|
||||
export default withPopper(Tooltip);
|
||||
|
@ -3,11 +3,9 @@
|
||||
exports[`Popover renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager test-class"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="popper__target"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div>
|
||||
<button>
|
||||
Button with Popover
|
||||
</button>
|
||||
|
@ -3,12 +3,10 @@
|
||||
exports[`Tooltip renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager test-class"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<div
|
||||
className="popper__target"
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
>
|
||||
<div>
|
||||
<a
|
||||
href="http://www.grafana.com"
|
||||
>
|
||||
|
83
public/app/core/components/Tooltip/withPopper.tsx
Normal file
83
public/app/core/components/Tooltip/withPopper.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface UsingPopperProps {
|
||||
showPopper: (prevState: object) => void;
|
||||
hidePopper: (prevState: object) => void;
|
||||
renderContent: (content: any) => any;
|
||||
show: boolean;
|
||||
placement?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
placement?: string;
|
||||
className?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
}
|
||||
|
||||
interface State {
|
||||
placement: string;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export default function withPopper(WrappedComponent) {
|
||||
return class extends React.Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setState = this.setState.bind(this);
|
||||
this.state = {
|
||||
placement: this.props.placement || 'auto',
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
placement: nextProps.placement,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showPopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
}));
|
||||
};
|
||||
|
||||
hidePopper = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
};
|
||||
|
||||
renderContent(content) {
|
||||
if (typeof content === 'function') {
|
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content;
|
||||
return <ReactComponent />;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { show, placement } = this.state;
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...this.props}
|
||||
showPopper={this.showPopper}
|
||||
hidePopper={this.hidePopper}
|
||||
renderContent={this.renderContent}
|
||||
show={show}
|
||||
placement={placement}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Manager, Popper, Arrow } from 'react-popper';
|
||||
|
||||
interface IwithTooltipProps {
|
||||
placement?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function withTooltip(WrappedComponent) {
|
||||
return class extends React.Component<IwithTooltipProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setState = this.setState.bind(this);
|
||||
this.state = {
|
||||
placement: this.props.placement || 'auto',
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
placement: nextProps.placement,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderContent(content) {
|
||||
if (typeof content === 'function') {
|
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content;
|
||||
return <ReactComponent />;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { content, className } = this.props;
|
||||
|
||||
return (
|
||||
<Manager className={`popper__manager ${className || ''}`}>
|
||||
<WrappedComponent {...this.props} tooltipSetState={this.setState} />
|
||||
{this.state.show ? (
|
||||
<Popper placement={this.state.placement} className="popper">
|
||||
{this.renderContent(content)}
|
||||
<Arrow className="popper__arrow" />
|
||||
</Popper>
|
||||
) : null}
|
||||
</Manager>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
.popper {
|
||||
position: absolute;
|
||||
z-index: $zindex-tooltip;
|
||||
background: $tooltipBackground;
|
||||
color: $tooltipColor;
|
||||
max-width: 400px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -35,10 +31,18 @@
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.popper[data-placement^='bottom'] {
|
||||
margin-top: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.popper__background {
|
||||
background: $tooltipBackground;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.popper[data-placement^='bottom'] .popper__arrow {
|
||||
@ -46,21 +50,21 @@
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
border-top-color: transparent;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
top: 0;
|
||||
left: calc(50% - 8px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.popper[data-placement^='right'] {
|
||||
margin-left: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.popper[data-placement^='right'] .popper__arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
left: 0;
|
||||
top: calc(50% - 8px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user