Grafana-UI: replace react-color with react-colorful (#33267)

* Grafana-UI: replace react-color with react-colorful

* Throttle onChange from SpectrumPalette
This commit is contained in:
Giordano Ricci
2021-04-23 15:03:48 +01:00
committed by GitHub
parent d76c056656
commit ec1c85acca
6 changed files with 97 additions and 218 deletions

View File

@@ -66,7 +66,7 @@
"react": "17.0.1",
"react-beautiful-dnd": "13.0.0",
"react-calendar": "2.19.2",
"react-color": "2.18.0",
"react-colorful": "5.1.2",
"react-custom-scrollbars": "4.2.1",
"react-dom": "17.0.1",
"react-highlight-words": "0.16.0",

View File

@@ -3,7 +3,10 @@ import tinycolor from 'tinycolor2';
import { debounce } from 'lodash';
import { ColorPickerProps } from './ColorPickerPopover';
import { Input } from '../Forms/Legacy/Input/Input';
import { Input } from '../Input/Input';
import { useStyles } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { cx, css } from '@emotion/css';
interface ColorInputState {
previousColor: string;
@@ -12,6 +15,7 @@ interface ColorInputState {
interface ColorInputProps extends ColorPickerProps {
style?: React.CSSProperties;
className?: string;
}
class ColorInput extends React.PureComponent<ColorInputProps, ColorInputState> {
@@ -66,31 +70,41 @@ class ColorInput extends React.PureComponent<ColorInputProps, ColorInputState> {
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.onChange} onBlur={this.onBlur} />
</div>
</div>
<Input
className={this.props.className}
value={value}
onChange={this.onChange}
onBlur={this.onBlur}
addonBefore={<ColorPreview color={this.props.color} />}
/>
);
}
}
export default ColorInput;
interface ColorPreviewProps {
color: string;
}
const ColorPreview = ({ color }: ColorPreviewProps) => {
const styles = useStyles(getColorPreviewStyles);
return (
<div
className={cx(
styles,
css`
background-color: ${color};
`
)}
/>
);
};
const getColorPreviewStyles = (theme: GrafanaTheme) => css`
height: 100%;
width: ${theme.spacing.formInputHeight}px;
border-radius: ${theme.border.radius.sm} 0 0 ${theme.border.radius.sm};
border: 1px solid ${theme.colors.formInputBorder};
`;

View File

@@ -72,7 +72,7 @@ class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends Reac
switch (activePicker) {
case 'spectrum':
return <SpectrumPalette color={color} onChange={this.handleChange} theme={theme} />;
return <SpectrumPalette color={color} onChange={this.handleChange} />;
case 'palette':
return <NamedColorsPalette color={color} onChange={this.handleChange} theme={theme} />;
default:

View File

@@ -1,101 +1,67 @@
import React from 'react';
import { CustomPicker, ColorResult } from 'react-color';
import React, { useMemo, useState } from 'react';
import { Saturation, Hue, Alpha } from 'react-color/lib/components/common';
import { RgbaStringColorPicker } from 'react-colorful';
import tinycolor from 'tinycolor2';
import ColorInput from './ColorInput';
import { Themeable } from '../../types';
import SpectrumPalettePointer, { SpectrumPalettePointerProps } from './SpectrumPalettePointer';
import { GrafanaTheme, getColorForTheme } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { useStyles, useTheme } from '../../themes';
import { useThrottleFn } from 'react-use';
export interface SpectrumPaletteProps extends Themeable {
export interface SpectrumPaletteProps {
color: string;
onChange: (color: string) => void;
}
// eslint-disable-next-line react/display-name
const renderPointer = (theme: GrafanaTheme) => (props: SpectrumPalettePointerProps) => (
<SpectrumPalettePointer {...props} theme={theme} />
);
const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color, onChange }) => {
const [currentColor, setColor] = useState(color);
useThrottleFn(onChange, 500, [currentColor]);
const theme = useTheme();
const styles = useStyles(getStyles);
const rgbaString = useMemo(() => {
return currentColor.startsWith('rgba')
? currentColor
: tinycolor(getColorForTheme(currentColor, theme)).toRgbString();
}, [currentColor, theme]);
// @ts-ignore
const SpectrumPicker = CustomPicker<Themeable>(({ rgb, hsl, onChange, theme }) => {
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} pointer={renderPointer(theme)} />
</div>
</div>
<>
<RgbaStringColorPicker className={cx(styles.root)} color={rgbaString} onChange={setColor} />
<div
style={{
position: 'relative',
width: '16px',
height: '100px',
marginLeft: '16px',
}}
>
{/*
// @ts-ignore */}
<Hue onChange={onChange} hsl={hsl} direction="vertical" pointer={renderPointer(theme)} />
</div>
</div>
</div>
);
});
const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color, onChange, theme }) => {
return (
<div>
<SpectrumPicker
color={tinycolor(getColorForTheme(color, theme)).toRgb()}
onChange={(a: ColorResult) => {
onChange(tinycolor(a.rgb).toString());
}}
theme={theme}
/>
<ColorInput theme={theme} color={color} onChange={onChange} style={{ marginTop: '16px' }} />
</div>
<ColorInput theme={theme} color={currentColor} onChange={setColor} className={styles.colorInput} />
</>
);
};
const getStyles = (theme: GrafanaTheme) => ({
root: css`
&.react-colorful {
width: auto;
}
.react-colorful {
&__saturation {
border-radius: ${theme.border.radius.sm} ${theme.border.radius.sm} 0 0;
}
&__alpha {
border-radius: 0 0 ${theme.border.radius.sm} ${theme.border.radius.sm};
}
&__alpha,
&__hue {
height: ${theme.spacing.md};
position: relative;
}
&__pointer {
height: ${theme.spacing.md};
width: ${theme.spacing.md};
}
}
`,
colorInput: css`
margin-top: ${theme.spacing.md};
`,
});
export default SpectrumPalette;

