apvarun / toastify-js

Pure JavaScript library for better notification messages
https://apvarun.github.io/toastify-js/
MIT License
2.09k stars 230 forks source link

Reposition function is not working with shadow roots (selector option) #111

Open thomleclerc opened 1 year ago

thomleclerc commented 1 year ago

Actual behavior

You provide a useful feature for shadow roots which is the selector property, however the reposition function is not working due to shadow roots. You are using document.getElementsByClassName which gets blocked by the shadow roots so whenever we use shadow roots nothing get selected, so nothing is repositioned.

Expected behavior

I expect the reposition function to work in shadow root by checking if a selector is passed to the toast and using it to do the getElements located here. I have managed to make it work locally by doing the following (I haven't tested any other usecases so it may broke other usecases but it's a good track of solution) :

I have passed the this object as props to the reposition function to get access to the selector and check if any is provided, if so we do the equivalent of getElementsByClassName but with shadow roots way, which is the querySelectorAll.

We get the following for the lime 363: var allToasts = toast.options.selector ? toast.options.selector.querySelectorAll('.toastify') : document.getElementsByClassName("toastify");

Don't hesitate if you need more information.

kusyka911 commented 1 month ago

Have same issue. Made a patch with patch-package to fix this in my app. It just works fine, but code probably can be done better.

diff --git a/node_modules/toastify-js/src/toastify.js b/node_modules/toastify-js/src/toastify.js
index 5d9659c..69dfbdc 100644
--- a/node_modules/toastify-js/src/toastify.js
+++ b/node_modules/toastify-js/src/toastify.js
@@ -279,6 +279,8 @@
         rootElement = document.body;
       }

+      this.rootElement = rootElement;
+
       // Validating if root element is present in DOM
       if (!rootElement) {
         throw "Root element is not defined";
@@ -289,7 +291,7 @@
       rootElement.insertBefore(this.toastElement, elementToInsert);

       // Repositioning the toasts in case multiple toasts are present
-      Toastify.reposition();
+      Toastify.reposition(rootElement);

       if (this.options.duration > 0) {
         this.toastElement.timeOutValue = window.setTimeout(
@@ -335,7 +337,7 @@
           this.options.callback.call(toastElement);

           // Repositioning the toasts again
-          Toastify.reposition();
+          Toastify.reposition(this.rootElement);
         }.bind(this),
         400
       ); // Binding `this` for function invocation
@@ -343,7 +345,11 @@
   };

   // Positioning the toasts on the DOM
-  Toastify.reposition = function() {
+  Toastify.reposition = function(rootElement) {
+
+    if (!rootElement) {
+      rootElement = document.body;
+    }

     // Top margins with gravity
     var topLeftOffsetSize = {
@@ -360,7 +366,7 @@
     };

     // Get all toast messages on the DOM
-    var allToasts = document.getElementsByClassName("toastify");
+    var allToasts = rootElement.getElementsByClassName("toastify");

     var classUsed;