diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx index 14026b20177..bae31a405a0 100644 --- a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx @@ -13,7 +13,7 @@ import { import { Popover, PopoverProps } from '@patternfly/react-core/dist/esm/components/Popover'; import { TooltipPosition } from '@patternfly/react-core/dist/esm/components/Tooltip'; import { getResizeObserver } from '@patternfly/react-core/dist/esm/helpers/resizeObserver'; -import Editor, { EditorProps, Monaco } from '@monaco-editor/react'; +import Editor, { BeforeMount, EditorProps, Monaco } from '@monaco-editor/react'; import type { editor } from 'monaco-editor'; import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon'; import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; @@ -23,6 +23,7 @@ import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; import Dropzone, { FileRejection } from 'react-dropzone'; import { CodeEditorContext } from './CodeEditorUtils'; import { CodeEditorControl } from './CodeEditorControl'; +import { defineThemes } from './CodeEditorTheme'; export type ChangeHandler = (value: string, event: editor.IModelContentChangedEvent) => void; export type EditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void; @@ -366,6 +367,11 @@ export const CodeEditor = ({ }; }, []); + const editorBeforeMount: BeforeMount = (monaco) => { + defineThemes(monaco.editor); + editorProps?.beforeMount?.(monaco); + }; + const editorDidMount: EditorDidMount = (editor, monaco) => { // eslint-disable-next-line no-bitwise editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Tab, () => wrapperRef.current.focus()); @@ -428,6 +434,7 @@ export const CodeEditor = ({ }; const editorOptions: editor.IStandaloneEditorConstructionOptions = { + fontFamily: 'var(--pf-t--global--font--family--mono)', scrollBeyondLastLine: height !== 'sizeToFit', readOnly: isReadOnly, cursorStyle: 'line', @@ -571,8 +578,9 @@ export const CodeEditor = ({ onChange={onModelChange} onMount={editorDidMount} loading={loading} - theme={isDarkTheme ? 'vs-dark' : 'vs-light'} + theme={isDarkTheme ? 'pf-v6-theme-dark' : 'pf-v6-theme-light'} {...editorProps} + beforeMount={editorBeforeMount} /> ); diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts b/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts new file mode 100644 index 00000000000..d6223dd3da5 --- /dev/null +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts @@ -0,0 +1,55 @@ +import green70 from '@patternfly/react-tokens/dist/esm/t_color_green_70'; +import yellow70 from '@patternfly/react-tokens/dist/esm/t_color_yellow_70'; +import blue70 from '@patternfly/react-tokens/dist/esm/t_color_blue_70'; +import purple70 from '@patternfly/react-tokens/dist/esm/t_color_purple_70'; +import green30 from '@patternfly/react-tokens/dist/esm/t_color_green_30'; +import blue30 from '@patternfly/react-tokens/dist/esm/t_color_blue_30'; +import yellow30 from '@patternfly/react-tokens/dist/esm/t_color_yellow_30'; +import purple30 from '@patternfly/react-tokens/dist/esm/t_color_purple_30'; +import white from '@patternfly/react-tokens/dist/esm/t_color_white'; +import gray20 from '@patternfly/react-tokens/dist/esm/t_color_gray_20'; +import gray60 from '@patternfly/react-tokens/dist/esm/t_color_gray_60'; +import gray90 from '@patternfly/react-tokens/dist/esm/t_color_gray_90'; +import black from '@patternfly/react-tokens/dist/esm/t_color_black'; +import type { editor as monacoEditor } from 'monaco-editor/esm/vs/editor/editor.api'; + +/** + * Define the themes `pf-v6-theme-light` and + * `pf-v6-theme-dark` for an instance of Monaco editor. + * + * Note that base tokens must be used as Monaco will throw a runtime + * error for CSS variables. + */ +export const defineThemes = (editor: typeof monacoEditor) => { + editor.defineTheme('pf-v6-theme-light', { + base: 'vs', + inherit: true, + colors: { + 'editor.background': white.value, + 'editorLineNumber.activeForeground': black.value, + 'editorLineNumber.foreground': gray60.value + }, + rules: [ + { token: 'number', foreground: green70.value }, + { token: 'type', foreground: yellow70.value }, + { token: 'string', foreground: blue70.value }, + { token: 'keyword', foreground: purple70.value } + ] + }); + + editor.defineTheme('pf-v6-theme-dark', { + base: 'vs-dark', + inherit: true, + colors: { + 'editor.background': gray90.value, + 'editorLineNumber.activeForeground': white.value, + 'editorLineNumber.foreground': gray20.value + }, + rules: [ + { token: 'number', foreground: green30.value }, + { token: 'type', foreground: blue30.value }, + { token: 'string', foreground: yellow30.value }, + { token: 'keyword', foreground: purple30.value } + ] + }); +};