瀏覽代碼

Enable custom picers on color color picker popovers (for y-axis support in legend picker)

Dominik Prokop 7 年之前
父節點
當前提交
8d8f944a1f

+ 8 - 6
packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx

@@ -9,15 +9,10 @@ import propDeprecationWarning from '../../utils/propDeprecationWarning';
 
 type ColorPickerChangeHandler = (color: string) => void;
 
-export const handleColorPickerPropsDeprecation = (componentName: string, props: ColorPickerProps) => {
-  const { onColorChange } = props;
-  if (onColorChange) {
-    propDeprecationWarning(componentName, 'onColorChange', 'onChange');
-  }
-};
 export interface ColorPickerProps extends Themeable {
   color: string;
   onChange: ColorPickerChangeHandler;
+
   /**
    * @deprecated Use onChange instead
    */
@@ -27,6 +22,13 @@ export interface ColorPickerProps extends Themeable {
   children?: JSX.Element;
 }
 
+export const handleColorPickerPropsDeprecation = (componentName: string, props: ColorPickerProps) => {
+  const { onColorChange } = props;
+  if (onColorChange) {
+    propDeprecationWarning(componentName, 'onColorChange', 'onChange');
+  }
+};
+
 export const colorPickerFactory = <T extends ColorPickerProps>(
   popover: React.ComponentType<T>,
   displayName = 'ColorPicker',

+ 80 - 33
packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx

@@ -2,20 +2,28 @@ import React from 'react';
 import { NamedColorsPalette } from './NamedColorsPalette';
 import { getColorName, getColorFromHexRgbOrName } from '../../utils/namedColorsPalette';
 import { ColorPickerProps, handleColorPickerPropsDeprecation } from './ColorPicker';
-import { GrafanaTheme, Themeable } from '../../types';
+import { GrafanaTheme } from '../../types';
 import { PopperContentProps } from '../Tooltip/PopperController';
 import SpectrumPalette from './SpectrumPalette';
 
-export interface Props extends ColorPickerProps, Themeable, PopperContentProps {}
+export interface Props<T> extends ColorPickerProps, PopperContentProps {
+  customPickers?: T;
+}
 
 type PickerType = 'palette' | 'spectrum';
 
-interface State {
-  activePicker: PickerType;
+interface CustomPickersDescriptor {
+  [key: string]: {
+    tabComponent: React.ComponentType<ColorPickerProps>;
+    name: string;
+  };
+}
+interface State<T> {
+  activePicker: PickerType | keyof T;
 }
 
-export class ColorPickerPopover extends React.Component<Props, State> {
-  constructor(props: Props) {
+export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React.Component<Props<T>, State<T>> {
+  constructor(props: Props<T>) {
     super(props);
     this.state = {
       activePicker: 'palette',
@@ -23,6 +31,11 @@ export class ColorPickerPopover extends React.Component<Props, State> {
     handleColorPickerPropsDeprecation('ColorPickerPopover', props);
   }
 
+  getTabClassName = (tabName: PickerType | keyof T) => {
+    const { activePicker } = this.state;
+    return `ColorPickerPopover__tab ${activePicker === tabName && 'ColorPickerPopover__tab--active'}`;
+  };
+
   handleChange = (color: any) => {
     const { onColorChange, onChange, enableNamedColors } = this.props;
     const changeHandler = onColorChange || onChange;
@@ -33,55 +46,89 @@ export class ColorPickerPopover extends React.Component<Props, State> {
     changeHandler(getColorFromHexRgbOrName(color));
   };
 
+  handleTabChange = (tab: PickerType | keyof T, updatePopperPosition?: () => void) => {
+    return () =>
+      this.setState({ activePicker: tab }, () => {
+        if (updatePopperPosition) {
+          updatePopperPosition();
+        }
+      });
+  };
+
   renderPicker = () => {
     const { activePicker } = this.state;
     const { color, theme } = this.props;
 
-    return activePicker === 'spectrum' ? (
-      <SpectrumPalette color={color} onChange={this.handleChange} theme={theme} />
-    ) : (
-      <NamedColorsPalette color={getColorName(color, theme)} onChange={this.handleChange} theme={theme} />
+    switch (activePicker) {
+      case 'spectrum':
+        return <SpectrumPalette color={color} onChange={this.handleChange} theme={theme} />;
+      case 'palette':
+        return <NamedColorsPalette color={getColorName(color, theme)} onChange={this.handleChange} theme={theme} />;
+      default:
+        return this.renderCustomPicker(activePicker);
+    }
+  };
+
+  renderCustomPicker = (tabKey: keyof T) => {
+    const { customPickers, color, theme } = this.props;
+    if (!customPickers) {
+      return null;
+    }
+
+    return React.createElement(customPickers[tabKey].tabComponent, {
+      color,
+      theme,
+      onChange: this.handleChange,
+    });
+  };
+
+  renderCustomPickerTabs = (updatePopperPosition?: () => void) => {
+    const { customPickers } = this.props;
+
+    if (!customPickers) {
+      return null;
+    }
+
+    return (
+      <>
+        {Object.keys(customPickers).map(key => {
+          return (
+            <div
+              className={this.getTabClassName(key)}
+              onClick={this.handleTabChange(key, updatePopperPosition)}
+              key={key}
+            >
+              {customPickers[key].name}
+            </div>
+          );
+        })}
+      </>
     );
   };
 
   render() {
-    const { activePicker } = this.state;
-    const { theme, children, updatePopperPosition } = this.props;
+    const { theme, updatePopperPosition } = this.props;
     const colorPickerTheme = theme || GrafanaTheme.Dark;
 
     return (
       <div className={`ColorPickerPopover ColorPickerPopover--${colorPickerTheme}`}>
         <div className="ColorPickerPopover__tabs">
           <div
-            className={`ColorPickerPopover__tab ${activePicker === 'palette' && 'ColorPickerPopover__tab--active'}`}
-            onClick={() => {
-              this.setState({ activePicker: 'palette' }, () => {
-                if (updatePopperPosition) {
-                  updatePopperPosition();
-                }
-              });
-            }}
+            className={this.getTabClassName('palette')}
+            onClick={this.handleTabChange('palette', updatePopperPosition)}
           >
-            Default
+            Colors
           </div>
           <div
-            className={`ColorPickerPopover__tab ${activePicker === 'spectrum' && 'ColorPickerPopover__tab--active'}`}
-            onClick={() => {
-              this.setState({ activePicker: 'spectrum' }, () => {
-                if (updatePopperPosition) {
-                  updatePopperPosition();
-                }
-              });
-            }}
+            className={this.getTabClassName('spectrum')}
+            onClick={this.handleTabChange('spectrum', updatePopperPosition)}
           >
             Custom
           </div>
+          {this.renderCustomPickerTabs(updatePopperPosition)}
         </div>
 
-        <div className="ColorPickerPopover__content">
-          {this.renderPicker()}
-          {children}
-        </div>
+        <div className="ColorPickerPopover__content">{this.renderPicker()}</div>
       </div>
     );
   }

+ 10 - 3
packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx

@@ -13,9 +13,16 @@ export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopove
   const { yaxis, onToggleAxis, color, ...colorPickerProps } = props;
 
   return (
-    <ColorPickerPopover color={color || '#000000'} {...colorPickerProps}>
-      <div style={{ marginTop: '32px' }}>{yaxis && <AxisSelector yaxis={yaxis} onToggleAxis={onToggleAxis} />}</div>
-    </ColorPickerPopover>
+    <ColorPickerPopover
+      {...colorPickerProps}
+      color={color || '#000000'}
+      customPickers={{
+        yaxis: {
+          name: 'Y-Axis',
+          tabComponent: () => <div style={{ marginTop: '24px' }}>{yaxis && <AxisSelector yaxis={yaxis} onToggleAxis={onToggleAxis} />}</div>
+        },
+      }}
+    />
   );
 };