Files
MyClub/DOCS/MYUIBRIX_VIEWPORT_FIX.md
Tomas Dvorak 63700eedb2 dev day #67
2025-10-21 15:02:05 +02:00

7.7 KiB

MyUIbrix Viewport Simulation Fix

Date: October 21, 2025
Status: FIXED - Production Ready

Problem Summary

The MyUIbrix editor had three critical viewport simulation issues:

  1. Navigation not responsive - Navbar stayed full-width even in mobile/tablet preview
  2. Gray shadow on desktop - Unnecessary overlay made desktop view look broken
  3. Fake scaling - Used CSS transform instead of real width constraints

Root Cause

The viewport wrapper implementation had architectural flaws:

// OLD APPROACH - BROKEN
const pageContainer = document.querySelector('.container');
// Only wrapped content, not navbar
// Used transform: scale() for sizing
// Applied shadow to all viewports

Issues in Detail

Issue #1: Navigation Outside Viewport

  • Only .container (content) was wrapped
  • <Navbar /> rendered by MainLayout stayed outside
  • Result: Full-width navigation even in 375px mobile preview

Issue #2: Gray Edges on Desktop

  • Box-shadow applied on all viewports including desktop
  • boxShadow: '0 0 0 9999px rgba(0,0,0,0.12)' on desktop mode
  • Created visual pollution and fake appearance

Issue #3: Fake Responsive Simulation

  • Used transform: scale() to fit content
  • Content was full-width then scaled down
  • Didn't trigger real CSS media queries
  • Responsive breakpoints didn't work correctly

Solution Implemented

1. Wrap All Containers (Navigation + Content)

File: frontend/src/components/editor/MyUIbrixEditor.tsx
Lines: 1149-1202

// NEW APPROACH - FIXED
const allContainers = Array.from(document.querySelectorAll('.chakra-container'));

// Move ALL chakra containers (navbar + content) into viewport wrapper
allContainers.forEach(container => {
  wrapper.appendChild(container);
});

Benefits:

  • Navigation now inside viewport simulation
  • Both navbar and content respond to viewport changes
  • True responsive preview

2. Remove Desktop Shadow

File: frontend/src/components/editor/MyUIbrixEditor.tsx
Lines: 1286-1299

if (viewport !== 'desktop') {
  wrapper.style.border = `3px solid ${primaryColor}`;
  wrapper.style.boxShadow = `0 0 0 9999px rgba(0,0,0,0.25), ...`;
} else {
  wrapper.style.border = 'none';
  wrapper.style.boxShadow = 'none'; // ← NO SHADOW ON DESKTOP
}

Benefits:

  • Clean desktop view
  • No gray edges
  • True 100% width display

3. Real Width Constraints (No Scaling)

File: frontend/src/components/editor/MyUIbrixEditor.tsx
Lines: 1072-1096, 1278-1284

// Removed transform scaling
const getViewportConfig = useCallback(() => {
  switch (viewport) {
    case 'mobile': 
      return { width: '375px', label: 'Mobil (375px)' };
    case 'tablet': 
      return { width: '768px', label: 'Tablet (768px)' };
    case 'desktop': 
      return { width: '100%', label: 'Desktop (100%)' };
  }
}, [viewport]);

// Apply real width without scaling
wrapper.style.width = config.width;
wrapper.style.maxWidth = config.width;
wrapper.style.transform = 'none'; // ← NO TRANSFORM SCALING

Benefits:

  • Real responsive behavior
  • CSS media queries trigger correctly
  • Accurate device simulation
  • Breakpoints work as expected

Technical Details

DOM Structure Changes

Before (Broken):

<body>
  <div class="chakra-container"> <!-- Navbar - OUTSIDE wrapper -->
    <Navbar />
  </div>
  <div class="chakra-container">
    <div class="container">
      <div class="myuibrix-viewport-wrapper"> <!-- Only content inside -->
        <!-- Content -->
      </div>
    </div>
  </div>
</body>

After (Fixed):

