fix: Improve TabBar pointer handling and state management

- Added logic to clear the settle timer when pointer events are triggered, enhancing responsiveness during drag-and-drop interactions.
- Implemented checks to ensure pointer events are only processed if they match the current drag state, preventing unintended actions.
- Introduced a new callback for handling lost pointer capture, ensuring proper state reset and cleanup when pointer capture is lost.

Made-with: Cursor
This commit is contained in:
syc0123 2026-03-03 17:07:04 +09:00
parent 2647031ef7
commit 52c6af472d
1 changed files with 18 additions and 0 deletions

View File

@ -285,6 +285,11 @@ export function TabBar() {
if ((e.target as HTMLElement).closest("button")) return; if ((e.target as HTMLElement).closest("button")) return;
if (dragState?.settling) return; if (dragState?.settling) return;
if (settleTimer.current) {
clearTimeout(settleTimer.current);
settleTimer.current = null;
}
e.preventDefault(); e.preventDefault();
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
@ -304,6 +309,7 @@ export function TabBar() {
const handlePointerMove = useCallback( const handlePointerMove = useCallback(
(e: React.PointerEvent) => { (e: React.PointerEvent) => {
if (!dragState || dragState.settling) return; if (!dragState || dragState.settling) return;
if (e.pointerId !== dragState.pointerId) return;
const bar = containerRef.current?.getBoundingClientRect(); const bar = containerRef.current?.getBoundingClientRect();
if (!bar) return; if (!bar) return;
@ -334,6 +340,7 @@ export function TabBar() {
const handlePointerUp = useCallback( const handlePointerUp = useCallback(
(e: React.PointerEvent) => { (e: React.PointerEvent) => {
if (!dragState || dragState.settling) return; if (!dragState || dragState.settling) return;
if (e.pointerId !== dragState.pointerId) return;
(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId); (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);
if (!dragState.activated) { if (!dragState.activated) {
@ -365,6 +372,16 @@ export function TabBar() {
[dragState, tabs, displayVisible, switchTab, updateTabOrder], [dragState, tabs, displayVisible, switchTab, updateTabOrder],
); );
const handleLostPointerCapture = useCallback(() => {
if (dragState && !dragState.settling) {
setDragState(null);
if (settleTimer.current) {
clearTimeout(settleTimer.current);
settleTimer.current = null;
}
}
}, [dragState]);
// ============================================================ // ============================================================
// 스타일 계산 // 스타일 계산
// ============================================================ // ============================================================
@ -471,6 +488,7 @@ export function TabBar() {
onPointerDown={(e) => handlePointerDown(e, tab.id, displayIndex)} onPointerDown={(e) => handlePointerDown(e, tab.id, displayIndex)}
onPointerMove={handlePointerMove} onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp} onPointerUp={handlePointerUp}
onLostPointerCapture={handleLostPointerCapture}
onContextMenu={(e) => handleContextMenu(e, tab.id)} onContextMenu={(e) => handleContextMenu(e, tab.id)}
className={cn( className={cn(
"group relative flex h-7 shrink-0 cursor-pointer items-center gap-0.5 rounded-t-md border border-b-0 px-3 select-none", "group relative flex h-7 shrink-0 cursor-pointer items-center gap-0.5 rounded-t-md border border-b-0 px-3 select-none",