7
7
// transition(this.element, false)
8
8
export async function transition ( element , state , transitionOptions = { } ) {
9
9
if ( ! ! state ) {
10
- enter ( element , transitionOptions )
10
+ await enter ( element , transitionOptions )
11
11
} else {
12
- leave ( element , transitionOptions )
12
+ await leave ( element , transitionOptions )
13
13
}
14
14
}
15
15
@@ -22,62 +22,121 @@ export async function transition(element, state, transitionOptions = {}) {
22
22
// data-transition-leave-to="bg-opacity-0"
23
23
export async function enter ( element , transitionOptions = { } ) {
24
24
const transitionClasses = element . dataset . transitionEnter || transitionOptions . enter || 'enter'
25
- const fromClasses =
26
- element . dataset . transitionEnterFrom || transitionOptions . enterFrom || 'enter-from'
25
+ const fromClasses = element . dataset . transitionEnterFrom || transitionOptions . enterFrom || 'enter-from'
27
26
const toClasses = element . dataset . transitionEnterTo || transitionOptions . enterTo || 'enter-to'
28
27
const toggleClass = element . dataset . toggleClass || transitionOptions . toggleClass || 'hidden'
29
28
30
- // Prepare transition
31
- element . classList . add ( ...transitionClasses . split ( ' ' ) )
32
- element . classList . add ( ...fromClasses . split ( ' ' ) )
33
- element . classList . remove ( ...toClasses . split ( ' ' ) )
34
- element . classList . remove ( ...toggleClass . split ( ' ' ) )
35
-
36
- await nextFrame ( )
37
-
38
- element . classList . remove ( ...fromClasses . split ( ' ' ) )
39
- element . classList . add ( ...toClasses . split ( ' ' ) )
40
-
41
- try {
42
- await afterTransition ( element )
43
- } finally {
44
- element . classList . remove ( ...transitionClasses . split ( ' ' ) )
45
- }
29
+ return performTransitions ( element , {
30
+ firstFrame ( ) {
31
+ element . classList . add ( ...transitionClasses . split ( ' ' ) )
32
+ element . classList . add ( ...fromClasses . split ( ' ' ) )
33
+ element . classList . remove ( ...toClasses . split ( ' ' ) )
34
+ element . classList . remove ( ...toggleClass . split ( ' ' ) )
35
+ } ,
36
+ secondFrame ( ) {
37
+ element . classList . remove ( ...fromClasses . split ( ' ' ) )
38
+ element . classList . add ( ...toClasses . split ( ' ' ) )
39
+ } ,
40
+ ending ( ) {
41
+ element . classList . remove ( ...transitionClasses . split ( ' ' ) )
42
+ }
43
+ } )
46
44
}
47
45
48
46
export async function leave ( element , transitionOptions = { } ) {
49
47
const transitionClasses = element . dataset . transitionLeave || transitionOptions . leave || 'leave'
50
- const fromClasses =
51
- element . dataset . transitionLeaveFrom || transitionOptions . leaveFrom || 'leave-from'
48
+ const fromClasses = element . dataset . transitionLeaveFrom || transitionOptions . leaveFrom || 'leave-from'
52
49
const toClasses = element . dataset . transitionLeaveTo || transitionOptions . leaveTo || 'leave-to'
53
50
const toggleClass = element . dataset . toggleClass || transitionOptions . toggle || 'hidden'
54
51
55
- // Prepare transition
56
- element . classList . add ( ...transitionClasses . split ( ' ' ) )
57
- element . classList . add ( ...fromClasses . split ( ' ' ) )
58
- element . classList . remove ( ...toClasses . split ( ' ' ) )
59
-
60
- await nextFrame ( )
52
+ return performTransitions ( element , {
53
+ firstFrame ( ) {
54
+ element . classList . add ( ...fromClasses . split ( ' ' ) )
55
+ element . classList . remove ( ...toClasses . split ( ' ' ) )
56
+ element . classList . add ( ...transitionClasses . split ( ' ' ) )
57
+ } ,
58
+ secondFrame ( ) {
59
+ element . classList . remove ( ...fromClasses . split ( ' ' ) )
60
+ element . classList . add ( ...toClasses . split ( ' ' ) )
61
+ } ,
62
+ ending ( ) {
63
+ element . classList . remove ( ...transitionClasses . split ( ' ' ) )
64
+ element . classList . add ( ...toggleClass . split ( ' ' ) )
65
+ }
66
+ } )
67
+ }
61
68
62
- element . classList . remove ( ...fromClasses . split ( ' ' ) )
63
- element . classList . add ( ...toClasses . split ( ' ' ) )
69
+ function setupTransition ( element ) {
70
+ element . _stimulus_transition = {
71
+ timeout : null ,
72
+ interrupted : false
73
+ }
74
+ }
64
75
65
- try {
66
- await afterTransition ( element )
67
- } finally {
68
- element . classList . remove ( ...transitionClasses . split ( ' ' ) )
69
- element . classList . add ( ...toggleClass . split ( ' ' ) )
76
+ export function cancelTransition ( element ) {
77
+ if ( element . _stimulus_transition && element . _stimulus_transition . interrupt ) {
78
+ element . _stimulus_transition . interrupt ( )
70
79
}
71
80
}
72
81
73
- function nextFrame ( ) {
74
- return new Promise ( resolve => {
82
+ function performTransitions ( element , transitionStages ) {
83
+ if ( element . _stimulus_transition ) cancelTransition ( element )
84
+
85
+ let interrupted , firstStageComplete , secondStageComplete
86
+ setupTransition ( element )
87
+
88
+ element . _stimulus_transition . cleanup = ( ) => {
89
+ if ( ! firstStageComplete ) transitionStages . firstFrame ( )
90
+ if ( ! secondStageComplete ) transitionStages . secondFrame ( )
91
+
92
+ transitionStages . ending ( )
93
+ element . _stimulus_transition = null
94
+ }
95
+
96
+ element . _stimulus_transition . interrupt = ( ) => {
97
+ interrupted = true
98
+ if ( element . _stimulus_transition . timeout ) {
99
+ clearTimeout ( element . _stimulus_transition . timeout )
100
+ }
101
+ element . _stimulus_transition . cleanup ( )
102
+ }
103
+
104
+ return new Promise ( ( resolve ) => {
105
+ if ( interrupted ) return
106
+
75
107
requestAnimationFrame ( ( ) => {
76
- requestAnimationFrame ( resolve )
108
+ if ( interrupted ) return
109
+
110
+ transitionStages . firstFrame ( )
111
+ firstStageComplete = true
112
+
113
+ requestAnimationFrame ( ( ) => {
114
+ if ( interrupted ) return
115
+
116
+ transitionStages . secondFrame ( )
117
+ secondStageComplete = true
118
+
119
+ if ( element . _stimulus_transition ) {
120
+ element . _stimulus_transition . timeout = setTimeout ( ( ) => {
121
+ if ( interrupted ) {
122
+ resolve ( )
123
+ return
124
+ }
125
+
126
+ element . _stimulus_transition . cleanup ( )
127
+ resolve ( )
128
+ } , getAnimationDuration ( element ) )
129
+ }
130
+ } )
77
131
} )
78
132
} )
79
133
}
80
134
81
- function afterTransition ( element ) {
82
- return Promise . all ( element . getAnimations ( ) . map ( animation => animation . finished ) )
135
+ function getAnimationDuration ( element ) {
136
+ let duration = Number ( getComputedStyle ( element ) . transitionDuration . replace ( / , .* / , '' ) . replace ( 's' , '' ) ) * 1000
137
+ let delay = Number ( getComputedStyle ( element ) . transitionDelay . replace ( / , .* / , '' ) . replace ( 's' , '' ) ) * 1000
138
+
139
+ if ( duration === 0 ) duration = Number ( getComputedStyle ( element ) . animationDuration . replace ( 's' , '' ) ) * 1000
140
+
141
+ return duration + delay
83
142
}
0 commit comments