From a5ac790ebc87fbe3ff8d2667a41476335048e408 Mon Sep 17 00:00:00 2001 From: Marius Ahsmus Date: Mon, 12 Aug 2024 15:41:40 +0200 Subject: [PATCH] feat: portal logic --- package.json | 2 +- src/component/toast.tsx | 7 ---- src/component/toaster.tsx | 65 ++++++++++++++++++----------------- src/component/toastportal.tsx | 30 ++++++++++++++++ 4 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 src/component/toastportal.tsx diff --git a/package.json b/package.json index 7a58ec3..37dd915 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "griller", "license": "MIT", - "version": "1.0.15", + "version": "1.0.16", "private": false, "repository": { "url": "https://github.com/mvriu5/griller" diff --git a/src/component/toast.tsx b/src/component/toast.tsx index dc0930a..6f0fab5 100644 --- a/src/component/toast.tsx +++ b/src/component/toast.tsx @@ -5,7 +5,6 @@ import {X} from "lucide-react"; import {AnimatePresence, motion} from "framer-motion"; import clsx, {ClassValue} from "clsx"; import {twMerge} from "tailwind-merge"; -import ReactDOM from "react-dom"; export const cn = (...classes: ClassValue[]) => twMerge(clsx(classes)); @@ -22,10 +21,6 @@ export const positionClasses = (position: Position) => { return ''; } -const ToastPortal: React.FC<{ children: ReactNode }> = ({ children }) => { - return ReactDOM.createPortal(children, document.body); -} - interface ToastProps extends HTMLAttributes { id: string; title: string; @@ -108,7 +103,6 @@ const Toast: React.FC removeToast(id)}> {visible && ( )} - ); }; diff --git a/src/component/toaster.tsx b/src/component/toaster.tsx index 6d173a8..270a3ea 100644 --- a/src/component/toaster.tsx +++ b/src/component/toaster.tsx @@ -3,6 +3,7 @@ import React, {createContext, ReactNode, useCallback, useContext, useMemo, useRef, useState} from 'react'; import {Position, positionClasses, Toast, ToastProps} from './toast'; import {AnimatePresence, motion} from "framer-motion"; +import { ToastPortal } from './toastportal'; interface ToastContextType { addToast: (props: Omit) => string; @@ -84,37 +85,39 @@ export const Toaster: React.FC = ({ children, layout = "stack" }) return ( {children} - {Object.entries(groupedToasts).map(([position, positionToasts]) => ( - setIsPaused(true)} - onMouseLeave={() => setIsPaused(false)} - > - - {positionToasts.map((toast) => { - return( - - - - ) - })} - - - ))} + + {Object.entries(groupedToasts).map(([position, positionToasts]) => ( + setIsPaused(true)} + onMouseLeave={() => setIsPaused(false)} + > + + {positionToasts.map((toast) => { + return( + + + + ) + })} + + + ))} + ); }; diff --git a/src/component/toastportal.tsx b/src/component/toastportal.tsx new file mode 100644 index 0000000..6dd0cf3 --- /dev/null +++ b/src/component/toastportal.tsx @@ -0,0 +1,30 @@ +import ReactDOM from 'react-dom'; +import React, {ReactNode, useEffect, useState} from 'react'; + +interface ToastPortalProps { + children: ReactNode; +} + +export const ToastPortal: React.FC = ({ children }) => { + const [portalElement, setPortalElement] = useState(null); + + useEffect(() => { + let element = document.getElementById('toast-portal-root'); + if (!element) { + element = document.createElement('div'); + element.id = 'toast-portal-root'; + document.body.appendChild(element); + } + setPortalElement(element); + + return () => { + if (element && element.parentNode) { + element.parentNode.removeChild(element); + } + }; + }, []); + + if (!portalElement) return null; + + return ReactDOM.createPortal(children, portalElement); +}; \ No newline at end of file