fix: replace imperative DOM overlay with React-based positioning

The imperative approach inserted overlay elements directly into
Lexical-managed CodeNode DOM elements.  Lexical's MutationObserver
detected the foreign DOM nodes, reconciled them away, which triggered
update listeners that re-inserted them — causing an infinite loop
that froze the app.

The new approach renders overlay elements via React, positioned
absolutely in a pointer-events:none container that sits over the
content editable.  Overlay positions are computed from each code
element's bounding rect and updated via requestAnimationFrame on
editor updates and scroll events.  This avoids all Lexical DOM
mutation and eliminates the freeze.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-25 19:49:16 +01:00
co-authored by Copilot
parent 9ef7150183
commit 38d7e339a2
2 changed files with 106 additions and 75 deletions
+13 -5
View File
@@ -228,7 +228,6 @@ textarea {
/* Code block */
.mc-code-block {
display: block;
position: relative;
background: rgba(24, 24, 27, 0.8);
border: 1px solid #27272a;
border-radius: 6px;
@@ -241,12 +240,21 @@ textarea {
overflow-x: auto;
}
/* Language selector overlay inside code blocks */
/* Language selector overlays positioned outside Lexical-managed DOM */
.mc-code-overlays-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 10;
overflow: hidden;
}
.mc-code-lang-overlay {
position: absolute;
top: 3px;
right: 4px;
z-index: 1;
pointer-events: auto;
user-select: none;
}