LinkDesk/frontend/docs/shot-delete-event-bubbling-...

166 lines
6.0 KiB
Markdown

# Shot Delete Event Bubbling - Final Fix
## Issue Description
The shot detail panel was still being triggered when performing delete shot actions, despite previous attempts to fix event bubbling. This was happening because the event prevention logic in the `handleRowClick` function was not comprehensive enough to catch all interactive elements within the dropdown menu.
## Root Cause Analysis
The issue occurred in the `ShotsDataTable.vue` component where the `handleRowClick` function was not properly detecting all types of interactive elements that should prevent row click events. Specifically:
1. **Incomplete Element Detection**: The original selector list was missing some Radix UI specific attributes and SVG icons
2. **Missing Parent Element Traversal**: The function wasn't checking parent elements for event handlers
3. **Icon Click Events**: SVG icons within buttons were not being properly detected
4. **Radix UI Elements**: Some Radix UI dropdown elements have dynamic attributes that weren't being caught
## Solution Implementation
### 1. Enhanced Interactive Element Detection
Updated the `handleRowClick` function in `ShotsDataTable.vue` to include a more comprehensive list of selectors:
```typescript
const isInteractiveElement = target.closest([
'button',
'[role="menuitem"]',
'[role="menu"]',
'[data-radix-collection-item]',
'[data-radix-dropdown-menu-trigger]',
'[data-radix-dropdown-menu-content]',
'[data-radix-dropdown-menu-item]',
'[data-state]', // Radix UI elements often have data-state
'.dropdown-menu',
'.dropdown-trigger',
'input',
'select',
'textarea',
'a[href]',
'[tabindex]:not([tabindex="-1"])',
'[onclick]',
'svg', // Icons within buttons
'.lucide' // Lucide icons specifically
].join(', '))
```
### 2. Parent Element Traversal
Added logic to traverse up the DOM tree to check for elements with event handlers:
```typescript
let currentElement: HTMLElement | null = target
while (currentElement && currentElement !== event.currentTarget) {
if (
currentElement.onclick ||
currentElement.getAttribute('role') === 'button' ||
currentElement.tagName === 'BUTTON' ||
(currentElement.classList.contains('cursor-pointer') &&
currentElement !== event.currentTarget)
) {
return // Don't emit row-click
}
currentElement = currentElement.parentElement
}
```
### 3. Enhanced Event Prevention in Columns
The `columns.ts` file was already enhanced by the IDE autofix to include `onMouseDown` event handlers on all dropdown elements:
```typescript
// Dropdown trigger
h(DropdownMenuTrigger, {
asChild: true,
onMouseDown: (e: Event) => {
e.stopPropagation()
},
onClick: (e: Event) => {
e.stopPropagation()
e.preventDefault()
}
})
// Dropdown content and items
h(DropdownMenuContent, {
align: 'end',
onMouseDown: (e: Event) => {
e.stopPropagation()
},
onClick: (e: Event) => {
e.stopPropagation()
}
})
```
## Files Modified
### 1. `frontend/src/components/shot/ShotsDataTable.vue`
- Enhanced `handleRowClick` function with comprehensive interactive element detection
- Added parent element traversal logic
- Fixed TypeScript typing for element traversal
- Removed unused `computed` import
### 2. `frontend/src/components/shot/columns.ts` (Enhanced by IDE autofix)
- Added `onMouseDown` event handlers to all dropdown elements
- Enhanced event prevention with both `stopPropagation()` and `preventDefault()`
- Improved event handling for all dropdown menu items
## Testing
### Test File Created
- `frontend/test-shot-delete-event-bubbling-final-fix.html` - Comprehensive test interface
### Test Scenarios Covered
1. **Row Click Test**: Clicking on non-interactive areas should trigger row click
2. **Dropdown Button Test**: Clicking the three-dot menu button should NOT trigger row click
3. **Menu Item Test**: Clicking "Edit Shot" or "View Tasks" should NOT trigger row click
4. **Delete Test**: Clicking "Delete Shot" should NOT trigger row click (main issue)
5. **Icon Test**: Clicking directly on SVG icons within buttons should NOT trigger row click
### Expected Results
- ✅ Row clicks work on non-interactive areas
- ✅ Dropdown button clicks don't trigger row click
- ✅ Menu item clicks don't trigger row click
- ✅ Delete button clicks don't trigger row click
- ✅ Shot detail panel doesn't open during delete operations
## Technical Details
### Event Flow
1. User clicks delete button in dropdown menu
2. `onMouseDown` handler on dropdown elements prevents initial bubbling
3. `onClick` handler on menu item executes delete action
4. Enhanced `handleRowClick` function detects interactive element and prevents row click emission
5. Shot detail panel remains closed during delete operation
### Browser Compatibility
- Uses standard DOM traversal methods (`closest`, `parentElement`)
- Compatible with all modern browsers
- Handles both mouse and touch events
### Performance Impact
- Minimal performance impact due to efficient DOM traversal
- Event prevention happens early in the event chain
- No unnecessary event listeners or watchers added
## Prevention Measures
To prevent similar issues in the future:
1. **Comprehensive Testing**: Always test interactive elements within table rows
2. **Event Handler Documentation**: Document all event prevention strategies
3. **Radix UI Awareness**: Be aware of Radix UI's dynamic attributes and event handling
4. **Icon Handling**: Remember that SVG icons can be click targets within buttons
5. **Parent Traversal**: Consider parent element event handlers when preventing bubbling
## Verification
The fix can be verified by:
1. Opening the shot table in the application
2. Clicking the three-dot menu on any shot row
3. Clicking "Delete Shot" option
4. Confirming that the shot detail panel does NOT open
5. Confirming that the delete confirmation dialog opens instead
## Related Issues
This fix resolves the core issue where delete actions were inadvertently opening the shot detail panel, improving the user experience and preventing confusion during delete operations.