🐛 fix(query-editor): 修复大字号表候选下划线裁剪

This commit is contained in:
kunghim
2026-08-03 15:34:07 +08:00
parent d06d9a0f7f
commit 630ba7fc3f
5 changed files with 122 additions and 32 deletions

View File

@@ -296,27 +296,27 @@ body[data-theme='light'] ::-webkit-scrollbar-thumb:hover {
/* 表候选使用 Monaco 原生 CompletionItemLabel第一行表名第二行注释。 */
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) {
height: 36px !important;
min-height: 36px !important;
max-height: 36px !important;
height: var(--gn-query-suggest-row-height, 36px) !important;
min-height: var(--gn-query-suggest-row-height, 36px) !important;
max-height: var(--gn-query-suggest-row-height, 36px) !important;
}
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents {
height: 36px !important;
height: var(--gn-query-suggest-row-height, 36px) !important;
overflow: visible !important;
}
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main {
display: grid !important;
grid-template-columns: 18px minmax(0, 1fr);
grid-template-rows: 18px 18px;
grid-template-rows: var(--gn-query-suggest-name-row-height, 18px) var(--gn-query-suggest-comment-row-height, 18px);
grid-template-areas:
"icon name"
"comment comment";
align-content: center;
gap: 0 !important;
height: 36px;
line-height: 18px !important;
height: var(--gn-query-suggest-row-height, 36px);
line-height: var(--gn-query-suggest-name-row-height, 18px) !important;
overflow: visible;
white-space: normal;
}
@@ -333,19 +333,21 @@ body[data-theme='light'] ::-webkit-scrollbar-thumb:hover {
display: flex;
align-items: center;
width: 100%;
height: 18px;
height: var(--gn-query-suggest-name-row-height, 18px);
min-width: 0;
max-width: none;
overflow: visible;
line-height: 18px !important;
line-height: var(--gn-query-suggest-name-row-height, 18px) !important;
}
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label {
min-width: 0;
max-width: 100%;
height: var(--gn-query-suggest-name-row-height, 18px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: var(--gn-query-suggest-name-row-height, 18px);
}
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .right {
@@ -358,7 +360,7 @@ body[data-theme='light'] ::-webkit-scrollbar-thumb:hover {
min-width: 0;
max-width: none;
overflow: visible;
line-height: 18px !important;
line-height: var(--gn-query-suggest-comment-row-height, 18px) !important;
}
.gn-query-monaco-stage .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .right > .details-label {
@@ -371,7 +373,7 @@ body[data-theme='light'] ::-webkit-scrollbar-thumb:hover {
overflow: visible;
color: var(--vscode-editorSuggestWidget-foreground);
font-size: 11px !important;
line-height: 18px !important;
line-height: var(--gn-query-suggest-comment-row-height, 18px) !important;
opacity: 0.68;
text-align: right;
white-space: nowrap;

View File

@@ -3,7 +3,10 @@ import Editor, { loader, type BeforeMount, type EditorProps, type OnMount } from
import { useStore } from '../store';
import { sanitizeDataTableFontSize } from '../utils/dataGridDisplay';
import { DEFAULT_MONO_FONT_FAMILY } from '../utils/fontFamilies';
import { resolveSqlEditorFontSize } from '../utils/sqlEditorTypography';
import {
resolveSqlEditorFontSize,
resolveSqlEditorSuggestionLayout,
} from '../utils/sqlEditorTypography';
export type { BeforeMount, OnMount } from '@monaco-editor/react';
export type GonaviMonacoTypography = 'code' | 'data' | 'sql';
@@ -842,26 +845,6 @@ const MonacoEditor: React.FC<MonacoEditorProps> = ({
onMount?.(editor, monaco);
}, [onMount]);
// Unified surface: all call sites inherit panel via --gn-monaco-bg (no per-page bg).
const surfaceStyle: React.CSSProperties = {
height: props.height || '100%',
width: props.width || '100%',
minHeight: 0,
minWidth: 0,
background: `var(${GONAVI_MONACO_BG_CSS_VAR}, var(--gn-bg-panel, transparent))`,
};
const loadingFallback = (
<div
className={GONAVI_MONACO_SURFACE_CLASS}
data-monaco-editor-loading="true"
aria-busy="true"
style={surfaceStyle}
>
{loading || null}
</div>
);
const resolvedOptions = useMemo(() => {
if (uiVersion !== 'v2') {
return {
@@ -891,6 +874,9 @@ const MonacoEditor: React.FC<MonacoEditorProps> = ({
10,
Math.round(Number(options?.fontSize) || resolvedFontSize),
);
const suggestionLayout = gonaviTypography === 'sql'
? resolveSqlEditorSuggestionLayout(effectiveEditorFontSize)
: null;
return {
...options,
@@ -898,6 +884,7 @@ const MonacoEditor: React.FC<MonacoEditorProps> = ({
fontFamily: options?.fontFamily ?? monoFontFamily ?? DEFAULT_MONO_FONT_FAMILY,
fontSize: options?.fontSize ?? resolvedFontSize,
lineHeight: options?.lineHeight ?? Math.max(18, Math.round(effectiveEditorFontSize * 1.62)),
...(suggestionLayout ? { suggestLineHeight: suggestionLayout.rowHeight } : {}),
};
}, [
dataTableFontSize,
@@ -911,6 +898,37 @@ const MonacoEditor: React.FC<MonacoEditorProps> = ({
uiVersion,
]);
const suggestionLayout = uiVersion === 'v2' && gonaviTypography === 'sql'
? resolveSqlEditorSuggestionLayout(resolvedOptions.fontSize)
: null;
// Unified surface: all call sites inherit panel via --gn-monaco-bg (no per-page bg).
const surfaceStyle = {
height: props.height || '100%',
width: props.width || '100%',
minHeight: 0,
minWidth: 0,
background: `var(${GONAVI_MONACO_BG_CSS_VAR}, var(--gn-bg-panel, transparent))`,
...(suggestionLayout
? {
'--gn-query-suggest-name-row-height': `${suggestionLayout.nameLineHeight}px`,
'--gn-query-suggest-comment-row-height': `${suggestionLayout.commentLineHeight}px`,
'--gn-query-suggest-row-height': `${suggestionLayout.rowHeight}px`,
}
: {}),
} as React.CSSProperties;
const loadingFallback = (
<div
className={GONAVI_MONACO_SURFACE_CLASS}
data-monaco-editor-loading="true"
aria-busy="true"
style={surfaceStyle}
>
{loading || null}
</div>
);
if (!ready) {
return loadingFallback;
}

View File

@@ -110,6 +110,29 @@ describe('MonacoEditor typography', () => {
expect(dataMarkup).toContain('&quot;lineHeight&quot;:18');
});
it('sizes structured SQL completion rows from the final editor font size', () => {
storeState.appearance.sqlEditorFontSizeFollowGlobal = false;
storeState.appearance.sqlEditorFontSize = 18;
const largeMarkup = renderToStaticMarkup(
<MonacoEditor gonaviTypography="sql" options={{ minimap: { enabled: false } }} />,
);
expect(largeMarkup).toContain('&quot;suggestLineHeight&quot;:43');
expect(largeMarkup).toContain('--gn-query-suggest-name-row-height:25px');
expect(largeMarkup).toContain('--gn-query-suggest-row-height:43px');
});
it('sizes structured SQL completion rows from an explicit editor font size', () => {
const explicitMarkup = renderToStaticMarkup(
<MonacoEditor gonaviTypography="sql" options={{ fontSize: 20 }} />,
);
expect(explicitMarkup).toContain('&quot;suggestLineHeight&quot;:46');
expect(explicitMarkup).toContain('--gn-query-suggest-name-row-height:28px');
expect(explicitMarkup).toContain('--gn-query-suggest-row-height:46px');
});
it('keeps legacy editors on their explicit font settings', () => {
storeState.appearance.uiVersion = 'legacy';

View File

@@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest';
import {
migrateLegacySqlEditorTypographySettings,
resolveSqlEditorFontSize,
resolveSqlEditorSuggestionLayout,
sanitizeSqlEditorTypographySettings,
} from './sqlEditorTypography';
@@ -39,4 +40,22 @@ describe('SQL editor typography', () => {
sqlEditorFontSizeFollowGlobal: false,
});
});
it('keeps default completion rows unchanged and grows the table-name row for large fonts', () => {
expect(resolveSqlEditorSuggestionLayout(13)).toEqual({
nameLineHeight: 18,
commentLineHeight: 18,
rowHeight: 36,
});
expect(resolveSqlEditorSuggestionLayout(18)).toEqual({
nameLineHeight: 25,
commentLineHeight: 18,
rowHeight: 43,
});
expect(resolveSqlEditorSuggestionLayout(20)).toEqual({
nameLineHeight: 28,
commentLineHeight: 18,
rowHeight: 46,
});
});
});

View File

@@ -6,6 +6,14 @@ export interface SqlEditorTypographySettings {
export const MIN_SQL_EDITOR_FONT_SIZE = 10;
export const MAX_SQL_EDITOR_FONT_SIZE = 20;
export const DEFAULT_SQL_EDITOR_FONT_SCALE = 0.92;
export const SQL_EDITOR_SUGGESTION_COMMENT_LINE_HEIGHT = 18;
export const SQL_EDITOR_SUGGESTION_NAME_LINE_HEIGHT_SCALE = 1.4;
export interface SqlEditorSuggestionLayout {
nameLineHeight: number;
commentLineHeight: number;
rowHeight: number;
}
export const DEFAULT_SQL_EDITOR_TYPOGRAPHY_SETTINGS: SqlEditorTypographySettings = {
sqlEditorFontSize: null,
@@ -45,6 +53,26 @@ export const resolveSqlEditorFontSize = ({
return sanitizeSqlEditorFontSize(sqlEditorFontSize) ?? globalDerivedFontSize;
};
/**
* Keep the structured table completion label tall enough for the editor font's
* descenders while preserving the existing 18px + 18px layout at default sizes.
*/
export const resolveSqlEditorSuggestionLayout = (fontSize: unknown): SqlEditorSuggestionLayout => {
const normalizedFontSize = Number.isFinite(Number(fontSize))
? Math.max(MIN_SQL_EDITOR_FONT_SIZE, Math.round(Number(fontSize)))
: 14;
const nameLineHeight = Math.max(
SQL_EDITOR_SUGGESTION_COMMENT_LINE_HEIGHT,
Math.round(normalizedFontSize * SQL_EDITOR_SUGGESTION_NAME_LINE_HEIGHT_SCALE),
);
const commentLineHeight = SQL_EDITOR_SUGGESTION_COMMENT_LINE_HEIGHT;
return {
nameLineHeight,
commentLineHeight,
rowHeight: nameLineHeight + commentLineHeight,
};
};
export const sanitizeSqlEditorTypographySettings = (
value: Partial<SqlEditorTypographySettings> | undefined,
): SqlEditorTypographySettings => {