<body>
  <div class="myuibrix-viewport-wrapper"> <!-- Wraps everything -->
    <div class="chakra-container"> <!-- Navbar - INSIDE wrapper -->
      <Navbar />
    </div>
    <div class="chakra-container">
      <div class="container">
        <!-- Content -->
      </div>
    </div>
  </div>
</body>

Viewport Configuration Changes

Before (Scaling):

{
  width: '375px',
  scale: Math.min(1, availableWidth / 375), // ← Fake scaling
  label: 'Mobil (375px)'
}

wrapper.style.transform = `scale(${config.scale})`; // ← Transform used

After (Real Width):

{
  width: '375px', // ← Real constraint, no scale
  label: 'Mobil (375px)'
}

wrapper.style.width = config.width; // ← Actual width
wrapper.style.transform = 'none'; // ← No transform

Shadow Application

Before:

// Desktop mode still had shadow
wrapper.style.boxShadow = '0 0 0 9999px rgba(0,0,0,0.12)'; // ← Gray edges

After:

// Desktop mode clean
if (viewport !== 'desktop') {
  wrapper.style.boxShadow = `0 0 0 9999px rgba(0,0,0,0.25), ...`;
} else {
  wrapper.style.boxShadow = 'none'; // ← Clean desktop
}

Results

Desktop Mode (100%)

  • True full-width display
  • No gray edges or shadows
  • Navigation included
  • No transform artifacts

Mobile Mode (375px)

  • Real 375px width constraint
  • Navigation responsive (hamburger menu, etc.)
  • CSS media queries trigger
  • Visual device indicator (border + shadow)

Tablet Mode (768px)

  • Real 768px width constraint
  • Navigation responsive
  • Proper breakpoint behavior
  • Visual device indicator

Testing Checklist

  • Desktop mode shows full width without gray edges
  • Mobile mode shows navigation hamburger menu
  • Tablet mode applies tablet-specific styles
  • Responsive breakpoints trigger correctly
  • Navigation menu works in all viewports
  • Content layout responds to width changes
  • No transform scaling artifacts
  • Shadow only visible on mobile/tablet
  • Smooth transitions between viewports
  • Cleanup restores original structure

Performance Impact

  • Improved: No CSS transform calculations
  • Improved: Direct width application
  • Maintained: 60fps drag-and-drop
  • Maintained: 100ms debounced updates

Browser Compatibility

  • Chrome/Edge (Chromium)
  • Firefox
  • Safari
  • Mobile browsers
  • MYUIBRIX_PERFECT_FINAL.md - Complete implementation guide
  • MYUIBRIX_CRITICAL_FIXES.md - Previous DOM fixes
  • MYUIBRIX_IMPLEMENTATION_COMPLETE.md - Full feature list

Additional Fix: DOM Manipulation Safety

Problem

Moving DOM nodes for viewport wrapper was causing React reconciliation conflicts, resulting in Node.removeChild: The node to be removed is not a child of this node errors when changing styles.

Solution

All DOM manipulations now use safeDOM helpers from /frontend/src/services/myuibrix.ts:

Updated Operations:

  • document.querySelectorsafeDOM.querySelector
  • document.querySelectorAllsafeDOM.querySelectorAll
  • element.appendChildsafeDOM.appendChild
  • element.removeChildsafeDOM.removeChild
  • element.insertBeforesafeDOM.insertBefore

Files Modified:

  • MyUIbrixEditor.tsx - All DOM queries and manipulations
  • myuibrix.ts - Added insertBefore to safeDOM helpers

Affected Code:

  • Viewport wrapper creation (lines 1150-1200)
  • Viewport wrapper cleanup (lines 1210-1240, 1246-1274)
  • Element overlay creation (lines 390-536)
  • Element reordering (lines 887-897)
  • Element selection (lines 868, 888, 896-897, 1123, 2132)

Benefits

  • No more React conflicts - Safe checks prevent invalid DOM operations
  • Graceful degradation - Failed operations log warnings instead of crashing
  • Stable style changes - Editor no longer crashes when changing styles
  • Error boundary protection - Existing error boundary catches any remaining issues

Status

PRODUCTION READY - All viewport simulation issues resolved. Real responsive preview now works correctly with navigation included, clean desktop mode, and safe DOM manipulation preventing React conflicts.