import React, { FC, HTMLAttributes, Children, useState, useEffect, useRef, createContext, useMemo, startTransition } from "react"; import { getCN } from "../utils"; import "./ModalRoot.css"; export interface IModalRoot extends HTMLAttributes { activeModal: string; delay?: number; safe?: boolean; nav?: string; onClose?: () => void }; class SaveContext { private value: Record = {}; constructor(value: Record) { this.value = value; }; public getvalue = (title: string) => this.value[title] || 0; public setValue = (title: string, value: number) => this.value[title] = value; }; export const ScrollContext = createContext(new SaveContext({})); const ModalRoot: FC = ({ activeModal, delay = 300, safe = true, //Безопасная зона children, onClose, ...restProps }) => { const scrollContext = useRef(new SaveContext({})).current; const [[back, active, animation, show], setNav] = useState(["", "", false, false]); const ModalRoots = useMemo(() => Children.toArray(children) as React.ReactElement[], [children]); const pageClose = ModalRoots.find((elem) => elem.props.id === back); const pageActive = ModalRoots.find((elem) => elem.props.id === active); useEffect(() => { handleCloseModal(active); }, [activeModal]); const handleCloseModal = (active: string, callback?: () => void) => { if (active !== activeModal) { setNav([active, activeModal, true, true]); const timer = setTimeout(() => { setNav([active, activeModal, false, false]); }, delay); if (callback) callback() return () => clearTimeout(timer); }; } const handleClose = () => onClose && onClose() const hd = handleSwipe({ maxTop: 0, onClose: () => handleClose() }); return (
{ pageActive && (
e.stopPropagation()} className={getCN("ModalRoot__active__in")}> {pageActive}
) } { back && show && pageClose && (
{pageClose}
) }
); }; export default ModalRoot; type IHandleSwipe = { maxTop: number, bottomClose?: number, onClose?: () => void; } const handleSwipe = ({ maxTop, bottomClose = 100, onClose }: IHandleSwipe) => { const [transformY, setTransformY] = useState(0); const [touchStart, setTouchStart] = useState(0); const handleTouchStart = (e: React.TouchEvent) => { e.stopPropagation(); setTouchStart(e.targetTouches[0].clientY); } const handleTouchMove = (e: React.TouchEvent) => { e.stopPropagation(); const reTransform = e.targetTouches[0].clientY var px = reTransform - touchStart; if (px <= 0) { if (Math.abs(px) > maxTop) return; } setTransformY(px) } const handleTouchEnd = (e: React.TouchEvent) => { if (transformY >= bottomClose) { if (onClose) onClose(); }; setTransformY(0) } const varTransformY = { "--modal_root_transformY": `${transformY}px` } as React.CSSProperties; return { varTransformY, transformY, component: { onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, // onMouseDown: handleTouchEnd, // onMouseMove: handleTouchEnd, // onMouseUp: handleTouchEnd, // onMouseLeave: handleTouchEnd, } } }