diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.story.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.story.tsx
new file mode 100644
index 00000000000..1cdf01a2dd3
--- /dev/null
+++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.story.tsx
@@ -0,0 +1,68 @@
+import React, { FunctionComponent } from 'react';
+import { storiesOf } from '@storybook/react';
+import NamedColorsPicker from './NamedColorsPicker';
+import { Color, getColorName } from '@grafana/ui/src/utils/colorsPalette';
+
+const CenteredStory: FunctionComponent<{}> = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+interface StateHolderProps
{
+ initialState: T;
+ children: (currentState: T, updateState: (nextState: T) => void) => JSX.Element;
+}
+
+class UseState extends React.Component, {value: T}> {
+ constructor(props: StateHolderProps) {
+ 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/ColorPicker', module)
+ .addDecorator(story => {story()})
+ .add('Named colors swatch - support for named colors', () => {
+ return(
+
+ {(selectedColor, updateSelectedColor) => {
+ return (
+ { updateSelectedColor(color.name);}}
+ />
+ )
+ }}
+ );
+ })
+ .add('Named colors swatch - support for hex values', () => {
+ return(
+
+ {(selectedColor, updateSelectedColor) => {
+ return (
+ updateSelectedColor(color.variants.dark)}
+ />
+ )
+ }}
+ );
+ });
diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.tsx
new file mode 100644
index 00000000000..a0732e4e21d
--- /dev/null
+++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPicker.tsx
@@ -0,0 +1,121 @@
+import React, { FunctionComponent } from 'react';
+import { find, upperFirst } from 'lodash';
+import { Color, ColorsPalete, ColorDefinition } from '../../utils/colorsPalette';
+
+type ColorChangeHandler = (color: ColorDefinition) => void;
+
+enum ColorSwatchVariant {
+ Small = 'small',
+ Large = 'large',
+}
+
+interface ColorSwatchProps extends React.DOMAttributes {
+ color: ColorDefinition;
+ variant?: ColorSwatchVariant;
+ isSelected?: boolean;
+}
+
+const ColorSwatch: FunctionComponent = ({
+ color,
+ variant = ColorSwatchVariant.Small,
+ isSelected,
+ ...otherProps
+}) => {
+ const isSmall = variant === ColorSwatchVariant.Small;
+ const swatchSize = isSmall ? '16px' : '32px';
+ const swatchStyles = {
+ width: swatchSize,
+ height: swatchSize,
+ borderRadius: '50%',
+ background: `${color.variants.dark}`,
+ marginRight: isSmall ? '0px' : '8px',
+ boxShadow: isSelected ? `inset 0 0 0 2px ${color.variants.dark}, inset 0 0 0 4px white` : 'none',
+ cursor: isSelected ? 'default' : 'pointer'
+ };
+
+ return (
+
+
+ {variant === ColorSwatchVariant.Large &&
{upperFirst(color.hue)}}
+
+ );
+};
+
+const ColorsGroup = ({
+ colors,
+ selectedColor,
+ onColorSelect,
+}: {
+ colors: ColorDefinition[];
+ selectedColor?: Color;
+ onColorSelect: ColorChangeHandler
+}) => {
+ const primaryColor = find(colors, color => !!color.isPrimary);
+
+ return (
+
+ {primaryColor && (
+
onColorSelect(primaryColor)}
+ />
+ )}
+
+ {colors.map(color => !color.isPrimary && (
+
+ onColorSelect(color)}
+ />
+
+ ))}
+
+
+ );
+};
+
+
+interface NamedColorsPickerProps {
+ selectedColor?: Color;
+ onChange: ColorChangeHandler;
+}
+const NamedColorsPicker = ({ selectedColor, onChange }: NamedColorsPickerProps) => {
+ const swatches: JSX.Element[] = [];
+
+ ColorsPalete.forEach((colors, hue) => {
+ swatches.push(
+ <>
+
+ >
+ );
+ });
+
+ return (
+
+ {swatches}
+
+ );
+};
+
+export default NamedColorsPicker;
diff --git a/packages/grafana-ui/src/utils/colors.ts b/packages/grafana-ui/src/utils/colors.ts
index 263d128aec4..65ee605c33b 100644
--- a/packages/grafana-ui/src/utils/colors.ts
+++ b/packages/grafana-ui/src/utils/colors.ts
@@ -9,7 +9,6 @@ export const ALERTING_COLOR = 'rgba(237, 46, 24, 1)';
export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)';
export const PENDING_COLOR = 'rgba(247, 149, 32, 1)';
export const REGION_FILL_ALPHA = 0.09;
-
export const colors = [
'#7EB26D', // 0: pale green
'#EAB839', // 1: mustard
diff --git a/packages/grafana-ui/src/utils/colorsPalette.test.ts b/packages/grafana-ui/src/utils/colorsPalette.test.ts
new file mode 100644
index 00000000000..41a615410ef
--- /dev/null
+++ b/packages/grafana-ui/src/utils/colorsPalette.test.ts
@@ -0,0 +1,31 @@
+import { getColorName, getColorDefinition, ColorsPalete, buildColorDefinition } from './colorsPalette';
+
+describe('colors', () => {
+ const FakeBlue = buildColorDefinition('blue', 'blue', ['#0000ff', '#00000ee']);
+
+ beforeAll(() => {
+ ColorsPalete.set('blue', [FakeBlue])
+ });
+
+ describe('getColorDefinition', () => {
+ it('returns undefined for unknown hex', () => {
+ expect(getColorDefinition('#ff0000')).toBeUndefined();
+ });
+
+ it('returns definition for known hex', () => {
+ expect(getColorDefinition(FakeBlue.variants.light)).toEqual(FakeBlue);
+ expect(getColorDefinition(FakeBlue.variants.dark)).toEqual(FakeBlue);
+ });
+ });
+
+ describe('getColorName', () => {
+ it('returns undefined for unknown hex', () => {
+ expect(getColorName('#ff0000')).toBeUndefined();
+ });
+
+ it('returns name for known hex', () => {
+ expect(getColorName(FakeBlue.variants.light)).toEqual(FakeBlue.name);
+ expect(getColorName(FakeBlue.variants.dark)).toEqual(FakeBlue.name);
+ });
+ });
+});
diff --git a/packages/grafana-ui/src/utils/colorsPalette.ts b/packages/grafana-ui/src/utils/colorsPalette.ts
new file mode 100644
index 00000000000..2f6300b1e18
--- /dev/null
+++ b/packages/grafana-ui/src/utils/colorsPalette.ts
@@ -0,0 +1,125 @@
+import { flatten, some, values } from 'lodash';
+
+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';
+
+type ThemeVariants = {
+ dark: string;
+ light: string;
+};
+export type ColorDefinition = {
+ hue: Hue;
+ isPrimary?: boolean;
+ name: Color;
+ variants: ThemeVariants;
+};
+
+export const ColorsPalete = new Map();
+
+export const buildColorDefinition = (
+ hue: Hue,
+ name: Color,
+ [light, dark]: string[],
+ isPrimary?: boolean
+): ColorDefinition => ({
+ hue,
+ name,
+ variants: {
+ light,
+ dark,
+ },
+ isPrimary: !!isPrimary,
+});
+
+export const BasicGreen = buildColorDefinition('green', 'green', ['#53A642', '#53A642'], true);
+export const DarkGreen = buildColorDefinition('green', 'dark-green', ['#106100', '#106100']);
+export const SemiDarkGreen = buildColorDefinition('green', 'semi-dark-green', ['#388729', '#388729']);
+export const LightGreen = buildColorDefinition('green', 'light-green', ['#72C462', '#72C462']);
+export const SuperLightGreen = buildColorDefinition('green', 'super-light-green', ['#99E68A', '#99E68A']);
+
+export const BasicYellow = buildColorDefinition('yellow', 'yellow', ['#F2CA00', '#F2CA00'], true);
+export const DarkYellow = buildColorDefinition('yellow', 'dark-yellow', ['#A68A00', '#A68A00']);
+export const SemiDarkYellow = buildColorDefinition('yellow', 'semi-dark-yellow', ['#CCAA00', '#CCAA00']);
+export const LightYellow = buildColorDefinition('yellow', 'light-yellow', ['#F7D636', '#F7D636']);
+export const SuperLightYellow = buildColorDefinition('yellow', 'super-light-yellow', ['#FFEB8A', '#FFEB8A']);
+
+export const BasicRed = buildColorDefinition('red', 'red', ['#F94462', '#F94462'], true);
+export const DarkRed = buildColorDefinition('red', 'dark-red', ['#B3001D', '#B3001D']);
+export const SemiDarkRed = buildColorDefinition('red', 'semi-dark-red', ['#D93651', '#D93651']);
+export const LightRed = buildColorDefinition('red', 'light-red', ['#F07387', '#F07387']);
+export const SuperLightRed = buildColorDefinition('red', 'super-light-red', ['#E6A1AC', '#E6A1AC']);
+
+export const BasicBlue = buildColorDefinition('blue', 'blue', ['#408BFF', '#408BFF'], true);
+export const DarkBlue = buildColorDefinition('blue', 'dark-blue', ['#2155A6', '#2155A6']);
+export const SemiDarkBlue = buildColorDefinition('blue', 'semi-dark-blue', ['#3471CF', '#3471CF']);
+export const LightBlue = buildColorDefinition('blue', 'light-blue', ['#7DAEFA', '#7DAEFA']);
+export const SuperLightBlue = buildColorDefinition('blue', 'super-light-blue', ['#B8D0F5', '#B8D0F5']);
+
+export const BasicOrange = buildColorDefinition('orange', 'orange', ['#FA6400', '#FA6400'], true);
+export const DarkOrange = buildColorDefinition('orange', 'dark-orange', ['#963C00', '#963C00']);
+export const SemiDarkOrange = buildColorDefinition('orange', 'semi-dark-orange', ['#ED4B00', '#ED4B00']);
+export const LightOrange = buildColorDefinition('orange', 'light-orange', ['#FC934C', '#FC934C']);
+export const SuperLightOrange = buildColorDefinition('orange', 'super-light-orange', ['#FFC299', '#FFC299']);
+
+export const BasicPurple = buildColorDefinition('purple', 'purple', ['#BC67E6', '#BC67E6'], true);
+export const DarkPurple = buildColorDefinition('purple', 'dark-purple', ['#701F99', '#701F99']);
+export const SemiDarkPurple = buildColorDefinition('purple', 'semi-dark-purple', ['#9E43CC', '#9E43CC']);
+export const LightPurple = buildColorDefinition('purple', 'light-purple', ['#D19AED', '#D19AED']);
+export const SuperLightPurple = buildColorDefinition('purple', 'super-light-purple', ['#E6CEF2', '#E6CEF2']);
+
+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];
+
+ColorsPalete.set('green', greens);
+ColorsPalete.set('yellow', yellows);
+ColorsPalete.set('red', reds);
+ColorsPalete.set('blue', blues);
+ColorsPalete.set('orange', oranges);
+ColorsPalete.set('purple', purples);
+
+export const getColorDefinition = (hex: string): ColorDefinition | undefined => {
+ return flatten(Array.from(ColorsPalete.values())).filter(definition =>
+ some(values(definition.variants), color => color === hex)
+ )[0];
+};
+
+export const getColorName = (hex: string): Color | undefined => {
+ const definition = getColorDefinition(hex);
+
+ return definition ? definition.name : undefined;
+};
diff --git a/yarn.lock b/yarn.lock
index 1aa0d7f20c3..32881e10817 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1673,7 +1673,7 @@
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-1.10.35.tgz#4e5c2b1e5b3bf0b863efb8c5e70081f52e6c9518"
integrity sha512-SVtqEcudm7yjkTwoRA1gC6CNMhGDdMx4Pg8BPdiqI7bXXdCn1BPmtxgeWYQOgDxrq53/5YTlhq5ULxBEAlWIBg==
-"@types/lodash@4.14.119", "@types/lodash@^4.14.119":
+"@types/lodash@^4.14.119":
version "4.14.119"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.119.tgz#be847e5f4bc3e35e46d041c394ead8b603ad8b39"
integrity sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw==
@@ -1735,7 +1735,7 @@
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@^16.7.6":
+"@types/react@*", "@types/react@16.7.6", "@types/react@^16.7.6":
version "16.7.6"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040"
integrity sha512-QBUfzftr/8eg/q3ZRgf/GaDP6rTYc7ZNem+g4oZM38C9vXyV8AWRWaTQuW5yCoZTsfHrN7b3DeEiUnqH9SrnpA==
@@ -4429,7 +4429,7 @@ caniuse-api@^1.5.2:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
+caniuse-db@1.0.30000772, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000772"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000772.tgz#51aae891768286eade4a3d8319ea76d6a01b512b"
integrity sha1-UarokXaChureSj2DGep21qAbUSs=