diff --git a/RESIZE_HANDLES_INVESTIGATION.md b/RESIZE_HANDLES_INVESTIGATION.md deleted file mode 100644 index 43425d6..0000000 --- a/RESIZE_HANDLES_INVESTIGATION.md +++ /dev/null @@ -1,321 +0,0 @@ -# Resize Handle Overlay Issue - Investigation Report - -## Problem Summary - -The resize handles in edit mode are being rendered **INSIDE the widget container DOM**, causing: -- Widgets to stretch and overflow their grid bounds -- Scrollbars to appear unexpectedly -- Edit/delete buttons to be hidden or inconsistently visible -- Layout overflow issues - -The handles use negative positioning (`top: -6px`, `left: -3px`) to extend outside widget bounds, but being children of the widget element causes them to contribute to the widget's `offsetHeight` and `offsetWidth`, which creates unwanted scrollbars and overflow. - ---- - -## Investigation Findings - -### 1. Where Resize Handles Are Created and Appended - -**File:** `src/systems/dashboard/resizeHandler.js` - -**Key Code (Lines 172-215):** -```javascript -createResizeHandles() { - const container = document.createElement('div'); - container.className = 'resize-handles'; - container.style.position = 'absolute'; - container.style.inset = '0'; - container.style.pointerEvents = 'none'; - - // Create 8 handles (4 corners + 4 edges) - Object.entries(this.handleTypes).forEach(([handleType, cursor]) => { - const handle = document.createElement('div'); - handle.className = `resize-handle resize-handle-${handleType}`; - // ... positioning ... - handle.style.top = '-6px'; // Negative positioning - handle.style.left = '-3px'; // Negative positioning - handle.style.zIndex = '100'; - container.appendChild(handle); - }); - - return container; -} -``` - -**Appended At (Line 77):** -```javascript -initWidget(element, widget, onResizeEnd, constraints = {}) { - const handles = this.createResizeHandles(); - element.appendChild(handles); // <-- APPENDED INSIDE WIDGET - // ... -} -``` - -**Problem:** The handles container is appended directly to the widget element (`element.appendChild(handles)`), making it a child of `.rpg-widget`. - ---- - -### 2. Where Edit/Delete Buttons Are Created - -**File:** `src/systems/dashboard/editModeManager.js` - -**Key Code (Lines 325-373):** -```javascript -addWidgetControls(element, widgetId) { - const controls = document.createElement('div'); - controls.className = 'widget-edit-controls'; - controls.style.position = 'absolute'; - controls.style.top = '4px'; - controls.style.right = '4px'; - controls.style.display = 'flex'; - controls.style.gap = '4px'; - controls.style.zIndex = '100'; - controls.style.opacity = '0'; - controls.style.transition = 'opacity 0.2s'; - - // Create settings and delete buttons - const settingsBtn = this.createControlButton('⚙', 'Settings'); - const deleteBtn = this.createControlButton('×', 'Delete'); - - controls.appendChild(settingsBtn); - controls.appendChild(deleteBtn); - - element.appendChild(controls); // <-- APPENDED INSIDE WIDGET - // ... -} -``` - -**Problem:** Like the resize handles, the edit controls are appended inside the widget element as a child. - ---- - -### 3. Current DOM Structure - -``` -
- -
...
- - -
-
- -
- - -
- - -
-
-``` - -**Why This Causes Issues:** -- Even though handles have `position: absolute`, they're still part of the DOM flow calculation -- Negative positioning extends them outside the widget visually, but the browser still includes them in overflow calculations -- This causes scrollbars when the widget container has `overflow: auto` or `overflow: scroll` -- The controls at `top: 4px; right: 4px` with `z-index: 100` can be covered or hidden by other elements - ---- - -### 4. CSS Widget Styling - -**File:** `style.css` - -**Key Widget CSS:** -```css -.rpg-widget { - box-sizing: border-box; - overflow: visible; /* Allow resize handles to extend beyond widget bounds */ - display: flex; - flex-direction: column; - max-height: 100%; /* Prevent content from overflowing grid cell */ - /* ... other styles ... */ -} - -/* Hide resize handles by default */ -.resize-handles { - opacity: 0; - pointer-events: none; - transition: opacity 0.2s; -} - -/* Show resize handles in edit mode */ -.edit-mode .resize-handles { - opacity: 1; - pointer-events: auto; -} - -/* Hide resize handles when widgets are locked */ -.widgets-locked .resize-handles { - opacity: 0 !important; - pointer-events: none !important; -} -``` - -**Current State:** -- Widget has `overflow: visible` - correct for allowing handles to show -- But the negative positioning of handles inside the widget still causes layout issues -- The `max-height: 100%` on flex column can cause scrollbars if child heights exceed parent - ---- - -### 5. Why Buttons Are Inconsistently Visible - -The edit/delete buttons are positioned inside the widget at `top: 4px; right: 4px;` with `z-index: 100`. Issues arise: - -1. **Scrollbars Overlap:** If the widget develops a scrollbar, the buttons are positioned relative to the widget's content box, not the visible area, so they can be hidden by the scrollbar. - -2. **Parent Stacking Context:** The widget element's positioning and z-index hierarchy may cause the buttons to be layered differently depending on scroll state. - -3. **Hover State Lost:** When scrollbars appear, the widget's visual bounds change, and hover detection may fail to show/hide buttons consistently. - -4. **Absolute Positioning Within Scrollable Parent:** Buttons positioned absolutely within a widget that can scroll create unpredictable rendering. - ---- - -## Recommended Approach: Make Handles & Buttons True Overlays - -### Strategy - -**Move resize handles and edit controls outside the widget DOM to a shared overlay container at the dashboard/grid level.** - -**Current (Problematic) Structure:** -``` -
- - - -
-``` - -**Target (Fixed) Structure:** -``` -
-
- -
-
- - - - -
-
-``` - -### Benefits - -1. **No DOM Overflow:** Handles and controls are outside widgets, don't contribute to widget dimensions -2. **Clean Widget DOM:** Widgets only contain their actual content -3. **Consistent Visibility:** Overlays are positioned relative to grid container, not affected by widget scrolling -4. **Proper Z-stacking:** True layers with proper z-index control -5. **Easier Positioning:** Overlay containers can be precisely positioned relative to grid, and handles/controls positioned relative to overlay -6. **No Scrollbar Interference:** Buttons and handles won't be hidden by scrollbars - -### Implementation Plan - -1. **Create overlay container management in DashboardManager:** - - Create and maintain `#rpg-resize-handles-overlay` container - - Create and maintain `#rpg-edit-controls-overlay` container - - Both positioned absolutely, covering entire grid, `pointer-events: none` by default - -2. **Modify ResizeHandler:** - - Change `initWidget()` to NOT append handles to widget element - - Instead, create handles and append to `#rpg-resize-handles-overlay` - - Position handles using absolute positioning relative to overlay container - - Calculate positions based on widget's grid position + negative offsets - -3. **Modify EditModeManager:** - - Change `addWidgetControls()` to NOT append controls to widget element - - Instead, create controls and append to `#rpg-edit-controls-overlay` - - Position controls using absolute positioning relative to overlay container - - Calculate positions based on widget's grid position - -4. **Update repositioning logic:** - - When widgets are repositioned (drag/resize), update overlay child positions - - On tab switch, show/hide overlay child elements for that tab's widgets - - On widget removal, remove corresponding overlay children - -5. **CSS updates:** - - Add styles for overlay containers - - Add positioning rules for handles and controls within overlays - ---- - -## Key Files Needing Changes - -| File | Change | Impact | -|------|--------|--------| -| `src/systems/dashboard/resizeHandler.js` | Don't append handles to widget; append to overlay instead | Prevents widget overflow | -| `src/systems/dashboard/editModeManager.js` | Don't append controls to widget; append to overlay instead | Fixes button visibility | -| `src/systems/dashboard/dashboardManager.js` | Create/maintain overlay containers; manage overlay children on reposition | Coordinates layout | -| `style.css` | Add overlay container styles; update handle/control positioning | Visual presentation | - ---- - -## CSS Overflow Issue Analysis - -**Current `.rpg-widget` CSS:** -```css -.rpg-widget { - overflow: visible; /* Good - allows content overflow */ - max-height: 100%; /* Can cause scrollbars if flex children exceed 100% */ - display: flex; - flex-direction: column; -} -``` - -**Why Scrollbars Appear:** -1. Widget has `display: flex; flex-direction: column` -2. Widget has `max-height: 100%` -3. If flex children (content + handles + controls) exceed max-height, scrollbars appear -4. The `overflow: visible` doesn't prevent scrollbars - `max-height` triggers them - -**Solution:** -- Moving handles/controls outside widget DOM solves the flex child height problem -- Keep `overflow: visible` for clean content overflow -- Remove or adjust `max-height` constraint - ---- - -## Event Handler Interaction Points - -### Resize Handler -- **Source:** `resizeHandler.js`, line 77 in `initWidget()` -- **Current:** Appends handles to widget element -- **Change:** Accept overlay container reference, append there instead - -### Drag/Drop Handler -- **Source:** `dragDrop.js`, line 76 checks for `.resize-handle` with `closest()` -- **Impact:** Still works (CSS class-based detection) -- **Change:** None needed - will still detect overlaid handles - -### Edit Mode Manager -- **Source:** `editModeManager.js`, lines 325-373 in `addWidgetControls()` -- **Current:** Appends controls to widget element -- **Change:** Accept overlay container reference, append there instead - -### Dashboard Manager -- **Source:** `dashboardManager.js`, lines 631-703 in `renderWidget()` -- **Current:** Calls `resizeHandler.initWidget()` and `editManager.addWidgetControls()` with widget element -- **Change:** Pass overlay containers, handle repositioning on layout changes - ---- - -## Summary - -The resize handles are being rendered **inside the widget container**, causing them to: -1. Contribute to widget dimensions via negative positioning tricks -2. Trigger scrollbars when combined with flex layout and `max-height` -3. Cause edit/delete buttons to be hidden or inaccessible -4. Create inconsistent UI behavior - -**Solution:** Create true overlay containers at the grid level, position handles and controls outside the widget DOM, and coordinate their positioning through the DashboardManager lifecycle. - -This approach is used in many professional UI frameworks and provides: -- Clean separation of concerns -- Better visual control -- Elimination of overflow/scrollbar issues -- Consistent button visibility -- Proper z-index layering