Clean up MCP Monaco editor (#21643)
Rebuild the MCP setup block on the shared Monaco editor with theme-driven colors, padding, and auto-height; add the settings description line-height token; revert the clipboard util to the shared navigator.clipboard implementation; and consolidate the code editor's auto-height to a single disposed, reactive effect.
This commit is contained in:
committed by
GitHub
parent
ce92a1f1e1
commit
a67fdf2dac
@@ -4,14 +4,27 @@ import { BASE_CODE_EDITOR_THEME_ID } from '@ui/input/code-editor/constants/BaseC
|
||||
import { getBaseCodeEditorTheme } from '@ui/input/code-editor/theme/utils/getBaseCodeEditorTheme';
|
||||
import { ResizeHandle } from '@ui/layout/resize-handle/components/ResizeHandle';
|
||||
import { useResizeHandle } from '@ui/layout/resize-handle/hooks/useResizeHandle';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { ThemeContext, type ThemeType } from '@ui/theme-constants';
|
||||
import { type editor } from 'monaco-editor';
|
||||
import { type KeyboardEvent, useContext, useState } from 'react';
|
||||
import { type KeyboardEvent, useContext, useEffect, useState } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import styles from './CodeEditor.module.scss';
|
||||
|
||||
type CodeEditorVariant = 'default' | 'with-header' | 'borderless';
|
||||
type CodeEditorContentPadding = 'default' | 'comfortable';
|
||||
|
||||
const setCodeEditorTheme = (
|
||||
monaco: Monaco,
|
||||
theme: ThemeType,
|
||||
colorScheme: 'light' | 'dark',
|
||||
) => {
|
||||
monaco.editor.defineTheme(
|
||||
BASE_CODE_EDITOR_THEME_ID,
|
||||
getBaseCodeEditorTheme(theme, colorScheme),
|
||||
);
|
||||
monaco.editor.setTheme(BASE_CODE_EDITOR_THEME_ID);
|
||||
};
|
||||
|
||||
type CodeEditorProps = Pick<
|
||||
EditorProps,
|
||||
@@ -23,6 +36,8 @@ type CodeEditorProps = Pick<
|
||||
isLoading?: boolean;
|
||||
transparentBackground?: boolean;
|
||||
resizable?: boolean;
|
||||
contentPadding?: CodeEditorContentPadding;
|
||||
autoHeight?: boolean;
|
||||
};
|
||||
|
||||
export const CodeEditor = ({
|
||||
@@ -38,13 +53,18 @@ export const CodeEditor = ({
|
||||
isLoading = false,
|
||||
options,
|
||||
resizable = false,
|
||||
contentPadding = 'default',
|
||||
autoHeight = false,
|
||||
}: CodeEditorProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const { theme, colorScheme } = useContext(ThemeContext);
|
||||
const [monaco, setMonaco] = useState<Monaco | undefined>(undefined);
|
||||
const [editor, setEditor] = useState<
|
||||
editor.IStandaloneCodeEditor | undefined
|
||||
>(undefined);
|
||||
const [isEditorFocused, setIsEditorFocused] = useState(false);
|
||||
const [autoHeightContentHeight, setAutoHeightContentHeight] = useState<
|
||||
number | undefined
|
||||
>(undefined);
|
||||
|
||||
const numericHeight = typeof height === 'number' ? height : 450;
|
||||
const {
|
||||
@@ -56,7 +76,28 @@ export const CodeEditor = ({
|
||||
initialSize: numericHeight,
|
||||
});
|
||||
|
||||
const currentHeight = resizable ? resizableHeight : height;
|
||||
const shouldAutoHeight = autoHeight && !resizable;
|
||||
const codeEditorPadding =
|
||||
typeof theme.spacingMultiplicator === 'number'
|
||||
? theme.spacingMultiplicator * 4
|
||||
: undefined;
|
||||
const currentHeight = shouldAutoHeight
|
||||
? (autoHeightContentHeight ?? height)
|
||||
: resizable
|
||||
? resizableHeight
|
||||
: height;
|
||||
const contentPaddingOptions = {
|
||||
...(contentPadding === 'comfortable'
|
||||
? {
|
||||
lineDecorationsWidth: codeEditorPadding,
|
||||
}
|
||||
: {}),
|
||||
padding: {
|
||||
bottom: codeEditorPadding,
|
||||
top: codeEditorPadding,
|
||||
},
|
||||
};
|
||||
const { padding: _callerPadding, ...editorOptions } = options ?? {};
|
||||
|
||||
const setModelMarkers = (
|
||||
editor: editor.IStandaloneCodeEditor | undefined,
|
||||
@@ -78,6 +119,43 @@ export const CodeEditor = ({
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDefined(monaco)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCodeEditorTheme(monaco, theme, colorScheme);
|
||||
}, [colorScheme, monaco, theme]);
|
||||
|
||||
// Drive the container height from Monaco's content height; the editor's
|
||||
// default automaticLayout then re-fits the canvas (no manual layout needed).
|
||||
useEffect(() => {
|
||||
if (!shouldAutoHeight || !isDefined(editor)) {
|
||||
setAutoHeightContentHeight(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const updateAutoHeight = () => {
|
||||
const nextHeight = editor.getContentHeight();
|
||||
|
||||
if (!Number.isFinite(nextHeight) || nextHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setAutoHeightContentHeight((currentHeight) =>
|
||||
currentHeight === nextHeight ? currentHeight : nextHeight,
|
||||
);
|
||||
};
|
||||
|
||||
updateAutoHeight();
|
||||
|
||||
const disposable = editor.onDidContentSizeChange(updateAutoHeight);
|
||||
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [editor, shouldAutoHeight]);
|
||||
|
||||
return isLoading ? (
|
||||
<div
|
||||
className={styles.editorLoader}
|
||||
@@ -115,11 +193,7 @@ export const CodeEditor = ({
|
||||
setMonaco(monaco);
|
||||
setEditor(editor);
|
||||
|
||||
monaco.editor.defineTheme(
|
||||
BASE_CODE_EDITOR_THEME_ID,
|
||||
getBaseCodeEditorTheme(theme),
|
||||
);
|
||||
monaco.editor.setTheme(BASE_CODE_EDITOR_THEME_ID);
|
||||
setCodeEditorTheme(monaco, theme, colorScheme);
|
||||
|
||||
editor.onDidFocusEditorWidget(() => {
|
||||
setIsEditorFocused(true);
|
||||
@@ -143,6 +217,10 @@ export const CodeEditor = ({
|
||||
options={{
|
||||
formatOnPaste: true,
|
||||
formatOnType: true,
|
||||
fontFamily: theme.code.font.family,
|
||||
bracketPairColorization: {
|
||||
enabled: false,
|
||||
},
|
||||
overviewRulerLanes: 0,
|
||||
scrollBeyondLastLine: false,
|
||||
scrollbar: {
|
||||
@@ -152,7 +230,8 @@ export const CodeEditor = ({
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
...options,
|
||||
...editorOptions,
|
||||
...contentPaddingOptions,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,10 @@ import { type editor } from 'monaco-editor';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
const convertColorToHex = (color: string): string => {
|
||||
if (color.trim() === 'transparent') {
|
||||
return '#00000000';
|
||||
}
|
||||
|
||||
const displayP3Match = color.match(
|
||||
/color\(display-p3\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s+\/\s+([\d.]+))?\)/,
|
||||
);
|
||||
@@ -33,35 +37,81 @@ const convertColorToHex = (color: string): string => {
|
||||
|
||||
export const getBaseCodeEditorTheme = (
|
||||
theme: ThemeType,
|
||||
colorScheme: 'light' | 'dark',
|
||||
): editor.IStandaloneThemeData => {
|
||||
return {
|
||||
base: 'vs',
|
||||
base: colorScheme === 'dark' ? 'vs-dark' : 'vs',
|
||||
inherit: true,
|
||||
rules: [
|
||||
{
|
||||
token: '',
|
||||
foreground: convertColorToHex(theme.code.text.gray),
|
||||
fontStyle: 'bold',
|
||||
foreground: convertColorToHex(theme.font.color.secondary),
|
||||
},
|
||||
{
|
||||
token: 'keyword',
|
||||
foreground: convertColorToHex(theme.code.text.sky),
|
||||
foreground: convertColorToHex(theme.color.pink11),
|
||||
},
|
||||
{
|
||||
token: 'delimiter',
|
||||
foreground: convertColorToHex(theme.code.text.gray),
|
||||
token: 'keyword.control',
|
||||
foreground: convertColorToHex(theme.color.pink11),
|
||||
},
|
||||
{
|
||||
token: 'keyword.json',
|
||||
foreground: convertColorToHex(theme.color.orange11),
|
||||
},
|
||||
{
|
||||
token: 'number',
|
||||
foreground: convertColorToHex(theme.color.orange11),
|
||||
},
|
||||
{
|
||||
token: 'number.json',
|
||||
foreground: convertColorToHex(theme.color.orange11),
|
||||
},
|
||||
{
|
||||
token: 'regexp',
|
||||
foreground: convertColorToHex(theme.color.orange11),
|
||||
},
|
||||
{
|
||||
token: 'type',
|
||||
foreground: convertColorToHex(theme.color.green11),
|
||||
},
|
||||
{
|
||||
token: 'attribute.name',
|
||||
foreground: convertColorToHex(theme.color.blue11),
|
||||
},
|
||||
{
|
||||
token: 'tag',
|
||||
foreground: convertColorToHex(theme.color.pink11),
|
||||
},
|
||||
{
|
||||
token: 'string',
|
||||
foreground: convertColorToHex(theme.code.text.pink),
|
||||
foreground: convertColorToHex(theme.color.green11),
|
||||
},
|
||||
{
|
||||
token: 'string.key.json',
|
||||
foreground: convertColorToHex(theme.color.blue11),
|
||||
},
|
||||
{
|
||||
token: 'delimiter',
|
||||
foreground: convertColorToHex(theme.font.color.light),
|
||||
},
|
||||
{
|
||||
token: 'delimiter.bracket.json',
|
||||
foreground: convertColorToHex(theme.font.color.light),
|
||||
},
|
||||
{
|
||||
token: 'string.value.json',
|
||||
foreground: convertColorToHex(theme.color.green11),
|
||||
},
|
||||
{
|
||||
token: 'comment',
|
||||
foreground: convertColorToHex(theme.code.text.orange),
|
||||
foreground: convertColorToHex(theme.font.color.light),
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
'editor.background': '#00000000',
|
||||
'editor.background': convertColorToHex('transparent'),
|
||||
'editor.foreground': convertColorToHex(theme.font.color.secondary),
|
||||
'editorCursor.foreground': convertColorToHex(theme.font.color.primary),
|
||||
'editorLineNumber.foreground': convertColorToHex(
|
||||
theme.font.color.extraLight,
|
||||
@@ -72,6 +122,22 @@ export const getBaseCodeEditorTheme = (
|
||||
'editor.lineHighlightBackground': convertColorToHex(
|
||||
theme.background.tertiary,
|
||||
),
|
||||
'editor.selectionBackground': convertColorToHex(
|
||||
theme.background.transparent.blue,
|
||||
),
|
||||
'editor.inactiveSelectionBackground': convertColorToHex(
|
||||
theme.background.transparent.light,
|
||||
),
|
||||
'editorIndentGuide.background1': convertColorToHex(
|
||||
theme.border.color.light,
|
||||
),
|
||||
'editorIndentGuide.activeBackground1': convertColorToHex(
|
||||
theme.border.color.medium,
|
||||
),
|
||||
'editorBracketMatch.background': convertColorToHex(
|
||||
theme.background.transparent.light,
|
||||
),
|
||||
'editorBracketMatch.border': convertColorToHex(theme.border.color.medium),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user