import React, {
createContext,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import { OVERLAY_CONTAINER_ID } from "./constaints";
export const OverlayContainer = () => {
return
;
};
interface OverlayContextProps {
count: number;
/** The open overlays in the order they opened: the last one is on top */
ids: string[];
show: (id: string) => void;
close: (id: string) => void;
}
const OverlayContext = createContext({
count: 0,
ids: [],
show: (id: string) => {},
close: (id: string) => {},
});
export const useOverlayContext = () => useContext(OverlayContext);
/** The overlay a component is rendered in; null — the page */
export const CurrentOverlayContext = createContext(null);
export interface OverlayLayer {
/**
* The component is on the top layer: on the page while no overlay is
* open, or in the overlay opened last. Under an open window it's false —
* e.g. a video stops, hotkeys don't act
*/
isTopLayer: boolean;
}
/** Where the component is among the open overlays */
export const useOverlayLayer = (): OverlayLayer => {
const current = useContext(CurrentOverlayContext);
const { ids } = useOverlayContext();
return { isTopLayer: (ids[ids.length - 1] ?? null) === current };
};
export const OverlayProvider = ({
children,
}: {
children: React.ReactElement | React.ReactElement[];
}) => {
const [overlayIds, setOverlayIds] = useState([]);
const count = useMemo(() => overlayIds.length, [overlayIds]);
const show = (id: string) => {
setOverlayIds((value) => {
if (value.includes(id)) {
return value;
}
return [...value, id];
});
};
const close = (id: string) => {
// console.log("-------------------");
// console.log("close");
// console.log("-------------------");
setOverlayIds((value) => {
return value.filter((item) => item !== id);
});
};
// Only the document stops scrolling: an overflow on too would make
// it the scroll container of sticky elements, and they'd jump. The
// scrollbar's width goes to the body's padding so the page doesn't shift
const hideScrollBar = () => {
const html = document.documentElement;
const widthBefore = html.clientWidth;
html.classList.add("kl-overflow-hidden");
const scrollbarWidth = html.clientWidth - widthBefore;
if (scrollbarWidth > 0) {
document.body.style.paddingRight = `${scrollbarWidth}px`;
}
};
const getBackScrollBar = () => {
document.documentElement.classList.remove("kl-overflow-hidden");
document.body.style.removeProperty("padding-right");
};
useEffect(() => {
if (count == 0) {
getBackScrollBar();
} else {
hideScrollBar();
}
return () => {
getBackScrollBar();
};
}, [count]);
return (
{children}
);
};