11import Log from '@libs/Log' ;
22import CONST from '@src/CONST' ;
33
4+ type TransitionHandle = symbol ;
5+
46type CancelHandle = { cancel : ( ) => void } ;
57
68type RunAfterTransitionsOptions = {
@@ -16,9 +18,7 @@ type RunAfterTransitionsOptions = {
1618 waitForUpcomingTransition ?: boolean ;
1719} ;
1820
19- let activeCount = 0 ;
20-
21- const activeTimeouts : Array < ReturnType < typeof setTimeout > > = [ ] ;
21+ const activeTransitions = new Map < TransitionHandle , ReturnType < typeof setTimeout > > ( ) ;
2222
2323let pendingCallbacks : Array < ( ) => void > = [ ] ;
2424
@@ -44,24 +44,23 @@ function flushCallbacks(): void {
4444}
4545
4646/**
47- * Decrements the active count and flushes callbacks when all transitions are idle.
47+ * Flushes callbacks when all transitions are idle.
4848 * Shared by {@link endTransition} (manual) and the auto-timeout.
4949 */
5050function decrementAndFlush ( ) : void {
51- activeCount = Math . max ( 0 , activeCount - 1 ) ;
52-
53- if ( activeCount === 0 ) {
54- flushCallbacks ( ) ;
51+ if ( activeTransitions . size !== 0 ) {
52+ return ;
5553 }
54+ flushCallbacks ( ) ;
5655}
5756
5857/**
59- * Increments the active transition count.
60- * Multiple overlapping transitions are counted .
61- * Each transition automatically ends after {@link MAX_TRANSITION_DURATION_MS} as a safety net.
58+ * Increments the active transition count and returns a handle that must be passed to { @link endTransition} .
59+ * Multiple overlapping transitions are tracked independently .
60+ * Each transition automatically ends after {@link CONST. MAX_TRANSITION_DURATION_MS} as a safety net.
6261 */
63- function startTransition ( ) : void {
64- activeCount += 1 ;
62+ function startTransition ( ) : TransitionHandle {
63+ const handle : TransitionHandle = Symbol ( 'transition' ) ;
6564
6665 const resolve = nextTransitionStartResolve ;
6766 if ( resolve ) {
@@ -73,27 +72,29 @@ function startTransition(): void {
7372 }
7473
7574 const timeout = setTimeout ( ( ) => {
76- const idx = activeTimeouts . indexOf ( timeout ) ;
77- if ( idx !== - 1 ) {
78- activeTimeouts . splice ( idx , 1 ) ;
79- }
75+ activeTransitions . delete ( handle ) ;
8076 decrementAndFlush ( ) ;
8177 } , CONST . MAX_TRANSITION_DURATION_MS ) ;
8278
83- activeTimeouts . push ( timeout ) ;
79+ activeTransitions . set ( handle , timeout ) ;
80+
81+ return handle ;
8482}
8583
8684/**
87- * Decrements the active transition count.
88- * Clears the corresponding auto-timeout since the transition ended normally.
89- * When the count reaches zero, flushes all pending callbacks.
85+ * Ends the transition identified by {@link handle}.
86+ * Clears the corresponding safety timeout since the transition ended normally.
87+ * When no active transitions remain, flushes all pending callbacks.
88+ * If the handle is unknown (already ended or already expired via safety timeout), this is a no-op.
9089 */
91- function endTransition ( ) : void {
92- const timeout = activeTimeouts . shift ( ) ;
93- if ( timeout ! == undefined ) {
94- clearTimeout ( timeout ) ;
90+ function endTransition ( handle : TransitionHandle ) : void {
91+ const timeout = activeTransitions . get ( handle ) ;
92+ if ( timeout = == undefined ) {
93+ return ;
9594 }
9695
96+ clearTimeout ( timeout ) ;
97+ activeTransitions . delete ( handle ) ;
9798 decrementAndFlush ( ) ;
9899}
99100
@@ -133,12 +134,13 @@ function runAfterTransitions({callback, runImmediately = false, waitForUpcomingT
133134 return {
134135 cancel : ( ) => {
135136 cancelled = true ;
137+ clearTimeout ( transitionStartTimeoutId ) ;
136138 innerHandle ?. cancel ( ) ;
137139 } ,
138140 } ;
139141 }
140142
141- if ( activeCount === 0 || runImmediately ) {
143+ if ( activeTransitions . size === 0 || runImmediately ) {
142144 callback ( ) ;
143145 return { cancel : ( ) => { } } ;
144146 }
@@ -162,4 +164,4 @@ const TransitionTracker = {
162164} ;
163165
164166export default TransitionTracker ;
165- export type { CancelHandle } ;
167+ export type { CancelHandle , TransitionHandle } ;
0 commit comments