44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
export interface UseIntersectionVisibleOptions {
|
|
root?: Element | Document | null;
|
|
rootMargin?: string;
|
|
threshold?: number | number[];
|
|
/** true — 포커스·전체화면 등 항상 활성 */
|
|
initialVisible?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 요소가 뷰포트(또는 root)에 들어왔는지 — 차트·폴링 gating 용
|
|
*/
|
|
export function useIntersectionVisible(
|
|
options: UseIntersectionVisibleOptions = {},
|
|
): { ref: (node: HTMLElement | null) => void; visible: boolean } {
|
|
const {
|
|
root = null,
|
|
rootMargin = '100px 0px',
|
|
threshold = 0.05,
|
|
initialVisible = false,
|
|
} = options;
|
|
const [element, setElement] = useState<HTMLElement | null>(null);
|
|
const [visible, setVisible] = useState(initialVisible);
|
|
|
|
const ref = useCallback((node: HTMLElement | null) => {
|
|
setElement(node);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!element) return;
|
|
const io = new IntersectionObserver(
|
|
entries => {
|
|
setVisible(entries[0]?.isIntersecting ?? false);
|
|
},
|
|
{ root, rootMargin, threshold },
|
|
);
|
|
io.observe(element);
|
|
return () => io.disconnect();
|
|
}, [element, root, rootMargin, threshold]);
|
|
|
|
return { ref, visible };
|
|
}
|