base animation
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user