Enhance DragDropGrid and PageEditor with improved undo manager functionality and scroll handling during drag operations

This commit is contained in:
Reece 2025-10-23 20:46:58 +01:00
parent be037b727f
commit ddefe81082
3 changed files with 36 additions and 11 deletions

View File

@ -23,12 +23,8 @@ interface DragDropItem {
interface DragDropGridProps<T extends DragDropItem> {
items: T[];
selectedItems: string[];
selectionMode: boolean;
isAnimating: boolean;
onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void;
renderItem: (item: T, index: number, refs: React.MutableRefObject<Map<string, HTMLDivElement>>, 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 = <T extends DragDropItem>({
const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map());
const containerRef = useRef<HTMLDivElement>(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 = <T extends DragDropItem>({
// 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 = <T extends DragDropItem>({
};
}, [hoveredItemId, dropSide, activeId, itemGap, zoomLevel]);
const handleWheelWhileDragging = useCallback((event: React.WheelEvent<HTMLDivElement>) => {
if (!activeId) {
return;
}
const scrollElement = getScrollElement();
if (!scrollElement) {
return;
}
scrollElement.scrollBy({
top: event.deltaY,
left: event.deltaX,
});
event.preventDefault();
}, [activeId, getScrollElement]);
return (
<DndContext
sensors={sensors}
@ -508,6 +526,7 @@ const DragDropGrid = <T extends DragDropItem>({
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onWheel={handleWheelWhileDragging}
style={{
// Basic container styles
width: '100%',

View File

@ -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 */}
<DragDropGrid
items={displayedPages}
selectedItems={selectedPageIds}
selectionMode={selectionMode}
isAnimating={isAnimating}
onReorderPages={handleReorderPages}
zoomLevel={zoomLevel}
getThumbnailData={(pageId) => {

View File

@ -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 = [];