mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 16:58:05 +02:00
103 lines
3.2 KiB
React
103 lines
3.2 KiB
React
import { useEffect, useRef } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import "../styles/signature.css";
|
|
import Loader from "./Loader";
|
|
import Tooltip from "./Tooltip";
|
|
|
|
const ModalUi = ({
|
|
id,
|
|
children,
|
|
title,
|
|
isOpen,
|
|
handleClose,
|
|
showHeader = true,
|
|
showClose = true,
|
|
reduceWidth,
|
|
position,
|
|
crossColor,
|
|
showScrollBar = false,
|
|
isLoader = false,
|
|
helpText = ""
|
|
}) => {
|
|
const { t } = useTranslation();
|
|
const dialogRef = useRef(null);
|
|
const width = reduceWidth;
|
|
const isBottom = position === "bottom" ? "items-end pb-2 !bg-black/10" : "";
|
|
const crossBtnColor = crossColor ?? "text-base-content";
|
|
const hideScrollBar = !showScrollBar ? "hide-scrollbar" : "";
|
|
|
|
// Keep bottom-sheet modals above the mobile virtual keyboard by tracking the
|
|
// visual viewport (which shrinks when the keyboard opens) and adjusting the
|
|
// dialog's height/top to match, so the modal never slides behind the keyboard.
|
|
useEffect(() => {
|
|
if (!isOpen || position !== "bottom" || !window.visualViewport) return;
|
|
const vp = window.visualViewport;
|
|
|
|
const updatePosition = () => {
|
|
if (!dialogRef.current) return;
|
|
dialogRef.current.style.height = `${vp.height}px`;
|
|
dialogRef.current.style.top = `${vp.offsetTop}px`;
|
|
};
|
|
|
|
updatePosition();
|
|
vp.addEventListener("resize", updatePosition);
|
|
vp.addEventListener("scroll", updatePosition);
|
|
|
|
return () => {
|
|
vp.removeEventListener("resize", updatePosition);
|
|
vp.removeEventListener("scroll", updatePosition);
|
|
};
|
|
}, [isOpen, position]);
|
|
|
|
return (
|
|
<>
|
|
{isOpen && (
|
|
<dialog
|
|
ref={dialogRef}
|
|
id={id || "selectSignerModal"}
|
|
className={`${isBottom} op-modal op-modal-open`}
|
|
style={{
|
|
overlay: { zIndex: 1000 },
|
|
content: { zIndex: 1001, overflow: "visible" } // Ensure modal doesn't clip content
|
|
}}
|
|
>
|
|
{isLoader && (
|
|
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
|
|
<Loader />
|
|
</div>
|
|
)}
|
|
<div
|
|
className={`${width || "md:min-w-[500px]"} op-modal-box p-0 max-h-90 overflow-y-auto ${hideScrollBar} text-sm`}
|
|
>
|
|
{showHeader && (
|
|
<>
|
|
{title && (
|
|
<h3 className="text-base-content text-left font-bold text-lg pt-[15px] px-[20px]">
|
|
{title}
|
|
{helpText && (
|
|
<span className="ml-0.5 text-sm font-medium">
|
|
<Tooltip id={title} message={t(helpText)} />
|
|
</span>
|
|
)}
|
|
</h3>
|
|
)}
|
|
{showClose && (
|
|
<button
|
|
className={`${crossBtnColor} op-btn op-btn-sm op-btn-circle op-btn-ghost absolute right-2 top-2 z-40`}
|
|
onClick={() => handleClose && handleClose()}
|
|
>
|
|
✕
|
|
</button>
|
|
)}
|
|
</>
|
|
)}
|
|
<div>{children}</div>
|
|
</div>
|
|
</dialog>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ModalUi;
|