Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
117 lines
3.3 KiB
Plaintext
117 lines
3.3 KiB
Plaintext
'use client';
|
|
|
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
import { useWindowInfo } from '@faceless-ui/window-info';
|
|
import { usePathname } from 'next/navigation.js';
|
|
import { PREFERENCE_KEYS } from 'payload/shared';
|
|
import React, { useEffect, useRef } from 'react';
|
|
import { usePreferences } from '../../providers/Preferences/index.js';
|
|
/**
|
|
* @internal
|
|
*/
|
|
export const NavContext = /*#__PURE__*/React.createContext({
|
|
hydrated: false,
|
|
navOpen: true,
|
|
navRef: null,
|
|
setNavOpen: () => {},
|
|
shouldAnimate: false
|
|
});
|
|
export const useNav = () => React.use(NavContext);
|
|
const getNavPreference = async getPreference => {
|
|
const navPrefs = await getPreference(PREFERENCE_KEYS.NAV);
|
|
const preferredState = navPrefs?.open;
|
|
if (typeof preferredState === 'boolean') {
|
|
return preferredState;
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
/**
|
|
* @internal
|
|
*/
|
|
export const NavProvider = ({
|
|
children,
|
|
initialIsOpen
|
|
}) => {
|
|
const {
|
|
breakpoints: {
|
|
l: largeBreak,
|
|
m: midBreak,
|
|
s: smallBreak
|
|
}
|
|
} = useWindowInfo();
|
|
const pathname = usePathname();
|
|
const {
|
|
getPreference
|
|
} = usePreferences();
|
|
const navRef = useRef(null);
|
|
// initialize the nav to be closed
|
|
// this is because getting the preference is async
|
|
// so instead of closing it after the preference is loaded
|
|
// we will open it after the preference is loaded
|
|
const [navOpen, setNavOpen] = React.useState(initialIsOpen);
|
|
const [shouldAnimate, setShouldAnimate] = React.useState(false);
|
|
const [hydrated, setHydrated] = React.useState(false);
|
|
// on load check the user's preference and set "initial" state
|
|
useEffect(() => {
|
|
if (largeBreak === false) {
|
|
const setNavFromPreferences = async () => {
|
|
const preferredState = await getNavPreference(getPreference);
|
|
setNavOpen(preferredState);
|
|
};
|
|
void setNavFromPreferences();
|
|
}
|
|
}, [largeBreak, getPreference, setNavOpen]);
|
|
// on smaller screens where the nav is a modal
|
|
// close the nav when the user navigates away
|
|
useEffect(() => {
|
|
if (smallBreak === true) {
|
|
setNavOpen(false);
|
|
}
|
|
}, [pathname]);
|
|
// on open and close, lock the body scroll
|
|
// do not do this on desktop, the sidebar is not a modal
|
|
useEffect(() => {
|
|
if (navRef.current) {
|
|
if (navOpen && midBreak) {
|
|
navRef.current.style.overscrollBehavior = 'contain';
|
|
} else {
|
|
navRef.current.style.overscrollBehavior = 'auto';
|
|
}
|
|
}
|
|
}, [navOpen, midBreak]);
|
|
// on smaller screens where the nav is a modal
|
|
// close the nav when the user resizes down to mobile
|
|
// the sidebar is a modal on mobile
|
|
useEffect(() => {
|
|
if (largeBreak === true || midBreak === true || smallBreak === true) {
|
|
setNavOpen(false);
|
|
}
|
|
setHydrated(true);
|
|
const timeout = setTimeout(() => {
|
|
setShouldAnimate(true);
|
|
}, 100);
|
|
return () => {
|
|
clearTimeout(timeout);
|
|
};
|
|
}, [largeBreak, midBreak, smallBreak]);
|
|
// when the component unmounts, clear all body scroll locks
|
|
useEffect(() => {
|
|
return () => {
|
|
if (navRef.current) {
|
|
navRef.current.style.overscrollBehavior = 'auto';
|
|
}
|
|
};
|
|
}, []);
|
|
return /*#__PURE__*/_jsx(NavContext, {
|
|
value: {
|
|
hydrated,
|
|
navOpen,
|
|
navRef,
|
|
setNavOpen,
|
|
shouldAnimate
|
|
},
|
|
children: children
|
|
});
|
|
};
|
|
//# sourceMappingURL=context.js.map |