Make popover hide delay configurable to enable better UX

pull/14914/head
Dominik Prokop 7 years ago
parent 2b34933554
commit d86d063900
  1. 4
      packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
  2. 1
      packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx
  3. 82
      packages/grafana-ui/src/components/Tooltip/Popper.tsx
  4. 22
      packages/grafana-ui/src/components/Tooltip/PopperController.tsx

@ -37,7 +37,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
}; };
return ( return (
<PopperController content={popoverElement} placement="bottom-start"> <PopperController content={popoverElement} hideAfter={500}>
{(showPopper, hidePopper, popperProps) => { {(showPopper, hidePopper, popperProps) => {
return ( 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'); export const SeriesColorPicker = colorPickerFactory(SeriesColorPickerPopover, 'SeriesColorPicker');

@ -6,7 +6,6 @@ import { ColorPickerProps } from './ColorPicker';
import { GrafanaTheme, Themeable } from '../../types'; import { GrafanaTheme, Themeable } from '../../types';
import { PopperContentProps } from '../Tooltip/PopperController'; import { PopperContentProps } from '../Tooltip/PopperController';
// const DEFAULT_COLOR = '#000000';
export interface Props extends ColorPickerProps, Themeable, PopperContentProps {} export interface Props extends ColorPickerProps, Themeable, PopperContentProps {}

@ -13,8 +13,8 @@ const defaultTransitionStyles = {
const transitionStyles: { [key: string]: object } = { const transitionStyles: { [key: string]: object } = {
exited: { opacity: 0 }, exited: { opacity: 0 },
entering: { opacity: 0 }, entering: { opacity: 0 },
entered: { opacity: 1 }, entered: { opacity: 1, transitionDelay: '0s' },
exiting: { opacity: 0 }, exiting: { opacity: 0, transitionDelay: '500ms' },
}; };
export type RenderPopperArrowFn = ( export type RenderPopperArrowFn = (
@ -41,46 +41,48 @@ class Popper extends PureComponent<Props> {
return ( return (
<Manager> <Manager>
<Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}> <Transition in={show} timeout={100} mountOnEnter={true} unmountOnExit={true}>
{transitionState => ( {transitionState => {
<Portal> return (
<ReactPopper <Portal>
placement={placement} <ReactPopper
referenceElement={this.props.referenceElement} placement={placement}
// TODO: move modifiers config to popper controller referenceElement={this.props.referenceElement}
modifiers={{ preventOverflow: { enabled: true, boundariesElement: 'window' } }} // TODO: move modifiers config to popper controller
> modifiers={{ preventOverflow: { enabled: true, boundariesElement: 'window' } }}
{({ ref, style, placement, arrowProps, scheduleUpdate }) => { >
return ( {({ ref, style, placement, arrowProps, scheduleUpdate }) => {
<div return (
onMouseEnter={onMouseEnter} <div
onMouseLeave={onMouseLeave} onMouseEnter={onMouseEnter}
ref={ref} onMouseLeave={onMouseLeave}
style={{ ref={ref}
...style, style={{
...defaultTransitionStyles, ...style,
...transitionStyles[transitionState], ...defaultTransitionStyles,
}} ...transitionStyles[transitionState],
data-placement={placement} }}
className={`${wrapperClassName}`} data-placement={placement}
> className={`${wrapperClassName}`}
<div className={className}> >
{typeof content === 'string' <div className={className}>
? content {typeof content === 'string'
: React.cloneElement(content, { ? content
updatePopperPosition: scheduleUpdate, : React.cloneElement(content, {
updatePopperPosition: scheduleUpdate,
})}
{renderArrow &&
renderArrow({
arrowProps,
placement,
})} })}
{renderArrow && </div>
renderArrow({
arrowProps,
placement,
})}
</div> </div>
</div> );
); }}
}} </ReactPopper>
</ReactPopper> </Portal>
</Portal> );
)} }}
</Transition> </Transition>
</Manager> </Manager>
); );

@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import * as PopperJS from 'popper.js'; 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 // 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>; export type PopperContent<T extends PopperContentProps> = string | React.ReactElement<T>;
@ -29,6 +31,7 @@ interface Props {
content: PopperContent<any>; content: PopperContent<any>;
className?: string; className?: string;
children: PopperControllerRenderProp; children: PopperControllerRenderProp;
hideAfter?: number;
} }
interface State { interface State {
@ -37,6 +40,8 @@ interface State {
} }
class PopperController extends React.Component<Props, State> { class PopperController extends React.Component<Props, State> {
private hideTimeout: any;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -58,6 +63,10 @@ class PopperController extends React.Component<Props, State> {
} }
showPopper = () => { showPopper = () => {
if (this.hideTimeout) {
clearTimeout(this.hideTimeout);
}
this.setState(prevState => ({ this.setState(prevState => ({
...prevState, ...prevState,
show: true, show: true,
@ -65,6 +74,15 @@ class PopperController extends React.Component<Props, State> {
}; };
hidePopper = () => { hidePopper = () => {
if (this.props.hideAfter !== 0) {
this.hideTimeout = setTimeout(() => {
this.setState(prevState => ({
...prevState,
show: false,
}));
}, this.props.hideAfter);
return;
}
this.setState(prevState => ({ this.setState(prevState => ({
...prevState, ...prevState,
show: false, show: false,

Loading…
Cancel
Save