Răsfoiți Sursa

Bug - Another regression (#2096)

* Add failing tests

* Fix regression with nested transitions
Simone Todaro 3 ani în urmă
părinte
comite
9f59936837

+ 7 - 2
packages/alpinejs/src/directives/x-transition.js

@@ -125,10 +125,15 @@ function registerTransitionObject(el, setFunction, defaultValue = {}) {
 }
 
 window.Element.prototype._x_toggleAndCascadeWithTransitions = function (el, value, show, hide) {
-    // We are wrapping this function in a setTimeout here to prevent
+    // We are running this function after one tick to prevent
     // a race condition from happening where elements that have a
     // @click.away always view themselves as shown on the page.
-    let clickAwayCompatibleShow = () => setTimeout(show)
+    // If the tab is active, we prioritise requestAnimationFrame which plays
+    // nicely with nested animations otherwise we use setTimeout to make sure
+    // it keeps running in background. setTimeout has a lower priority in the
+    // event loop so it would skip nested transitions but when the tab is
+    // hidden, it's not relevant.
+    let clickAwayCompatibleShow = () => {document.visibilityState === 'visible' ? requestAnimationFrame(show) : setTimeout(show)}
 
     if (value) {
         el._x_transition

+ 27 - 1
tests/cypress/integration/directives/x-transition.spec.js

@@ -1,4 +1,4 @@
-import { beHidden, beVisible, haveClasses, html, notBeVisible, notHaveClasses, test } from '../../utils'
+import { beHidden, beVisible, haveClasses, haveComputedStyle, html, notBeVisible, notHaveClasses, notHaveComputedStyle, test } from '../../utils'
 
 test('transition in',
     html`
@@ -54,3 +54,29 @@ test('transition out',
         get('span').should(beHidden())
     }
 )
+
+test('transition:enter in nested x-show visually runs',
+    html`
+        <style>
+            .transition { transition: opacity 1s ease; }
+            .opacity-0 {opacity: 0}
+            .opacity-1 {opacity: 1}
+        </style>
+        <div x-data="{ show: false }">
+            <span x-show="show">
+                <h1 x-show="show"
+                    x-transition:enter="transition"
+                    x-transition:enter-start="opacity-0"
+                    x-transition:enter-end="opacity-1">thing</h1>
+            </span>
+
+            <button x-on:click="show = true"></button>
+        </div>
+    `,
+    ({ get }) => {
+        get('button').click()
+        get('span').should(beVisible())
+        get('h1').should(notHaveComputedStyle('opacity', '1')) // We expect a value between 0 and 1
+        get('h1').should(haveComputedStyle('opacity', '1')) // Eventually opacity will be 1
+    }
+)

+ 10 - 0
tests/cypress/utils.js

@@ -103,6 +103,16 @@ export let haveLength = length => el => expect(el).to.have.length(length)
 
 export let beEqualTo = value => el => expect(el).to.eq(value)
 
+export let notHaveComputedStyle = (name, value) => el => {
+    const win = el[0].ownerDocument.defaultView
+    expect(win.getComputedStyle(el[0]).getPropertyValue(name)).not.to.eq(value)
+}
+
+export let haveComputedStyle = (name, value) => el => {
+    const win = el[0].ownerDocument.defaultView
+    expect(win.getComputedStyle(el[0]).getPropertyValue(name)).to.eq(value)
+}
+
 export function root(el) {
     if (el._x_dataStack) return el