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; borderHover: string;
text: string; text: string;
}; };
tooltip: {
text: string;
background: string;
};
panel: { panel: {
padding: number; padding: number;
headerHeight: number; headerHeight: number;
@ -58,6 +62,10 @@ export function createComponents(palette: ThemePalette, shadows: ThemeShadows):
text: palette.text.primary, text: palette.text.primary,
}, },
panel, panel,
tooltip: {
background: palette.background.secondary,
text: palette.text.primary,
},
dashboard: { dashboard: {
background: palette.background.canvas, background: palette.background.canvas,
padding: 1, padding: 1,

View File

@ -1,28 +1,14 @@
import { createBreakpoints, ThemeBreakpoints } from './breakpoints'; import { createBreakpoints } from './breakpoints';
import { ThemeComponents, createComponents } from './createComponents'; import { createComponents } from './createComponents';
import { createPalette, ThemePalette, ThemePaletteInput } from './createPalette'; import { createPalette, ThemePaletteInput } from './createPalette';
import { createShadows, ThemeShadows } from './createShadows'; import { createShadows } from './createShadows';
import { createShape, ThemeShape, ThemeShapeInput } from './createShape'; import { createShape, ThemeShapeInput } from './createShape';
import { createSpacing, ThemeSpacingOptions, ThemeSpacing } from './createSpacing'; import { createSpacing, ThemeSpacingOptions } from './createSpacing';
import { createTransitions, ThemeTransitions } from './createTransitions'; import { createTransitions } from './createTransitions';
import { createTypography, ThemeTypography, ThemeTypographyInput } from './createTypography'; import { createTypography, ThemeTypographyInput } from './createTypography';
import { ThemeZIndices, zIndex } from './zIndex'; import { createV1Theme } from './createV1Theme';
import { GrafanaThemeV2 } from './types';
/** @beta */ import { zIndex } from './zIndex';
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;
}
/** @internal */ /** @internal */
export interface NewThemeOptions { export interface NewThemeOptions {
@ -52,7 +38,7 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaThemeV2 {
const transitions = createTransitions(); const transitions = createTransitions();
const components = createComponents(palette, shadows); const components = createComponents(palette, shadows);
return { const theme = {
name, name,
isDark: palette.mode === 'dark', isDark: palette.mode === 'dark',
isLight: palette.mode === 'light', isLight: palette.mode === 'light',
@ -68,4 +54,9 @@ export function createTheme(options: NewThemeOptions = {}): GrafanaThemeV2 {
...zIndex, ...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 { createTheme } from './createTheme';
export { ThemePaletteColor } from './types'; export { ThemePaletteColor, GrafanaThemeV2 } from './types';
export { ThemePalette } from './createPalette'; export { ThemePalette } from './createPalette';
export { ThemeBreakpoints } from './breakpoints'; export { ThemeBreakpoints } from './breakpoints';
export { ThemeShadows } from './createShadows'; 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 */ /** @alpha */
export interface ThemePaletteColor { export interface ThemePaletteColor {
/** color intent (primary, secondary, info, error, etc) */ /** color intent (primary, secondary, info, error, etc) */

View File

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

View File

@ -6,7 +6,6 @@ import {
FeatureToggles, FeatureToggles,
GrafanaConfig, GrafanaConfig,
GrafanaTheme, GrafanaTheme,
GrafanaThemeType,
LicenseInfo, LicenseInfo,
PanelPluginMeta, PanelPluginMeta,
systemDateFormats, systemDateFormats,
@ -76,7 +75,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
awsAssumeRoleEnabled = false; awsAssumeRoleEnabled = false;
constructor(options: GrafanaBootConfig) { 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 = { const defaults = {
datasources: {}, datasources: {},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,8 +3,8 @@ import { css } from '@emotion/css';
import { Modal } from '../Modal/Modal'; import { Modal } from '../Modal/Modal';
import { IconName } from '../../types/icon'; import { IconName } from '../../types/icon';
import { Button } from '../Button'; import { Button } from '../Button';
import { useStyles } from '../../themes'; import { useStyles2 } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { HorizontalGroup, Input } from '..'; import { HorizontalGroup, Input } from '..';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
@ -50,7 +50,7 @@ export const ConfirmModal = ({
onAlternative, onAlternative,
}: ConfirmModalProps): JSX.Element => { }: ConfirmModalProps): JSX.Element => {
const [disabled, setDisabled] = useState(Boolean(confirmationText)); const [disabled, setDisabled] = useState(Boolean(confirmationText));
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
const onConfirmationTextChange = (event: React.FormEvent<HTMLInputElement>) => { const onConfirmationTextChange = (event: React.FormEvent<HTMLInputElement>) => {
setDisabled(confirmationText?.localeCompare(event.currentTarget.value) !== 0); setDisabled(confirmationText?.localeCompare(event.currentTarget.value) !== 0);
}; };
@ -92,7 +92,7 @@ export const ConfirmModal = ({
); );
}; };
const getStyles = (theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaThemeV2) => ({
modal: css` modal: css`
width: 500px; width: 500px;
`, `,
@ -100,16 +100,16 @@ const getStyles = (theme: GrafanaTheme) => ({
text-align: center; text-align: center;
`, `,
modalText: css({ modalText: css({
fontSize: theme.v2.typography.h4.fontSize, fontSize: theme.typography.h4.fontSize,
color: theme.v2.palette.text.primary, color: theme.palette.text.primary,
marginBottom: `calc(${theme.v2.spacing(2)}*2)`, marginBottom: `calc(${theme.spacing(2)}*2)`,
paddingTop: theme.v2.spacing(2), paddingTop: theme.spacing(2),
}), }),
modalDescription: css({ modalDescription: css({
fontSize: theme.v2.typography.h6.fontSize, fontSize: theme.typography.h6.fontSize,
paddingTop: theme.v2.spacing(2), paddingTop: theme.spacing(2),
}), }),
modalConfirmationInput: css({ 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 classNames from 'classnames';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import Scrollbars from 'react-custom-scrollbars'; import Scrollbars from 'react-custom-scrollbars';
import { useStyles } from '../../themes'; import { useStyles2 } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
interface Props { interface Props {
className?: string; className?: string;
@ -38,7 +38,7 @@ export const CustomScrollbar: FC<Props> = ({
children, children,
}) => { }) => {
const ref = useRef<Scrollbars>(null); const ref = useRef<Scrollbars>(null);
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
const updateScroll = () => { const updateScroll = () => {
if (ref.current && !isNil(scrollTop)) { if (ref.current && !isNil(scrollTop)) {
@ -127,7 +127,7 @@ export const CustomScrollbar: FC<Props> = ({
export default CustomScrollbar; export default CustomScrollbar;
const getStyles = (theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
return { return {
customScrollbar: css` customScrollbar: css`
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to // 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; flex-direction: column;
} }
.track-vertical { .track-vertical {
border-radius: ${theme.border.radius.md}; border-radius: ${theme.shape.borderRadius(2)};
width: ${theme.spacing.sm} !important; width: ${theme.spacing(1)} !important;
right: 0px; right: 0px;
bottom: ${theme.spacing.xxs}; bottom: ${theme.spacing(0.25)};
top: ${theme.spacing.xxs}; top: ${theme.spacing(0.25)};
} }
.track-horizontal { .track-horizontal {
border-radius: ${theme.border.radius.md}; border-radius: ${theme.shape.borderRadius(2)};
height: ${theme.spacing.sm} !important; height: ${theme.spacing(1)} !important;
right: ${theme.spacing.xxs}; right: ${theme.spacing(0.25)};
bottom: ${theme.spacing.xxs}; bottom: ${theme.spacing(0.25)};
left: ${theme.spacing.xxs}; left: ${theme.spacing(0.25)};
} }
.thumb-vertical { .thumb-vertical {
background: ${theme.v2.palette.action.focus}; background: ${theme.palette.action.focus};
border-radius: ${theme.border.radius.md}; border-radius: ${theme.shape.borderRadius(2)};
opacity: 0; opacity: 0;
} }
.thumb-horizontal { .thumb-horizontal {
background: ${theme.v2.palette.action.focus}; background: ${theme.palette.action.focus};
border-radius: ${theme.border.radius.md}; border-radius: ${theme.shape.borderRadius(2)};
opacity: 0; opacity: 0;
} }
&:hover { &:hover {

View File

@ -2,7 +2,7 @@
exports[`CustomScrollbar renders correctly 1`] = ` exports[`CustomScrollbar renders correctly 1`] = `
<div <div
className="css-d4ozb2" className="css-ccjpr2"
style={ style={
Object { Object {
"height": "auto", "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 { VariableSuggestion, GrafanaTheme, DataLink } from '@grafana/data';
import { Switch } from '../Switch/Switch'; import { Switch } from '../Switch/Switch';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { ThemeContext, stylesFactory } from '../../themes/index'; import { useStyles } from '../../themes/index';
import { DataLinkInput } from './DataLinkInput'; import { DataLinkInput } from './DataLinkInput';
import { Field } from '../Forms/Field'; import { Field } from '../Forms/Field';
import { Input } from '../Input/Input'; import { Input } from '../Input/Input';
@ -15,7 +15,7 @@ interface DataLinkEditorProps {
onChange: (index: number, link: DataLink, callback?: () => void) => void; onChange: (index: number, link: DataLink, callback?: () => void) => void;
} }
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaTheme) => ({
listItem: css` listItem: css`
margin-bottom: ${theme.spacing.sm}; margin-bottom: ${theme.spacing.sm};
`, `,
@ -24,12 +24,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
margin-left: 66px; margin-left: 66px;
color: ${theme.colors.textWeak}; color: ${theme.colors.textWeak};
`, `,
})); });
export const DataLinkEditor: React.FC<DataLinkEditorProps> = React.memo( export const DataLinkEditor: React.FC<DataLinkEditorProps> = React.memo(
({ index, value, onChange, suggestions, isLast }) => { ({ index, value, onChange, suggestions, isLast }) => {
const theme = useContext(ThemeContext); const styles = useStyles(getStyles);
const styles = getStyles(theme);
const onUrlChange = (url: string, callback?: () => void) => { const onUrlChange = (url: string, callback?: () => void) => {
onChange(index, { ...value, url }, callback); 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 usePrevious from 'react-use/lib/usePrevious';
import { DataLinkSuggestions } from './DataLinkSuggestions'; import { DataLinkSuggestions } from './DataLinkSuggestions';
import { makeValue, ThemeContext } from '../../index'; import { makeValue } from '../../index';
import { SelectionReference } from './SelectionReference'; import { SelectionReference } from './SelectionReference';
import { Portal } from '../index'; import { Portal } from '../index';
@ -15,8 +15,8 @@ import { css, cx } from '@emotion/css';
import { SlatePrism } from '../../slate-plugins'; import { SlatePrism } from '../../slate-plugins';
import { SCHEMA } from '../../utils/slate'; import { SCHEMA } from '../../utils/slate';
import { stylesFactory } from '../../themes'; import { useStyles2 } from '../../themes';
import { DataLinkBuiltInVars, GrafanaTheme, VariableOrigin, VariableSuggestion } from '@grafana/data'; import { DataLinkBuiltInVars, GrafanaThemeV2, VariableOrigin, VariableSuggestion } from '@grafana/data';
import { getInputStyles } from '../Input/Input'; import { getInputStyles } from '../Input/Input';
const modulo = (a: number, n: number) => a - n * Math.floor(a / n); 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, input: getInputStyles({ theme, invalid: false }).input,
editor: css` editor: css`
.token.builtInVariable { .token.builtInVariable {
color: ${theme.palette.queryGreen}; color: ${theme.palette.success.text};
} }
.token.variable { .token.variable {
color: ${theme.colors.textBlue}; color: ${theme.palette.primary.text};
} }
`, `,
// Wrapper with child selector needed. // Wrapper with child selector needed.
@ -64,15 +64,14 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
border: none; border: none;
} }
`, `,
})); });
// This memoised also because rerendering the slate editor grabs focus which created problem in some cases this // 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. // was used and changes to different state were propagated here.
export const DataLinkInput: React.FC<DataLinkInputProps> = memo( export const DataLinkInput: React.FC<DataLinkInputProps> = memo(
({ value, onChange, suggestions, placeholder = 'http://your-grafana.com/d/000000010/annotations' }) => { ({ value, onChange, suggestions, placeholder = 'http://your-grafana.com/d/000000010/annotations' }) => {
const editorRef = useRef<Editor>() as RefObject<Editor>; const editorRef = useRef<Editor>() as RefObject<Editor>;
const theme = useContext(ThemeContext); const styles = useStyles2(getStyles);
const styles = getStyles(theme);
const [showingSuggestions, setShowingSuggestions] = useState(false); const [showingSuggestions, setShowingSuggestions] = useState(false);
const [suggestionsIndex, setSuggestionsIndex] = useState(0); const [suggestionsIndex, setSuggestionsIndex] = useState(0);
const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value)); const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value));

View File

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

View File

@ -1,8 +1,8 @@
import React, { FC, FormEvent, useCallback, useState } from 'react'; 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 { css, cx } from '@emotion/css';
import { Icon } from '../index'; import { Icon } from '../index';
import { stylesFactory, useTheme } from '../../themes'; import { stylesFactory, useTheme2 } from '../../themes';
import { ComponentSize } from '../../types/size'; import { ComponentSize } from '../../types/size';
import { getButtonStyles } from '../Button'; import { getButtonStyles } from '../Button';
@ -37,7 +37,7 @@ export const FileUpload: FC<Props> = ({
accept = '*', accept = '*',
size = 'md', size = 'md',
}) => { }) => {
const theme = useTheme(); const theme = useTheme2();
const style = getStyles(theme, size); const style = getStyles(theme, size);
const [fileName, setFileName] = useState(''); 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 }); const buttonStyles = getButtonStyles({ theme, variant: 'primary', size, iconOnly: false });
return { return {
fileUpload: css` fileUpload: css`
@ -84,7 +84,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme, size: ComponentSize) => {
button: buttonStyles.button, button: buttonStyles.button,
icon: buttonStyles.icon, icon: buttonStyles.icon,
fileName: css` 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 React from 'react';
import { stylesFactory, ThemeContext } from '../../themes'; import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { IconButton } from '../IconButton/IconButton'; import { IconButton } from '../IconButton/IconButton';
@ -13,7 +13,7 @@ export interface FilterPillProps {
} }
export const FilterPill: React.FC<FilterPillProps> = ({ label, selected, onClick, icon = 'check' }) => { export const FilterPill: React.FC<FilterPillProps> = ({ label, selected, onClick, icon = 'check' }) => {
const theme = useContext(ThemeContext); const theme = useTheme();
const styles = getFilterPillStyles(theme, selected); const styles = getFilterPillStyles(theme, selected);
return ( return (
<div className={styles.wrapper} onClick={onClick}> <div className={styles.wrapper} onClick={onClick}>

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import { stylesFactory } from '../../themes'; import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { getLabelStyles } from './Label'; import { getLabelStyles } from './Label';
import { getLegendStyles } from './Legend'; import { getLegendStyles } from './Legend';
import { getFieldValidationMessageStyles } from './FieldValidationMessage'; import { getFieldValidationMessageStyles } from './FieldValidationMessage';
@ -10,20 +10,20 @@ import { getCheckboxStyles } from './Checkbox';
/** @deprecated */ /** @deprecated */
export const getFormStyles = stylesFactory( 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'); console.warn('getFormStyles is deprecated');
return { return {
label: getLabelStyles(theme), label: getLabelStyles(theme.v1),
legend: getLegendStyles(theme), legend: getLegendStyles(theme.v1),
fieldValidationMessage: getFieldValidationMessageStyles(theme), fieldValidationMessage: getFieldValidationMessageStyles(theme.v1),
button: getButtonStyles({ button: getButtonStyles({
theme, theme,
variant: options.variant, variant: options.variant,
size: options.size, size: options.size,
}), }),
input: getInputStyles({ theme, invalid: options.invalid }), 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 { css } from '@emotion/css';
import { IconButton } from '@grafana/ui'; import { IconButton } from '@grafana/ui';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { useTheme } from '../../themes'; import { useTheme2 } from '../../themes';
import { IconSize, IconName } from '../../types'; import { IconSize, IconName } from '../../types';
import mdx from './IconButton.mdx'; import mdx from './IconButton.mdx';
@ -32,7 +32,7 @@ interface ScenarioProps {
} }
const RenderScenario = ({ background }: ScenarioProps) => { const RenderScenario = ({ background }: ScenarioProps) => {
const theme = useTheme(); const theme = useTheme2();
const sizes: IconSize[] = ['sm', 'md', 'lg', 'xl', 'xxl']; const sizes: IconSize[] = ['sm', 'md', 'lg', 'xl', 'xxl'];
const icons: IconName[] = ['search', 'trash-alt', 'arrow-left', 'times']; const icons: IconName[] = ['search', 'trash-alt', 'arrow-left', 'times'];
@ -40,7 +40,7 @@ const RenderScenario = ({ background }: ScenarioProps) => {
<div <div
className={css` className={css`
padding: 30px; padding: 30px;
background: ${theme.v2.palette.background[background]}; background: ${theme.palette.background[background]};
button { button {
margin-right: 8px; margin-right: 8px;
margin-left: 8px; margin-left: 8px;

View File

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

View File

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

View File

@ -1,8 +1,8 @@
import React, { HTMLProps, ReactNode } from 'react'; import React, { HTMLProps, ReactNode } from 'react';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles'; import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
import { stylesFactory, useTheme } from '../../themes'; import { stylesFactory, useTheme2 } from '../../themes';
import { Spinner } from '../Spinner/Spinner'; import { Spinner } from '../Spinner/Spinner';
import { useClientRect } from '../../utils/useClientRect'; import { useClientRect } from '../../utils/useClientRect';
@ -24,7 +24,7 @@ export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'siz
} }
interface StyleDeps { interface StyleDeps {
theme: GrafanaTheme; theme: GrafanaThemeV2;
invalid: boolean; invalid: boolean;
width?: number; width?: number;
} }
@ -44,7 +44,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
height: 100%; height: 100%;
/* Min width specified for prefix/suffix classes used outside React component*/ /* Min width specified for prefix/suffix classes used outside React component*/
min-width: ${prefixSuffixStaticWidth}; min-width: ${prefixSuffixStaticWidth};
color: ${theme.v2.palette.text.secondary}; color: ${theme.palette.text.secondary};
`; `;
return { return {
@ -53,14 +53,14 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
css` css`
label: input-wrapper; label: input-wrapper;
display: flex; display: flex;
width: ${width ? `${theme.v2.spacing(width)}` : '100%'}; width: ${width ? `${theme.spacing(width)}` : '100%'};
height: ${theme.v2.spacing(theme.v2.components.height.md)}; height: ${theme.spacing(theme.components.height.md)};
border-radius: ${theme.v2.shape.borderRadius()}; border-radius: ${theme.shape.borderRadius()};
&:hover { &:hover {
> .prefix, > .prefix,
.suffix, .suffix,
.input { .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 // only show number buttons on hover
@ -130,21 +130,21 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
`, `,
input: cx( input: cx(
getFocusStyle(theme), getFocusStyle(theme.v1),
sharedInputStyle(theme, invalid), sharedInputStyle(theme, invalid),
css` css`
label: input-input; label: input-input;
position: relative; position: relative;
z-index: 0; z-index: 0;
flex-grow: 1; flex-grow: 1;
border-radius: ${theme.v2.shape.borderRadius()}; border-radius: ${theme.shape.borderRadius()};
height: 100%; height: 100%;
width: 100%; width: 100%;
` `
), ),
inputDisabled: css` inputDisabled: css`
background-color: ${theme.v2.palette.action.disabledBackground}; background-color: ${theme.palette.action.disabledBackground};
color: ${theme.v2.palette.action.disabledText}; color: ${theme.palette.action.disabledText};
`, `,
addon: css` addon: css`
label: input-addon; label: input-addon;
@ -181,8 +181,8 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
prefixSuffix, prefixSuffix,
css` css`
label: input-prefix; label: input-prefix;
padding-left: ${theme.v2.spacing(1)}; padding-left: ${theme.spacing(1)};
padding-right: ${theme.v2.spacing(0.5)}; padding-right: ${theme.spacing(0.5)};
border-right: none; border-right: none;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
@ -192,8 +192,8 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
prefixSuffix, prefixSuffix,
css` css`
label: input-suffix; label: input-suffix;
padding-left: ${theme.v2.spacing(1)}; padding-left: ${theme.spacing(1)};
padding-right: ${theme.v2.spacing(0.5)}; padding-right: ${theme.spacing(0.5)};
margin-bottom: -2px; margin-bottom: -2px;
border-left: none; border-left: none;
border-top-left-radius: 0; border-top-left-radius: 0;
@ -203,7 +203,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
), ),
loadingIndicator: css` 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 [prefixRect, prefixRef] = useClientRect<HTMLDivElement>();
const [suffixRect, suffixRef] = useClientRect<HTMLDivElement>(); const [suffixRect, suffixRef] = useClientRect<HTMLDivElement>();
const theme = useTheme(); const theme = useTheme2();
const styles = getInputStyles({ theme, invalid: !!invalid, width }); const styles = getInputStyles({ theme, invalid: !!invalid, width });
return ( 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 { css, cx } from '@emotion/css';
import { ThemeContext } from '../../themes/ThemeContext';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '../../themes/ThemeContext';
const getStyles = (theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaTheme) => ({
logsStatsRow: css` logsStatsRow: css`
@ -58,8 +57,7 @@ export interface Props {
} }
export const LogLabelStatsRow: FunctionComponent<Props> = ({ active, count, proportion, value }) => { export const LogLabelStatsRow: FunctionComponent<Props> = ({ active, count, proportion, value }) => {
const theme = useContext(ThemeContext); const style = useStyles(getStyles);
const style = getStyles(theme);
const percent = `${Math.round(proportion * 100)}%`; const percent = `${Math.round(proportion * 100)}%`;
const barStyle = { width: percent }; const barStyle = { width: percent };
const className = active ? cx([style.logsStatsRow, style.logsStatsRowActive]) : cx([style.logsStatsRow]); 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 { GrafanaTheme, DataQueryError, LogRowModel, textUtil } from '@grafana/data';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { Alert } from '../Alert/Alert'; import { Alert } from '../Alert/Alert';
import { LogRowContextRows, LogRowContextQueryErrors, HasMoreContextRows } from './LogRowContextProvider'; import { LogRowContextRows, LogRowContextQueryErrors, HasMoreContextRows } from './LogRowContextProvider';
import { ThemeContext } from '../../themes/ThemeContext'; import { useStyles } from '../../themes/ThemeContext';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
import { List } from '../List/List'; import { List } from '../List/List';
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
@ -66,8 +66,7 @@ const LogRowContextGroupHeader: React.FunctionComponent<LogRowContextGroupHeader
onLoadMoreContext, onLoadMoreContext,
canLoadMoreRows, canLoadMoreRows,
}) => { }) => {
const theme = useContext(ThemeContext); const { header } = useStyles(getLogRowContextStyles);
const { header } = getLogRowContextStyles(theme);
return ( return (
<div className={header}> <div className={header}>
@ -105,8 +104,7 @@ export const LogRowContextGroup: React.FunctionComponent<LogRowContextGroupProps
canLoadMoreRows, canLoadMoreRows,
onLoadMoreContext, onLoadMoreContext,
}) => { }) => {
const theme = useContext(ThemeContext); const { commonStyles, logs } = useStyles(getLogRowContextStyles);
const { commonStyles, logs } = getLogRowContextStyles(theme);
const [scrollTop, setScrollTop] = useState(0); const [scrollTop, setScrollTop] = useState(0);
const listContainerRef = useRef<HTMLDivElement>() as React.RefObject<HTMLDivElement>; const listContainerRef = useRef<HTMLDivElement>() as React.RefObject<HTMLDivElement>;

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { useStyles } from '../../themes'; import { useStyles2 } from '../../themes';
/** @internal */ /** @internal */
export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> { export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> {
@ -14,7 +14,7 @@ export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> {
/** @internal */ /** @internal */
export const Menu = React.forwardRef<HTMLDivElement, MenuProps>( export const Menu = React.forwardRef<HTMLDivElement, MenuProps>(
({ header, children, ariaLabel, ...otherProps }, ref) => { ({ header, children, ariaLabel, ...otherProps }, ref) => {
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
return ( return (
<div {...otherProps} ref={ref} className={styles.wrapper} aria-label={ariaLabel}> <div {...otherProps} ref={ref} className={styles.wrapper} aria-label={ariaLabel}>
@ -27,17 +27,17 @@ export const Menu = React.forwardRef<HTMLDivElement, MenuProps>(
Menu.displayName = 'Menu'; Menu.displayName = 'Menu';
/** @internal */ /** @internal */
const getStyles = (theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
return { return {
header: css` header: css`
padding: ${theme.v2.spacing(0.5, 0.5, 1, 0.5)}; padding: ${theme.spacing(0.5, 0.5, 1, 0.5)};
border-bottom: 1px solid ${theme.v2.palette.border.medium}; border-bottom: 1px solid ${theme.palette.border.medium};
`, `,
wrapper: css` wrapper: css`
background: ${theme.v2.palette.background.secondary}; background: ${theme.palette.background.secondary};
box-shadow: ${theme.v2.shadows.z2}; box-shadow: ${theme.shadows.z2};
display: inline-block; 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 React from 'react';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { useStyles } from '../../themes'; import { useStyles2 } from '../../themes';
import { MenuItemProps } from './MenuItem'; import { MenuItemProps } from './MenuItem';
/** @internal */ /** @internal */
@ -21,7 +21,7 @@ export interface MenuGroupProps extends Partial<MenuItemsGroup> {
/** @internal */ /** @internal */
export const MenuGroup: React.FC<MenuGroupProps> = ({ label, children, ariaLabel }) => { export const MenuGroup: React.FC<MenuGroupProps> = ({ label, children, ariaLabel }) => {
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
return ( return (
<div> <div>
@ -37,12 +37,12 @@ export const MenuGroup: React.FC<MenuGroupProps> = ({ label, children, ariaLabel
MenuGroup.displayName = 'MenuGroup'; MenuGroup.displayName = 'MenuGroup';
/** @internal */ /** @internal */
const getStyles = (theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
return { return {
groupLabel: css` groupLabel: css`
color: ${theme.v2.palette.text.secondary}; color: ${theme.palette.text.secondary};
font-size: ${theme.v2.typography.size.sm}; font-size: ${theme.typography.size.sm};
padding: ${theme.v2.spacing(0.5, 1)}; padding: ${theme.spacing(0.5, 1)};
`, `,
}; };
}; };

View File

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

View File

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

View File

@ -1,18 +1,18 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { stylesFactory } from '../../themes'; import { stylesFactory } from '../../themes';
export const getModalStyles = stylesFactory((theme: GrafanaTheme) => { export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => {
// rgba(1,4,9,0.8) // rgba(1,4,9,0.8)
const backdropBackground = 'rgba(0, 0, 0, 0.5)'; const backdropBackground = 'rgba(0, 0, 0, 0.5)';
const borderRadius = theme.v2.shape.borderRadius(2); const borderRadius = theme.shape.borderRadius(2);
return { return {
modal: css` modal: css`
position: fixed; position: fixed;
z-index: ${theme.v2.zIndex.modal}; z-index: ${theme.zIndex.modal};
background: ${theme.v2.palette.background.primary}; background: ${theme.palette.background.primary};
box-shadow: ${theme.v2.shadows.z4}; box-shadow: ${theme.shadows.z4};
border-radius: ${borderRadius}; border-radius: ${borderRadius};
background-clip: padding-box; background-clip: padding-box;
outline: none; outline: none;
@ -30,26 +30,26 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => {
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: ${theme.v2.zIndex.modalBackdrop}; z-index: ${theme.zIndex.modalBackdrop};
background-color: ${backdropBackground}; background-color: ${backdropBackground};
`, `,
modalHeader: css` modalHeader: css`
label: modalHeader; label: modalHeader;
background: ${theme.colors.bg2}; background: ${theme.palette.background.secondary};
border-bottom: 1px solid ${theme.colors.pageHeaderBorder}; border-bottom: 1px solid ${theme.palette.border.weak};
border-radius: ${borderRadius} ${borderRadius} 0 0; border-radius: ${borderRadius} ${borderRadius} 0 0;
display: flex; display: flex;
height: 42px; height: 42px;
`, `,
modalHeaderTitle: css` modalHeaderTitle: css`
font-size: ${theme.typography.size.lg}; font-size: ${theme.typography.size.lg};
margin: 0 ${theme.spacing.md}; margin: 0 ${theme.spacing(2)};
display: flex; display: flex;
align-items: center; align-items: center;
line-height: 42px; line-height: 42px;
`, `,
modalHeaderIcon: css` modalHeaderIcon: css`
margin-right: ${theme.spacing.md}; margin-right: ${theme.spacing(2)};
font-size: inherit; font-size: inherit;
&:before { &:before {
vertical-align: baseline; vertical-align: baseline;
@ -61,13 +61,13 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme) => {
align-items: center; align-items: center;
flex-grow: 1; flex-grow: 1;
justify-content: flex-end; justify-content: flex-end;
padding-right: ${theme.spacing.sm}; padding-right: ${theme.spacing(1)};
`, `,
modalContent: css` modalContent: css`
padding: calc(${theme.spacing.d} * 2); padding: calc(${theme.spacing.gridSize} * 2);
overflow: auto; overflow: auto;
width: 100%; 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 React, { memo } from 'react';
import { EdgeDatum, NodeDatum } from './types'; import { EdgeDatum, NodeDatum } from './types';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { stylesFactory, useTheme } from '../../themes'; import { useStyles2 } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import tinycolor from 'tinycolor2';
import lightTheme from '../../themes/light';
import darkTheme from '../../themes/dark';
import { shortenLine } from './utils'; import { shortenLine } from './utils';
const getStyles = stylesFactory((theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
const inverseTheme = theme.isDark ? lightTheme : darkTheme;
return { return {
mainGroup: css` mainGroup: css`
pointer-events: none; pointer-events: none;
@ -17,14 +13,14 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
`, `,
background: css` background: css`
fill: ${tinycolor(inverseTheme.colors.bodyBg).setAlpha(0.8).toHex8String()}; fill: ${theme.components.tooltip.background};
`, `,
text: css` text: css`
fill: ${inverseTheme.colors.text}; fill: ${theme.components.tooltip.text};
`, `,
}; };
}); };
interface Props { interface Props {
edge: EdgeDatum; edge: EdgeDatum;
@ -49,7 +45,7 @@ export const EdgeLabel = memo(function EdgeLabel(props: Props) {
x: line.x1 + (line.x2 - line.x1) / 2, x: line.x1 + (line.x2 - line.x1) / 2,
y: line.y1 + (line.y2 - line.y1) / 2, y: line.y1 + (line.y2 - line.y1) / 2,
}; };
const styles = getStyles(useTheme()); const styles = useStyles2(getStyles);
return ( return (
<g className={styles.mainGroup}> <g className={styles.mainGroup}>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { useTheme } from '../../themes/ThemeContext'; import { useTheme2 } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles'; import { getSelectStyles } from './getSelectStyles';
import { cx } from '@emotion/css'; import { cx } from '@emotion/css';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
@ -12,7 +12,7 @@ interface SelectMenuProps {
} }
export const SelectMenu = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuProps>>((props, ref) => { export const SelectMenu = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuProps>>((props, ref) => {
const theme = useTheme(); const theme = useTheme2();
const styles = getSelectStyles(theme); const styles = getSelectStyles(theme);
const { children, maxHeight, innerRef, innerProps } = props; const { children, maxHeight, innerRef, innerProps } = props;
@ -38,7 +38,7 @@ interface SelectMenuOptionProps<T> {
export const SelectMenuOptions = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuOptionProps<any>>>( export const SelectMenuOptions = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SelectMenuOptionProps<any>>>(
(props, ref) => { (props, ref) => {
const theme = useTheme(); const theme = useTheme2();
const styles = getSelectStyles(theme); const styles = getSelectStyles(theme);
const { children, innerProps, data, renderOptionLabel, isSelected, isFocused } = props; 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 { css, cx } from '@emotion/css';
import { components, SingleValueProps } from 'react-select'; import { components, SingleValueProps } from 'react-select';
import { useDelayedSwitch } from '../../utils/useDelayedSwitch'; import { useDelayedSwitch } from '../../utils/useDelayedSwitch';
import { stylesFactory, useTheme } from '../../themes'; import { useStyles2 } from '../../themes';
import { SlideOutTransition } from '../transitions/SlideOutTransition'; import { SlideOutTransition } from '../transitions/SlideOutTransition';
import { FadeTransition } from '../transitions/FadeTransition'; import { FadeTransition } from '../transitions/FadeTransition';
import { Spinner } from '../Spinner/Spinner'; 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` const singleValue = css`
label: singleValue; label: singleValue;
color: ${theme.v2.components.input.text}; color: ${theme.components.input.text};
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -36,7 +36,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
`; `;
return { singleValue, container, item }; return { singleValue, container, item };
}); };
type StylesType = ReturnType<typeof getStyles>;
interface Props interface Props
extends SingleValueProps<{ extends SingleValueProps<{
@ -47,8 +49,7 @@ interface Props
export const SingleValue = (props: Props) => { export const SingleValue = (props: Props) => {
const { children, data } = props; const { children, data } = props;
const theme = useTheme(); const styles = useStyles2(getStyles);
const styles = getStyles(theme);
const loading = useDelayedSwitch(data.loading || false, { delay: 250, duration: 750 }); const loading = useDelayedSwitch(data.loading || false, { delay: 250, duration: 750 });
@ -56,7 +57,7 @@ export const SingleValue = (props: Props) => {
<components.SingleValue {...props}> <components.SingleValue {...props}>
<div className={cx(styles.singleValue)}> <div className={cx(styles.singleValue)}>
{data.imgUrl ? ( {data.imgUrl ? (
<FadeWithImage loading={loading} imgUrl={data.imgUrl} /> <FadeWithImage loading={loading} imgUrl={data.imgUrl} styles={styles} />
) : ( ) : (
<SlideOutTransition horizontal size={16} visible={loading} duration={150}> <SlideOutTransition horizontal size={16} visible={loading} duration={150}>
<div className={styles.container}> <div className={styles.container}>
@ -70,17 +71,14 @@ export const SingleValue = (props: Props) => {
); );
}; };
const FadeWithImage = (props: { loading: boolean; imgUrl: string }) => { const FadeWithImage = (props: { loading: boolean; imgUrl: string; styles: StylesType }) => {
const theme = useTheme();
const styles = getStyles(theme);
return ( return (
<div className={styles.container}> <div className={props.styles.container}>
<FadeTransition duration={150} visible={props.loading}> <FadeTransition duration={150} visible={props.loading}>
<Spinner className={styles.item} inline /> <Spinner className={props.styles.item} inline />
</FadeTransition> </FadeTransition>
<FadeTransition duration={150} visible={!props.loading}> <FadeTransition duration={150} visible={!props.loading}>
<img className={styles.item} src={props.imgUrl} /> <img className={props.styles.item} src={props.imgUrl} />
</FadeTransition> </FadeTransition>
</div> </div>
); );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import React, { HTMLProps } from 'react'; import React, { HTMLProps } from 'react';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { stylesFactory, useTheme } from '../../themes'; import { stylesFactory, useTheme2 } from '../../themes';
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles'; import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
export interface Props extends Omit<HTMLProps<HTMLTextAreaElement>, 'size'> { 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) => { export const TextArea = React.forwardRef<HTMLTextAreaElement, Props>(({ invalid, className, ...props }, ref) => {
const theme = useTheme(); const theme = useTheme2();
const styles = getTextAreaStyle(theme, invalid); const styles = getTextAreaStyle(theme, invalid);
return <textarea {...props} className={cx(styles.textarea, className)} ref={ref} />; 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 { return {
textarea: cx( textarea: cx(
sharedInputStyle(theme), sharedInputStyle(theme),
getFocusStyle(theme), getFocusStyle(theme.v1),
css` css`
border-radius: ${theme.border.radius.sm}; border-radius: ${theme.shape.borderRadius()};
padding: ${theme.spacing.formSpacingBase / 4}px ${theme.spacing.formSpacingBase}px; padding: ${theme.spacing.gridSize / 4}px ${theme.spacing.gridSize}px;
width: 100%; 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 */ /** @jsxImportSource @emotion/react */
import { Profiler, ProfilerOnRenderCallback, useState, FC } from '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 { css, cx } from '@emotion/css';
import { useStyles, useTheme } from '../../themes'; import { useStyles2, useTheme2 } from '../../themes';
import { Button } from '../Button'; import { Button } from '../Button';
import { VerticalGroup } from '../Layout/Layout'; import { VerticalGroup } from '../Layout/Layout';
import classnames from 'classnames'; import classnames from 'classnames';
@ -53,7 +53,7 @@ interface TestComponentProps {
} }
function UseStylesNoCX({ index }: TestComponentProps) { function UseStylesNoCX({ index }: TestComponentProps) {
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
return ( return (
<div className={styles.main}> <div className={styles.main}>
<div className={styles.child}>{index}</div> <div className={styles.child}>{index}</div>
@ -62,7 +62,7 @@ function UseStylesNoCX({ index }: TestComponentProps) {
} }
function UseStylesWithConditionalCX({ 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 }); const mainStyles = cx(styles.main, { [styles.large]: index > 10, [styles.disabed]: index % 10 === 0 });
return ( return (
@ -73,7 +73,7 @@ function UseStylesWithConditionalCX({ index }: TestComponentProps) {
} }
function UseStylesWithConditionalClassNames({ 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 }); const mainStyles = classnames(styles.main, { [styles.large]: index > 10, [styles.disabed]: index % 10 === 0 });
return ( return (
@ -84,7 +84,7 @@ function UseStylesWithConditionalClassNames({ index }: TestComponentProps) {
} }
function UseStylesWithCSSProp({ index }: TestComponentProps) { function UseStylesWithCSSProp({ index }: TestComponentProps) {
const styles = useStyles(getStylesObjects); const styles = useStyles2(getStylesObjects);
return ( return (
<div css={styles.main}> <div css={styles.main}>
@ -94,7 +94,7 @@ function UseStylesWithCSSProp({ index }: TestComponentProps) {
} }
function UseStylesWithConditionalCSS({ 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]; const mainStyles = [styles.main, index > 10 && styles.large, index % 10 === 0 && styles.disabed];
return ( return (
<div css={mainStyles}> <div css={mainStyles}>
@ -104,7 +104,7 @@ function UseStylesWithConditionalCSS({ index }: TestComponentProps) {
} }
function InlineEmotionCSS({ index }: TestComponentProps) { function InlineEmotionCSS({ index }: TestComponentProps) {
const theme = useTheme(); const theme = useTheme2();
const styles = getStyles(theme); const styles = getStyles(theme);
return ( return (
@ -141,7 +141,7 @@ function MeasureRender({ children, id }: { children: React.ReactNode; id: string
); );
} }
const getStyles = (theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
return { return {
main: css(getStylesObjectMain(theme)), main: css(getStylesObjectMain(theme)),
large: css({ large: css({
@ -156,7 +156,7 @@ const getStyles = (theme: GrafanaTheme) => {
}; };
}; };
const getStylesObjects = (theme: GrafanaTheme) => { const getStylesObjects = (theme: GrafanaThemeV2) => {
return { return {
main: getStylesObjectMain(theme), main: getStylesObjectMain(theme),
large: { large: {
@ -171,20 +171,20 @@ const getStylesObjects = (theme: GrafanaTheme) => {
}; };
}; };
function getStylesObjectMain(theme: GrafanaTheme): any { function getStylesObjectMain(theme: GrafanaThemeV2): any {
return { return {
background: 'blue', background: 'blue',
border: '1px solid red', border: '1px solid red',
color: 'white', color: 'white',
padding: theme.v2.spacing(1), padding: theme.spacing(1),
shadow: theme.v2.shadows.z1, shadow: theme.shadows.z1,
':hover': { ':hover': {
background: theme.colors.bg1, background: theme.palette.background.primary,
}, },
}; };
} }
function getStylesObjectChild(theme: GrafanaTheme): any { function getStylesObjectChild(theme: GrafanaThemeV2): any {
return { return {
padding: '2px', padding: '2px',
fontSize: '10px', fontSize: '10px',

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import React, { FC, FormEvent, MouseEvent, useState } from 'react'; import React, { FC, FormEvent, MouseEvent, useState } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { dateMath, dateTime, getDefaultTimeRange, GrafanaTheme, TimeRange, TimeZone } from '@grafana/data'; import { dateMath, dateTime, getDefaultTimeRange, GrafanaThemeV2, TimeRange, TimeZone } from '@grafana/data';
import { useStyles } from '../../themes/ThemeContext'; import { useStyles2 } from '../../themes/ThemeContext';
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
import { Icon } from '../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { getInputStyles } from '../Input/Input'; import { getInputStyles } from '../Input/Input';
@ -40,7 +40,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
hideQuickRanges = false, hideQuickRanges = false,
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
const onOpen = (event: FormEvent<HTMLDivElement>) => { const onOpen = (event: FormEvent<HTMLDivElement>) => {
event.stopPropagation(); 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 }); const inputStyles = getInputStyles({ theme, invalid: false });
return { return {
container: css` container: css`
@ -119,25 +119,25 @@ const getStyles = (theme: GrafanaTheme) => {
justify-content: space-between; justify-content: space-between;
cursor: pointer; cursor: pointer;
padding-right: 0; padding-right: 0;
line-height: ${theme.spacing.formInputHeight - 2}px; line-height: ${theme.v1.spacing.formInputHeight - 2}px;
${getFocusStyle(theme)}; ${getFocusStyle(theme.v1)};
` `
), ),
caretIcon: cx( caretIcon: cx(
inputStyles.suffix, inputStyles.suffix,
css` css`
position: relative; position: relative;
margin-left: ${theme.spacing.xs}; margin-left: ${theme.v1.spacing.xs};
` `
), ),
clearIcon: css` clearIcon: css`
margin-right: ${theme.spacing.xs}; margin-right: ${theme.v1.spacing.xs};
&:hover { &:hover {
color: ${theme.colors.linkHover}; color: ${theme.v1.colors.linkHover};
} }
`, `,
placeholder: css` placeholder: css`
color: ${theme.colors.formInputPlaceholderText}; color: ${theme.v1.colors.formInputPlaceholderText};
opacity: 1; 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 { render } from '@testing-library/react';
import React from 'react'; import React from 'react';
import dark from '../../themes/dark';
import { UnthemedTimeRangePicker } from './TimeRangePicker'; import { UnthemedTimeRangePicker } from './TimeRangePicker';
const from = dateTime('2019-12-17T07:48:27.433Z'); const from = dateTime('2019-12-17T07:48:27.433Z');
@ -23,7 +22,7 @@ describe('TimePicker', () => {
onMoveBackward={() => {}} onMoveBackward={() => {}}
onMoveForward={() => {}} onMoveForward={() => {}}
onZoom={() => {}} 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 { css, cx } from '@emotion/css';
import React, { memo, useState } from 'react'; import React, { memo, useState } from 'react';
import { useMedia } from 'react-use'; import { useMedia } from 'react-use';
import { stylesFactory, useTheme } from '../../../themes'; import { stylesFactory, useTheme2 } from '../../../themes';
import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar'; import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar';
import { Icon } from '../../Icon/Icon'; import { Icon } from '../../Icon/Icon';
import { mapRangeToTimeOption } from './mapper'; import { mapRangeToTimeOption } from './mapper';
@ -11,20 +11,20 @@ import { TimeRangeForm } from './TimeRangeForm';
import { TimeRangeList } from './TimeRangeList'; import { TimeRangeList } from './TimeRangeList';
import { TimePickerFooter } from './TimePickerFooter'; import { TimePickerFooter } from './TimePickerFooter';
const getStyles = stylesFactory((theme: GrafanaTheme, isReversed, hideQuickRanges, isContainerTall) => { const getStyles = stylesFactory((theme: GrafanaThemeV2, isReversed, hideQuickRanges, isContainerTall) => {
return { return {
container: css` container: css`
background: ${theme.v2.palette.background.secondary}; background: ${theme.palette.background.secondary};
box-shadow: ${theme.v2.shadows.z4}; box-shadow: ${theme.shadows.z4};
position: absolute; position: absolute;
z-index: ${theme.zIndex.dropdown}; z-index: ${theme.zIndex.dropdown};
width: 546px; width: 546px;
top: 116%; top: 116%;
border-radius: 2px; border-radius: 2px;
border: 1px solid ${theme.v2.palette.border.weak}; border: 1px solid ${theme.palette.border.weak};
${isReversed ? 'left' : 'right'}: 0; ${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; width: 262px;
} }
`, `,
@ -35,16 +35,16 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isReversed, hideQuickRange
leftSide: css` leftSide: css`
display: flex; display: flex;
flex-direction: column; 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%'}; width: ${!hideQuickRanges ? '60%' : '100%'};
overflow: hidden; overflow: hidden;
order: ${isReversed ? 1 : 0}; order: ${isReversed ? 1 : 0};
`, `,
rightSide: css` rightSide: css`
width: 40% !important; 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; 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 { return {
header: css` header: css`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; 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; padding: 7px 9px 7px 9px;
`, `,
body: css` body: css`
border-bottom: 1px solid ${theme.v2.palette.border.weak}; border-bottom: 1px solid ${theme.palette.border.weak};
`, `,
form: css` form: css`
padding: 7px 9px 7px 9px; 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 { return {
container: css` container: css`
padding-top: 9px; padding-top: 9px;
@ -88,12 +88,12 @@ const getFullScreenStyles = stylesFactory((theme: GrafanaTheme, hideQuickRanges?
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; 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 { return {
container: css` container: css`
padding: 12px; padding: 12px;
@ -105,7 +105,7 @@ const getEmptyListStyles = stylesFactory((theme: GrafanaTheme) => {
} }
`, `,
link: css` 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 isHistoryEmpty = !history?.length;
const isContainerTall = const isContainerTall =
(isFullscreen && showHistory) || (!isFullscreen && ((showHistory && !isHistoryEmpty) || !hideQuickRanges)); (isFullscreen && showHistory) || (!isFullscreen && ((showHistory && !isHistoryEmpty) || !hideQuickRanges));
const theme = useTheme(); const theme = useTheme2();
const styles = getStyles(theme, isReversed, hideQuickRanges, isContainerTall); const styles = getStyles(theme, isReversed, hideQuickRanges, isContainerTall);
const historyOptions = mapToHistoryOptions(history, timeZone); const historyOptions = mapToHistoryOptions(history, timeZone);
@ -196,15 +196,15 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
}; };
export const TimePickerContent: React.FC<Props> = (props) => { export const TimePickerContent: React.FC<Props> = (props) => {
const theme = useTheme(); const theme = useTheme2();
const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.lg})`); const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.values.lg}px)`);
return <TimePickerContentWithScreenSize {...props} isFullscreen={isFullscreen} />; return <TimePickerContentWithScreenSize {...props} isFullscreen={isFullscreen} />;
}; };
const NarrowScreenForm: React.FC<FormProps> = (props) => { const NarrowScreenForm: React.FC<FormProps> = (props) => {
const { value, hideQuickRanges, onChange, timeZone, historyOptions = [], showHistory } = props; const { value, hideQuickRanges, onChange, timeZone, historyOptions = [], showHistory } = props;
const theme = useTheme(); const theme = useTheme2();
const styles = getNarrowScreenStyles(theme); const styles = getNarrowScreenStyles(theme);
const isAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to); const isAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
const [collapsedFlag, setCollapsedFlag] = useState(!isAbsolute); const [collapsedFlag, setCollapsedFlag] = useState(!isAbsolute);
@ -246,7 +246,7 @@ const NarrowScreenForm: React.FC<FormProps> = (props) => {
}; };
const FullScreenForm: React.FC<FormProps> = (props) => { const FullScreenForm: React.FC<FormProps> = (props) => {
const theme = useTheme(); const theme = useTheme2();
const styles = getFullScreenStyles(theme, props.hideQuickRanges); const styles = getFullScreenStyles(theme, props.hideQuickRanges);
return ( return (
@ -280,7 +280,7 @@ const FullScreenForm: React.FC<FormProps> = (props) => {
}; };
const EmptyRecentList = memo(() => { const EmptyRecentList = memo(() => {
const theme = useTheme(); const theme = useTheme2();
const styles = getEmptyListStyles(theme); const styles = getEmptyListStyles(theme);
return ( return (

View File

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

View File

@ -1,9 +1,9 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { GrafanaTheme, TimeOption } from '@grafana/data'; import { GrafanaThemeV2, TimeOption } from '@grafana/data';
import { useTheme, stylesFactory } from '../../../themes'; import { useStyles2 } from '../../../themes/ThemeContext';
const getStyles = stylesFactory((theme: GrafanaTheme) => { const getStyles = (theme: GrafanaThemeV2) => {
return { return {
container: css` container: css`
display: flex; display: flex;
@ -12,16 +12,16 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
padding: 7px 9px 7px 9px; padding: 7px 9px 7px 9px;
&:hover { &:hover {
background: ${theme.v2.palette.action.hover}; background: ${theme.palette.action.hover};
cursor: pointer; cursor: pointer;
} }
`, `,
selected: css` selected: css`
background: ${theme.v2.palette.action.selected}; background: ${theme.palette.action.selected};
} }
`, `,
}; };
}); };
interface Props { interface Props {
value: TimeOption; value: TimeOption;
@ -30,8 +30,7 @@ interface Props {
} }
export const TimeRangeOption = memo<Props>(({ value, onSelect, selected = false }) => { export const TimeRangeOption = memo<Props>(({ value, onSelect, selected = false }) => {
const theme = useTheme(); const styles = useStyles2(getStyles);
const styles = getStyles(theme);
return ( return (
<div className={cx(styles.container, selected && styles.selected)} onClick={() => onSelect(value)} tabIndex={-1}> <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 allItems = flattenGroupItems(this.props.groupedItems);
const longestLabel = calculateLongestLabel(allItems); 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({ this.setState({
listWidth, listWidth,
listHeight, listHeight,
@ -86,7 +86,7 @@ export class Typeahead extends React.PureComponent<Props, State> {
if (isEqual(prevProps.groupedItems, this.props.groupedItems) === false) { if (isEqual(prevProps.groupedItems, this.props.groupedItems) === false) {
const allItems = flattenGroupItems(this.props.groupedItems); const allItems = flattenGroupItems(this.props.groupedItems);
const longestLabel = calculateLongestLabel(allItems); 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 }); 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 { css, cx } from '@emotion/css';
import { CompletionItem, ThemeContext } from '../..';
import { GrafanaTheme, renderMarkdown } from '@grafana/data'; import { GrafanaTheme, renderMarkdown } from '@grafana/data';
import { useTheme } from '../../themes/ThemeContext';
import { CompletionItem } from '../../types';
const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => { const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => {
return { return {
@ -36,7 +37,7 @@ export const TypeaheadInfo: React.FC<Props> = ({ item, height }) => {
const visible = item && !!item.documentation; const visible = item && !!item.documentation;
const label = item ? item.label : ''; const label = item ? item.label : '';
const documentation = renderMarkdown(item?.documentation); const documentation = renderMarkdown(item?.documentation);
const theme = useContext(ThemeContext); const theme = useTheme();
const styles = getStyles(theme, height, visible); const styles = getStyles(theme, height, visible);
return ( return (

View File

@ -1,12 +1,12 @@
import React, { useContext } from 'react'; import React from 'react';
// @ts-ignore // @ts-ignore
import Highlighter from 'react-highlight-words'; import Highlighter from 'react-highlight-words';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { CompletionItem, CompletionItemKind } from '../../types/completion'; import { CompletionItem, CompletionItemKind } from '../../types/completion';
import { ThemeContext } from '../../themes/ThemeContext';
import { PartialHighlighter } from './PartialHighlighter'; import { PartialHighlighter } from './PartialHighlighter';
import { useStyles } from '../../themes/ThemeContext';
interface Props { interface Props {
isSelected: boolean; isSelected: boolean;
@ -59,8 +59,7 @@ const getStyles = (theme: GrafanaTheme) => ({
}); });
export const TypeaheadItem: React.FC<Props> = (props: Props) => { export const TypeaheadItem: React.FC<Props> = (props: Props) => {
const theme = useContext(ThemeContext); const styles = useStyles(getStyles);
const styles = getStyles(theme);
const { isSelected, item, prefix, style, onMouseEnter, onMouseLeave, onClickItem } = props; const { isSelected, item, prefix, style, onMouseEnter, onMouseLeave, onClickItem } = props;
const className = isSelected ? cx([styles.typeaheadItem, styles.typeaheadItemSelected]) : cx([styles.typeaheadItem]); 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, theme,
} = this.props; } = 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 = { let config: Axis = {
scale: scaleKey, scale: scaleKey,
show, show,
stroke: theme.v2.palette.text.primary, stroke: theme.colors.text,
side: getUPlotSideFromAxis(placement), side: getUPlotSideFromAxis(placement),
font, font,
labelFont: font, labelFont: font,

View File

@ -10,9 +10,11 @@ import {
ScaleOrientation, ScaleOrientation,
ScaleDirection, ScaleDirection,
} from '../config'; } from '../config';
import darkTheme from '../../../themes/dark'; import { createTheme } from '@grafana/data';
describe('UPlotConfigBuilder', () => { describe('UPlotConfigBuilder', () => {
const darkTheme = createTheme().v1;
describe('default config', () => { describe('default config', () => {
it('builds default config', () => { it('builds default config', () => {
const builder = new UPlotConfigBuilder(); 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 tinycolor from 'tinycolor2';
import uPlot from 'uplot'; import uPlot from 'uplot';
import darkTheme from '../../../themes/dark';
import { getCanvasContext } from '../../../utils/measureText'; import { getCanvasContext } from '../../../utils/measureText';
export function getOpacityGradientFn( export function getOpacityGradientFn(
@ -69,7 +68,7 @@ export function getScaleGradientFn(
console.log('series.max', series.max); console.log('series.max', series.max);
const getColorWithAlpha = (color: string) => { const getColorWithAlpha = (color: string) => {
return tinycolor(getColorForTheme(color, darkTheme)).setAlpha(opacity).toString(); return 'rgb(255, 0, 0)';
}; };
const addColorStop = (value: number, color: string) => { const addColorStop = (value: number, color: string) => {

View File

@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { Global } from '@emotion/react'; import { Global } from '@emotion/react';
import { useTheme } from '..'; import { useTheme2 } from '..';
import { getElementStyles } from './elements'; import { getElementStyles } from './elements';
/** @internal */ /** @internal */
export function GlobalStyles() { export function GlobalStyles() {
const theme = useTheme(); const theme = useTheme2();
const types = getElementStyles(theme.v2); const types = getElementStyles(theme);
return <Global styles={[types]} />; 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 hoistNonReactStatics from 'hoist-non-react-statics';
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { Themeable } from '../types/theme'; import { Themeable } from '../types/theme';
import { getTheme } from './getTheme';
import { stylesFactory } from './stylesFactory'; import { stylesFactory } from './stylesFactory';
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; 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 * Mock used in tests
*/ */
let ThemeContextMock: React.Context<GrafanaTheme> | null = null; let ThemeContextMock: React.Context<GrafanaThemeV2> | null = null;
// Used by useStyles() // Used by useStyles()
export const memoizedStyleCreators = new WeakMap(); export const memoizedStyleCreators = new WeakMap();
// Use Grafana Dark theme by default // Use Grafana Dark theme by default
/** @public */ /** @public */
export const ThemeContext = React.createContext(getTheme(GrafanaThemeType.Dark)); export const ThemeContext = React.createContext(createTheme());
ThemeContext.displayName = 'ThemeContext'; ThemeContext.displayName = 'ThemeContext';
/** @deprecated use withTheme2 */
export const withTheme = <P extends Themeable, S extends {} = {}>(Component: React.ComponentType<P>) => { export const withTheme = <P extends Themeable, S extends {} = {}>(Component: React.ComponentType<P>) => {
const WithTheme: React.FunctionComponent<Subtract<P, Themeable>> = (props) => { 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 * This is used in tests when mocking theme using mockThemeContext function defined below
*/ */
const ContextComponent = ThemeContextMock || ThemeContext; const ContextComponent = ThemeContextMock || ThemeContext;
// @ts-ignore return (
return <ContextComponent.Consumer>{(theme) => <Component {...props} theme={theme} />}</ContextComponent.Consumer>; // @ts-ignore
<ContextComponent.Consumer>{(theme) => <Component {...props} theme={theme.v1} />}</ContextComponent.Consumer>
);
}; };
WithTheme.displayName = `WithTheme(${Component.displayName})`; WithTheme.displayName = `WithTheme(${Component.displayName})`;
@ -38,7 +41,32 @@ export const withTheme = <P extends Themeable, S extends {} = {}>(Component: Rea
return WithTheme as Hoisted; 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 { export function useTheme(): GrafanaTheme {
return useContext(ThemeContextMock || ThemeContext).v1;
}
export function useTheme2(): GrafanaThemeV2 {
return useContext(ThemeContextMock || ThemeContext); return useContext(ThemeContextMock || ThemeContext);
} }
@ -67,11 +95,37 @@ export function useStyles<T>(getStyles: (theme: GrafanaTheme) => T) {
return memoizedStyleCreator(theme); 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 * Enables theme context mocking
*/ */
export const mockThemeContext = (theme: Partial<GrafanaTheme>) => { export const mockThemeContext = (theme: Partial<GrafanaThemeV2>) => {
ThemeContextMock = React.createContext(theme as GrafanaTheme); ThemeContextMock = React.createContext(theme as GrafanaThemeV2);
return () => { return () => {
ThemeContextMock = null; ThemeContextMock = null;
}; };

View File

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

View File

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

View File

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

View File

@ -1,8 +1,6 @@
import { ThemeContext, withTheme, useTheme, useStyles, mockThemeContext } from './ThemeContext'; export { ThemeContext, withTheme, useTheme, useTheme2, useStyles, useStyles2, mockThemeContext } from './ThemeContext';
import { getTheme, mockTheme } from './getTheme'; export { getTheme, mockTheme } from './getTheme';
import { selectThemeVariant } from './selectThemeVariant';
export { stylesFactory } from './stylesFactory'; export { stylesFactory } from './stylesFactory';
export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext, useStyles };
export { GlobalStyles } from './GlobalStyles/GlobalStyles'; export { GlobalStyles } from './GlobalStyles/GlobalStyles';
import * as styleMixins from './mixins'; 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 { map, sortBy, flattenDeep, chunk, zip } from 'lodash';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import lightTheme from '../themes/light';
import darkTheme from '../themes/dark';
const PALETTE_ROWS = 4; const PALETTE_ROWS = 4;
@ -116,7 +114,7 @@ function hslToHex(color: any) {
export function getTextColorForBackground(color: string) { export function getTextColorForBackground(color: string) {
const b = tinycolor(color).getBrightness(); 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); 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 React from 'react';
import { ThemeContext } from '../../themes/ThemeContext'; import { ThemeContext } from '../../themes/ThemeContext';
import { getTheme, GlobalStyles } from '../../themes/index'; import { createTheme, GrafanaThemeV2 } from '@grafana/data';
import { GrafanaThemeType } from '@grafana/data';
import { RenderFunction } from '../../types'; import { RenderFunction } from '../../types';
import { useDarkMode } from 'storybook-dark-mode'; 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 }> = ({ const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassThemeChangeHandler }> = ({
children, children,
handleSassThemeChange, handleSassThemeChange,
}) => { }) => {
const themeType = useDarkMode() ? GrafanaThemeType.Dark : GrafanaThemeType.Light; const theme = createTheme({ palette: { mode: useDarkMode() ? 'dark' : 'light' } });
handleSassThemeChange(themeType); handleSassThemeChange(theme);
const theme = getTheme(themeType);
return ( return (
<ThemeContext.Provider value={theme}> <ThemeContext.Provider value={theme}>
@ -25,7 +22,7 @@ const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassTheme
padding: '20px', padding: '20px',
display: 'flex', display: 'flex',
minHeight: '80vh', minHeight: '80vh',
background: `${theme.v2.palette.background.primary}`, background: `${theme.palette.background.primary}`,
}} }}
> >
<GlobalStyles /> <GlobalStyles />

View File

@ -1,7 +1,7 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { Tab, TabsBar, Icon, IconName, useStyles } from '@grafana/ui'; import { Tab, TabsBar, Icon, IconName, useStyles2 } from '@grafana/ui';
import { NavModel, NavModelItem, NavModelBreadcrumb, GrafanaTheme } from '@grafana/data'; import { NavModel, NavModelItem, NavModelBreadcrumb, GrafanaThemeV2 } from '@grafana/data';
import { PanelHeaderMenuItem } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem'; import { PanelHeaderMenuItem } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem';
export interface Props { export interface Props {
@ -72,7 +72,7 @@ const Navigation = ({ children }: { children: NavModelItem[] }) => {
}; };
export const PageHeader: FC<Props> = ({ model }) => { export const PageHeader: FC<Props> = ({ model }) => {
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
if (!model) { if (!model) {
return null; return null;
@ -137,10 +137,10 @@ function renderTitle(title: string, breadcrumbs: NavModelBreadcrumb[]) {
return <h1 className="page-header__title">{breadcrumbsResult}</h1>; return <h1 className="page-header__title">{breadcrumbsResult}</h1>;
} }
const getStyles = (theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaThemeV2) => ({
headerCanvas: css` headerCanvas: css`
background: ${theme.v2.palette.background.canvas}; background: ${theme.palette.background.canvas};
border-bottom: 1px solid ${theme.v2.palette.border.weak}; 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 { ThemeChangedEvent } from 'app/types/events';
import appEvents from '../app_events'; import appEvents from '../app_events';
import { config } from '../config'; import { config } from '../config';
import { PreferencesService } from './PreferencesService'; import { PreferencesService } from './PreferencesService';
import { contextSrv } from '../core'; import { contextSrv } from '../core';
import { createTheme } from '@grafana/data';
export async function toggleTheme(runtimeOnly: boolean) { export async function toggleTheme(runtimeOnly: boolean) {
const currentTheme = config.theme; 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)); appEvents.publish(new ThemeChangedEvent(newTheme));
if (runtimeOnly) { if (runtimeOnly) {
@ -17,7 +22,7 @@ export async function toggleTheme(runtimeOnly: boolean) {
// Add css file for new theme // Add css file for new theme
const newCssLink = document.createElement('link'); const newCssLink = document.createElement('link');
newCssLink.rel = 'stylesheet'; newCssLink.rel = 'stylesheet';
newCssLink.href = config.bootData.themePaths[newTheme.type]; newCssLink.href = config.bootData.themePaths[newTheme.palette.mode];
document.body.appendChild(newCssLink); document.body.appendChild(newCssLink);
// Remove old css file // Remove old css file
@ -43,6 +48,6 @@ export async function toggleTheme(runtimeOnly: boolean) {
await service.update({ await service.update({
...currentPref, ...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 { ThemeContext } from '@grafana/ui';
import { appEvents } from '../core'; import { appEvents } from '../core';
import { ThemeChangedEvent } from 'app/types/events'; 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 ConfigContext = React.createContext<GrafanaBootConfig>(config);
export const ConfigConsumer = ConfigContext.Consumer; export const ConfigConsumer = ConfigContext.Consumer;
@ -16,11 +16,11 @@ export const provideConfig = (component: React.ComponentType<any>) => {
}; };
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => { export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
const [theme, setTheme] = useState<GrafanaTheme>(config.theme); const [theme, setTheme] = useState(getCurrentUserTheme());
useEffect(() => { useEffect(() => {
const sub = appEvents.subscribe(ThemeChangedEvent, (event) => { const sub = appEvents.subscribe(ThemeChangedEvent, (event) => {
config.theme = event.payload; //config.theme = event.payload;
setTheme(event.payload); setTheme(event.payload);
}); });
@ -30,6 +30,14 @@ export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>; 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>) => { export const provideTheme = (component: React.ComponentType<any>) => {
return provideConfig((props: any) => <ThemeProvider>{React.createElement(component, { ...props })}</ThemeProvider>); 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 React, { FC, ReactNode, useCallback, useEffect, useState } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaThemeV2 } from '@grafana/data';
import { Counter, Icon, useStyles } from '@grafana/ui'; import { Counter, Icon, useStyles2 } from '@grafana/ui';
import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers'; import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
import { useLocalStorage } from 'react-use'; import { useLocalStorage } from 'react-use';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
@ -24,7 +24,7 @@ export const OptionsPaneCategory: FC<OptionsPaneCategoryProps> = React.memo(
isExpanded: isOpenDefault !== false, isExpanded: isOpenDefault !== false,
}); });
const [isExpanded, setIsExpanded] = useState(savedState.isExpanded); const [isExpanded, setIsExpanded] = useState(savedState.isExpanded);
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
useEffect(() => { useEffect(() => {
if (!isExpanded && forceOpen && forceOpen > 0) { 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 { return {
box: css` box: css`
border-bottom: 1px solid ${theme.v2.palette.border.weak}; border-bottom: 1px solid ${theme.palette.border.weak};
&:last-child { &:last-child {
border-bottom: none; border-bottom: none;
} }
@ -98,11 +98,11 @@ const getStyles = (theme: GrafanaTheme) => {
border-bottom: 0; border-bottom: 0;
`, `,
boxNestedExpanded: css` boxNestedExpanded: css`
margin-bottom: ${theme.spacing.formSpacingBase * 2}px; margin-bottom: ${theme.spacing(2)};
`, `,
toggle: css` toggle: css`
color: ${theme.v2.palette.text.secondary}; color: ${theme.palette.text.secondary};
margin-right: ${theme.spacing.sm}; margin-right: ${theme.spacing(1)};
`, `,
title: css` title: css`
flex-grow: 1; flex-grow: 1;
@ -112,22 +112,22 @@ const getStyles = (theme: GrafanaTheme) => {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
align-items: baseline; align-items: baseline;
padding: ${theme.v2.spacing(1)}; padding: ${theme.spacing(1)};
color: ${theme.v2.palette.text.primary}; color: ${theme.palette.text.primary};
font-weight: ${theme.v2.typography.fontWeightMedium}; font-weight: ${theme.typography.fontWeightMedium};
&:hover { &: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` headerExpanded: css`
color: ${theme.v2.palette.text.primary}; color: ${theme.palette.text.primary};
`, `,
headerNested: css` headerNested: css`
padding: ${theme.v2.spacing(0.5, 0, 0.5, 0)}; padding: ${theme.spacing(0.5, 0, 0.5, 0)};
`, `,
body: css` body: css`
padding: ${theme.v2.spacing(1, 2, 1, 4)}; padding: ${theme.spacing(1, 2, 1, 4)};
`, `,
bodyNested: css` bodyNested: css`
position: relative; position: relative;
@ -139,7 +139,7 @@ const getStyles = (theme: GrafanaTheme) => {
left: 8px; left: 8px;
width: 1px; width: 1px;
height: 100%; 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 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 { DashboardModel, PanelModel } from '../../state';
import { CustomScrollbar, RadioButtonGroup, useStyles } from '@grafana/ui'; import { CustomScrollbar, RadioButtonGroup, useStyles2 } from '@grafana/ui';
import { getPanelFrameCategory } from './getPanelFrameOptions'; import { getPanelFrameCategory } from './getPanelFrameOptions';
import { getVizualizationOptions } from './getVizualizationOptions'; import { getVizualizationOptions } from './getVizualizationOptions';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
@ -26,7 +26,7 @@ export const OptionsPaneOptions: React.FC<Props> = (props) => {
const { plugin, dashboard, panel } = props; const { plugin, dashboard, panel } = props;
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [listMode, setListMode] = useState(OptionFilter.All); const [listMode, setListMode] = useState(OptionFilter.All);
const styles = useStyles(getStyles); const styles = useStyles2(getStyles);
const [panelFrameOptions, vizOptions, justOverrides] = useMemo( const [panelFrameOptions, vizOptions, justOverrides] = useMemo(
() => [getPanelFrameCategory(props), getVizualizationOptions(props), getFieldOverrideCategories(props)], () => [getPanelFrameCategory(props), getVizualizationOptions(props), getFieldOverrideCategories(props)],
@ -143,7 +143,7 @@ function renderSearchHits(
); );
} }
const getStyles = (theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaThemeV2) => ({
wrapper: css` wrapper: css`
height: 100%; height: 100%;
display: flex; display: flex;
@ -156,19 +156,19 @@ const getStyles = (theme: GrafanaTheme) => ({
min-height: 0; min-height: 0;
`, `,
formRow: css` formRow: css`
margin-bottom: ${theme.spacing.sm}; margin-bottom: ${theme.spacing(1)};
`, `,
formBox: css` formBox: css`
padding: ${theme.spacing.sm}; padding: ${theme.spacing(1)};
background: ${theme.colors.bg1}; background: ${theme.palette.background.primary};
border: 1px solid ${theme.colors.border1}; border: 1px solid ${theme.components.panel.border};
border-bottom: none; border-bottom: none;
`, `,
closeButton: css` closeButton: css`
margin-left: ${theme.spacing.sm}; margin-left: ${theme.spacing(1)};
`, `,
searchHits: css` searchHits: css`
padding: ${theme.spacing.sm} ${theme.spacing.sm} 0 ${theme.spacing.sm}; padding: ${theme.spacing(1, 1, 0, 1)};
`, `,
scrollWrapper: css` scrollWrapper: css`
flex-grow: 1; flex-grow: 1;
@ -176,13 +176,13 @@ const getStyles = (theme: GrafanaTheme) => ({
`, `,
searchNotice: css` searchNotice: css`
font-size: ${theme.typography.size.sm}; font-size: ${theme.typography.size.sm};
color: ${theme.colors.textWeak}; color: ${theme.palette.text.secondary};
padding: ${theme.spacing.sm}; padding: ${theme.spacing(1)};
text-align: center; text-align: center;
`, `,
mainBox: css` mainBox: css`
background: ${theme.colors.bg1}; background: ${theme.palette.background.primary};
border: 1px solid ${theme.v2.components.panel.border}; border: 1px solid ${theme.components.panel.border};
border-top: none; border-top: none;
flex-grow: 1; flex-grow: 1;
`, `,

View File

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

View File

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

View File

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

View File

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

View File

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

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