Fix compare tool file selection and other files improvements (#6133)

This commit is contained in:
Anthony Stirling
2026-04-20 12:53:37 +01:00
committed by GitHub
parent 30aff3236f
commit b4b196556d
15 changed files with 522 additions and 20 deletions
@@ -1,4 +1,5 @@
import { useState, useCallback, useRef, useMemo, useEffect } from "react";
import { flushSync } from "react-dom";
import { Text, Center, Box, LoadingOverlay, Stack } from "@mantine/core";
import { Dropzone } from "@mantine/dropzone";
import {
@@ -306,8 +307,23 @@ const FileEditor = ({
// Insert files at the calculated position
newOrder.splice(insertIndex, 0, ...filesToMove);
// Update file order
reorderFiles(newOrder);
// Animate the reorder using the View Transitions API where available.
// Each FileEditorThumbnail carries a stable `view-transition-name`, so
// the browser snapshots each card before and after the DOM reorder and
// interpolates the positions automatically. `flushSync` forces React to
// apply the reorderFiles dispatch synchronously inside the transition
// callback so the BEFORE/AFTER snapshots capture the correct frames.
const applyReorder = () => reorderFiles(newOrder);
const docWithViewTransition = document as Document & {
startViewTransition?: (cb: () => void) => unknown;
};
if (typeof docWithViewTransition.startViewTransition === "function") {
docWithViewTransition.startViewTransition(() => {
flushSync(applyReorder);
});
} else {
applyReorder();
}
// Update status
const moveCount = filesToMove.length;
@@ -99,6 +99,7 @@ const FileEditorThumbnail = ({
// ---- Drag state ----
const [isDragging, setIsDragging] = useState(false);
const [isDragOver, setIsDragOver] = useState(false);
const dragElementRef = useRef<HTMLDivElement | null>(null);
const [showHoverMenu, setShowHoverMenu] = useState(false);
const isMobile = useIsMobile();
@@ -210,7 +211,10 @@ const FileEditorThumbnail = ({
const sourceData = source.data;
return sourceData.type === "file" && sourceData.fileId !== file.id;
},
onDragEnter: () => setIsDragOver(true),
onDragLeave: () => setIsDragOver(false),
onDrop: ({ source }) => {
setIsDragOver(false);
const sourceData = source.data;
if (sourceData.type === "file" && onReorderFiles) {
const sourceFileId = sourceData.fileId as FileId;
@@ -435,7 +439,22 @@ const FileEditorThumbnail = ({
data-selected={isSelected}
data-supported={isSupported}
className={`${styles.card} w-[18rem] h-[22rem] select-none flex flex-col shadow-sm transition-all relative`}
style={{ opacity: isDragging ? 0.9 : 1 }}
style={
{
opacity: isDragging ? 0.4 : 1,
outline: isDragOver
? "3px dashed var(--mantine-color-blue-5, #3b82f6)"
: undefined,
outlineOffset: isDragOver ? "2px" : undefined,
transform: isDragOver ? "scale(1.02)" : undefined,
transition:
"outline 120ms ease, transform 120ms ease, opacity 120ms ease",
// Tag each card with a stable, unique view-transition-name so the
// browser can animate the reorder (see FileEditor.handleReorderFiles,
// which dispatches reorderFiles inside document.startViewTransition).
viewTransitionName: `file-card-${file.id}`,
} as React.CSSProperties
}
tabIndex={0}
role="listitem"
aria-selected={isSelected}