From a2ec2c6d56e6a35e34a4f6ff2c2f8759fc72a6d1 Mon Sep 17 00:00:00 2001 From: prateek-bruno Date: Fri, 15 May 2026 14:40:19 +0530 Subject: [PATCH] fix: add resize listener for code mirror instances (#7889) --- .../src/components/CodeEditor/index.js | 4 ++ .../RequestPane/QueryEditor/index.js | 3 ++ .../bruno-app/src/utils/codemirror/resize.js | 38 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 packages/bruno-app/src/utils/codemirror/resize.js diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index fcb55fbd8..38cb1ace5 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -16,6 +16,7 @@ import stripJsonComments from 'strip-json-comments'; import { getAllVariables } from 'utils/collections'; import { setupLinkAware } from 'utils/codemirror/linkAware'; import { setupLintErrorTooltip } from 'utils/codemirror/lint-errors'; +import { setupCodeMirrorResizeRefresh } from 'utils/codemirror/resize'; import CodeMirrorSearch from 'components/CodeMirrorSearch/index'; import { applyEditorState, @@ -269,6 +270,8 @@ class CodeEditor extends React.Component { if (cmInput) { cmInput.classList.add('mousetrap'); } + + this.cleanupResizeRefresh = setupCodeMirrorResizeRefresh(editor, this._node); } } @@ -402,6 +405,7 @@ class CodeEditor extends React.Component { // Clean up lint error tooltip this.cleanupLintErrorTooltip?.(); + this.cleanupResizeRefresh?.(); const wrapper = this.editor.getWrapperElement(); wrapper?.parentNode?.removeChild(wrapper); diff --git a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js index b3a174bac..57c698bd4 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js @@ -16,6 +16,7 @@ import toast from 'react-hot-toast'; import StyledWrapper from './StyledWrapper'; import onHasCompletion from './onHasCompletion'; import { setupLinkAware } from 'utils/codemirror/linkAware'; +import { setupCodeMirrorResizeRefresh } from 'utils/codemirror/resize'; const CodeMirror = require('codemirror'); @@ -149,6 +150,7 @@ export default class QueryEditor extends React.Component { this.addOverlay(); setupLinkAware(editor); + this.cleanupResizeRefresh = setupCodeMirrorResizeRefresh(editor, this._node); // Add mousetrap class so Mousetrap captures shortcuts even when CodeMirror is focused const cmInput = editor.getInputField(); @@ -192,6 +194,7 @@ export default class QueryEditor extends React.Component { if (this.editor?._destroyLinkAware) { this.editor._destroyLinkAware(); } + this.cleanupResizeRefresh?.(); this.editor.off('change', this._onEdit); this.editor.off('keyup', this._onKeyUp); this.editor.off('hasCompletion', this._onHasCompletion); diff --git a/packages/bruno-app/src/utils/codemirror/resize.js b/packages/bruno-app/src/utils/codemirror/resize.js new file mode 100644 index 000000000..dc43173f6 --- /dev/null +++ b/packages/bruno-app/src/utils/codemirror/resize.js @@ -0,0 +1,38 @@ +/** + * Refreshes a CodeMirror editor when its container size changes. + * CodeMirror measures its DOM during refresh(), so resize callbacks are + * coalesced into a single animation frame to avoid repeated layout work. + * + * @param {Object} editor - CodeMirror editor instance + * @param {HTMLElement} element - Element whose size changes should refresh the editor + * @returns {Function} Cleanup function + */ +export const setupCodeMirrorResizeRefresh = (editor, element) => { + if (!editor || !element || typeof ResizeObserver === 'undefined') { + return () => {}; + } + + let resizeRefreshFrameId = null; + + const resizeObserver = new ResizeObserver(() => { + if (resizeRefreshFrameId) { + cancelAnimationFrame(resizeRefreshFrameId); + } + + resizeRefreshFrameId = requestAnimationFrame(() => { + editor.refresh?.(); + resizeRefreshFrameId = null; + }); + }); + + resizeObserver.observe(element); + + return () => { + resizeObserver.disconnect(); + + if (resizeRefreshFrameId) { + cancelAnimationFrame(resizeRefreshFrameId); + resizeRefreshFrameId = null; + } + }; +};