base animation

This commit is contained in:
hamid zarghami
2026-05-12 15:19:44 +03:30
parent 8cfe559fb6
commit 6a8eaab8cb
13 changed files with 548 additions and 122 deletions
@@ -0,0 +1,56 @@
import { useCallback, useEffect, useRef, useState } from "react";
/**
* وقتی صفحهٔ کتاب به viewport می‌رسد، یک شمارنده زیاد می‌شود تا انیمیشن ورود دوباره اجرا شود
* (مشابه ورود مجدد به اسلاید در PowerPoint).
*/
export function useBookPageEntranceSequence(disabled: boolean) {
const wasVisibleRef = useRef(false);
const [entranceSeq, setEntranceSeq] = useState(0);
const observerRef = useRef<IntersectionObserver | null>(null);
const attachRootRef = useCallback(
(node: HTMLDivElement | null) => {
observerRef.current?.disconnect();
observerRef.current = null;
if (disabled || !node) {
wasVisibleRef.current = false;
return;
}
const io = new IntersectionObserver(
(entries) => {
const entry = entries[0];
if (!entry) return;
const visible = entry.isIntersecting && entry.intersectionRatio >= 0.06;
const mostlyHidden = !entry.isIntersecting || entry.intersectionRatio < 0.02;
if (visible && !wasVisibleRef.current) {
wasVisibleRef.current = true;
setEntranceSeq((s) => s + 1);
} else if (mostlyHidden) {
wasVisibleRef.current = false;
}
},
{ threshold: [0, 0.02, 0.06, 0.12, 0.25] },
);
io.observe(node);
observerRef.current = io;
},
[disabled],
);
useEffect(
() => () => {
observerRef.current?.disconnect();
observerRef.current = null;
},
[],
);
return {
attachRootRef,
entranceSeq: disabled ? 0 : entranceSeq,
};
}