mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
10389 react tooltip components (#10473)
* poc: Use react-popper for tooltips #10389 * poc: Add popover component and use a hoc() for Tooltip + Popover to avoid code duplication #10389 * jest: Add snapshot tests to Popover and Tooltip #10389 * poc: Move target from hoc into Popover/Tooltip-component #10389 * poc: Clean up unused styles and use the existing Grafana style/colors on popper tooltip #10389 * poc: Remove test code before PR * poc: Remove imports used in poc but shouldn't be included anymore #10389
This commit is contained in:
committed by
Torkel Ödegaard
parent
aac1b250af
commit
e4a2bda4f2
@@ -23,6 +23,11 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
||||
|
||||
this.props.nav.load('alerting', 'alert-list');
|
||||
this.fetchRules();
|
||||
this.handleTooltipPositionChange = this.handleTooltipPositionChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
tooltipPosition: 'auto',
|
||||
};
|
||||
}
|
||||
|
||||
onStateFilterChanged = evt => {
|
||||
@@ -44,6 +49,12 @@ export class AlertRuleList extends React.Component<IContainerProps, any> {
|
||||
});
|
||||
};
|
||||
|
||||
handleTooltipPositionChange(evt) {
|
||||
evt.preventDefault();
|
||||
this.setState({
|
||||
tooltipPosition: evt.target.value,
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const { nav, alertList } = this.props;
|
||||
|
||||
|
||||
16
public/app/core/components/Tooltip/Popover.jest.tsx
Normal file
16
public/app/core/components/Tooltip/Popover.jest.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Popover from './Popover';
|
||||
|
||||
describe('Popover', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Popover placement="auto" content="Popover text">
|
||||
<button>Button with Popover</button>
|
||||
</Popover>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
34
public/app/core/components/Tooltip/Popover.tsx
Normal file
34
public/app/core/components/Tooltip/Popover.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import withTooltip from './withTooltip';
|
||||
import { Target } from 'react-popper';
|
||||
|
||||
interface IPopoverProps {
|
||||
tooltipSetState: (prevState: object) => void;
|
||||
}
|
||||
|
||||
class Popover extends React.Component<IPopoverProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.toggleTooltip = this.toggleTooltip.bind(this);
|
||||
}
|
||||
|
||||
toggleTooltip() {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: !prevState.show,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Target className="popper__target" onClick={this.toggleTooltip}>
|
||||
{this.props.children}
|
||||
</Target>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTooltip(Popover);
|
||||
16
public/app/core/components/Tooltip/Tooltip.jest.tsx
Normal file
16
public/app/core/components/Tooltip/Tooltip.jest.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import Tooltip from './Tooltip';
|
||||
|
||||
describe('Tooltip', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Tooltip placement="auto" content="Tooltip text">
|
||||
<a href="http://www.grafana.com">Link with tooltip</a>
|
||||
</Tooltip>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
45
public/app/core/components/Tooltip/Tooltip.tsx
Normal file
45
public/app/core/components/Tooltip/Tooltip.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import withTooltip from './withTooltip';
|
||||
import { Target } from 'react-popper';
|
||||
|
||||
interface ITooltipProps {
|
||||
tooltipSetState: (prevState: object) => void;
|
||||
}
|
||||
|
||||
class Tooltip extends React.Component<ITooltipProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.showTooltip = this.showTooltip.bind(this);
|
||||
this.hideTooltip = this.hideTooltip.bind(this);
|
||||
}
|
||||
|
||||
showTooltip() {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
hideTooltip() {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: false,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Target className="popper__target" onMouseOver={this.showTooltip} onMouseOut={this.hideTooltip}>
|
||||
{this.props.children}
|
||||
</Target>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTooltip(Tooltip);
|
||||
@@ -0,0 +1,16 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Popover renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager"
|
||||
>
|
||||
<div
|
||||
className="popper__target"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button>
|
||||
Button with Popover
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,19 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Tooltip renders correctly 1`] = `
|
||||
<div
|
||||
className="popper__manager"
|
||||
>
|
||||
<div
|
||||
className="popper__target"
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
>
|
||||
<a
|
||||
href="http://www.grafana.com"
|
||||
>
|
||||
Link with tooltip
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
57
public/app/core/components/Tooltip/withTooltip.tsx
Normal file
57
public/app/core/components/Tooltip/withTooltip.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { Manager, Popper, Arrow } from 'react-popper';
|
||||
|
||||
interface IwithTooltipProps {
|
||||
placement?: string;
|
||||
content: string | ((props: any) => JSX.Element);
|
||||
}
|
||||
|
||||
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 } = this.props;
|
||||
|
||||
return (
|
||||
<Manager className="popper__manager">
|
||||
<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>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user