Skip to content

Commit 0e2d010

Browse files
Merge pull request #120 from greglittlefield-wf/transition-in-out
UIP-2751 Transition in/out-specific config, test attributes
2 parents ac9a909 + d9dabc5 commit 0e2d010

File tree

3 files changed

+296
-105
lines changed

3 files changed

+296
-105
lines changed

lib/src/component/abstract_transition.dart

+52-18
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'dart:html';
1919

2020
import 'package:meta/meta.dart';
2121
import 'package:over_react/over_react.dart';
22+
import 'package:over_react/component_base.dart' as component_base;
2223

2324
@AbstractProps()
2425
abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin {}
@@ -27,7 +28,7 @@ abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin
2728
abstract class AbstractTransitionState extends UiState {
2829
/// The current phase of transition the [AbstractTransitionComponent] is in.
2930
///
30-
/// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionState.SHOWN] : [TransitionState.HIDDEN]
31+
/// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionPhase.SHOWN] : [TransitionPhase.HIDDEN]
3132
TransitionPhase transitionPhase;
3233
}
3334

@@ -81,6 +82,18 @@ abstract class AbstractTransitionState extends UiState {
8182
abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
8283
S extends AbstractTransitionState>
8384
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+
8497
@override
8598
get consumedProps => const [
8699
const $Props(AbstractTransitionProps),
@@ -106,9 +119,25 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
106119
/// Returns the DOM node that will transition.
107120
Element getTransitionDomNode();
108121

109-
/// Whether the Element returned by [getTransitionDomNode] will have a transition event.
122+
/// Whether transitions are enabled for this component.
110123
bool get hasTransition => true;
111124

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+
112141
/// The duration that can elapse before a transition timeout occurs.
113142
Duration get transitionTimeout => const Duration(seconds: 1);
114143

@@ -135,7 +164,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
135164
prepareShow();
136165

137166
setState(newState()
138-
..transitionPhase = hasTransition ? TransitionPhase.PRE_SHOWING : TransitionPhase.SHOWN
167+
..transitionPhase = hasTransitionIn ? TransitionPhase.PRE_SHOWING : TransitionPhase.SHOWN
139168
);
140169
}
141170

@@ -155,27 +184,15 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
155184
prepareHide();
156185

157186
setState(newState()
158-
..transitionPhase = hasTransition ? TransitionPhase.HIDING : TransitionPhase.HIDDEN
187+
..transitionPhase = hasTransitionOut ? TransitionPhase.HIDING : TransitionPhase.HIDDEN
159188
);
160189
}
161190

162191
/// Listens for the next `transitionend` event and invokes a callback after
163192
/// the event is dispatched.
164193
@mustCallSuper
165194
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;
179196

180197
_cancelTransitionEventListener();
181198
_cancelTransitionEndTimer();
@@ -191,7 +208,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
191208
complete();
192209
});
193210

194-
_endTransitionSubscription = getTransitionDomNode()?.onTransitionEnd?.skip(skipCount)?.take(1)?.listen((_) {
211+
_endTransitionSubscription = getTransitionDomNode()?.onTransitionEnd?.skip(transitionCount - 1)?.take(1)?.listen((_) {
195212
_cancelTransitionEndTimer();
196213

197214
complete();
@@ -368,6 +385,23 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps,
368385
}
369386
}
370387

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+
371405
// --------------------------------------------------------------------------
372406
// Public API Methods
373407
// --------------------------------------------------------------------------

lib/src/component/abstract_transition_props.dart

+14-2
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,23 @@ abstract class TransitionPropsMixin {
2727

2828
Map get props;
2929

30-
/// Number of transitions to occur within the [AbstractTransitionComponent].
30+
/// The number of `transitionend` event that occur when the transition node is shown/hidden.
3131
///
32-
/// Default: 1
32+
/// Serves as the default for [transitionInCount]/[transitionOutCount] when they are not specified.
33+
///
34+
/// Default: `1`
3335
int transitionCount;
3436

37+
/// The number of `transitionend` event that occur when the transition node is shown.
38+
///
39+
/// Default: [transitionCount]
40+
int transitionInCount;
41+
42+
/// The number of `transitionend` event that occur when the transition node is hidden.
43+
///
44+
/// Default: [transitionCount]
45+
int transitionOutCount;
46+
3547
/// Optional callback that fires before the [AbstractTransitionComponent] is hidden.
3648
///
3749
/// Returning `false` will cancel default behavior, and the [AbstractTransitionComponent] will remain visible.

0 commit comments

Comments
 (0)