Skip to content
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

Merged
merged 6 commits into from
Oct 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions lib/src/component/abstract_transition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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),
Expand All @@ -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);

Expand All @@ -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
);
}

Expand All @@ -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.';
}
Copy link
Contributor Author

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 in hasTransitionIn and hasTransitionOut, and behave as if there is no transition (see tests).


assert(ValidationUtil.warn(warningMessage, this));

skipCount = 0;
}
var transitionCount = isOrWillBeHidden ? transitionOutCount : transitionInCount;

_cancelTransitionEventListener();
_cancelTransitionEndTimer();
Expand All @@ -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();
Expand Down Expand Up @@ -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>{
Copy link
Contributor

@seangerhardt-wf seangerhardt-wf Oct 9, 2017

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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):

TransitionPhase.SHOWN

<div data-transition-phase="shown"><!-- ... -->

TransitionPhase.HIDDEN

<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
// --------------------------------------------------------------------------
Expand Down
16 changes: 14 additions & 2 deletions lib/src/component/abstract_transition_props.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,23 @@ abstract class TransitionPropsMixin {

Map get props;

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

/// The number of `transitionend` event that occur when the transition node is shown.
///
/// Default: [transitionCount]
int transitionInCount;

/// The number of `transitionend` event that occur when the transition node is hidden.
///
/// Default: [transitionCount]
int transitionOutCount;

/// Optional callback that fires before the [AbstractTransitionComponent] is hidden.
///
/// Returning `false` will cancel default behavior, and the [AbstractTransitionComponent] will remain visible.
Expand Down
Loading