@@ -19,6 +19,7 @@ import 'dart:html';
19
19
20
20
import 'package:meta/meta.dart' ;
21
21
import 'package:over_react/over_react.dart' ;
22
+ import 'package:over_react/component_base.dart' as component_base;
22
23
23
24
@AbstractProps ()
24
25
abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin {}
@@ -27,7 +28,7 @@ abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin
27
28
abstract class AbstractTransitionState extends UiState {
28
29
/// The current phase of transition the [AbstractTransitionComponent] is in.
29
30
///
30
- /// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionState .SHOWN] : [TransitionState .HIDDEN]
31
+ /// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionPhase .SHOWN] : [TransitionPhase .HIDDEN]
31
32
TransitionPhase transitionPhase;
32
33
}
33
34
@@ -81,6 +82,18 @@ abstract class AbstractTransitionState extends UiState {
81
82
abstract class AbstractTransitionComponent <T extends AbstractTransitionProps ,
82
83
S extends AbstractTransitionState >
83
84
extends UiStatefulComponent <T , S > {
85
+ /// The DOM attribute used to indicate the current transition phase,
86
+ /// added in test mode in [getTransitionTestAttributes] .
87
+ ///
88
+ /// Possible values:
89
+ ///
90
+ /// - `pre-showing`
91
+ /// - `showing`
92
+ /// - `shown`
93
+ /// - `hiding`
94
+ /// - `hidden`
95
+ static const String transitionPhaseTestAttr = 'data-transition-phase' ;
96
+
84
97
@override
85
98
get consumedProps => const [
86
99
const $Props (AbstractTransitionProps ),
@@ -106,9 +119,25 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
106
119
/// Returns the DOM node that will transition.
107
120
Element getTransitionDomNode ();
108
121
109
- /// Whether the Element returned by [getTransitionDomNode] will have a transition event .
122
+ /// Whether transitions are enabled for this component .
110
123
bool get hasTransition => true ;
111
124
125
+ /// Whether the Element returned by [getTransitionDomNode] will have a transition event when showing.
126
+ bool get hasTransitionIn => hasTransition && transitionInCount > 0 ;
127
+
128
+ /// Whether the Element returned by [getTransitionDomNode] will have a transition event when hiding.
129
+ bool get hasTransitionOut => hasTransition && transitionOutCount > 0 ;
130
+
131
+ /// The number of `transitionend` events that occur when the transition node is shown.
132
+ ///
133
+ /// Defaults to `1` to match previous behavior in the case where `props.transitionCount` is `null` .
134
+ int get transitionInCount => props.transitionInCount ?? props.transitionCount ?? 1 ;
135
+
136
+ /// The number of `transitionend` events that occur when the transition node is hidden.
137
+ ///
138
+ /// Defaults to `1` to match previous behavior in the case where `props.transitionCount` is `null` .
139
+ int get transitionOutCount => props.transitionOutCount ?? props.transitionCount ?? 1 ;
140
+
112
141
/// The duration that can elapse before a transition timeout occurs.
113
142
Duration get transitionTimeout => const Duration (seconds: 1 );
114
143
@@ -135,7 +164,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
135
164
prepareShow ();
136
165
137
166
setState (newState ()
138
- ..transitionPhase = hasTransition ? TransitionPhase .PRE_SHOWING : TransitionPhase .SHOWN
167
+ ..transitionPhase = hasTransitionIn ? TransitionPhase .PRE_SHOWING : TransitionPhase .SHOWN
139
168
);
140
169
}
141
170
@@ -155,27 +184,15 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
155
184
prepareHide ();
156
185
157
186
setState (newState ()
158
- ..transitionPhase = hasTransition ? TransitionPhase .HIDING : TransitionPhase .HIDDEN
187
+ ..transitionPhase = hasTransitionOut ? TransitionPhase .HIDING : TransitionPhase .HIDDEN
159
188
);
160
189
}
161
190
162
191
/// Listens for the next `transitionend` event and invokes a callback after
163
192
/// the event is dispatched.
164
193
@mustCallSuper
165
194
void onNextTransitionEnd (complete ()) {
166
- var skipCount = props.transitionCount - 1 ;
167
-
168
- if (props.transitionCount <= 0 ) {
169
- var warningMessage = 'You have set `props.transitionCount` to an invalid option: ${props .transitionCount }.' ;
170
-
171
- if (props.transitionCount == 0 ) {
172
- warningMessage += ' Instead of setting this prop to 0, override the `hasTransition` getter to return false.' ;
173
- }
174
-
175
- assert (ValidationUtil .warn (warningMessage, this ));
176
-
177
- skipCount = 0 ;
178
- }
195
+ var transitionCount = isOrWillBeHidden ? transitionOutCount : transitionInCount;
179
196
180
197
_cancelTransitionEventListener ();
181
198
_cancelTransitionEndTimer ();
@@ -191,7 +208,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
191
208
complete ();
192
209
});
193
210
194
- _endTransitionSubscription = getTransitionDomNode ()? .onTransitionEnd? .skip (skipCount )? .take (1 )? .listen ((_) {
211
+ _endTransitionSubscription = getTransitionDomNode ()? .onTransitionEnd? .skip (transitionCount - 1 )? .take (1 )? .listen ((_) {
195
212
_cancelTransitionEndTimer ();
196
213
197
214
complete ();
@@ -368,6 +385,23 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
368
385
}
369
386
}
370
387
388
+ /// Returns attributes only available during testing that indicate the state of the transition.
389
+ Map <String , String > getTransitionTestAttributes () {
390
+ if (! component_base.UiProps .testMode) return const {};
391
+
392
+ const enumToAttrValue = const < TransitionPhase , String > {
393
+ TransitionPhase .SHOWN : 'shown' ,
394
+ TransitionPhase .HIDDEN : 'hidden' ,
395
+ TransitionPhase .HIDING : 'hiding' ,
396
+ TransitionPhase .PRE_SHOWING : 'pre-showing' ,
397
+ TransitionPhase .SHOWING : 'showing' ,
398
+ };
399
+
400
+ return {
401
+ transitionPhaseTestAttr: enumToAttrValue[state.transitionPhase],
402
+ };
403
+ }
404
+
371
405
// --------------------------------------------------------------------------
372
406
// Public API Methods
373
407
// --------------------------------------------------------------------------
0 commit comments