Skip to content

Commit 9329b65

Browse files
authored
New: event handler for CSS transitions (#537)
1 parent d4a8f27 commit 9329b65

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

js/transitions.js

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import logging from 'core/js/logging';
2+
3+
/**
4+
* Handler to await completion of active `CSSTransitions`.
5+
* An optional `transition-property` to await can be specified, else all properties will be evaluated.
6+
* @param {jQuery} $element
7+
* @param {string} [property=null]
8+
* @returns {Promise<boolean>}
9+
*/
10+
export async function transitionsEnded($element, property = null) {
11+
$element = $($element).first();
12+
if (!willTransition($element, property)) return false;
13+
const longestEndTime = getTransitionsLongestEndTime($element, property);
14+
const buffer = 100;
15+
const timeoutDuration = longestEndTime + buffer;
16+
return new Promise(resolve => {
17+
const onRun = () => clearTimeout(resolveInterval);
18+
const onEnd = () => {
19+
if (hasActiveTransition($element, property)) return;
20+
done(true);
21+
};
22+
const done = (didTransition) => {
23+
clearTimeout(resolveInterval);
24+
$element
25+
.off('transitionrun', onRun)
26+
.off('transitioncancel transitionend', onEnd);
27+
resolve(didTransition);
28+
};
29+
$element
30+
.on('transitionrun', onRun)
31+
.on('transitioncancel transitionend', onEnd);
32+
const resolveInterval = setTimeout(() => {
33+
logging.warn('transition could/did not run, forcing resolution', $element[0]);
34+
if (hasActiveTransition($element, property)) return;
35+
done(false);
36+
}, timeoutDuration);
37+
});
38+
}
39+
40+
/**
41+
* Returns the longest end time of the configured transitions
42+
* @param {jQuery} $element
43+
* @param {string} [property=null]
44+
* @returns {number}
45+
*/
46+
export function getTransitionsLongestEndTime($element, property = null) {
47+
$element = $($element);
48+
const properties = $element.css('transition-property').split(',').map(property => property.trim());
49+
const durations = $element.css('transition-duration').split(',').map(duration => parseFloat(duration));
50+
const delays = $element.css('transition-delay').split(',').map(delay => parseFloat(delay));
51+
const endTimes = properties.reduce((result, transitionProperty, index) => {
52+
// cycle through populated timings as per spec
53+
const duration = durations[index % durations.length];
54+
const delay = delays[index % delays.length];
55+
const endTime = duration + delay;
56+
result[transitionProperty] = endTime;
57+
return result;
58+
}, {});
59+
const isAllProperty = property === 'all' || Boolean(endTimes.all);
60+
const longestEndTime = (property && !isAllProperty)
61+
? endTimes[property]
62+
: Math.max(...Object.values(endTimes));
63+
return (longestEndTime ?? 0) * 1000; // Convert to milliseconds
64+
}
65+
66+
/**
67+
* Returns whether a `CSSTransition` will be run on an element.
68+
* An optional `transition-property` can be specified, else all properties will be evaluated.
69+
* @param {jQuery} $element
70+
* @param {string} [property=null]
71+
* @returns {boolean}
72+
*/
73+
export function willTransition($element, property = null) {
74+
if (hasActiveTransition($element, property)) return true;
75+
return (getTransitionsLongestEndTime($element, property) > 0);
76+
}
77+
78+
/**
79+
* Returns whether `CSSTransitions` are still active for an element.
80+
* An optional `transition-property` can be specified, else all properties will be evaluated.
81+
* @param {jQuery} $element
82+
* @param {string} [property=null]
83+
* @returns {boolean}
84+
*/
85+
export function hasActiveTransition($element, property = null) {
86+
const element = $($element)[0];
87+
let transitions = element.getAnimations().filter(animation => animation instanceof window.CSSTransition);
88+
if (property) transitions = transitions.filter(({ transitionProperty }) => transitionProperty === property);
89+
return Boolean(transitions.length);
90+
}
91+
92+
export default {
93+
transitionsEnded,
94+
getTransitionsLongestEndTime,
95+
willTransition,
96+
hasActiveTransition
97+
};

0 commit comments

Comments
 (0)