Bladeren bron

:recycle: Cleans Up Entangle (#3792)

* :recycle: Cleans Up entangle

* :bug: Set hash on first run

* :bug: Deeply clones entangled values

* :bug: Actually fixes livewire regression
Eric Kwoka 1 jaar geleden
bovenliggende
commit
3184106527
3 gewijzigde bestanden met toevoegingen van 63 en 35 verwijderingen
  1. 10 15
      package-lock.json
  2. 18 20
      packages/alpinejs/src/entangle.js
  3. 35 0
      tests/cypress/integration/entangle.spec.js

+ 10 - 15
package-lock.json

@@ -7825,7 +7825,7 @@
             }
         },
         "packages/alpinejs": {
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT",
             "dependencies": {
                 "@vue/reactivity": "~3.1.1"
@@ -7833,7 +7833,7 @@
         },
         "packages/collapse": {
             "name": "@alpinejs/collapse",
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT"
         },
         "packages/csp": {
@@ -7846,12 +7846,12 @@
         },
         "packages/docs": {
             "name": "@alpinejs/docs",
-            "version": "3.12.3-revision.1",
+            "version": "3.13.1-revision.1",
             "license": "MIT"
         },
         "packages/focus": {
             "name": "@alpinejs/focus",
-            "version": "3.12.1",
+            "version": "3.13.1",
             "license": "MIT",
             "dependencies": {
                 "focus-trap": "^6.9.4",
@@ -7868,17 +7868,17 @@
         },
         "packages/intersect": {
             "name": "@alpinejs/intersect",
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT"
         },
         "packages/mask": {
             "name": "@alpinejs/mask",
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT"
         },
         "packages/morph": {
             "name": "@alpinejs/morph",
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT"
         },
         "packages/navigate": {
@@ -7891,19 +7891,14 @@
         },
         "packages/persist": {
             "name": "@alpinejs/persist",
-            "version": "3.12.3",
+            "version": "3.13.1",
             "license": "MIT"
         },
         "packages/ui": {
             "name": "@alpinejs/ui",
-            "version": "3.12.3-beta.0",
+            "version": "3.13.1-beta.0",
             "license": "MIT",
-            "devDependencies": {
-                "alpinejs": "file:../alpinejs"
-            },
-            "peerDependencies": {
-                "alpinejs": "^3.10.0"
-            }
+            "devDependencies": {}
         }
     }
 }

+ 18 - 20
packages/alpinejs/src/entangle.js

@@ -2,39 +2,37 @@ import { effect, release } from './reactivity'
 
 export function entangle({ get: outerGet, set: outerSet }, { get: innerGet, set: innerSet }) {
     let firstRun = true
-    let outerHash, innerHash, outerHashLatest, innerHashLatest
+    let outerHash
 
     let reference = effect(() => {
-        let outer, inner
-
+        const outer = outerGet()
+        const inner = innerGet()
         if (firstRun) {
-            outer = outerGet()
-            innerSet(JSON.parse(JSON.stringify(outer))) // We need to break internal references using parse/stringify...
-            inner = innerGet()
+            innerSet(cloneIfObject(outer))
             firstRun = false
+            outerHash = JSON.stringify(outer)
         } else {
-            outer = outerGet()
-            inner = innerGet()
-
-            outerHashLatest = JSON.stringify(outer)
-            innerHashLatest = JSON.stringify(inner)
+            const outerHashLatest = JSON.stringify(outer)
 
             if (outerHashLatest !== outerHash) { // If outer changed...
-                inner = innerGet()
-                innerSet(outer)
-                inner = outer // Assign inner to outer so that it can be serialized for diffing...
+                innerSet(cloneIfObject(outer))
+                outerHash = outerHashLatest
             } else { // If inner changed...
-                outerSet(JSON.parse(innerHashLatest ?? null)) // We need to break internal references using parse/stringify...
-                outer = inner // Assign outer to inner so that it can be serialized for diffing...
+                outerSet(cloneIfObject(inner))
+                outerHash = JSON.stringify(inner)
             }
         }
-
-        // Re serialize values...
-        outerHash = JSON.stringify(outer)
-        innerHash = JSON.stringify(inner)
+        JSON.stringify(innerGet())
+        JSON.stringify(outerGet())
     })
 
     return () => {
         release(reference)
     }
 }
+
+function cloneIfObject(value) {
+    return typeof value === 'object'
+        ? JSON.parse(JSON.stringify(value))
+        : value
+}

+ 35 - 0
tests/cypress/integration/entangle.spec.js

@@ -69,3 +69,38 @@ test.skip('can release entanglement',
         get('input[outer]').should(haveValue('foobar'))
     }
 )
+
+test(
+    "can handle undefined",
+    [
+        html`
+            <div x-data="{ outer: undefined }">
+                <input x-model="outer" outer />
+
+                <div
+                    x-data="{ inner: 'bar' }"
+                    x-init="() => {}; Alpine.entangle(
+            {
+                get() { return outer },
+                set(value) { outer = value },
+            },
+            {
+                get() { return inner },
+                set(value) { inner = value },
+            }
+        )"
+                >
+                    <input x-model="inner" inner />
+                </div>
+            </div>
+        `,
+    ],
+    ({ get }) => {
+        get("input[outer]").should(haveValue(''));
+        get("input[inner]").should(haveValue(''));
+
+        get("input[inner]").type("bar");
+        get("input[inner]").should(haveValue("bar"));
+        get("input[outer]").should(haveValue("bar"));
+    }
+);