From 54842f71c6b805410cb37ed4ba0e18bf9f6e81ed Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sun, 17 May 2026 10:27:28 +0200 Subject: [PATCH] fix(editor-v2): fix cm6 to rows-derived height, eliminate layout shift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLS verified zero (0.00000) on /blueprints/1 and /overlays/1 via PerformanceObserver({type: 'layout-shift', buffered: true}) on a real browser session — previously CLS=0.00859 from a 253 px shift when cm6 mounted into a display:none slot. Mechanism: - editor-entry.js: mount() accepts `rows`. When provided, prepends an EditorView.theme that pins .cm-editor { height: calc(rows * 1.84rem + 1.125rem) } and sets .cm-scroller overflow:auto. cm6 renders at a fixed, predictable height; long content scrolls internally (same UX the raw +
diff --git a/l4d2web/l4d2web/templates/overlay_detail.html b/l4d2web/l4d2web/templates/overlay_detail.html index 597e11a..17576cb 100644 --- a/l4d2web/l4d2web/templates/overlay_detail.html +++ b/l4d2web/l4d2web/templates/overlay_detail.html @@ -24,7 +24,7 @@

Runs sandboxed against the overlay directory mounted at /overlay.

{% if not latest_build_is_running %} @@ -186,7 +186,7 @@
UTF-8 · 0 bytes diff --git a/l4d2web/scripts/editor-src/editor-entry.js b/l4d2web/scripts/editor-src/editor-entry.js index 1e1ac94..1fc58e3 100644 --- a/l4d2web/scripts/editor-src/editor-entry.js +++ b/l4d2web/scripts/editor-src/editor-entry.js @@ -21,7 +21,7 @@ function pickThemeForMatchMedia(mm) { return mm.matches ? editorDarkTheme : editorLightTheme; } -function mount(textarea, { language = "plain", vocab = null } = {}) { +function mount(textarea, { language = "plain", vocab = null, rows = 0 } = {}) { const langCompartment = new Compartment(); const themeCompartment = new Compartment(); const autocompleteCompartment = new Compartment(); @@ -29,7 +29,21 @@ function mount(textarea, { language = "plain", vocab = null } = {}) { const lang = pickLanguage(language); const mm = window.matchMedia("(prefers-color-scheme: dark)"); + // Fix the editor's rendered height to match the textarea's `rows` + // attribute via a small EditorView.theme — keeps the wrapper's + // pre-reserved space (editor.css `.editor-mount`) and the actual + // cm6 height in lockstep, eliminating the mount-time layout shift. + // Empirical per-row metric on this build: 1.84rem content + 1.125rem + // chrome (8px top + 8px bottom padding + 1px×2 border). + const heightThemes = rows > 0 ? [ + EditorView.theme({ + "&": { height: `calc(${rows} * 1.84rem + 1.125rem)` }, + ".cm-scroller": { overflow: "auto" }, + }), + ] : []; + const extensions = [ + ...heightThemes, history(), lineNumbers(), highlightActiveLine(),