mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Theme: New visualization colors model (#33973)
* Initial design for new viz colors * added unit tests * Progress * Updated selected color * Use old named color names and colors to begin with * Updates * Fixing tests * Progress * Updates * updating * fixing tests * Using some named colors * renames && fixes * remove plural * fixed tests
This commit is contained in:
@@ -11,7 +11,6 @@ import { KeyValue, TimeZone } from '../types';
|
||||
import { getScaleCalculator, ScaleCalculator } from './scale';
|
||||
import { GrafanaTheme2 } from '../themes/types';
|
||||
import { anyToNumber } from '../utils/anyToNumber';
|
||||
import { classicColors, getColorForTheme } from '../utils/namedColorsPalette';
|
||||
|
||||
interface DisplayProcessorOptions {
|
||||
field: Partial<Field>;
|
||||
@@ -82,7 +81,7 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP
|
||||
}
|
||||
|
||||
if (mappingResult.color != null) {
|
||||
color = getColorForTheme(mappingResult.color, options.theme.v1);
|
||||
color = options.theme.visualization.getColorByName(mappingResult.color);
|
||||
}
|
||||
|
||||
shouldFormat = false;
|
||||
@@ -143,7 +142,7 @@ function getDefaultColorFunc(field: Field, scaleFunc: ScaleCalculator, theme: Gr
|
||||
|
||||
const hc = strHashCode(value as string);
|
||||
return {
|
||||
color: classicColors[Math.floor(hc % classicColors.length)],
|
||||
color: theme.visualization.palette[Math.floor(hc % theme.visualization.palette.length)],
|
||||
percent: 0,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,12 +37,12 @@ describe('fieldColorModeRegistry', () => {
|
||||
|
||||
it('Palette classic with series index 0', () => {
|
||||
const calcFn = getCalculator({ mode: FieldColorModeId.PaletteClassic, seriesIndex: 0 });
|
||||
expect(calcFn(70, 0, undefined)).toEqual('#7EB26D');
|
||||
expect(calcFn(70, 0, undefined)).toEqual('#73BF69');
|
||||
});
|
||||
|
||||
it('Palette classic with series index 1', () => {
|
||||
const calcFn = getCalculator({ mode: FieldColorModeId.PaletteClassic, seriesIndex: 1 });
|
||||
expect(calcFn(70, 0, undefined)).toEqual('#EAB839');
|
||||
expect(calcFn(70, 0, undefined)).toEqual('#F2CC0C');
|
||||
});
|
||||
|
||||
it('When color.seriesBy is set to last use that instead of v', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FALLBACK_COLOR, Field, FieldColorModeId, Threshold } from '../types';
|
||||
import { classicColors, getColorForTheme, RegistryItem } from '../utils';
|
||||
import { RegistryItem } from '../utils';
|
||||
import { Registry } from '../utils/Registry';
|
||||
import { interpolateRgbBasis } from 'd3-interpolate';
|
||||
import { fallBackTreshold } from './thresholds';
|
||||
@@ -13,7 +13,7 @@ export type FieldValueColorCalculator = (value: number, percent: number, Thresho
|
||||
/** @beta */
|
||||
export interface FieldColorMode extends RegistryItem {
|
||||
getCalculator: (field: Field, theme: GrafanaTheme2) => FieldValueColorCalculator;
|
||||
colors?: string[];
|
||||
getColors?: (theme: GrafanaTheme2) => string[];
|
||||
isContinuous?: boolean;
|
||||
isByValue?: boolean;
|
||||
}
|
||||
@@ -35,106 +35,88 @@ export const fieldColorModeRegistry = new Registry<FieldColorMode>(() => {
|
||||
getCalculator: (_field, theme) => {
|
||||
return (_value, _percent, threshold) => {
|
||||
const thresholdSafe = threshold ?? fallBackTreshold;
|
||||
return getColorForTheme(thresholdSafe.color, theme.v1);
|
||||
return theme.visualization.getColorByName(thresholdSafe.color);
|
||||
};
|
||||
},
|
||||
},
|
||||
// new FieldColorSchemeMode({
|
||||
// id: FieldColorModeId.PaletteSaturated,
|
||||
// name: 'Saturated palette',
|
||||
// //description: 'Assigns color based on series or field index',
|
||||
// isContinuous: false,
|
||||
// isByValue: false,
|
||||
// colors: [
|
||||
// 'blue',
|
||||
// 'red',
|
||||
// 'green',
|
||||
// 'orange',
|
||||
// 'purple',
|
||||
// 'orange',
|
||||
// 'dark-blue',
|
||||
// 'dark-red',
|
||||
// 'dark-yellow',
|
||||
// 'dark-purple',
|
||||
// 'dark-orange',
|
||||
// ],
|
||||
// }),
|
||||
new FieldColorSchemeMode({
|
||||
id: FieldColorModeId.PaletteClassic,
|
||||
name: 'Classic palette',
|
||||
isContinuous: false,
|
||||
isByValue: false,
|
||||
colors: classicColors,
|
||||
getColors: (theme: GrafanaTheme2) => {
|
||||
return theme.visualization.palette;
|
||||
},
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-GrYlRd',
|
||||
name: 'Green-Yellow-Red',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['green', 'yellow', 'red'],
|
||||
getColors: (theme: GrafanaTheme2) => ['green', 'yellow', 'red'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-RdYlGr',
|
||||
name: 'Red-Yellow-Green',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['red', 'yellow', 'green'],
|
||||
getColors: (theme: GrafanaTheme2) => ['red', 'yellow', 'green'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-BlYlRd',
|
||||
name: 'Blue-Yellow-Red',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['dark-blue', 'super-light-yellow', 'dark-red'],
|
||||
getColors: (theme: GrafanaTheme2) => ['dark-blue', 'super-light-yellow', 'dark-red'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-YlRd',
|
||||
name: 'Yellow-Red',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['super-light-yellow', 'dark-red'],
|
||||
getColors: (theme: GrafanaTheme2) => ['super-light-yellow', 'dark-red'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-BlPu',
|
||||
name: 'Blue-Purple',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['blue', 'purple'],
|
||||
getColors: (theme: GrafanaTheme2) => ['blue', 'purple'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-YlBl',
|
||||
name: 'Yellow-Blue',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['super-light-yellow', 'dark-blue'],
|
||||
getColors: (theme: GrafanaTheme2) => ['super-light-yellow', 'dark-blue'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-blues',
|
||||
name: 'Blues',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['panel-bg', 'dark-blue'],
|
||||
getColors: (theme: GrafanaTheme2) => ['panel-bg', 'dark-blue'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-reds',
|
||||
name: 'Reds',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['panel-bg', 'dark-red'],
|
||||
getColors: (theme: GrafanaTheme2) => ['panel-bg', 'dark-red'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-greens',
|
||||
name: 'Greens',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['panel-bg', 'dark-green'],
|
||||
getColors: (theme: GrafanaTheme2) => ['panel-bg', 'dark-green'],
|
||||
}),
|
||||
new FieldColorSchemeMode({
|
||||
id: 'continuous-purples',
|
||||
name: 'Purples',
|
||||
isContinuous: true,
|
||||
isByValue: true,
|
||||
colors: ['panel-bg', 'dark-purple'],
|
||||
getColors: (theme: GrafanaTheme2) => ['panel-bg', 'dark-purple'],
|
||||
}),
|
||||
];
|
||||
});
|
||||
@@ -143,7 +125,7 @@ interface FieldColorSchemeModeOptions {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
colors: string[];
|
||||
getColors: (theme: GrafanaTheme2) => string[];
|
||||
isContinuous: boolean;
|
||||
isByValue: boolean;
|
||||
}
|
||||
@@ -152,27 +134,34 @@ export class FieldColorSchemeMode implements FieldColorMode {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
colors: string[];
|
||||
isContinuous: boolean;
|
||||
isByValue: boolean;
|
||||
colorCache?: string[];
|
||||
colorCacheTheme?: GrafanaTheme2;
|
||||
interpolator?: (value: number) => string;
|
||||
getNamedColors?: (theme: GrafanaTheme2) => string[];
|
||||
|
||||
constructor(options: FieldColorSchemeModeOptions) {
|
||||
this.id = options.id;
|
||||
this.name = options.name;
|
||||
this.description = options.description;
|
||||
this.colors = options.colors;
|
||||
this.getNamedColors = options.getColors;
|
||||
this.isContinuous = options.isContinuous;
|
||||
this.isByValue = options.isByValue;
|
||||
}
|
||||
|
||||
private getColors(theme: GrafanaTheme2) {
|
||||
if (this.colorCache) {
|
||||
getColors(theme: GrafanaTheme2): string[] {
|
||||
if (!this.getNamedColors) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this.colorCache && this.colorCacheTheme === theme) {
|
||||
return this.colorCache;
|
||||
}
|
||||
|
||||
this.colorCache = this.colors.map((c) => getColorForTheme(c, theme.v1));
|
||||
this.colorCache = this.getNamedColors(theme).map(theme.visualization.getColorByName);
|
||||
this.colorCacheTheme = theme;
|
||||
|
||||
return this.colorCache;
|
||||
}
|
||||
|
||||
@@ -243,6 +232,6 @@ export function getFieldSeriesColor(field: Field, theme: GrafanaTheme2): ColorSc
|
||||
|
||||
function getFixedColor(field: Field, theme: GrafanaTheme2) {
|
||||
return () => {
|
||||
return getColorForTheme(field.config.color?.fixedColor ?? FALLBACK_COLOR, theme.v1);
|
||||
return theme.visualization.getColorByName(field.config.color?.fixedColor ?? FALLBACK_COLOR);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { isNumber } from 'lodash';
|
||||
import { GrafanaTheme2 } from '../themes/types';
|
||||
import { reduceField, ReducerID } from '../transformations/fieldReducer';
|
||||
import { Field, FieldConfig, FieldType, NumericRange, Threshold } from '../types';
|
||||
import { getColorForTheme } from '../utils';
|
||||
import { getFieldColorModeForField } from './fieldColor';
|
||||
import { getActiveThresholdForValue } from './thresholds';
|
||||
|
||||
@@ -42,21 +41,22 @@ export function getScaleCalculator(field: Field, theme: GrafanaTheme2): ScaleCal
|
||||
|
||||
function getBooleanScaleCalculator(field: Field, theme: GrafanaTheme2): ScaleCalculator {
|
||||
const trueValue: ColorScaleValue = {
|
||||
color: getColorForTheme('green', theme.v1),
|
||||
color: theme.visualization.getColorByName('green'),
|
||||
percent: 1,
|
||||
threshold: (undefined as unknown) as Threshold,
|
||||
};
|
||||
|
||||
const falseValue: ColorScaleValue = {
|
||||
color: getColorForTheme('red', theme.v1),
|
||||
color: theme.visualization.getColorByName('red'),
|
||||
percent: 0,
|
||||
threshold: (undefined as unknown) as Threshold,
|
||||
};
|
||||
|
||||
const mode = getFieldColorModeForField(field);
|
||||
if (mode.isContinuous && mode.colors) {
|
||||
trueValue.color = getColorForTheme(mode.colors[mode.colors.length - 1], theme.v1);
|
||||
falseValue.color = getColorForTheme(mode.colors[0], theme.v1);
|
||||
if (mode.isContinuous && mode.getColors) {
|
||||
const colors = mode.getColors(theme);
|
||||
trueValue.color = colors[colors.length - 1];
|
||||
falseValue.color = colors[0];
|
||||
}
|
||||
|
||||
return (value: number) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { createTypography, ThemeTypographyInput } from './createTypography';
|
||||
import { createV1Theme } from './createV1Theme';
|
||||
import { GrafanaTheme2 } from './types';
|
||||
import { zIndex } from './zIndex';
|
||||
import { createVisualizationColors } from './createVisualizationColors';
|
||||
|
||||
/** @internal */
|
||||
export interface NewThemeOptions {
|
||||
@@ -37,6 +38,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 {
|
||||
const shadows = createShadows(colors);
|
||||
const transitions = createTransitions();
|
||||
const components = createComponents(colors, shadows);
|
||||
const visualization = createVisualizationColors(colors);
|
||||
|
||||
const theme = {
|
||||
name,
|
||||
@@ -50,6 +52,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 {
|
||||
typography,
|
||||
shadows,
|
||||
transitions,
|
||||
visualization,
|
||||
zIndex: {
|
||||
...zIndex,
|
||||
},
|
||||
|
||||
@@ -229,6 +229,7 @@ export function createV1Theme(theme: Omit<GrafanaTheme2, 'v1'>): GrafanaTheme {
|
||||
shadows: {
|
||||
listItem: 'none',
|
||||
},
|
||||
visualization: theme.visualization,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { createColors } from './createColors';
|
||||
import { createVisualizationColors } from './createVisualizationColors';
|
||||
|
||||
describe('createVizColors', () => {
|
||||
const darkThemeColors = createColors({});
|
||||
const vizColors = createVisualizationColors(darkThemeColors);
|
||||
|
||||
it('Can map named colors to real color', () => {
|
||||
expect(vizColors.getColorByName('green')).toBe('#73BF69');
|
||||
});
|
||||
|
||||
it('Can map named colors using old aliases to real color', () => {
|
||||
expect(vizColors.getColorByName('dark-green')).toBe('#37872D');
|
||||
});
|
||||
|
||||
it('Can get color from palette', () => {
|
||||
expect(vizColors.palette[0]).not.toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns color if specified as hex or rgb/a', () => {
|
||||
expect(vizColors.getColorByName('#ff0000')).toBe('#ff0000');
|
||||
expect(vizColors.getColorByName('#ff0000')).toBe('#ff0000');
|
||||
expect(vizColors.getColorByName('#FF0000')).toBe('#FF0000');
|
||||
expect(vizColors.getColorByName('#CCC')).toBe('#CCC');
|
||||
expect(vizColors.getColorByName('rgb(0,0,0)')).toBe('rgb(0,0,0)');
|
||||
expect(vizColors.getColorByName('rgba(0,0,0,1)')).toBe('rgba(0,0,0,1)');
|
||||
});
|
||||
|
||||
it('returns hex for named color that is not a part of named colors palette', () => {
|
||||
expect(vizColors.getColorByName('lime')).toBe('#00ff00');
|
||||
});
|
||||
});
|
||||
521
packages/grafana-data/src/themes/createVisualizationColors.ts
Normal file
521
packages/grafana-data/src/themes/createVisualizationColors.ts
Normal file
@@ -0,0 +1,521 @@
|
||||
import { FALLBACK_COLOR } from '../types';
|
||||
import { ThemeColors } from './createColors';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ThemeVisualizationColors {
|
||||
/** Only for internal use by color schemes */
|
||||
palette: string[];
|
||||
/** Lookup the real color given the name */
|
||||
getColorByName: (color: string) => string;
|
||||
/** Colors organized by hue */
|
||||
hues: ThemeVizHue[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ThemeVizColor {
|
||||
color: string;
|
||||
name: string;
|
||||
aliases?: string[];
|
||||
primary?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ThemeVizHue {
|
||||
name: string;
|
||||
shades: ThemeVizColor[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function createVisualizationColors(colors: ThemeColors): ThemeVisualizationColors {
|
||||
let hues: ThemeVizHue[] = [];
|
||||
|
||||
if (colors.mode === 'dark') {
|
||||
hues = getDarkHues();
|
||||
} else if (colors.mode === 'light') {
|
||||
hues = getLightHues();
|
||||
}
|
||||
|
||||
const byNameIndex: Record<string, string> = {};
|
||||
|
||||
for (const hue of hues) {
|
||||
for (const shade of hue.shades) {
|
||||
byNameIndex[shade.name] = shade.color;
|
||||
if (shade.aliases) {
|
||||
for (const alias of shade.aliases) {
|
||||
byNameIndex[alias] = shade.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special colors
|
||||
byNameIndex['transparent'] = 'rgba(0,0,0,0)';
|
||||
byNameIndex['panel-bg'] = colors.background.primary;
|
||||
byNameIndex['text'] = colors.text.primary;
|
||||
|
||||
const getColorByName = (colorName: string) => {
|
||||
if (!colorName) {
|
||||
return FALLBACK_COLOR;
|
||||
}
|
||||
|
||||
const realColor = byNameIndex[colorName];
|
||||
if (realColor) {
|
||||
return realColor;
|
||||
}
|
||||
|
||||
if (colorName[0] === '#') {
|
||||
return colorName;
|
||||
}
|
||||
|
||||
if (colorName.indexOf('rgb') > -1) {
|
||||
return colorName;
|
||||
}
|
||||
|
||||
const nativeColor = nativeColorNames[colorName.toLowerCase()];
|
||||
if (nativeColor) {
|
||||
byNameIndex[colorName] = nativeColor;
|
||||
return nativeColor;
|
||||
}
|
||||
|
||||
return colorName;
|
||||
};
|
||||
|
||||
const palette = getClassicPalette();
|
||||
|
||||
return {
|
||||
hues,
|
||||
palette,
|
||||
getColorByName,
|
||||
};
|
||||
}
|
||||
|
||||
function getDarkHues(): ThemeVizHue[] {
|
||||
return [
|
||||
{
|
||||
name: 'red',
|
||||
shades: [
|
||||
{ color: '#FFA6B0', name: 'super-light-red' },
|
||||
{ color: '#FF7383', name: 'light-red' },
|
||||
{ color: '#F2495C', name: 'red', primary: true },
|
||||
{ color: '#E02F44', name: 'semi-dark-red' },
|
||||
{ color: '#C4162A', name: 'dark-red' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'orange',
|
||||
shades: [
|
||||
{ color: '#FFCB7D', name: 'super-light-orange', aliases: [] },
|
||||
{ color: '#FFB357', name: 'light-orange', aliases: [] },
|
||||
{ color: '#FF9830', name: 'orange', aliases: [], primary: true },
|
||||
{ color: '#FF780A', name: 'semi-dark-orange', aliases: [] },
|
||||
{ color: '#FA6400', name: 'dark-orange', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'yellow',
|
||||
shades: [
|
||||
{ color: '#FFF899', name: 'super-light-yellow', aliases: [] },
|
||||
{ color: '#FFEE52', name: 'light-yellow', aliases: [] },
|
||||
{ color: '#FADE2A', name: 'yellow', aliases: [], primary: true },
|
||||
{ color: '#F2CC0C', name: 'semi-dark-yellow', aliases: [] },
|
||||
{ color: '#E0B400', name: 'dark-yellow', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'green',
|
||||
shades: [
|
||||
{ color: '#C8F2C2', name: 'super-light-green', aliases: [] },
|
||||
{ color: '#96D98D', name: 'light-green', aliases: [] },
|
||||
{ color: '#73BF69', name: 'green', aliases: [], primary: true },
|
||||
{ color: '#56A64B', name: 'semi-dark-green', aliases: [] },
|
||||
{ color: '#37872D', name: 'dark-green', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blue',
|
||||
shades: [
|
||||
{ color: '#C0D8FF', name: 'super-light-blue', aliases: [] },
|
||||
{ color: '#8AB8FF', name: 'light-blue', aliases: [] },
|
||||
{ color: '#5794F2', name: 'blue', aliases: [], primary: true },
|
||||
{ color: '#3274D9', name: 'semi-dark-blue', aliases: [] },
|
||||
{ color: '#1F60C4', name: 'dark-blue', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'purple',
|
||||
shades: [
|
||||
{ color: '#DEB6F2', name: 'super-light-purple', aliases: [] },
|
||||
{ color: '#CA95E5', name: 'light-purple', aliases: [] },
|
||||
{ color: '#B877D9', name: 'purple', aliases: [], primary: true },
|
||||
{ color: '#A352CC', name: 'semi-dark-purple', aliases: [] },
|
||||
{ color: '#8F3BB8', name: 'dark-purple', aliases: [] },
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function getLightHues(): ThemeVizHue[] {
|
||||
return [
|
||||
{
|
||||
name: 'red',
|
||||
shades: [
|
||||
{ color: '#FF7383', name: 'super-light-red' },
|
||||
{ color: '#F2495C', name: 'light-red' },
|
||||
{ color: '#E02F44', name: 'red', primary: true },
|
||||
{ color: '#C4162A', name: 'semi-dark-red' },
|
||||
{ color: '#AD0317', name: 'dark-red' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'orange',
|
||||
shades: [
|
||||
{ color: '#FFB357', name: 'super-light-orange', aliases: [] },
|
||||
{ color: '#FF9830', name: 'light-orange', aliases: [] },
|
||||
{ color: '#FF780A', name: 'orange', aliases: [], primary: true },
|
||||
{ color: '#FA6400', name: 'semi-dark-orange', aliases: [] },
|
||||
{ color: '#E55400', name: 'dark-orange', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'yellow',
|
||||
shades: [
|
||||
{ color: '#FFEE52', name: 'super-light-yellow', aliases: [] },
|
||||
{ color: '#FADE2A', name: 'light-yellow', aliases: [] },
|
||||
{ color: '#F2CC0C', name: 'yellow', aliases: [], primary: true },
|
||||
{ color: '#E0B400', name: 'semi-dark-yellow', aliases: [] },
|
||||
{ color: '#CC9D00', name: 'dark-yellow', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'green',
|
||||
shades: [
|
||||
{ color: '#96D98D', name: 'super-light-green', aliases: [] },
|
||||
{ color: '#73BF69', name: 'light-green', aliases: [] },
|
||||
{ color: '#56A64B', name: 'green', aliases: [], primary: true },
|
||||
{ color: '#37872D', name: 'semi-dark-green', aliases: [] },
|
||||
{ color: '#19730E', name: 'dark-green', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blue',
|
||||
shades: [
|
||||
{ color: '#8AB8FF', name: 'super-light-blue', aliases: [] },
|
||||
{ color: '#5794F2', name: 'light-blue', aliases: [] },
|
||||
{ color: '#3274D9', name: 'blue', aliases: [], primary: true },
|
||||
{ color: '#1F60C4', name: 'semi-dark-blue', aliases: [] },
|
||||
{ color: '#1250B0', name: 'dark-blue', aliases: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'purple',
|
||||
shades: [
|
||||
{ color: '#CA95E5', name: 'super-light-purple', aliases: [] },
|
||||
{ color: '#B877D9', name: 'light-purple', aliases: [] },
|
||||
{ color: '#A352CC', name: 'purple', aliases: [], primary: true },
|
||||
{ color: '#8F3BB8', name: 'semi-dark-purple', aliases: [] },
|
||||
{ color: '#7C2EA3', name: 'dark-purple', aliases: [] },
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function getClassicPalette() {
|
||||
// Todo replace these with named colors (as many as possible)
|
||||
|
||||
return [
|
||||
'green', // '#7EB26D', // 0: pale green
|
||||
'semi-dark-yellow', // '#EAB839', // 1: mustard
|
||||
'light-blue', // #6ED0E0', // 2: light blue
|
||||
'semi-dark-orange', // '#EF843C', // 3: orange
|
||||
'red', // '#E24D42', // 4: red
|
||||
'blue', // #1F78C1', // 5: ocean
|
||||
'purple', // '#BA43A9', // 6: purple
|
||||
'#705DA0', // 7: violet
|
||||
'dark-green', // '#508642', // 8: dark green
|
||||
'yellow', //'#CCA300', // 9: dark sand
|
||||
'#447EBC',
|
||||
'#C15C17',
|
||||
'#890F02',
|
||||
'#0A437C',
|
||||
'#6D1F62',
|
||||
'#584477',
|
||||
'#B7DBAB',
|
||||
'#F4D598',
|
||||
'#70DBED',
|
||||
'#F9BA8F',
|
||||
'#F29191',
|
||||
'#82B5D8',
|
||||
'#E5A8E2',
|
||||
'#AEA2E0',
|
||||
'#629E51',
|
||||
'#E5AC0E',
|
||||
'#64B0C8',
|
||||
'#E0752D',
|
||||
'#BF1B00',
|
||||
'#0A50A1',
|
||||
'#962D82',
|
||||
'#614D93',
|
||||
'#9AC48A',
|
||||
'#F2C96D',
|
||||
'#65C5DB',
|
||||
'#F9934E',
|
||||
'#EA6460',
|
||||
'#5195CE',
|
||||
'#D683CE',
|
||||
'#806EB7',
|
||||
'#3F6833',
|
||||
'#967302',
|
||||
'#2F575E',
|
||||
'#99440A',
|
||||
'#58140C',
|
||||
'#052B51',
|
||||
'#511749',
|
||||
'#3F2B5B',
|
||||
'#E0F9D7',
|
||||
'#FCEACA',
|
||||
'#CFFAFF',
|
||||
'#F9E2D2',
|
||||
'#FCE2DE',
|
||||
'#BADFF4',
|
||||
'#F9D9F9',
|
||||
'#DEDAF7',
|
||||
];
|
||||
}
|
||||
|
||||
// Old hues
|
||||
// function getDarkHues(): ThemeVizHue[] {
|
||||
// return [
|
||||
// {
|
||||
// name: 'red',
|
||||
// shades: [
|
||||
// { name: 'red1', color: '#FFC2D4', aliases: ['super-light-red'] },
|
||||
// { name: 'red2', color: '#FFA8C2', aliases: ['light-red'] },
|
||||
// { name: 'red3', color: '#FF85A9', aliases: ['red'], primary: true },
|
||||
// { name: 'red4', color: '#FF5286', aliases: ['semi-dark-red'] },
|
||||
// { name: 'red5', color: '#E0226E', aliases: ['dark-red'] },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'orange',
|
||||
// shades: [
|
||||
// { name: 'orange1', color: '#FFC0AD', aliases: ['super-light-orange'] },
|
||||
// { name: 'orange2', color: '#FFA98F', aliases: ['light-orange'] },
|
||||
// { name: 'orange3', color: '#FF825C', aliases: ['orange'], primary: true },
|
||||
// { name: 'orange4', color: '#FF5F2E', aliases: ['semi-dark-orange'] },
|
||||
// { name: 'orange5', color: '#E73903', aliases: ['dark-orange'] },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'yellow',
|
||||
// shades: [
|
||||
// { name: 'yellow1', color: '#FFE68F', aliases: ['super-light-yellow'] },
|
||||
// { name: 'yellow2', color: '#FAD34A', aliases: ['light-yellow'] },
|
||||
// { name: 'yellow3', color: '#ECBB09', aliases: ['yellow'], primary: true },
|
||||
// { name: 'yellow4', color: '#CFA302', aliases: ['semi-dark-yellow'] },
|
||||
// { name: 'yellow5', color: '#AD8800', aliases: ['dark-yellow'] },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'green',
|
||||
// shades: [
|
||||
// { name: 'green1', color: '#93ECCB', aliases: ['super-light-green'] },
|
||||
// { name: 'green2', color: '#65DCB1', aliases: ['light-green'] },
|
||||
// { name: 'green3', color: '#2DC88F', aliases: ['green'], primary: true },
|
||||
// { name: 'green4', color: '#25A777', aliases: ['semi-dark-green'] },
|
||||
// { name: 'green5', color: '#1B855E', aliases: ['dark-green'] },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'teal',
|
||||
// shades: [
|
||||
// { name: 'teal1', color: '#73E7F7' },
|
||||
// { name: 'teal2', color: '#2BD6EE' },
|
||||
// { name: 'teal3', color: '#11BDD4', primary: true },
|
||||
// { name: 'teal4', color: '#0EA0B4' },
|
||||
// { name: 'teal5', color: '#077D8D' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'blue',
|
||||
// shades: [
|
||||
// { name: 'blue1', color: '#C2D7FF', aliases: ['super-light-blue'] },
|
||||
// { name: 'blue2', color: '#A3C2FF', aliases: ['light-blue'] },
|
||||
// { name: 'blue3', color: '#83ACFC', aliases: ['blue'], primary: true },
|
||||
// { name: 'blue4', color: '#5D8FEF', aliases: ['semi-dark-blue'] },
|
||||
// { name: 'blue5', color: '#3871DC', aliases: ['dark-blue'] },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'violet',
|
||||
// shades: [
|
||||
// { name: 'violet1', color: '#DACCFF' },
|
||||
// { name: 'violet2', color: '#C7B2FF' },
|
||||
// { name: 'violet3', color: '#B094FF', primary: true },
|
||||
// { name: 'violet4', color: '#9271EF' },
|
||||
// { name: 'violet5', color: '#7E63CA' },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'purple',
|
||||
// shades: [
|
||||
// { name: 'purple1', color: '#FFBDFF', aliases: ['super-light-purple'] },
|
||||
// { name: 'purple2', color: '#F5A3F5', aliases: ['light-purple'] },
|
||||
// { name: 'purple3', color: '#E48BE4', aliases: ['purple'], primary: true },
|
||||
// { name: 'purple4', color: '#CA68CA', aliases: ['semi-dark-purple'] },
|
||||
// { name: 'purple5', color: '#B545B5', aliases: ['dark-purple'] },
|
||||
// ],
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
|
||||
const nativeColorNames: Record<string, string> = {
|
||||
aliceblue: '#f0f8ff',
|
||||
antiquewhite: '#faebd7',
|
||||
aqua: '#00ffff',
|
||||
aquamarine: '#7fffd4',
|
||||
azure: '#f0ffff',
|
||||
beige: '#f5f5dc',
|
||||
bisque: '#ffe4c4',
|
||||
black: '#000000',
|
||||
blanchedalmond: '#ffebcd',
|
||||
blue: '#0000ff',
|
||||
blueviolet: '#8a2be2',
|
||||
brown: '#a52a2a',
|
||||
burlywood: '#deb887',
|
||||
cadetblue: '#5f9ea0',
|
||||
chartreuse: '#7fff00',
|
||||
chocolate: '#d2691e',
|
||||
coral: '#ff7f50',
|
||||
cornflowerblue: '#6495ed',
|
||||
cornsilk: '#fff8dc',
|
||||
crimson: '#dc143c',
|
||||
cyan: '#00ffff',
|
||||
darkblue: '#00008b',
|
||||
darkcyan: '#008b8b',
|
||||
darkgoldenrod: '#b8860b',
|
||||
darkgray: '#a9a9a9',
|
||||
darkgreen: '#006400',
|
||||
darkkhaki: '#bdb76b',
|
||||
darkmagenta: '#8b008b',
|
||||
darkolivegreen: '#556b2f',
|
||||
darkorange: '#ff8c00',
|
||||
darkorchid: '#9932cc',
|
||||
darkred: '#8b0000',
|
||||
darksalmon: '#e9967a',
|
||||
darkseagreen: '#8fbc8f',
|
||||
darkslateblue: '#483d8b',
|
||||
darkslategray: '#2f4f4f',
|
||||
darkturquoise: '#00ced1',
|
||||
darkviolet: '#9400d3',
|
||||
deeppink: '#ff1493',
|
||||
deepskyblue: '#00bfff',
|
||||
dimgray: '#696969',
|
||||
dodgerblue: '#1e90ff',
|
||||
firebrick: '#b22222',
|
||||
floralwhite: '#fffaf0',
|
||||
forestgreen: '#228b22',
|
||||
fuchsia: '#ff00ff',
|
||||
gainsboro: '#dcdcdc',
|
||||
ghostwhite: '#f8f8ff',
|
||||
gold: '#ffd700',
|
||||
goldenrod: '#daa520',
|
||||
gray: '#808080',
|
||||
green: '#008000',
|
||||
greenyellow: '#adff2f',
|
||||
honeydew: '#f0fff0',
|
||||
hotpink: '#ff69b4',
|
||||
'indianred ': '#cd5c5c',
|
||||
indigo: '#4b0082',
|
||||
ivory: '#fffff0',
|
||||
khaki: '#f0e68c',
|
||||
lavender: '#e6e6fa',
|
||||
lavenderblush: '#fff0f5',
|
||||
lawngreen: '#7cfc00',
|
||||
lemonchiffon: '#fffacd',
|
||||
lightblue: '#add8e6',
|
||||
lightcoral: '#f08080',
|
||||
lightcyan: '#e0ffff',
|
||||
lightgoldenrodyellow: '#fafad2',
|
||||
lightgrey: '#d3d3d3',
|
||||
lightgreen: '#90ee90',
|
||||
lightpink: '#ffb6c1',
|
||||
lightsalmon: '#ffa07a',
|
||||
lightseagreen: '#20b2aa',
|
||||
lightskyblue: '#87cefa',
|
||||
lightslategray: '#778899',
|
||||
lightsteelblue: '#b0c4de',
|
||||
lightyellow: '#ffffe0',
|
||||
lime: '#00ff00',
|
||||
limegreen: '#32cd32',
|
||||
linen: '#faf0e6',
|
||||
magenta: '#ff00ff',
|
||||
maroon: '#800000',
|
||||
mediumaquamarine: '#66cdaa',
|
||||
mediumblue: '#0000cd',
|
||||
mediumorchid: '#ba55d3',
|
||||
mediumpurple: '#9370d8',
|
||||
mediumseagreen: '#3cb371',
|
||||
mediumslateblue: '#7b68ee',
|
||||
mediumspringgreen: '#00fa9a',
|
||||
mediumturquoise: '#48d1cc',
|
||||
mediumvioletred: '#c71585',
|
||||
midnightblue: '#191970',
|
||||
mintcream: '#f5fffa',
|
||||
mistyrose: '#ffe4e1',
|
||||
moccasin: '#ffe4b5',
|
||||
navajowhite: '#ffdead',
|
||||
navy: '#000080',
|
||||
oldlace: '#fdf5e6',
|
||||
olive: '#808000',
|
||||
olivedrab: '#6b8e23',
|
||||
orange: '#ffa500',
|
||||
orangered: '#ff4500',
|
||||
orchid: '#da70d6',
|
||||
palegoldenrod: '#eee8aa',
|
||||
palegreen: '#98fb98',
|
||||
paleturquoise: '#afeeee',
|
||||
palevioletred: '#d87093',
|
||||
papayawhip: '#ffefd5',
|
||||
peachpuff: '#ffdab9',
|
||||
peru: '#cd853f',
|
||||
pink: '#ffc0cb',
|
||||
plum: '#dda0dd',
|
||||
powderblue: '#b0e0e6',
|
||||
purple: '#800080',
|
||||
rebeccapurple: '#663399',
|
||||
red: '#ff0000',
|
||||
rosybrown: '#bc8f8f',
|
||||
royalblue: '#4169e1',
|
||||
saddlebrown: '#8b4513',
|
||||
salmon: '#fa8072',
|
||||
sandybrown: '#f4a460',
|
||||
seagreen: '#2e8b57',
|
||||
seashell: '#fff5ee',
|
||||
sienna: '#a0522d',
|
||||
silver: '#c0c0c0',
|
||||
skyblue: '#87ceeb',
|
||||
slateblue: '#6a5acd',
|
||||
slategray: '#708090',
|
||||
snow: '#fffafa',
|
||||
springgreen: '#00ff7f',
|
||||
steelblue: '#4682b4',
|
||||
tan: '#d2b48c',
|
||||
teal: '#008080',
|
||||
thistle: '#d8bfd8',
|
||||
tomato: '#ff6347',
|
||||
turquoise: '#40e0d0',
|
||||
violet: '#ee82ee',
|
||||
wheat: '#f5deb3',
|
||||
white: '#ffffff',
|
||||
whitesmoke: '#f5f5f5',
|
||||
yellow: '#ffff00',
|
||||
yellowgreen: '#9acd32',
|
||||
};
|
||||
@@ -8,7 +8,7 @@ export { ThemeTypography, ThemeTypographyVariant } from './createTypography';
|
||||
export { ThemeTransitions } from './createTransitions';
|
||||
export { ThemeSpacing } from './createSpacing';
|
||||
export { ThemeZIndices } from './zIndex';
|
||||
export { palette } from './palette';
|
||||
export { ThemeVisualizationColors, ThemeVizColor, ThemeVizHue } from './createVisualizationColors';
|
||||
|
||||
/** Exporting the module like this to be able to generate docs properly. */
|
||||
import * as colorManipulator from './colorManipulator';
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ThemeSpacing } from './createSpacing';
|
||||
import { ThemeTransitions } from './createTransitions';
|
||||
import { ThemeTypography } from './createTypography';
|
||||
import { ThemeZIndices } from './zIndex';
|
||||
import { ThemeVisualizationColors } from './createVisualizationColors';
|
||||
|
||||
/**
|
||||
* @beta
|
||||
@@ -25,6 +26,7 @@ export interface GrafanaTheme2 {
|
||||
typography: ThemeTypography;
|
||||
zIndex: ThemeZIndices;
|
||||
shadows: ThemeShadows;
|
||||
visualization: ThemeVisualizationColors;
|
||||
transitions: ThemeTransitions;
|
||||
v1: GrafanaTheme;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ThemeVisualizationColors } from '../themes';
|
||||
|
||||
export enum GrafanaThemeType {
|
||||
Light = 'light',
|
||||
Dark = 'dark',
|
||||
@@ -238,4 +240,5 @@ export interface GrafanaTheme extends GrafanaThemeCommons {
|
||||
shadows: {
|
||||
listItem: string;
|
||||
};
|
||||
visualization: ThemeVisualizationColors;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,16 @@
|
||||
import { getColorFromHexRgbOrName, getColorDefinitionByName } from './namedColorsPalette';
|
||||
import { GrafanaThemeType } from '../types/theme';
|
||||
import { getColorForTheme } from './namedColorsPalette';
|
||||
import { createTheme } from '../themes';
|
||||
|
||||
describe('colors', () => {
|
||||
const SemiDarkBlue = getColorDefinitionByName('semi-dark-blue');
|
||||
const theme = createTheme();
|
||||
|
||||
describe('getColorFromHexRgbOrName', () => {
|
||||
it('returns black for unknown color', () => {
|
||||
expect(getColorFromHexRgbOrName('aruba-sunshine')).toBe('#000000');
|
||||
expect(getColorForTheme('aruba-sunshine', theme.v1)).toBe('aruba-sunshine');
|
||||
});
|
||||
|
||||
it('returns dark hex variant for known color if theme not specified', () => {
|
||||
expect(getColorFromHexRgbOrName(SemiDarkBlue.name)).toBe(SemiDarkBlue.variants.dark);
|
||||
});
|
||||
|
||||
it("returns correct variant's hex for known color if theme specified", () => {
|
||||
expect(getColorFromHexRgbOrName(SemiDarkBlue.name, GrafanaThemeType.Light)).toBe(SemiDarkBlue.variants.light);
|
||||
});
|
||||
|
||||
it('returns color if specified as hex or rgb/a', () => {
|
||||
expect(getColorFromHexRgbOrName('ff0000')).toBe('#ff0000');
|
||||
expect(getColorFromHexRgbOrName('#ff0000')).toBe('#ff0000');
|
||||
expect(getColorFromHexRgbOrName('#FF0000')).toBe('#FF0000');
|
||||
expect(getColorFromHexRgbOrName('#CCC')).toBe('#CCC');
|
||||
expect(getColorFromHexRgbOrName('rgb(0,0,0)')).toBe('rgb(0,0,0)');
|
||||
expect(getColorFromHexRgbOrName('rgba(0,0,0,1)')).toBe('rgba(0,0,0,1)');
|
||||
});
|
||||
|
||||
it('returns hex for named color that is not a part of named colors palette', () => {
|
||||
expect(getColorFromHexRgbOrName('lime')).toBe('#00ff00');
|
||||
expect(getColorForTheme('semi-dark-blue', theme.v1)).toBe('#3274D9');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,216 +1,19 @@
|
||||
import { flatten } from 'lodash';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { GrafanaTheme, GrafanaThemeType } from '../types/theme';
|
||||
|
||||
type Hue = 'green' | 'yellow' | 'red' | 'blue' | 'orange' | 'purple';
|
||||
|
||||
export type Color =
|
||||
| 'green'
|
||||
| 'dark-green'
|
||||
| 'semi-dark-green'
|
||||
| 'light-green'
|
||||
| 'super-light-green'
|
||||
| 'yellow'
|
||||
| 'dark-yellow'
|
||||
| 'semi-dark-yellow'
|
||||
| 'light-yellow'
|
||||
| 'super-light-yellow'
|
||||
| 'red'
|
||||
| 'dark-red'
|
||||
| 'semi-dark-red'
|
||||
| 'light-red'
|
||||
| 'super-light-red'
|
||||
| 'blue'
|
||||
| 'dark-blue'
|
||||
| 'semi-dark-blue'
|
||||
| 'light-blue'
|
||||
| 'super-light-blue'
|
||||
| 'orange'
|
||||
| 'dark-orange'
|
||||
| 'semi-dark-orange'
|
||||
| 'light-orange'
|
||||
| 'super-light-orange'
|
||||
| 'purple'
|
||||
| 'dark-purple'
|
||||
| 'semi-dark-purple'
|
||||
| 'light-purple'
|
||||
| 'super-light-purple'
|
||||
| 'panel-bg'
|
||||
| 'transparent'
|
||||
| 'text';
|
||||
|
||||
type ThemeVariants = {
|
||||
dark: string;
|
||||
light: string;
|
||||
};
|
||||
|
||||
export type ColorDefinition = {
|
||||
hue: Hue;
|
||||
isPrimary?: boolean;
|
||||
name: Color;
|
||||
variants: ThemeVariants;
|
||||
};
|
||||
|
||||
let colorsPaletteInstance: Map<Hue, ColorDefinition[]>;
|
||||
let colorsMap: Record<Color, string> | undefined;
|
||||
let colorsMapTheme: GrafanaTheme | undefined;
|
||||
|
||||
const buildColorDefinition = (
|
||||
hue: Hue,
|
||||
name: Color,
|
||||
[light, dark]: string[],
|
||||
isPrimary?: boolean
|
||||
): ColorDefinition => ({
|
||||
hue,
|
||||
name,
|
||||
variants: {
|
||||
light,
|
||||
dark,
|
||||
},
|
||||
isPrimary: !!isPrimary,
|
||||
});
|
||||
|
||||
export function getColorDefinitionByName(name: Color): ColorDefinition {
|
||||
return flatten(Array.from(getNamedColorPalette().values())).filter((definition) => definition.name === name)[0];
|
||||
}
|
||||
|
||||
export function buildColorsMapForTheme(theme: GrafanaTheme): Record<Color, string> {
|
||||
theme = theme ?? GrafanaThemeType.Dark;
|
||||
|
||||
colorsMap = {} as Record<Color, string>;
|
||||
|
||||
for (const def of getNamedColorPalette().values()) {
|
||||
for (const c of def) {
|
||||
colorsMap[c.name] = c.variants[theme.type];
|
||||
}
|
||||
}
|
||||
|
||||
colorsMap['panel-bg'] = theme.colors.panelBg;
|
||||
colorsMap['transparent'] = 'rgba(0,0,0,0)';
|
||||
colorsMap['text'] = theme.colors.text;
|
||||
|
||||
return colorsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use theme.vizColors.getByName
|
||||
*/
|
||||
export function getColorForTheme(color: string, theme: GrafanaTheme): string {
|
||||
if (!color) {
|
||||
return 'gray';
|
||||
}
|
||||
|
||||
// check if we need to rebuild cache
|
||||
if (!colorsMap || colorsMapTheme !== theme) {
|
||||
colorsMap = buildColorsMapForTheme(theme);
|
||||
colorsMapTheme = theme;
|
||||
}
|
||||
|
||||
let realColor = colorsMap[color as Color];
|
||||
if (realColor) {
|
||||
return realColor;
|
||||
}
|
||||
|
||||
if (color[0] === '#') {
|
||||
return (colorsMap[color as Color] = color);
|
||||
}
|
||||
|
||||
if (color.indexOf('rgb') > -1) {
|
||||
return (colorsMap[color as Color] = color);
|
||||
}
|
||||
|
||||
return (colorsMap[color as Color] = tinycolor(color).toHexString());
|
||||
return theme.visualization.getColorByName(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getColorForTheme
|
||||
*/
|
||||
export function getColorFromHexRgbOrName(color: string, type?: GrafanaThemeType): string {
|
||||
const themeType = type ?? GrafanaThemeType.Dark;
|
||||
|
||||
if (themeType === GrafanaThemeType.Dark) {
|
||||
const darkTheme = ({
|
||||
type: themeType,
|
||||
colors: {
|
||||
panelBg: '#141619',
|
||||
},
|
||||
} as unknown) as GrafanaTheme;
|
||||
|
||||
return getColorForTheme(color, darkTheme);
|
||||
}
|
||||
|
||||
const lightTheme = ({
|
||||
type: themeType,
|
||||
colors: {
|
||||
panelBg: '#000000',
|
||||
},
|
||||
} as unknown) as GrafanaTheme;
|
||||
|
||||
return getColorForTheme(color, lightTheme);
|
||||
return 'gray';
|
||||
}
|
||||
|
||||
const buildNamedColorsPalette = () => {
|
||||
const palette = new Map<Hue, ColorDefinition[]>();
|
||||
|
||||
const BasicGreen = buildColorDefinition('green', 'green', ['#56A64B', '#73BF69'], true);
|
||||
const DarkGreen = buildColorDefinition('green', 'dark-green', ['#19730E', '#37872D']);
|
||||
const SemiDarkGreen = buildColorDefinition('green', 'semi-dark-green', ['#37872D', '#56A64B']);
|
||||
const LightGreen = buildColorDefinition('green', 'light-green', ['#73BF69', '#96D98D']);
|
||||
const SuperLightGreen = buildColorDefinition('green', 'super-light-green', ['#96D98D', '#C8F2C2']);
|
||||
|
||||
const BasicYellow = buildColorDefinition('yellow', 'yellow', ['#F2CC0C', '#FADE2A'], true);
|
||||
const DarkYellow = buildColorDefinition('yellow', 'dark-yellow', ['#CC9D00', '#E0B400']);
|
||||
const SemiDarkYellow = buildColorDefinition('yellow', 'semi-dark-yellow', ['#E0B400', '#F2CC0C']);
|
||||
const LightYellow = buildColorDefinition('yellow', 'light-yellow', ['#FADE2A', '#FFEE52']);
|
||||
const SuperLightYellow = buildColorDefinition('yellow', 'super-light-yellow', ['#FFEE52', '#FFF899']);
|
||||
|
||||
const BasicRed = buildColorDefinition('red', 'red', ['#E02F44', '#F2495C'], true);
|
||||
const DarkRed = buildColorDefinition('red', 'dark-red', ['#AD0317', '#C4162A']);
|
||||
const SemiDarkRed = buildColorDefinition('red', 'semi-dark-red', ['#C4162A', '#E02F44']);
|
||||
const LightRed = buildColorDefinition('red', 'light-red', ['#F2495C', '#FF7383']);
|
||||
const SuperLightRed = buildColorDefinition('red', 'super-light-red', ['#FF7383', '#FFA6B0']);
|
||||
|
||||
const BasicBlue = buildColorDefinition('blue', 'blue', ['#3274D9', '#5794F2'], true);
|
||||
const DarkBlue = buildColorDefinition('blue', 'dark-blue', ['#1250B0', '#1F60C4']);
|
||||
const SemiDarkBlue = buildColorDefinition('blue', 'semi-dark-blue', ['#1F60C4', '#3274D9']);
|
||||
const LightBlue = buildColorDefinition('blue', 'light-blue', ['#5794F2', '#8AB8FF']);
|
||||
const SuperLightBlue = buildColorDefinition('blue', 'super-light-blue', ['#8AB8FF', '#C0D8FF']);
|
||||
|
||||
const BasicOrange = buildColorDefinition('orange', 'orange', ['#FF780A', '#FF9830'], true);
|
||||
const DarkOrange = buildColorDefinition('orange', 'dark-orange', ['#E55400', '#FA6400']);
|
||||
const SemiDarkOrange = buildColorDefinition('orange', 'semi-dark-orange', ['#FA6400', '#FF780A']);
|
||||
const LightOrange = buildColorDefinition('orange', 'light-orange', ['#FF9830', '#FFB357']);
|
||||
const SuperLightOrange = buildColorDefinition('orange', 'super-light-orange', ['#FFB357', '#FFCB7D']);
|
||||
|
||||
const BasicPurple = buildColorDefinition('purple', 'purple', ['#A352CC', '#B877D9'], true);
|
||||
const DarkPurple = buildColorDefinition('purple', 'dark-purple', ['#7C2EA3', '#8F3BB8']);
|
||||
const SemiDarkPurple = buildColorDefinition('purple', 'semi-dark-purple', ['#8F3BB8', '#A352CC']);
|
||||
const LightPurple = buildColorDefinition('purple', 'light-purple', ['#B877D9', '#CA95E5']);
|
||||
const SuperLightPurple = buildColorDefinition('purple', 'super-light-purple', ['#CA95E5', '#DEB6F2']);
|
||||
|
||||
const greens = [BasicGreen, DarkGreen, SemiDarkGreen, LightGreen, SuperLightGreen];
|
||||
const yellows = [BasicYellow, DarkYellow, SemiDarkYellow, LightYellow, SuperLightYellow];
|
||||
const reds = [BasicRed, DarkRed, SemiDarkRed, LightRed, SuperLightRed];
|
||||
const blues = [BasicBlue, DarkBlue, SemiDarkBlue, LightBlue, SuperLightBlue];
|
||||
const oranges = [BasicOrange, DarkOrange, SemiDarkOrange, LightOrange, SuperLightOrange];
|
||||
const purples = [BasicPurple, DarkPurple, SemiDarkPurple, LightPurple, SuperLightPurple];
|
||||
|
||||
palette.set('green', greens);
|
||||
palette.set('yellow', yellows);
|
||||
palette.set('red', reds);
|
||||
palette.set('blue', blues);
|
||||
palette.set('orange', oranges);
|
||||
palette.set('purple', purples);
|
||||
|
||||
return palette;
|
||||
};
|
||||
|
||||
export const getNamedColorPalette = () => {
|
||||
if (colorsPaletteInstance) {
|
||||
return colorsPaletteInstance;
|
||||
}
|
||||
|
||||
colorsPaletteInstance = buildNamedColorsPalette();
|
||||
return colorsPaletteInstance;
|
||||
};
|
||||
|
||||
export const classicColors = [
|
||||
'#7EB26D', // 0: pale green
|
||||
'#EAB839', // 1: mustard
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
FieldConfig,
|
||||
FieldColorModeId,
|
||||
getFieldColorMode,
|
||||
getColorForTheme,
|
||||
FALLBACK_COLOR,
|
||||
TextDisplayOptions,
|
||||
VizOrientation,
|
||||
@@ -536,7 +535,7 @@ export function getBarGradient(props: Props, maxSize: number): string {
|
||||
|
||||
for (let i = 0; i < thresholds.steps.length; i++) {
|
||||
const threshold = thresholds.steps[i];
|
||||
const color = getColorForTheme(threshold.color, props.theme.v1);
|
||||
const color = props.theme.visualization.getColorByName(threshold.color);
|
||||
const valuePercent =
|
||||
thresholds.mode === ThresholdsMode.Percentage
|
||||
? threshold.value / 100
|
||||
@@ -560,8 +559,9 @@ export function getBarGradient(props: Props, maxSize: number): string {
|
||||
return gradient + ')';
|
||||
}
|
||||
|
||||
if (mode.isContinuous && mode.colors) {
|
||||
const scheme = mode.colors.map((item) => getColorForTheme(item, theme.v1));
|
||||
if (mode.isContinuous && mode.getColors) {
|
||||
const scheme = mode.getColors(theme);
|
||||
|
||||
for (let i = 0; i < scheme.length; i++) {
|
||||
const color = scheme[i];
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ function getProps(propOverrides?: Partial<Props>): Props {
|
||||
value: {
|
||||
text: '25',
|
||||
numeric: 25,
|
||||
color: 'red',
|
||||
},
|
||||
theme: createTheme(),
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { CSSProperties } from 'react';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
// Utils
|
||||
import { formattedValueToString, DisplayValue, getColorForTheme, FieldConfig } from '@grafana/data';
|
||||
import { formattedValueToString, DisplayValue, FieldConfig } from '@grafana/data';
|
||||
import { calculateFontSize } from '../../utils/measureText';
|
||||
|
||||
// Types
|
||||
@@ -30,9 +30,9 @@ export abstract class BigValueLayout {
|
||||
textValues: BigValueTextValues;
|
||||
|
||||
constructor(private props: Props) {
|
||||
const { width, height, value, theme, text } = props;
|
||||
const { width, height, value, text } = props;
|
||||
|
||||
this.valueColor = getColorForTheme(value.color || 'green', theme.v1);
|
||||
this.valueColor = value.color ?? 'gray';
|
||||
this.panelPadding = height > 100 ? 12 : 8;
|
||||
this.textValues = getTextValues(props);
|
||||
this.justifyCenter = shouldJustifyCenter(props.justifyMode, this.textValues.title);
|
||||
|
||||
@@ -5,7 +5,7 @@ exports[`BigValue Render with basic options should render 1`] = `
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"background": "linear-gradient(120deg, rgb(66, 154, 67), rgb(111, 183, 87))",
|
||||
"background": "linear-gradient(120deg, rgb(179, 24, 0), rgb(230, 0, 31))",
|
||||
"borderRadius": "3px",
|
||||
"display": "flex",
|
||||
"flexDirection": "row",
|
||||
@@ -41,6 +41,7 @@ exports[`BigValue Render with basic options should render 1`] = `
|
||||
}
|
||||
value={
|
||||
Object {
|
||||
"color": "red",
|
||||
"numeric": 25,
|
||||
"text": "25",
|
||||
"titleToAlignTo": undefined,
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component, createRef } from 'react';
|
||||
import { PopoverController } from '../Tooltip/PopoverController';
|
||||
import { Popover } from '../Tooltip/Popover';
|
||||
import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover';
|
||||
import { getColorForTheme, GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
@@ -75,7 +75,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
|
||||
ref={this.pickerTriggerRef}
|
||||
onClick={showPopper}
|
||||
onMouseLeave={hidePopper}
|
||||
color={getColorForTheme(this.props.color || '#000000', theme.v1)}
|
||||
color={theme.visualization.getColorByName(this.props.color || '#000000')}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { ColorPickerPopover } from './ColorPickerPopover';
|
||||
import { flatten } from 'lodash';
|
||||
import { getNamedColorPalette, getColorFromHexRgbOrName } from '@grafana/data';
|
||||
import { ColorSwatch } from './ColorSwatch';
|
||||
|
||||
const allColors = flatten(Array.from(getNamedColorPalette().values()));
|
||||
import { createTheme, getColorForTheme } from '@grafana/data';
|
||||
|
||||
describe('ColorPickerPopover', () => {
|
||||
const theme = createTheme();
|
||||
|
||||
describe('rendering', () => {
|
||||
it('should render provided color as selected if color provided by name', () => {
|
||||
const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} />);
|
||||
@@ -15,18 +14,7 @@ describe('ColorPickerPopover', () => {
|
||||
const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false);
|
||||
|
||||
expect(selectedSwatch.length).toBe(1);
|
||||
expect(notSelectedSwatches.length).toBe(allColors.length + 1);
|
||||
expect(selectedSwatch.prop('isSelected')).toBe(true);
|
||||
});
|
||||
|
||||
it('should render provided color as selected if color provided by hex', () => {
|
||||
const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} />);
|
||||
|
||||
const selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green');
|
||||
const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false);
|
||||
|
||||
expect(selectedSwatch.length).toBe(1);
|
||||
expect(notSelectedSwatches.length).toBe(allColors.length + 1);
|
||||
expect(notSelectedSwatches.length).toBe(31);
|
||||
expect(selectedSwatch.prop('isSelected')).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -47,7 +35,7 @@ describe('ColorPickerPopover', () => {
|
||||
basicBlueSwatch.simulate('click');
|
||||
|
||||
expect(onChangeSpy).toBeCalledTimes(1);
|
||||
expect(onChangeSpy).toBeCalledWith(getColorFromHexRgbOrName('green'));
|
||||
expect(onChangeSpy).toBeCalledWith(getColorForTheme('green', theme.v1));
|
||||
});
|
||||
|
||||
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, getColorForTheme } from '@grafana/data';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { stylesFactory, withTheme2 } from '../../themes';
|
||||
|
||||
export type ColorPickerChangeHandler = (color: string) => void;
|
||||
@@ -59,7 +59,7 @@ class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends Reac
|
||||
if (enableNamedColors) {
|
||||
return changeHandler(color);
|
||||
}
|
||||
changeHandler(getColorForTheme(color, theme.v1));
|
||||
changeHandler(theme.visualization.getColorByName(color));
|
||||
};
|
||||
|
||||
onTabChange = (tab: PickerType | keyof T) => {
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { ColorDefinition } from '@grafana/data';
|
||||
import { ThemeVizHue } from '@grafana/data';
|
||||
import { Color } from 'csstype';
|
||||
import { upperFirst, find } from 'lodash';
|
||||
import { ColorSwatch, ColorSwatchVariant } from './ColorSwatch';
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
type ColorChangeHandler = (color: ColorDefinition) => void;
|
||||
import { upperFirst } from 'lodash';
|
||||
|
||||
interface NamedColorsGroupProps {
|
||||
colors: ColorDefinition[];
|
||||
hue: ThemeVizHue;
|
||||
selectedColor?: Color;
|
||||
onColorSelect: ColorChangeHandler;
|
||||
onColorSelect: (colorName: string) => void;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
const NamedColorsGroup: FunctionComponent<NamedColorsGroupProps> = ({
|
||||
colors,
|
||||
hue,
|
||||
selectedColor,
|
||||
onColorSelect,
|
||||
...otherProps
|
||||
}) => {
|
||||
const theme = useTheme2();
|
||||
const primaryColor = find(colors, (color) => !!color.isPrimary);
|
||||
const primaryShade = hue.shades.find((shade) => shade.primary)!;
|
||||
|
||||
return (
|
||||
<div {...otherProps} style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
{primaryColor && (
|
||||
{primaryShade && (
|
||||
<ColorSwatch
|
||||
key={primaryColor.name}
|
||||
isSelected={primaryColor.name === selectedColor}
|
||||
key={primaryShade.name}
|
||||
isSelected={primaryShade.name === selectedColor}
|
||||
variant={ColorSwatchVariant.Large}
|
||||
color={primaryColor.variants[theme.colors.mode]}
|
||||
label={upperFirst(primaryColor.hue)}
|
||||
onClick={() => onColorSelect(primaryColor)}
|
||||
color={primaryShade.color}
|
||||
label={upperFirst(hue.name)}
|
||||
onClick={() => onColorSelect(primaryShade.name)}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
@@ -41,15 +37,15 @@ const NamedColorsGroup: FunctionComponent<NamedColorsGroupProps> = ({
|
||||
marginTop: '8px',
|
||||
}}
|
||||
>
|
||||
{colors.map(
|
||||
(color) =>
|
||||
!color.isPrimary && (
|
||||
<div key={color.name} style={{ marginRight: '4px' }}>
|
||||
{hue.shades.map(
|
||||
(shade) =>
|
||||
!shade.primary && (
|
||||
<div key={shade.name} style={{ marginRight: '4px' }}>
|
||||
<ColorSwatch
|
||||
key={color.name}
|
||||
isSelected={color.name === selectedColor}
|
||||
color={color.variants[theme.colors.mode]}
|
||||
onClick={() => onColorSelect(color)}
|
||||
key={shade.name}
|
||||
isSelected={shade.name === selectedColor}
|
||||
color={shade.color}
|
||||
onClick={() => onColorSelect(shade.name)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { NamedColorsPalette } from './NamedColorsPalette';
|
||||
import { createTheme, getColorDefinitionByName } from '@grafana/data';
|
||||
import { createTheme } from '@grafana/data';
|
||||
import { ColorSwatch } from './ColorSwatch';
|
||||
import { ThemeContext } from '../../themes';
|
||||
|
||||
describe('NamedColorsPalette', () => {
|
||||
const BasicGreen = getColorDefinitionByName('green');
|
||||
const theme = createTheme();
|
||||
const greenHue = theme.visualization.hues.find((x) => x.name === 'green')!;
|
||||
const selectedShade = greenHue.shades[2];
|
||||
|
||||
describe('theme support for named colors', () => {
|
||||
let wrapper: ReactWrapper, selectedSwatch;
|
||||
@@ -16,21 +17,9 @@ describe('NamedColorsPalette', () => {
|
||||
});
|
||||
|
||||
it('should render provided color variant specific for theme', () => {
|
||||
wrapper = mount(<NamedColorsPalette color={BasicGreen.name} onChange={() => {}} />);
|
||||
selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === BasicGreen.name);
|
||||
expect(selectedSwatch.prop('color')).toBe(BasicGreen.variants.dark);
|
||||
|
||||
wrapper.unmount();
|
||||
|
||||
const withLightTheme = (
|
||||
<ThemeContext.Provider value={createTheme({ colors: { mode: 'light' } })}>
|
||||
<NamedColorsPalette color={BasicGreen.name} onChange={() => {}} />
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
|
||||
wrapper = mount(withLightTheme);
|
||||
selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === BasicGreen.name);
|
||||
expect(selectedSwatch.prop('color')).toBe(BasicGreen.variants.light);
|
||||
wrapper = mount(<NamedColorsPalette color={selectedShade.name} onChange={() => {}} />);
|
||||
selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === selectedShade.name);
|
||||
expect(selectedSwatch.prop('color')).toBe(selectedShade.color);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { getNamedColorPalette } from '@grafana/data';
|
||||
import NamedColorsGroup from './NamedColorsGroup';
|
||||
import { VerticalGroup } from '../Layout/Layout';
|
||||
import { ColorSwatch } from './ColorSwatch';
|
||||
@@ -14,18 +13,9 @@ export const NamedColorsPalette = ({ color, onChange }: NamedColorsPaletteProps)
|
||||
const theme = useTheme2();
|
||||
|
||||
const swatches: JSX.Element[] = [];
|
||||
getNamedColorPalette().forEach((colors, hue) => {
|
||||
swatches.push(
|
||||
<NamedColorsGroup
|
||||
key={hue}
|
||||
selectedColor={color}
|
||||
colors={colors}
|
||||
onColorSelect={(color) => {
|
||||
onChange(color.name);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
for (const hue of theme.visualization.hues) {
|
||||
swatches.push(<NamedColorsGroup key={hue.name} selectedColor={color} hue={hue} onColorSelect={onChange} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<VerticalGroup spacing="md">
|
||||
@@ -39,6 +29,7 @@ export const NamedColorsPalette = ({ color, onChange }: NamedColorsPaletteProps)
|
||||
}}
|
||||
>
|
||||
{swatches}
|
||||
<div />
|
||||
<ColorSwatch
|
||||
isSelected={color === 'transparent'}
|
||||
color={'rgba(0,0,0,0)'}
|
||||
|
||||
@@ -6,15 +6,14 @@ import {
|
||||
FieldColor,
|
||||
fieldColorModeRegistry,
|
||||
FieldColorMode,
|
||||
GrafanaTheme,
|
||||
getColorForTheme,
|
||||
GrafanaTheme2,
|
||||
FieldColorConfigSettings,
|
||||
FieldColorSeriesByMode,
|
||||
getFieldColorMode,
|
||||
} from '@grafana/data';
|
||||
import { Select } from '../Select/Select';
|
||||
import { ColorValueEditor } from './color';
|
||||
import { useStyles, useTheme } from '../../themes/ThemeContext';
|
||||
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
|
||||
import { css } from '@emotion/css';
|
||||
import { Field } from '../Forms/Field';
|
||||
import { RadioButtonGroup } from '../Forms/RadioButtonGroup/RadioButtonGroup';
|
||||
@@ -24,8 +23,8 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
onChange,
|
||||
item,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const styles = useStyles(getStyles);
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const colorMode = getFieldColorMode(value?.mode);
|
||||
const availableOptions = item.settings?.byValueSupport
|
||||
@@ -90,7 +89,7 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ marginBottom: theme.spacing.formInputMargin }}>
|
||||
<div style={{ marginBottom: theme.spacing(2) }}>
|
||||
<Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />
|
||||
</div>
|
||||
<Field label="Color series by">
|
||||
@@ -105,15 +104,15 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
|
||||
interface ModeProps {
|
||||
mode: FieldColorMode;
|
||||
theme: GrafanaTheme;
|
||||
theme: GrafanaTheme2;
|
||||
}
|
||||
|
||||
const FieldColorModeViz: FC<ModeProps> = ({ mode, theme }) => {
|
||||
if (!mode.colors) {
|
||||
if (!mode.getColors) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const colors = mode.colors.map((item) => getColorForTheme(item, theme));
|
||||
const colors = mode.getColors(theme).map(theme.visualization.getColorByName);
|
||||
const style: CSSProperties = {
|
||||
height: '8px',
|
||||
width: '100%',
|
||||
@@ -145,7 +144,7 @@ const FieldColorModeViz: FC<ModeProps> = ({ mode, theme }) => {
|
||||
return <div style={style} />;
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => {
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
group: css`
|
||||
display: flex;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { css } from '@emotion/css';
|
||||
import { mockThemeContext, useStyles } from './ThemeContext';
|
||||
@@ -36,8 +35,6 @@ describe('useStyles', () => {
|
||||
it('passes in theme and returns style object', (done) => {
|
||||
const Dummy: React.FC = function () {
|
||||
const styles = useStyles((theme) => {
|
||||
expect(theme).toEqual(config.theme);
|
||||
|
||||
return {
|
||||
someStyle: css`
|
||||
color: ${theme.palette.critical};
|
||||
|
||||
@@ -289,6 +289,7 @@ function PieLabel({ arc, outerRadius, innerRadius, displayLabels, total, color,
|
||||
y={labelY}
|
||||
dy=".33em"
|
||||
fontSize={labelFontSize}
|
||||
fontWeight={500}
|
||||
textAnchor="middle"
|
||||
pointerEvents="none"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user