grafana/public/app/plugins/datasource/graphite/FunctionEditor.tsx
Chi-Hsuan Huang 546f569e0c
Chore: Enable eslint-plugin-react partial rules (#29428)
* Chore: Enable eslint react/display-name

Enable react/display-name and fixed the corresponding linting issue

part of: #29201

* Chore: Enable eslint react/no-deprecated

Enable react/no-deprecated and add the UNSAFE_ prefix for deprected methods

part of: #29201

* Chore: Enable eslint react/no-find-dom-node

Enable react/no-find-dom-node rule and use ref instead

part of: #29201

* Test: Update TeamGroupSync test snapshot

Since we added the displayName for ToolTip compontent and tag name is changed.

* Fix: Fixed ClickOutsideWrapper render

The props.children might contains numbers of nodes which make cloneElement failed. Change to simply use a div to wrapper
the children and assign the ref to div for this feature

* Style: Use shorthand method definition style for inline component

* Fix: Rebase master and fix linting

Rebase from master branch and fix new displayName linting warning
2020-12-01 16:19:52 +01:00

121 lines
3.6 KiB
TypeScript

import React, { Suspense } from 'react';
import { PopoverController, Popover, ClickOutsideWrapper } from '@grafana/ui';
import { FunctionDescriptor, FunctionEditorControls, FunctionEditorControlsProps } from './FunctionEditorControls';
interface FunctionEditorProps extends FunctionEditorControlsProps {
func: FunctionDescriptor;
}
interface FunctionEditorState {
showingDescription: boolean;
}
const FunctionDescription = React.lazy(async () => {
// @ts-ignore
const { default: rst2html } = await import(/* webpackChunkName: "rst2html" */ 'rst2html');
return {
default(props: { description?: string }) {
return <div dangerouslySetInnerHTML={{ __html: rst2html(props.description ?? '') }} />;
},
};
});
class FunctionEditor extends React.PureComponent<FunctionEditorProps, FunctionEditorState> {
private triggerRef = React.createRef<HTMLSpanElement>();
constructor(props: FunctionEditorProps) {
super(props);
this.state = {
showingDescription: false,
};
}
renderContent = ({ updatePopperPosition }: any) => {
const {
onMoveLeft,
onMoveRight,
func: {
def: { name, description },
},
} = this.props;
const { showingDescription } = this.state;
if (showingDescription) {
return (
<div style={{ overflow: 'auto', maxHeight: '30rem', textAlign: 'left', fontWeight: 'normal' }}>
<h4 style={{ color: 'white' }}> {name} </h4>
<Suspense fallback={<span>Loading description...</span>}>
<FunctionDescription description={description} />
</Suspense>
</div>
);
}
return (
<FunctionEditorControls
{...this.props}
onMoveLeft={() => {
onMoveLeft(this.props.func);
updatePopperPosition();
}}
onMoveRight={() => {
onMoveRight(this.props.func);
updatePopperPosition();
}}
onDescriptionShow={() => {
this.setState({ showingDescription: true }, () => {
updatePopperPosition();
});
}}
/>
);
};
render() {
return (
<PopoverController content={this.renderContent} placement="top" hideAfter={100}>
{(showPopper, hidePopper, popperProps) => {
return (
<>
{this.triggerRef.current && (
<Popover
{...popperProps}
referenceElement={this.triggerRef.current}
wrapperClassName="popper"
className="popper__background"
onMouseLeave={() => {
this.setState({ showingDescription: false });
}}
renderArrow={({ arrowProps, placement }) => (
<div className="popper__arrow" data-placement={placement} {...arrowProps} />
)}
/>
)}
<ClickOutsideWrapper
onClick={() => {
if (popperProps.show) {
hidePopper();
}
}}
>
<span
ref={this.triggerRef}
onClick={popperProps.show ? hidePopper : showPopper}
onMouseLeave={() => {
this.setState({ showingDescription: false });
}}
style={{ cursor: 'pointer' }}
>
{this.props.func.def.name}
</span>
</ClickOutsideWrapper>
</>
);
}}
</PopoverController>
);
}
}
export { FunctionEditor };