refactor: improvements

This commit is contained in:
2026-03-12 18:14:21 +01:00
parent 51c96641f0
commit a0bf9c6b70
4 changed files with 123 additions and 29 deletions

View File

@@ -0,0 +1,46 @@
/**
* 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, and provides it to descendants.
*/
export function ViewportDisplayProvider({ children }: { children: React.ReactNode }) {
const { zoom } = useViewport()
const [displayMode, setDisplayMode] = useState<ViewportDisplayMode>(() =>
zoom <= CONTEXTUAL_ZOOM_THRESHOLD ? 'compact' : 'full'
)
const lastRef = useRef(displayMode)
useLayoutEffect(() => {
const low = CONTEXTUAL_ZOOM_THRESHOLD - HYSTERESIS
const high = CONTEXTUAL_ZOOM_THRESHOLD + HYSTERESIS
let next: ViewportDisplayMode = lastRef.current
if (zoom <= low) next = 'compact'
else if (zoom >= high) next = 'full'
if (next !== lastRef.current) {
lastRef.current = next
setDisplayMode(next)
}
}, [zoom])
return (
<ViewportDisplayContext.Provider value={displayMode}>
{children}
</ViewportDisplayContext.Provider>
)
}