Browse Source

Implemented new spectrum palette

Dominik Prokop 7 years ago
parent
commit
9fd9bba1f4

+ 94 - 0
packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx

@@ -0,0 +1,94 @@
+import React from 'react';
+import { ColorPickerProps } from './ColorPicker';
+import tinycolor from 'tinycolor2';
+import { debounce } from 'lodash';
+
+interface ColorInputState {
+  previousColor: string;
+  value: string;
+}
+
+interface ColorInputProps extends ColorPickerProps {
+  style?: React.CSSProperties;
+}
+
+class ColorInput extends React.PureComponent<ColorInputProps, ColorInputState> {
+  constructor(props: ColorInputProps) {
+    super(props);
+    this.state = {
+      previousColor: props.color,
+      value: props.color,
+    };
+
+    this.updateColor = debounce(this.updateColor, 100);
+  }
+
+  static getDerivedStateFromProps(props: ColorPickerProps, state: ColorInputState) {
+    const newColor = tinycolor(props.color);
+    if (newColor.isValid() && props.color !== state.previousColor) {
+      return {
+        ...state,
+        previousColor: props.color,
+        value: newColor.toString(),
+      };
+    }
+
+    return state;
+  }
+  updateColor = (color: string) => {
+    this.props.onChange(color);
+  };
+
+  handleChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
+    const newColor = tinycolor(event.currentTarget.value);
+
+    this.setState({
+      value: event.currentTarget.value,
+    });
+
+    if (newColor.isValid()) {
+      this.updateColor(newColor.toString());
+    }
+  };
+
+  handleBlur = () => {
+    const newColor = tinycolor(this.state.value);
+
+    if (!newColor.isValid()) {
+      this.setState({
+        value: this.props.color,
+      });
+    }
+  };
+
+  render() {
+    const { value } = this.state;
+    return (
+      <div
+        style={{
+          display: 'flex',
+          ...this.props.style,
+        }}
+      >
+        <div
+          style={{
+            background: this.props.color,
+            width: '35px',
+            height: '35px',
+            flexGrow: 0,
+            borderRadius: '3px 0 0 3px',
+          }}
+        />
+        <div
+          style={{
+            flexGrow: 1,
+          }}
+        >
+          <input className="gf-form-input" value={value} onChange={this.handleChange} onBlur={this.handleBlur} />
+        </div>
+      </div>
+    );
+  }
+}
+
+export default ColorInput;

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

@@ -29,10 +29,9 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
       if (enableNamedColors) {
         return onChange(color);
       }
-
       return onChange(getColorFromHexRgbOrName(color));
-
     };
