Caleb Porzio 1 mês atrás
pai
commit
b889909bf4

+ 18 - 5
packages/morph/src/morph.js

@@ -96,7 +96,10 @@ function createMorphContext(options = {}) {
         // So we're using `shouldSkipChildren()` instead which doesn't have this problem as it allows us to pass in the `skipChildren()`
         // So we're using `shouldSkipChildren()` instead which doesn't have this problem as it allows us to pass in the `skipChildren()`
         // function as an earlier parameter and then append it to the `updating` hook signature manually. The signature of `updating`
         // function as an earlier parameter and then append it to the `updating` hook signature manually. The signature of `updating`
         // hook is now `updating: (el, toEl, childrenOnly, skip, skipChildren)`.
         // hook is now `updating: (el, toEl, childrenOnly, skip, skipChildren)`.
-        if (shouldSkipChildren(context.updating, () => skipChildren = true, from, to, () => updateChildrenOnly = true)) return
+
+        let skipUntil = predicate => context.skipUntilCondition = predicate
+
+        if (shouldSkipChildren(context.updating, () => skipChildren = true, skipUntil, from, to, () => updateChildrenOnly = true)) return
 
 
         // Initialize the server-side HTML element with Alpine...
         // Initialize the server-side HTML element with Alpine...
         if (from.nodeType === 1 && window.Alpine) {
         if (from.nodeType === 1 && window.Alpine) {
@@ -201,6 +204,18 @@ function createMorphContext(options = {}) {
             let toKey = context.getKey(currentTo)
             let toKey = context.getKey(currentTo)
             let fromKey = context.getKey(currentFrom)
             let fromKey = context.getKey(currentFrom)
 
 
+            if (context.skipUntilCondition) {
+                let fromDone = ! currentFrom || context.skipUntilCondition(currentFrom)
+                let toDone   = ! currentTo   || context.skipUntilCondition(currentTo)
+                if (fromDone && toDone) {
+                    context.skipUntilCondition = null
+                } else {
+                    if (! fromDone) currentFrom = currentFrom && getNextSibling(from, currentFrom)
+                    if (! toDone)   currentTo   = currentTo   && getNextSibling(to, currentTo)
+                    continue
+                }
+            }
+
             // Add new elements...
             // Add new elements...
             if (! currentFrom) {
             if (! currentFrom) {
                 if (toKey && fromKeyHoldovers[toKey]) {
                 if (toKey && fromKeyHoldovers[toKey]) {
@@ -431,11 +446,9 @@ function shouldSkip(hook, ...args) {
 // are using this function instead which doesn't have this problem as we can pass the
 // are using this function instead which doesn't have this problem as we can pass the
 // `skipChildren` function in as an earlier argument and then append it to the end
 // `skipChildren` function in as an earlier argument and then append it to the end
 // of the hook signature manually.
 // of the hook signature manually.
-function shouldSkipChildren(hook, skipChildren, ...args) {
+function shouldSkipChildren(hook, skipChildren, skipUntil, ...args) {
     let skip = false
     let skip = false
-
-    hook(...args, () => skip = true, skipChildren)
-
+    hook(...args, () => skip = true, skipChildren, skipUntil)
     return skip
     return skip
 }
 }
 
 

+ 47 - 0
tests/cypress/integration/plugins/morph.spec.js

@@ -1014,3 +1014,50 @@ test('morphBetween with conditional blocks',
         get('p input').should(haveValue('p-value'))
         get('p input').should(haveValue('p-value'))
     },
     },
 )
 )
+
+test('can ignore region between comment markers using skipUntil',
+    [html`
+        <ul>
+            <li>foo</li>
+            <!-- [Slot] -->
+            <li>bar</li>
+            <li>baz</li>
+            <!-- [EndSlot] -->
+            <!-- bob -->
+        </ul>
+    `],
+    ({ get }, reload, window, document) => {
+        // Generate "to" html without the items between Slot markers
+        let toHtml = html`
+            <ul>
+                <li>foo</li>
+                <!-- [Slot] -->
+                <!-- [EndSlot] -->
+                <!-- bob -->
+            </ul>
+        `
+
+        // The original list should have 3 li's
+        get('li').should(haveLength(3))
+        get('li:nth-of-type(1)').should(haveText('foo'))
+        get('li:nth-of-type(2)').should(haveText('bar'))
+        get('li:nth-of-type(3)').should(haveText('baz'))
+
+        // Run morph with custom updating hook that calls skipUntil
+        let isStart = node => node && node.nodeType === 8 && node.textContent.trim() === '[Slot]'
+        let isEnd   = node => node && node.nodeType === 8 && node.textContent.trim() === '[EndSlot]'
+
+        get('ul').then(([el]) => window.Alpine.morph(el, toHtml, {
+            updating(from, to, childrenOnly, skip, skipChildren, skipUntil) {
+                if (isStart(from) && isStart(to)) {
+                    skipUntil(node => isEnd(node))
+                }
+            },
+        }))
+
+        // After morph, the list should still contain the items inside the slot
+        get('li').should(haveLength(3))
+        get('li:nth-of-type(2)').should(haveText('bar'))
+        get('li:nth-of-type(3)').should(haveText('baz'))
+    },
+)