Leon4gr45's picture
Deploy to clean space
75fefa7 verified
"use client";
import { usePathname } from "next/navigation";
import React, {
createContext,
useContext,
useEffect,
useRef,
useState,
} from "react";
interface HeaderContextType {
dropdownContent: React.ReactNode;
setDropdownContent: (content: React.ReactNode) => void;
clearDropdown: (force?: boolean) => void;
resetDropdownTimeout: () => void;
dropdownKey: number;
headerHeight: React.RefObject<number>;
headerTop: React.RefObject<number>;
}
const HeaderContext = createContext<HeaderContextType | undefined>(undefined);
export const HeaderProvider = ({ children }: { children: React.ReactNode }) => {
const [dropdownContent, setDropdownContent] = useState<React.ReactNode>(null);
const [dropdownKey, setDropdownKey] = useState(0);
const headerHeight = useRef(0);
const headerTop = useRef(0);
const pathname = usePathname();
const timeout = useRef<number | null>(null);
const clearDropdown = (force?: boolean) => {
if (force) {
setDropdownContent(null);
return;
}
if (timeout.current) {
clearTimeout(timeout.current);
}
timeout.current = window.setTimeout(() => {
setDropdownContent(null);
}, 500);
};
const resetDropdownTimeout = () => {
if (timeout.current) {
clearTimeout(timeout.current);
}
};
useEffect(() => {
const header = document.querySelector(".header") as HTMLElement;
if (header) {
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
headerHeight.current = entry.contentRect.height;
}
});
resizeObserver.observe(header);
headerHeight.current = header.clientHeight;
headerTop.current = header.getBoundingClientRect().top;
const onScroll = () => {
headerTop.current = header.getBoundingClientRect().top;
};
window.addEventListener("scroll", onScroll, { passive: true });
return () => {
resizeObserver.disconnect();
window.removeEventListener("scroll", onScroll);
};
}
}, [pathname]);
return (
<HeaderContext.Provider
value={{
dropdownContent,
setDropdownContent: (content) => {
resetDropdownTimeout();
if (content === dropdownContent) return;
setDropdownKey((prev) => prev + 1);
setDropdownContent(content);
},
clearDropdown,
resetDropdownTimeout,
dropdownKey,
headerHeight,
headerTop,
}}
>
{children}
</HeaderContext.Provider>
);
};
export const useHeaderContext = () => {
const context = useContext(HeaderContext);
if (!context) {
throw new Error("useHeaderContext must be used within a HeaderProvider");
}
return context;
};
export const useHeaderHeight = () => {
const [headerHeight, setHeaderHeight] = useState(0);
useEffect(() => {
const header = document.querySelector(".header");
if (header) {
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
setHeaderHeight(entry.contentRect.height);
}
});
resizeObserver.observe(header);
setHeaderHeight(header.clientHeight);
return () => {
resizeObserver.disconnect();
};
}
}, []);
return { headerHeight };
};