diff --git a/src/components/DraggableList/SortableItem.tsx b/src/components/DraggableList/SortableItem.tsx index 7ed0e0b85a0f7..b4c412bbdcbd1 100644 --- a/src/components/DraggableList/SortableItem.tsx +++ b/src/components/DraggableList/SortableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type {SortableItemProps} from './types'; function SortableItem({id, children, disabled = false}: SortableItemProps) { - const {attributes, listeners, setNodeRef, transform, transition} = useSortable({id, disabled}); + const {attributes, listeners, setNodeRef, transform, transition, isDragging} = useSortable({id, disabled}); const style = { touchAction: 'none', @@ -12,10 +12,21 @@ function SortableItem({id, children, disabled = false}: SortableItemProps) { transition, }; + // Prevent Enter key from reaching MenuItem when dragging to avoid navigation conflicts + const handleKeyDown = (e: React.KeyboardEvent) => { + if (!isDragging || e.key !== 'Enter') { + return; + } + e.preventDefault(); + e.stopPropagation(); + }; + return (
({ }: DraggableListProps & {ref?: React.ForwardedRef}) { const styles = useThemeStyles(); + // Unique ID per mount to ensure DndContext state resets when component remounts + const instanceId = useId(); + + // Track if a drag is currently active to avoid dispatching global Escape when not needed + const isDraggingRef = useRef(false); + + // Cancel any active keyboard drag when the component unmounts to prevent ghost drag state + useEffect(() => { + return () => { + if (typeof document === 'undefined' || !isDraggingRef.current) { + return; + } + document.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape', code: 'Escape', bubbles: true, cancelable: true})); + }; + }, []); + const items = data.map((item, index) => { return keyExtractor(item, index); }); + const onDragStart = () => { + isDraggingRef.current = true; + }; + /** * Function to be called when the user finishes dragging an item * It will reorder the list and call the callback function * to notify the parent component about the change */ const onDragEnd = (event: DragEndEvent) => { + isDraggingRef.current = false; const {active, over} = event; if (over !== null && active.id !== over.id) { @@ -49,6 +70,10 @@ function DraggableList({ } }; + const onDragCancel = () => { + isDraggingRef.current = false; + }; + const sortableItems = data.map((item, index) => { const key = keyExtractor(item, index); // Check if item has a disabled property for dragging @@ -77,6 +102,11 @@ function DraggableList({ }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, + keyboardCodes: { + start: ['Space'], + cancel: ['Escape'], + end: ['Space'], + }, }), ); @@ -90,7 +120,10 @@ function DraggableList({ >