Просмотр исходного кода

Make popover hide delay configurable to enable better UX

Dominik Prokop 7 лет назад
Родитель
Сommit
d86d063900

+ 2 - 2
packages/grafana-ui/src/components/ColorPicker/ColorPicker.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');

+ 0 - 1
packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx

@@ -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 {}
 
 

+ 42 - 40
packages/grafana-ui/src/components/Tooltip/Popper.tsx

@@ -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 },
-  exiting: { opacity: 0 },
+  entered: { opacity: 1, transitionDelay: '0s' },
+  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 => (
-            <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>
-                    </div>
-                  );
-                }}
-              </ReactPopper>
-            </Portal>
-          )}
+                    );
+                  }}
+                </ReactPopper>
+              </Portal>
+            );
+          }}
         </Transition>
         </Transition>
       </Manager>
       </Manager>
     );
     );

+ 20 - 2
packages/grafana-ui/src/components/Tooltip/PopperController.tsx

@@ -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,