fix(editor): constrain table structure hover size

* fix(editor): constrain table structure hover size

* fix(editor): improve DDL hover scrolling

* fix(editor): use CodeMirror tooltip lifecycle for hover layout

---------

Co-authored-by: zipg <4047349+zipg@users.noreply.github.com>
Co-authored-by: t8y2 <1156263951@qq.com>
This commit is contained in:
authored and GitHub committed 2026-08-11 00:53:42 +08:00
1 parent 823c260316
commit 7b3f4875e3
3 files changed
+293 -9

No files matched your search

@@ -80,6 +80,7 @@ import {
type SqlObjectNavigationTarget,
} from "@/lib/sql/sqlNavigation";
import { buildHoverTableSql, ddlForHoverPreview, hoverTableMatchesScope, quoteQualifiedName, reformatHoverDdl, scopeHoverTables, type HoverTableScope } from "@/lib/editor/hoverTableSql";
import { constrainSqlHoverLayout } from "@/lib/editor/sqlHoverLayout";
import { lineColumnToOffset, sqlErrorDecorationRange as resolveSqlErrorDecorationRange } from "@/lib/sql/sqlDiagnostics";
import {
DBX_TABLE_REFERENCE_MIME,
@@ -2314,7 +2315,7 @@ async function ensureForeignKeysForTables(tables: Array<{ name: string; database
}
}
function createHoverDom(title: string, detail: string, sqlContent?: string, rows: string[] = []) {
function createHoverDom(title: string, detail: string, sqlContent?: string, rows: string[] = []): { dom: HTMLElement; mount?: () => void; destroy?: () => void } {
const dom = document.createElement("div");
dom.className = "rounded-md border bg-popover px-3 py-2 text-xs text-popover-foreground shadow-md";
@@ -2328,13 +2329,15 @@ function createHoverDom(title: string, detail: string, sqlContent?: string, rows
detailNode.textContent = detail;
dom.appendChild(detailNode);
let layoutController: ReturnType<typeof constrainSqlHoverLayout> | null = null;
if (sqlContent) {
const separator = document.createElement("div");
separator.className = "mt-2 border-t border-border/60";
dom.appendChild(separator);
const sqlContainer = document.createElement("div");
sqlContainer.className = "mt-1.5 max-h-64 overflow-y-auto text-[11px] leading-5 whitespace-pre font-mono";
sqlContainer.className = "mt-1.5 text-[11px] leading-5 whitespace-pre font-mono";
if (hoverSqlHighlighter) {
sqlContainer.innerHTML = hoverSqlHighlighter(sqlContent, isDark.value ? "dark" : "light");
@@ -2344,6 +2347,9 @@ function createHoverDom(title: string, detail: string, sqlContent?: string, rows
}
dom.appendChild(sqlContainer);
// 返回 mount/destroy 给 CodeMirror TooltipView 生命周期钩子,
// 避免 MutationObserver 监听 body 全子树来兜底清理。
layoutController = constrainSqlHoverLayout(dom, sqlContainer);
}
for (const row of rows) {
@@ -2353,7 +2359,11 @@ function createHoverDom(title: string, detail: string, sqlContent?: string, rows
dom.appendChild(rowNode);
}
return dom;
return {
dom,
mount: layoutController ? () => layoutController?.mount() : undefined,
destroy: layoutController ? () => layoutController?.destroy() : undefined,
};
}
async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number) {
@@ -2476,9 +2486,7 @@ async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number)
return {
pos: range.from,
end: range.to,
create: () => ({
dom: createHoverDom(table.name, sqlObjectHoverDetail(table), sqlContent, metadataLoadFailed ? ["[DBX] Failed to load table structure — check connection"] : undefined),
}),
create: () => createHoverDom(table.name, sqlObjectHoverDetail(table), sqlContent, metadataLoadFailed ? ["[DBX] Failed to load table structure — check connection"] : undefined),
};
}
@@ -2502,9 +2510,7 @@ async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number)
return {
pos: range.from,
end: range.to,
create: () => ({
dom: createHoverDom(column.name, column.dataType || "column", undefined, [column.schema ? `${column.schema}.${column.table}` : column.table, ...(column.comment?.trim() ? [column.comment.trim()] : [])]),
}),
create: () => createHoverDom(column.name, column.dataType || "column", undefined, [column.schema ? `${column.schema}.${column.table}` : column.table, ...(column.comment?.trim() ? [column.comment.trim()] : [])]),
};
}
} catch {
@@ -5802,6 +5808,66 @@ defineExpose({
</style>
<style>
[data-sql-structure-hover-content="true"] {
scrollbar-color: color-mix(in oklab, var(--foreground) 42%, transparent) color-mix(in oklab, var(--muted) 65%, transparent);
}
[data-sql-structure-hover-content="true"]::-webkit-scrollbar {
width: 8px;
height: 0;
}
[data-sql-structure-hover-content="true"]::-webkit-scrollbar:horizontal {
display: none;
height: 0;
}
[data-sql-structure-hover-content="true"]::-webkit-scrollbar-track {
border-radius: 999px;
background: color-mix(in oklab, var(--muted) 65%, transparent);
}
[data-sql-structure-hover-content="true"]::-webkit-scrollbar-thumb {
min-width: 32px;
min-height: 32px;
border: 1px solid transparent;
border-radius: 999px;
background: color-mix(in oklab, var(--foreground) 42%, transparent);
background-clip: padding-box;
}
[data-sql-structure-hover-content="true"]::-webkit-scrollbar-corner {
background: transparent;
}
[data-sql-structure-hover-scrollbar="true"] {
position: relative;
width: 100%;
height: 10px;
margin-top: 6px;
border-radius: 999px;
background: color-mix(in oklab, var(--muted) 72%, var(--border));
cursor: pointer;
touch-action: none;
user-select: none;
flex: 0 0 10px;
}
[data-sql-structure-hover-scrollbar-thumb="true"] {
position: absolute;
top: 1px;
left: 0;
height: 8px;
border: 1px solid transparent;
border-radius: 999px;
background: color-mix(in oklab, var(--foreground) 52%, transparent);
background-clip: padding-box;
}
[data-sql-structure-hover-scrollbar="true"]:hover [data-sql-structure-hover-scrollbar-thumb="true"] {
background: color-mix(in oklab, var(--foreground) 70%, transparent);
}
.intention-popup-overlay {
position: fixed;
inset: 0;