mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 11:44:26 -06:00
Make popover hide delay configurable to enable better UX
This commit is contained in:
parent
2b34933554
commit
d86d063900
@ -37,7 +37,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
|
||||
};
|
||||
|
||||
return (
|
||||
<PopperController content={popoverElement} placement="bottom-start">
|
||||
<PopperController content={popoverElement} hideAfter={500}>
|
||||
{(showPopper, hidePopper, popperProps) => {
|
||||
return (
|
||||
<>
|
||||
@ -79,5 +79,5 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
|
||||
};
|
||||
};
|
||||
|
||||
export const ColorPicker = colorPickerFactory(ColorPickerPopover, 'ColorPicker');
|
||||
export const ColorPicker = colorPickerFactory(ColorPickerPopover, 'ColorPicker');
|
||||
export const SeriesColorPicker = colorPickerFactory(SeriesColorPickerPopover, 'SeriesColorPicker');
|
||||
|
@ -6,7 +6,6 @@ import { ColorPickerProps } from './ColorPicker';
|
||||
import { GrafanaTheme, Themeable } from '../../types';
|
||||
import { PopperContentProps } from '../Tooltip/PopperController';
|
||||
|
||||
// const DEFAULT_COLOR = '#000000';
|
||||
|
||||
export interface Props extends ColorPickerProps, Themeable, PopperContentProps {}
|
||||
|
||||
|
@ -13,8 +13,8 @@ const defaultTransitionStyles = {
|
||||
const transitionStyles: { [key: string]: object } = {
|
||||
exited: { opacity: 0 },
|
||||
entering: { opacity: 0 },
|
||||
entered: { opacity: 1 },
|
||||
exiting: { opacity: 0 },
|
||||
entered: { opacity: 1, transitionDelay: '0s' },
|
||||
exiting: { opacity: 0, transitionDelay: '500ms' },
|
||||
};
|
||||
|
||||
export type RenderPopperArrowFn = (
|
||||
@ -41,46 +41,48 @@ class Popper extends PureComponent<Props> {
|
||||
return (
|
||||
<Manager>
|
||||
<Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}>
|
||||
{transitionState => (
|
||||
<Portal>
|
||||
<ReactPopper
|
||||
placement={placement}
|
||||
referenceElement={this.props.referenceElement}
|
||||
// TODO: move modifiers config to popper controller
|
||||
modifiers={{ preventOverflow: { enabled: true, boundariesElement: 'window' } }}
|
||||
>
|
||||
{({ ref, style, placement, arrowProps, scheduleUpdate }) => {
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
ref={ref}
|
||||
style={{
|
||||
...style,
|
||||
...defaultTransitionStyles,
|
||||
...transitionStyles[transitionState],
|
||||
}}
|
||||
data-placement={placement}
|
||||
className={`${wrapperClassName}`}
|
||||
>
|
||||
<div className={className}>
|
||||
{typeof content === 'string'
|
||||
? content
|
||||
: React.cloneElement(content, {
|
||||
updatePopperPosition: scheduleUpdate,
|
||||
{transitionState => {
|
||||
return (
|
||||
<Portal>
|
||||
<ReactPopper
|
||||
placement={placement}
|
||||
referenceElement={this.props.referenceElement}
|
||||
// TODO: move modifiers config to popper controller
|
||||
modifiers={{ preventOverflow: { enabled: true, boundariesElement: 'window' } }}
|
||||
>
|
||||
{({ ref, style, placement, arrowProps, scheduleUpdate }) => {
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
ref={ref}
|
||||
style={{
|
||||
...style,
|
||||
...defaultTransitionStyles,
|
||||
...transitionStyles[transitionState],
|
||||
}}
|
||||
data-placement={placement}
|
||||
className={`${wrapperClassName}`}
|
||||
>
|
||||
<div className={className}>
|
||||
{typeof content === 'string'
|
||||
? content
|
||||
: React.cloneElement(content, {
|
||||
updatePopperPosition: scheduleUpdate,
|
||||
})}
|
||||
{renderArrow &&
|
||||
renderArrow({
|
||||
arrowProps,
|
||||
placement,
|
||||
})}
|
||||
{renderArrow &&
|
||||
renderArrow({
|
||||
arrowProps,
|
||||
placement,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</ReactPopper>
|
||||
</Portal>
|
||||
)}
|
||||
);
|
||||
}}
|
||||
</ReactPopper>
|
||||
</Portal>
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
</Manager>
|
||||
);
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import * as PopperJS from 'popper.js';
|
||||
|
||||
// This API allows popovers to update Popper's position when e.g. popover content chaanges
|
||||
// This API allows popovers to update Popper's position when e.g. popover content changes
|
||||
// updatePopperPosition is delivered to content by react-popper
|
||||
export interface PopperContentProps { updatePopperPosition?: () => void; }
|
||||
export interface PopperContentProps {
|
||||
updatePopperPosition?: () => void;
|
||||
}
|
||||
|
||||
export type PopperContent<T extends PopperContentProps> = string | React.ReactElement<T>;
|
||||
|
||||
@ -29,6 +31,7 @@ interface Props {
|
||||
content: PopperContent<any>;
|
||||
className?: string;
|
||||
children: PopperControllerRenderProp;
|
||||
hideAfter?: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
@ -37,6 +40,8 @@ interface State {
|
||||
}
|
||||
|
||||
class PopperController extends React.Component<Props, State> {
|
||||
private hideTimeout: any;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -58,6 +63,10 @@ class PopperController extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
showPopper = () => {
|
||||
if (this.hideTimeout) {
|
||||
clearTimeout(this.hideTimeout);
|
||||
}
|
||||
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
@ -65,6 +74,15 @@ class PopperController extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
hidePopper = () => {
|
||||
if (this.props.hideAfter !== 0) {
|
||||
this.hideTimeout = setTimeout(() => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
}, this.props.hideAfter);
|
||||
return;
|
||||
}
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
|
Loading…
Reference in New Issue
Block a user