({
zoomLevel,
zoomInTitle,
zoomOutTitle,
useContinuousZoom = false,
adjustZoom,
zoomInStep = 0.1,
zoomOutStep = -0.1,
onZoomIn,
onZoomOut,
}: ZoomControlsProps)
| 15 | } |
| 16 | |
| 17 | export function ZoomControls({ |
| 18 | zoomLevel, |
| 19 | zoomInTitle, |
| 20 | zoomOutTitle, |
| 21 | useContinuousZoom = false, |
| 22 | adjustZoom, |
| 23 | zoomInStep = 0.1, |
| 24 | zoomOutStep = -0.1, |
| 25 | onZoomIn, |
| 26 | onZoomOut, |
| 27 | }: ZoomControlsProps) { |
| 28 | const zoomIntervalRef = useRef<NodeJS.Timeout | null>(null) |
| 29 | |
| 30 | /** |
| 31 | * Start continuous zoom on mouse down |
| 32 | */ |
| 33 | const startContinuousZoom = (amount: number) => { |
| 34 | if (!useContinuousZoom || !adjustZoom) return |
| 35 | |
| 36 | // Clear any existing interval first |
| 37 | if (zoomIntervalRef.current) { |
| 38 | clearInterval(zoomIntervalRef.current) |
| 39 | } |
| 40 | |
| 41 | // Immediately apply first zoom adjustment |
| 42 | adjustZoom(amount) |
| 43 | |
| 44 | // Set up interval for continuous zooming |
| 45 | zoomIntervalRef.current = setInterval(() => { |
| 46 | adjustZoom(amount) |
| 47 | }, 150) // Adjust every 150ms while button is held down |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Stop continuous zoom on mouse up or mouse leave |
| 52 | */ |
| 53 | const stopContinuousZoom = () => { |
| 54 | if (zoomIntervalRef.current) { |
| 55 | clearInterval(zoomIntervalRef.current) |
| 56 | zoomIntervalRef.current = null |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | // Clean up interval on unmount |
| 61 | useEffect(() => { |
| 62 | return () => { |
| 63 | if (zoomIntervalRef.current) { |
| 64 | clearInterval(zoomIntervalRef.current) |
| 65 | } |
| 66 | } |
| 67 | }, []) |
| 68 | |
| 69 | return ( |
| 70 | <div className="flex items-center gap-2"> |
| 71 | <StandardTooltip content={zoomOutTitle}> |
| 72 | <IconButton |
| 73 | icon="zoom-out" |
| 74 | onClick={!useContinuousZoom ? onZoomOut || (() => adjustZoom?.(zoomOutStep)) : undefined} |
nothing calls this directly
no test coverage detected