feat(panels): improve drag UX and add close buttons to live panels#1447
feat(panels): improve drag UX and add close buttons to live panels#1447rayanhabib07 wants to merge 2 commits intokoala73:mainfrom
Conversation
|
@rayanhabib07 is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
|
Thanks for this @rayanhabib07! The ghost-based drag is a clear improvement over live DOM shuffling, and the close buttons for live panels are a clean fix for #1395. A few things need fixing before merge: Blocking:
Should fix:
Minor:
Fix items 1-3 and this is good to go! |
SebastienMelki
left a comment
There was a problem hiding this comment.
Nice work @rayanhabib07 — the ghost-based drag is a significant UX upgrade and the code is well-structured. Koala covered the main issues thoroughly; here are a few additional things I spotted:
Bug — ghost & indicator leak in the DOM
In onMouseUp (panel-layout.ts), the fade-out cleanup has a closure bug:
if (ghostEl) {
ghostEl.style.opacity = '0';
setTimeout(() => ghostEl?.remove(), 200); // ← closure captures the variable
ghostEl = null; // ← variable is null before timeout fires
}The arrow function closes over the ghostEl variable, not its current value. By the time the 200ms timeout fires, ghostEl is already null, so ?.remove() is a no-op. The invisible DOM node stays in the document forever — one orphan per drag. Same issue with dropIndicator right below it.
Fix: capture the reference before nulling:
if (ghostEl) {
ghostEl.style.opacity = '0';
const g = ghostEl;
setTimeout(() => g.remove(), 200);
ghostEl = null;
}Missing Escape-to-cancel
There's no way to abort a drag mid-flight. If a user starts dragging and wants to bail, they have to drop it somewhere and then undo. Adding an Escape keydown listener during drag that cleans up the ghost/indicator and restores the original position would be a nice touch (non-blocking, but worth considering).
Drag on panels with panel-content click targets
onMouseDown correctly bails if target.closest('button, a, input, select, textarea, .panel-content') — but the drag handle is the panel header area. Just double-checking: this means users can only grab panels by their header bar, right? That's fine UX-wise, just want to confirm it's intentional since the older code may have allowed dragging from anywhere on the panel.
Everything else looks clean — the close button change is minimal and correct (closable: true), the event listener cleanup in destroy() is solid, and the CSS animations are tasteful. Great first contribution, looking forward to seeing the fixes! 🤘
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
SebastienMelki
left a comment
There was a problem hiding this comment.
Reviewed the fix commit (71a1ce7) against all feedback from both reviews — everything has been addressed:
Koala's blocking items (1–3): all fixed
- Cmd+Z now guards against INPUT/TEXTAREA/contentEditable before calling preventDefault
cloneNodestrips iframes from the ghost to avoid duplicate network requests- Drop logic replaced with
swapElements()which avoids the ghost-center offset bug entirely
Koala's should-fix items (4–8): all fixed
- Undo stack capped at 20 entries
performUndo()now callsfetchData()on the restored panel.panel-drop-indicatorstyles moved from inline JS to CSS class- Redundant
pointerEventsassignment replaced with save/restore pattern docs/DRAG_SYSTEM_IMPROVEMENTS.mddeleted
Koala's minor items (9–10): fixed (blank line removed, max-items comment added)
Seb's items: all fixed
- Ghost/indicator DOM leak fixed — reference captured before nulling (
const g = ghostEl; setTimeout(() => g.remove(), 200)) - Escape-to-cancel added with full cleanup (ghost, indicator, target highlight, original position restore, listener removal, RAF cancellation)
LGTM on the code side — nice work on the fixes!
|
This was replaced by #1550 |
Improves the drag-and-drop system and adds close buttons to live panels.
Changes: