Evo.External.App/apps/web/app/context/SidebarContext.tsx
2023-11-03 11:57:10 +03:00

77 lines
1.9 KiB
TypeScript

'use client';
import type { PropsWithChildren } from 'react';
import { createContext, useContext, useEffect, useState } from 'react';
type SidebarContextProps = {
isOpenOnSmallScreens: boolean;
isPageWithSidebar: boolean;
// eslint-disable-next-line no-unused-vars
setOpenOnSmallScreens: (isOpen: boolean) => void;
};
const SidebarContext = createContext<SidebarContextProps>(undefined!);
export function SidebarProvider({
children,
}: PropsWithChildren<Record<string, unknown>>) {
const location = isBrowser() ? window.location.pathname : '/';
const [isOpen, setOpen] = useState(false);
// Close Sidebar on page change on mobile
useEffect(() => {
if (isSmallScreen()) {
setOpen(false);
}
}, [location]);
// Close Sidebar on mobile tap inside main content
useEffect(() => {
function handleMobileTapInsideMain(event: MouseEvent) {
const main = document.querySelector('main');
const isClickInsideMain = main?.contains(event.target as Node);
if (isSmallScreen() && isClickInsideMain) {
setOpen(false);
}
}
document.addEventListener('mousedown', handleMobileTapInsideMain);
return () => {
document.removeEventListener('mousedown', handleMobileTapInsideMain);
};
}, []);
return (
<SidebarContext.Provider
value={{
isOpenOnSmallScreens: isOpen,
isPageWithSidebar: true,
setOpenOnSmallScreens: setOpen,
}}
>
{children}
</SidebarContext.Provider>
);
}
function isBrowser(): boolean {
return typeof window !== 'undefined';
}
function isSmallScreen(): boolean {
return isBrowser() && window.innerWidth < 768;
}
export function useSidebarContext(): SidebarContextProps {
const context = useContext(SidebarContext) as SidebarContextProps | undefined;
if (!context) {
throw new Error(
'useSidebarContext should be used within the SidebarContext provider!',
);
}
return context;
}