104 lines
3.1 KiB
TypeScript
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,
|
|
}
|
|
}
|