fix: Fix tab reload/state loss whenever moving them to the rigbht
This commit is contained in:
@@ -720,6 +720,9 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
console.log(
|
||||||
|
`🔴 Terminal UNMOUNTING - this should NOT happen during drag!`,
|
||||||
|
);
|
||||||
isUnmountingRef.current = true;
|
isUnmountingRef.current = true;
|
||||||
shouldNotReconnectRef.current = true;
|
shouldNotReconnectRef.current = true;
|
||||||
isReconnectingRef.current = false;
|
isReconnectingRef.current = false;
|
||||||
@@ -742,10 +745,21 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
|
|||||||
}, [xtermRef, terminal]);
|
}, [xtermRef, terminal]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log(`📡 Terminal connection useEffect triggered:`, {
|
||||||
|
terminal: !!terminal,
|
||||||
|
hostConfig: !!hostConfig,
|
||||||
|
visible,
|
||||||
|
isConnected,
|
||||||
|
isConnecting,
|
||||||
|
});
|
||||||
|
|
||||||
if (!terminal || !hostConfig || !visible) return;
|
if (!terminal || !hostConfig || !visible) return;
|
||||||
|
|
||||||
if (isConnected || isConnecting) return;
|
if (isConnected || isConnecting) return;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`🔌 Initiating NEW connection - this should only happen on mount!`,
|
||||||
|
);
|
||||||
setIsConnecting(true);
|
setIsConnecting(true);
|
||||||
|
|
||||||
const readyFonts =
|
const readyFonts =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState, useMemo } from "react";
|
||||||
import { Terminal } from "@/ui/Desktop/Apps/Terminal/Terminal.tsx";
|
import { Terminal } from "@/ui/Desktop/Apps/Terminal/Terminal.tsx";
|
||||||
import { Server as ServerView } from "@/ui/Desktop/Apps/Server/Server.tsx";
|
import { Server as ServerView } from "@/ui/Desktop/Apps/Server/Server.tsx";
|
||||||
import { FileManager } from "@/ui/Desktop/Apps/File Manager/FileManager.tsx";
|
import { FileManager } from "@/ui/Desktop/Apps/File Manager/FileManager.tsx";
|
||||||
@@ -43,11 +43,15 @@ export function AppView({
|
|||||||
};
|
};
|
||||||
const { state: sidebarState } = useSidebar();
|
const { state: sidebarState } = useSidebar();
|
||||||
|
|
||||||
const terminalTabs = tabs.filter(
|
const terminalTabs = useMemo(
|
||||||
(tab: TabData) =>
|
() =>
|
||||||
tab.type === "terminal" ||
|
tabs.filter(
|
||||||
tab.type === "server" ||
|
(tab: TabData) =>
|
||||||
tab.type === "file_manager",
|
tab.type === "terminal" ||
|
||||||
|
tab.type === "server" ||
|
||||||
|
tab.type === "file_manager",
|
||||||
|
),
|
||||||
|
[tabs],
|
||||||
);
|
);
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
@@ -107,9 +111,61 @@ export function AppView({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const prevStateRef = useRef({
|
||||||
|
terminalTabsLength: terminalTabs.length,
|
||||||
|
currentTab,
|
||||||
|
splitScreenTabsStr: allSplitScreenTab.join(","),
|
||||||
|
terminalTabIds: terminalTabs.map((t) => t.id).join(","),
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
hideThenFit();
|
const prev = prevStateRef.current;
|
||||||
}, [currentTab, terminalTabs.length, allSplitScreenTab.join(",")]);
|
const currentTabIds = terminalTabs.map((t) => t.id).join(",");
|
||||||
|
|
||||||
|
const lengthChanged = prev.terminalTabsLength !== terminalTabs.length;
|
||||||
|
const currentTabChanged = prev.currentTab !== currentTab;
|
||||||
|
const splitChanged =
|
||||||
|
prev.splitScreenTabsStr !== allSplitScreenTab.join(",");
|
||||||
|
const tabIdsChanged = prev.terminalTabIds !== currentTabIds;
|
||||||
|
|
||||||
|
// Only trigger hideThenFit if tabs were added/removed (not just reordered)
|
||||||
|
// or if current tab or split screen changed
|
||||||
|
const isJustReorder =
|
||||||
|
!lengthChanged && tabIdsChanged && !currentTabChanged && !splitChanged;
|
||||||
|
|
||||||
|
console.log("AppView useEffect:", {
|
||||||
|
lengthChanged,
|
||||||
|
currentTabChanged,
|
||||||
|
splitChanged,
|
||||||
|
tabIdsChanged,
|
||||||
|
isJustReorder,
|
||||||
|
willCallHideThenFit:
|
||||||
|
(lengthChanged || currentTabChanged || splitChanged) && !isJustReorder,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
(lengthChanged || currentTabChanged || splitChanged) &&
|
||||||
|
!isJustReorder
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
"CALLING hideThenFit - this will set ready=false and cause Terminal isVisible to become false!",
|
||||||
|
);
|
||||||
|
hideThenFit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the ref for next comparison
|
||||||
|
prevStateRef.current = {
|
||||||
|
terminalTabsLength: terminalTabs.length,
|
||||||
|
currentTab,
|
||||||
|
splitScreenTabsStr: allSplitScreenTab.join(","),
|
||||||
|
terminalTabIds: currentTabIds,
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
currentTab,
|
||||||
|
terminalTabs.length,
|
||||||
|
allSplitScreenTab.join(","),
|
||||||
|
terminalTabs,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scheduleMeasureAndFit();
|
scheduleMeasureAndFit();
|
||||||
@@ -138,6 +194,14 @@ export function AppView({
|
|||||||
|
|
||||||
const HEADER_H = 28;
|
const HEADER_H = 28;
|
||||||
|
|
||||||
|
// Create a stable map of terminal IDs to preserve component identity
|
||||||
|
const terminalIdMapRef = useRef<Set<number>>(new Set());
|
||||||
|
|
||||||
|
// Track all terminal IDs that have ever existed
|
||||||
|
useEffect(() => {
|
||||||
|
terminalTabs.forEach((t) => terminalIdMapRef.current.add(t.id));
|
||||||
|
}, [terminalTabs]);
|
||||||
|
|
||||||
const renderTerminalsLayer = () => {
|
const renderTerminalsLayer = () => {
|
||||||
const styles: Record<number, React.CSSProperties> = {};
|
const styles: Record<number, React.CSSProperties> = {};
|
||||||
const splitTabs = terminalTabs.filter((tab: TabData) =>
|
const splitTabs = terminalTabs.filter((tab: TabData) =>
|
||||||
@@ -184,9 +248,13 @@ export function AppView({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render in a STABLE order by ID to prevent React from unmounting
|
||||||
|
// Sort by ID instead of array position
|
||||||
|
const sortedTerminalTabs = [...terminalTabs].sort((a, b) => a.id - b.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 z-[1]">
|
<div className="absolute inset-0 z-[1]">
|
||||||
{terminalTabs.map((t: TabData) => {
|
{sortedTerminalTabs.map((t: TabData) => {
|
||||||
const hasStyle = !!styles[t.id];
|
const hasStyle = !!styles[t.id];
|
||||||
const isVisible =
|
const isVisible =
|
||||||
hasStyle || (allSplitScreenTab.length === 0 && t.id === currentTab);
|
hasStyle || (allSplitScreenTab.length === 0 && t.id === currentTab);
|
||||||
@@ -202,6 +270,7 @@ export function AppView({
|
|||||||
} as React.CSSProperties);
|
} as React.CSSProperties);
|
||||||
|
|
||||||
const effectiveVisible = isVisible && ready;
|
const effectiveVisible = isVisible && ready;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={t.id} style={finalStyle}>
|
<div key={t.id} style={finalStyle}>
|
||||||
<div className="absolute inset-0 rounded-md bg-dark-bg">
|
<div className="absolute inset-0 rounded-md bg-dark-bg">
|
||||||
|
|||||||
@@ -153,11 +153,26 @@ export function TabProvider({ children }: TabProviderProps) {
|
|||||||
return tabs.find((tab) => tab.id === tabId);
|
return tabs.find((tab) => tab.id === tabId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isReorderingRef = useRef(false);
|
||||||
|
|
||||||
const reorderTabs = (fromIndex: number, toIndex: number) => {
|
const reorderTabs = (fromIndex: number, toIndex: number) => {
|
||||||
|
if (isReorderingRef.current) return;
|
||||||
|
|
||||||
|
isReorderingRef.current = true;
|
||||||
|
|
||||||
setTabs((prev) => {
|
setTabs((prev) => {
|
||||||
const newTabs = [...prev];
|
const newTabs = [...prev];
|
||||||
const [movedTab] = newTabs.splice(fromIndex, 1);
|
const [movedTab] = newTabs.splice(fromIndex, 1);
|
||||||
newTabs.splice(toIndex, 0, movedTab);
|
|
||||||
|
const maxIndex = newTabs.length;
|
||||||
|
const safeToIndex = Math.min(toIndex, maxIndex);
|
||||||
|
|
||||||
|
newTabs.splice(safeToIndex, 0, movedTab);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
isReorderingRef.current = false;
|
||||||
|
}, 100);
|
||||||
|
|
||||||
return newTabs;
|
return newTabs;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { flushSync } from "react-dom";
|
||||||
import { useSidebar } from "@/components/ui/sidebar.tsx";
|
import { useSidebar } from "@/components/ui/sidebar.tsx";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { ChevronDown, ChevronUpIcon, Hammer, FileText } from "lucide-react";
|
import { ChevronDown, ChevronUpIcon, Hammer, FileText } from "lucide-react";
|
||||||
@@ -58,7 +59,8 @@ export function TopNavbar({
|
|||||||
const [isRecording, setIsRecording] = useState(false);
|
const [isRecording, setIsRecording] = useState(false);
|
||||||
const [selectedTabIds, setSelectedTabIds] = useState<number[]>([]);
|
const [selectedTabIds, setSelectedTabIds] = useState<number[]>([]);
|
||||||
const [snippetsSidebarOpen, setSnippetsSidebarOpen] = useState(false);
|
const [snippetsSidebarOpen, setSnippetsSidebarOpen] = useState(false);
|
||||||
const [justDroppedTabId, setJustDroppedTabId] = useState<number | null>(null); // New state variable
|
const [justDroppedTabId, setJustDroppedTabId] = useState<number | null>(null);
|
||||||
|
const [isInDropAnimation, setIsInDropAnimation] = useState(false);
|
||||||
const [dragState, setDragState] = useState<{
|
const [dragState, setDragState] = useState<{
|
||||||
draggedId: number | null;
|
draggedId: number | null;
|
||||||
draggedIndex: number | null;
|
draggedIndex: number | null;
|
||||||
@@ -74,6 +76,7 @@ export function TopNavbar({
|
|||||||
});
|
});
|
||||||
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
||||||
const tabRefs = React.useRef<Map<number, HTMLDivElement>>(new Map());
|
const tabRefs = React.useRef<Map<number, HTMLDivElement>>(new Map());
|
||||||
|
const isProcessingDropRef = React.useRef(false);
|
||||||
|
|
||||||
const prevTabsRef = React.useRef<TabData[]>([]);
|
const prevTabsRef = React.useRef<TabData[]>([]);
|
||||||
|
|
||||||
@@ -256,27 +259,9 @@ export function TopNavbar({
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (prevTabsRef.current.length > 0 && tabs !== prevTabsRef.current) {
|
if (prevTabsRef.current.length > 0 && tabs !== prevTabsRef.current) {
|
||||||
// Check if tabs actually changed
|
|
||||||
console.log("Tabs AFTER reorder (IDs and references):");
|
|
||||||
tabs.forEach((newTab, newIdx) => {
|
|
||||||
const oldTab = prevTabsRef.current.find((t) => t.id === newTab.id);
|
|
||||||
console.log(
|
|
||||||
` [${newIdx}] ID: ${newTab.id}, Ref:`,
|
|
||||||
newTab,
|
|
||||||
`(Old Ref:`,
|
|
||||||
oldTab,
|
|
||||||
`)`,
|
|
||||||
);
|
|
||||||
if (oldTab && oldTab !== newTab) {
|
|
||||||
console.warn(` Tab ID ${newTab.id} object reference CHANGED!`);
|
|
||||||
} else if (oldTab && oldTab === newTab) {
|
|
||||||
console.info(` Tab ID ${newTab.id} object reference PRESERVED.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Clear prevTabsRef.current only after the comparison is done
|
|
||||||
prevTabsRef.current = [];
|
prevTabsRef.current = [];
|
||||||
}
|
}
|
||||||
}, [tabs]); // Depend only on tabs
|
}, [tabs]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (justDroppedTabId !== null) {
|
if (justDroppedTabId !== null) {
|
||||||
@@ -286,9 +271,6 @@ export function TopNavbar({
|
|||||||
}, [justDroppedTabId]);
|
}, [justDroppedTabId]);
|
||||||
|
|
||||||
const handleDragStart = (e: React.DragEvent, index: number) => {
|
const handleDragStart = (e: React.DragEvent, index: number) => {
|
||||||
console.log("Drag start:", index, e.clientX);
|
|
||||||
|
|
||||||
// Create transparent drag image
|
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src =
|
img.src =
|
||||||
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
||||||
@@ -304,11 +286,9 @@ export function TopNavbar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDrag = (e: React.DragEvent) => {
|
const handleDrag = (e: React.DragEvent) => {
|
||||||
if (e.clientX === 0) return; // Skip the final drag event
|
if (e.clientX === 0) return;
|
||||||
if (dragState.draggedIndex === null) return;
|
if (dragState.draggedIndex === null) return;
|
||||||
|
|
||||||
console.log("Dragging:", e.clientX);
|
|
||||||
|
|
||||||
setDragState((prev) => ({
|
setDragState((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
currentX: e.clientX,
|
currentX: e.clientX,
|
||||||
@@ -370,7 +350,7 @@ export function TopNavbar({
|
|||||||
// Moving right - find the rightmost tab whose midpoint we've passed
|
// Moving right - find the rightmost tab whose midpoint we've passed
|
||||||
for (let i = draggedIndex + 1; i < tabBoundaries.length; i++) {
|
for (let i = draggedIndex + 1; i < tabBoundaries.length; i++) {
|
||||||
if (draggedCenter > tabBoundaries[i].mid) {
|
if (draggedCenter > tabBoundaries[i].mid) {
|
||||||
newTargetIndex = i; // Reverted from i + 1 to i
|
newTargetIndex = i;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -385,7 +365,9 @@ export function TopNavbar({
|
|||||||
const containerRect = containerRef.current.getBoundingClientRect();
|
const containerRect = containerRef.current.getBoundingClientRect();
|
||||||
const lastTabEndInContainer = lastTabRect.right - containerRect.left;
|
const lastTabEndInContainer = lastTabRect.right - containerRect.left;
|
||||||
if (currentX > lastTabEndInContainer) {
|
if (currentX > lastTabEndInContainer) {
|
||||||
newTargetIndex = tabBoundaries.length; // Insert at the very end
|
// When dragging past the last tab, insert at the very end
|
||||||
|
// Use the last valid index (length - 1) not length itself
|
||||||
|
newTargetIndex = lastTabIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,40 +404,52 @@ export function TopNavbar({
|
|||||||
|
|
||||||
const handleDrop = (e: React.DragEvent) => {
|
const handleDrop = (e: React.DragEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Drop:", dragState);
|
|
||||||
|
|
||||||
if (
|
if (isProcessingDropRef.current) return;
|
||||||
dragState.draggedIndex !== null &&
|
isProcessingDropRef.current = true;
|
||||||
dragState.targetIndex !== null &&
|
|
||||||
dragState.draggedIndex !== dragState.targetIndex
|
const fromIndex = dragState.draggedIndex;
|
||||||
) {
|
const toIndex = dragState.targetIndex;
|
||||||
console.log("Tabs before reorder (IDs and references):");
|
const draggedId = dragState.draggedId;
|
||||||
tabs.forEach((tab, idx) =>
|
|
||||||
console.log(` [${idx}] ID: ${tab.id}, Ref:`, tab),
|
if (fromIndex !== null && toIndex !== null && fromIndex !== toIndex) {
|
||||||
);
|
prevTabsRef.current = tabs;
|
||||||
prevTabsRef.current = tabs; // Store current tabs before reorder
|
|
||||||
reorderTabs(dragState.draggedIndex, dragState.targetIndex);
|
// Set animation flag and clear drag state synchronously
|
||||||
if (dragState.draggedId !== null) {
|
flushSync(() => {
|
||||||
setJustDroppedTabId(dragState.draggedId);
|
setIsInDropAnimation(true);
|
||||||
|
setDragState({
|
||||||
|
draggedId: null,
|
||||||
|
draggedIndex: null,
|
||||||
|
startX: 0,
|
||||||
|
currentX: 0,
|
||||||
|
targetIndex: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
reorderTabs(fromIndex, toIndex);
|
||||||
|
|
||||||
|
if (draggedId !== null) {
|
||||||
|
setJustDroppedTabId(draggedId);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setDragState({
|
||||||
|
draggedId: null,
|
||||||
|
draggedIndex: null,
|
||||||
|
startX: 0,
|
||||||
|
currentX: 0,
|
||||||
|
targetIndex: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Immediately reset drag state after drop to ensure a single re-render
|
|
||||||
// with updated tabs and cleared drag state.
|
setTimeout(() => {
|
||||||
setDragState({
|
isProcessingDropRef.current = false;
|
||||||
draggedId: null,
|
setIsInDropAnimation(false);
|
||||||
draggedIndex: null,
|
}, 50);
|
||||||
startX: 0,
|
|
||||||
currentX: 0,
|
|
||||||
targetIndex: null,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragEnd = () => {
|
const handleDragEnd = () => {
|
||||||
console.log("Drag end:", dragState);
|
setIsInDropAnimation(false);
|
||||||
|
|
||||||
// Immediately reset drag state. If a drop occurred, handleDrop has already
|
|
||||||
// initiated the state clear. If the drag was cancelled (e.g., dropped
|
|
||||||
// outside a valid target), this clears the drag state.
|
|
||||||
setDragState({
|
setDragState({
|
||||||
draggedId: null,
|
draggedId: null,
|
||||||
draggedIndex: null,
|
draggedIndex: null,
|
||||||
@@ -533,55 +527,46 @@ export function TopNavbar({
|
|||||||
? dragState.currentX - dragState.startX
|
? dragState.currentX - dragState.startX
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
// Diagnostic logs
|
|
||||||
if (dragState.draggedIndex !== null) {
|
|
||||||
console.log(
|
|
||||||
`Tab ID: ${tab.id}, Index: ${index}, isDraggingThisTab: ${isDraggingThisTab}, draggedOriginalIndex: ${dragState.draggedIndex}, currentTargetIndex: ${dragState.targetIndex}, isDroppedAndSnapping: ${isDroppedAndSnapping}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate transform
|
|
||||||
let transform = "";
|
let transform = "";
|
||||||
if (isDraggingThisTab) {
|
|
||||||
transform = `translateX(${dragOffset}px)`;
|
|
||||||
} else if (
|
|
||||||
dragState.draggedIndex !== null &&
|
|
||||||
dragState.targetIndex !== null
|
|
||||||
) {
|
|
||||||
const draggedOriginalIndex = dragState.draggedIndex;
|
|
||||||
const currentTargetIndex = dragState.targetIndex;
|
|
||||||
|
|
||||||
// Determine if this tab should shift left or right
|
// Skip all transforms if we just dropped to prevent glitches
|
||||||
if (
|
if (!isInDropAnimation) {
|
||||||
draggedOriginalIndex < currentTargetIndex && // Dragging rightwards
|
if (isDraggingThisTab) {
|
||||||
index > draggedOriginalIndex && // This tab is to the right of the original position
|
transform = `translateX(${dragOffset}px)`;
|
||||||
index <= currentTargetIndex // This tab is at or before the target position
|
|
||||||
) {
|
|
||||||
// Shift left to make space
|
|
||||||
const draggedTabWidth =
|
|
||||||
tabRefs.current
|
|
||||||
.get(draggedOriginalIndex)
|
|
||||||
?.getBoundingClientRect().width || 0;
|
|
||||||
const gap = 4;
|
|
||||||
transform = `translateX(-${draggedTabWidth + gap}px)`;
|
|
||||||
} else if (
|
} else if (
|
||||||
draggedOriginalIndex > currentTargetIndex && // Dragging leftwards
|
dragState.draggedIndex !== null &&
|
||||||
index >= currentTargetIndex && // This tab is at or after the target position
|
dragState.targetIndex !== null
|
||||||
index < draggedOriginalIndex // This tab is to the left of the original position
|
|
||||||
) {
|
) {
|
||||||
// Shift right to make space
|
const draggedOriginalIndex = dragState.draggedIndex;
|
||||||
const draggedTabWidth =
|
const currentTargetIndex = dragState.targetIndex;
|
||||||
tabRefs.current
|
|
||||||
.get(draggedOriginalIndex)
|
|
||||||
?.getBoundingClientRect().width || 0;
|
|
||||||
const gap = 4;
|
|
||||||
transform = `translateX(${draggedTabWidth + gap}px)`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diagnostic log for transform
|
// Determine if this tab should shift left or right
|
||||||
if (dragState.draggedIndex !== null) {
|
if (
|
||||||
console.log(` Tab ID: ${tab.id}, Transform: ${transform}`);
|
draggedOriginalIndex < currentTargetIndex && // Dragging rightwards
|
||||||
|
index > draggedOriginalIndex && // This tab is to the right of the original position
|
||||||
|
index <= currentTargetIndex // This tab is at or before the target position
|
||||||
|
) {
|
||||||
|
// Shift left to make space
|
||||||
|
const draggedTabWidth =
|
||||||
|
tabRefs.current
|
||||||
|
.get(draggedOriginalIndex)
|
||||||
|
?.getBoundingClientRect().width || 0;
|
||||||
|
const gap = 4;
|
||||||
|
transform = `translateX(-${draggedTabWidth + gap}px)`;
|
||||||
|
} else if (
|
||||||
|
draggedOriginalIndex > currentTargetIndex && // Dragging leftwards
|
||||||
|
index >= currentTargetIndex && // This tab is at or after the target position
|
||||||
|
index < draggedOriginalIndex // This tab is to the left of the original position
|
||||||
|
) {
|
||||||
|
// Shift right to make space
|
||||||
|
const draggedTabWidth =
|
||||||
|
tabRefs.current
|
||||||
|
.get(draggedOriginalIndex)
|
||||||
|
?.getBoundingClientRect().width || 0;
|
||||||
|
const gap = 4;
|
||||||
|
transform = `translateX(${draggedTabWidth + gap}px)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -606,7 +591,9 @@ export function TopNavbar({
|
|||||||
style={{
|
style={{
|
||||||
transform,
|
transform,
|
||||||
transition:
|
transition:
|
||||||
isDraggingThisTab || isDroppedAndSnapping
|
isDraggingThisTab ||
|
||||||
|
isDroppedAndSnapping ||
|
||||||
|
isInDropAnimation
|
||||||
? "none"
|
? "none"
|
||||||
: "transform 200ms ease-out",
|
: "transform 200ms ease-out",
|
||||||
zIndex: isDraggingThisTab ? 1000 : 1,
|
zIndex: isDraggingThisTab ? 1000 : 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user