Commit 9fd9bba1 by Dominik Prokop

Implemented new spectrum palette

parent ba4b774c
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;
...@@ -29,10 +29,9 @@ export const colorPickerFactory = <T extends ColorPickerProps>( ...@@ -29,10 +29,9 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
if (enableNamedColors) { if (enableNamedColors) {
return onChange(color); return onChange(color);
} }
return onChange(getColorFromHexRgbOrName(color)); return onChange(getColorFromHexRgbOrName(color));
}; };
render() { render() {
const popoverElement = React.createElement(popover, { const popoverElement = React.createElement(popover, {
...this.props, ...this.props,
...@@ -40,7 +39,6 @@ export const colorPickerFactory = <T extends ColorPickerProps>( ...@@ -40,7 +39,6 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
}); });
const { theme, withArrow, children } = this.props; const { theme, withArrow, children } = this.props;
// TODO: hoist that this shit
const renderArrow: RenderPopperArrowFn = ({ arrowProps, placement }) => { const renderArrow: RenderPopperArrowFn = ({ arrowProps, placement }) => {
return ( return (
<div <div
......
import React from 'react'; import React from 'react';
import NamedColorsPicker from './NamedColorsPalette'; import NamedColorsPicker from './NamedColorsPalette';
import { getColorName } from '../..//utils/colorsPalette'; import { getColorName } from '../..//utils/colorsPalette';
import { SpectrumPalette } from './SpectrumPalette';
import { ColorPickerProps } from './ColorPicker'; import { ColorPickerProps } from './ColorPicker';
import { GrafanaTheme, Themeable } from '../../types'; import { GrafanaTheme, Themeable } from '../../types';
import { PopperContentProps } from '../Tooltip/PopperController'; import { PopperContentProps } from '../Tooltip/PopperController';
import SpectrumPalette from './SpectrumPalette';
export interface Props extends ColorPickerProps, Themeable, PopperContentProps {} export interface Props extends ColorPickerProps, Themeable, PopperContentProps {}
...@@ -24,7 +23,7 @@ export class ColorPickerPopover extends React.Component<Props, State> { ...@@ -24,7 +23,7 @@ export class ColorPickerPopover extends React.Component<Props, State> {
} }
handleSpectrumColorSelect = (color: any) => { handleSpectrumColorSelect = (color: any) => {
this.props.onChange(color.toRgbString()); this.props.onChange(color);
}; };
renderPicker = () => { renderPicker = () => {
...@@ -32,7 +31,7 @@ export class ColorPickerPopover extends React.Component<Props, State> { ...@@ -32,7 +31,7 @@ export class ColorPickerPopover extends React.Component<Props, State> {
const { color, onChange, theme } = this.props; const { color, onChange, theme } = this.props;
return activePicker === 'spectrum' ? ( return activePicker === 'spectrum' ? (
<SpectrumPalette color={color} onColorSelect={this.handleSpectrumColorSelect} options={{}} /> <SpectrumPalette color={color} onChange={this.handleSpectrumColorSelect} />
) : ( ) : (
<NamedColorsPicker color={getColorName(color)} onChange={onChange} theme={theme} /> <NamedColorsPicker color={getColorName(color)} onChange={onChange} theme={theme} />
); );
......
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>
);
});
import React from 'react'; import React from 'react';
import _ from 'lodash'; import { CustomPicker, ColorResult } from 'react-color';
import $ from 'jquery';
import '../../vendor/spectrum';
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; color: string;
options: object; onChange: (color: string) => void;
onColorSelect: (color: string) => void;
} }
export class SpectrumPalette extends React.Component<Props, any> { // @ts-ignore
elem: any; const SpectrumPicker = CustomPicker(({ rgb, hsl, onChange, renderers }) => {
isMoving: boolean; return (
<div
constructor(props: Props) { style={{
super(props); display: 'flex',
this.onSpectrumMove = this.onSpectrumMove.bind(this); width: '100%',
this.setComponentElem = this.setComponentElem.bind(this); flexDirection: 'column',
} }}
>
setComponentElem(elem: any) { <div
this.elem = $(elem); style={{
} display: 'flex',
}}
onSpectrumMove(color: any) { >
this.isMoving = true; <div
this.props.onColorSelect(color); 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() { <div
const spectrumOptions = _.assignIn( style={{
{ position: 'relative',
flat: true, width: '16px',
showAlpha: true, height: '100px',
showButtons: false, marginLeft: '16px',
color: this.props.color, }}
appendTo: this.elem, >
move: this.onSpectrumMove, {/*
}, // @ts-ignore */}
this.props.options <Hue onChange={onChange} hsl={hsl} direction="vertical" />
); </div>
</div>
</div>
);
});
this.elem.spectrum(spectrumOptions); const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color, onChange }) => {
this.elem.spectrum('show'); return (
this.elem.spectrum('set', this.props.color); <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) { export default SpectrumPalette;
// 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} />;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment