mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-12-30 20:06:30 +01:00
Fix reorder after merge bug
This commit is contained in:
parent
bc71de599e
commit
7b5a2bfbcd
@ -26,6 +26,8 @@ interface DragDropItem {
|
||||
id: string;
|
||||
splitAfter?: boolean;
|
||||
isPlaceholder?: boolean;
|
||||
originalFileId?: string;
|
||||
pageNumber?: number;
|
||||
}
|
||||
|
||||
interface DragDropGridProps<T extends DragDropItem> {
|
||||
@ -34,6 +36,7 @@ interface DragDropGridProps<T extends DragDropItem> {
|
||||
renderItem: (item: T, index: number, refs: React.MutableRefObject<Map<string, HTMLDivElement>>, boxSelectedIds: string[], clearBoxSelection: () => void, getBoxSelection: () => string[], activeId: string | null, activeDragIds: string[], justMoved: boolean, isOver: boolean, dragHandleProps?: any, zoomLevel?: number) => React.ReactNode;
|
||||
getThumbnailData?: (itemId: string) => { src: string; rotation: number } | null;
|
||||
zoomLevel?: number;
|
||||
selectedFileIds?: string[];
|
||||
}
|
||||
|
||||
type DropSide = 'left' | 'right' | null;
|
||||
@ -196,11 +199,14 @@ interface DraggableItemProps<T extends DragDropItem> {
|
||||
}
|
||||
|
||||
const DraggableItem = <T extends DragDropItem>({ item, index, itemRefs, boxSelectedPageIds, clearBoxSelection, getBoxSelection, activeId, activeDragIds, justMoved, getThumbnailData, renderItem, onUpdateDropTarget, zoomLevel }: DraggableItemProps<T>) => {
|
||||
const isPlaceholder = Boolean(item.isPlaceholder);
|
||||
const pageNumber = (item as any).pageNumber ?? index + 1;
|
||||
const { attributes, listeners, setNodeRef: setDraggableRef } = useDraggable({
|
||||
id: item.id,
|
||||
disabled: isPlaceholder,
|
||||
data: {
|
||||
index,
|
||||
pageNumber: index + 1,
|
||||
pageNumber,
|
||||
getThumbnail: () => {
|
||||
if (getThumbnailData) {
|
||||
const data = getThumbnailData(item.id);
|
||||
@ -252,6 +258,7 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
onReorderPages,
|
||||
getThumbnailData,
|
||||
zoomLevel = 1.0,
|
||||
selectedFileIds,
|
||||
}: DragDropGridProps<T>) => {
|
||||
const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map());
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@ -263,16 +270,37 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
const { filteredItems: visibleItems, filteredToOriginalIndex } = useMemo(() => {
|
||||
const filtered: T[] = [];
|
||||
const indexMap: number[] = [];
|
||||
const selectedIds =
|
||||
selectedFileIds && selectedFileIds.length > 0 ? new Set(selectedFileIds) : null;
|
||||
|
||||
items.forEach((item, index) => {
|
||||
if (!item.isPlaceholder) {
|
||||
filtered.push(item);
|
||||
indexMap.push(index);
|
||||
const isPlaceholder = Boolean(item.isPlaceholder);
|
||||
if (isPlaceholder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const belongsToVisibleFile =
|
||||
!selectedIds || !item.originalFileId || selectedIds.has(item.originalFileId);
|
||||
|
||||
if (!belongsToVisibleFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.push(item);
|
||||
indexMap.push(index);
|
||||
});
|
||||
|
||||
return { filteredItems: filtered, filteredToOriginalIndex: indexMap };
|
||||
}, [items]);
|
||||
}, [items, selectedFileIds]);
|
||||
|
||||
useEffect(() => {
|
||||
const visibleIdSet = new Set(visibleItems.map(item => item.id));
|
||||
itemRefs.current.forEach((_, pageId) => {
|
||||
if (!visibleIdSet.has(pageId)) {
|
||||
itemRefs.current.delete(pageId);
|
||||
}
|
||||
});
|
||||
}, [visibleItems]);
|
||||
|
||||
// Box selection state
|
||||
const [boxSelectStart, setBoxSelectStart] = useState<{ x: number; y: number } | null>(null);
|
||||
@ -396,7 +424,7 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
// Re-measure virtualizer when zoom or items per row changes
|
||||
useEffect(() => {
|
||||
rowVirtualizer.measure();
|
||||
}, [zoomLevel, itemsPerRow]);
|
||||
}, [zoomLevel, itemsPerRow, visibleItems.length]);
|
||||
|
||||
// Cleanup highlight timeout on unmount
|
||||
useEffect(() => {
|
||||
@ -530,7 +558,6 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
// Handle drag end
|
||||
const handleDragEnd = useCallback((event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
|
||||
const finalDropSide = dropSide;
|
||||
setActiveId(null);
|
||||
setDragPreview(null);
|
||||
@ -541,9 +568,10 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data from hooks
|
||||
const activeData = active.data.current;
|
||||
if (!activeData) return;
|
||||
if (!activeData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourcePageNumber = activeData.pageNumber;
|
||||
|
||||
@ -557,7 +585,9 @@ const DragDropGrid = <T extends DragDropItem>({
|
||||
overData ? overData.index : null
|
||||
);
|
||||
|
||||
if (targetIndex === null) return;
|
||||
if (targetIndex === null) {
|
||||
return;
|
||||
}
|
||||
if (targetIndex < 0) targetIndex = 0;
|
||||
if (targetIndex > items.length) targetIndex = items.length;
|
||||
|
||||
|
||||
@ -453,6 +453,7 @@ const PageEditor = ({
|
||||
items={displayedPages}
|
||||
onReorderPages={handleReorderPages}
|
||||
zoomLevel={zoomLevel}
|
||||
selectedFileIds={selectedFileIds}
|
||||
getThumbnailData={(pageId) => {
|
||||
const page = displayDocument.pages.find(p => p.id === pageId);
|
||||
if (!page?.thumbnail) return null;
|
||||
@ -520,6 +521,3 @@ const PageEditor = ({
|
||||
};
|
||||
|
||||
export default PageEditor;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ export interface PageDocumentHook {
|
||||
*/
|
||||
export function usePageDocument(): PageDocumentHook {
|
||||
const { state, selectors } = useFileState();
|
||||
const { fileOrder } = usePageEditor();
|
||||
const { fileOrder, currentPages } = usePageEditor();
|
||||
|
||||
// Use PageEditorContext's fileOrder instead of FileContext's global order
|
||||
// This ensures the page editor respects its own workspace ordering
|
||||
@ -48,6 +48,10 @@ export function usePageDocument(): PageDocumentHook {
|
||||
const processedFileTotalPages = primaryStirlingFileStub?.processedFile?.totalPages;
|
||||
|
||||
// Compute merged document with stable signature (prevents infinite loops)
|
||||
const currentPagesSignature = useMemo(() => {
|
||||
return currentPages ? currentPages.map(page => page.id).join(',') : '';
|
||||
}, [currentPages]);
|
||||
|
||||
const mergedPdfDocument = useMemo((): PDFDocument | null => {
|
||||
if (activeFileIds.length === 0) return null;
|
||||
|
||||
@ -201,6 +205,22 @@ export function usePageDocument(): PageDocumentHook {
|
||||
pageNumber: index + 1,
|
||||
}));
|
||||
|
||||
const currentPagesSet = currentPages ? new Set(currentPages.map(page => page.id)) : null;
|
||||
if (currentPagesSet && currentPagesSet.size === pages.length) {
|
||||
const sameIds = pages.every(page => currentPagesSet.has(page.id));
|
||||
if (sameIds) {
|
||||
const mergedById = new Map(pages.map(page => [page.id, page]));
|
||||
pages = currentPages.map((currentPage, index) => {
|
||||
const source = mergedById.get(currentPage.id);
|
||||
const mergedPage = source ? { ...source, ...currentPage } : currentPage;
|
||||
return {
|
||||
...mergedPage,
|
||||
pageNumber: index + 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const mergedDoc: PDFDocument = {
|
||||
id: activeFileIds.join('-'),
|
||||
name,
|
||||
@ -210,7 +230,7 @@ export function usePageDocument(): PageDocumentHook {
|
||||
};
|
||||
|
||||
return mergedDoc;
|
||||
}, [activeFileIds, primaryFileId, primaryStirlingFileStub, processedFilePages, processedFileTotalPages, selectors, activeFilesSignature, selectedFileIdsKey, state.ui.selectedFileIds, allFileIds]);
|
||||
}, [activeFileIds, primaryFileId, primaryStirlingFileStub, processedFilePages, processedFileTotalPages, selectors, activeFilesSignature, selectedFileIdsKey, state.ui.selectedFileIds, allFileIds, currentPagesSignature, currentPages]);
|
||||
|
||||
// Large document detection for smart loading
|
||||
const isVeryLargeDocument = useMemo(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user