Theming: Make new theme exposed by ThemeContext and make new theme include v1 for compatability (to pass to useTheme) (#33207)

* WIP: Making new theme the default

* Progress

* Updates, lots of updates

* Things are working

* Fixed issues with storybook

* Fixed tests
This commit is contained in:
Torkel Ödegaard 2021-04-21 14:25:43 +02:00 committed by GitHub
parent 569fb3f112
commit 7e2bf4f6c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 1505 additions and 1534 deletions

View File

@ -15,6 +15,10 @@ export interface ThemeComponents {
borderHover: string;
text: string;
};
tooltip: {
text: string;
background: string;
};
panel: {
padding: number;
headerHeight: number;
@ -58,6 +62,10 @@ export function createComponents(palette: ThemePalette, shadows: ThemeShadows):
text: palette.text.primary,
},
panel,
tooltip: {
background: palette.background.secondary,
text: palette.text.primary,
},
dashboard: {
background: palette.background.canvas,
padding: 1,

View File

@ -1,28 +1,14 @@
import { createBreakpoints, ThemeBreakpoints } from './breakpoints';
import { ThemeComponents, createComponents } from './createComponents';
import { createPalette, ThemePalette, ThemePaletteInput } from './createPalette';
import { createShadows, ThemeShadows } from './createShadows';
import { createShape, ThemeShape, ThemeShapeInput } from './createShape';
import { createSpacing, ThemeSpacingOptions, ThemeSpacing } from './createSpacing';
import { createTransitions, ThemeTransitions } from './createTransitions';
import { createTypography, ThemeTypography, ThemeTypographyInput } from './createTypography';
import { ThemeZIndices, zIndex } from './zIndex';
/** @beta */
export interface GrafanaThemeV2 {
name: string;
isDark: boolean;
isLight: boolean;
palette: ThemePalette;
breakpoints: ThemeBreakpoints;
spacing: ThemeSpacing;
shape: ThemeShape;
components: ThemeComponents;
typography: ThemeTypography;
zIndex: ThemeZIndices;
shadows: ThemeShadows;
transitions: ThemeTransitions;
}
import { createBreakpoints } from './breakpoints';
import { createComponents } from './createComponents';
import { createPalette, ThemePaletteInput } from './createPalette';
import { createShadows } from './createShadows';
import { createShape, ThemeShapeInput } from './createShape';
import { createSpacing, ThemeSpacingOptions } from './createSpacing';
import { createTransitions } from './createTransitions';
import { createTypography, ThemeTypographyInput } from './createTypography';
import { createV1Theme } from './createV1Theme';
import { GrafanaThemeV2 } from './types';
import { zIndex } from './zIndex';
/** @internal */
export interface NewThemeOptions {
@ -52,7 +38,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaThemeV2 {
const transitions = createTransitions();
const components = createComponents(palette, shadows);
return {
const theme = {
name,
isDark: palette.mode === 'dark',
isLight: palette.mode === 'light',
@ -68,4 +54,9 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaThemeV2 {
...zIndex,
},
};
return {
...theme,
v1: createV1Theme(theme),
};
}

View File

@ -0,0 +1,267 @@
import { GrafanaTheme, GrafanaThemeCommons, GrafanaThemeType } from '../types';
import { GrafanaThemeV2 } from './types';
export function createV1Theme(theme: Omit<GrafanaThemeV2, 'v1'>): GrafanaTheme {
const oldCommon: GrafanaThemeCommons = {
name: 'Grafana Default',
typography: {
fontFamily: {
sansSerif: theme.typography.fontFamily,
monospace: theme.typography.fontFamilyMonospace,
},
size: {
base: `${theme.typography.fontSize}px`,
xs: theme.typography.size.xs,
sm: theme.typography.size.sm,
md: theme.typography.size.md,
lg: theme.typography.size.lg,
},
heading: {
h1: theme.typography.h1.fontSize,
h2: theme.typography.h2.fontSize,
h3: theme.typography.h3.fontSize,
h4: theme.typography.h4.fontSize,
h5: theme.typography.h5.fontSize,
h6: theme.typography.h6.fontSize,
},
weight: {
light: theme.typography.fontWeightLight,
regular: theme.typography.fontWeightRegular,
semibold: theme.typography.fontWeightMedium,
bold: theme.typography.fontWeightBold,
},
lineHeight: {
xs: theme.typography.bodySmall.lineHeight,
sm: theme.typography.bodySmall.lineHeight,
md: theme.typography.body.lineHeight,
lg: theme.typography.h2.lineHeight,
},
link: {
decoration: 'none',
hoverDecoration: 'none',
},
},
breakpoints: {
xs: `${theme.breakpoints.values.xs}px`,
sm: `${theme.breakpoints.values.sm}px`,
md: `${theme.breakpoints.values.md}px`,
lg: `${theme.breakpoints.values.lg}px`,
xl: `${theme.breakpoints.values.xl}px`,
xxl: `${theme.breakpoints.values.xxl}px`,
},
spacing: {
base: theme.spacing.gridSize,
insetSquishMd: theme.spacing(0.5, 1),
d: theme.spacing(2),
xxs: theme.spacing(0.25),
xs: theme.spacing(0.5),
sm: theme.spacing(1),
md: theme.spacing(2),
lg: theme.spacing(3),
xl: theme.spacing(4),
gutter: theme.spacing(4),
// Next-gen forms spacing variables
// TODO: Move variables definition to respective components when implementing
formSpacingBase: theme.spacing.gridSize,
formMargin: `${theme.spacing.gridSize * 4}px`,
formFieldsetMargin: `${theme.spacing.gridSize * 2}px`,
formInputHeight: theme.spacing.gridSize * 4,
formButtonHeight: theme.spacing.gridSize * 4,
formInputPaddingHorizontal: `${theme.spacing.gridSize}px`,
// Used for icons do define spacing between icon and input field
// Applied on the right(prefix) or left(suffix)
formInputAffixPaddingHorizontal: `${theme.spacing.gridSize / 2}px`,
formInputMargin: `${theme.spacing.gridSize * 2}px`,
formLabelPadding: '0 0 0 2px',
formLabelMargin: `0 0 ${theme.spacing.gridSize / 2 + 'px'} 0`,
formValidationMessagePadding: '4px 8px',
formValidationMessageMargin: '4px 0 0 0',
inlineFormMargin: '4px',
},
border: {
radius: {
sm: theme.shape.borderRadius(1),
md: theme.shape.borderRadius(2),
lg: theme.shape.borderRadius(3),
},
width: {
sm: '1px',
},
},
height: {
sm: theme.spacing.gridSize * theme.components.height.sm,
md: theme.spacing.gridSize * theme.components.height.md,
lg: theme.spacing.gridSize * theme.components.height.lg,
},
panelPadding: theme.components.panel.padding * theme.spacing.gridSize,
panelHeaderHeight: theme.spacing.gridSize * theme.components.panel.headerHeight,
zIndex: {
navbarFixed: theme.zIndex.navbarFixed,
sidemenu: theme.zIndex.sidemenu,
dropdown: theme.zIndex.dropdown,
typeahead: theme.zIndex.typeahead,
tooltip: theme.zIndex.tooltip,
modalBackdrop: theme.zIndex.modalBackdrop,
modal: theme.zIndex.modal,
},
};
const basicColors = {
...commonColorsPalette,
black: '#000000',
white: '#ffffff',
dark1: '#141414',
dark2: '#161719',
dark3: '#1f1f20',
dark4: '#212124',
dark5: '#222426',
dark6: '#262628',
dark7: '#292a2d',
dark8: '#2f2f32',
dark9: '#343436',
dark10: '#424345',
gray1: '#555555',
gray2: '#8e8e8e',
gray3: '#b3b3b3',
gray4: '#d8d9da',
gray5: '#ececec',
gray6: '#f4f5f8', // not used in dark theme
gray7: '#fbfbfb', // not used in dark theme
redBase: '#e02f44',
redShade: '#c4162a',
greenBase: '#299c46',
greenShade: '#23843b',
red: '#d44a3a',
yellow: '#ecbb13',
purple: '#9933cc',
variable: '#32d1df',
orange: '#eb7b18',
orangeDark: '#ff780a',
};
const backgrounds = {
bg1: theme.palette.background.primary,
bg2: theme.palette.background.secondary,
bg3: theme.palette.action.hover,
dashboardBg: theme.palette.background.canvas,
bgBlue1: theme.palette.primary.main,
bgBlue2: theme.palette.primary.shade,
};
const borders = {
border1: theme.palette.border.weak,
border2: theme.palette.border.medium,
border3: theme.palette.border.strong,
};
const textColors = {
textStrong: theme.palette.text.maxContrast,
textHeading: theme.palette.text.primary,
text: theme.palette.text.primary,
textSemiWeak: theme.palette.text.secondary,
textWeak: theme.palette.text.secondary,
textFaint: theme.palette.text.disabled,
textBlue: theme.palette.primary.text,
};
const form = {
// Next-gen forms functional colors
formLabel: theme.palette.text.primary,
formDescription: theme.palette.text.secondary,
formInputBg: basicColors.gray05,
formInputBgDisabled: basicColors.gray10,
formInputBorder: borders.border2,
formInputBorderHover: basicColors.gray33,
formInputBorderActive: basicColors.blue95,
formInputBorderInvalid: basicColors.red88,
formInputPlaceholderText: textColors.textFaint,
formInputText: basicColors.gray85,
formInputDisabledText: basicColors.gray70,
formFocusOutline: basicColors.blue77,
formValidationMessageText: basicColors.white,
formValidationMessageBg: basicColors.red88,
formSwitchBg: basicColors.gray25,
formSwitchBgActive: basicColors.blue95,
formSwitchBgHover: basicColors.gray33,
formSwitchBgActiveHover: basicColors.blue80,
formSwitchBgDisabled: basicColors.gray25,
formSwitchDot: basicColors.gray15,
formCheckboxBgChecked: basicColors.blue95,
formCheckboxBgCheckedHover: basicColors.blue80,
formCheckboxCheckmark: basicColors.gray25,
};
return {
...oldCommon,
type: theme.palette.mode === 'dark' ? GrafanaThemeType.Dark : GrafanaThemeType.Light,
isDark: theme.isDark,
isLight: theme.isLight,
name: theme.name,
palette: {
...basicColors,
brandPrimary: basicColors.orange,
brandSuccess: basicColors.greenBase,
brandWarning: basicColors.orange,
brandDanger: basicColors.redBase,
queryRed: basicColors.redBase,
queryGreen: '#74e680',
queryPurple: '#fe85fc',
queryOrange: basicColors.orange,
online: basicColors.greenBase,
warn: '#f79520',
critical: basicColors.redBase,
},
colors: {
...backgrounds,
...borders,
...form,
...textColors,
bodyBg: theme.palette.background.canvas,
panelBg: theme.components.panel.background,
panelBorder: theme.components.panel.border,
pageHeaderBg: theme.palette.background.canvas,
pageHeaderBorder: theme.palette.background.canvas,
dropdownBg: form.formInputBg,
dropdownShadow: basicColors.black,
dropdownOptionHoverBg: backgrounds.bg2,
link: theme.palette.text.primary,
linkDisabled: theme.palette.text.disabled,
linkHover: theme.palette.text.maxContrast,
linkExternal: theme.palette.text.link,
},
shadows: {
listItem: 'none',
},
};
}
const commonColorsPalette = {
// New greys palette used by next-gen form elements
gray98: '#f7f8fa',
gray97: '#f1f5f9',
gray95: '#e9edf2',
gray90: '#dce1e6',
gray85: '#c7d0d9',
gray70: '#9fa7b3',
gray60: '#7b8087',
gray33: '#464c54',
gray25: '#2c3235',
gray15: '#202226',
gray10: '#141619',
gray05: '#0b0c0e',
// New blues palette used by next-gen form elements
blue95: '#5794f2', // blue95
blue85: '#33a2e5', // blueText
blue80: '#3274d9', // blue80
blue77: '#1f60c4', // blue77
// New reds palette used by next-gen form elements
red88: '#e02f44',
};

View File

@ -1,5 +1,5 @@
export { createTheme, GrafanaThemeV2 } from './createTheme';
export { ThemePaletteColor } from './types';
export { createTheme } from './createTheme';
export { ThemePaletteColor, GrafanaThemeV2 } from './types';
export { ThemePalette } from './createPalette';
export { ThemeBreakpoints } from './breakpoints';
export { ThemeShadows } from './createShadows';

View File

@ -1,3 +1,31 @@
import { GrafanaTheme } from '../types/theme';
import { ThemeBreakpoints } from './breakpoints';
import { ThemeComponents } from './createComponents';
import { ThemePalette } from './createPalette';
import { ThemeShadows } from './createShadows';
import { ThemeShape } from './createShape';
import { ThemeSpacing } from './createSpacing';
import { ThemeTransitions } from './createTransitions';
import { ThemeTypography } from './createTypography';
import { ThemeZIndices } from './zIndex';
/** @beta */
export interface GrafanaThemeV2 {
name: string;
isDark: boolean;
isLight: boolean;
palette: ThemePalette;
breakpoints: ThemeBreakpoints;
spacing: ThemeSpacing;
shape: ThemeShape;
components: ThemeComponents;
typography: ThemeTypography;
zIndex: ThemeZIndices;
shadows: ThemeShadows;
transitions: ThemeTransitions;
v1: GrafanaTheme;
}
/** @alpha */
export interface ThemePaletteColor {
/** color intent (primary, secondary, info, error, etc) */

View File

@ -1,5 +1,3 @@
import { GrafanaThemeV2 } from '../themes/createTheme';
export enum GrafanaThemeType {
Light = 'light',
Dark = 'dark',
@ -113,7 +111,6 @@ export interface GrafanaThemeCommons {
}
export interface GrafanaTheme extends GrafanaThemeCommons {
v2: GrafanaThemeV2;
type: GrafanaThemeType;
isDark: boolean;
isLight: boolean;

View File

@ -6,7 +6,6 @@ import {
FeatureToggles,
GrafanaConfig,
GrafanaTheme,
GrafanaThemeType,
LicenseInfo,
PanelPluginMeta,
systemDateFormats,
@ -76,7 +75,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
awsAssumeRoleEnabled = false;
constructor(options: GrafanaBootConfig) {
this.theme = options.bootData.user.lightTheme ? getTheme(GrafanaThemeType.Light) : getTheme(GrafanaThemeType.Dark);
this.theme = getTheme(options.bootData.user.lightTheme ? 'light' : 'dark');
const defaults = {
datasources: {},

View File

@ -1,41 +1,39 @@
import { GrafanaThemeV2, createTheme } from '@grafana/data';
//@ts-ignore
import { create } from '@storybook/theming/create';
import lightTheme from '../src/themes/light';
import darkTheme from '../src/themes/dark';
import { GrafanaTheme } from '@grafana/data';
import '../src/components/Icon/iconBundle';
const createTheme = (theme: GrafanaTheme) => {
const createStorybookTheme = (theme: GrafanaThemeV2) => {
return create({
base: theme.name.includes('Light') ? 'light' : 'dark',
colorPrimary: theme.v2.palette.primary.main,
colorSecondary: theme.v2.palette.error.main,
colorPrimary: theme.palette.primary.main,
colorSecondary: theme.palette.error.main,
// UI
appBg: theme.v2.palette.background.canvas,
appContentBg: theme.v2.palette.background.primary,
appBorderColor: theme.v2.palette.border.medium,
appBorderRadius: theme.v2.shape.borderRadius(1),
appBg: theme.palette.background.canvas,
appContentBg: theme.palette.background.primary,
appBorderColor: theme.palette.border.medium,
appBorderRadius: theme.shape.borderRadius(1),
// Typography
fontBase: theme.v2.typography.fontFamily,
fontCode: theme.v2.typography.fontFamilyMonospace,
fontBase: theme.typography.fontFamily,
fontCode: theme.typography.fontFamilyMonospace,
// Text colors
textColor: theme.v2.palette.primary.text,
textInverseColor: theme.v2.palette.primary.contrastText,
textColor: theme.palette.primary.text,
textInverseColor: theme.palette.primary.contrastText,
// Toolbar default and active colors
barTextColor: theme.v2.palette.text.primary,
barSelectedColor: theme.v2.palette.emphasize(theme.v2.palette.primary.text),
barBg: theme.v2.palette.background.primary,
barTextColor: theme.palette.text.primary,
barSelectedColor: theme.palette.emphasize(theme.palette.primary.text),
barBg: theme.palette.background.primary,
// Form colors
inputBg: theme.v2.components.input.background,
inputBorder: theme.v2.components.input.border,
inputTextColor: theme.v2.components.input.text,
inputBorderRadius: theme.v2.shape.borderRadius(1),
inputBg: theme.components.input.background,
inputBorder: theme.components.input.border,
inputTextColor: theme.components.input.text,
inputBorderRadius: theme.shape.borderRadius(1),
brandTitle: 'Grafana UI',
brandUrl: './',
@ -43,7 +41,7 @@ const createTheme = (theme: GrafanaTheme) => {
});
};
const GrafanaLight = createTheme(lightTheme);
const GrafanaDark = createTheme(darkTheme);
const GrafanaLight = createStorybookTheme(createTheme({ palette: { mode: 'light' } }));
const GrafanaDark = createStorybookTheme(createTheme({ palette: { mode: 'dark' } }));
export { GrafanaLight, GrafanaDark };

View File

@ -1,8 +1,8 @@
import React, { FC, HTMLAttributes, ReactNode } from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { Icon } from '../Icon/Icon';
import { IconName } from '../../types/icon';
import { IconButton } from '../IconButton/IconButton';
@ -36,7 +36,7 @@ function getIconFromSeverity(severity: AlertVariant): string {
export const Alert: FC<Props> = React.forwardRef<HTMLDivElement, Props>(
({ title, onRemove, children, buttonContent, elevated, severity = 'error', ...restProps }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme, severity, elevated);
return (
@ -68,19 +68,19 @@ export const Alert: FC<Props> = React.forwardRef<HTMLDivElement, Props>(
Alert.displayName = 'Alert';
const getStyles = (theme: GrafanaTheme, severity: AlertVariant, elevated?: boolean) => {
const color = theme.v2.palette[severity];
const getStyles = (theme: GrafanaThemeV2, severity: AlertVariant, elevated?: boolean) => {
const color = theme.palette[severity];
return {
alert: css`
flex-grow: 1;
position: relative;
border-radius: ${theme.v2.shape.borderRadius()};
border-radius: ${theme.shape.borderRadius()};
display: flex;
flex-direction: row;
align-items: stretch;
background: ${theme.v2.palette.background.secondary};
box-shadow: ${elevated ? theme.v2.shadows.z4 : theme.v2.shadows.z1};
background: ${theme.palette.background.secondary};
box-shadow: ${elevated ? theme.shadows.z4 : theme.shadows.z1};
&:before {
content: '';
@ -89,12 +89,12 @@ const getStyles = (theme: GrafanaTheme, severity: AlertVariant, elevated?: boole
left: 0;
bottom: 0;
right: 0;
background: ${theme.v2.palette.background.primary};
background: ${theme.palette.background.primary};
z-index: -1;
}
`,
icon: css`
padding: ${theme.v2.spacing(2, 3)};
padding: ${theme.spacing(2, 3)};
background: ${color.main};
color: ${color.contrastText};
display: flex;
@ -102,12 +102,12 @@ const getStyles = (theme: GrafanaTheme, severity: AlertVariant, elevated?: boole
justify-content: center;
`,
title: css`
font-weight: ${theme.v2.typography.fontWeightMedium};
color: ${theme.v2.palette.text.primary};
font-weight: ${theme.typography.fontWeightMedium};
color: ${theme.palette.text.primary};
`,
body: css`
color: ${theme.v2.palette.text.secondary};
padding: ${theme.v2.spacing(2)};
color: ${theme.palette.text.secondary};
padding: ${theme.spacing(2)};
flex-grow: 1;
display: flex;
flex-direction: column;
@ -116,13 +116,13 @@ const getStyles = (theme: GrafanaTheme, severity: AlertVariant, elevated?: boole
word-break: break-word;
`,
buttonWrapper: css`
padding: ${theme.v2.spacing(1)};
padding: ${theme.spacing(1)};
background: none;
display: flex;
align-items: center;
`,
close: css`
padding: ${theme.v2.spacing(1)};
padding: ${theme.spacing(1)};
background: none;
align-items: center;
display: flex;

View File

@ -17,12 +17,12 @@ export const AlphaNotice: FC<Props> = ({ state, text, className }) => {
const styles = cx(
className,
css`
background: ${theme.v2.palette.primary.transparent};
color: ${theme.v2.palette.text.secondary};
background: ${theme.palette.primary.transparent};
color: ${theme.palette.text.secondary};
white-space: nowrap;
border-radius: 3px;
text-shadow: none;
font-size: ${theme.v2.typography.size.sm};
font-size: ${theme.typography.size.sm};
padding: 0 8px;
cursor: help;
display: inline-block;

View File

@ -30,7 +30,7 @@ exports[`BigValue Render with basic options should render 1`] = `
<FormattedDisplayValue
style={
Object {
"color": "#fff",
"color": "rgb(32, 34, 38)",
"fontSize": 230,
"fontWeight": 500,
"lineHeight": 1.2,

View File

@ -1,9 +1,9 @@
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
import { css, CSSObject, cx } from '@emotion/css';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { IconName } from '../../types/icon';
import { getPropertiesForButtonSize } from '../Forms/commonStyles';
import { colorManipulator, GrafanaTheme, GrafanaThemeV2, ThemePaletteColor } from '@grafana/data';
import { colorManipulator, GrafanaThemeV2, ThemePaletteColor } from '@grafana/data';
import { ComponentSize } from '../../types/size';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
import { Icon } from '../Icon/Icon';
@ -24,7 +24,7 @@ export type ButtonProps = CommonProps & ButtonHTMLAttributes<HTMLButtonElement>;
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'md', icon, fullWidth, children, className, ...otherProps }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getButtonStyles({
theme,
size,
@ -62,7 +62,7 @@ export const LinkButton = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(
},
ref
) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getButtonStyles({
theme,
fullWidth,
@ -88,32 +88,32 @@ export interface StyleProps {
size: ComponentSize;
variant: ButtonVariant;
iconOnly?: boolean;
theme: GrafanaTheme;
theme: GrafanaThemeV2;
fullWidth?: boolean;
narrow?: boolean;
}
export const getButtonStyles = (props: StyleProps) => {
const { theme, variant, size, iconOnly, fullWidth } = props;
const { height, padding, fontSize } = getPropertiesForButtonSize(size, theme.v2);
const variantStyles = getPropertiesForVariant(theme.v2, variant);
const { height, padding, fontSize } = getPropertiesForButtonSize(size, theme);
const variantStyles = getPropertiesForVariant(theme, variant);
const disabledStyles: CSSObject = {
cursor: 'not-allowed',
boxShadow: 'none',
background: theme.v2.palette.action.disabledBackground,
background: theme.palette.action.disabledBackground,
border: `1px solid transparent`,
color: theme.v2.palette.text.disabled,
color: theme.palette.text.disabled,
pointerEvents: 'none',
'&:hover': {
background: theme.v2.palette.action.disabledBackground,
color: theme.v2.palette.text.disabled,
background: theme.palette.action.disabledBackground,
color: theme.palette.text.disabled,
boxShadow: 'none',
},
};
const focusStyle = getFocusStyles(theme.v2);
const focusStyle = getFocusStyles(theme);
return {
button: css({
@ -121,18 +121,18 @@ export const getButtonStyles = (props: StyleProps) => {
display: 'inline-flex',
alignItems: 'center',
fontSize: fontSize,
fontWeight: theme.v2.typography.fontWeightMedium,
fontFamily: theme.v2.typography.fontFamily,
padding: theme.v2.spacing(0, padding),
height: theme.v2.spacing(height),
fontWeight: theme.typography.fontWeightMedium,
fontFamily: theme.typography.fontFamily,
padding: theme.spacing(0, padding),
height: theme.spacing(height),
// Deduct border from line-height for perfect vertical centering on windows and linux
lineHeight: `${theme.v2.spacing.gridSize * height - 2}px`,
lineHeight: `${theme.spacing.gridSize * height - 2}px`,
verticalAlign: 'middle',
cursor: 'pointer',
borderRadius: theme.v2.shape.borderRadius(1),
borderRadius: theme.shape.borderRadius(1),
'&:focus': focusStyle,
'&:focus-visible': focusStyle,
'&:focus:not(:focus-visible)': getMouseFocusStyles(theme.v2),
'&:focus:not(:focus-visible)': getMouseFocusStyles(theme),
...(fullWidth && {
flexGrow: 1,
justifyContent: 'center',
@ -145,10 +145,10 @@ export const getButtonStyles = (props: StyleProps) => {
img: css`
width: 16px;
height: 16px;
margin: ${theme.v2.spacing(0, 1, 0, 0.5)};
margin: ${theme.spacing(0, 1, 0, 0.5)};
`,
icon: css`
margin: ${theme.v2.spacing(0, (iconOnly ? -padding : padding) / 2, 0, -(padding / 2))};
margin: ${theme.spacing(0, (iconOnly ? -padding : padding) / 2, 0, -(padding / 2))};
`,
content: css`
display: flex;

View File

@ -1,14 +1,14 @@
import React, { forwardRef, ButtonHTMLAttributes } from 'react';
import { cx, css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { styleMixins, useStyles } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { styleMixins, useStyles2 } from '../../themes';
import { IconName } from '../../types/icon';
import { Tooltip } from '../Tooltip/Tooltip';
import { Icon } from '../Icon/Icon';
import { getPropertiesForVariant } from './Button';
import { isString } from 'lodash';
import { selectors } from '@grafana/e2e-selectors';
import { focusCss, getMouseFocusStyles } from '../../themes/mixins';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
export interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
/** Icon name */
@ -49,7 +49,7 @@ export const ToolbarButton = forwardRef<HTMLButtonElement, Props>(
},
ref
) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const buttonStyles = cx(
'toolbar-button',
@ -104,81 +104,82 @@ function renderIcon(icon: IconName | React.ReactNode) {
return icon;
}
const getStyles = (theme: GrafanaTheme) => {
const primaryVariant = getPropertiesForVariant(theme.v2, 'primary');
const destructiveVariant = getPropertiesForVariant(theme.v2, 'destructive');
const getStyles = (theme: GrafanaThemeV2) => {
const primaryVariant = getPropertiesForVariant(theme, 'primary');
const destructiveVariant = getPropertiesForVariant(theme, 'destructive');
return {
button: css`
label: toolbar-button;
display: flex;
align-items: center;
height: ${theme.v2.spacing(theme.v2.components.height.md)};
padding: ${theme.v2.spacing(0, 1)};
border-radius: ${theme.v2.shape.borderRadius()};
line-height: ${theme.v2.components.height.md * theme.v2.spacing.gridSize - 2}px;
font-weight: ${theme.v2.typography.fontWeightMedium};
border: 1px solid ${theme.v2.palette.border.medium};
height: ${theme.spacing(theme.components.height.md)};
padding: ${theme.spacing(0, 1)};
border-radius: ${theme.shape.borderRadius()};
line-height: ${theme.components.height.md * theme.spacing.gridSize - 2}px;
font-weight: ${theme.typography.fontWeightMedium};
border: 1px solid ${theme.palette.border.medium};
white-space: nowrap;
transition: ${theme.v2.transitions.create(['background', 'box-shadow', 'border-color', 'color'], {
duration: theme.v2.transitions.duration.short,
transition: ${theme.transitions.create(['background', 'box-shadow', 'border-color', 'color'], {
duration: theme.transitions.duration.short,
})};
&:focus,
&:focus-visible {
${focusCss(theme)}
${getFocusStyles(theme)}
z-index: 1;
}
&:focus:not(:focus-visible) {
${getMouseFocusStyles(theme.v2)}
${getMouseFocusStyles(theme)}
}
&:hover {
box-shadow: ${theme.v2.shadows.z2};
box-shadow: ${theme.shadows.z2};
}
&[disabled],
&:disabled {
cursor: not-allowed;
opacity: ${theme.v2.palette.action.disabledOpacity};
background: ${theme.v2.palette.action.disabledBackground};
opacity: ${theme.palette.action.disabledOpacity};
background: ${theme.palette.action.disabledBackground};
box-shadow: none;
&:hover {
color: ${theme.v2.palette.text.disabled};
background: ${theme.v2.palette.action.disabledBackground};
color: ${theme.palette.text.disabled};
background: ${theme.palette.action.disabledBackground};
box-shadow: none;
}
}
`,
default: css`
color: ${theme.v2.palette.text.secondary};
background-color: ${theme.v2.palette.background.primary};
color: ${theme.palette.text.secondary};
background-color: ${theme.palette.background.primary};
&:hover {
color: ${theme.v2.palette.text.primary};
background: ${theme.v2.palette.background.secondary};
color: ${theme.palette.text.primary};
background: ${theme.palette.background.secondary};
}
`,
active: css`
color: ${theme.palette.orangeDark};
border-color: ${theme.palette.orangeDark};
color: ${theme.v1.palette.orangeDark};
border-color: ${theme.v1.palette.orangeDark};
background-color: transparent;
&:hover {
color: ${theme.colors.text};
background: ${styleMixins.hoverColor(theme.colors.bg1, theme)};
color: ${theme.palette.text.primary};
background: ${theme.palette.emphasize(theme.palette.background.canvas, 0.03)};
}
`,
primary: css(primaryVariant),
destructive: css(destructiveVariant),
narrow: css`
padding: 0 ${theme.spacing.xs};
padding: 0 ${theme.spacing(0.5)};
`,
img: css`
width: 16px;
height: 16px;
margin-right: ${theme.spacing.sm};
margin-right: ${theme.spacing(1)};
`,
buttonFullWidth: css`
flex-grow: 1;
@ -188,14 +189,14 @@ const getStyles = (theme: GrafanaTheme) => {
`,
contentWithIcon: css`
display: none;
padding-left: ${theme.spacing.sm};
padding-left: ${theme.spacing(1)};
@media ${styleMixins.mediaUp(theme.breakpoints.md)} {
@media ${styleMixins.mediaUp(theme.v1.breakpoints.md)} {
display: block;
}
`,
contentWithRightIcon: css`
padding-right: ${theme.spacing.xs};
padding-right: ${theme.spacing(0.5)};
`,
};
};

View File

@ -2,7 +2,7 @@
exports[`CallToActionCard rendering when message and footer provided 1`] = `
<div
class="css-1wsd3n2-call-to-action-card"
class="css-xtd6ws-call-to-action-card"
>
<div
class="css-m2iibx"
@ -24,7 +24,7 @@ exports[`CallToActionCard rendering when message and footer provided 1`] = `
exports[`CallToActionCard rendering when message and no footer provided 1`] = `
<div
class="css-1wsd3n2-call-to-action-card"
class="css-xtd6ws-call-to-action-card"
>
<div
class="css-m2iibx"
@ -41,7 +41,7 @@ exports[`CallToActionCard rendering when message and no footer provided 1`] = `
exports[`CallToActionCard rendering when no message and footer provided 1`] = `
<div
class="css-1wsd3n2-call-to-action-card"
class="css-xtd6ws-call-to-action-card"
>
<a
href="http://dummy.link"

View File

@ -1,7 +1,7 @@
import React, { memo, cloneElement, FC, HTMLAttributes, ReactNode, useCallback } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { useTheme, styleMixins, stylesFactory } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { useTheme2, styleMixins, stylesFactory } from '../../themes';
import { Tooltip, PopoverContent } from '../Tooltip/Tooltip';
/**
@ -30,7 +30,7 @@ export interface CardInnerProps {
}
const CardInner: FC<CardInnerProps> = ({ children, href }) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getCardStyles(theme);
return href ? (
<a className={styles.innerLink} href={href}>
@ -81,7 +81,7 @@ export const Card: CardInterface = ({
children,
...htmlProps
}) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getCardStyles(theme);
const [tags, figure, meta, actions, secondaryActions] = ['Tags', 'Figure', 'Meta', 'Actions', 'SecondaryActions'].map(
(item) => {
@ -136,26 +136,26 @@ export const Card: CardInterface = ({
);
};
const getContainerStyles = stylesFactory((theme: GrafanaTheme, disabled = false, disableHover = false) => {
const getContainerStyles = stylesFactory((theme: GrafanaThemeV2, disabled = false, disableHover = false) => {
return css({
display: 'flex',
width: '100%',
background: theme.v2.palette.background.secondary,
borderRadius: theme.v2.shape.borderRadius(),
background: theme.palette.background.secondary,
borderRadius: theme.shape.borderRadius(),
position: 'relative',
pointerEvents: disabled ? 'none' : 'auto',
marginBottom: theme.v2.spacing(1),
transition: theme.v2.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
duration: theme.v2.transitions.duration.short,
marginBottom: theme.spacing(1),
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
duration: theme.transitions.duration.short,
}),
...(!disableHover && {
'&:hover': {
background: theme.v2.palette.emphasize(theme.v2.palette.background.secondary, 0.03),
background: theme.palette.emphasize(theme.palette.background.secondary, 0.03),
cursor: 'pointer',
zIndex: 1,
},
'&:focus': styleMixins.getFocusStyles(theme.v2),
'&:focus': styleMixins.getFocusStyles(theme),
}),
});
});
@ -163,7 +163,7 @@ const getContainerStyles = stylesFactory((theme: GrafanaTheme, disabled = false,
/**
* @public
*/
export const getCardStyles = stylesFactory((theme: GrafanaTheme) => {
export const getCardStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
inner: css`
display: flex;
@ -179,9 +179,9 @@ export const getCardStyles = stylesFactory((theme: GrafanaTheme) => {
width: 100%;
margin-bottom: 0;
font-size: ${theme.typography.size.md};
line-height: ${theme.typography.lineHeight.xs};
color: ${theme.colors.text};
font-weight: ${theme.typography.weight.semibold};
line-height: ${theme.typography.body.lineHeight};
color: ${theme.palette.text.primary};
font-weight: ${theme.typography.fontWeightMedium};
`,
info: css`
display: flex;
@ -195,18 +195,18 @@ export const getCardStyles = stylesFactory((theme: GrafanaTheme) => {
align-items: center;
width: 100%;
font-size: ${theme.typography.size.sm};
color: ${theme.colors.textSemiWeak};
margin: ${theme.spacing.xs} 0 0;
line-height: ${theme.typography.lineHeight.xs};
color: ${theme.palette.text.secondary};
margin: ${theme.spacing(0.5, 0, 0)};
line-height: ${theme.typography.bodySmall.lineHeight};
`,
description: css`
width: 100%;
margin: ${theme.spacing.sm} 0 0;
color: ${theme.colors.textSemiWeak};
line-height: ${theme.typography.lineHeight.md};
margin: ${theme.spacing(1, 0, 0)};
color: ${theme.palette.text.secondary};
line-height: ${theme.typography.body.lineHeight};
`,
media: css`
margin-right: ${theme.spacing.md};
margin-right: ${theme.spacing(2)};
width: 40px;
display: flex;
align-items: center;
@ -224,30 +224,30 @@ export const getCardStyles = stylesFactory((theme: GrafanaTheme) => {
justify-content: space-between;
align-items: center;
width: 100%;
margin-top: ${theme.spacing.md};
margin-top: ${theme.spacing(2)};
`,
actions: css`
& > * {
margin-right: ${theme.spacing.sm};
margin-right: ${theme.spacing(1)};
}
`,
secondaryActions: css`
display: flex;
align-items: center;
color: ${theme.colors.textSemiWeak};
color: ${theme.palette.text.secondary};
// align to the right
margin-left: auto;
& > * {
margin-right: ${theme.spacing.sm} !important;
margin-right: ${theme.spacing(1)} !important;
}
`,
separator: css`
margin: 0 ${theme.spacing.sm};
margin: 0 ${theme.spacing(1)};
`,
innerLink: css`
display: flex;
width: 100%;
padding: ${theme.spacing.md};
padding: ${theme.spacing(2)};
`,
tagList: css`
max-width: 50%;

View File

@ -1,12 +1,11 @@
import React, { FunctionComponent, useContext, useState } from 'react';
import React, { FunctionComponent, useState } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { ThemeContext } from '../../themes/ThemeContext';
import { stylesFactory } from '../../themes/stylesFactory';
import { useStyles } from '../../themes/ThemeContext';
import { Icon } from '../Icon/Icon';
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaTheme) => ({
collapse: css`
label: collapse;
margin-bottom: ${theme.spacing.sm};
@ -89,7 +88,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
margin-right: ${theme.spacing.sm};
font-size: ${theme.typography.heading.h6};
`,
}));
});
export interface Props {
/** Expand or collapse te content */
@ -131,8 +130,7 @@ export const Collapse: FunctionComponent<Props> = ({
className,
children,
}) => {
const theme = useContext(ThemeContext);
const style = getStyles(theme);
const style = useStyles(getStyles);
const onClickToggle = () => {
if (onToggle) {
onToggle(!isOpen);

View File

@ -3,8 +3,8 @@ import { css } from '@emotion/css';
import { Modal } from '../Modal/Modal';
import { IconName } from '../../types/icon';
import { Button } from '../Button';
import { useStyles } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { HorizontalGroup, Input } from '..';
import { selectors } from '@grafana/e2e-selectors';
@ -50,7 +50,7 @@ export const ConfirmModal = ({
onAlternative,
}: ConfirmModalProps): JSX.Element => {
const [disabled, setDisabled] = useState(Boolean(confirmationText));
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const onConfirmationTextChange = (event: React.FormEvent<HTMLInputElement>) => {
setDisabled(confirmationText?.localeCompare(event.currentTarget.value) !== 0);
};
@ -92,7 +92,7 @@ export const ConfirmModal = ({
);
};
const getStyles = (theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaThemeV2) => ({
modal: css`
width: 500px;
`,
@ -100,16 +100,16 @@ const getStyles = (theme: GrafanaTheme) => ({
text-align: center;
`,
modalText: css({
fontSize: theme.v2.typography.h4.fontSize,
color: theme.v2.palette.text.primary,
marginBottom: `calc(${theme.v2.spacing(2)}*2)`,
paddingTop: theme.v2.spacing(2),
fontSize: theme.typography.h4.fontSize,
color: theme.palette.text.primary,
marginBottom: `calc(${theme.spacing(2)}*2)`,
paddingTop: theme.spacing(2),
}),
modalDescription: css({
fontSize: theme.v2.typography.h6.fontSize,
paddingTop: theme.v2.spacing(2),
fontSize: theme.typography.h6.fontSize,
paddingTop: theme.spacing(2),
}),
modalConfirmationInput: css({
paddingTop: theme.v2.spacing(2),
paddingTop: theme.spacing(2),
}),
});

View File

@ -3,8 +3,8 @@ import { isNil } from 'lodash';
import classNames from 'classnames';
import { css } from '@emotion/css';
import Scrollbars from 'react-custom-scrollbars';
import { useStyles } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
interface Props {
className?: string;
@ -38,7 +38,7 @@ export const CustomScrollbar: FC<Props> = ({
children,
}) => {
const ref = useRef<Scrollbars>(null);
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const updateScroll = () => {
if (ref.current && !isNil(scrollTop)) {
@ -127,7 +127,7 @@ export const CustomScrollbar: FC<Props> = ({
export default CustomScrollbar;
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
customScrollbar: css`
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to
@ -141,27 +141,27 @@ const getStyles = (theme: GrafanaTheme) => {
flex-direction: column;
}
.track-vertical {
border-radius: ${theme.border.radius.md};
width: ${theme.spacing.sm} !important;
border-radius: ${theme.shape.borderRadius(2)};
width: ${theme.spacing(1)} !important;
right: 0px;
bottom: ${theme.spacing.xxs};
top: ${theme.spacing.xxs};
bottom: ${theme.spacing(0.25)};
top: ${theme.spacing(0.25)};
}
.track-horizontal {
border-radius: ${theme.border.radius.md};
height: ${theme.spacing.sm} !important;
right: ${theme.spacing.xxs};
bottom: ${theme.spacing.xxs};
left: ${theme.spacing.xxs};
border-radius: ${theme.shape.borderRadius(2)};
height: ${theme.spacing(1)} !important;
right: ${theme.spacing(0.25)};
bottom: ${theme.spacing(0.25)};
left: ${theme.spacing(0.25)};
}
.thumb-vertical {
background: ${theme.v2.palette.action.focus};
border-radius: ${theme.border.radius.md};
background: ${theme.palette.action.focus};
border-radius: ${theme.shape.borderRadius(2)};
opacity: 0;
}
.thumb-horizontal {
background: ${theme.v2.palette.action.focus};
border-radius: ${theme.border.radius.md};
background: ${theme.palette.action.focus};
border-radius: ${theme.shape.borderRadius(2)};
opacity: 0;
}
&:hover {

View File

@ -2,7 +2,7 @@
exports[`CustomScrollbar renders correctly 1`] = `
<div
className="css-d4ozb2"
className="css-ccjpr2"
style={
Object {
"height": "auto",

View File

@ -1,8 +1,8 @@
import React, { ChangeEvent, useContext } from 'react';
import React, { ChangeEvent } from 'react';
import { VariableSuggestion, GrafanaTheme, DataLink } from '@grafana/data';
import { Switch } from '../Switch/Switch';
import { css } from '@emotion/css';
import { ThemeContext, stylesFactory } from '../../themes/index';
import { useStyles } from '../../themes/index';
import { DataLinkInput } from './DataLinkInput';
import { Field } from '../Forms/Field';
import { Input } from '../Input/Input';
@ -15,7 +15,7 @@ interface DataLinkEditorProps {
onChange: (index: number, link: DataLink, callback?: () => void) => void;
}
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaTheme) => ({
listItem: css`
margin-bottom: ${theme.spacing.sm};
`,
@ -24,12 +24,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
margin-left: 66px;
color: ${theme.colors.textWeak};
`,
}));
});
export const DataLinkEditor: React.FC<DataLinkEditorProps> = React.memo(
({ index, value, onChange, suggestions, isLast }) => {
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
const styles = useStyles(getStyles);
const onUrlChange = (url: string, callback?: () => void) => {
onChange(index, { ...value, url }, callback);

View File

@ -1,7 +1,7 @@
import React, { memo, RefObject, useContext, useEffect, useMemo, useRef, useState } from 'react';
import React, { memo, RefObject, useEffect, useMemo, useRef, useState } from 'react';
import usePrevious from 'react-use/lib/usePrevious';
import { DataLinkSuggestions } from './DataLinkSuggestions';
import { makeValue, ThemeContext } from '../../index';
import { makeValue } from '../../index';
import { SelectionReference } from './SelectionReference';
import { Portal } from '../index';
@ -15,8 +15,8 @@ import { css, cx } from '@emotion/css';
import { SlatePrism } from '../../slate-plugins';
import { SCHEMA } from '../../utils/slate';
import { stylesFactory } from '../../themes';
import { DataLinkBuiltInVars, GrafanaTheme, VariableOrigin, VariableSuggestion } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { DataLinkBuiltInVars, GrafanaThemeV2, VariableOrigin, VariableSuggestion } from '@grafana/data';
import { getInputStyles } from '../Input/Input';
const modulo = (a: number, n: number) => a - n * Math.floor(a / n);
@ -44,14 +44,14 @@ const plugins = [
),
];
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaThemeV2) => ({
input: getInputStyles({ theme, invalid: false }).input,
editor: css`
.token.builtInVariable {
color: ${theme.palette.queryGreen};
color: ${theme.palette.success.text};
}
.token.variable {
color: ${theme.colors.textBlue};
color: ${theme.palette.primary.text};
}
`,
// Wrapper with child selector needed.
@ -64,15 +64,14 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
border: none;
}
`,
}));
});
// This memoised also because rerendering the slate editor grabs focus which created problem in some cases this
// was used and changes to different state were propagated here.
export const DataLinkInput: React.FC<DataLinkInputProps> = memo(
({ value, onChange, suggestions, placeholder = 'http://your-grafana.com/d/000000010/annotations' }) => {
const editorRef = useRef<Editor>() as RefObject<Editor>;
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
const styles = useStyles2(getStyles);
const [showingSuggestions, setShowingSuggestions] = useState(false);
const [suggestionsIndex, setSuggestionsIndex] = useState(0);
const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value));

View File

@ -1,11 +1,10 @@
import { ThemeContext } from '../../index';
import { GrafanaTheme, VariableSuggestion } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { groupBy, capitalize } from 'lodash';
import React, { useRef, useContext, useMemo } from 'react';
import React, { useRef, useMemo } from 'react';
import useClickAway from 'react-use/lib/useClickAway';
import { List } from '../index';
import { styleMixins, stylesFactory } from '../../themes';
import { styleMixins, useStyles } from '../../themes';
interface DataLinkSuggestionsProps {
suggestions: VariableSuggestion[];
@ -14,7 +13,7 @@ interface DataLinkSuggestionsProps {
onClose?: () => void;
}
const getStyles = stylesFactory((theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaTheme) => {
const wrapperBg = theme.colors.bg1;
const wrapperShadow = theme.colors.dropdownShadow;
const itemColor = theme.colors.text;
@ -58,11 +57,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
font-size: ${theme.typography.size.sm};
`,
};
});
};
export const DataLinkSuggestions: React.FC<DataLinkSuggestionsProps> = ({ suggestions, ...otherProps }) => {
const ref = useRef(null);
const theme = useContext(ThemeContext);
useClickAway(ref, () => {
if (otherProps.onClose) {
otherProps.onClose();
@ -73,7 +72,8 @@ export const DataLinkSuggestions: React.FC<DataLinkSuggestionsProps> = ({ sugges
return groupBy(suggestions, (s) => s.origin);
}, [suggestions]);
const styles = getStyles(theme);
const styles = useStyles(getStyles);
return (
<div ref={ref} className={styles.wrapper}>
{Object.keys(groupedSuggestions).map((key, i) => {
@ -111,8 +111,7 @@ interface DataLinkSuggestionsListProps extends DataLinkSuggestionsProps {
const DataLinkSuggestionsList: React.FC<DataLinkSuggestionsListProps> = React.memo(
({ activeIndex, activeIndexOffset, label, onClose, onSuggestionSelect, suggestions }) => {
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
const styles = useStyles(getStyles);
return (
<>

View File

@ -1,8 +1,8 @@
import React, { FC, FormEvent, useCallback, useState } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { Icon } from '../index';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { ComponentSize } from '../../types/size';
import { getButtonStyles } from '../Button';
@ -37,7 +37,7 @@ export const FileUpload: FC<Props> = ({
accept = '*',
size = 'md',
}) => {
const theme = useTheme();
const theme = useTheme2();
const style = getStyles(theme, size);
const [fileName, setFileName] = useState('');
@ -75,7 +75,7 @@ export const FileUpload: FC<Props> = ({
);
};
const getStyles = stylesFactory((theme: GrafanaTheme, size: ComponentSize) => {
const getStyles = stylesFactory((theme: GrafanaThemeV2, size: ComponentSize) => {
const buttonStyles = getButtonStyles({ theme, variant: 'primary', size, iconOnly: false });
return {
fileUpload: css`
@ -84,7 +84,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme, size: ComponentSize) => {
button: buttonStyles.button,
icon: buttonStyles.icon,
fileName: css`
margin-left: ${theme.spacing.xs};
margin-left: ${theme.spacing(0.5)};
`,
};
});

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { stylesFactory, ThemeContext } from '../../themes';
import React from 'react';
import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css';
import { IconButton } from '../IconButton/IconButton';
@ -13,7 +13,7 @@ export interface FilterPillProps {
}
export const FilterPill: React.FC<FilterPillProps> = ({ label, selected, onClick, icon = 'check' }) => {
const theme = useContext(ThemeContext);
const theme = useTheme();
const styles = getFilterPillStyles(theme, selected);
return (
<div className={styles.wrapper} onClick={onClick}>

View File

@ -1,6 +1,6 @@
import React from 'react';
import { useTheme, stylesFactory } from '../../../themes';
import { GrafanaTheme } from '@grafana/data';
import { useTheme2, stylesFactory } from '../../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { getPropertiesForButtonSize } from '../commonStyles';
import { getFocusStyles, getMouseFocusStyles } from '../../../themes/mixins';
@ -29,7 +29,7 @@ export const RadioButton: React.FC<RadioButtonProps> = ({
description,
fullWidth,
}) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getRadioButtonStyles(theme, size, fullWidth);
return (
@ -52,14 +52,14 @@ export const RadioButton: React.FC<RadioButtonProps> = ({
RadioButton.displayName = 'RadioButton';
const getRadioButtonStyles = stylesFactory((theme: GrafanaTheme, size: RadioButtonSize, fullWidth?: boolean) => {
const { fontSize, height, padding } = getPropertiesForButtonSize(size, theme.v2);
const getRadioButtonStyles = stylesFactory((theme: GrafanaThemeV2, size: RadioButtonSize, fullWidth?: boolean) => {
const { fontSize, height, padding } = getPropertiesForButtonSize(size, theme);
const textColor = theme.v2.palette.text.secondary;
const textColorHover = theme.v2.palette.text.primary;
const bg = theme.v2.components.input.background;
const textColor = theme.palette.text.secondary;
const textColorHover = theme.palette.text.primary;
const bg = theme.components.input.background;
// remove the group inner padding (set on RadioButtonGroup)
const labelHeight = height * theme.v2.spacing.gridSize - 4 - 2;
const labelHeight = height * theme.spacing.gridSize - 4 - 2;
return {
radio: css`
@ -68,24 +68,24 @@ const getRadioButtonStyles = stylesFactory((theme: GrafanaTheme, size: RadioButt
z-index: -1000;
&:checked + label {
color: ${theme.v2.palette.text.primary};
font-weight: ${theme.v2.typography.fontWeightMedium};
background: ${theme.v2.palette.action.selected};
color: ${theme.palette.text.primary};
font-weight: ${theme.typography.fontWeightMedium};
background: ${theme.palette.action.selected};
z-index: 3;
}
&:focus + label,
&:focus-visible + label {
${getFocusStyles(theme.v2)};
${getFocusStyles(theme)};
}
&:focus:not(:focus-visible) + label {
${getMouseFocusStyles(theme.v2)}
${getMouseFocusStyles(theme)}
}
&:disabled + label {
cursor: default;
color: ${theme.v2.palette.text.disabled};
color: ${theme.palette.text.disabled};
cursor: not-allowed;
}
`,
@ -97,8 +97,8 @@ const getRadioButtonStyles = stylesFactory((theme: GrafanaTheme, size: RadioButt
// Deduct border from line-height for perfect vertical centering on windows and linux
line-height: ${labelHeight}px;
color: ${textColor};
padding: ${theme.v2.spacing(0, padding)};
border-radius: ${theme.v2.shape.borderRadius()};
padding: ${theme.spacing(0, padding)};
border-radius: ${theme.shape.borderRadius()};
background: ${bg};
cursor: pointer;
z-index: 1;

View File

@ -1,11 +1,11 @@
import React, { useCallback, useRef } from 'react';
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
import { GrafanaThemeV2, SelectableValue } from '@grafana/data';
import { RadioButtonSize, RadioButton } from './RadioButton';
import { Icon } from '../../Icon/Icon';
import { IconName } from '../../../types/icon';
import { useStyles } from '../../../themes';
import { useStyles2 } from '../../../themes';
export interface RadioButtonGroupProps<T> {
value?: T;
@ -40,7 +40,7 @@ export function RadioButtonGroup<T>({
);
const id = uniqueId('radiogroup-');
const groupName = useRef(id);
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.radioGroup, fullWidth && styles.fullWidth, className)}>
@ -69,14 +69,14 @@ export function RadioButtonGroup<T>({
RadioButtonGroup.displayName = 'RadioButtonGroup';
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
radioGroup: css({
display: 'inline-flex',
flexDirection: 'row',
flexWrap: 'nowrap',
border: `1px solid ${theme.v2.components.input.border}`,
borderRadius: theme.v2.shape.borderRadius(),
border: `1px solid ${theme.components.input.border}`,
borderRadius: theme.shape.borderRadius(),
padding: '2px',
}),
fullWidth: css({

View File

@ -9,19 +9,19 @@ export const getFocusStyle = (theme: GrafanaTheme) => css`
}
`;
export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
const borderColor = invalid ? theme.v2.palette.error.border : theme.v2.components.input.border;
const borderColorHover = invalid ? theme.v2.palette.error.shade : theme.v2.components.input.borderHover;
const background = theme.v2.components.input.background;
const textColor = theme.v2.components.input.text;
export const sharedInputStyle = (theme: GrafanaThemeV2, invalid = false) => {
const borderColor = invalid ? theme.palette.error.border : theme.components.input.border;
const borderColorHover = invalid ? theme.palette.error.shade : theme.components.input.borderHover;
const background = theme.components.input.background;
const textColor = theme.components.input.text;
return css`
background: ${background};
line-height: ${theme.v2.typography.body.lineHeight};
font-size: ${theme.v2.typography.size.md};
line-height: ${theme.typography.body.lineHeight};
font-size: ${theme.typography.size.md};
color: ${textColor};
border: 1px solid ${borderColor};
padding: ${theme.v2.spacing(0, 1, 0, 1)};
padding: ${theme.spacing(0, 1, 0, 1)};
&:-webkit-autofill,
&:-webkit-autofill:hover {
@ -32,7 +32,7 @@ export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
&:-webkit-autofill:focus {
/* Welcome to 2005. This is a HACK to get rid od Chromes default autofill styling */
box-shadow: 0 0 0 2px ${theme.colors.bodyBg}, 0 0 0px 4px ${theme.colors.formFocusOutline},
box-shadow: 0 0 0 2px ${theme.palette.background.primary}, 0 0 0px 4px ${theme.palette.primary.main},
inset 0 0 0 1px rgba(255, 255, 255, 0), inset 0 0 0 100px ${background}!important;
-webkit-text-fill-color: ${textColor} !important;
}
@ -46,9 +46,9 @@ export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
}
&:disabled {
background-color: ${theme.v2.palette.action.disabledBackground};
color: ${theme.v2.palette.action.disabledText};
border: 1px solid ${theme.v2.palette.action.disabledBackground};
background-color: ${theme.palette.action.disabledBackground};
color: ${theme.palette.action.disabledText};
border: 1px solid ${theme.palette.action.disabledBackground};
&:hover {
border-color: ${borderColor};
@ -56,7 +56,7 @@ export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
}
&::placeholder {
color: ${theme.v2.palette.text.disabled};
color: ${theme.palette.text.disabled};
opacity: 1;
}
`;

View File

@ -1,5 +1,5 @@
import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { getLabelStyles } from './Label';
import { getLegendStyles } from './Legend';
import { getFieldValidationMessageStyles } from './FieldValidationMessage';
@ -10,20 +10,20 @@ import { getCheckboxStyles } from './Checkbox';
/** @deprecated */
export const getFormStyles = stylesFactory(
(theme: GrafanaTheme, options: { variant: ButtonVariant; size: ComponentSize; invalid: boolean }) => {
(theme: GrafanaThemeV2, options: { variant: ButtonVariant; size: ComponentSize; invalid: boolean }) => {
console.warn('getFormStyles is deprecated');
return {
label: getLabelStyles(theme),
legend: getLegendStyles(theme),
fieldValidationMessage: getFieldValidationMessageStyles(theme),
label: getLabelStyles(theme.v1),
legend: getLegendStyles(theme.v1),
fieldValidationMessage: getFieldValidationMessageStyles(theme.v1),
button: getButtonStyles({
theme,
variant: options.variant,
size: options.size,
}),
input: getInputStyles({ theme, invalid: options.invalid }),
checkbox: getCheckboxStyles(theme),
checkbox: getCheckboxStyles(theme.v1),
};
}
);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { css } from '@emotion/css';
import { IconButton } from '@grafana/ui';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { IconSize, IconName } from '../../types';
import mdx from './IconButton.mdx';
@ -32,7 +32,7 @@ interface ScenarioProps {
}
const RenderScenario = ({ background }: ScenarioProps) => {
const theme = useTheme();
const theme = useTheme2();
const sizes: IconSize[] = ['sm', 'md', 'lg', 'xl', 'xxl'];
const icons: IconName[] = ['search', 'trash-alt', 'arrow-left', 'times'];
@ -40,7 +40,7 @@ const RenderScenario = ({ background }: ScenarioProps) => {
<div
className={css`
padding: 30px;
background: ${theme.v2.palette.background[background]};
background: ${theme.palette.background[background]};
button {
margin-right: 8px;
margin-left: 8px;

View File

@ -3,11 +3,11 @@ import { Icon, getSvgSize } from '../Icon/Icon';
import { IconName, IconSize, IconType } from '../../types/icon';
import { stylesFactory } from '../../themes/stylesFactory';
import { css, cx } from '@emotion/css';
import { useTheme } from '../../themes/ThemeContext';
import { GrafanaTheme } from '@grafana/data';
import { useTheme2 } from '../../themes/ThemeContext';
import { GrafanaThemeV2 } from '@grafana/data';
import { Tooltip } from '../Tooltip/Tooltip';
import { TooltipPlacement } from '../Tooltip/PopoverController';
import { focusCss, getMouseFocusStyles } from '../../themes/mixins';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
export interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
/** Name of the icon **/
@ -28,7 +28,7 @@ type SurfaceType = 'dashboard' | 'panel' | 'header';
export const IconButton = React.forwardRef<HTMLButtonElement, Props>(
({ name, size = 'md', iconType, tooltip, tooltipPlacement, className, ...restProps }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme, size);
const button = (
@ -51,8 +51,8 @@ export const IconButton = React.forwardRef<HTMLButtonElement, Props>(
IconButton.displayName = 'IconButton';
const getStyles = stylesFactory((theme: GrafanaTheme, size: IconSize) => {
const hoverColor = theme.v2.palette.action.hover;
const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => {
const hoverColor = theme.palette.action.hover;
const pixelSize = getSvgSize(size);
const hoverSize = pixelSize / 2;
@ -70,9 +70,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme, size: IconSize) => {
align-items: center;
justify-content: center;
position: relative;
border-radius: ${theme.v2.shape.borderRadius()};
border-radius: ${theme.shape.borderRadius()};
z-index: 0;
margin-right: ${theme.spacing.xs};
margin-right: ${theme.spacing(0.5)};
&[disabled],
&:disabled {
@ -102,15 +102,15 @@ const getStyles = stylesFactory((theme: GrafanaTheme, size: IconSize) => {
&:focus,
&:focus-visible {
${focusCss(theme)}
${getFocusStyles(theme)}
}
&:focus:not(:focus-visible) {
${getMouseFocusStyles(theme.v2)}
${getMouseFocusStyles(theme)}
}
&:hover {
color: ${theme.colors.linkHover};
color: ${theme.palette.text.primary};
&:before {
background-color: ${hoverColor};

View File

@ -1,13 +1,13 @@
import React from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { Icon } from '../Icon/Icon';
import { IconButton } from '../IconButton/IconButton';
import { HorizontalGroup } from '../Layout/Layout';
import { AlertVariant } from '../Alert/Alert';
import panelArtDark from './panelArt_dark.svg';
import panelArtLight from './panelArt_light.svg';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
export interface InfoBoxProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
children: React.ReactNode;
@ -31,7 +31,7 @@ export interface InfoBoxProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
export const InfoBox = React.memo(
React.forwardRef<HTMLDivElement, InfoBoxProps>(
({ title, className, children, branded, url, urlTitle, onDismiss, severity = 'info', ...otherProps }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getInfoBoxStyles(theme, severity);
const wrapperClassName = cx(branded ? styles.wrapperBranded : styles.wrapper, className);
@ -56,25 +56,25 @@ export const InfoBox = React.memo(
);
InfoBox.displayName = 'InfoBox';
const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVariant) => {
const color = theme.v2.palette[severity];
const getInfoBoxStyles = stylesFactory((theme: GrafanaThemeV2, severity: AlertVariant) => {
const color = theme.palette[severity];
return {
wrapper: css`
position: relative;
padding: ${theme.spacing.md};
background-color: ${theme.colors.bg2};
padding: ${theme.v1.spacing.md};
background-color: ${theme.v1.colors.bg2};
border-left: 3px solid ${color.border};
margin-bottom: ${theme.spacing.md};
margin-bottom: ${theme.v1.spacing.md};
flex-grow: 1;
color: ${theme.colors.textSemiWeak};
box-shadow: ${theme.v2.shadows.z1};
color: ${theme.v1.colors.textSemiWeak};
box-shadow: ${theme.shadows.z1};
code {
font-size: ${theme.typography.size.sm};
background-color: ${theme.colors.bg1};
color: ${theme.colors.text};
border: 1px solid ${theme.colors.border2};
background-color: ${theme.v1.colors.bg1};
color: ${theme.v1.colors.text};
border: 1px solid ${theme.v1.colors.border2};
border-radius: 4px;
}
@ -83,12 +83,12 @@ const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVari
}
&--max-lg {
max-width: ${theme.breakpoints.lg};
max-width: ${theme.v1.breakpoints.lg};
}
`,
wrapperBranded: css`
padding: ${theme.spacing.md};
border-radius: ${theme.border.radius.md};
padding: ${theme.v1.spacing.md};
border-radius: ${theme.v1.border.radius.md};
position: relative;
z-index: 0;
@ -100,7 +100,7 @@ const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVari
width: 100%;
height: 100%;
background-image: url(${theme.isLight ? panelArtLight : panelArtDark});
border-radius: ${theme.border.radius.md};
border-radius: ${theme.v1.border.radius.md};
background-position: 50% 50%;
background-size: cover;
filter: saturate(80%);
@ -113,9 +113,9 @@ const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVari
`,
docsLink: css`
display: inline-block;
margin-top: ${theme.spacing.md};
font-size: ${theme.typography.size.sm};
color: ${theme.colors.textSemiWeak};
margin-top: ${theme.v1.spacing.md};
font-size: ${theme.v1.typography.size.sm};
color: ${theme.v1.colors.textSemiWeak};
`,
};
});

View File

@ -1,8 +1,8 @@
import React, { HTMLProps, ReactNode } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { Spinner } from '../Spinner/Spinner';
import { useClientRect } from '../../utils/useClientRect';
@ -24,7 +24,7 @@ export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'siz
}
interface StyleDeps {
theme: GrafanaTheme;
theme: GrafanaThemeV2;
invalid: boolean;
width?: number;
}
@ -44,7 +44,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
height: 100%;
/* Min width specified for prefix/suffix classes used outside React component*/
min-width: ${prefixSuffixStaticWidth};
color: ${theme.v2.palette.text.secondary};
color: ${theme.palette.text.secondary};
`;
return {
@ -53,14 +53,14 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
css`
label: input-wrapper;
display: flex;
width: ${width ? `${theme.v2.spacing(width)}` : '100%'};
height: ${theme.v2.spacing(theme.v2.components.height.md)};
border-radius: ${theme.v2.shape.borderRadius()};
width: ${width ? `${theme.spacing(width)}` : '100%'};
height: ${theme.spacing(theme.components.height.md)};
border-radius: ${theme.shape.borderRadius()};
&:hover {
> .prefix,
.suffix,
.input {
border-color: ${invalid ? theme.v2.palette.error.border : theme.v2.palette.primary.border};
border-color: ${invalid ? theme.palette.error.border : theme.palette.primary.border};
}
// only show number buttons on hover
@ -130,21 +130,21 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
`,
input: cx(
getFocusStyle(theme),
getFocusStyle(theme.v1),
sharedInputStyle(theme, invalid),
css`
label: input-input;
position: relative;
z-index: 0;
flex-grow: 1;
border-radius: ${theme.v2.shape.borderRadius()};
border-radius: ${theme.shape.borderRadius()};
height: 100%;
width: 100%;
`
),
inputDisabled: css`
background-color: ${theme.v2.palette.action.disabledBackground};
color: ${theme.v2.palette.action.disabledText};
background-color: ${theme.palette.action.disabledBackground};
color: ${theme.palette.action.disabledText};
`,
addon: css`
label: input-addon;
@ -181,8 +181,8 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
prefixSuffix,
css`
label: input-prefix;
padding-left: ${theme.v2.spacing(1)};
padding-right: ${theme.v2.spacing(0.5)};
padding-left: ${theme.spacing(1)};
padding-right: ${theme.spacing(0.5)};
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
@ -192,8 +192,8 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
prefixSuffix,
css`
label: input-suffix;
padding-left: ${theme.v2.spacing(1)};
padding-right: ${theme.v2.spacing(0.5)};
padding-left: ${theme.spacing(1)};
padding-right: ${theme.spacing(0.5)};
margin-bottom: -2px;
border-left: none;
border-top-left-radius: 0;
@ -203,7 +203,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
),
loadingIndicator: css`
& + * {
margin-left: ${theme.v2.spacing(0.5)};
margin-left: ${theme.spacing(0.5)};
}
`,
};
@ -219,7 +219,7 @@ export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
const [prefixRect, prefixRef] = useClientRect<HTMLDivElement>();
const [suffixRect, suffixRef] = useClientRect<HTMLDivElement>();
const theme = useTheme();
const theme = useTheme2();
const styles = getInputStyles({ theme, invalid: !!invalid, width });
return (

View File

@ -1,8 +1,7 @@
import React, { FunctionComponent, useContext } from 'react';
import React, { FunctionComponent } from 'react';
import { css, cx } from '@emotion/css';
import { ThemeContext } from '../../themes/ThemeContext';
import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '../../themes/ThemeContext';
const getStyles = (theme: GrafanaTheme) => ({
logsStatsRow: css`
@ -58,8 +57,7 @@ export interface Props {
}
export const LogLabelStatsRow: FunctionComponent<Props> = ({ active, count, proportion, value }) => {
const theme = useContext(ThemeContext);
const style = getStyles(theme);
const style = useStyles(getStyles);
const percent = `${Math.round(proportion * 100)}%`;
const barStyle = { width: percent };
const className = active ? cx([style.logsStatsRow, style.logsStatsRowActive]) : cx([style.logsStatsRow]);

View File

@ -1,10 +1,10 @@
import React, { useContext, useRef, useState, useLayoutEffect, useEffect } from 'react';
import React, { useRef, useState, useLayoutEffect, useEffect } from 'react';
import { GrafanaTheme, DataQueryError, LogRowModel, textUtil } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { Alert } from '../Alert/Alert';
import { LogRowContextRows, LogRowContextQueryErrors, HasMoreContextRows } from './LogRowContextProvider';
import { ThemeContext } from '../../themes/ThemeContext';
import { useStyles } from '../../themes/ThemeContext';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
import { List } from '../List/List';
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
@ -66,8 +66,7 @@ const LogRowContextGroupHeader: React.FunctionComponent<LogRowContextGroupHeader
onLoadMoreContext,
canLoadMoreRows,
}) => {
const theme = useContext(ThemeContext);
const { header } = getLogRowContextStyles(theme);
const { header } = useStyles(getLogRowContextStyles);
return (
<div className={header}>
@ -105,8 +104,7 @@ export const LogRowContextGroup: React.FunctionComponent<LogRowContextGroupProps
canLoadMoreRows,
onLoadMoreContext,
}) => {
const theme = useContext(ThemeContext);
const { commonStyles, logs } = getLogRowContextStyles(theme);
const { commonStyles, logs } = useStyles(getLogRowContextStyles);
const [scrollTop, setScrollTop] = useState(0);
const listContainerRef = useRef<HTMLDivElement>() as React.RefObject<HTMLDivElement>;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { useStyles2 } from '../../themes';
/** @internal */
export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> {
@ -14,7 +14,7 @@ export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> {
/** @internal */
export const Menu = React.forwardRef<HTMLDivElement, MenuProps>(
({ header, children, ariaLabel, ...otherProps }, ref) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
return (
<div {...otherProps} ref={ref} className={styles.wrapper} aria-label={ariaLabel}>
@ -27,17 +27,17 @@ export const Menu = React.forwardRef<HTMLDivElement, MenuProps>(
Menu.displayName = 'Menu';
/** @internal */
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
header: css`
padding: ${theme.v2.spacing(0.5, 0.5, 1, 0.5)};
border-bottom: 1px solid ${theme.v2.palette.border.medium};
padding: ${theme.spacing(0.5, 0.5, 1, 0.5)};
border-bottom: 1px solid ${theme.palette.border.medium};
`,
wrapper: css`
background: ${theme.v2.palette.background.secondary};
box-shadow: ${theme.v2.shadows.z2};
background: ${theme.palette.background.secondary};
box-shadow: ${theme.shadows.z2};
display: inline-block;
border-radius: ${theme.v2.shape.borderRadius()};
border-radius: ${theme.shape.borderRadius()};
`,
};
};

View File

@ -1,7 +1,7 @@
import React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { MenuItemProps } from './MenuItem';
/** @internal */
@ -21,7 +21,7 @@ export interface MenuGroupProps extends Partial<MenuItemsGroup> {
/** @internal */
export const MenuGroup: React.FC<MenuGroupProps> = ({ label, children, ariaLabel }) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
return (
<div>
@ -37,12 +37,12 @@ export const MenuGroup: React.FC<MenuGroupProps> = ({ label, children, ariaLabel
MenuGroup.displayName = 'MenuGroup';
/** @internal */
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
groupLabel: css`
color: ${theme.v2.palette.text.secondary};
font-size: ${theme.v2.typography.size.sm};
padding: ${theme.v2.spacing(0.5, 1)};
color: ${theme.palette.text.secondary};
font-size: ${theme.typography.size.sm};
padding: ${theme.spacing(0.5, 1)};
`,
};
};

View File

@ -1,7 +1,7 @@
import React from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme, LinkTarget } from '@grafana/data';
import { useStyles } from '../../themes';
import { GrafanaThemeV2, LinkTarget } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { Icon } from '../Icon/Icon';
import { IconName } from '../../types';
@ -28,7 +28,7 @@ export interface MenuItemProps {
/** @internal */
export const MenuItem: React.FC<MenuItemProps> = React.memo(
({ url, icon, label, ariaLabel, target, onClick, className, active }) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const itemStyle = cx(
{
[styles.item]: true,
@ -55,16 +55,16 @@ export const MenuItem: React.FC<MenuItemProps> = React.memo(
MenuItem.displayName = 'MenuItem';
/** @internal */
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
link: css`
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
display: flex;
cursor: pointer;
padding: 5px 12px 5px 10px;
&:hover {
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
text-decoration: none;
}
`,
@ -74,16 +74,16 @@ const getStyles = (theme: GrafanaTheme) => {
white-space: nowrap;
&:hover {
background: ${theme.v2.palette.action.hover};
background: ${theme.palette.action.hover};
}
`,
activeItem: css`
background: ${theme.v2.palette.action.selected};
background: ${theme.palette.action.selected};
`,
icon: css`
opacity: 0.7;
margin-right: 10px;
color: ${theme.v2.palette.text.secondary};
color: ${theme.palette.text.secondary};
`,
};
};

View File

@ -1,7 +1,7 @@
import React, { FC, PropsWithChildren, useCallback, useEffect } from 'react';
import { Portal } from '../Portal/Portal';
import { cx } from '@emotion/css';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { IconName } from '../../types';
import { getModalStyles } from './getModalStyles';
import { ModalHeader } from './ModalHeader';
@ -34,7 +34,7 @@ export function Modal(props: PropsWithChildren<Props>): ReturnType<FC<Props>> {
onDismiss: propsOnDismiss,
onClickBackdrop,
} = props;
const theme = useTheme();
const theme = useTheme2();
const styles = getModalStyles(theme);
const onDismiss = useCallback(() => {
if (propsOnDismiss) {

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react';
import React from 'react';
import { getModalStyles } from './getModalStyles';
import { IconName } from '../../types';
import { ThemeContext } from '../../themes';
import { useStyles2 } from '../../themes';
import { Icon } from '../Icon/Icon';
import { Tooltip } from '..';
@ -12,8 +12,7 @@ interface Props {
}
export const ModalHeader: React.FC<Props> = ({ icon, iconTooltip, title, children }) => {
const theme = useContext(ThemeContext);
const styles = getModalStyles(theme);
const styles = useStyles2(getModalStyles);
return (
<>

View File

@ -1,18 +1,18 @@
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { stylesFactory } from '../../themes';
export const getModalStyles = stylesFactory((theme: GrafanaTheme) => {
export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => {
// rgba(1,4,9,0.8)
const backdropBackground = 'rgba(0, 0, 0, 0.5)';
const borderRadius = theme.v2.shape.borderRadius(2);
const borderRadius = theme.shape.borderRadius(2);
return {
modal: css`
position: fixed;
z-index: ${theme.v2.zIndex.modal};
background: ${theme.v2.palette.background.primary};
box-shadow: ${theme.v2.shadows.z4};
z-index: ${theme.zIndex.modal};
background: ${theme.palette.background.primary};
box-shadow: ${theme.shadows.z4};
border-radius: ${borderRadius};
background-clip: padding-box;
outline: none;
@ -30,26 +30,26 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => {
right: 0;
bottom: 0;
left: 0;
z-index: ${theme.v2.zIndex.modalBackdrop};
z-index: ${theme.zIndex.modalBackdrop};
background-color: ${backdropBackground};
`,
modalHeader: css`
label: modalHeader;
background: ${theme.colors.bg2};
border-bottom: 1px solid ${theme.colors.pageHeaderBorder};
background: ${theme.palette.background.secondary};
border-bottom: 1px solid ${theme.palette.border.weak};
border-radius: ${borderRadius} ${borderRadius} 0 0;
display: flex;
height: 42px;
`,
modalHeaderTitle: css`
font-size: ${theme.typography.size.lg};
margin: 0 ${theme.spacing.md};
margin: 0 ${theme.spacing(2)};
display: flex;
align-items: center;
line-height: 42px;
`,
modalHeaderIcon: css`
margin-right: ${theme.spacing.md};
margin-right: ${theme.spacing(2)};
font-size: inherit;
&:before {
vertical-align: baseline;
@ -61,13 +61,13 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => {
align-items: center;
flex-grow: 1;
justify-content: flex-end;
padding-right: ${theme.spacing.sm};
padding-right: ${theme.spacing(1)};
`,
modalContent: css`
padding: calc(${theme.spacing.d} * 2);
padding: calc(${theme.spacing.gridSize} * 2);
overflow: auto;
width: 100%;
max-height: calc(90vh - ${theme.spacing.d} * 2);
max-height: calc(90vh - ${theme.spacing.gridSize} * 2);
`,
};
});

View File

@ -1,15 +1,11 @@
import React, { memo } from 'react';
import { EdgeDatum, NodeDatum } from './types';
import { css } from '@emotion/css';
import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import tinycolor from 'tinycolor2';
import lightTheme from '../../themes/light';
import darkTheme from '../../themes/dark';
import { useStyles2 } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { shortenLine } from './utils';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
const inverseTheme = theme.isDark ? lightTheme : darkTheme;
const getStyles = (theme: GrafanaThemeV2) => {
return {
mainGroup: css`
pointer-events: none;
@ -17,14 +13,14 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
`,
background: css`
fill: ${tinycolor(inverseTheme.colors.bodyBg).setAlpha(0.8).toHex8String()};
fill: ${theme.components.tooltip.background};
`,
text: css`
fill: ${inverseTheme.colors.text};
fill: ${theme.components.tooltip.text};
`,
};
});
};
interface Props {
edge: EdgeDatum;
@ -49,7 +45,7 @@ export const EdgeLabel = memo(function EdgeLabel(props: Props) {
x: line.x1 + (line.x2 - line.x1) / 2,
y: line.y1 + (line.y2 - line.y1) / 2,
};
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<g className={styles.mainGroup}>

View File

@ -1,9 +1,11 @@
import { createTheme } from '@grafana/data';
import { makeEdgesDataFrame, makeNodesDataFrame, processNodes } from './utils';
import lightTheme from '../../themes/light';
describe('processNodes', () => {
const theme = createTheme();
it('handles empty args', async () => {
expect(processNodes(undefined, undefined, lightTheme)).toEqual({ nodes: [], edges: [] });
expect(processNodes(undefined, undefined, theme.v1)).toEqual({ nodes: [], edges: [] });
});
it('returns proper nodes and edges', async () => {
@ -15,7 +17,7 @@ describe('processNodes', () => {
[0, 2],
[1, 2],
]),
lightTheme
theme.v1
)
).toEqual({
nodes: [
@ -30,7 +32,7 @@ describe('processNodes', () => {
value: 0.5,
},
],
color: 'rgb(213, 172, 32)',
color: 'rgb(226, 192, 61)',
dataFrameRowIndex: 0,
id: '0',
incoming: 0,
@ -50,7 +52,7 @@ describe('processNodes', () => {
value: 0.5,
},
],
color: 'rgb(213, 172, 32)',
color: 'rgb(226, 192, 61)',
dataFrameRowIndex: 1,
id: '1',
incoming: 1,
@ -70,7 +72,7 @@ describe('processNodes', () => {
value: 0.5,
},
],
color: 'rgb(213, 172, 32)',
color: 'rgb(226, 192, 61)',
dataFrameRowIndex: 2,
id: '2',
incoming: 2,

View File

@ -1,7 +1,7 @@
import React, { FC, ReactNode } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '../../themes/ThemeContext';
import { GrafanaThemeV2 } from '@grafana/data';
import { useStyles2 } from '../../themes/ThemeContext';
import { IconName } from '../../types';
import { Icon } from '../Icon/Icon';
import { styleMixins } from '../../themes';
@ -35,7 +35,7 @@ export const PageToolbar: FC<Props> = React.memo(
isFullscreen,
className,
}) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
/**
* .page-toolbar css class is used for some legacy css view modes (TV/Kiosk) and
@ -109,12 +109,12 @@ export const PageToolbar: FC<Props> = React.memo(
PageToolbar.displayName = 'PageToolbar';
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
const { spacing, typography } = theme;
const titleStyles = `
font-size: ${typography.size.lg};
padding-left: ${spacing.sm};
padding-left: ${spacing(1)};
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
@ -124,7 +124,7 @@ const getStyles = (theme: GrafanaTheme) => {
background: none;
border: none;
@media ${styleMixins.mediaUp(theme.breakpoints.xl)} {
@media ${styleMixins.mediaUp(theme.v1.breakpoints.xl)} {
max-width: unset;
}
`;
@ -132,10 +132,10 @@ const getStyles = (theme: GrafanaTheme) => {
return {
toolbar: css`
display: flex;
background: ${theme.v2.palette.background.canvas};
background: ${theme.palette.background.canvas};
justify-content: flex-end;
flex-wrap: wrap;
padding: ${theme.v2.spacing(0, 1, 1, 2)};
padding: ${theme.spacing(0, 1, 1, 2)};
`,
toolbarLeft: css`
display: flex;
@ -146,19 +146,19 @@ const getStyles = (theme: GrafanaTheme) => {
flex-grow: 1;
`,
pageIcon: css`
padding-top: ${spacing.sm};
padding-top: ${spacing(1)};
align-items: center;
display: none;
@media ${styleMixins.mediaUp(theme.breakpoints.md)} {
@media ${styleMixins.mediaUp(theme.v1.breakpoints.md)} {
display: flex;
}
`,
titleWrapper: css`
display: flex;
align-items: center;
padding-top: ${spacing.sm};
padding-right: ${spacing.sm};
padding-top: ${spacing(1)};
padding-right: ${spacing(1)};
min-width: 0;
overflow: hidden;
`,
@ -178,13 +178,13 @@ const getStyles = (theme: GrafanaTheme) => {
parentLink: css`
display: none;
@media ${styleMixins.mediaUp(theme.breakpoints.md)} {
@media ${styleMixins.mediaUp(theme.v1.breakpoints.md)} {
display: inline-block;
}
`,
actionWrapper: css`
padding-left: ${spacing.sm};
padding-top: ${spacing.sm};
padding-left: ${spacing(1)};
padding-top: ${spacing(1)};
`,
leftActionItem: css`
display: none;
@ -192,9 +192,9 @@ const getStyles = (theme: GrafanaTheme) => {
position: relative;
top: 5px;
align-items: center;
padding-left: ${spacing.xs};
padding-left: ${spacing(0.5)};
@media ${styleMixins.mediaUp(theme.breakpoints.md)} {
@media ${styleMixins.mediaUp(theme.v1.breakpoints.md)} {
display: flex;
}
`,

View File

@ -1,11 +1,11 @@
import React from 'react';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { getInputStyles } from '../Input/Input';
import { cx, css } from '@emotion/css';
export const IndicatorsContainer = React.forwardRef<HTMLDivElement, React.PropsWithChildren<any>>((props, ref) => {
const { children } = props;
const theme = useTheme();
const theme = useTheme2();
const styles = getInputStyles({ theme, invalid: false });
return (

View File

@ -1,10 +1,10 @@
import React from 'react';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { sharedInputStyle } from '../Forms/commonStyles';
import { getInputStyles } from '../Input/Input';
import { css, cx } from '@emotion/css';
import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { focusCss } from '../../themes/mixins';
interface InputControlProps {
@ -17,7 +17,7 @@ interface InputControlProps {
}
const getInputControlStyles = stylesFactory(
(theme: GrafanaTheme, invalid: boolean, focused: boolean, disabled: boolean, withPrefix: boolean) => {
(theme: GrafanaThemeV2, invalid: boolean, focused: boolean, disabled: boolean, withPrefix: boolean) => {
const styles = getInputStyles({ theme, invalid });
return {
@ -26,7 +26,7 @@ const getInputControlStyles = stylesFactory(
sharedInputStyle(theme, invalid),
focused &&
css`
${focusCss(theme)}
${focusCss(theme.v1)}
`,
disabled && styles.inputDisabled,
css`
@ -60,7 +60,7 @@ const getInputControlStyles = stylesFactory(
export const InputControl = React.forwardRef<HTMLDivElement, React.PropsWithChildren<InputControlProps>>(
function InputControl({ focused, invalid, disabled, children, innerProps, prefix, ...otherProps }, ref) {
const theme = useTheme();
const theme = useTheme2();
const styles = getInputControlStyles(theme, invalid, focused, disabled, !!prefix);
return (
<div className={styles.wrapper} {...innerProps} ref={ref}>

View File

@ -1,5 +1,5 @@
import React from 'react';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { getSelectStyles } from './getSelectStyles';
import { Icon } from '../Icon/Icon';
@ -8,7 +8,7 @@ interface MultiValueContainerProps {
}
export const MultiValueContainer: React.FC<MultiValueContainerProps> = ({ innerProps, children }) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getSelectStyles(theme);
return (
@ -23,7 +23,7 @@ export type MultiValueRemoveProps = {
};
export const MultiValueRemove: React.FC<MultiValueRemoveProps> = ({ children, innerProps }) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getSelectStyles(theme);
return (
<div {...innerProps} className={styles.multiValueRemove}>

View File

@ -16,7 +16,7 @@ import { DropdownIndicator } from './DropdownIndicator';
import { SelectOptionGroup } from './SelectOptionGroup';
import { SingleValue } from './SingleValue';
import { MultiValueContainer, MultiValueRemove } from './MultiValue';
import { useTheme } from '../../themes';
import { useTheme2 } from '../../themes';
import { getSelectStyles } from './getSelectStyles';
import { cleanValue, findSelectedValue } from './utils';
import { SelectBaseProps, SelectValue } from './types';
@ -135,7 +135,7 @@ export function SelectBase<T>({
value,
width,
}: SelectBaseProps<T>) {
const theme = useTheme();
const theme = useTheme2();
const styles = getSelectStyles(theme);
const onChangeWithEmpty = useCallback(
(value: SelectValue<T>) => {
@ -245,7 +245,7 @@ export function SelectBase<T>({
css(props.getStyles('placeholder', props)),
css`
display: inline-block;
color: ${theme.colors.formInputPlaceholderText};
color: ${theme.palette.text.disabled};
position: absolute;
top: 50%;
transform: translateY(-50%);

View File

@ -1,5 +1,5 @@
import React from 'react';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles';
import { cx } from '@emotion/css';
import { SelectableValue } from '@grafana/data';
@ -12,7 +12,7 @@ interface SelectMenuProps {
}
export const SelectMenu = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuProps>>((props, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getSelectStyles(theme);
const { children, maxHeight, innerRef, innerProps } = props;
@ -38,7 +38,7 @@ interface SelectMenuOptionProps<T> {
export const SelectMenuOptions = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuOptionProps<any>>>(
(props, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getSelectStyles(theme);
const { children, innerProps, data, renderOptionLabel, isSelected, isFocused } = props;

View File

@ -2,16 +2,16 @@ import React from 'react';
import { css, cx } from '@emotion/css';
import { components, SingleValueProps } from 'react-select';
import { useDelayedSwitch } from '../../utils/useDelayedSwitch';
import { stylesFactory, useTheme } from '../../themes';
import { useStyles2 } from '../../themes';
import { SlideOutTransition } from '../transitions/SlideOutTransition';
import { FadeTransition } from '../transitions/FadeTransition';
import { Spinner } from '../Spinner/Spinner';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
const singleValue = css`
label: singleValue;
color: ${theme.v2.components.input.text};
color: ${theme.components.input.text};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -36,7 +36,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
`;
return { singleValue, container, item };
});
};
type StylesType = ReturnType<typeof getStyles>;
interface Props
extends SingleValueProps<{
@ -47,8 +49,7 @@ interface Props
export const SingleValue = (props: Props) => {
const { children, data } = props;
const theme = useTheme();
const styles = getStyles(theme);
const styles = useStyles2(getStyles);
const loading = useDelayedSwitch(data.loading || false, { delay: 250, duration: 750 });
@ -56,7 +57,7 @@ export const SingleValue = (props: Props) => {
<components.SingleValue {...props}>
<div className={cx(styles.singleValue)}>
{data.imgUrl ? (
<FadeWithImage loading={loading} imgUrl={data.imgUrl} />
<FadeWithImage loading={loading} imgUrl={data.imgUrl} styles={styles} />
) : (
<SlideOutTransition horizontal size={16} visible={loading} duration={150}>
<div className={styles.container}>
@ -70,17 +71,14 @@ export const SingleValue = (props: Props) => {
);
};
const FadeWithImage = (props: { loading: boolean; imgUrl: string }) => {
const theme = useTheme();
const styles = getStyles(theme);
const FadeWithImage = (props: { loading: boolean; imgUrl: string; styles: StylesType }) => {
return (
<div className={styles.container}>
<div className={props.styles.container}>
<FadeTransition duration={150} visible={props.loading}>
<Spinner className={styles.item} inline />
<Spinner className={props.styles.item} inline />
</FadeTransition>
<FadeTransition duration={150} visible={!props.loading}>
<img className={styles.item} src={props.imgUrl} />
<img className={props.styles.item} src={props.imgUrl} />
</FadeTransition>
</div>
);

View File

@ -1,7 +1,7 @@
import React, { ReactNode } from 'react';
import { cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { withTheme } from '../../themes/ThemeContext';
import { withTheme2 } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles';
class UnthemedValueContainer extends React.Component<any & { theme: GrafanaTheme }> {
@ -33,4 +33,4 @@ class UnthemedValueContainer extends React.Component<any & { theme: GrafanaTheme
}
}
export const ValueContainer = withTheme(UnthemedValueContainer);
export const ValueContainer = withTheme2(UnthemedValueContainer);

View File

@ -1,13 +1,13 @@
import { stylesFactory } from '../../themes/stylesFactory';
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
export const getSelectStyles = stylesFactory((theme: GrafanaTheme) => {
export const getSelectStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
menu: css`
label: grafana-select-menu;
background: ${theme.v2.palette.background.secondary};
box-shadow: ${theme.v2.shadows.z3};
background: ${theme.palette.background.secondary};
box-shadow: ${theme.shadows.z3};
position: relative;
min-width: 100%;
z-index: 1;
@ -24,7 +24,7 @@ export const getSelectStyles = stylesFactory((theme: GrafanaTheme) => {
border-left: 2px solid transparent;
&:hover {
background: ${theme.v2.palette.action.hover};
background: ${theme.palette.action.hover};
}
`,
optionImage: css`
@ -35,28 +35,28 @@ export const getSelectStyles = stylesFactory((theme: GrafanaTheme) => {
optionDescription: css`
label: grafana-select-option-description;
font-weight: normal;
font-size: ${theme.v2.typography.size.sm};
color: ${theme.v2.palette.text.secondary};
font-size: ${theme.typography.size.sm};
color: ${theme.palette.text.secondary};
white-space: normal;
line-height: ${theme.v2.typography.body.lineHeight};
line-height: ${theme.typography.body.lineHeight};
`,
optionBody: css`
label: grafana-select-option-body;
display: flex;
font-weight: ${theme.v2.typography.fontWeightMedium};
font-weight: ${theme.typography.fontWeightMedium};
flex-direction: column;
flex-grow: 1;
`,
optionFocused: css`
label: grafana-select-option-focused;
background: ${theme.v2.palette.action.focus};
background: ${theme.palette.action.focus};
`,
optionSelected: css`
background: ${theme.v2.palette.action.selected};
background: ${theme.palette.action.selected};
`,
singleValue: css`
label: grafana-select-single-value;
color: ${theme.v2.components.input.text};
color: ${theme.components.input.text};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -79,7 +79,7 @@ export const getSelectStyles = stylesFactory((theme: GrafanaTheme) => {
`,
loadingMessage: css`
label: grafana-select-loading-message;
padding: ${theme.v2.spacing(1)};
padding: ${theme.spacing(1)};
text-align: center;
width: 100%;
`,
@ -88,16 +88,16 @@ export const getSelectStyles = stylesFactory((theme: GrafanaTheme) => {
display: flex;
align-items: center;
line-height: 1;
background: ${theme.v2.palette.background.secondary};
border-radius: ${theme.v2.shape.borderRadius()};
margin: ${theme.v2.spacing(0, 1, 0, 0)};
padding: ${theme.v2.spacing(0.25, 0, 0.25, 1)};
color: ${theme.v2.palette.text.primary};
background: ${theme.palette.background.secondary};
border-radius: ${theme.shape.borderRadius()};
margin: ${theme.spacing(0, 1, 0, 0)};
padding: ${theme.spacing(0.25, 0, 0.25, 1)};
color: ${theme.palette.text.primary};
font-size: ${theme.typography.size.sm};
`,
multiValueRemove: css`
label: grafana-select-multi-value-remove;
margin: ${theme.v2.spacing(0, 0.5)};
margin: ${theme.spacing(0, 0.5)};
cursor: pointer;
`,
};

View File

@ -2,7 +2,7 @@ import React, { FunctionComponent } from 'react';
import { Range as RangeComponent, createSliderWithTooltip } from 'rc-slider';
import { cx } from '@emotion/css';
import { Global } from '@emotion/react';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { getStyles } from './styles';
import { RangeSliderProps } from './types';
@ -24,7 +24,7 @@ export const RangeSlider: FunctionComponent<RangeSliderProps> = ({
tooltipAlwaysVisible = true,
}) => {
const isHorizontal = orientation === 'horizontal';
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme, isHorizontal);
const RangeWithTooltip = createSliderWithTooltip(RangeComponent);
return (

View File

@ -2,7 +2,7 @@ import React, { useState, useCallback, ChangeEvent, FunctionComponent } from 're
import SliderComponent from 'rc-slider';
import { cx } from '@emotion/css';
import { Global } from '@emotion/react';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { getStyles } from './styles';
import { SliderProps } from './types';
import { Input } from '../Input/Input';
@ -21,7 +21,7 @@ export const Slider: FunctionComponent<SliderProps> = ({
value,
}) => {
const isHorizontal = orientation === 'horizontal';
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme, isHorizontal);
const SliderWithTooltip = SliderComponent;
const [sliderValue, setSliderValue] = useState<number>(value || min);

View File

@ -1,27 +1,20 @@
import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { focusCss } from '../../themes/mixins';
import { GrafanaThemeV2 } from '@grafana/data';
import { css as cssCore } from '@emotion/react';
import { css } from '@emotion/css';
export const getFocusStyle = (theme: GrafanaTheme) => css`
&:focus {
${focusCss(theme)}
}
`;
export const getStyles = stylesFactory((theme: GrafanaTheme, isHorizontal: boolean) => {
export const getStyles = stylesFactory((theme: GrafanaThemeV2, isHorizontal: boolean) => {
const { spacing } = theme;
const railColor = theme.v2.palette.border.strong;
const trackColor = theme.v2.palette.primary.main;
const handleColor = theme.v2.palette.primary.main;
const blueOpacity = theme.v2.palette.primary.transparent;
const railColor = theme.palette.border.strong;
const trackColor = theme.palette.primary.main;
const handleColor = theme.palette.primary.main;
const blueOpacity = theme.palette.primary.transparent;
const hoverSyle = `box-shadow: 0px 0px 0px 6px ${blueOpacity}`;
return {
container: css`
width: 100%;
margin: ${isHorizontal ? 'none' : `${spacing.sm} ${spacing.lg} ${spacing.sm} ${spacing.sm}`};
margin: ${isHorizontal ? 'none' : `${spacing(1, 3, 1, 1)}`};
height: ${isHorizontal ? 'auto' : '100%'};
`,
slider: css`
@ -36,7 +29,7 @@ export const getStyles = stylesFactory((theme: GrafanaTheme, isHorizontal: boole
.rc-slider-handle {
border: none;
background-color: ${handleColor};
box-shadow: ${theme.v2.shadows.z1};
box-shadow: ${theme.shadows.z1};
cursor: pointer;
}
.rc-slider-handle:hover,
@ -66,7 +59,7 @@ export const getStyles = stylesFactory((theme: GrafanaTheme, isHorizontal: boole
}
.rc-slider-tooltip-inner {
color: ${theme.colors.text};
color: ${theme.palette.text.primary};
background-color: transparent !important;
border-radius: 0;
box-shadow: none;
@ -97,14 +90,14 @@ export const getStyles = stylesFactory((theme: GrafanaTheme, isHorizontal: boole
}
`,
sliderInputField: css`
margin-left: ${theme.spacing.lg};
margin-left: ${theme.spacing(3)};
width: 60px;
input {
text-align: center;
}
`,
sliderInputFieldVertical: css`
margin: 0 0 ${theme.spacing.lg} 0;
margin: 0 0 ${theme.spacing(3)} 0;
order: 1;
`,
};

View File

@ -1,9 +1,9 @@
import React, { HTMLProps, useRef } from 'react';
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
import { GrafanaTheme, deprecationWarning } from '@grafana/data';
import { stylesFactory, useTheme } from '../../themes';
import { focusCss, getMouseFocusStyles } from '../../themes/mixins';
import { GrafanaThemeV2, deprecationWarning } from '@grafana/data';
import { stylesFactory, useTheme2 } from '../../themes';
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'value'> {
value?: boolean;
@ -17,7 +17,7 @@ export const Switch = React.forwardRef<HTMLInputElement, Props>(
deprecationWarning('Switch', 'checked prop', 'value');
}
const theme = useTheme();
const theme = useTheme2();
const styles = getSwitchStyles(theme);
const switchIdRef = useRef(id ? id : uniqueId('switch-'));
@ -43,7 +43,7 @@ export const Switch = React.forwardRef<HTMLInputElement, Props>(
Switch.displayName = 'Switch';
export const InlineSwitch = React.forwardRef<HTMLInputElement, Props>(({ transparent, ...props }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getSwitchStyles(theme, transparent);
return (
@ -55,7 +55,7 @@ export const InlineSwitch = React.forwardRef<HTMLInputElement, Props>(({ transpa
InlineSwitch.displayName = 'Switch';
const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolean) => {
const getSwitchStyles = stylesFactory((theme: GrafanaThemeV2, transparent?: boolean) => {
return {
switch: css`
width: 32px;
@ -69,31 +69,31 @@ const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolea
position: absolute;
&:disabled + label {
background: ${theme.v2.palette.action.disabledBackground};
background: ${theme.palette.action.disabledBackground};
cursor: not-allowed;
}
&:checked + label {
background: ${theme.v2.palette.primary.main};
border-color: ${theme.v2.palette.primary.main};
background: ${theme.palette.primary.main};
border-color: ${theme.palette.primary.main};
&:hover {
background: ${theme.v2.palette.primary.shade};
background: ${theme.palette.primary.shade};
}
&::after {
transform: translate3d(18px, -50%, 0);
background: ${theme.v2.palette.primary.contrastText};
background: ${theme.palette.primary.contrastText};
}
}
&:focus + label,
&:focus-visible + label {
${focusCss(theme)}
${getFocusStyles(theme)}
}
&:focus:not(:focus-visible) + label {
${getMouseFocusStyles(theme.v2)}
${getMouseFocusStyles(theme)}
}
}
@ -103,12 +103,12 @@ const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolea
cursor: pointer;
border: none;
border-radius: 50px;
background: ${theme.v2.components.input.background};
border: 1px solid ${theme.v2.components.input.border};
background: ${theme.components.input.background};
border: 1px solid ${theme.components.input.border};
transition: all 0.3s ease;
&:hover {
border-color: ${theme.v2.components.input.borderHover};
border-color: ${theme.components.input.borderHover};
}
&::after {
@ -118,8 +118,8 @@ const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolea
width: 12px;
height: 12px;
border-radius: 6px;
background: ${theme.v2.palette.text.secondary};
box-shadow: ${theme.v2.shadows.z1};
background: ${theme.palette.text.secondary};
box-shadow: ${theme.shadows.z1};
top: 50%;
transform: translate3d(2px, -50%, 0);
transition: transform 0.2s cubic-bezier(0.19, 1, 0.22, 1);
@ -127,13 +127,13 @@ const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolea
}
`,
inlineContainer: css`
padding: ${theme.v2.spacing(0, 1)};
height: ${theme.v2.spacing(theme.v2.components.height.md)};
padding: ${theme.spacing(0, 1)};
height: ${theme.spacing(theme.components.height.md)};
display: flex;
align-items: center;
background: ${transparent ? 'transparent' : theme.v2.components.input.background};
border: 1px solid ${transparent ? 'transparent' : theme.v2.components.input.border};
border-radius: ${theme.v2.shape.borderRadius()};
background: ${transparent ? 'transparent' : theme.components.input.background};
border: 1px solid ${transparent ? 'transparent' : theme.components.input.border};
border-radius: ${theme.shape.borderRadius()};
`,
};
});

View File

@ -1,9 +1,9 @@
import React, { FC, useCallback, useMemo, useState } from 'react';
import { FixedSizeList as List } from 'react-window';
import { css } from '@emotion/css';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
import { GrafanaThemeV2, SelectableValue } from '@grafana/data';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { Checkbox, Input, Label, VerticalGroup } from '..';
interface Props {
@ -16,14 +16,14 @@ const ITEM_HEIGHT = 28;
const MIN_HEIGHT = ITEM_HEIGHT * 5;
export const FilterList: FC<Props> = ({ options, values, onChange }) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme);
const [searchFilter, setSearchFilter] = useState('');
const items = useMemo(() => options.filter((option) => option.label?.indexOf(searchFilter) !== -1), [
options,
searchFilter,
]);
const gutter = parseInt(theme.spacing.sm, 10);
const gutter = theme.spacing.gridSize;
const height = useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);
const onInputChange = useCallback(
@ -78,7 +78,7 @@ export const FilterList: FC<Props> = ({ options, values, onChange }) => {
);
};
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
const getStyles = stylesFactory((theme: GrafanaThemeV2) => ({
filterList: css`
label: filterList;
`,
@ -88,10 +88,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: ${theme.spacing.xs};
padding: ${theme.spacing(0.5)};
:hover {
background-color: ${theme.v2.palette.action.hover};
background-color: ${theme.palette.action.hover};
}
`,
filterListInput: css`

View File

@ -1,18 +1,18 @@
import React, { FC } from 'react';
import { css } from '@emotion/css';
import { stylesFactory, useStyles } from '../../themes';
import { GrafanaTheme, locale } from '@grafana/data';
import { stylesFactory, useStyles2 } from '../../themes';
import { GrafanaThemeV2, locale } from '@grafana/data';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
const getStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
counter: css`
label: counter;
margin-left: ${theme.spacing.sm};
border-radius: ${theme.spacing.lg};
background-color: ${theme.v2.palette.action.hover};
padding: ${theme.spacing.xxs} ${theme.spacing.sm};
color: ${theme.colors.textWeak};
font-weight: ${theme.typography.weight.semibold};
margin-left: ${theme.spacing(1)};
border-radius: ${theme.spacing(3)};
background-color: ${theme.palette.action.hover};
padding: ${theme.spacing(0.25, 1)};
color: ${theme.palette.text.secondary};
font-weight: ${theme.typography.fontWeightMedium};
font-size: ${theme.typography.size.sm};
`,
};
@ -23,7 +23,7 @@ export interface CounterProps {
}
export const Counter: FC<CounterProps> = ({ value }) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
return <span className={styles.counter}>{locale(value, 0).text}</span>;
};

View File

@ -1,11 +1,11 @@
import React, { HTMLProps } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Icon } from '../Icon/Icon';
import { IconName } from '../../types';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { Counter } from './Counter';
export interface TabProps extends HTMLProps<HTMLAnchorElement> {
@ -21,7 +21,7 @@ export interface TabProps extends HTMLProps<HTMLAnchorElement> {
export const Tab = React.forwardRef<HTMLAnchorElement, TabProps>(
({ label, active, icon, onChangeTab, counter, className, href, ...otherProps }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const tabsStyles = getTabStyles(theme);
const content = () => (
<>
@ -52,7 +52,7 @@ export const Tab = React.forwardRef<HTMLAnchorElement, TabProps>(
Tab.displayName = 'Tab';
const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
const getTabStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
item: css`
list-style: none;
@ -60,24 +60,24 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
display: flex;
`,
link: css`
color: ${theme.v2.palette.text.secondary};
padding: ${theme.v2.spacing(1.5, 2, 1)};
color: ${theme.palette.text.secondary};
padding: ${theme.spacing(1.5, 2, 1)};
svg {
margin-right: ${theme.v2.spacing(1)};
margin-right: ${theme.spacing(1)};
}
a {
display: block;
height: 100%;
color: ${theme.v2.palette.text.secondary};
color: ${theme.palette.text.secondary};
}
`,
notActive: css`
a:hover,
&:hover,
&:focus {
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
&::before {
display: block;
@ -88,18 +88,18 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
height: 4px;
border-radius: 2px;
bottom: 0px;
background: ${theme.v2.palette.action.hover};
background: ${theme.palette.action.hover};
}
}
`,
activeStyle: css`
label: activeTabStyle;
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
overflow: hidden;
font-weight: ${theme.v2.typography.fontWeightMedium};
font-weight: ${theme.typography.fontWeightMedium};
a {
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
}
&::before {
@ -111,7 +111,7 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
height: 4px;
border-radius: 2px;
bottom: 0px;
background-image: ${theme.v2.palette.gradients.brandHorizontal} !important;
background-image: ${theme.palette.gradients.brandHorizontal} !important;
}
`,
};

View File

@ -1,23 +1,23 @@
import React, { FC, HTMLAttributes, ReactNode } from 'react';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
interface Props extends HTMLAttributes<HTMLDivElement> {
children: ReactNode;
}
const getTabContentStyle = stylesFactory((theme: GrafanaTheme) => {
const getTabContentStyle = stylesFactory((theme: GrafanaThemeV2) => {
return {
tabContent: css`
padding: ${theme.spacing.sm};
background: ${theme.v2.palette.background.primary};
padding: ${theme.spacing(1)};
background: ${theme.palette.background.primary};
`,
};
});
export const TabContent: FC<Props> = ({ children, className, ...restProps }) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getTabContentStyle(theme);
return (

View File

@ -1,6 +1,6 @@
import React, { ReactNode } from 'react';
import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
import { stylesFactory, useTheme2 } from '../../themes';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
export interface Props {
@ -11,12 +11,12 @@ export interface Props {
hideBorder?: boolean;
}
const getTabsBarStyles = stylesFactory((theme: GrafanaTheme, hideBorder = false) => {
const getTabsBarStyles = stylesFactory((theme: GrafanaThemeV2, hideBorder = false) => {
return {
tabsWrapper:
!hideBorder &&
css`
border-bottom: 1px solid ${theme.v2.palette.border.weak};
border-bottom: 1px solid ${theme.palette.border.weak};
`,
tabs: css`
position: relative;
@ -29,7 +29,7 @@ const getTabsBarStyles = stylesFactory((theme: GrafanaTheme, hideBorder = false)
});
export const TabsBar = React.forwardRef<HTMLDivElement, Props>(({ children, className, hideBorder }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const tabsStyles = getTabsBarStyles(theme, hideBorder);
return (

View File

@ -1,7 +1,7 @@
import React, { HTMLProps } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { stylesFactory, useTheme } from '../../themes';
import { stylesFactory, useTheme2 } from '../../themes';
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
export interface Props extends Omit<HTMLProps<HTMLTextAreaElement>, 'size'> {
@ -10,22 +10,22 @@ export interface Props extends Omit<HTMLProps<HTMLTextAreaElement>, 'size'> {
}
export const TextArea = React.forwardRef<HTMLTextAreaElement, Props>(({ invalid, className, ...props }, ref) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getTextAreaStyle(theme, invalid);
return <textarea {...props} className={cx(styles.textarea, className)} ref={ref} />;
});
const getTextAreaStyle = stylesFactory((theme: GrafanaTheme, invalid = false) => {
const getTextAreaStyle = stylesFactory((theme: GrafanaThemeV2, invalid = false) => {
return {
textarea: cx(
sharedInputStyle(theme),
getFocusStyle(theme),
getFocusStyle(theme.v1),
css`
border-radius: ${theme.border.radius.sm};
padding: ${theme.spacing.formSpacingBase / 4}px ${theme.spacing.formSpacingBase}px;
border-radius: ${theme.shape.borderRadius()};
padding: ${theme.spacing.gridSize / 4}px ${theme.spacing.gridSize}px;
width: 100%;
border-color: ${invalid ? theme.palette.redBase : theme.colors.formInputBorder};
border-color: ${invalid ? theme.palette.error.border : theme.components.input.border};
`
),
};

View File

@ -1,18 +0,0 @@
import React from 'react';
import { Colors } from './Colors';
export default {
title: 'Docs Overview/Theme',
component: Colors,
decorators: [],
parameters: {
options: {
showPanel: false,
},
docs: {},
},
};
export const ColorsDemo = () => {
return <Colors />;
};

View File

@ -1,75 +0,0 @@
import React from 'react';
import { css, cx } from '@emotion/css';
import darkTheme from '../../themes/dark';
import lightTheme from '../../themes/light';
import { useStyles } from '../../themes';
export const Colors = () => {
const styles = useStyles(getStyles);
const renderColors = (color: any) => {
return Object.entries(color)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([name, color]: [string, any]) => {
return (
<div key={name} className={styles.wrapper}>
<span className={styles.name}>
{name} ({color})
</span>
<span
className={cx(
styles.color,
css`
background: ${color};
`
)}
/>
</div>
);
});
};
return (
<div className={styles.container}>
<div>
<h2>Light theme</h2>
<h3 className={styles.subheader}>Palette</h3>
{renderColors(lightTheme.palette)}
<h3 className={styles.subheader}>Colors</h3>
{renderColors(lightTheme.colors)}
</div>
<div>
<h2>Dark theme</h2>
<h3 className={styles.subheader}>Palette</h3>
{renderColors(darkTheme.palette)}
<h3 className={styles.subheader}>Colors</h3>
{renderColors(darkTheme.colors)}
</div>
</div>
);
};
const getStyles = () => {
return {
subheader: css`
margin: 20px 0;
`,
container: css`
display: flex;
justify-content: space-around;
width: 100%;
`,
wrapper: css`
display: flex;
align-items: center;
`,
name: css`
width: 250px;
`,
color: css`
display: inline-block;
width: 50px;
height: 50px;
`,
};
};

View File

@ -1,9 +1,9 @@
/** @jsxImportSource @emotion/react */
import { Profiler, ProfilerOnRenderCallback, useState, FC } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { useStyles, useTheme } from '../../themes';
import { useStyles2, useTheme2 } from '../../themes';
import { Button } from '../Button';
import { VerticalGroup } from '../Layout/Layout';
import classnames from 'classnames';
@ -53,7 +53,7 @@ interface TestComponentProps {
}
function UseStylesNoCX({ index }: TestComponentProps) {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
return (
<div className={styles.main}>
<div className={styles.child}>{index}</div>
@ -62,7 +62,7 @@ function UseStylesNoCX({ index }: TestComponentProps) {
}
function UseStylesWithConditionalCX({ index }: TestComponentProps) {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const mainStyles = cx(styles.main, { [styles.large]: index > 10, [styles.disabed]: index % 10 === 0 });
return (
@ -73,7 +73,7 @@ function UseStylesWithConditionalCX({ index }: TestComponentProps) {
}
function UseStylesWithConditionalClassNames({ index }: TestComponentProps) {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const mainStyles = classnames(styles.main, { [styles.large]: index > 10, [styles.disabed]: index % 10 === 0 });
return (
@ -84,7 +84,7 @@ function UseStylesWithConditionalClassNames({ index }: TestComponentProps) {
}
function UseStylesWithCSSProp({ index }: TestComponentProps) {
const styles = useStyles(getStylesObjects);
const styles = useStyles2(getStylesObjects);
return (
<div css={styles.main}>
@ -94,7 +94,7 @@ function UseStylesWithCSSProp({ index }: TestComponentProps) {
}
function UseStylesWithConditionalCSS({ index }: TestComponentProps) {
const styles = useStyles(getStylesObjects);
const styles = useStyles2(getStylesObjects);
const mainStyles = [styles.main, index > 10 && styles.large, index % 10 === 0 && styles.disabed];
return (
<div css={mainStyles}>
@ -104,7 +104,7 @@ function UseStylesWithConditionalCSS({ index }: TestComponentProps) {
}
function InlineEmotionCSS({ index }: TestComponentProps) {
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme);
return (
@ -141,7 +141,7 @@ function MeasureRender({ children, id }: { children: React.ReactNode; id: string
);
}
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
main: css(getStylesObjectMain(theme)),
large: css({
@ -156,7 +156,7 @@ const getStyles = (theme: GrafanaTheme) => {
};
};
const getStylesObjects = (theme: GrafanaTheme) => {
const getStylesObjects = (theme: GrafanaThemeV2) => {
return {
main: getStylesObjectMain(theme),
large: {
@ -171,20 +171,20 @@ const getStylesObjects = (theme: GrafanaTheme) => {
};
};
function getStylesObjectMain(theme: GrafanaTheme): any {
function getStylesObjectMain(theme: GrafanaThemeV2): any {
return {
background: 'blue',
border: '1px solid red',
color: 'white',
padding: theme.v2.spacing(1),
shadow: theme.v2.shadows.z1,
padding: theme.spacing(1),
shadow: theme.shadows.z1,
':hover': {
background: theme.colors.bg1,
background: theme.palette.background.primary,
},
};
}
function getStylesObjectChild(theme: GrafanaTheme): any {
function getStylesObjectChild(theme: GrafanaThemeV2): any {
return {
padding: '2px',
fontSize: '10px',

View File

@ -1,6 +1,6 @@
import React, { FC, useState } from 'react';
import { css, cx } from '@emotion/css';
import { useTheme } from '../../themes/ThemeContext';
import { useTheme2 } from '../../themes/ThemeContext';
import { Icon } from '../Icon/Icon';
import { HorizontalGroup, VerticalGroup } from '../Layout/Layout';
import { GrafanaThemeV2, ThemePaletteColor } from '@grafana/data';
@ -53,9 +53,7 @@ export const ThemeDemo = () => {
const [radioValue, setRadioValue] = useState('v');
const [boolValue, setBoolValue] = useState(false);
const [selectValue, setSelectValue] = useState('Item 2');
const oldTheme = useTheme();
const t = oldTheme.v2;
const t = useTheme2();
const richColors = [
t.palette.primary,
@ -299,7 +297,7 @@ export function ShadowDemo({ name, shadow }: { name: string; shadow: string }) {
}
export function ActionsDemo() {
const t = useTheme().v2;
const t = useTheme2();
const item = css({
padding: '8px',

View File

@ -1,10 +1,9 @@
import React, { ChangeEvent } from 'react';
import { mount } from 'enzyme';
import { ThresholdsMode } from '@grafana/data';
import { createTheme, ThresholdsMode } from '@grafana/data';
import { ThresholdsEditor, Props, thresholdsWithoutKey } from './ThresholdsEditor';
import { colors } from '../../utils';
import { mockThemeContext } from '../../themes/ThemeContext';
import { getTheme } from '../../themes/getTheme';
const setup = (propOverrides?: Partial<Props>) => {
const props: Props = {
@ -31,7 +30,7 @@ describe('ThresholdsEditor', () => {
let restoreThemeContext: any;
beforeAll(() => {
restoreThemeContext = mockThemeContext(getTheme('dark'));
restoreThemeContext = mockThemeContext(createTheme());
});
afterAll(() => {

View File

@ -206,7 +206,7 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
return (
<ThemeContext.Consumer>
{(theme) => {
const styles = getStyles(theme);
const styles = getStyles(theme.v1);
return (
<div className={styles.wrapper}>
<Button

View File

@ -1,7 +1,7 @@
import React, { FC, FormEvent, MouseEvent, useState } from 'react';
import { css, cx } from '@emotion/css';
import { dateMath, dateTime, getDefaultTimeRange, GrafanaTheme, TimeRange, TimeZone } from '@grafana/data';
import { useStyles } from '../../themes/ThemeContext';
import { dateMath, dateTime, getDefaultTimeRange, GrafanaThemeV2, TimeRange, TimeZone } from '@grafana/data';
import { useStyles2 } from '../../themes/ThemeContext';
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
import { Icon } from '../Icon/Icon';
import { getInputStyles } from '../Input/Input';
@ -40,7 +40,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
hideQuickRanges = false,
}) => {
const [isOpen, setIsOpen] = useState(false);
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const onOpen = (event: FormEvent<HTMLDivElement>) => {
event.stopPropagation();
@ -100,7 +100,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
);
};
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
const inputStyles = getInputStyles({ theme, invalid: false });
return {
container: css`
@ -119,25 +119,25 @@ const getStyles = (theme: GrafanaTheme) => {
justify-content: space-between;
cursor: pointer;
padding-right: 0;
line-height: ${theme.spacing.formInputHeight - 2}px;
${getFocusStyle(theme)};
line-height: ${theme.v1.spacing.formInputHeight - 2}px;
${getFocusStyle(theme.v1)};
`
),
caretIcon: cx(
inputStyles.suffix,
css`
position: relative;
margin-left: ${theme.spacing.xs};
margin-left: ${theme.v1.spacing.xs};
`
),
clearIcon: css`
margin-right: ${theme.spacing.xs};
margin-right: ${theme.v1.spacing.xs};
&:hover {
color: ${theme.colors.linkHover};
color: ${theme.v1.colors.linkHover};
}
`,
placeholder: css`
color: ${theme.colors.formInputPlaceholderText};
color: ${theme.v1.colors.formInputPlaceholderText};
opacity: 1;
`,
};

View File

@ -1,7 +1,6 @@
import { dateTime, TimeRange } from '@grafana/data';
import { createTheme, dateTime, TimeRange } from '@grafana/data';
import { render } from '@testing-library/react';
import React from 'react';
import dark from '../../themes/dark';
import { UnthemedTimeRangePicker } from './TimeRangePicker';
const from = dateTime('2019-12-17T07:48:27.433Z');
@ -23,7 +22,7 @@ describe('TimePicker', () => {
onMoveBackward={() => {}}
onMoveForward={() => {}}
onZoom={() => {}}
theme={dark}
theme={createTheme().v1}
/>
);

View File

@ -1,8 +1,8 @@
import { GrafanaTheme, isDateTime, TimeOption, TimeRange, TimeZone } from '@grafana/data';
import { GrafanaThemeV2, isDateTime, TimeOption, TimeRange, TimeZone } from '@grafana/data';
import { css, cx } from '@emotion/css';
import React, { memo, useState } from 'react';
import { useMedia } from 'react-use';
import { stylesFactory, useTheme } from '../../../themes';
import { stylesFactory, useTheme2 } from '../../../themes';
import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar';
import { Icon } from '../../Icon/Icon';
import { mapRangeToTimeOption } from './mapper';
@ -11,20 +11,20 @@ import { TimeRangeForm } from './TimeRangeForm';
import { TimeRangeList } from './TimeRangeList';
import { TimePickerFooter } from './TimePickerFooter';
const getStyles = stylesFactory((theme: GrafanaTheme, isReversed, hideQuickRanges, isContainerTall) => {
const getStyles = stylesFactory((theme: GrafanaThemeV2, isReversed, hideQuickRanges, isContainerTall) => {
return {
container: css`
background: ${theme.v2.palette.background.secondary};
box-shadow: ${theme.v2.shadows.z4};
background: ${theme.palette.background.secondary};
box-shadow: ${theme.shadows.z4};
position: absolute;
z-index: ${theme.zIndex.dropdown};
width: 546px;
top: 116%;
border-radius: 2px;
border: 1px solid ${theme.v2.palette.border.weak};
border: 1px solid ${theme.palette.border.weak};
${isReversed ? 'left' : 'right'}: 0;
@media only screen and (max-width: ${theme.breakpoints.lg}) {
@media only screen and (max-width: ${theme.breakpoints.values.lg}px) {
width: 262px;
}
`,
@ -35,16 +35,16 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isReversed, hideQuickRange
leftSide: css`
display: flex;
flex-direction: column;
border-right: ${isReversed ? 'none' : `1px solid ${theme.v2.palette.border.weak}`};
border-right: ${isReversed ? 'none' : `1px solid ${theme.palette.border.weak}`};
width: ${!hideQuickRanges ? '60%' : '100%'};
overflow: hidden;
order: ${isReversed ? 1 : 0};
`,
rightSide: css`
width: 40% !important;
border-right: ${isReversed ? `1px solid ${theme.v2.palette.border.weak}` : 'none'};
border-right: ${isReversed ? `1px solid ${theme.palette.border.weak}` : 'none'};
@media only screen and (max-width: ${theme.breakpoints.lg}) {
@media only screen and (max-width: ${theme.breakpoints.values.lg}px) {
width: 100% !important;
}
`,
@ -54,18 +54,18 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isReversed, hideQuickRange
};
});
const getNarrowScreenStyles = stylesFactory((theme: GrafanaTheme) => {
const getNarrowScreenStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
header: css`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid ${theme.v2.palette.border.weak};
border-bottom: 1px solid ${theme.palette.border.weak};
padding: 7px 9px 7px 9px;
`,
body: css`
border-bottom: 1px solid ${theme.v2.palette.border.weak};
border-bottom: 1px solid ${theme.palette.border.weak};
`,
form: css`
padding: 7px 9px 7px 9px;
@ -73,7 +73,7 @@ const getNarrowScreenStyles = stylesFactory((theme: GrafanaTheme) => {
};
});
const getFullScreenStyles = stylesFactory((theme: GrafanaTheme, hideQuickRanges?: boolean) => {
const getFullScreenStyles = stylesFactory((theme: GrafanaThemeV2, hideQuickRanges?: boolean) => {
return {
container: css`
padding-top: 9px;
@ -88,12 +88,12 @@ const getFullScreenStyles = stylesFactory((theme: GrafanaTheme, hideQuickRanges?
display: flex;
flex-direction: column;
justify-content: flex-end;
padding-top: ${theme.spacing.sm};
padding-top: ${theme.spacing(1)};
`,
};
});
const getEmptyListStyles = stylesFactory((theme: GrafanaTheme) => {
const getEmptyListStyles = stylesFactory((theme: GrafanaThemeV2) => {
return {
container: css`
padding: 12px;
@ -105,7 +105,7 @@ const getEmptyListStyles = stylesFactory((theme: GrafanaTheme) => {
}
`,
link: css`
color: ${theme.colors.linkExternal};
color: ${theme.palette.text.link};
`,
};
});
@ -153,7 +153,7 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
const isHistoryEmpty = !history?.length;
const isContainerTall =
(isFullscreen && showHistory) || (!isFullscreen && ((showHistory && !isHistoryEmpty) || !hideQuickRanges));
const theme = useTheme();
const theme = useTheme2();
const styles = getStyles(theme, isReversed, hideQuickRanges, isContainerTall);
const historyOptions = mapToHistoryOptions(history, timeZone);
@ -196,15 +196,15 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
};
export const TimePickerContent: React.FC<Props> = (props) => {
const theme = useTheme();
const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.lg})`);
const theme = useTheme2();
const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.values.lg}px)`);
return <TimePickerContentWithScreenSize {...props} isFullscreen={isFullscreen} />;
};
const NarrowScreenForm: React.FC<FormProps> = (props) => {
const { value, hideQuickRanges, onChange, timeZone, historyOptions = [], showHistory } = props;
const theme = useTheme();
const theme = useTheme2();
const styles = getNarrowScreenStyles(theme);
const isAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
const [collapsedFlag, setCollapsedFlag] = useState(!isAbsolute);
@ -246,7 +246,7 @@ const NarrowScreenForm: React.FC<FormProps> = (props) => {
};
const FullScreenForm: React.FC<FormProps> = (props) => {
const theme = useTheme();
const theme = useTheme2();
const styles = getFullScreenStyles(theme, props.hideQuickRanges);
return (
@ -280,7 +280,7 @@ const FullScreenForm: React.FC<FormProps> = (props) => {
};
const EmptyRecentList = memo(() => {
const theme = useTheme();
const theme = useTheme2();
const styles = getEmptyListStyles(theme);
return (

View File

@ -1,7 +1,7 @@
import React, { FC, useState, useCallback } from 'react';
import { css, cx } from '@emotion/css';
import { TimeZone, GrafanaTheme, getTimeZoneInfo } from '@grafana/data';
import { stylesFactory, useTheme } from '../../../themes';
import { TimeZone, GrafanaThemeV2, getTimeZoneInfo } from '@grafana/data';
import { stylesFactory, useTheme2 } from '../../../themes';
import { TimeZoneTitle } from '../TimeZonePicker/TimeZoneTitle';
import { TimeZoneDescription } from '../TimeZonePicker/TimeZoneDescription';
import { TimeZoneOffset } from '../TimeZonePicker/TimeZoneOffset';
@ -30,7 +30,7 @@ export const TimePickerFooter: FC<Props> = (props) => {
[isEditing, setEditing]
);
const theme = useTheme();
const theme = useTheme2();
const style = getStyle(theme);
if (!isString(timeZone)) {
@ -82,10 +82,10 @@ export const TimePickerFooter: FC<Props> = (props) => {
);
};
const getStyle = stylesFactory((theme: GrafanaTheme) => {
const getStyle = stylesFactory((theme: GrafanaThemeV2) => {
return {
container: css`
border-top: 1px solid ${theme.v2.palette.border.weak};
border-top: 1px solid ${theme.palette.border.weak};
padding: 11px;
display: flex;
flex-direction: row;

View File

@ -1,9 +1,9 @@
import React, { memo } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme, TimeOption } from '@grafana/data';
import { useTheme, stylesFactory } from '../../../themes';
import { GrafanaThemeV2, TimeOption } from '@grafana/data';
import { useStyles2 } from '../../../themes/ThemeContext';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
container: css`
display: flex;
@ -12,16 +12,16 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
padding: 7px 9px 7px 9px;
&:hover {
background: ${theme.v2.palette.action.hover};
background: ${theme.palette.action.hover};
cursor: pointer;
}
`,
selected: css`
background: ${theme.v2.palette.action.selected};
background: ${theme.palette.action.selected};
}
`,
};
});
};
interface Props {
value: TimeOption;
@ -30,8 +30,7 @@ interface Props {
}
export const TimeRangeOption = memo<Props>(({ value, onSelect, selected = false }) => {
const theme = useTheme();
const styles = getStyles(theme);
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.container, selected && styles.selected)} onClick={() => onSelect(value)} tabIndex={-1}>

View File

@ -52,7 +52,7 @@ export class Typeahead extends React.PureComponent<Props, State> {
const allItems = flattenGroupItems(this.props.groupedItems);
const longestLabel = calculateLongestLabel(allItems);
const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context, allItems, longestLabel);
const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context.v1, allItems, longestLabel);
this.setState({
listWidth,
listHeight,
@ -86,7 +86,7 @@ export class Typeahead extends React.PureComponent<Props, State> {
if (isEqual(prevProps.groupedItems, this.props.groupedItems) === false) {
const allItems = flattenGroupItems(this.props.groupedItems);
const longestLabel = calculateLongestLabel(allItems);
const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context, allItems, longestLabel);
const { listWidth, listHeight, itemHeight } = calculateListSizes(this.context.v1, allItems, longestLabel);
this.setState({ listWidth, listHeight, itemHeight, allItems, typeaheadIndex: null });
}
};

View File

@ -1,8 +1,9 @@
import React, { useContext } from 'react';
import React from 'react';
import { css, cx } from '@emotion/css';
import { CompletionItem, ThemeContext } from '../..';
import { GrafanaTheme, renderMarkdown } from '@grafana/data';
import { useTheme } from '../../themes/ThemeContext';
import { CompletionItem } from '../../types';
const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => {
return {
@ -36,7 +37,7 @@ export const TypeaheadInfo: React.FC<Props> = ({ item, height }) => {
const visible = item && !!item.documentation;
const label = item ? item.label : '';
const documentation = renderMarkdown(item?.documentation);
const theme = useContext(ThemeContext);
const theme = useTheme();
const styles = getStyles(theme, height, visible);
return (

View File

@ -1,12 +1,12 @@
import React, { useContext } from 'react';
import React from 'react';
// @ts-ignore
import Highlighter from 'react-highlight-words';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { CompletionItem, CompletionItemKind } from '../../types/completion';
import { ThemeContext } from '../../themes/ThemeContext';
import { PartialHighlighter } from './PartialHighlighter';
import { useStyles } from '../../themes/ThemeContext';
interface Props {
isSelected: boolean;
@ -59,8 +59,7 @@ const getStyles = (theme: GrafanaTheme) => ({
});
export const TypeaheadItem: React.FC<Props> = (props: Props) => {
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
const styles = useStyles(getStyles);
const { isSelected, item, prefix, style, onMouseEnter, onMouseLeave, onClickItem } = props;
const className = isSelected ? cx([styles.typeaheadItem, styles.typeaheadItemSelected]) : cx([styles.typeaheadItem]);

View File

@ -50,14 +50,14 @@ export class UPlotAxisBuilder extends PlotConfigBuilder<AxisProps, Axis> {
theme,
} = this.props;
const font = `12px ${theme.v2.typography.fontFamily}`;
const font = `12px ${theme.typography.fontFamily.sansSerif}`;
const gridColor = theme.v2.isDark ? 'rgba(240, 250, 255, 0.09)' : 'rgba(0, 10, 23, 0.09)';
const gridColor = theme.isDark ? 'rgba(240, 250, 255, 0.09)' : 'rgba(0, 10, 23, 0.09)';
let config: Axis = {
scale: scaleKey,
show,
stroke: theme.v2.palette.text.primary,
stroke: theme.colors.text,
side: getUPlotSideFromAxis(placement),
font,
labelFont: font,

View File

@ -10,9 +10,11 @@ import {
ScaleOrientation,
ScaleDirection,
} from '../config';
import darkTheme from '../../../themes/dark';
import { createTheme } from '@grafana/data';
describe('UPlotConfigBuilder', () => {
const darkTheme = createTheme().v1;
describe('default config', () => {
it('builds default config', () => {
const builder = new UPlotConfigBuilder();

View File

@ -1,7 +1,6 @@
import { FieldColorMode, getColorForTheme, GrafanaTheme, ThresholdsConfig } from '@grafana/data';
import { FieldColorMode, GrafanaTheme, ThresholdsConfig } from '@grafana/data';
import tinycolor from 'tinycolor2';
import uPlot from 'uplot';
import darkTheme from '../../../themes/dark';
import { getCanvasContext } from '../../../utils/measureText';
export function getOpacityGradientFn(
@ -69,7 +68,7 @@ export function getScaleGradientFn(
console.log('series.max', series.max);
const getColorWithAlpha = (color: string) => {
return tinycolor(getColorForTheme(color, darkTheme)).setAlpha(opacity).toString();
return 'rgb(255, 0, 0)';
};
const addColorStop = (value: number, color: string) => {

View File

@ -1,12 +1,12 @@
import React from 'react';
import { Global } from '@emotion/react';
import { useTheme } from '..';
import { useTheme2 } from '..';
import { getElementStyles } from './elements';
/** @internal */
export function GlobalStyles() {
const theme = useTheme();
const types = getElementStyles(theme.v2);
const theme = useTheme2();
const types = getElementStyles(theme);
return <Global styles={[types]} />;
}

View File

@ -1,8 +1,7 @@
import { GrafanaTheme, GrafanaThemeType } from '@grafana/data';
import { createTheme, GrafanaTheme, GrafanaThemeV2 } from '@grafana/data';
import hoistNonReactStatics from 'hoist-non-react-statics';
import React, { useContext, useEffect } from 'react';
import { Themeable } from '../types/theme';
import { getTheme } from './getTheme';
import { stylesFactory } from './stylesFactory';
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
@ -11,16 +10,18 @@ type Subtract<T, K> = Omit<T, keyof K>;
/**
* Mock used in tests
*/
let ThemeContextMock: React.Context<GrafanaTheme> | null = null;
let ThemeContextMock: React.Context<GrafanaThemeV2> | null = null;
// Used by useStyles()
export const memoizedStyleCreators = new WeakMap();
// Use Grafana Dark theme by default
/** @public */
export const ThemeContext = React.createContext(getTheme(GrafanaThemeType.Dark));
export const ThemeContext = React.createContext(createTheme());
ThemeContext.displayName = 'ThemeContext';
/** @deprecated use withTheme2 */
export const withTheme = <P extends Themeable, S extends {} = {}>(Component: React.ComponentType<P>) => {
const WithTheme: React.FunctionComponent<Subtract<P, Themeable>> = (props) => {
/**
@ -28,8 +29,10 @@ export const withTheme = <P extends Themeable, S extends {} = {}>(Component: Rea
* This is used in tests when mocking theme using mockThemeContext function defined below
*/
const ContextComponent = ThemeContextMock || ThemeContext;
// @ts-ignore
return <ContextComponent.Consumer>{(theme) => <Component {...props} theme={theme} />}</ContextComponent.Consumer>;
return (
// @ts-ignore
<ContextComponent.Consumer>{(theme) => <Component {...props} theme={theme.v1} />}</ContextComponent.Consumer>
);
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
@ -38,7 +41,32 @@ export const withTheme = <P extends Themeable, S extends {} = {}>(Component: Rea
return WithTheme as Hoisted;
};
/** @alpha */
export const withTheme2 = <P extends Themeable, S extends {} = {}>(Component: React.ComponentType<P>) => {
const WithTheme: React.FunctionComponent<Subtract<P, Themeable>> = (props) => {
/**
* If theme context is mocked, let's use it instead of the original context
* This is used in tests when mocking theme using mockThemeContext function defined below
*/
const ContextComponent = ThemeContextMock || ThemeContext;
return (
// @ts-ignore
<ContextComponent.Consumer>{(theme) => <Component {...props} theme={theme} />}</ContextComponent.Consumer>
);
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
hoistNonReactStatics(WithTheme, Component);
type Hoisted = typeof WithTheme & S;
return WithTheme as Hoisted;
};
/** @deprecated use useTheme2 */
export function useTheme(): GrafanaTheme {
return useContext(ThemeContextMock || ThemeContext).v1;
}
export function useTheme2(): GrafanaThemeV2 {
return useContext(ThemeContextMock || ThemeContext);
}
@ -67,11 +95,37 @@ export function useStyles<T>(getStyles: (theme: GrafanaTheme) => T) {
return memoizedStyleCreator(theme);
}
/**
* Hook for using memoized styles with access to the theme.
*
* NOTE: For memoization to work, you need to ensure that the function
* you pass in doesn't change, or only if it needs to. (i.e. declare
* your style creator outside of a function component or use `useCallback()`.)
* */
export function useStyles2<T>(getStyles: (theme: GrafanaThemeV2) => T) {
const theme = useTheme2();
let memoizedStyleCreator = memoizedStyleCreators.get(getStyles) as typeof getStyles;
if (!memoizedStyleCreator) {
memoizedStyleCreator = stylesFactory(getStyles);
memoizedStyleCreators.set(getStyles, memoizedStyleCreator);
}
useEffect(() => {
return () => {
memoizedStyleCreators.delete(getStyles);
};
}, [getStyles]);
return memoizedStyleCreator(theme);
}
/**
* Enables theme context mocking
*/
export const mockThemeContext = (theme: Partial<GrafanaTheme>) => {
ThemeContextMock = React.createContext(theme as GrafanaTheme);
export const mockThemeContext = (theme: Partial<GrafanaThemeV2>) => {
ThemeContextMock = React.createContext(theme as GrafanaThemeV2);
return () => {
ThemeContextMock = null;
};

View File

@ -1,9 +1,9 @@
/* eslint-disable max-len */
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { renderGeneratedFileBanner } from '../utils/generatedFileBanner';
export const darkThemeVarsTemplate = (theme: GrafanaTheme) =>
export const darkThemeVarsTemplate = (theme: GrafanaThemeV2) =>
`${renderGeneratedFileBanner('grafana-ui/src/themes/dark.ts', 'grafana-ui/src/themes/_variables.dark.scss.tmpl.ts')}
// Global values
// --------------------------------------------------
@ -12,96 +12,96 @@ $theme-name: dark;
// New Colors
// -------------------------
$blue-light: ${theme.palette.blue95};
$blue-base: ${theme.palette.blue80};
$blue-shade: ${theme.palette.blue77};
$red-base: ${theme.palette.redBase};
$red-shade: ${theme.palette.redShade};
$green-base: ${theme.palette.greenBase};
$green-shade: ${theme.palette.greenShade};
$orange-dark: ${theme.palette.orangeDark};
$blue-light: ${theme.palette.primary.text};
$blue-base: ${theme.palette.primary.main};
$blue-shade: ${theme.palette.primary.shade};
$red-base: ${theme.palette.error.main};
$red-shade: ${theme.palette.error.shade};
$green-base: ${theme.palette.success.main};
$green-shade: ${theme.palette.success.shade};
$orange-dark: ${theme.v1.palette.orangeDark};
$gray98: ${theme.palette.gray98};
$gray95: ${theme.palette.gray95};
$gray85: ${theme.palette.gray85};
$gray70: ${theme.palette.gray70};
$gray60: ${theme.palette.gray60};
$gray33: ${theme.palette.gray33};
$gray25: ${theme.palette.gray25};
$gray15: ${theme.palette.gray15};
$gray10: ${theme.palette.gray10};
$gray05: ${theme.palette.gray05};
$gray98: ${theme.v1.palette.gray98};
$gray95: ${theme.v1.palette.gray95};
$gray85: ${theme.v1.palette.gray85};
$gray70: ${theme.v1.palette.gray70};
$gray60: ${theme.v1.palette.gray60};
$gray33: ${theme.v1.palette.gray33};
$gray25: ${theme.v1.palette.gray25};
$gray15: ${theme.v1.palette.gray15};
$gray10: ${theme.v1.palette.gray10};
$gray05: ${theme.v1.palette.gray05};
// Grays
// -------------------------
$black: ${theme.palette.black};
$dark-1: ${theme.palette.dark1};
$dark-2: ${theme.palette.dark2};
$dark-3: ${theme.palette.dark3};
$dark-4: ${theme.palette.dark4};
$dark-5: ${theme.palette.dark5};
$dark-6: ${theme.palette.dark6};
$dark-7: ${theme.palette.dark7};
$dark-8: ${theme.palette.dark8};
$dark-9: ${theme.palette.dark9};
$dark-10: ${theme.palette.dark10};
$gray-1: ${theme.palette.gray1};
$gray-2: ${theme.palette.gray2};
$gray-3: ${theme.palette.gray3};
$gray-4: ${theme.palette.gray4};
$gray-5: ${theme.palette.gray5};
$gray-6: ${theme.palette.gray6};
$black: ${theme.v1.palette.black};
$dark-1: ${theme.v1.palette.dark1};
$dark-2: ${theme.v1.palette.dark2};
$dark-3: ${theme.v1.palette.dark3};
$dark-4: ${theme.v1.palette.dark4};
$dark-5: ${theme.v1.palette.dark5};
$dark-6: ${theme.v1.palette.dark6};
$dark-7: ${theme.v1.palette.dark7};
$dark-8: ${theme.v1.palette.dark8};
$dark-9: ${theme.v1.palette.dark9};
$dark-10: ${theme.v1.palette.dark10};
$gray-1: ${theme.v1.palette.gray1};
$gray-2: ${theme.v1.palette.gray2};
$gray-3: ${theme.v1.palette.gray3};
$gray-4: ${theme.v1.palette.gray4};
$gray-5: ${theme.v1.palette.gray5};
$gray-6: ${theme.v1.palette.gray6};
$input-black: ${theme.colors.formInputBg};
$white: ${theme.palette.white};
$input-black: ${theme.v1.colors.formInputBg};
$white: ${theme.v1.palette.white};
$layer0: ${theme.v2.palette.background.canvas};
$layer1: ${theme.v2.palette.background.primary};
$layer2: ${theme.v2.palette.background.secondary};
$layer0: ${theme.palette.background.canvas};
$layer1: ${theme.palette.background.primary};
$layer2: ${theme.palette.background.secondary};
$divider: ${theme.v2.palette.border.weak};
$divider: ${theme.palette.border.weak};
$border0: ${theme.v2.palette.border.weak};
$border1: ${theme.v2.palette.border.medium};
$border0: ${theme.palette.border.weak};
$border1: ${theme.palette.border.medium};
// Accent colors
// -------------------------
$blue: ${theme.palette.blue85};
$blue: ${theme.v1.palette.blue85};
$red: $red-base;
$yellow: ${theme.palette.yellow};
$orange: ${theme.palette.orange};
$purple: ${theme.palette.purple};
$variable: ${theme.colors.textBlue};
$yellow: ${theme.v1.palette.yellow};
$orange: ${theme.v1.palette.orange};
$purple: ${theme.v1.palette.purple};
$variable: ${theme.v1.colors.textBlue};
$brand-primary: ${theme.palette.brandPrimary};
$brand-success: ${theme.palette.brandSuccess};
$brand-warning: ${theme.palette.brandWarning};
$brand-danger: ${theme.palette.brandDanger};
$brand-primary: ${theme.v1.palette.brandPrimary};
$brand-success: ${theme.v1.palette.brandSuccess};
$brand-warning: ${theme.v1.palette.brandWarning};
$brand-danger: ${theme.v1.palette.brandDanger};
$query-red: ${theme.palette.queryRed};
$query-green: ${theme.palette.queryGreen};
$query-purple: ${theme.palette.queryPurple};
$query-orange: ${theme.palette.orange};
$query-red: ${theme.v1.palette.queryRed};
$query-green: ${theme.v1.palette.queryGreen};
$query-purple: ${theme.v1.palette.queryPurple};
$query-orange: ${theme.v1.palette.orange};
// Status colors
// -------------------------¨
$online: ${theme.palette.online};
$warn: ${theme.palette.warn};
$critical: ${theme.palette.critical};
$online: ${theme.v1.palette.online};
$warn: ${theme.v1.palette.warn};
$critical: ${theme.v1.palette.critical};
// Scaffolding
// -------------------------
$body-bg: ${theme.colors.bodyBg};
$page-bg: ${theme.colors.bodyBg};
$dashboard-bg: ${theme.colors.dashboardBg};
$body-bg: ${theme.v1.colors.bodyBg};
$page-bg: ${theme.v1.colors.bodyBg};
$dashboard-bg: ${theme.v1.colors.dashboardBg};
$text-color-strong: ${theme.colors.textStrong};
$text-color: ${theme.colors.text};
$text-color-semi-weak: ${theme.colors.textSemiWeak};
$text-color-weak: ${theme.colors.textWeak};
$text-color-faint: ${theme.colors.textFaint};
$text-color-emphasis: ${theme.colors.textStrong};
$text-blue: ${theme.colors.textBlue};
$text-color-strong: ${theme.v1.colors.textStrong};
$text-color: ${theme.v1.colors.text};
$text-color-semi-weak: ${theme.v1.colors.textSemiWeak};
$text-color-weak: ${theme.v1.colors.textWeak};
$text-color-faint: ${theme.v1.colors.textFaint};
$text-color-emphasis: ${theme.v1.colors.textStrong};
$text-blue: ${theme.v1.colors.textBlue};
$text-shadow-faint: 1px 1px 4px rgb(45, 45, 45);
$textShadow: none;
@ -112,14 +112,14 @@ $brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
// Links
// -------------------------
$link-color: ${theme.colors.link};
$link-color-disabled: ${theme.colors.linkDisabled};
$link-hover-color: ${theme.colors.linkHover};
$external-link-color: ${theme.colors.linkExternal};
$link-color: ${theme.v1.colors.link};
$link-color-disabled: ${theme.v1.colors.linkDisabled};
$link-hover-color: ${theme.v1.colors.linkHover};
$external-link-color: ${theme.v1.colors.linkExternal};
// Typography
// -------------------------
$headings-color: ${theme.colors.textHeading};
$headings-color: ${theme.v1.colors.textHeading};
$abbr-border-color: $gray-2 !default;
$text-muted: $text-color-weak;
@ -127,30 +127,30 @@ $hr-border-color: $dark-9;
// Panel
// -------------------------
$panel-bg: ${theme.v2.components.panel.background};
$panel-border: ${theme.v2.components.panel.border};
$panel-header-hover-bg: ${theme.v2.palette.action.hover};
$panel-box-shadow: ${theme.v2.components.panel.boxShadow};
$panel-bg: ${theme.components.panel.background};
$panel-border: ${theme.components.panel.border};
$panel-header-hover-bg: ${theme.palette.action.hover};
$panel-box-shadow: ${theme.components.panel.boxShadow};
$panel-corner: $panel-bg;
// page header
$page-header-bg: ${theme.colors.pageHeaderBg};
$page-header-bg: ${theme.v1.colors.pageHeaderBg};
$page-header-shadow: inset 0px -4px 14px $dark-3;
$page-header-border-color: ${theme.colors.pageHeaderBorder};
$page-header-border-color: ${theme.v1.colors.pageHeaderBorder};
$divider-border-color: $gray-1;
// Graphite Target Editor
$tight-form-func-bg: ${theme.v2.palette.background.secondary};
$tight-form-func-highlight-bg: ${theme.v2.palette.emphasize(theme.v2.palette.background.secondary, 0.03)};
$tight-form-func-bg: ${theme.palette.background.secondary};
$tight-form-func-highlight-bg: ${theme.palette.emphasize(theme.palette.background.secondary, 0.03)};
$modal-backdrop-bg: ${theme.colors.bg3};
$modal-backdrop-bg: ${theme.v1.colors.bg3};
$code-tag-bg: $dark-1;
$code-tag-border: $dark-9;
// cards
$card-background: ${theme.v2.palette.background.secondary};
$card-background-hover: ${theme.v2.palette.emphasize(theme.v2.palette.background.secondary, 0.03)};
$card-background: ${theme.palette.background.secondary};
$card-background-hover: ${theme.palette.emphasize(theme.palette.background.secondary, 0.03)};
$card-shadow: none;
// Lists
@ -158,7 +158,7 @@ $list-item-bg: $card-background;
$list-item-hover-bg: $card-background-hover;
$list-item-shadow: $card-shadow;
$empty-list-cta-bg: ${theme.colors.bg2};
$empty-list-cta-bg: ${theme.v1.colors.bg2};
// Scrollbars
$scrollbarBackground: #404357;
@ -167,10 +167,10 @@ $scrollbarBorder: black;
// Tables
// -------------------------
$table-bg-accent: ${theme.v2.palette.background.secondary};
$table-border: ${theme.v2.palette.border.medium};
$table-bg-odd: ${theme.v2.palette.emphasize(theme.v2.palette.background.primary, 0.02)};
$table-bg-hover: ${theme.v2.palette.emphasize(theme.v2.palette.background.primary, 0.05)};
$table-bg-accent: ${theme.palette.background.secondary};
$table-border: ${theme.palette.border.medium};
$table-bg-odd: ${theme.palette.emphasize(theme.palette.background.primary, 0.02)};
$table-bg-hover: ${theme.palette.emphasize(theme.palette.background.primary, 0.05)};
// Buttons
// -------------------------
@ -209,13 +209,13 @@ $btn-active-box-shadow: 0px 0px 4px rgba(255, 120, 10, 0.5);
$input-bg: $input-black;
$input-bg-disabled: $dark-6;
$input-color: ${theme.colors.formInputText};
$input-border-color: ${theme.colors.formInputBorder};
$input-color: ${theme.v1.colors.formInputText};
$input-border-color: ${theme.v1.colors.formInputBorder};
$input-box-shadow: none;
$input-border-focus: ${theme.palette.blue95};
$input-border-focus: ${theme.v1.palette.blue95};
$input-box-shadow-focus: $blue-light !default;
$input-color-placeholder: ${theme.colors.formInputPlaceholderText};
$input-label-bg: ${theme.colors.bg2};
$input-color-placeholder: ${theme.v1.colors.formInputPlaceholderText};
$input-label-bg: ${theme.v1.colors.bg2};
$input-color-select-arrow: $white;
// Search
@ -228,10 +228,10 @@ $typeahead-selected-color: $yellow;
// Dropdowns
// -------------------------
$dropdownBackground: ${theme.v2.palette.background.secondary};
$dropdownBorder: ${theme.v2.palette.border.weak};
$dropdownDividerTop: ${theme.v2.palette.border.weak};
$dropdownDividerBottom: ${theme.v2.palette.border.weak};
$dropdownBackground: ${theme.palette.background.secondary};
$dropdownBorder: ${theme.palette.border.weak};
$dropdownDividerTop: ${theme.palette.border.weak};
$dropdownDividerBottom: ${theme.palette.border.weak};
$dropdownLinkColor: $link-color;
$dropdownLinkColorHover: $white;
@ -252,16 +252,16 @@ $navbarBorder: 1px solid $dark-6;
$side-menu-bg: $panel-bg;
$side-menu-bg-mobile: $panel-bg;
$side-menu-border: none;
$side-menu-item-hover-bg: ${theme.colors.bg2};
$side-menu-item-hover-bg: ${theme.v1.colors.bg2};
$side-menu-shadow: 0 0 30px #111;
$side-menu-icon-color: ${theme.palette.gray70};
$side-menu-header-color: ${theme.colors.text};
$side-menu-icon-color: ${theme.v1.palette.gray70};
$side-menu-header-color: ${theme.v1.colors.text};
// Menu dropdowns
// -------------------------
$menu-dropdown-bg: ${theme.v2.palette.background.secondary};
$menu-dropdown-hover-bg: ${theme.v2.palette.action.hover};
$menu-dropdown-shadow: ${theme.v2.shadows.z3};
$menu-dropdown-bg: ${theme.palette.background.secondary};
$menu-dropdown-hover-bg: ${theme.palette.action.hover};
$menu-dropdown-shadow: ${theme.shadows.z3};
// Tabs
// -------------------------
@ -284,17 +284,17 @@ $tooltipArrowWidth: 5px;
$tooltipLinkColor: $link-color;
$graph-tooltip-bg: $dark-1;
$tooltipBackground: ${theme.v2.palette.background.secondary};
$tooltipColor: ${theme.v2.palette.text.primary};
$tooltipArrowColor: ${theme.v2.palette.background.secondary};
$tooltipBackgroundError: ${theme.v2.palette.error.main};
$tooltipShadow: ${theme.v2.shadows.z2};
$tooltipBackground: ${theme.palette.background.secondary};
$tooltipColor: ${theme.palette.text.primary};
$tooltipArrowColor: ${theme.palette.background.secondary};
$tooltipBackgroundError: ${theme.palette.error.main};
$tooltipShadow: ${theme.shadows.z2};
$popover-bg: ${theme.v2.palette.background.secondary};
$popover-color: ${theme.v2.palette.text.primary};
$popover-border-color: ${theme.v2.palette.border.medium};
$popover-header-bg: ${theme.v2.palette.background.secondary};
$popover-shadow: ${theme.v2.shadows.z4};
$popover-bg: ${theme.palette.background.secondary};
$popover-color: ${theme.palette.text.primary};
$popover-border-color: ${theme.palette.border.medium};
$popover-header-bg: ${theme.palette.background.secondary};
$popover-shadow: ${theme.shadows.z4};
$popover-help-bg: $tooltipBackground;
$popover-help-color: $text-color;
@ -329,14 +329,14 @@ $json-explorer-url-color: #027bff;
// Changelog and diff
// -------------------------
$diff-label-bg: ${theme.colors.bg3};
$diff-label-bg: ${theme.v1.colors.bg3};
$diff-label-fg: $white;
$diff-group-bg: ${theme.colors.bg2};
$diff-group-bg: ${theme.v1.colors.bg2};
$diff-arrow-color: $white;
$diff-json-bg: ${theme.colors.bg2};
$diff-json-fg: ${theme.colors.text};
$diff-json-bg: ${theme.v1.colors.bg2};
$diff-json-fg: ${theme.v1.colors.text};
$diff-json-added: $blue-shade;
$diff-json-deleted: $red-shade;
@ -357,7 +357,7 @@ $variable-option-bg: $dropdownLinkBackgroundHover;
$switch-bg: $input-bg;
$switch-slider-color: $dark-3;
$switch-slider-off-bg: $gray-1;
$switch-slider-on-bg: ${theme.palette.blue95};
$switch-slider-on-bg: ${theme.v1.palette.blue95};
$switch-slider-shadow: 0 0 3px black;
//Checkbox
@ -380,8 +380,8 @@ $panel-editor-tabs-line-color: #e3e3e3;
$panel-editor-viz-item-bg-hover: darken($blue-base, 46%);
$panel-grid-placeholder-bg: darken(${theme.palette.blue77}, 30%);
$panel-grid-placeholder-shadow: 0 0 4px ${theme.palette.blue80};
$panel-grid-placeholder-bg: darken(${theme.v1.palette.blue77}, 30%);
$panel-grid-placeholder-shadow: 0 0 4px ${theme.v1.palette.blue80};
// logs
$logs-color-unknown: $gray-2;

View File

@ -1,10 +1,10 @@
/* eslint-disable max-len */
import { GrafanaTheme } from '@grafana/data';
import { renderGeneratedFileBanner } from '../utils/generatedFileBanner';
import { styleMixins } from '.';
import { GrafanaThemeV2 } from '@grafana/data';
export const lightThemeVarsTemplate = (theme: GrafanaTheme) =>
export const lightThemeVarsTemplate = (theme: GrafanaThemeV2) =>
`${renderGeneratedFileBanner('grafana-ui/src/themes/light.ts', 'grafana-ui/src/themes/_variable.light.scss.tmpl.ts')}
// Global values
// --------------------------------------------------
@ -13,91 +13,91 @@ $theme-name: light;
// New Colors
// -------------------------
$blue-light: ${theme.palette.blue95};
$blue-base: ${theme.palette.blue80};
$blue-shade: ${theme.palette.blue77};
$red-base: ${theme.palette.redBase};
$red-shade: ${theme.palette.redShade};
$green-base: ${theme.palette.greenBase};
$green-shade: ${theme.palette.greenShade};
$orange-dark: ${theme.palette.orangeDark};
$blue-light: ${theme.palette.primary.text};
$blue-base: ${theme.palette.primary.main};
$blue-shade: ${theme.palette.primary.shade};
$red-base: ${theme.palette.error.main};
$red-shade: ${theme.palette.error.shade};
$green-base: ${theme.palette.success.main};
$green-shade: ${theme.palette.success.shade};
$orange-dark: ${theme.v1.palette.orangeDark};
$gray98: ${theme.palette.gray98};
$gray95: ${theme.palette.gray95};
$gray85: ${theme.palette.gray85};
$gray70: ${theme.palette.gray70};
$gray60: ${theme.palette.gray60};
$gray33: ${theme.palette.gray33};
$gray25: ${theme.palette.gray25};
$gray15: ${theme.palette.gray15};
$gray10: ${theme.palette.gray10};
$gray05: ${theme.palette.gray05};
$gray98: ${theme.v1.palette.gray98};
$gray95: ${theme.v1.palette.gray95};
$gray85: ${theme.v1.palette.gray85};
$gray70: ${theme.v1.palette.gray70};
$gray60: ${theme.v1.palette.gray60};
$gray33: ${theme.v1.palette.gray33};
$gray25: ${theme.v1.palette.gray25};
$gray15: ${theme.v1.palette.gray15};
$gray10: ${theme.v1.palette.gray10};
$gray05: ${theme.v1.palette.gray05};
// Grays
// -------------------------
$black: ${theme.palette.black};
$black: ${theme.v1.palette.black};
$dark-1: ${theme.palette.dark1};
$dark-2: ${theme.palette.dark2};
$dark-4: ${theme.palette.dark4};
$dark-10: ${theme.palette.dark10};
$gray-1: ${theme.palette.gray1};
$gray-2: ${theme.palette.gray2};
$gray-3: ${theme.palette.gray3};
$gray-4: ${theme.palette.gray4};
$gray-5: ${theme.palette.gray5};
$gray-6: ${theme.palette.gray6};
$gray-7: ${theme.palette.gray7};
$dark-1: ${theme.v1.palette.dark1};
$dark-2: ${theme.v1.palette.dark2};
$dark-4: ${theme.v1.palette.dark4};
$dark-10: ${theme.v1.palette.dark10};
$gray-1: ${theme.v1.palette.gray1};
$gray-2: ${theme.v1.palette.gray2};
$gray-3: ${theme.v1.palette.gray3};
$gray-4: ${theme.v1.palette.gray4};
$gray-5: ${theme.v1.palette.gray5};
$gray-6: ${theme.v1.palette.gray6};
$gray-7: ${theme.v1.palette.gray7};
$white: ${theme.palette.white};
$white: ${theme.v1.palette.white};
$layer0: ${theme.v2.palette.background.canvas};
$layer1: ${theme.v2.palette.background.primary};
$layer2: ${theme.v2.palette.background.secondary};
$layer0: ${theme.palette.background.canvas};
$layer1: ${theme.palette.background.primary};
$layer2: ${theme.palette.background.secondary};
$divider: ${theme.v2.palette.border.weak};
$divider: ${theme.palette.border.weak};
$border0: ${theme.v2.palette.border.weak};
$border1: ${theme.v2.palette.border.medium};
$border0: ${theme.palette.border.weak};
$border1: ${theme.palette.border.medium};
// Accent colors
// -------------------------
$blue: ${theme.colors.textBlue};
$blue: ${theme.v1.colors.textBlue};
$red: $red-base;
$yellow: ${theme.palette.yellow};
$orange: ${theme.palette.orange};
$purple: ${theme.palette.purple};
$variable: ${theme.colors.textBlue};
$yellow: ${theme.v1.palette.yellow};
$orange: ${theme.v1.palette.orange};
$purple: ${theme.v1.palette.purple};
$variable: ${theme.v1.colors.textBlue};
$brand-primary: ${theme.palette.brandPrimary};
$brand-success: ${theme.palette.brandSuccess};
$brand-warning: ${theme.palette.brandWarning};
$brand-danger: ${theme.palette.brandDanger};
$brand-primary: ${theme.v1.palette.brandPrimary};
$brand-success: ${theme.v1.palette.brandSuccess};
$brand-warning: ${theme.v1.palette.brandWarning};
$brand-danger: ${theme.v1.palette.brandDanger};
$query-red: ${theme.palette.queryRed};
$query-green: ${theme.palette.queryGreen};
$query-purple: ${theme.palette.queryPurple};
$query-orange: ${theme.palette.orange};
$query-red: ${theme.v1.palette.queryRed};
$query-green: ${theme.v1.palette.queryGreen};
$query-purple: ${theme.v1.palette.queryPurple};
$query-orange: ${theme.v1.palette.orange};
// Status colors
// -------------------------
$online: ${theme.palette.online};
$warn: ${theme.palette.warn};
$critical: ${theme.palette.critical};
$online: ${theme.v1.palette.online};
$warn: ${theme.v1.palette.warn};
$critical: ${theme.v1.palette.critical};
// Scaffolding
// -------------------------
$body-bg: ${theme.colors.bodyBg};
$page-bg: ${theme.colors.bodyBg};
$dashboard-bg: ${theme.colors.dashboardBg};
$body-bg: ${theme.v1.colors.bodyBg};
$page-bg: ${theme.v1.colors.bodyBg};
$dashboard-bg: ${theme.v1.colors.dashboardBg};
$text-color: ${theme.colors.text};
$text-color-strong: ${theme.colors.textStrong};
$text-color-semi-weak: ${theme.colors.textSemiWeak};
$text-color-weak: ${theme.colors.textWeak};
$text-color-faint: ${theme.colors.textFaint};
$text-color-emphasis: ${theme.colors.textStrong};
$text-blue: ${theme.colors.textBlue};
$text-color: ${theme.v1.colors.text};
$text-color-strong: ${theme.v1.colors.textStrong};
$text-color-semi-weak: ${theme.v1.colors.textSemiWeak};
$text-color-weak: ${theme.v1.colors.textWeak};
$text-color-faint: ${theme.v1.colors.textFaint};
$text-color-emphasis: ${theme.v1.colors.textStrong};
$text-blue: ${theme.v1.colors.textBlue};
$text-shadow-faint: none;
@ -107,14 +107,14 @@ $brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
// Links
// -------------------------
$link-color: ${theme.colors.link};
$link-color-disabled: ${theme.colors.linkDisabled};
$link-hover-color: ${theme.colors.linkHover};
$external-link-color: ${theme.colors.linkExternal};
$link-color: ${theme.v1.colors.link};
$link-color-disabled: ${theme.v1.colors.linkDisabled};
$link-hover-color: ${theme.v1.colors.linkHover};
$external-link-color: ${theme.v1.colors.linkExternal};
// Typography
// -------------------------
$headings-color: ${theme.colors.textHeading};
$headings-color: ${theme.v1.colors.textHeading};
$abbr-border-color: $gray-2 !default;
$text-muted: $text-color-weak;
@ -122,30 +122,30 @@ $hr-border-color: $gray-4 !default;
// Panel
// -------------------------
$panel-bg: ${theme.v2.components.panel.background};
$panel-border: ${theme.v2.components.panel.border};
$panel-header-hover-bg: ${theme.v2.palette.action.hover};
$panel-box-shadow: ${theme.v2.components.panel.boxShadow};
$panel-bg: ${theme.components.panel.background};
$panel-border: ${theme.components.panel.border};
$panel-header-hover-bg: ${theme.palette.action.hover};
$panel-box-shadow: ${theme.components.panel.boxShadow};
$panel-corner: $panel-bg;
// Page header
$page-header-bg: ${theme.colors.pageHeaderBg};
$page-header-bg: ${theme.v1.colors.pageHeaderBg};
$page-header-shadow: inset 0px -3px 10px $gray-6;
$page-header-border-color: ${theme.colors.pageHeaderBorder};
$page-header-border-color: ${theme.v1.colors.pageHeaderBorder};
$divider-border-color: $gray-2;
// Graphite Target Editor
$tight-form-func-bg: ${theme.colors.bg2};
$tight-form-func-highlight-bg: ${styleMixins.hoverColor(theme.colors.bg2, theme)};
$tight-form-func-bg: ${theme.v1.colors.bg2};
$tight-form-func-highlight-bg: ${styleMixins.hoverColor(theme.v1.colors.bg2, theme.v1)};
$modal-backdrop-bg: ${theme.colors.bg1};
$modal-backdrop-bg: ${theme.v1.colors.bg1};
$code-tag-bg: $gray-6;
$code-tag-border: $gray-4;
// cards
$card-background: ${theme.v2.palette.background.secondary};
$card-background-hover: ${theme.v2.palette.background.secondary};
$card-background: ${theme.palette.background.secondary};
$card-background-hover: ${theme.palette.background.secondary};
$card-shadow: none;
// Lists
@ -162,10 +162,10 @@ $scrollbarBorder: $gray-7;
// Tables
// -------------------------
$table-bg-accent: ${theme.v2.palette.background.secondary};
$table-border: ${theme.v2.palette.border.medium};
$table-bg-odd: ${theme.v2.palette.emphasize(theme.v2.palette.background.primary, 0.02)};
$table-bg-hover: ${theme.v2.palette.emphasize(theme.v2.palette.background.primary, 0.05)};
$table-bg-accent: ${theme.palette.background.secondary};
$table-border: ${theme.palette.border.medium};
$table-bg-odd: ${theme.palette.emphasize(theme.palette.background.primary, 0.02)};
$table-bg-hover: ${theme.palette.emphasize(theme.palette.background.primary, 0.05)};
// Buttons
// -------------------------
@ -204,14 +204,14 @@ $btn-active-box-shadow: 0px 0px 4px rgba(234, 161, 51, 0.6);
$input-bg: $white;
$input-bg-disabled: $gray-5;
$input-color: ${theme.colors.formInputText};
$input-border-color: ${theme.colors.formInputBorder};
$input-color: ${theme.v1.colors.formInputText};
$input-border-color: ${theme.v1.colors.formInputBorder};
$input-box-shadow: none;
$input-border-focus: ${theme.palette.blue95};
$input-box-shadow-focus: ${theme.palette.blue95};
$input-color-placeholder: ${theme.colors.formInputPlaceholderText};
$input-label-bg: ${theme.colors.bg2};
$input-color-select-arrow: ${theme.palette.gray60};
$input-border-focus: ${theme.v1.palette.blue95};
$input-box-shadow-focus: ${theme.v1.palette.blue95};
$input-color-placeholder: ${theme.v1.colors.formInputPlaceholderText};
$input-label-bg: ${theme.v1.colors.bg2};
$input-color-select-arrow: ${theme.v1.palette.gray60};
// search
$search-shadow: 0 1px 5px 0 $gray-5;
@ -223,10 +223,10 @@ $typeahead-selected-color: $yellow;
// Dropdowns
// -------------------------
$dropdownBackground: ${theme.v2.palette.background.secondary};
$dropdownBorder: ${theme.v2.palette.border.weak};
$dropdownDividerTop: ${theme.v2.palette.border.weak};
$dropdownDividerBottom: ${theme.v2.palette.border.weak};
$dropdownBackground: ${theme.palette.background.secondary};
$dropdownBorder: ${theme.palette.border.weak};
$dropdownDividerTop: ${theme.palette.border.weak};
$dropdownDividerBottom: ${theme.palette.border.weak};
$dropdownLinkColor: $dark-2;
$dropdownLinkColorHover: $link-color;
@ -245,20 +245,20 @@ $navbarBorder: 1px solid $gray-5;
// Sidemenu
// -------------------------
$side-menu-bg: ${theme.palette.gray15};
$side-menu-border: 1px solid ${theme.palette.gray25};
$side-menu-bg: ${theme.v1.palette.gray15};
$side-menu-border: 1px solid ${theme.v1.palette.gray25};
$side-menu-bg-mobile: rgba(0, 0, 0, 0); //$gray-6;
$side-menu-item-hover-bg: ${theme.palette.gray25};
$side-menu-item-hover-bg: ${theme.v1.palette.gray25};
$side-menu-shadow: 5px 0px 10px -5px $gray-1;
$side-menu-link-color: $gray-4;
$side-menu-icon-color: ${theme.palette.gray70};
$side-menu-header-color: ${theme.palette.gray95};
$side-menu-icon-color: ${theme.v1.palette.gray70};
$side-menu-header-color: ${theme.v1.palette.gray95};
// Menu dropdowns
// -------------------------
$menu-dropdown-bg: ${theme.v2.palette.background.secondary};
$menu-dropdown-hover-bg: ${theme.v2.palette.action.hover};
$menu-dropdown-shadow: ${theme.v2.shadows.z3};
$menu-dropdown-bg: ${theme.palette.background.secondary};
$menu-dropdown-hover-bg: ${theme.palette.action.hover};
$menu-dropdown-shadow: ${theme.shadows.z3};
// Tabs
// -------------------------
@ -276,17 +276,17 @@ $alert-warning-bg: linear-gradient(90deg, $red-base, $red-shade);
$alert-info-bg: linear-gradient(100deg, $blue-base, $blue-shade);
// Tooltips and popovers
$tooltipBackground: ${theme.v2.palette.background.secondary};
$tooltipColor: ${theme.v2.palette.text.primary};
$tooltipArrowColor: ${theme.v2.palette.background.secondary};
$tooltipBackgroundError: ${theme.v2.palette.error.main};
$tooltipShadow: ${theme.v2.shadows.z2};
$tooltipBackground: ${theme.palette.background.secondary};
$tooltipColor: ${theme.palette.text.primary};
$tooltipArrowColor: ${theme.palette.background.secondary};
$tooltipBackgroundError: ${theme.palette.error.main};
$tooltipShadow: ${theme.shadows.z2};
$popover-bg: ${theme.v2.palette.background.secondary};
$popover-color: ${theme.v2.palette.text.primary};
$popover-border-color: ${theme.v2.palette.border.medium};
$popover-header-bg: ${theme.v2.palette.background.secondary};
$popover-shadow: ${theme.v2.shadows.z4};
$popover-bg: ${theme.palette.background.secondary};
$popover-color: ${theme.palette.text.primary};
$popover-border-color: ${theme.palette.border.medium};
$popover-header-bg: ${theme.palette.background.secondary};
$popover-shadow: ${theme.shadows.z4};
$graph-tooltip-bg: $gray-5;
@ -297,7 +297,7 @@ $popover-error-bg: $btn-danger-bg;
$popover-help-bg: $tooltipBackground;
$popover-help-color: $tooltipColor;
$popover-code-bg: ${theme.colors.bg1};
$popover-code-bg: ${theme.v1.colors.bg1};
$popover-code-boxshadow: 0 0 5px $gray60;
// images
@ -326,14 +326,14 @@ $json-explorer-url-color: $blue-base;
// Changelog and diff
// -------------------------
$diff-label-bg: ${theme.colors.bg3};
$diff-label-bg: ${theme.v1.colors.bg3};
$diff-label-fg: $gray-2;
$diff-arrow-color: $dark-2;
$diff-group-bg: ${theme.colors.bg2};
$diff-group-bg: ${theme.v1.colors.bg2};
$diff-json-bg: ${theme.colors.bg2};
$diff-json-fg: ${theme.colors.text};
$diff-json-bg: ${theme.v1.colors.bg2};
$diff-json-fg: ${theme.v1.colors.text};
$diff-json-added: $blue-shade;
$diff-json-deleted: $red-shade;
@ -354,7 +354,7 @@ $variable-option-bg: $dropdownLinkBackgroundHover;
$switch-bg: $white;
$switch-slider-color: $gray-7;
$switch-slider-off-bg: $gray-5;
$switch-slider-on-bg: ${theme.palette.blue77};
$switch-slider-on-bg: ${theme.v1.palette.blue77};
$switch-slider-shadow: 0 0 3px $dark-2;
//Checkbox
@ -377,8 +377,8 @@ $panel-editor-tabs-line-color: $dark-2;
$panel-editor-viz-item-bg-hover: lighten($blue-base, 45%);
$panel-grid-placeholder-bg: lighten(${theme.palette.blue95}, 30%);
$panel-grid-placeholder-shadow: 0 0 4px ${theme.palette.blue95};
$panel-grid-placeholder-bg: lighten(${theme.v1.palette.blue95}, 30%);
$panel-grid-placeholder-shadow: 0 0 4px ${theme.v1.palette.blue95};
// logs
$logs-color-unknown: $gray-5;

View File

@ -1,9 +1,9 @@
/* eslint-disable max-len */
import { GrafanaThemeCommons } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
import { renderGeneratedFileBanner } from '../utils/generatedFileBanner';
export const commonThemeVarsTemplate = (theme: GrafanaThemeCommons) =>
export const commonThemeVarsTemplate = (theme: GrafanaThemeV2) =>
`${renderGeneratedFileBanner('grafana-ui/src/themes/default.ts', 'grafana-ui/src/themes/_variables.scss.tmpl.ts')}
// Options
//
@ -17,16 +17,16 @@ $enable-hover-media-query: false !default;
// Control the default styling of most Bootstrap elements by modifying these
// variables. Mostly focused on spacing.
$space-inset-squish-md: ${theme.spacing.insetSquishMd} !default;
$space-inset-squish-md: ${theme.v1.spacing.insetSquishMd} !default;
$space-xxs: ${theme.spacing.xxs} !default;
$space-xs: ${theme.spacing.xs} !default;
$space-sm: ${theme.spacing.sm} !default;
$space-md: ${theme.spacing.md} !default;
$space-lg: ${theme.spacing.lg} !default;
$space-xl: ${theme.spacing.xl} !default;
$space-xxs: ${theme.v1.spacing.xxs} !default;
$space-xs: ${theme.v1.spacing.xs} !default;
$space-sm: ${theme.v1.spacing.sm} !default;
$space-md: ${theme.v1.spacing.md} !default;
$space-lg: ${theme.v1.spacing.lg} !default;
$space-xl: ${theme.v1.spacing.xl} !default;
$spacer: ${theme.spacing.d} !default;
$spacer: ${theme.v1.spacing.d} !default;
$spacer-x: $spacer !default;
$spacer-y: $spacer !default;
$spacers: (
@ -62,11 +62,11 @@ $spacers: (
// adapting to different screen sizes, for use in media queries.
$grid-breakpoints: (
xs: ${theme.breakpoints.xs},
sm: ${theme.breakpoints.sm},
md: ${theme.breakpoints.md},
lg: ${theme.breakpoints.lg},
xl: ${theme.breakpoints.xl},
xs: ${theme.v1.breakpoints.xs},
sm: ${theme.v1.breakpoints.sm},
md: ${theme.v1.breakpoints.md},
lg: ${theme.v1.breakpoints.lg},
xl: ${theme.v1.breakpoints.xl},
) !default;
// Grid containers
@ -85,50 +85,50 @@ $container-max-widths: (
// Set the number of columns and specify the width of the gutters.
$grid-columns: 12 !default;
$grid-gutter-width: ${theme.spacing.gutter} !default;
$grid-gutter-width: ${theme.v1.spacing.gutter} !default;
// Component heights
// -------------------------
$height-sm: ${theme.height.sm};
$height-md: ${theme.height.md};
$height-lg: ${theme.height.lg};
$height-sm: ${theme.v1.height.sm};
$height-md: ${theme.v1.height.md};
$height-lg: ${theme.v1.height.lg};
// Typography
// -------------------------
$font-family-sans-serif: ${theme.typography.fontFamily.sansSerif};
$font-family-monospace: ${theme.typography.fontFamily.monospace};
$font-family-sans-serif: ${theme.v1.typography.fontFamily.sansSerif};
$font-family-monospace: ${theme.v1.typography.fontFamily.monospace};
$font-size-base: ${theme.typography.size.base} !default;
$font-size-base: ${theme.v1.typography.size.base} !default;
$font-size-lg: ${theme.typography.size.lg} !default;
$font-size-md: ${theme.typography.size.md} !default;
$font-size-sm: ${theme.typography.size.sm} !default;
$font-size-xs: ${theme.typography.size.xs} !default;
$font-size-lg: ${theme.v1.typography.size.lg} !default;
$font-size-md: ${theme.v1.typography.size.md} !default;
$font-size-sm: ${theme.v1.typography.size.sm} !default;
$font-size-xs: ${theme.v1.typography.size.xs} !default;
$line-height-base: ${theme.typography.lineHeight.md} !default;
$line-height-base: ${theme.v1.typography.lineHeight.md} !default;
$font-weight-regular: ${theme.typography.weight.regular} !default;
$font-weight-semi-bold: ${theme.typography.weight.semibold} !default;
$font-weight-regular: ${theme.v1.typography.weight.regular} !default;
$font-weight-semi-bold: ${theme.v1.typography.weight.semibold} !default;
$font-size-h1: ${theme.typography.heading.h1} !default;
$font-size-h2: ${theme.typography.heading.h2} !default;
$font-size-h3: ${theme.typography.heading.h3} !default;
$font-size-h4: ${theme.typography.heading.h4} !default;
$font-size-h5: ${theme.typography.heading.h5} !default;
$font-size-h6: ${theme.typography.heading.h6} !default;
$font-size-h1: ${theme.v1.typography.heading.h1} !default;
$font-size-h2: ${theme.v1.typography.heading.h2} !default;
$font-size-h3: ${theme.v1.typography.heading.h3} !default;
$font-size-h4: ${theme.v1.typography.heading.h4} !default;
$font-size-h5: ${theme.v1.typography.heading.h5} !default;
$font-size-h6: ${theme.v1.typography.heading.h6} !default;
$headings-line-height: ${theme.typography.lineHeight.sm} !default;
$headings-line-height: ${theme.v1.typography.lineHeight.sm} !default;
// Components
//
// Define common padding and border radius sizes and more.
$border-width: ${theme.border.width.sm} !default;
$border-width: ${theme.v1.border.width.sm} !default;
$border-radius: ${theme.border.radius.md} !default;
$border-radius-lg: ${theme.border.radius.lg} !default;
$border-radius-sm: ${theme.border.radius.sm} !default;
$border-radius: ${theme.v1.border.radius.md} !default;
$border-radius-lg: ${theme.v1.border.radius.lg} !default;
$border-radius-sm: ${theme.v1.border.radius.sm} !default;
// Page
@ -137,13 +137,13 @@ $page-sidebar-margin: 56px;
// Links
// -------------------------
$link-decoration: ${theme.typography.link.decoration} !default;
$link-hover-decoration: ${theme.typography.link.hoverDecoration} !default;
$link-decoration: ${theme.v1.typography.link.decoration} !default;
$link-hover-decoration: ${theme.v1.typography.link.hoverDecoration} !default;
// Forms
$input-line-height: 18px !default;
$input-border-radius: $border-radius;
$input-padding: 0 ${theme.spacing.sm};
$input-padding: 0 ${theme.v1.spacing.sm};
$input-height: 32px !default;
$cursor-disabled: not-allowed !default;
@ -157,13 +157,13 @@ $form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www
// -------------------------
// Used for a bird's eye view of components dependent on the z-axis
// Try to avoid customizing these :)
$zindex-dropdown: ${theme.zIndex.dropdown};
$zindex-navbar-fixed: ${theme.zIndex.navbarFixed};
$zindex-sidemenu: ${theme.zIndex.sidemenu};
$zindex-tooltip: ${theme.zIndex.tooltip};
$zindex-modal-backdrop: ${theme.zIndex.modalBackdrop};
$zindex-modal: ${theme.zIndex.modal};
$zindex-typeahead: ${theme.zIndex.typeahead};
$zindex-dropdown: ${theme.v1.zIndex.dropdown};
$zindex-navbar-fixed: ${theme.v1.zIndex.navbarFixed};
$zindex-sidemenu: ${theme.v1.zIndex.sidemenu};
$zindex-tooltip: ${theme.v1.zIndex.tooltip};
$zindex-modal-backdrop: ${theme.v1.zIndex.modalBackdrop};
$zindex-modal: ${theme.v1.zIndex.modal};
$zindex-typeahead: ${theme.v1.zIndex.typeahead};
// Buttons
//
@ -171,7 +171,7 @@ $zindex-typeahead: ${theme.zIndex.typeahead};
$btn-padding-x: 14px !default;
$btn-padding-y: 0 !default;
$btn-line-height: $line-height-base;
$btn-font-weight: ${theme.typography.weight.semibold} !default;
$btn-font-weight: ${theme.v1.typography.weight.semibold} !default;
$btn-padding-x-sm: 7px !default;
$btn-padding-y-sm: 4px !default;
@ -190,8 +190,8 @@ $navbar-padding: 20px;
// dashboard
$dashboard-padding: $space-md;
$panel-padding: ${theme.panelPadding}px;
$panel-header-height: ${theme.panelHeaderHeight}px;
$panel-padding: ${theme.v1.panelPadding}px;
$panel-header-height: ${theme.v1.panelHeaderHeight}px;
$panel-header-z-index: 10;
// tabs

View File

@ -1,138 +0,0 @@
import defaultTheme, { commonColorsPalette } from './default';
import { GrafanaThemeType, GrafanaTheme, createTheme } from '@grafana/data';
const v2 = createTheme({ palette: { mode: 'dark' } });
const basicColors = {
...commonColorsPalette,
black: '#000000',
white: '#ffffff',
dark1: '#141414',
dark2: '#161719',
dark3: '#1f1f20',
dark4: '#212124',
dark5: '#222426',
dark6: '#262628',
dark7: '#292a2d',
dark8: '#2f2f32',
dark9: '#343436',
dark10: '#424345',
gray1: '#555555',
gray2: '#8e8e8e',
gray3: '#b3b3b3',
gray4: '#d8d9da',
gray5: '#ececec',
gray6: '#f4f5f8', // not used in dark theme
gray7: '#fbfbfb', // not used in dark theme
redBase: '#e02f44',
redShade: '#c4162a',
greenBase: '#299c46',
greenShade: '#23843b',
red: '#d44a3a',
yellow: '#ecbb13',
purple: '#9933cc',
variable: '#32d1df',
orange: '#eb7b18',
orangeDark: '#ff780a',
};
const backgrounds = {
bg1: v2.palette.background.primary,
bg2: v2.palette.background.secondary,
bg3: v2.palette.action.hover,
dashboardBg: v2.palette.background.canvas,
bgBlue1: v2.palette.primary.main,
bgBlue2: v2.palette.primary.shade,
};
const borders = {
border1: v2.palette.border.weak,
border2: v2.palette.border.medium,
border3: v2.palette.border.strong,
};
const textColors = {
textStrong: v2.palette.text.maxContrast,
textHeading: v2.palette.text.primary,
text: v2.palette.text.primary,
textSemiWeak: v2.palette.text.secondary,
textWeak: v2.palette.text.secondary,
textFaint: v2.palette.text.disabled,
textBlue: v2.palette.primary.text,
};
const form = {
// Next-gen forms functional colors
formLabel: v2.palette.text.primary,
formDescription: v2.palette.text.secondary,
formInputBg: basicColors.gray05,
formInputBgDisabled: basicColors.gray10,
formInputBorder: borders.border2,
formInputBorderHover: basicColors.gray33,
formInputBorderActive: basicColors.blue95,
formInputBorderInvalid: basicColors.red88,
formInputPlaceholderText: textColors.textFaint,
formInputText: basicColors.gray85,
formInputDisabledText: basicColors.gray70,
formFocusOutline: basicColors.blue77,
formValidationMessageText: basicColors.white,
formValidationMessageBg: basicColors.red88,
formSwitchBg: basicColors.gray25,
formSwitchBgActive: basicColors.blue95,
formSwitchBgHover: basicColors.gray33,
formSwitchBgActiveHover: basicColors.blue80,
formSwitchBgDisabled: basicColors.gray25,
formSwitchDot: basicColors.gray15,
formCheckboxBgChecked: basicColors.blue95,
formCheckboxBgCheckedHover: basicColors.blue80,
formCheckboxCheckmark: basicColors.gray25,
};
const darkTheme: GrafanaTheme = {
...defaultTheme,
type: GrafanaThemeType.Dark,
isDark: true,
isLight: false,
name: 'Grafana Dark',
palette: {
...basicColors,
brandPrimary: basicColors.orange,
brandSuccess: basicColors.greenBase,
brandWarning: basicColors.orange,
brandDanger: basicColors.redBase,
queryRed: basicColors.redBase,
queryGreen: '#74e680',
queryPurple: '#fe85fc',
queryOrange: basicColors.orange,
online: basicColors.greenBase,
warn: '#f79520',
critical: basicColors.redBase,
},
colors: {
...backgrounds,
...borders,
...form,
...textColors,
bodyBg: v2.palette.background.canvas,
panelBg: v2.components.panel.background,
panelBorder: v2.components.panel.border,
pageHeaderBg: v2.palette.background.canvas,
pageHeaderBorder: v2.palette.background.canvas,
dropdownBg: form.formInputBg,
dropdownShadow: basicColors.black,
dropdownOptionHoverBg: backgrounds.bg2,
link: basicColors.gray4,
linkDisabled: basicColors.gray2,
linkHover: basicColors.white,
linkExternal: basicColors.blue85,
},
shadows: {
listItem: 'none',
},
v2: v2,
};
export default darkTheme;

View File

@ -1,11 +1,14 @@
import darkTheme from './dark';
import lightTheme from './light';
import { GrafanaTheme } from '@grafana/data';
import { createTheme, GrafanaTheme } from '@grafana/data';
let themeMock: ((name?: string) => GrafanaTheme) | null;
export const getTheme = (name?: string) =>
(themeMock && themeMock(name)) || (name === 'light' ? lightTheme : darkTheme);
export const getTheme = (mode: 'dark' | 'light' = 'dark') => {
if (themeMock) {
return themeMock(mode);
}
return createTheme({ palette: { mode } }).v1;
};
export const mockTheme = (mock: (name?: string) => GrafanaTheme) => {
themeMock = mock;

View File

@ -1,8 +1,6 @@
import { ThemeContext, withTheme, useTheme, useStyles, mockThemeContext } from './ThemeContext';
import { getTheme, mockTheme } from './getTheme';
import { selectThemeVariant } from './selectThemeVariant';
export { ThemeContext, withTheme, useTheme, useTheme2, useStyles, useStyles2, mockThemeContext } from './ThemeContext';
export { getTheme, mockTheme } from './getTheme';
export { stylesFactory } from './stylesFactory';
export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext, useStyles };
export { GlobalStyles } from './GlobalStyles/GlobalStyles';
import * as styleMixins from './mixins';

View File

@ -1,139 +0,0 @@
import defaultTheme, { commonColorsPalette } from './default';
import { GrafanaThemeType, GrafanaTheme, createTheme } from '@grafana/data';
const v2 = createTheme({ palette: { mode: 'light' } });
const basicColors = {
...commonColorsPalette,
black: '#000000',
white: '#ffffff',
dark1: '#1e2028',
dark2: '#41444b',
dark3: '#303133', // not used in light theme
dark4: '#35373f', // not used in light theme
dark5: '#41444b', // not used in light theme
dark6: '#41444b', // not used in light theme
dark7: '#41444b', // not used in light theme
dark8: '#2f2f32', // not used in light theme
dark9: '#343436', // not used in light theme
dark10: '#424345', // not used in light theme
gray1: '#52545c',
gray2: '#767980',
gray3: '#acb6bf',
gray4: '#c7d0d9',
gray5: '#dde4ed',
gray6: '#e9edf2', // same as gray95
gray7: '#f7f8fa', // same as gray98
redBase: '#e02f44',
redShade: '#c4162a',
greenBase: '#3eb15b',
greenShade: '#369b4f',
red: '#d44939',
yellow: '#ff851b',
purple: '#9954bb',
orange: '#ff7941',
orangeDark: '#ed5700',
};
const backgrounds = {
bg1: v2.palette.background.primary,
bg2: v2.palette.background.secondary,
bg3: v2.palette.action.hover,
dashboardBg: v2.palette.background.canvas,
bgBlue1: basicColors.blue80,
bgBlue2: basicColors.blue77,
};
const borders = {
border1: v2.palette.border.weak,
border2: v2.palette.border.medium,
border3: v2.palette.border.strong,
};
const textColors = {
// Text colors
textStrong: v2.palette.text.maxContrast,
text: v2.palette.text.primary,
textSemiWeak: v2.palette.text.secondary,
textWeak: v2.palette.text.secondary,
textFaint: v2.palette.text.disabled,
textBlue: v2.palette.primary.text,
};
const form = {
formLabel: textColors.text,
formDescription: v2.palette.text.secondary,
formLegend: basicColors.gray25,
formInputBg: basicColors.white,
formInputBgDisabled: basicColors.gray95,
formInputBorder: basicColors.gray85,
formInputBorderHover: basicColors.gray70,
formInputBorderActive: basicColors.blue77,
formInputBorderInvalid: basicColors.red88,
formInputText: textColors.text,
formInputPlaceholderText: textColors.textFaint,
formInputDisabledText: textColors.textWeak,
formFocusOutline: basicColors.blue95,
formValidationMessageText: basicColors.white,
formValidationMessageBg: basicColors.red88,
formSwitchBg: basicColors.gray85,
formSwitchBgActive: basicColors.blue77,
formSwitchBgHover: basicColors.gray3,
formSwitchBgActiveHover: basicColors.blue80,
formSwitchBgDisabled: basicColors.gray4,
formSwitchDot: basicColors.white,
formCheckboxBgChecked: basicColors.blue77,
formCheckboxBgCheckedHover: basicColors.blue80,
formCheckboxCheckmark: basicColors.white,
};
const lightTheme: GrafanaTheme = {
...defaultTheme,
type: GrafanaThemeType.Light,
isDark: false,
isLight: true,
name: 'Grafana Light',
palette: {
...basicColors,
brandPrimary: basicColors.orange,
brandSuccess: basicColors.greenBase,
brandWarning: basicColors.orange,
brandDanger: basicColors.redBase,
queryRed: basicColors.redBase,
queryGreen: basicColors.greenBase,
queryPurple: basicColors.purple,
queryOrange: basicColors.orange,
online: basicColors.greenShade,
warn: '#f79520',
critical: basicColors.redShade,
},
colors: {
...backgrounds,
...borders,
...textColors,
...form,
bodyBg: v2.palette.background.canvas,
panelBg: backgrounds.bg1,
pageHeaderBg: backgrounds.bg2,
pageHeaderBorder: borders.border1,
panelBorder: borders.border1,
dropdownBg: form.formInputBg,
dropdownShadow: basicColors.gray3,
dropdownOptionHoverBg: backgrounds.bg2,
// Link colors
link: textColors.text,
linkDisabled: textColors.textWeak,
linkHover: textColors.textStrong,
linkExternal: basicColors.blue85,
textHeading: v2.palette.text.primary,
},
shadows: {
listItem: 'none',
},
v2: v2,
};
export default lightTheme;

View File

@ -1,7 +1,5 @@
import { map, sortBy, flattenDeep, chunk, zip } from 'lodash';
import tinycolor from 'tinycolor2';
import lightTheme from '../themes/light';
import darkTheme from '../themes/dark';
const PALETTE_ROWS = 4;
@ -116,7 +114,7 @@ function hslToHex(color: any) {
export function getTextColorForBackground(color: string) {
const b = tinycolor(color).getBrightness();
return b > 180 ? lightTheme.colors.textStrong : darkTheme.colors.textStrong;
return b > 180 ? 'rgb(247, 248, 250)' : 'rgb(32, 34, 38)';
}
export let sortedColors = sortColorsByHue(colors);

View File

@ -0,0 +1,24 @@
import React from 'react';
import { GlobalStyles, useTheme2 } from '../../themes';
import { RenderFunction } from '../../types';
const PaddedStory: React.FunctionComponent<{}> = ({ children }) => {
const theme = useTheme2();
return (
<div
style={{
width: '100%',
padding: '20px',
display: 'flex',
minHeight: '80vh',
background: `${theme.palette.background.primary}`,
}}
>
<GlobalStyles />
{children}
</div>
);
};
export const withPaddedStory = (story: RenderFunction) => <PaddedStory>{story()}</PaddedStory>;

View File

@ -1,21 +1,18 @@
import React from 'react';
import { ThemeContext } from '../../themes/ThemeContext';
import { getTheme, GlobalStyles } from '../../themes/index';
import { GrafanaThemeType } from '@grafana/data';
import { createTheme, GrafanaThemeV2 } from '@grafana/data';
import { RenderFunction } from '../../types';
import { useDarkMode } from 'storybook-dark-mode';
import { GlobalStyles } from '../../themes/GlobalStyles/GlobalStyles';
type SassThemeChangeHandler = (theme: GrafanaThemeType) => void;
type SassThemeChangeHandler = (theme: GrafanaThemeV2) => void;
const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassThemeChangeHandler }> = ({
children,
handleSassThemeChange,
}) => {
const themeType = useDarkMode() ? GrafanaThemeType.Dark : GrafanaThemeType.Light;
const theme = createTheme({ palette: { mode: useDarkMode() ? 'dark' : 'light' } });
handleSassThemeChange(themeType);
const theme = getTheme(themeType);
handleSassThemeChange(theme);
return (
<ThemeContext.Provider value={theme}>
@ -25,7 +22,7 @@ const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassTheme
padding: '20px',
display: 'flex',
minHeight: '80vh',
background: `${theme.v2.palette.background.primary}`,
background: `${theme.palette.background.primary}`,
}}
>
<GlobalStyles />

View File

@ -1,7 +1,7 @@
import React, { FC } from 'react';
import { css } from '@emotion/css';
import { Tab, TabsBar, Icon, IconName, useStyles } from '@grafana/ui';
import { NavModel, NavModelItem, NavModelBreadcrumb, GrafanaTheme } from '@grafana/data';
import { Tab, TabsBar, Icon, IconName, useStyles2 } from '@grafana/ui';
import { NavModel, NavModelItem, NavModelBreadcrumb, GrafanaThemeV2 } from '@grafana/data';
import { PanelHeaderMenuItem } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem';
export interface Props {
@ -72,7 +72,7 @@ const Navigation = ({ children }: { children: NavModelItem[] }) => {
};
export const PageHeader: FC<Props> = ({ model }) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
if (!model) {
return null;
@ -137,10 +137,10 @@ function renderTitle(title: string, breadcrumbs: NavModelBreadcrumb[]) {
return <h1 className="page-header__title">{breadcrumbsResult}</h1>;
}
const getStyles = (theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaThemeV2) => ({
headerCanvas: css`
background: ${theme.v2.palette.background.canvas};
border-bottom: 1px solid ${theme.v2.palette.border.weak};
background: ${theme.palette.background.canvas};
border-bottom: 1px solid ${theme.palette.border.weak};
`,
});

View File

@ -1,13 +1,18 @@
import { getTheme } from '@grafana/ui';
import { ThemeChangedEvent } from 'app/types/events';
import appEvents from '../app_events';
import { config } from '../config';
import { PreferencesService } from './PreferencesService';
import { contextSrv } from '../core';
import { createTheme } from '@grafana/data';
export async function toggleTheme(runtimeOnly: boolean) {
const currentTheme = config.theme;
const newTheme = getTheme(currentTheme.isDark ? 'light' : 'dark');
const newTheme = createTheme({
palette: {
mode: currentTheme.isDark ? 'light' : 'dark',
},
});
appEvents.publish(new ThemeChangedEvent(newTheme));
if (runtimeOnly) {
@ -17,7 +22,7 @@ export async function toggleTheme(runtimeOnly: boolean) {
// Add css file for new theme
const newCssLink = document.createElement('link');
newCssLink.rel = 'stylesheet';
newCssLink.href = config.bootData.themePaths[newTheme.type];
newCssLink.href = config.bootData.themePaths[newTheme.palette.mode];
document.body.appendChild(newCssLink);
// Remove old css file
@ -43,6 +48,6 @@ export async function toggleTheme(runtimeOnly: boolean) {
await service.update({
...currentPref,
theme: newTheme.type,
theme: newTheme.palette.mode,
});
}

View File

@ -3,7 +3,7 @@ import { config, GrafanaBootConfig } from '@grafana/runtime';
import { ThemeContext } from '@grafana/ui';
import { appEvents } from '../core';
import { ThemeChangedEvent } from 'app/types/events';
import { GrafanaTheme } from '@grafana/data';
import { createTheme } from '@grafana/data';
export const ConfigContext = React.createContext<GrafanaBootConfig>(config);
export const ConfigConsumer = ConfigContext.Consumer;
@ -16,11 +16,11 @@ export const provideConfig = (component: React.ComponentType<any>) => {
};
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
const [theme, setTheme] = useState<GrafanaTheme>(config.theme);
const [theme, setTheme] = useState(getCurrentUserTheme());
useEffect(() => {
const sub = appEvents.subscribe(ThemeChangedEvent, (event) => {
config.theme = event.payload;
//config.theme = event.payload;
setTheme(event.payload);
});
@ -30,6 +30,14 @@ export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
};
function getCurrentUserTheme() {
return createTheme({
palette: {
mode: config.bootData.user.lightTheme ? 'light' : 'dark',
},
});
}
export const provideTheme = (component: React.ComponentType<any>) => {
return provideConfig((props: any) => <ThemeProvider>{React.createElement(component, { ...props })}</ThemeProvider>);
};

View File

@ -1,7 +1,7 @@
import React, { FC, ReactNode, useCallback, useEffect, useState } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { Counter, Icon, useStyles } from '@grafana/ui';
import { GrafanaThemeV2 } from '@grafana/data';
import { Counter, Icon, useStyles2 } from '@grafana/ui';
import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
import { useLocalStorage } from 'react-use';
import { selectors } from '@grafana/e2e-selectors';
@ -24,7 +24,7 @@ export const OptionsPaneCategory: FC<OptionsPaneCategoryProps> = React.memo(
isExpanded: isOpenDefault !== false,
});
const [isExpanded, setIsExpanded] = useState(savedState.isExpanded);
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
useEffect(() => {
if (!isExpanded && forceOpen && forceOpen > 0) {
@ -86,10 +86,10 @@ export const OptionsPaneCategory: FC<OptionsPaneCategoryProps> = React.memo(
}
);
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
box: css`
border-bottom: 1px solid ${theme.v2.palette.border.weak};
border-bottom: 1px solid ${theme.palette.border.weak};
&:last-child {
border-bottom: none;
}
@ -98,11 +98,11 @@ const getStyles = (theme: GrafanaTheme) => {
border-bottom: 0;
`,
boxNestedExpanded: css`
margin-bottom: ${theme.spacing.formSpacingBase * 2}px;
margin-bottom: ${theme.spacing(2)};
`,
toggle: css`
color: ${theme.v2.palette.text.secondary};
margin-right: ${theme.spacing.sm};
color: ${theme.palette.text.secondary};
margin-right: ${theme.spacing(1)};
`,
title: css`
flex-grow: 1;
@ -112,22 +112,22 @@ const getStyles = (theme: GrafanaTheme) => {
display: flex;
cursor: pointer;
align-items: baseline;
padding: ${theme.v2.spacing(1)};
color: ${theme.v2.palette.text.primary};
font-weight: ${theme.v2.typography.fontWeightMedium};
padding: ${theme.spacing(1)};
color: ${theme.palette.text.primary};
font-weight: ${theme.typography.fontWeightMedium};
&:hover {
background: ${theme.v2.palette.emphasize(theme.v2.palette.background.primary, 0.03)};
background: ${theme.palette.emphasize(theme.palette.background.primary, 0.03)};
}
`,
headerExpanded: css`
color: ${theme.v2.palette.text.primary};
color: ${theme.palette.text.primary};
`,
headerNested: css`
padding: ${theme.v2.spacing(0.5, 0, 0.5, 0)};
padding: ${theme.spacing(0.5, 0, 0.5, 0)};
`,
body: css`
padding: ${theme.v2.spacing(1, 2, 1, 4)};
padding: ${theme.spacing(1, 2, 1, 4)};
`,
bodyNested: css`
position: relative;
@ -139,7 +139,7 @@ const getStyles = (theme: GrafanaTheme) => {
left: 8px;
width: 1px;
height: 100%;
background: ${theme.v2.palette.border.weak};
background: ${theme.palette.border.weak};
}
`,
};

View File

@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react';
import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
import { FieldConfigSource, GrafanaThemeV2, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
import { DashboardModel, PanelModel } from '../../state';
import { CustomScrollbar, RadioButtonGroup, useStyles } from '@grafana/ui';
import { CustomScrollbar, RadioButtonGroup, useStyles2 } from '@grafana/ui';
import { getPanelFrameCategory } from './getPanelFrameOptions';
import { getVizualizationOptions } from './getVizualizationOptions';
import { css } from '@emotion/css';
@ -26,7 +26,7 @@ export const OptionsPaneOptions: React.FC<Props> = (props) => {
const { plugin, dashboard, panel } = props;
const [searchQuery, setSearchQuery] = useState('');
const [listMode, setListMode] = useState(OptionFilter.All);
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const [panelFrameOptions, vizOptions, justOverrides] = useMemo(
() => [getPanelFrameCategory(props), getVizualizationOptions(props), getFieldOverrideCategories(props)],
@ -143,7 +143,7 @@ function renderSearchHits(
);
}
const getStyles = (theme: GrafanaTheme) => ({
const getStyles = (theme: GrafanaThemeV2) => ({
wrapper: css`
height: 100%;
display: flex;
@ -156,19 +156,19 @@ const getStyles = (theme: GrafanaTheme) => ({
min-height: 0;
`,
formRow: css`
margin-bottom: ${theme.spacing.sm};
margin-bottom: ${theme.spacing(1)};
`,
formBox: css`
padding: ${theme.spacing.sm};
background: ${theme.colors.bg1};
border: 1px solid ${theme.colors.border1};
padding: ${theme.spacing(1)};
background: ${theme.palette.background.primary};
border: 1px solid ${theme.components.panel.border};
border-bottom: none;
`,
closeButton: css`
margin-left: ${theme.spacing.sm};
margin-left: ${theme.spacing(1)};
`,
searchHits: css`
padding: ${theme.spacing.sm} ${theme.spacing.sm} 0 ${theme.spacing.sm};
padding: ${theme.spacing(1, 1, 0, 1)};
`,
scrollWrapper: css`
flex-grow: 1;
@ -176,13 +176,13 @@ const getStyles = (theme: GrafanaTheme) => ({
`,
searchNotice: css`
font-size: ${theme.typography.size.sm};
color: ${theme.colors.textWeak};
padding: ${theme.spacing.sm};
color: ${theme.palette.text.secondary};
padding: ${theme.spacing(1)};
text-align: center;
`,
mainBox: css`
background: ${theme.colors.bg1};
border: 1px solid ${theme.v2.components.panel.border};
background: ${theme.palette.background.primary};
border: 1px solid ${theme.components.panel.border};
border-top: none;
flex-grow: 1;
`,

View File

@ -1,6 +1,6 @@
import React, { FC, useEffect } from 'react';
import { css } from '@emotion/css';
import { IconName, Tab, TabContent, TabsBar, useForceUpdate, useStyles } from '@grafana/ui';
import { IconName, Tab, TabContent, TabsBar, useForceUpdate, useStyles2 } from '@grafana/ui';
import { AlertTab } from 'app/features/alerting/AlertTab';
import { TransformationsEditor } from '../TransformationsEditor/TransformationsEditor';
import { DashboardModel, PanelModel } from '../../state';
@ -8,7 +8,7 @@ import { PanelEditorTab, PanelEditorTabId } from './types';
import { Subscription } from 'rxjs';
import { PanelQueriesChangedEvent, PanelTransformationsChangedEvent } from 'app/types/events';
import { PanelEditorQueries } from './PanelEditorQueries';
import { GrafanaTheme } from '@grafana/data';
import { GrafanaThemeV2 } from '@grafana/data';
interface PanelEditorTabsProps {
panel: PanelModel;
@ -19,7 +19,7 @@ interface PanelEditorTabsProps {
export const PanelEditorTabs: FC<PanelEditorTabsProps> = React.memo(({ panel, dashboard, tabs, onChangeTab }) => {
const forceUpdate = useForceUpdate();
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
useEffect(() => {
const eventSubs = new Subscription();
@ -75,7 +75,7 @@ function getCounter(panel: PanelModel, tab: PanelEditorTab) {
return null;
}
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
wrapper: css`
display: flex;
@ -83,7 +83,7 @@ const getStyles = (theme: GrafanaTheme) => {
height: 100%;
`,
tabBar: css`
padding-left: ${theme.spacing.md};
padding-left: ${theme.spacing(2)};
`,
tabContent: css`
padding: 0;
@ -91,8 +91,8 @@ const getStyles = (theme: GrafanaTheme) => {
flex-direction: column;
flex-grow: 1;
min-height: 0;
background: ${theme.v2.palette.background.primary};
border-right: 1px solid ${theme.v2.components.panel.border};
background: ${theme.palette.background.primary};
border-right: 1px solid ${theme.components.panel.border};
`,
};
};

View File

@ -4,20 +4,19 @@ import {
Button,
Container,
CustomScrollbar,
stylesFactory,
Themeable,
FeatureInfoBox,
useTheme,
VerticalGroup,
withTheme,
Input,
IconButton,
useStyles2,
} from '@grafana/ui';
import {
DataFrame,
DataTransformerConfig,
DocsId,
GrafanaTheme,
GrafanaThemeV2,
PanelData,
SelectableValue,
standardTransformersRegistry,
@ -362,18 +361,17 @@ class UnThemedTransformationsEditor extends React.PureComponent<TransformationsE
}
const TransformationCard: React.FC<CardProps> = (props) => {
const theme = useTheme();
const styles = getTransformationCardStyles(theme);
const styles = useStyles2(getStyles);
return <Card {...props} className={styles.card} />;
};
const getTransformationCardStyles = stylesFactory((theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
card: css`
background: ${theme.colors.bg2};
background: ${theme.palette.background.secondary};
width: 100%;
border: none;
padding: ${theme.spacing.sm};
padding: ${theme.spacing(1)};
// hack because these cards use classes from a very different card for some reason
.add-data-source-item-text {
@ -381,12 +379,12 @@ const getTransformationCardStyles = stylesFactory((theme: GrafanaTheme) => {
}
&:hover {
background: ${theme.v2.palette.action.hover};
background: ${theme.palette.action.hover};
box-shadow: none;
border: none;
}
`,
};
});
};
export const TransformationsEditor = withTheme(UnThemedTransformationsEditor);

View File

@ -1,7 +1,7 @@
import React from 'react';
import { isArray, isObject, isUndefined } from 'lodash';
import { useStyles, Icon } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
import { useStyles2, Icon } from '@grafana/ui';
import { GrafanaThemeV2 } from '@grafana/data';
import { css } from '@emotion/css';
import { Diff } from './utils';
@ -10,7 +10,7 @@ type DiffProps = {
};
export const DiffValues: React.FC<DiffProps> = ({ diff }) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const hasLeftValue =
!isUndefined(diff.originalValue) && !isArray(diff.originalValue) && !isObject(diff.originalValue);
const hasRightValue = !isUndefined(diff.value) && !isArray(diff.value) && !isObject(diff.value);
@ -24,11 +24,11 @@ export const DiffValues: React.FC<DiffProps> = ({ diff }) => {
);
};
const getStyles = (theme: GrafanaTheme) => css`
background-color: ${theme.v2.palette.action.hover};
border-radius: ${theme.border.radius.md};
color: ${theme.colors.textHeading};
font-size: ${theme.typography.size.base};
margin: 0 ${theme.spacing.xs};
padding: ${theme.spacing.xs} ${theme.spacing.sm};
const getStyles = (theme: GrafanaThemeV2) => css`
background-color: ${theme.palette.action.hover};
border-radius: ${theme.shape.borderRadius()};
color: ${theme.palette.text.primary};
font-size: ${theme.typography.body.fontSize};
margin: 0 ${theme.spacing(0.5)};
padding: ${theme.spacing(0.5, 1)};
`;

View File

@ -1,6 +1,6 @@
import React from 'react';
import { GrafanaTheme, isUnsignedPluginSignature, PanelPluginMeta, PluginState } from '@grafana/data';
import { Badge, BadgeProps, IconButton, PluginSignatureBadge, styleMixins, useStyles } from '@grafana/ui';
import { GrafanaThemeV2, isUnsignedPluginSignature, PanelPluginMeta, PluginState } from '@grafana/data';
import { Badge, BadgeProps, IconButton, PluginSignatureBadge, useStyles2 } from '@grafana/ui';
import { css, cx } from '@emotion/css';
import { selectors } from '@grafana/e2e-selectors';
@ -23,7 +23,7 @@ export const PanelTypeCard: React.FC<Props> = ({
disabled,
showBadge,
}) => {
const styles = useStyles(getStyles);
const styles = useStyles2(getStyles);
const cssClass = cx({
[styles.item]: true,
[styles.disabled]: disabled || plugin.state === PluginState.deprecated,
@ -62,28 +62,28 @@ export const PanelTypeCard: React.FC<Props> = ({
PanelTypeCard.displayName = 'PanelTypeCard';
const getStyles = (theme: GrafanaTheme) => {
const getStyles = (theme: GrafanaThemeV2) => {
return {
item: css`
position: relative;
display: flex;
flex-shrink: 0;
cursor: pointer;
background: ${theme.v2.palette.background.secondary};
border-radius: ${theme.v2.shape.borderRadius()};
box-shadow: ${theme.v2.shadows.z0};
background: ${theme.palette.background.secondary};
border-radius: ${theme.shape.borderRadius()};
box-shadow: ${theme.shadows.z0};
align-items: center;
padding: 8px;
width: 100%;
position: relative;
overflow: hidden;
height: 55px;
transition: ${theme.v2.transitions.create(['background'], {
duration: theme.v2.transitions.duration.short,
transition: ${theme.transitions.create(['background'], {
duration: theme.transitions.duration.short,
})};
&:hover {
background: ${styleMixins.hoverColor(theme.v2.palette.background.secondary, theme)};
background: ${theme.palette.emphasize(theme.palette.background.secondary, 0.03)};
}
`,
itemContent: css`
@ -92,24 +92,20 @@ const getStyles = (theme: GrafanaTheme) => {
`,
current: css`
label: currentVisualizationItem;
border-color: ${theme.colors.bgBlue1};
border-color: ${theme.palette.primary.border};
`,
disabled: css`
opacity: 0.2;
filter: grayscale(1);
cursor: default;
pointer-events: none;
&:hover {
border: 1px solid ${theme.colors.border2};
}
`,
name: css`
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: ${theme.typography.size.sm};
font-weight: ${theme.typography.weight.semibold};
font-weight: ${theme.typography.fontWeightMedium};
padding: 0 10px;
width: 100%;
`,
@ -120,7 +116,7 @@ const getStyles = (theme: GrafanaTheme) => {
align-items: center;
`,
badge: css`
background: ${theme.colors.bg1};
background: ${theme.palette.background.primary};
`,
};
};

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { LegacyForms, ThemeContext } from '@grafana/ui';
import React from 'react';
import { LegacyForms, useStyles } from '@grafana/ui';
const { Select } = LegacyForms;
import { css, cx } from '@emotion/css';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
@ -32,8 +32,7 @@ export interface Props {
}
export const AdHocFilter: React.FunctionComponent<Props> = (props) => {
const theme = useContext(ThemeContext);
const styles = getStyles(theme);
const styles = useStyles(getStyles);
const onChange = (changeType: ChangeType) => (item: SelectableValue<string>) => {
const { onKeyChanged, onValueChanged, onOperatorChanged } = props;

Some files were not shown because too many files have changed in this diff Show More