diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx new file mode 100644 index 00000000000..4c5df5314b8 --- /dev/null +++ b/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 { + 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) => { + 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 ( +
+
+
+ +
+
+ ); + } +} + +export default ColorInput; diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx index 12ee4977137..f807b09bd93 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx @@ -29,10 +29,9 @@ export const colorPickerFactory = ( if (enableNamedColors) { return onChange(color); } - return onChange(getColorFromHexRgbOrName(color)); - }; + render() { const popoverElement = React.createElement(popover, { ...this.props, @@ -40,7 +39,6 @@ export const colorPickerFactory = ( }); const { theme, withArrow, children } = this.props; - // TODO: hoist that this shit const renderArrow: RenderPopperArrowFn = ({ arrowProps, placement }) => { return (
{ } handleSpectrumColorSelect = (color: any) => { - this.props.onChange(color.toRgbString()); + this.props.onChange(color); }; renderPicker = () => { @@ -32,7 +31,7 @@ export class ColorPickerPopover extends React.Component { const { color, onChange, theme } = this.props; return activePicker === 'spectrum' ? ( - + ) : ( ); diff --git a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.story.tsx b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.story.tsx new file mode 100644 index 00000000000..843359d0168 --- /dev/null +++ b/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 ( +
+ {children} +
+ ); +}; + +interface StateHolderProps { + initialState: T; + children: (currentState: T, updateState: (nextState: T) => void) => JSX.Element; +} + +export class UseState extends React.Component, { value: T }> { + constructor(props: StateHolderProps) { + 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 => {story()}) + .add('Named colors swatch - support for named colors', () => { + + return ( + + {(selectedColor, updateSelectedColor) => { + return ( + + ); + }} + + ); + }); diff --git a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx index 154ff4b5bab..b38d2f3031a 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx +++ b/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 { - elem: any; - isMoving: boolean; +// @ts-ignore +const SpectrumPicker = CustomPicker(({ rgb, hsl, onChange, renderers }) => { + return ( +
+
+
+
+ {/* + // @ts-ignore */} + +
+
+ {/* + // @ts-ignore */} + +
+
- constructor(props: Props) { - super(props); - this.onSpectrumMove = this.onSpectrumMove.bind(this); - this.setComponentElem = this.setComponentElem.bind(this); - } +
+ {/* + // @ts-ignore */} + +
+
+
+ ); +}); - setComponentElem(elem: any) { - this.elem = $(elem); - } +const SpectrumPalette: React.FunctionComponent = ({ color, onChange }) => { + return ( +
+ { + onChange(tinycolor(a.rgb).toString()); + }} + /> + +
+ ); +}; - onSpectrumMove(color: any) { - this.isMoving = true; - this.props.onColorSelect(color); - } - - componentDidMount() { - const spectrumOptions = _.assignIn( - { - flat: true, - showAlpha: true, - showButtons: false, - color: this.props.color, - appendTo: this.elem, - move: this.onSpectrumMove, - }, - this.props.options - ); - - this.elem.spectrum(spectrumOptions); - this.elem.spectrum('show'); - this.elem.spectrum('set', this.props.color); - } - - 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
; - } -} +export default SpectrumPalette;