ultisuite-client/hooks/use-sidebar-nav-drag.ts
2026-05-20 16:01:08 +02:00

104 lines
3.1 KiB
TypeScript

"use client"
import { useCallback, useRef, type Dispatch, type SetStateAction } from "react"
import type { SidebarNavDragPayload, SidebarNavDropPlacement } from "@/lib/sidebar-nav-dnd"
import {
markNavDragSource,
setNavDropIndicator,
unmarkNavDragSource,
} from "@/components/gmail/sidebar/sidebar-nav-primitives"
export function useSidebarNavDrag(opts: {
reorderLabelRows: (
sourceId: string,
targetId: string,
placement: "before" | "after"
) => void
moveFolderRelative: (
sourceId: string,
targetId: string,
placement: SidebarNavDropPlacement
) => void
setExpandedFolderIds: Dispatch<SetStateAction<Set<string>>>
}) {
const { reorderLabelRows, moveFolderRelative, setExpandedFolderIds } = opts
const navDragRef = useRef<SidebarNavDragPayload | null>(null)
const navDragSourceElRef = useRef<HTMLElement | null>(null)
const navDropTargetElRef = useRef<HTMLElement | null>(null)
const navDropPlacementRef = useRef<SidebarNavDropPlacement | null>(null)
const beginNavDrag = useCallback(
(payload: SidebarNavDragPayload, sourceEl: HTMLElement | null) => {
navDragRef.current = payload
navDragSourceElRef.current = sourceEl
markNavDragSource(sourceEl)
},
[]
)
const clearNavDrag = useCallback(() => {
unmarkNavDragSource(navDragSourceElRef.current)
setNavDropIndicator(navDropTargetElRef.current, null)
navDragRef.current = null
navDragSourceElRef.current = null
navDropTargetElRef.current = null
navDropPlacementRef.current = null
}, [])
const updateNavDropTarget = useCallback(
(el: HTMLElement, placement: SidebarNavDropPlacement) => {
if (navDropTargetElRef.current !== el) {
setNavDropIndicator(navDropTargetElRef.current, null)
}
navDropTargetElRef.current = el
navDropPlacementRef.current = placement
setNavDropIndicator(el, placement)
},
[]
)
const clearNavDropTarget = useCallback((el: HTMLElement) => {
if (navDropTargetElRef.current === el) {
setNavDropIndicator(el, null)
navDropTargetElRef.current = null
navDropPlacementRef.current = null
}
}, [])
const commitNavDrop = useCallback(
(
payload: SidebarNavDragPayload,
targetId: string,
placement: SidebarNavDropPlacement,
targetKind: "label" | "folder"
) => {
clearNavDrag()
if (payload.id === targetId && placement !== "inside") return
if (targetKind === "label" && payload.kind === "label") {
if (placement === "inside") return
reorderLabelRows(payload.id, targetId, placement)
} else if (targetKind === "folder" && payload.kind === "folder") {
moveFolderRelative(payload.id, targetId, placement)
if (placement === "inside") {
setExpandedFolderIds((prev) => {
const next = new Set(prev)
next.add(targetId)
return next
})
}
}
},
[clearNavDrag, moveFolderRelative, reorderLabelRows, setExpandedFolderIds]
)
return {
navDragRef,
navDropPlacementRef,
beginNavDrag,
clearNavDrag,
updateNavDropTarget,
clearNavDropTarget,
commitNavDrop,
}
}