Skip to content

Commit

Permalink
[SharedUX] Modify code editor theme definition and resolution impleme…
Browse files Browse the repository at this point in the history
…ntation to account for color modes in EUI Theme (elastic#203337)

## Summary

<!-- ### DONT MERGE, THIS PR DEPENDS ON AN UPDATE TO EUI, THAT'S IN
FLIGHT -->

Closes elastic#202782

This PR reworks how custom themes used within the kibana code editor for
the default visual look and ones specific to supported languages are
defined to accomodate the upcoming visual refresh, the approach here
leverages the `euiTheme` object value returned from the `useEuiTheme`
hook, now a single theme declaration is all that is required such that
using either the `colorMode `value or the `euiTheme` from the provided
`UseEUITheme` value it's possible to craft a theme that's in the context
of kIbana, color mode aware and the editor would be able to resolve the
appropriate colors depending on the user's color mode.

This required some modification to monaco itself; now when defining
languages if the `CustomLanguageType` specification is being followed, a
function that resolves to a standard monaco theme can be provided on the
property `languageThemeResolver` which will be passed the `euiTheme`
when registering this theme. It's worth mentioning that this can also be
done manually by leveraging the custom method
`registerLanguageThemeResolver` added on the monaco editor object, like
so

```tsx
 monaco.editor.registerLanguageThemeResolver(LanguageID, languageThemeResolver);
``` 

However one should take note that when calling this method directly, the
ID passed must correlate to a registered language ID, else the theme
will not be available for use after Monaco is initialised, hence the
theme name must equal an existing language ID if it's to be used for a
specific language.


## How to test

- Enable borealis, like so;
	- in your `kibana.dev.yml` file include the following config;
		```yml
		uiSettings.experimental.themeSwitcherEnabled: true
		```
- start kibana using the following command;
`KBN_OPTIMIZER_THEMES="borealislight,borealisdark,v8light,v8dark" yarn
start --run-examples`
- Tryout all downstream of the code editor to ascertain the code editor
colors are as should be for both Amsterdam and Borealis; downstreams
include;
  - ES|QL editor, navigate to discover and click the "try ES|QL" button
- Dev tools, on clicking the nav hamburger menu under the management
menu group there's a menu item that links to all dev tools
- Index Management use cases; navigate to stack management, under Index
management select any existing index, then navigate to it's settings
this should load up the code editor.
- Saved Object use case; navigate to stack management, under saved
objects attempt inspecting any saved object we'd be presented with the
code editor etc.
  
<!--
### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...


-->

---------

Co-authored-by: ek-so <eksomail@gmail.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people authored and kowalczyk-krzysztof committed Jan 7, 2025
1 parent 44c130c commit 61bde76
Show file tree
Hide file tree
Showing 30 changed files with 340 additions and 244 deletions.
7 changes: 3 additions & 4 deletions packages/kbn-monaco/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export {
export type { ParsedRequest } from './src/console';

export {
CODE_EDITOR_LIGHT_THEME_ID,
CODE_EDITOR_DARK_THEME_ID,
CODE_EDITOR_LIGHT_THEME_TRANSPARENT_ID,
CODE_EDITOR_DARK_THEME_TRANSPARENT_ID,
defaultThemesResolvers,
CODE_EDITOR_DEFAULT_THEME_ID,
CODE_EDITOR_TRANSPARENT_THEME_ID,
} from './src/code_editor';
6 changes: 2 additions & 4 deletions packages/kbn-monaco/src/code_editor/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export const CODE_EDITOR_LIGHT_THEME_ID = 'codeEditorLightTheme';
export const CODE_EDITOR_DARK_THEME_ID = 'codeEditorDarkTheme';
export const CODE_EDITOR_LIGHT_THEME_TRANSPARENT_ID = 'codeEditorLightTransparentTheme';
export const CODE_EDITOR_DARK_THEME_TRANSPARENT_ID = 'codeEditorDarkTransparentTheme';
export const CODE_EDITOR_DEFAULT_THEME_ID = 'codeEditorDefaultTheme';
export const CODE_EDITOR_TRANSPARENT_THEME_ID = 'codeEditorTransparentTheme';
21 changes: 9 additions & 12 deletions packages/kbn-monaco/src/code_editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { CODE_EDITOR_DEFAULT_THEME_ID, CODE_EDITOR_TRANSPARENT_THEME_ID } from './constants';

export {
CODE_EDITOR_LIGHT_THEME_ID,
CODE_EDITOR_DARK_THEME_ID,
CODE_EDITOR_LIGHT_THEME_TRANSPARENT_ID,
CODE_EDITOR_DARK_THEME_TRANSPARENT_ID,
} from './constants';
import { buildTheme, buildTransparentTheme } from './theme';

export {
buildLightTheme,
buildDarkTheme,
buildLightTransparentTheme,
buildDarkTransparentTheme,
} from './theme';
// export these so that they are consumed by the actual code editor implementation
export const defaultThemesResolvers = {
[CODE_EDITOR_DEFAULT_THEME_ID]: buildTheme,
[CODE_EDITOR_TRANSPARENT_THEME_ID]: buildTransparentTheme,
};

export { CODE_EDITOR_DEFAULT_THEME_ID, CODE_EDITOR_TRANSPARENT_THEME_ID };
141 changes: 69 additions & 72 deletions packages/kbn-monaco/src/code_editor/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-theme';
import type { UseEuiTheme } from '@elastic/eui';
import { monaco } from '../..';

export function createTheme(
euiTheme: typeof darkTheme | typeof lightTheme,
selectionBackgroundColor: string,
{ euiTheme }: UseEuiTheme,
backgroundColor?: string
): monaco.editor.IStandaloneThemeData {
return {
Expand All @@ -21,92 +20,90 @@ export function createTheme(
rules: [
{
token: '',
foreground: euiTheme.euiColorDarkestShade,
background: euiTheme.euiFormBackgroundColor,
foreground: euiTheme.colors.textParagraph,
background: euiTheme.colors.backgroundBaseSubdued,
},
{ token: 'invalid', foreground: euiTheme.euiColorAccentText },
{ token: 'invalid', foreground: euiTheme.colors.textAccent },
{ token: 'emphasis', fontStyle: 'italic' },
{ token: 'strong', fontStyle: 'bold' },

{ token: 'variable', foreground: euiTheme.euiColorPrimaryText },
{ token: 'variable.predefined', foreground: euiTheme.euiColorSuccessText },
{ token: 'constant', foreground: euiTheme.euiColorAccentText },
{ token: 'comment', foreground: euiTheme.euiTextSubduedColor },
{ token: 'number', foreground: euiTheme.euiColorAccentText },
{ token: 'number.hex', foreground: euiTheme.euiColorAccentText },
{ token: 'regexp', foreground: euiTheme.euiColorDangerText },
{ token: 'annotation', foreground: euiTheme.euiTextSubduedColor },
{ token: 'type', foreground: euiTheme.euiColorSuccessText },
{ token: 'variable', foreground: euiTheme.colors.textPrimary },
{ token: 'variable.predefined', foreground: euiTheme.colors.textSuccess },
{ token: 'constant', foreground: euiTheme.colors.textAccent },
{ token: 'comment', foreground: euiTheme.colors.textSubdued },
{ token: 'number', foreground: euiTheme.colors.textAccent },
{ token: 'number.hex', foreground: euiTheme.colors.textAccent },
{ token: 'regexp', foreground: euiTheme.colors.textDanger },
{ token: 'annotation', foreground: euiTheme.colors.textSubdued },
{ token: 'type', foreground: euiTheme.colors.textSuccess },

{ token: 'delimiter', foreground: euiTheme.euiTextSubduedColor },
{ token: 'delimiter.html', foreground: euiTheme.euiColorDarkShade },
{ token: 'delimiter.xml', foreground: euiTheme.euiColorPrimaryText },
{ token: 'delimiter', foreground: euiTheme.colors.textSubdued },
{ token: 'delimiter.html', foreground: euiTheme.colors.textParagraph },
{ token: 'delimiter.xml', foreground: euiTheme.colors.textPrimary },

{ token: 'tag', foreground: euiTheme.euiColorDangerText },
{ token: 'tag.id.jade', foreground: euiTheme.euiColorPrimaryText },
{ token: 'tag.class.jade', foreground: euiTheme.euiColorPrimaryText },
{ token: 'meta.scss', foreground: euiTheme.euiColorAccentText },
{ token: 'metatag', foreground: euiTheme.euiColorSuccessText },
{ token: 'metatag.content.html', foreground: euiTheme.euiColorDangerText },
{ token: 'metatag.html', foreground: euiTheme.euiTextSubduedColor },
{ token: 'metatag.xml', foreground: euiTheme.euiTextSubduedColor },
{ token: 'tag', foreground: euiTheme.colors.textDanger },
{ token: 'tag.id.jade', foreground: euiTheme.colors.textPrimary },
{ token: 'tag.class.jade', foreground: euiTheme.colors.textPrimary },
{ token: 'meta.scss', foreground: euiTheme.colors.textAccent },
{ token: 'metatag', foreground: euiTheme.colors.textSuccess },
{ token: 'metatag.content.html', foreground: euiTheme.colors.textDanger },
{ token: 'metatag.html', foreground: euiTheme.colors.textDanger },
{ token: 'metatag.xml', foreground: euiTheme.colors.textSubdued },
{ token: 'metatag.php', fontStyle: 'bold' },

{ token: 'key', foreground: euiTheme.euiColorWarningText },
{ token: 'string.key.json', foreground: euiTheme.euiColorDangerText },
{ token: 'string.value.json', foreground: euiTheme.euiColorPrimaryText },
{ token: 'key', foreground: euiTheme.colors.textWarning },
{ token: 'string.key.json', foreground: euiTheme.colors.textDanger },
{ token: 'string.value.json', foreground: euiTheme.colors.textPrimary },

{ token: 'attribute.name', foreground: euiTheme.euiColorDangerText },
{ token: 'attribute.name.css', foreground: euiTheme.euiColorSuccessText },
{ token: 'attribute.value', foreground: euiTheme.euiColorPrimaryText },
{ token: 'attribute.value.number', foreground: euiTheme.euiColorWarningText },
{ token: 'attribute.value.unit', foreground: euiTheme.euiColorWarningText },
{ token: 'attribute.value.html', foreground: euiTheme.euiColorPrimaryText },
{ token: 'attribute.value.xml', foreground: euiTheme.euiColorPrimaryText },
{ token: 'attribute.name', foreground: euiTheme.colors.textDanger },
{ token: 'attribute.name.css', foreground: euiTheme.colors.textSuccess },
{ token: 'attribute.value', foreground: euiTheme.colors.textPrimary },
{ token: 'attribute.value.number', foreground: euiTheme.colors.textWarning },
{ token: 'attribute.value.unit', foreground: euiTheme.colors.textWarning },
{ token: 'attribute.value.html', foreground: euiTheme.colors.textPrimary },
{ token: 'attribute.value.xml', foreground: euiTheme.colors.textPrimary },

{ token: 'string', foreground: euiTheme.euiColorDangerText },
{ token: 'string.html', foreground: euiTheme.euiColorPrimaryText },
{ token: 'string.sql', foreground: euiTheme.euiColorDangerText },
{ token: 'string.yaml', foreground: euiTheme.euiColorPrimaryText },
{ token: 'string', foreground: euiTheme.colors.textDanger },
{ token: 'string.html', foreground: euiTheme.colors.textPrimary },
{ token: 'string.sql', foreground: euiTheme.colors.textDanger },
{ token: 'string.yaml', foreground: euiTheme.colors.textPrimary },

{ token: 'keyword', foreground: euiTheme.euiColorPrimaryText },
{ token: 'keyword.json', foreground: euiTheme.euiColorPrimaryText },
{ token: 'keyword.flow', foreground: euiTheme.euiColorWarningText },
{ token: 'keyword.flow.scss', foreground: euiTheme.euiColorPrimaryText },
{ token: 'keyword', foreground: euiTheme.colors.textPrimary },
{ token: 'keyword.json', foreground: euiTheme.colors.textPrimary },
{ token: 'keyword.flow', foreground: euiTheme.colors.textWarning },
{ token: 'keyword.flow.scss', foreground: euiTheme.colors.textPrimary },
// Monaco editor supports strikethrough font style only starting from 0.32.0.
{ token: 'keyword.deprecated', foreground: euiTheme.euiColorAccentText },
{ token: 'keyword.deprecated', foreground: euiTheme.colors.textAccent },

{ token: 'operator.scss', foreground: euiTheme.euiColorDarkShade },
{ token: 'operator.sql', foreground: euiTheme.euiTextSubduedColor },
{ token: 'operator.swift', foreground: euiTheme.euiTextSubduedColor },
{ token: 'predefined.sql', foreground: euiTheme.euiTextSubduedColor },
{ token: 'operator.scss', foreground: euiTheme.colors.textParagraph },
{ token: 'operator.sql', foreground: euiTheme.colors.textSubdued },
{ token: 'operator.swift', foreground: euiTheme.colors.textSubdued },
{ token: 'predefined.sql', foreground: euiTheme.colors.textSubdued },

{ token: 'text', foreground: euiTheme.euiTitleColor },
{ token: 'label', foreground: euiTheme.euiColorVis9 },
{ token: 'text', foreground: euiTheme.colors.textHeading },
{ token: 'label', foreground: euiTheme.colors.vis.euiColorVis9 },
],
colors: {
'editor.foreground': euiTheme.euiColorDarkestShade,
'editor.background': backgroundColor ?? euiTheme.euiFormBackgroundColor,
'editorLineNumber.foreground': euiTheme.euiColorDarkShade,
'editorLineNumber.activeForeground': euiTheme.euiColorDarkShade,
'editorIndentGuide.background1': euiTheme.euiColorLightShade,
'editor.selectionBackground': selectionBackgroundColor,
'editorWidget.border': euiTheme.euiColorLightShade,
'editorWidget.background': euiTheme.euiColorLightestShade,
'editorCursor.foreground': euiTheme.euiColorDarkestShade,
'editorSuggestWidget.selectedForeground': euiTheme.euiColorDarkestShade,
'editorSuggestWidget.focusHighlightForeground': euiTheme.euiColorPrimary,
'editorSuggestWidget.selectedBackground': euiTheme.euiColorLightShade,
'list.hoverBackground': euiTheme.euiColorLightShade,
'list.highlightForeground': euiTheme.euiColorPrimary,
'editor.lineHighlightBorder': euiTheme.euiColorLightestShade,
'editorHoverWidget.foreground': euiTheme.euiColorDarkestShade,
'editorHoverWidget.background': euiTheme.euiFormBackgroundColor,
'editor.foreground': euiTheme.colors.textParagraph,
'editor.background': backgroundColor ?? euiTheme.colors.backgroundBasePlain,
'editorLineNumber.foreground': euiTheme.colors.textSubdued,
'editorLineNumber.activeForeground': euiTheme.colors.textSubdued,
'editorIndentGuide.background1': euiTheme.colors.lightShade,
'editor.selectionBackground': euiTheme.colors.backgroundBaseInteractiveSelect,
'editorWidget.border': euiTheme.colors.borderBasePlain,
'editorWidget.background': euiTheme.colors.backgroundBaseSubdued,
'editorCursor.foreground': euiTheme.colors.darkestShade,
'editorSuggestWidget.selectedForeground': euiTheme.colors.darkestShade,
'editorSuggestWidget.focusHighlightForeground': euiTheme.colors.primary,
'editorSuggestWidget.selectedBackground': euiTheme.colors.lightShade,
'list.hoverBackground': euiTheme.colors.backgroundBaseSubdued,
'list.highlightForeground': euiTheme.colors.primary,
'editor.lineHighlightBorder': euiTheme.colors.lightestShade,
'editorHoverWidget.foreground': euiTheme.colors.darkestShade,
'editorHoverWidget.background': euiTheme.colors.backgroundBaseSubdued,
},
};
}

export const buildDarkTheme = () => createTheme(darkTheme, '#343551');
export const buildLightTheme = () => createTheme(lightTheme, '#E3E4ED');
export const buildDarkTransparentTheme = () => createTheme(darkTheme, '#343551', '#00000000');
export const buildLightTransparentTheme = () => createTheme(lightTheme, '#E3E4ED', '#00000000');
export const buildTheme = createTheme;
export const buildTransparentTheme = (euiTheme: UseEuiTheme) => createTheme(euiTheme, '#00000000');
1 change: 0 additions & 1 deletion packages/kbn-monaco/src/console/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@
*/

export const CONSOLE_LANG_ID = 'console';
export const CONSOLE_THEME_ID = 'consoleTheme';
export const CONSOLE_OUTPUT_LANG_ID = 'consoleOutput';
export const CONSOLE_POSTFIX = '.console';
8 changes: 5 additions & 3 deletions packages/kbn-monaco/src/console/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import {
} from './lexer_rules';
import { foldingRangeProvider } from './folding_range_provider';

export { CONSOLE_LANG_ID, CONSOLE_OUTPUT_LANG_ID, CONSOLE_THEME_ID } from './constants';

export { buildConsoleTheme } from './theme';
export { CONSOLE_LANG_ID, CONSOLE_OUTPUT_LANG_ID } from './constants';
/**
* export the theme id for the console language
*/
export { CONSOLE_THEME_ID } from './language';

export const ConsoleLang: LangModuleType = {
ID: CONSOLE_LANG_ID,
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-monaco/src/console/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ import { ConsoleWorkerProxyService } from './console_worker_proxy';
import { monaco } from '../monaco_imports';
import { CONSOLE_LANG_ID } from './constants';
import { ConsoleParsedRequestsProvider } from './console_parsed_requests_provider';
import { buildConsoleTheme } from './theme';

const workerProxyService = new ConsoleWorkerProxyService();

export const getParsedRequestsProvider = (model: monaco.editor.ITextModel | null) => {
return new ConsoleParsedRequestsProvider(workerProxyService, model);
};

// Theme id is the same as lang id, as we register only one theme resolver that's color mode aware
export const CONSOLE_THEME_ID = CONSOLE_LANG_ID;
monaco.editor.registerLanguageThemeResolver(CONSOLE_THEME_ID, buildConsoleTheme);

monaco.languages.onLanguage(CONSOLE_LANG_ID, async () => {
workerProxyService.setup();
setupConsoleErrorsProvider(workerProxyService);
Expand Down
Loading

0 comments on commit 61bde76

Please sign in to comment.