mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
grafana-ui: simplify and centralize monaco-theme-handling (#40643)
* grafana-ui: simplify and centralize monaco-theme-handling * simplify code * monaco: better theme-setup code * eslint fix * fix useEffect dependency
This commit is contained in:
parent
57750639cd
commit
b5ae62d6ae
@ -10,7 +10,6 @@ import { Themeable2 } from '../../types';
|
||||
|
||||
import { CodeEditorProps, Monaco, MonacoEditor as MonacoEditorType, MonacoOptions } from './types';
|
||||
import { registerSuggestions } from './suggestions';
|
||||
import defineThemes from './theme';
|
||||
|
||||
type Props = CodeEditorProps & Themeable2;
|
||||
|
||||
@ -85,8 +84,7 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
|
||||
|
||||
handleBeforeMount = (monaco: Monaco) => {
|
||||
this.monaco = monaco;
|
||||
const { language, theme, getSuggestions, onBeforeEditorMount } = this.props;
|
||||
defineThemes(monaco, theme);
|
||||
const { language, getSuggestions, onBeforeEditorMount } = this.props;
|
||||
|
||||
if (getSuggestions) {
|
||||
this.completionCancel = registerSuggestions(monaco, language, getSuggestions);
|
||||
@ -148,7 +146,6 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
|
||||
width={width}
|
||||
height={height}
|
||||
language={language}
|
||||
theme={theme.isDark ? 'grafana-dark' : 'grafana-light'}
|
||||
value={value}
|
||||
options={{
|
||||
...options,
|
||||
|
@ -1,5 +1,8 @@
|
||||
import React from 'react';
|
||||
import MonacoEditor, { loader as monacoEditorLoader, EditorProps as MonacoEditorProps } from '@monaco-editor/react';
|
||||
import React, { useEffect } from 'react';
|
||||
import MonacoEditor, { loader as monacoEditorLoader, useMonaco } from '@monaco-editor/react';
|
||||
import defineThemes from './theme';
|
||||
import { useTheme2 } from '../../themes';
|
||||
import type { ReactMonacoEditorProps } from './types';
|
||||
|
||||
let initalized = false;
|
||||
function initMonaco() {
|
||||
@ -13,9 +16,30 @@ function initMonaco() {
|
||||
},
|
||||
});
|
||||
initalized = true;
|
||||
monacoEditorLoader.init().then((monaco) => {
|
||||
// this call makes sure the themes exist.
|
||||
// they will not have the correct colors,
|
||||
// but we need them to exist since the beginning,
|
||||
// because if we start a monaco instance with
|
||||
// a theme that does not exist, it will not work well.
|
||||
defineThemes(monaco);
|
||||
});
|
||||
}
|
||||
|
||||
export const ReactMonacoEditor = (props: MonacoEditorProps) => {
|
||||
export const ReactMonacoEditor = (props: ReactMonacoEditorProps) => {
|
||||
const theme = useTheme2();
|
||||
const monaco = useMonaco();
|
||||
|
||||
useEffect(() => {
|
||||
// monaco can be null at the beginning, because it is loaded in asynchronously
|
||||
if (monaco !== null) {
|
||||
defineThemes(monaco, theme);
|
||||
}
|
||||
}, [monaco, theme]);
|
||||
|
||||
initMonaco();
|
||||
return <MonacoEditor {...props} />;
|
||||
|
||||
const monacoTheme = theme.isDark ? 'grafana-dark' : 'grafana-light';
|
||||
|
||||
return <MonacoEditor theme={monacoTheme} {...props} />;
|
||||
};
|
||||
|
@ -2,13 +2,13 @@ import React from 'react';
|
||||
import { useAsyncDependency } from '../../utils/useAsyncDependency';
|
||||
import { ErrorWithStack, LoadingPlaceholder } from '..';
|
||||
// we only use import type so it will not be included in the bundle
|
||||
import type { EditorProps } from '@monaco-editor/react';
|
||||
import type { ReactMonacoEditorProps } from './types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Experimental export
|
||||
**/
|
||||
export const ReactMonacoEditorLazy = (props: EditorProps) => {
|
||||
export const ReactMonacoEditorLazy = (props: ReactMonacoEditorProps) => {
|
||||
const { loading, error, dependency } = useAsyncDependency(
|
||||
import(/* webpackChunkName: "react-monaco-editor" */ './ReactMonacoEditor')
|
||||
);
|
||||
|
@ -1,12 +1,22 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Monaco } from './types';
|
||||
import { Monaco, monacoTypes } from './types';
|
||||
|
||||
export default function defineThemes(monaco: Monaco, theme: GrafanaTheme2) {
|
||||
function getColors(theme?: GrafanaTheme2): monacoTypes.editor.IColors {
|
||||
if (theme === undefined) {
|
||||
return {};
|
||||
} else {
|
||||
return {
|
||||
'editor.background': theme.components.input.background,
|
||||
'minimap.background': theme.colors.background.secondary,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// we support calling this without a theme, it will make sure the themes
|
||||
// are registered in monaco, even if the colors are not perfect.
|
||||
export default function defineThemes(monaco: Monaco, theme?: GrafanaTheme2) {
|
||||
// color tokens are defined here https://github.com/microsoft/vscode/blob/main/src/vs/platform/theme/common/colorRegistry.ts#L174
|
||||
const colors = {
|
||||
'editor.background': theme.components.input.background,
|
||||
'minimap.background': theme.colors.background.secondary,
|
||||
};
|
||||
const colors = getColors(theme);
|
||||
|
||||
monaco.editor.defineTheme('grafana-dark', {
|
||||
base: 'vs-dark',
|
||||
|
@ -1,5 +1,14 @@
|
||||
// We use `import type` to guarantee it'll be erased from the JS and it doesnt accidently bundle monaco
|
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import type { EditorProps } from '@monaco-editor/react';
|
||||
|
||||
// we do not allow customizing the theme.
|
||||
// (theme is complicated in Monaco, right now there is
|
||||
// a limitation where all monaco editors must have
|
||||
// the same theme, see
|
||||
// https://github.com/microsoft/monaco-editor/issues/338#issuecomment-274837186
|
||||
// )
|
||||
export type ReactMonacoEditorProps = Omit<EditorProps, 'theme'>;
|
||||
|
||||
export type CodeEditorChangeHandler = (value: string) => void;
|
||||
export type CodeEditorSuggestionProvider = () => CodeEditorSuggestionItem[];
|
||||
|
@ -51,23 +51,6 @@ function ensurePromQL(monaco: Monaco) {
|
||||
}
|
||||
}
|
||||
|
||||
const THEME_NAME = 'grafana-prometheus-query-field';
|
||||
|
||||
let MONACO_THEME_SETUP_STARTED = false;
|
||||
function ensureMonacoTheme(monaco: Monaco, theme: GrafanaTheme2) {
|
||||
if (MONACO_THEME_SETUP_STARTED === false) {
|
||||
MONACO_THEME_SETUP_STARTED = true;
|
||||
monaco.editor.defineTheme(THEME_NAME, {
|
||||
base: theme.isDark ? 'vs-dark' : 'vs',
|
||||
inherit: true,
|
||||
colors: {
|
||||
'editor.background': theme.components.input.background,
|
||||
},
|
||||
rules: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
container: css`
|
||||
@ -106,11 +89,9 @@ const MonacoQueryField = (props: Props) => {
|
||||
<ReactMonacoEditor
|
||||
options={options}
|
||||
language="promql"
|
||||
theme={THEME_NAME}
|
||||
value={initialValue}
|
||||
beforeMount={(monaco) => {
|
||||
ensurePromQL(monaco);
|
||||
ensureMonacoTheme(monaco, theme);
|
||||
}}
|
||||
onMount={(editor, monaco) => {
|
||||
// we setup on-blur
|
||||
|
Loading…
Reference in New Issue
Block a user