/* This file is part of GNU Taler (C) 2022 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ import { css } from "@linaria/core"; import { createPortal, forwardRef } from "preact/compat"; import { h, JSX, VNode, ComponentChildren, RefObject, isValidElement, cloneElement, Fragment, } from "preact"; import { Ref, useEffect, useState } from "preact/hooks"; import { theme } from "./style.js"; const baseStyle = css` position: fixed; z-index: ${theme.zIndex.modal}; right: 0px; bottom: 0px; top: 0px; left: 0px; `; interface Props { // class: string; children: ComponentChildren; disablePortal?: boolean; container?: VNode; } export const Portal = forwardRef(function Portal( { container, disablePortal, children }: Props, ref: Ref, ): VNode { const [mountNode, setMountNode] = useState( undefined, ); const handleRef = null; // useForkRef( // isValidElement(children) ? children.ref : null, // ref, // ); useEffect(() => { if (!disablePortal) { setMountNode(getContainer(container) || document.body); } }, [container, disablePortal]); useEffect(() => { if (mountNode && !disablePortal) { setRef(ref, mountNode); return () => { setRef(ref, null); }; } return undefined; }, [ref, mountNode, disablePortal]); if (disablePortal) { if (isValidElement(children)) { return cloneElement(children, { ref: handleRef, }); } return {children}; } return mountNode ? ( createPortal({children}, mountNode) ) : ( ); } as any); function getContainer(container: any): any { return typeof container === "function" ? container() : container; } // function useForkRef( // refA: React.Ref | null | undefined, // refB: React.Ref | null | undefined, // ): React.Ref | null { // /** // * This will create a new function if the ref props change and are defined. // * This means react will call the old forkRef with `null` and the new forkRef // * with the ref. Cleanup naturally emerges from this behavior. // */ // return useMemo(() => { // if (refA == null && refB == null) { // return null; // } // return (refValue) => { // setRef(refA, refValue); // setRef(refB, refValue); // }; // }, [refA, refB]); // } function setRef( ref: RefObject | ((instance: T | null) => void) | null | undefined, value: T | null, ): void { if (typeof ref === "function") { ref(value); } else if (ref) { ref.current = value; } }