Browse Source

Merge transition-improvements-2

Simone Todaro 5 years ago
parent
commit
a306ac09de
2 changed files with 32 additions and 19 deletions
  1. 1 1
      src/directives/if.js
  2. 31 18
      src/utils.js

+ 1 - 1
src/directives/if.js

@@ -5,7 +5,7 @@ export function handleIfDirective(component, el, expressionResult, initialUpdate
 
     const elementHasAlreadyBeenAdded = el.nextElementSibling && el.nextElementSibling.__x_inserted_me === true
 
-    if (expressionResult && ! elementHasAlreadyBeenAdded) {
+    if (expressionResult && (! elementHasAlreadyBeenAdded || el.__x_transition)) {
         const clone = document.importNode(el.content, true);
 
         el.parentElement.insertBefore(clone, el.nextElementSibling)

+ 31 - 18
src/utils.js

@@ -165,6 +165,12 @@ const TRANSITION_TYPE_IN = 'in'
 const TRANSITION_TYPE_OUT = 'out'
 
 export function transitionIn(el, show, component, forceSkip = false) {
+    if (el.__x_transition && el.__x_transition.type === TRANSITION_TYPE_IN) {
+        // there is already a similar transition going on, this was probably triggered by
+        // a change in a different property, let's just leave the previous one doing its job
+        return
+    }
+
     // We don't want to transition on the initial page load.
     if (forceSkip) return show()
 
@@ -308,6 +314,7 @@ function modifierValue(modifiers, key, fallback) {
 export function transitionHelper(el, modifiers, hook1, hook2, styleValues, type) {
     // clear the previous transition if exists to avoid caching the wrong styles
     if (el.__x_transition) {
+        cancelAnimationFrame(el.__x_transition.nextFrame)
         el.__x_transition.callback()
     }
 
@@ -383,6 +390,7 @@ export function transitionClassesOut(el, component, directives, hideCallback) {
 export function transitionClasses(el, classesDuring, classesStart, classesEnd, hook1, hook2, type) {
     // clear the previous transition if exists to avoid caching the wrong classes
     if (el.__x_transition) {
+        cancelAnimationFrame(el.__x_transition.nextFrame)
         el.__x_transition.callback()
     }
 
@@ -416,10 +424,31 @@ export function transitionClasses(el, classesDuring, classesStart, classesEnd, h
 }
 
 export function transition(el, stages, type) {
+    el.__x_transition = {
+        // Set transition type so we can avoid clearing transition if the direction is the same
+       type: type,
+        // create a callback for the last stages of the transition so we can call it
+        // from different point and early terminate it. Once will ensure that function
+        // is only called one time.
+        callback: once(() => {
+            stages.hide()
+
+            // Adding an "isConnected" check, in case the callback
+            // removed the element from the DOM.
+            if (el.isConnected) {
+                stages.cleanup()
+            }
+
+            delete el.__x_transition
+        }),
+        // This store the next animation frame so we can cancel it
+        nextFrame: null
+    }
+
     stages.start()
     stages.during()
 
-    requestAnimationFrame(() => {
+    el.__x_transition.nextFrame =requestAnimationFrame(() => {
         // Note: Safari's transitionDuration property will list out comma separated transition durations
         // for every single transition property. Let's grab the first one and call it a day.
         let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000
@@ -430,25 +459,9 @@ export function transition(el, stages, type) {
 
         stages.show()
 
-        requestAnimationFrame(() => {
+        el.__x_transition.nextFrame =requestAnimationFrame(() => {
             stages.end()
 
-            // Set transition type so we can avoid clearing transition if the direction is the same
-            el.__x_transition = { type: type }
-
-            // Assign current transition to el in case we need to force it.
-            el.__x_transition.callback = once(() => {
-                stages.hide()
-
-                // Adding an "isConnected" check, in case the callback
-                // removed the element from the DOM.
-                if (el.isConnected) {
-                    stages.cleanup()
-                }
-
-                delete el.__x_transition
-            })
-
             setTimeout(el.__x_transition.callback, duration)
         })
     });