From c0115d2fd0f074b0fe0eba6d697d306c8f672402 Mon Sep 17 00:00:00 2001
From: Micah Geisel <micah@botandrose.com>
Date: Tue, 24 Sep 2024 12:20:30 +0200
Subject: [PATCH] only reload child frames during morph if the old and new
 frame have matching ids.

---
 src/core/drive/morphing_page_renderer.js   | 14 ++++++--------
 src/core/frames/morphing_frame_renderer.js | 13 ++++++-------
 src/core/renderer.js                       | 15 ++++++++++-----
 3 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/src/core/drive/morphing_page_renderer.js b/src/core/drive/morphing_page_renderer.js
index 489aceafe..0fff99992 100644
--- a/src/core/drive/morphing_page_renderer.js
+++ b/src/core/drive/morphing_page_renderer.js
@@ -6,18 +6,16 @@ export class MorphingPageRenderer extends PageRenderer {
   static renderElement(currentElement, newElement) {
     morphElements(currentElement, newElement, {
       callbacks: {
-        beforeNodeMorphed: element => {
-          return !super.shouldRefreshChildFrameWithMorphing(null, element)
+        beforeNodeMorphed: (node, newNode) => {
+          if (super.shouldRefreshChildFrameWithMorphing(null, node, newNode)) {
+            node.reload()
+            return false
+          }
+          return true
         }
       }
     })
 
-    for (const frame of currentElement.querySelectorAll("turbo-frame")) {
-      if (super.shouldRefreshChildFrameWithMorphing(null, frame)) {
-        frame.reload()
-      }
-    }
-
     dispatch("turbo:morph", { detail: { currentElement, newElement } })
   }
 
diff --git a/src/core/frames/morphing_frame_renderer.js b/src/core/frames/morphing_frame_renderer.js
index b62f68ae6..c6c6d13b2 100644
--- a/src/core/frames/morphing_frame_renderer.js
+++ b/src/core/frames/morphing_frame_renderer.js
@@ -11,16 +11,15 @@ export class MorphingFrameRenderer extends FrameRenderer {
 
     morphChildren(currentElement, newElement, {
       callbacks: {
-        beforeNodeMorphed: element => {
-          return !super.shouldRefreshChildFrameWithMorphing(currentElement, element)
+        beforeNodeMorphed: (node, newNode) => {
+          if (super.shouldRefreshChildFrameWithMorphing(currentElement, node, newNode)) {
+            node.reload()
+            return false
+          }
+          return true
         }
       }
     })
-    for (const frame of currentElement.querySelectorAll("turbo-frame")) {
-      if (super.shouldRefreshChildFrameWithMorphing(currentElement, frame)) {
-        frame.reload()
-      }
-    }
   }
 
   async preservingPermanentElements(callback) {
diff --git a/src/core/renderer.js b/src/core/renderer.js
index 97b97682a..aea85ac1e 100644
--- a/src/core/renderer.js
+++ b/src/core/renderer.js
@@ -8,11 +8,16 @@ export class Renderer {
     // Abstract method
   }
 
-  static shouldRefreshChildFrameWithMorphing(parentFrame, frame) {
-    return frame instanceof FrameElement &&
-      frame.shouldReloadWithMorph &&
-      !frame.closest("[data-turbo-permanent]") &&
-      frame.parentElement.closest("turbo-frame[src][refresh=morph]") === parentFrame
+  static shouldRefreshChildFrameWithMorphing(parentFrame, currentFrame, newFrame) {
+    return currentFrame instanceof FrameElement &&
+      // newFrame cannot yet be an instance of FrameElement because custom
+      // elements don't get initialized until they're attached to the DOM, so
+      // test its Element#nodeName instead
+      newFrame instanceof Element && newFrame.nodeName === "TURBO-FRAME" &&
+      currentFrame.shouldReloadWithMorph &&
+      currentFrame.id === newFrame.id &&
+      !currentFrame.closest("[data-turbo-permanent]") &&
+      currentFrame.parentElement.closest("turbo-frame[src][refresh=morph]") === parentFrame
   }
 
   constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {