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>(
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
......
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} />
);
......
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 _ 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;
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