mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ColorPicker: return values as hex strings and update theme (#37173)
* Color: fix alpha calculation < 16/255 and State-timeline threshold alpha * SpectrumPalette: Update to getColorByName * ColorValueEditor: Update to theme2 * SpectrumPalette: Update to theme2 * ColorPickerPopover: Format hex color * SpectrumPalette: Format hex color * SpectrumPalette: Refactor hex color alpha helper * SpectrumPalette: Fix import and update helper * ColorPickerPopover: Fix test to not make lowercase Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
be4b753aa0
commit
3e35021f7e
@ -32,7 +32,7 @@ import { getFrameDisplayName } from './fieldState';
|
||||
import { getTimeField } from '../dataframe/processDataFrame';
|
||||
import { mapInternalLinkToExplore } from '../utils/dataLinks';
|
||||
import { getTemplateProxyForField } from './templateProxies';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { asHexString } from '../themes/colorManipulator';
|
||||
|
||||
interface OverrideProps {
|
||||
match: FieldMatcher;
|
||||
@ -227,8 +227,7 @@ function cachingDisplayProcessor(disp: DisplayProcessor, maxCacheSize = 2500): D
|
||||
// convert to hex6 or hex8 so downstream we can cheaply test for alpha (and set new alpha)
|
||||
// via a simple length check (in colorManipulator) rather using slow parsing via tinycolor
|
||||
if (v.color && v.color[0] !== '#') {
|
||||
let color = tinycolor(v.color);
|
||||
v.color = color.getAlpha() < 1 ? color.toHex8String() : color.toHexString();
|
||||
v.color = asHexString(v.color);
|
||||
}
|
||||
|
||||
cache.set(value, v);
|
||||
|
@ -2,6 +2,8 @@
|
||||
// https://github.com/mui-org/material-ui/blob/1b096070faf102281f8e3c4f9b2bf50acf91f412/packages/material-ui/src/styles/colorManipulator.js#L97
|
||||
// MIT License Copyright (c) 2014 Call-Em-All
|
||||
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
/**
|
||||
* Returns a number whose value is limited to the given range.
|
||||
* @param value The value to be clamped
|
||||
@ -66,6 +68,19 @@ export function rgbToHex(color: string) {
|
||||
return `#${values.map((n: number) => intToHex(n)).join('')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a color to hex6 format if there is no alpha, hex8 if there is.
|
||||
* @param color - Hex, RGB, HSL color
|
||||
* @returns A hex color string, i.e. #ff0000 or #ff0000ff
|
||||
*/
|
||||
export function asHexString(color: string): string {
|
||||
if (color[0] === '#') {
|
||||
return color;
|
||||
}
|
||||
const tColor = tinycolor(color);
|
||||
return tColor.getAlpha() === 1 ? tColor.toHexString() : tColor.toHex8String();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a color from hsl format to rgb format.
|
||||
* @param color - HSL color values
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { ColorPickerPopover } from './ColorPickerPopover';
|
||||
import { ColorSwatch } from './ColorSwatch';
|
||||
import { createTheme, getColorForTheme } from '@grafana/data';
|
||||
import { createTheme } from '@grafana/data';
|
||||
|
||||
describe('ColorPickerPopover', () => {
|
||||
const theme = createTheme();
|
||||
@ -35,7 +35,7 @@ describe('ColorPickerPopover', () => {
|
||||
basicBlueSwatch.simulate('click');
|
||||
|
||||
expect(onChangeSpy).toBeCalledTimes(1);
|
||||
expect(onChangeSpy).toBeCalledWith(getColorForTheme('green', theme.v1));
|
||||
expect(onChangeSpy).toBeCalledWith(theme.visualization.getColorByName('green'));
|
||||
});
|
||||
|
||||
it('should pass color name to onChange prop when named colors enabled', () => {
|
||||
|
@ -5,7 +5,7 @@ import SpectrumPalette from './SpectrumPalette';
|
||||
import { Themeable2 } from '../../types/theme';
|
||||
import { warnAboutColorPickerPropsDeprecation } from './warnAboutColorPickerPropsDeprecation';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaTheme2, colorManipulator } from '@grafana/data';
|
||||
import { stylesFactory, withTheme2 } from '../../themes';
|
||||
|
||||
export type ColorPickerChangeHandler = (color: string) => void;
|
||||
@ -55,11 +55,10 @@ class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends Reac
|
||||
handleChange = (color: any) => {
|
||||
const { onColorChange, onChange, enableNamedColors, theme } = this.props;
|
||||
const changeHandler = onColorChange || onChange;
|
||||
|
||||
if (enableNamedColors) {
|
||||
return changeHandler(color);
|
||||
}
|
||||
changeHandler(theme.visualization.getColorByName(color));
|
||||
changeHandler(colorManipulator.asHexString(theme.visualization.getColorByName(color)));
|
||||
};
|
||||
|
||||
onTabChange = (tab: PickerType | keyof T) => {
|
||||
|
@ -3,9 +3,9 @@ import React, { useMemo, useState } from 'react';
|
||||
import { RgbaStringColorPicker } from 'react-colorful';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import ColorInput from './ColorInput';
|
||||
import { GrafanaTheme, getColorForTheme } from '@grafana/data';
|
||||
import { GrafanaTheme2, colorManipulator } from '@grafana/data';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useStyles, useTheme2 } from '../../themes';
|
||||
import { useStyles2, useTheme2 } from '../../themes';
|
||||
import { useThrottleFn } from 'react-use';
|
||||
|
||||
export interface SpectrumPaletteProps {
|
||||
@ -15,16 +15,23 @@ export interface SpectrumPaletteProps {
|
||||
|
||||
const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color, onChange }) => {
|
||||
const [currentColor, setColor] = useState(color);
|
||||
useThrottleFn(onChange, 500, [currentColor]);
|
||||
|
||||
useThrottleFn(
|
||||
(c) => {
|
||||
onChange(colorManipulator.asHexString(theme.visualization.getColorByName(c)));
|
||||
},
|
||||
500,
|
||||
[currentColor]
|
||||
);
|
||||
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles(getStyles);
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const rgbaString = useMemo(() => {
|
||||
return currentColor.startsWith('rgba')
|
||||
? currentColor
|
||||
: tinycolor(getColorForTheme(currentColor, theme.v1)).toRgbString();
|
||||
}, [currentColor, theme]);
|
||||
: tinycolor(theme.visualization.getColorByName(color)).toRgbString();
|
||||
}, [currentColor, theme, color]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
@ -34,7 +41,7 @@ const SpectrumPalette: React.FunctionComponent<SpectrumPaletteProps> = ({ color,
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
wrapper: css`
|
||||
flex-grow: 1;
|
||||
`,
|
||||
@ -45,24 +52,24 @@ const getStyles = (theme: GrafanaTheme) => ({
|
||||
|
||||
.react-colorful {
|
||||
&__saturation {
|
||||
border-radius: ${theme.border.radius.sm} ${theme.border.radius.sm} 0 0;
|
||||
border-radius: ${theme.v1.border.radius.sm} ${theme.v1.border.radius.sm} 0 0;
|
||||
}
|
||||
&__alpha {
|
||||
border-radius: 0 0 ${theme.border.radius.sm} ${theme.border.radius.sm};
|
||||
border-radius: 0 0 ${theme.v1.border.radius.sm} ${theme.v1.border.radius.sm};
|
||||
}
|
||||
&__alpha,
|
||||
&__hue {
|
||||
height: ${theme.spacing.md};
|
||||
height: ${theme.spacing(2)};
|
||||
position: relative;
|
||||
}
|
||||
&__pointer {
|
||||
height: ${theme.spacing.md};
|
||||
width: ${theme.spacing.md};
|
||||
height: ${theme.spacing(2)};
|
||||
width: ${theme.spacing(2)};
|
||||
}
|
||||
}
|
||||
`,
|
||||
colorInput: css`
|
||||
margin-top: ${theme.spacing.md};
|
||||
margin-top: ${theme.spacing(2)};
|
||||
`,
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { getColorForTheme, GrafanaTheme } from '@grafana/data';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { ColorPicker } from '../ColorPicker/ColorPicker';
|
||||
import { stylesFactory, useTheme } from '../../themes';
|
||||
import { useTheme2, useStyles2 } from '../../themes';
|
||||
import { css } from '@emotion/css';
|
||||
import { ColorSwatch } from '../ColorPicker/ColorSwatch';
|
||||
|
||||
@ -17,8 +17,8 @@ export interface ColorValueEditorProps {
|
||||
* @alpha
|
||||
* */
|
||||
export const ColorValueEditor: React.FC<ColorValueEditorProps> = ({ value, onChange }) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme);
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<ColorPicker color={value ?? ''} onChange={onChange} enableNamedColors={true}>
|
||||
@ -30,7 +30,7 @@ export const ColorValueEditor: React.FC<ColorValueEditorProps> = ({ value, onCha
|
||||
ref={ref}
|
||||
onClick={showColorPicker}
|
||||
onMouseLeave={hideColorPicker}
|
||||
color={value ? getColorForTheme(value, theme) : theme.colors.formInputBorder}
|
||||
color={value ? theme.visualization.getColorByName(value) : theme.components.input.borderColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -40,23 +40,23 @@ export const ColorValueEditor: React.FC<ColorValueEditorProps> = ({ value, onCha
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
spot: css`
|
||||
color: ${theme.colors.text};
|
||||
background: ${theme.colors.formInputBg};
|
||||
background: ${theme.components.input.background};
|
||||
padding: 3px;
|
||||
height: ${theme.spacing.formInputHeight}px;
|
||||
border: 1px solid ${theme.colors.formInputBorder};
|
||||
height: ${theme.v1.spacing.formInputHeight}px;
|
||||
border: 1px solid ${theme.components.input.borderColor};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
border: 1px solid ${theme.colors.formInputBorderHover};
|
||||
border: 1px solid ${theme.components.input.borderHover};
|
||||
}
|
||||
`,
|
||||
colorPicker: css`
|
||||
padding: 0 ${theme.spacing.sm};
|
||||
padding: 0 ${theme.spacing(1)};
|
||||
`,
|
||||
colorText: css`
|
||||
cursor: pointer;
|
||||
@ -64,10 +64,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
`,
|
||||
trashIcon: css`
|
||||
cursor: pointer;
|
||||
color: ${theme.colors.textWeak};
|
||||
color: ${theme.colors.text.secondary};
|
||||
&:hover {
|
||||
color: ${theme.colors.text};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user