+
     render() {
       const popoverElement = React.createElement(popover, {
         ...this.props,
@@ -40,7 +39,6 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
       });
       const { theme, withArrow, children } = this.props;
 
-      // TODO: hoist that this shit
       const renderArrow: RenderPopperArrowFn = ({ arrowProps, placement }) => {
         return (
           <div

+ 3 - 4
packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx

@@ -1,11 +1,10 @@
 import React from 'react';
 import NamedColorsPicker from './NamedColorsPalette';
 import { getColorName } from '../..//utils/colorsPalette';
-import { SpectrumPalette } from './SpectrumPalette';
 import { ColorPickerProps } from './ColorPicker';
 import { GrafanaTheme, Themeable } from '../../types';
 import { PopperContentProps } from '../Tooltip/PopperController';
-
+import SpectrumPalette from './SpectrumPalette';
 
 export interface Props extends ColorPickerProps, Themeable, PopperContentProps {}
 
@@ -24,7 +23,7 @@ export class ColorPickerPopover extends React.Component<Props, State> {
   }
 
   handleSpectrumColorSelect = (color: any) => {
-    this.props.onChange(color.toRgbString());
+    this.props.onChange(color);
   };
 
   renderPicker = () => {
@@ -32,7 +31,7 @@ export class ColorPickerPopover extends React.Component<Props, State> {
     const { color, onChange, theme } = this.props;
 
     return activePicker === 'spectrum' ? (
-      <SpectrumPalette color={color} onColorSelect={this.handleSpectrumColorSelect} options={{}} />
+      <SpectrumPalette color={color} onChange={this.handleSpectrumColorSelect} />
     ) : (
       <NamedColorsPicker color={getColorName(color)} onChange={onChange} theme={theme} />
     );

+ 57 - 0
packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.story.tsx

@@ -0,0 +1,57 @@
+import React, { FunctionComponent } from 'react';
+import { storiesOf } from '@storybook/react';
+import SpectrumPalette from './SpectrumPalette';
+
+const CenteredStory: FunctionComponent<{}> = ({ children }) => {
+  return (
+    <div
+      style={{
+        height: '100vh  ',
+        display: 'flex',
+        alignItems: 'center',
+        justifyContent: 'center',
+      }}
+    >
+      {children}
+    </div>
+  );
+};
+
+interface StateHolderProps<T> {
+  initialState: T;
+  children: (currentState: T, updateState: (nextState: T) => void) => JSX.Element;
+}
+
+export class UseState<T> extends React.Component<StateHolderProps<T>, { value: T }> {
+  constructor(props: StateHolderProps<T>) {
+    super(props);
+    this.state = {
+      value: props.initialState,
+    };
+  }
+
+  handleStateUpdate = (nextState: T) => {
+    this.setState({ value: nextState });
+  };
+  render() {
+    return this.props.children(this.state.value, this.handleStateUpdate);
+  }
+}
+
+storiesOf('UI/SpectrumPalette', module)
+  .addDecorator(story => <CenteredStory>{story()}</CenteredStory>)
+  .add('Named colors swatch - support for named colors', () => {
+
+    return (
+      <UseState initialState="red">
+        {(selectedColor, updateSelectedColor) => {
+          return (
+            <SpectrumPalette
+              color={selectedColor}
+              onChange={updateSelectedColor}
+            />
+          );
+        }}
+      </UseState>
+    );
+  });

+ 85 - 64
packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx

@@ -1,72 +1,93 @@
 import React from 'react';
-import _ from 'lodash';
-import $ from 'jquery';
-import '../../vendor/spectrum';
+import { CustomPicker, ColorResult } from 'react-color';
 
-export interface Props {
+import { Saturation, Hue, Alpha } from 'react-color/lib/components/common';
+import { getColorFromHexRgbOrName } from '../../utils/colorsPalette';
+import tinycolor from 'tinycolor2';
+import ColorInput from './ColorInput';
+
+export interface SpectrumPaletteProps {
   color: string;
-  options: object;
-  onColorSelect: (color: string) => void;
+  onChange: (color: string) => void;
 }
 
-export class SpectrumPalette extends React.Component<Props, any> {
-  elem: any;
-  isMoving: boolean;
-
-  constructor(props: Props) {
-    super(props);
-    this.onSpectrumMove = this.onSpectrumMove.bind(this);
-    this.setComponentElem = this.setComponentElem.bind(this);
-  }
-
-  setComponentElem(elem: any) {
-    this.elem = $(elem);
-  }
-
-  onSpectrumMove(color: any) {
-    this.isMoving = true;
-    this.props.onColorSelect(color);
-  }
+// @ts-ignore
+const SpectrumPicker = CustomPicker(({ rgb, hsl, onChange, renderers }) => {
+  return (
+    <div
+      style={{
+        display: 'flex',
+        width: '100%',
+        flexDirection: 'column',
+      }}
+    >
+      <div
+        style={{
+          display: 'flex',
+        }}
+      >
+        <div
+          style={{
+            display: 'flex',
+            flexGrow: 1,
+            flexDirection: 'column',
+          }}
+        >
+          <div
+            style={{
+              position: 'relative',
+              height: '100px',
+              width: '100%',
+            }}
+          >
+            {/*
+      // @ts-ignore */}
+            <Saturation onChange={onChange} hsl={hsl} hsv={tinycolor(hsl).toHsv()} />
+          </div>
+          <div
+            style={{
+              width: '100%',
+              height: '16px',
+              marginTop: '16px',
+              position: 'relative',
+              background: 'white',
+            }}
+          >
+            {/*
+      // @ts-ignore */}
+            <Alpha rgb={rgb} hsl={hsl} a={rgb.a} onChange={onChange} />
+          </div>
+        </div>
 
-  componentDidMount() {
-    const spectrumOptions = _.assignIn(
-      {
-        flat: true,
-        showAlpha: true,
-        showButtons: false,
-        color: this.props.color,
-        appendTo: this.elem,
-        move: this.onSpectrumMove,
-      },
-      this.props.options
-    );
+        <div
+          style={{
+            position: 'relative',
+            width: '16px',
+            height: '100px',
+            marginLeft: '16px',
+          }}
+        >
+          {/*
+        // @ts-ignore */}
+          <Hue onChange={onChange} hsl={hsl} direction="vertical" />
+        </div>
+      </div>
+    </div>
+  );
+});
 
-    this.elem.spectrum(spectrumOptions);
-    this.elem.spectrum('show');
-    this.elem.spectrum('set', this.props.color);
-  }
+const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color, onChange }) => {
+  return (
+    <div>
+      <SpectrumPicker
+        color={tinycolor(getColorFromHexRgbOrName(color)).toRgb()}
+        onChange={(a: ColorResult) => {
+          onChange(tinycolor(a.rgb).toString());
+        }}
+      />
+      <ColorInput color={color} onChange={onChange} style={{ marginTop: '16px' }} />
+    </div>
+  );
+};
 
-  componentWillUpdate(nextProps: any) {
-    // If user move pointer over spectrum field this produce 'move' event and component
-    // may update props.color. We don't want to update spectrum color in this case, so we can use
-    // isMoving flag for tracking moving state. Flag should be cleared in componentDidUpdate() which
-    // is called after updating occurs (when user finished moving).
-    if (!this.isMoving) {
-      this.elem.spectrum('set', nextProps.color);
-    }
-  }
-
-  componentDidUpdate() {
-    if (this.isMoving) {
-      this.isMoving = false;
-    }
-  }
-
-  componentWillUnmount() {
-    this.elem.spectrum('destroy');
-  }
-
-  render() {
-    return <div className="spectrum-container" ref={this.setComponentElem} />;
-  }
-}
+export default SpectrumPalette;