[WIP] Improve drag functionality in empty key list for designer#42
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive touch device support and tablet optimization to the Object UI Designer. The main objective is to enable component dragging on touch devices (tablets/mobile) and optimize the designer's responsive layout for smaller screens.
Changes:
- Implemented a touch drag polyfill that converts touch events into HTML5 drag events
- Made the designer layout responsive with Tailwind breakpoints for better tablet usage
- Refactored ComponentPalette to use a dedicated ComponentItem component with touch support
- Added comprehensive unit tests and documentation for the touch drag functionality
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/designer/src/utils/touchDragPolyfill.ts | New utility implementing touch-to-drag event conversion with visual feedback |
| packages/designer/src/components/ComponentPalette.tsx | Refactored to use ComponentItem component with touch drag support and responsive styling |
| packages/designer/src/components/Designer.tsx | Updated sidebar widths to be responsive (w-64 md:w-72, w-72 md:w-80) |
| packages/designer/src/components/LeftSidebar.tsx | Made tab labels responsive (icons only on small screens) and adjusted padding |
| packages/designer/src/tests/touchDragPolyfill.test.ts | Added comprehensive unit tests for touch drag polyfill functionality |
| packages/designer/TOUCH_DRAG_GUIDE.md | New documentation explaining touch drag implementation and usage |
| setTimeout(() => { | ||
| if (!startTouch) return; | ||
|
|
||
| isDragging = true; | ||
|
|
||
| // Create visual preview | ||
| dragPreview = createDragPreview(element, touch); | ||
|
|
||
| // Add dragging class to original element | ||
| element.classList.add('dragging', 'opacity-50', 'grayscale'); | ||
|
|
||
| // Simulate dragstart | ||
| simulateDragEvent('dragstart', touch, element, options.dragData); | ||
|
|
||
| // Call custom handler | ||
| options.onDragStart?.(e, element); | ||
| }, 100); |
There was a problem hiding this comment.
The 100ms timeout is not stored, which means it cannot be cleared if the component unmounts or if touchend/touchcancel fires before the timeout completes. This could lead to the drag starting after the user has already released their finger. Store the timeout ID and clear it in handleTouchEnd, handleTouchCancel, and the cleanup function.
| // Find element under touch | ||
| dragPreview.style.pointerEvents = 'none'; | ||
| const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); | ||
| dragPreview.style.pointerEvents = 'auto'; |
There was a problem hiding this comment.
Setting pointerEvents back to 'auto' after finding the element below defeats the purpose of temporarily disabling it. This line should be removed or the value should remain 'none' throughout the drag operation, as the preview should never intercept pointer events.
| onDragEnd={onDragEnd} | ||
| className={cn( | ||
| "group flex flex-col items-center justify-center gap-1.5 md:gap-2 p-2.5 md:p-3 rounded-xl border-2 border-transparent hover:border-indigo-200 hover:bg-gradient-to-br hover:from-indigo-50 hover:to-purple-50 hover:shadow-lg cursor-grab active:cursor-grabbing transition-all duration-200 bg-white relative overflow-hidden", | ||
| "h-20 md:h-24 hover:scale-105 active:scale-95 touch-none" |
There was a problem hiding this comment.
The CSS class 'touch-none' prevents all touch interactions, which conflicts with the touch drag functionality being added. This will block the touch event listeners from receiving events. Consider using 'select-none' or 'user-select-none' instead to prevent text selection while allowing touch events.
| <input | ||
| type="text" | ||
| placeholder="Search components..." | ||
| placeholder="Search..." |
There was a problem hiding this comment.
The search input placeholder was changed from 'Search components...' to 'Search...', which is less descriptive. For accessibility, the placeholder should clearly indicate what is being searched. Consider reverting to the more descriptive placeholder or adding an aria-label.
| // @ts-ignore - Testing browser API | ||
| global.window = { ontouchstart: {} } as any; |
There was a problem hiding this comment.
Modifying the global window object can cause test pollution affecting other tests. Store the original value and restore it in an afterEach hook, or use vi.stubGlobal() from Vitest which handles cleanup automatically.
| ```typescript | ||
| // Touch events flow | ||
| touchstart → (100ms delay to distinguish from scroll) → dragstart | ||
| touchmove → dragover on elements below touch point |
There was a problem hiding this comment.
The documentation states that touchmove converts to dragover, but according to the implementation in touchDragPolyfill.ts, touchmove also triggers dragleave and dragenter events when the touch moves between different elements. The documentation should accurately reflect this behavior for developers debugging touch interactions.
| touchmove → dragover on elements below touch point | |
| touchmove → dragover on element below touch point; when moving between elements: dragleave on previous + dragenter on new target |
|
@copilot fix |
|
✅ All checks passed!
|
|
✅ All checks passed!
|
|
✅ All checks passed!
|
Plan: Optimize Designer for Touch Devices and Tablets
Problem Statement
Root Cause
Implementation Plan
Phase 1: Add Touch Event Support for Drag and Drop
Phase 2: Optimize Layout for Tablets
Phase 3: Testing and Documentation
Changes Made
1. Touch Drag Polyfill (
touchDragPolyfill.ts)2. ComponentPalette Updates
ComponentItemcomponent with touch support viauseEffecthooktouch-noneCSS class to prevent text selection3. Designer Layout Optimization
w-64 md:w-72(256px → 288px)w-72 md:w-80(288px → 320px)min-w-0to canvas to prevent overflow4. LeftSidebar Responsiveness
hidden sm:inline)px-3 md:px-4)5. Tests and Documentation
Technical Approach
touch-noneCSS class to prevent text selection during dragBrowser Compatibility
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.