View File

@@ -1,77 +0,0 @@
import React from 'react';
import { Themeable } from '../../types';
export interface SpectrumPalettePointerProps extends Themeable {
direction?: string;
}
const SpectrumPalettePointer: React.FunctionComponent<SpectrumPalettePointerProps> = ({ theme, direction }) => {
const styles = {
picker: {
width: '16px',
height: '16px',
transform: direction === 'vertical' ? 'translate(0, -8px)' : 'translate(-8px, 0)',
},
};
const pointerColor = theme.colors.text;
let pointerStyles: React.CSSProperties = {
position: 'absolute',
left: '6px',
width: '0',
height: '0',
borderStyle: 'solid',
background: 'none',
};
let topArrowStyles: React.CSSProperties = {
top: '-7px',
borderWidth: '6px 3px 0px 3px',
borderColor: `${pointerColor} transparent transparent transparent`,
};
let bottomArrowStyles: React.CSSProperties = {
bottom: '-7px',
borderWidth: '0px 3px 6px 3px',
borderColor: ` transparent transparent ${pointerColor} transparent`,
};
if (direction === 'vertical') {
pointerStyles = {
...pointerStyles,
left: 'auto',
};
topArrowStyles = {
borderWidth: '3px 0px 3px 6px',
borderColor: `transparent transparent transparent ${pointerColor}`,
left: '-7px',
top: '7px',
};
bottomArrowStyles = {
borderWidth: '3px 6px 3px 0px',
borderColor: `transparent ${pointerColor} transparent transparent`,
right: '-7px',
top: '7px',
};
}
return (
<div style={styles.picker}>
<div
style={{
...pointerStyles,
...topArrowStyles,
}}
/>
<div
style={{
...pointerStyles,
...bottomArrowStyles,
}}
/>
</div>
);
};
export default SpectrumPalettePointer;