-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UIP-2751 Transition in/out-specific config, test attributes #120
Changes from all commits
a5ffa6b
1e9c476
87f8f2b
f8ace21
acbd73d
d9dabc5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ import 'dart:html'; | |
|
||
import 'package:meta/meta.dart'; | ||
import 'package:over_react/over_react.dart'; | ||
import 'package:over_react/component_base.dart' as component_base; | ||
|
||
@AbstractProps() | ||
abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin {} | ||
|
@@ -27,7 +28,7 @@ abstract class AbstractTransitionProps extends UiProps with TransitionPropsMixin | |
abstract class AbstractTransitionState extends UiState { | ||
/// The current phase of transition the [AbstractTransitionComponent] is in. | ||
/// | ||
/// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionState.SHOWN] : [TransitionState.HIDDEN] | ||
/// Default: [AbstractTransitionComponent.initiallyShown] ? [TransitionPhase.SHOWN] : [TransitionPhase.HIDDEN] | ||
TransitionPhase transitionPhase; | ||
} | ||
|
||
|
@@ -81,6 +82,18 @@ abstract class AbstractTransitionState extends UiState { | |
abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | ||
S extends AbstractTransitionState> | ||
extends UiStatefulComponent<T, S> { | ||
/// The DOM attribute used to indicate the current transition phase, | ||
/// added in test mode in [getTransitionTestAttributes]. | ||
/// | ||
/// Possible values: | ||
/// | ||
/// - `pre-showing` | ||
/// - `showing` | ||
/// - `shown` | ||
/// - `hiding` | ||
/// - `hidden` | ||
static const String transitionPhaseTestAttr = 'data-transition-phase'; | ||
|
||
@override | ||
get consumedProps => const [ | ||
const $Props(AbstractTransitionProps), | ||
|
@@ -106,9 +119,25 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | |
/// Returns the DOM node that will transition. | ||
Element getTransitionDomNode(); | ||
|
||
/// Whether the Element returned by [getTransitionDomNode] will have a transition event. | ||
/// Whether transitions are enabled for this component. | ||
bool get hasTransition => true; | ||
|
||
/// Whether the Element returned by [getTransitionDomNode] will have a transition event when showing. | ||
bool get hasTransitionIn => hasTransition && transitionInCount > 0; | ||
|
||
/// Whether the Element returned by [getTransitionDomNode] will have a transition event when hiding. | ||
bool get hasTransitionOut => hasTransition && transitionOutCount > 0; | ||
|
||
/// The number of `transitionend` events that occur when the transition node is shown. | ||
/// | ||
/// Defaults to `1` to match previous behavior in the case where `props.transitionCount` is `null`. | ||
int get transitionInCount => props.transitionInCount ?? props.transitionCount ?? 1; | ||
|
||
/// The number of `transitionend` events that occur when the transition node is hidden. | ||
/// | ||
/// Defaults to `1` to match previous behavior in the case where `props.transitionCount` is `null`. | ||
int get transitionOutCount => props.transitionOutCount ?? props.transitionCount ?? 1; | ||
|
||
/// The duration that can elapse before a transition timeout occurs. | ||
Duration get transitionTimeout => const Duration(seconds: 1); | ||
|
||
|
@@ -135,7 +164,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | |
prepareShow(); | ||
|
||
setState(newState() | ||
..transitionPhase = hasTransition ? TransitionPhase.PRE_SHOWING : TransitionPhase.SHOWN | ||
..transitionPhase = hasTransitionIn ? TransitionPhase.PRE_SHOWING : TransitionPhase.SHOWN | ||
); | ||
} | ||
|
||
|
@@ -155,27 +184,15 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | |
prepareHide(); | ||
|
||
setState(newState() | ||
..transitionPhase = hasTransition ? TransitionPhase.HIDING : TransitionPhase.HIDDEN | ||
..transitionPhase = hasTransitionOut ? TransitionPhase.HIDING : TransitionPhase.HIDDEN | ||
); | ||
} | ||
|
||
/// Listens for the next `transitionend` event and invokes a callback after | ||
/// the event is dispatched. | ||
@mustCallSuper | ||
void onNextTransitionEnd(complete()) { | ||
var skipCount = props.transitionCount - 1; | ||
|
||
if (props.transitionCount <= 0) { | ||
var warningMessage = 'You have set `props.transitionCount` to an invalid option: ${props.transitionCount}.'; | ||
|
||
if (props.transitionCount == 0) { | ||
warningMessage += ' Instead of setting this prop to 0, override the `hasTransition` getter to return false.'; | ||
} | ||
|
||
assert(ValidationUtil.warn(warningMessage, this)); | ||
|
||
skipCount = 0; | ||
} | ||
var transitionCount = isOrWillBeHidden ? transitionOutCount : transitionInCount; | ||
|
||
_cancelTransitionEventListener(); | ||
_cancelTransitionEndTimer(); | ||
|
@@ -191,7 +208,7 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | |
complete(); | ||
}); | ||
|
||
_endTransitionSubscription = getTransitionDomNode()?.onTransitionEnd?.skip(skipCount)?.take(1)?.listen((_) { | ||
_endTransitionSubscription = getTransitionDomNode()?.onTransitionEnd?.skip(transitionCount - 1)?.take(1)?.listen((_) { | ||
_cancelTransitionEndTimer(); | ||
|
||
complete(); | ||
|
@@ -368,6 +385,23 @@ abstract class AbstractTransitionComponent<T extends AbstractTransitionProps, | |
} | ||
} | ||
|
||
/// Returns attributes only available during testing that indicate the state of the transition. | ||
Map<String, String> getTransitionTestAttributes() { | ||
if (!component_base.UiProps.testMode) return const {}; | ||
|
||
const enumToAttrValue = const <TransitionPhase, String>{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noobie question - what is the attribute text for the "TransitionPhase"? I assume this is the attribute I'll have to search for in my functional tests when checking if the modal dialog has finished animating. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seangerhardt-wf the HTML will look like this based on the current transition phase (only listing the ones you'd probably be interested in for functional test purposes):
<div data-transition-phase="shown"><!-- ... -->
<div data-transition-phase="hidden"><!-- ... --> |
||
TransitionPhase.SHOWN: 'shown', | ||
TransitionPhase.HIDDEN: 'hidden', | ||
TransitionPhase.HIDING: 'hiding', | ||
TransitionPhase.PRE_SHOWING: 'pre-showing', | ||
TransitionPhase.SHOWING: 'showing', | ||
}; | ||
|
||
return { | ||
transitionPhaseTestAttr: enumToAttrValue[state.transitionPhase], | ||
}; | ||
} | ||
|
||
// -------------------------------------------------------------------------- | ||
// Public API Methods | ||
// -------------------------------------------------------------------------- | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are no longer necessary; transition counts that are
<=0
are accounted for inhasTransitionIn
andhasTransitionOut
, and behave as if there is no transition (see tests).