fix(adminui): render Monaco overflow widgets in a body-level node
v2-ci / build (push) Failing after 40s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

The suggest/hover popups were offset far from the caret because the theme's
.rise entrance animation leaves a CSS transform on an ancestor, which becomes
the containing block for the position:fixed overflow widgets. Render them in a
body-level overflowWidgetsDomNode so they stay viewport-correct at the caret.
This commit is contained in:
Joseph Doherty
2026-06-09 17:01:18 -04:00
parent 5c3aa4d211
commit da80195599
@@ -144,6 +144,25 @@
} catch (e) { return []; }
}
// A single body-level node for Monaco's overflow widgets (suggest / hover / parameter hints).
// Rendering them here — outside any ancestor with a CSS transform (e.g. the theme's `.rise`
// entrance animation) — keeps the position:fixed widgets viewport-correct. Without it, the
// transformed ancestor becomes the containing block and the popup is offset far from the caret.
function overflowWidgetsNode() {
let node = document.getElementById("otopcua-monaco-overflow");
if (!node) {
node = document.createElement("div");
node.id = "otopcua-monaco-overflow";
node.className = "monaco-editor"; // so the suggest/hover widget CSS applies
node.style.position = "absolute";
node.style.top = "0";
node.style.left = "0";
node.style.zIndex = "2000";
document.body.appendChild(node);
}
return node;
}
async function createEditor(id, host, options, dotNetRef) {
await ensureLoaded();
if (!host) return;
@@ -152,7 +171,10 @@
theme: "vs", minimap: { enabled: false }, scrollBeyondLastLine: false,
automaticLayout: true, fontSize: 13, lineNumbers: "on",
renderLineHighlight: "line", readOnly: !!options.readOnly,
tabSize: 4, insertSpaces: true, wordWrap: "off", fixedOverflowWidgets: true,
tabSize: 4, insertSpaces: true, wordWrap: "off",
// Render overflow widgets (suggest/hover) in a body-level node so an ancestor CSS
// transform doesn't mis-position them; requires fixedOverflowWidgets.
fixedOverflowWidgets: true, overflowWidgetsDomNode: overflowWidgetsNode(),
// Auto-suggest inside string literals too, so tag-path completion surfaces while typing
// inside ctx.GetTag("…") / ctx.SetVirtualTag("…") without requiring an explicit Ctrl+Space.
quickSuggestions: { other: true, comments: false, strings: true }