mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 19:35:06 +03:00
- move navigation components to `apps/studio/components/layouts/Navigation` - add [FloatingMobileToolbar](https://github.com/supabase/supabase/pull/43444/changes#diff-3dffe47fd51ca851d612d8728e03b2dc344ec213d4f3a46a824d3fa32a7cc851) as quick access to tools such as search, assistant, inline editor, etc - behind feature flag and feature preview (true by default as it's a bit annoying to have to enable it all the time as previews are stored in local-storage) - fix sidebar panels closing on viewport resizing (regression from previous pr) https://github.com/user-attachments/assets/d6881e3b-5128-4306-bb82-3ca39c755dba <img width="986" height="697" alt="Screenshot 2026-03-12 at 12 40 11" src="https://github.com/user-attachments/assets/da8511e2-7d01-4237-b814-596031c747c5" />
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
import { useCallback, useRef, useState } from 'react'
|
|
|
|
import {
|
|
DRAG_THRESHOLD_PX,
|
|
getNextPosition,
|
|
type NavSize,
|
|
type Position,
|
|
type Viewport,
|
|
} from './FloatingMobileToolbar.utils'
|
|
|
|
type DragStartState = {
|
|
x: number
|
|
y: number
|
|
startX: number
|
|
startY: number
|
|
pointerId: number
|
|
}
|
|
|
|
export function useFloatingToolbarDrag(navRef: React.RefObject<HTMLElement | null>) {
|
|
const [position, setPosition] = useState<Position | null>(null)
|
|
const dragStartRef = useRef<DragStartState | null>(null)
|
|
|
|
const applyMove = useCallback(
|
|
(clientX: number, clientY: number) => {
|
|
const state = dragStartRef.current
|
|
if (!state) return
|
|
const rect = navRef.current?.getBoundingClientRect()
|
|
const viewport: Viewport = {
|
|
width: typeof window !== 'undefined' ? window.innerWidth : 0,
|
|
height: typeof window !== 'undefined' ? window.innerHeight : 0,
|
|
}
|
|
const navSize: NavSize = {
|
|
width: rect?.width ?? 200,
|
|
height: rect?.height ?? 48,
|
|
}
|
|
const next = getNextPosition(state, clientX, clientY, viewport, navSize, DRAG_THRESHOLD_PX)
|
|
if (next) setPosition(next)
|
|
},
|
|
[navRef]
|
|
)
|
|
|
|
const handlePointerDown = useCallback(
|
|
(e: React.PointerEvent) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
const rect = navRef.current?.getBoundingClientRect()
|
|
if (!rect) return
|
|
const currentX = position?.x ?? rect.left
|
|
const currentY = position?.y ?? rect.top
|
|
dragStartRef.current = {
|
|
x: currentX,
|
|
y: currentY,
|
|
startX: e.clientX,
|
|
startY: e.clientY,
|
|
pointerId: e.pointerId,
|
|
}
|
|
|
|
const onMove = (moveEvent: PointerEvent) => {
|
|
if (dragStartRef.current?.pointerId !== moveEvent.pointerId) return
|
|
const dist = Math.hypot(
|
|
moveEvent.clientX - dragStartRef.current.startX,
|
|
moveEvent.clientY - dragStartRef.current.startY
|
|
)
|
|
if (dist >= DRAG_THRESHOLD_PX) {
|
|
navRef.current?.setPointerCapture?.(moveEvent.pointerId)
|
|
}
|
|
applyMove(moveEvent.clientX, moveEvent.clientY)
|
|
}
|
|
const onUpOrCancel = (upEvent: PointerEvent) => {
|
|
if (dragStartRef.current?.pointerId !== upEvent.pointerId) return
|
|
;(upEvent.target as HTMLElement)?.releasePointerCapture?.(upEvent.pointerId)
|
|
window.removeEventListener('pointermove', onMove)
|
|
window.removeEventListener('pointerup', onUpOrCancel)
|
|
window.removeEventListener('pointercancel', onUpOrCancel)
|
|
dragStartRef.current = null
|
|
}
|
|
window.addEventListener('pointermove', onMove)
|
|
window.addEventListener('pointerup', onUpOrCancel)
|
|
window.addEventListener('pointercancel', onUpOrCancel)
|
|
},
|
|
[navRef, position, applyMove]
|
|
)
|
|
|
|
const handlePointerMove = useCallback(
|
|
(e: React.PointerEvent) => {
|
|
applyMove(e.clientX, e.clientY)
|
|
},
|
|
[applyMove]
|
|
)
|
|
|
|
return {
|
|
position,
|
|
dragStartRef,
|
|
handlePointerDown,
|
|
handlePointerMove,
|
|
}
|
|
}
|