From ddefe81082bfc0ef1485b482cb92fecdfe3ac7e1 Mon Sep 17 00:00:00 2001 From: Reece Date: Thu, 23 Oct 2025 20:46:58 +0100 Subject: [PATCH] Enhance DragDropGrid and PageEditor with improved undo manager functionality and scroll handling during drag operations --- .../components/pageEditor/DragDropGrid.tsx | 29 +++++++++++++++---- .../src/components/pageEditor/PageEditor.tsx | 14 +++++---- .../pageEditor/commands/pageCommands.ts | 4 +++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/pageEditor/DragDropGrid.tsx b/frontend/src/components/pageEditor/DragDropGrid.tsx index 078aefc5b..69abcf6e2 100644 --- a/frontend/src/components/pageEditor/DragDropGrid.tsx +++ b/frontend/src/components/pageEditor/DragDropGrid.tsx @@ -23,12 +23,8 @@ interface DragDropItem { interface DragDropGridProps { items: T[]; - selectedItems: string[]; - selectionMode: boolean; - isAnimating: boolean; onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void; renderItem: (item: T, index: number, refs: React.MutableRefObject>, boxSelectedIds: string[], clearBoxSelection: () => void, getBoxSelection: () => string[], activeId: string | null, isOver: boolean, dragHandleProps?: any, zoomLevel?: number) => React.ReactNode; - renderSplitMarker?: (item: T, index: number) => React.ReactNode; getThumbnailData?: (itemId: string) => { src: string; rotation: number } | null; zoomLevel?: number; } @@ -109,6 +105,10 @@ const DragDropGrid = ({ const itemRefs = useRef>(new Map()); const containerRef = useRef(null); + const getScrollElement = useCallback(() => { + return containerRef.current?.closest('[data-scrolling-container]') as HTMLElement | null; + }, []); + // Filter out placeholder items (invisible pages for deselected files) const visibleItems = items.filter(item => !item.isPlaceholder); @@ -286,7 +286,7 @@ const DragDropGrid = ({ // Virtualization with react-virtual library const rowVirtualizer = useVirtualizer({ count: Math.ceil(visibleItems.length / itemsPerRow), - getScrollElement: () => containerRef.current?.closest('[data-scrolling-container]') as Element, + getScrollElement, estimateSize: () => { const remToPx = parseFloat(getComputedStyle(document.documentElement).fontSize); return parseFloat(GRID_CONSTANTS.ITEM_HEIGHT) * remToPx * zoomLevel; @@ -495,6 +495,24 @@ const DragDropGrid = ({ }; }, [hoveredItemId, dropSide, activeId, itemGap, zoomLevel]); + const handleWheelWhileDragging = useCallback((event: React.WheelEvent) => { + if (!activeId) { + return; + } + + const scrollElement = getScrollElement(); + if (!scrollElement) { + return; + } + + scrollElement.scrollBy({ + top: event.deltaY, + left: event.deltaX, + }); + + event.preventDefault(); + }, [activeId, getScrollElement]); + return ( ({ onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} + onWheel={handleWheelWhileDragging} style={{ // Basic container styles width: '100%', diff --git a/frontend/src/components/pageEditor/PageEditor.tsx b/frontend/src/components/pageEditor/PageEditor.tsx index 6727bc3ea..2eb5ec5b3 100644 --- a/frontend/src/components/pageEditor/PageEditor.tsx +++ b/frontend/src/components/pageEditor/PageEditor.tsx @@ -265,9 +265,14 @@ const PageEditor = ({ // Update undo/redo state const updateUndoRedoState = useCallback(() => { - setCanUndo(undoManagerRef.current.canUndo()); - setCanRedo(undoManagerRef.current.canRedo()); - }, []); + const undoManager = undoManagerRef.current; + setCanUndo(undoManager.canUndo()); + setCanRedo(undoManager.canRedo()); + + if (!undoManager.hasHistory()) { + setHasUnsavedChanges(false); + } + }, [setHasUnsavedChanges]); // Set up undo manager callback useEffect(() => { @@ -1074,9 +1079,6 @@ const PageEditor = ({ {/* Pages Grid */} { diff --git a/frontend/src/components/pageEditor/commands/pageCommands.ts b/frontend/src/components/pageEditor/commands/pageCommands.ts index 63a4bf567..f3009aea5 100644 --- a/frontend/src/components/pageEditor/commands/pageCommands.ts +++ b/frontend/src/components/pageEditor/commands/pageCommands.ts @@ -905,6 +905,10 @@ export class UndoManager { return this.redoStack.length > 0; } + hasHistory(): boolean { + return this.undoStack.length > 0; + } + clear(): void { this.undoStack = []; this.redoStack = [];