mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Implemented new spectrum palette
This commit is contained in:
parent
ba4b774c96
commit
9fd9bba1f4
@ -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;
|
@ -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
|
||||
|
@ -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} />
|
||||
);
|
||||
|
@ -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>
|
||||
);
|
||||
});
|
@ -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;
|
||||
// @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>
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.onSpectrumMove = this.onSpectrumMove.bind(this);
|
||||
this.setComponentElem = this.setComponentElem.bind(this);
|
||||
}
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '16px',
|
||||
height: '100px',
|
||||
marginLeft: '16px',
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
// @ts-ignore */}
|
||||
<Hue onChange={onChange} hsl={hsl} direction="vertical" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
setComponentElem(elem: any) {
|
||||
this.elem = $(elem);
|
||||
}
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
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 <div className="spectrum-container" ref={this.setComponentElem} />;
|
||||
}
|
||||
}
|
||||
export default SpectrumPalette;
|
||||
|
Loading…
Reference in New Issue
Block a user