o2o-site-AEO/solution/site/src/lib/ui/use-scroll-lock.ts
Mina Choi b386982f34 [fix] site: 모달·갤러리·소식 스크롤 잠금을 훅 하나로 통합 — 복사된 스크롤 버그 재발 방지
모달 스크롤 버그를 Modal.tsx 한 곳만 고쳤더니 같은 잠금·복귀 코드가 그대로 복사돼
있던 GallerySection·EventSection 에는 버그가 그대로 남아 있었다(2026-09-21 실측).
복사한 코드는 복사한 곳마다 따로 고쳐야 하므로 훅 하나로 뺀다.

- lib/ui/use-scroll-lock.ts: 스크롤 잠금·복귀 로직 신규 — scroll-behavior:auto 강제 포함
- lib/ui/Modal.tsx, sections/GallerySection.tsx, sections/items/EventSection.tsx:
  중복 잠금 코드 제거, useScrollLock() 호출로 교체
- lib/ui/index.ts: useScrollLock export 추가

tsc 통과, vitest 100 passed(무관한 날씨 조건 테스트 2건은 이 변경 전부터 실패 중)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 13:57:33 +09:00

40 lines
1.7 KiB
TypeScript

/**
* 모달·오버레이가 열려 있는 동안 배경 스크롤을 잠근다 — **한 벌만 둔다.**
*
* ★ 왜 훅으로 뺐나 (2026-09-21, 사장님: "이거 목업 하나만 해결하면 끝이야? 훅으로 만들어놓던가")
* 같은 잠금·복귀 코드가 Modal · GallerySection · EventSection 세 곳에 따로 박혀 있었다.
* 모달 하나만 고치고 나니 나머지 둘은 그대로 남아 같은 스크롤 버그가 다시 났다 —
* 복사한 코드는 복사한 곳마다 따로 고쳐야 한다.
* ★ 복귀는 즉시 이동이어야 한다. `index.css` 의 전역 `html { scroll-behavior: smooth }` 때문에
* `window.scrollTo` 가 애니메이션으로 움직이며 "위로 튀었다 내려오는" 것처럼 보인다 —
* 이 한 번만 `scroll-behavior: auto` 로 강제한다.
*/
import {useEffect} from 'react';
export function useScrollLock(active: boolean) {
useEffect(() => {
if (!active) return;
const scrollY = window.scrollY;
const body = document.body;
const prevPosition = body.style.position;
const prevTop = body.style.top;
const prevWidth = body.style.width;
const prevOverflow = body.style.overflow;
body.style.position = 'fixed';
body.style.top = `-${scrollY}px`;
body.style.width = '100%';
body.style.overflow = 'hidden';
return () => {
body.style.position = prevPosition;
body.style.top = prevTop;
body.style.width = prevWidth;
body.style.overflow = prevOverflow;
const root = document.documentElement;
const prevScrollBehavior = root.style.scrollBehavior;
root.style.scrollBehavior = 'auto';
window.scrollTo(0, scrollY);
root.style.scrollBehavior = prevScrollBehavior;
};
}, [active]);
}