56 lines
1.9 KiB
TypeScript
56 lines
1.9 KiB
TypeScript
/**
|
|
* Single subscriber for viewport zoom: one component (ViewportDisplayProvider)
|
|
* subscribes to useViewport() and provides displayMode so contextual nodes
|
|
* don't each subscribe to viewport and re-render on every pan/zoom.
|
|
*/
|
|
|
|
import React, { useLayoutEffect, useRef, useState } from 'react'
|
|
import { useViewport } from '@xyflow/react'
|
|
import { CONTEXTUAL_ZOOM_THRESHOLD } from '@/app/canvas/ContextualZoomNode'
|
|
|
|
export type ViewportDisplayMode = 'compact' | 'full'
|
|
|
|
const HYSTERESIS = 0.02
|
|
|
|
const ViewportDisplayContext = React.createContext<ViewportDisplayMode>('full')
|
|
export { ViewportDisplayContext }
|
|
|
|
/**
|
|
* Must be rendered inside ReactFlowProvider. Subscribes to viewport once,
|
|
* maps zoom to displayMode with hysteresis. Throttles updates via rAF to avoid
|
|
* re-rendering all contextual nodes on every zoom tick.
|
|
*/
|
|
export function ViewportDisplayProvider({ children }: { children: React.ReactNode }) {
|
|
const { zoom } = useViewport()
|
|
const [displayMode, setDisplayMode] = useState<ViewportDisplayMode>(() =>
|
|
zoom <= CONTEXTUAL_ZOOM_THRESHOLD ? 'compact' : 'full'
|
|
)
|
|
const lastModeRef = useRef(displayMode)
|
|
const zoomRef = useRef(zoom)
|
|
const rafRef = useRef<number | null>(null)
|
|
zoomRef.current = zoom
|
|
|
|
useLayoutEffect(() => {
|
|
if (rafRef.current !== null) return
|
|
rafRef.current = requestAnimationFrame(() => {
|
|
rafRef.current = null
|
|
const z = zoomRef.current
|
|
const low = CONTEXTUAL_ZOOM_THRESHOLD - HYSTERESIS
|
|
const high = CONTEXTUAL_ZOOM_THRESHOLD + HYSTERESIS
|
|
let next: ViewportDisplayMode = lastModeRef.current
|
|
if (z <= low) next = 'compact'
|
|
else if (z >= high) next = 'full'
|
|
if (next !== lastModeRef.current) {
|
|
lastModeRef.current = next
|
|
setDisplayMode(next)
|
|
}
|
|
})
|
|
}, [zoom])
|
|
|
|
return (
|
|
<ViewportDisplayContext.Provider value={displayMode}>
|
|
{children}
|
|
</ViewportDisplayContext.Provider>
|
|
)
|
|
}
|