Files
OpenNoodl/dev-docs/tasks/phase-3-editor-ux-overhaul/TASK-013-integration-bugfixes/BUG-5-code-editor-modal-close.md

5.6 KiB

BUG-5: Code Editor Modal Won't Close on Outside Click

Priority: P1 - Significant UX Issue
Status: Sort of fixed but still bugs on the Blockly node 'generated code' button Created: January 13, 2026
Updated: January 14, 2026


Problem

When opening the new JavaScriptEditor (CodeMirror 6) by clicking a code property in the property panel, the modal stays on screen even when clicking outside of it. This prevents users from closing the editor without saving.

Expected behavior:

  • Click outside modal → Auto-saves and closes
  • Press Escape → Auto-saves and closes
  • Click Save button → Saves and stays open

Current behavior:

  • Click outside modal → Nothing happens (modal stays open)
  • Only way to close is clicking Save button

Impact

  • Users feel "trapped" in the code editor
  • Unclear how to dismiss the modal
  • Inconsistent with other popout behaviors in OpenNoodl

Root Cause Analysis

Code Flow

  1. CodeEditorType.ts calls this.parent.showPopout() with JavaScriptEditor content
  2. showPopout() should close on outside clicks by default (unless manualClose: true)
  3. onClose callback calls save() which auto-saves changes
  4. Something is preventing the outside click from triggering close

Likely Causes

Possibility 1: Event Propagation

  • JavaScriptEditor or its container might be stopping event propagation
  • Click events not bubbling up to PopupLayer

Possibility 2: Z-index/Pointer Events

  • Modal overlay might not be capturing clicks
  • CSS pointer-events preventing click detection

Possibility 3: React Event Handling

  • React's synthetic event system might interfere with jQuery-based popout system
  • Event listener attachment timing issue

Investigation Steps

1. Check Event Propagation

Verify JavaScriptEditor isn't stopping clicks:

// In JavaScriptEditor.tsx <div ref={rootRef}>
// Should NOT have onClick that calls event.stopPropagation()

2. Check Popout Configuration

Current call in CodeEditorType.ts:

this.parent.showPopout({
  content: { el: [this.popoutDiv] },
  attachTo: $(el),
  position: 'right',
  disableDynamicPositioning: true,
  // manualClose is NOT set, so should close on outside click
  onClose: function () {
    save(); // Auto-saves
    // ... cleanup
  }
});

3. Compare with Monaco Editor

The old Monaco CodeEditor works correctly - compare popout setup.

4. Test Overlay Click Handler

Check if PopupLayer's overlay click handler is working:

// In browser console when modal is open:
document.querySelector('.popout-overlay')?.addEventListener('click', (e) => {
  console.log('Overlay clicked', e);
});

Solution Options

Option A: Fix Event Propagation (Preferred)

If JavaScriptEditor is stopping events, remove/fix that:

// JavaScriptEditor.tsx - ensure no stopPropagation on root
<div
  ref={rootRef}
  className={css['Root']}
  // NO onClick handler here
>

Option B: Add Explicit Close Button

If outside-click proves unreliable, add a close button:

<div className={css['ToolbarRight']}>
  <button onClick={onClose} className={css['CloseButton']}>
     Close
  </button>
  <button onClick={handleFormat}>Format</button>
  <button onClick={onSave}>Save</button>
</div>

But this is less elegant - prefer fixing the root cause.

Option C: Set manualClose Flag

Force manual close behavior and add close button:

this.parent.showPopout({
  // ...
  manualClose: true, // Require explicit close
  onClose: function () {
    save(); // Still auto-save
    // ...
  }
});

Implementation Plan

  1. Investigate - Determine exact cause (event propagation vs overlay)
  2. Fix Root Cause - Prefer making outside-click work
  3. Test - Verify click-outside, Escape key, and Save all work
  4. Fallback - If outside-click unreliable, add close button

Design Decision: Auto-Save Behavior

Chosen: Option A - Auto-save on close

  • Clicking outside closes modal and auto-saves
  • No "unsaved changes" warning needed
  • Consistent with existing Monaco editor behavior
  • Simpler UX - less friction

Rejected alternatives:

  • Option B: Require explicit save (adds friction)
  • Option C: Add visual feedback (over-engineering for this use case)

Files to Modify

Investigation:

  • packages/noodl-core-ui/src/components/code-editor/JavaScriptEditor.tsx - Check event handlers
  • packages/noodl-editor/src/editor/src/views/popuplayer.js - Check overlay click handling

Fix (likely):

  • packages/noodl-core-ui/src/components/code-editor/JavaScriptEditor.tsx - Remove stopPropagation if present
  • packages/noodl-editor/src/editor/src/views/panels/propertyeditor/CodeEditor/CodeEditorType.ts - Verify popout config

Fallback:

  • Add close button to JavaScriptEditor if outside-click proves unreliable

Testing Checklist

  • Click outside modal closes it
  • Changes are auto-saved on close
  • Escape key closes modal (if PopupLayer supports it)
  • Save button works (saves but doesn't close)
  • Works for both editable and read-only editors
  • No console errors on close
  • Cursor position preserved if re-opening same editor

  • Related to Task 11 (Advanced Code Editor implementation)
  • Similar pattern needed for Blockly editor modals

Notes

  • This is a quick fix - should be resolved before continuing with other bugs
  • Auto-save behavior matches existing patterns in OpenNoodl
  • If outside-click proves buggy across different contexts, consider standardizing on explicit close buttons

Last Updated: January 13, 2026