# Shot Delete Event Bubbling Fix ## Issue Description When clicking the "Delete Shot" button in the ShotsDataTable, the shot detail panel was being triggered along with the delete action. This was happening because the delete button click event was bubbling up to the table row click handler, which opens the shot detail panel. ## Root Cause The issue was caused by event bubbling in the table row structure: 1. The table row has a `@click="handleRowClick"` event handler that opens the shot detail panel 2. The delete button (inside a dropdown menu) is within the table row 3. Even though the dropdown menu items had `e.stopPropagation()`, the event was still bubbling up to the row click handler ## Solution ### 1. Enhanced Event Handling in ShotsDataTable Modified the `handleRowClick` function in `ShotsDataTable.vue` to check if the click target is within an interactive element: ```typescript const handleRowClick = (shot: Shot, event: MouseEvent) => { // Check if the click target is within a dropdown menu, button, or other interactive element const target = event.target as HTMLElement if (target) { // Check if the click is on a button, dropdown, or any interactive element const isInteractiveElement = target.closest('button, [role="menuitem"], [data-radix-collection-item]') if (isInteractiveElement) { // Don't emit row-click if clicking on interactive elements return } } emit('row-click', shot, event) } ``` This approach: - Checks if the click target is within a button, dropdown menu item, or other interactive element - Uses `closest()` to traverse up the DOM tree to find interactive elements - Prevents the row-click event from being emitted when clicking on interactive elements ### 2. Improved Event Prevention in Columns Enhanced the event handling in `columns.ts` for all dropdown menu items: ```typescript // Before onClick: (e: Event) => { e.stopPropagation(); meta.onDelete(shot) } // After onClick: (e: Event) => { e.stopPropagation() e.preventDefault() meta.onDelete(shot) } ``` Added `e.preventDefault()` in addition to `e.stopPropagation()` for more robust event handling. ### 3. Enhanced Dropdown Trigger Improved the dropdown trigger button event handling: ```typescript h( DropdownMenuTrigger, { asChild: true, onClick: (e: Event) => { e.stopPropagation() e.preventDefault() } }, { default: () => h( Button, { variant: 'ghost', size: 'sm', class: 'h-8 w-8 p-0', onClick: (e: Event) => { e.stopPropagation() e.preventDefault() } }, // ... ), } ) ``` ## Testing Created `test-shot-delete-event-fix.html` to verify the fix works correctly: 1. Clicking the "Delete Shot" button should NOT trigger the row click event 2. Clicking anywhere else on the row SHOULD trigger the row click event 3. The event log shows which events are triggered and which are prevented ## Files Modified 1. `frontend/src/components/shot/ShotsDataTable.vue` - Enhanced `handleRowClick` function to detect interactive elements 2. `frontend/src/components/shot/columns.ts` - Added `e.preventDefault()` to all dropdown menu item click handlers - Enhanced dropdown trigger event handling ## Benefits - Prevents unwanted shot detail panel opening when deleting shots - Maintains proper row click functionality for non-interactive areas - Provides a robust solution that works with various UI components - Uses DOM traversal to detect interactive elements, making it future-proof ## Prevention To prevent similar issues in the future: 1. Always use both `e.stopPropagation()` and `e.preventDefault()` for interactive elements within clickable containers 2. Consider using DOM traversal (`closest()`) to detect interactive elements in container click handlers 3. Test interactive elements within clickable containers to ensure proper event handling 4. Use specific selectors for interactive elements (buttons, menu items, etc.)