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} ); };