@@ -15,6 +15,81 @@ const DEFAULT_REDUCED_MOTION_ATOM: NonNullable<AtomMotion['reducedMotion']> = {
1515 duration : 1 ,
1616} ;
1717
18+ /**
19+ * Creates an animation handle that controls multiple animations.
20+ * Is used to avoid leaking "element" references from the hook.
21+ *
22+ * @param animations
23+ */
24+ function createHandle ( animations : Animation [ ] ) : AnimationHandle {
25+ return {
26+ set playbackRate ( rate : number ) {
27+ animations . forEach ( animation => {
28+ animation . playbackRate = rate ;
29+ } ) ;
30+ } ,
31+ setMotionEndCallbacks ( onfinish : ( ) => void , oncancel : ( ) => void ) {
32+ // Heads up!
33+ // This could use "Animation:finished", but it's causing a memory leak in Chromium.
34+ // See: https://issues.chromium.org/u/2/issues/383016426
35+ const promises = animations . map ( animation => {
36+ return new Promise < void > ( ( resolve , reject ) => {
37+ animation . onfinish = ( ) => resolve ( ) ;
38+ animation . oncancel = ( ) => reject ( ) ;
39+ } ) ;
40+ } ) ;
41+
42+ Promise . all ( promises )
43+ . then ( ( ) => {
44+ onfinish ( ) ;
45+ } )
46+ . catch ( ( ) => {
47+ oncancel ( ) ;
48+ } ) ;
49+ } ,
50+ isRunning ( ) {
51+ return animations . some ( animation => isAnimationRunning ( animation ) ) ;
52+ } ,
53+
54+ dispose : ( ) => {
55+ animations . length = 0 ;
56+ } ,
57+
58+ cancel : ( ) => {
59+ animations . forEach ( animation => {
60+ animation . cancel ( ) ;
61+ } ) ;
62+ } ,
63+ pause : ( ) => {
64+ animations . forEach ( animation => {
65+ animation . pause ( ) ;
66+ } ) ;
67+ } ,
68+ play : ( ) => {
69+ animations . forEach ( animation => {
70+ animation . play ( ) ;
71+ } ) ;
72+ } ,
73+ finish : ( ) => {
74+ animations . forEach ( animation => {
75+ animation . finish ( ) ;
76+ } ) ;
77+ } ,
78+ reverse : ( ) => {
79+ // Heads up!
80+ //
81+ // This is used for the interruptible motion. If the animation is running, we need to reverse it.
82+ //
83+ // TODO: what do with animations that have "delay"?
84+ // TODO: what do with animations that have different "durations"?
85+
86+ animations . forEach ( animation => {
87+ animation . reverse ( ) ;
88+ } ) ;
89+ } ,
90+ } ;
91+ }
92+
1893function useAnimateAtomsInSupportedEnvironment ( ) {
1994 // eslint-disable-next-line @nx/workspace-no-restricted-globals
2095 const SUPPORTS_PERSIST = typeof window !== 'undefined' && typeof window . Animation ?. prototype . persist === 'function' ;
@@ -67,68 +142,7 @@ function useAnimateAtomsInSupportedEnvironment() {
67142 } )
68143 . filter ( animation => ! ! animation ) as Animation [ ] ;
69144
70- return {
71- set playbackRate ( rate : number ) {
72- animations . forEach ( animation => {
73- animation . playbackRate = rate ;
74- } ) ;
75- } ,
76- setMotionEndCallbacks ( onfinish : ( ) => void , oncancel : ( ) => void ) {
77- // Heads up!
78- // This could use "Animation:finished", but it's causing a memory leak in Chromium.
79- // See: https://issues.chromium.org/u/2/issues/383016426
80- const promises = animations . map ( animation => {
81- return new Promise < void > ( ( resolve , reject ) => {
82- animation . onfinish = ( ) => resolve ( ) ;
83- animation . oncancel = ( ) => reject ( ) ;
84- } ) ;
85- } ) ;
86-
87- Promise . all ( promises )
88- . then ( ( ) => {
89- onfinish ( ) ;
90- } )
91- . catch ( ( ) => {
92- oncancel ( ) ;
93- } ) ;
94- } ,
95- isRunning ( ) {
96- return animations . some ( animation => isAnimationRunning ( animation ) ) ;
97- } ,
98-
99- cancel : ( ) => {
100- animations . forEach ( animation => {
101- animation . cancel ( ) ;
102- } ) ;
103- } ,
104- pause : ( ) => {
105- animations . forEach ( animation => {
106- animation . pause ( ) ;
107- } ) ;
108- } ,
109- play : ( ) => {
110- animations . forEach ( animation => {
111- animation . play ( ) ;
112- } ) ;
113- } ,
114- finish : ( ) => {
115- animations . forEach ( animation => {
116- animation . finish ( ) ;
117- } ) ;
118- } ,
119- reverse : ( ) => {
120- // Heads up!
121- //
122- // This is used for the interruptible motion. If the animation is running, we need to reverse it.
123- //
124- // TODO: what do with animations that have "delay"?
125- // TODO: what do with animations that have different "durations"?
126-
127- animations . forEach ( animation => {
128- animation . reverse ( ) ;
129- } ) ;
130- } ,
131- } ;
145+ return createHandle ( animations ) ;
132146 } ,
133147 [ SUPPORTS_PERSIST ] ,
134148 ) ;
@@ -181,6 +195,10 @@ function useAnimateAtomsInTestEnvironment() {
181195 return false ;
182196 } ,
183197
198+ dispose ( ) {
199+ /* no-op */
200+ } ,
201+
184202 cancel ( ) {
185203 /* no-op */
186204 } ,
0 commit comments