From f404e524392d333f0cba82c4c8c717cd68f2323e Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Thu, 14 May 2026 17:50:50 -0400 Subject: [PATCH] perf(ui): tighten sensitive-mask decoration scope and reveal selector PR-Agent review on #1248 flagged two follow-ups: 1. The reveal CSS used `.cm-editor.cm-sensitive-revealed`, but @uiw/react-codemirror puts the consumer className on its outer wrapper, not on .cm-editor. The selector never matched, so the Eye toggle could not un-blur masked values. Drop `.cm-editor` from the selector so it matches the wrapper that actually carries the class. 2. The sensitive-decoration plugin rebuilt on every `viewportChanged`, which means each scroll event re-stringified and rescanned the entire document even though decorations are doc-only-dependent. Rebuild only on `docChanged` to remove scroll-time work. --- ui/src/components/shared/code-editor.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/components/shared/code-editor.tsx b/ui/src/components/shared/code-editor.tsx index cccf534e..d0370f11 100644 --- a/ui/src/components/shared/code-editor.tsx +++ b/ui/src/components/shared/code-editor.tsx @@ -263,7 +263,9 @@ function makeSensitivePlugin(language: 'json' | 'yaml' | 'toml'): Extension { this.decorations = buildSensitiveDecorations(view, language); } update(update: ViewUpdate) { - if (update.docChanged || update.viewportChanged) { + // Decorations are derived from the whole document, not the viewport, + // so a viewport-only change (scroll) does not require a rebuild. + if (update.docChanged) { this.decorations = buildSensitiveDecorations(update.view, language); } } @@ -343,7 +345,9 @@ const sensitiveMaskTheme = EditorView.baseTheme({ opacity: '0.7', transition: 'filter 200ms ease, opacity 200ms ease', }, - '.cm-editor.cm-sensitive-revealed .cm-sensitive-mask': { + // The reveal class is placed on the @uiw/react-codemirror wrapper rather + // than directly on `.cm-editor`, so target the wrapper as the toggle root. + '.cm-sensitive-revealed .cm-sensitive-mask': { filter: 'none', opacity: '1', },