Files
cinny/src/app/hooks/usePan.ts
T
Lotus Bot fa50a45e84
CI / Build & Quality Checks (push) Failing after 5m12s
chore: prettier format all files, brotli, Sentry release tagging, CI gates
Prettier: auto-formatted 103 files to fix baseline. Prettier check in CI
  is now a hard gate (removed continue-on-error).

Brotli: installed libnginx-mod-http-brotli-filter/static. Enabled in nginx
  with brotli_static on for pre-compressed assets and comp_level 6.

Sentry releases: deploy script now exports VITE_APP_VERSION=<git-short-sha>
  before building so each Sentry release maps to an exact commit.
  CI also passes github.sha as VITE_APP_VERSION.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 20:49:33 -04:00

73 lines
1.7 KiB
TypeScript

import { MouseEventHandler, useEffect, useState } from 'react';
export type Pan = {
translateX: number;
translateY: number;
};
const INITIAL_PAN = {
translateX: 0,
translateY: 0,
};
export const usePan = (active: boolean) => {
const [pan, setPan] = useState<Pan>(INITIAL_PAN);
const [cursor, setCursor] = useState<'grab' | 'grabbing' | 'initial'>(
active ? 'grab' : 'initial'
);
useEffect(() => {
setCursor(active ? 'grab' : 'initial');
}, [active]);
const handleMouseMove = (evt: MouseEvent) => {
evt.preventDefault();
evt.stopPropagation();
setPan((p) => {
const { translateX, translateY } = p;
const mX = translateX + evt.movementX;
const mY = translateY + evt.movementY;
return { translateX: mX, translateY: mY };
});
};
const handleMouseUp = (evt: MouseEvent) => {
evt.preventDefault();
setCursor('grab');
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
const handleMouseDown: MouseEventHandler<HTMLElement> = (evt) => {
if (!active) return;
evt.preventDefault();
setCursor('grabbing');
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};
useEffect(() => {
if (!active) setPan(INITIAL_PAN);
}, [active]);
// Clean up document listeners if component unmounts during an active drag
useEffect(
() => () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[]
);
return {
pan,
cursor,
onMouseDown: handleMouseDown,
};
};