Skip to content

Commit

Permalink
Add transition UX polish for lightbox animations (#14126)
Browse files Browse the repository at this point in the history
* Add transition UX polish

* Avoid flickering if transitioning from slide with no text
  • Loading branch information
cathyxz committed Mar 20, 2018
1 parent a59bb12 commit 84a316e
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 40 deletions.
12 changes: 8 additions & 4 deletions extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.css
Expand Up @@ -107,14 +107,20 @@
}
}

.i-amphtml-lbg-controls {
.i-amphtml-lbg-controls.show {
opacity: 1;
}

.i-amphtml-lbg-controls.hidden {
opacity: 0;
}

.i-amphtml-lbg-controls.fade-in {
animation: fadeIn ease-in 0.4s 1 forwards;
}

.i-amphtml-lbg-controls.fade-out
{
opacity: 1;
animation: fadeOut linear 0.4s 1 forwards;
}

Expand All @@ -126,8 +132,6 @@
overflow: hidden !important;
color: #ffffff;
z-index: 2 !important;
opacity: 0;
animation: fadeIn ease-in 0.4s 1 forwards;
}

.i-amphtml-lbg-desc-box.standard {
Expand Down
124 changes: 88 additions & 36 deletions extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js
Expand Up @@ -381,7 +381,12 @@ export class AmpLightboxGallery extends AMP.BaseElement {
// text area is a div that does not contain descendant elements.
this.descriptionTextArea_./*OK*/innerText = descText;

// Avoid flickering out if transitioning from a slide with no text
this.descriptionBox_.classList.remove('fade-out');
toggle(dev().assertElement(this.descriptionBox_), true);

// If the description is in overflow mode, we set it to the correct
// overflow position top pending the length of text.
this.vsync_.run({
measure: measureOverflow,
mutate: mutateOverflowIfApplicable,
Expand Down Expand Up @@ -492,25 +497,61 @@ export class AmpLightboxGallery extends AMP.BaseElement {
* @param {!Event} e
* @private
*/
toggleControls_(e) {
onToggleControls_(e) {
if (!this.shouldTriggerClick_(e)) {
return;
}

if (this.controlsMode_ == LightboxControlsModes.CONTROLS_HIDDEN) {
this.carousel_.setAttribute('controls', '');
this.topBar_.classList.remove('fade-out');
if (!this.container_.hasAttribute('gallery-view')) {
this.descriptionBox_.classList.remove('fade-out');
this.updateDescriptionBox_();
}
this.controlsMode_ = LightboxControlsModes.CONTROLS_DISPLAYED;
this.showControls_();
} else {
this.carousel_.removeAttribute('controls');
this.hideControls_();
// Toggle version of hide uses fade animation effects
this.topBar_.classList.add('fade-out');
this.descriptionBox_.classList.add('fade-out');
this.controlsMode_ = LightboxControlsModes.CONTROLS_HIDDEN;
} }

/**
* Show lightbox controls.
* @private
*/
showControls_() {
this.carousel_.setAttribute('controls', '');

this.topBar_.classList.remove('fade-out');
this.topBar_.classList.remove('hidden');
this.topBar_.classList.add('show');
this.topBar_.classList.add('fade-in');

this.descriptionBox_.classList.remove('fade-out');

if (!this.container_.hasAttribute('gallery-view')) {
this.descriptionBox_.classList.remove('hidden');
this.descriptionBox_.classList.add('fade-in');
this.descriptionBox_.classList.add('show');
this.updateDescriptionBox_();
}
this.controlsMode_ = LightboxControlsModes.CONTROLS_DISPLAYED;
}

/**
* Hide lightbox controls without fade effect.
* @private
*/
hideControls_() {
this.carousel_.removeAttribute('controls');

this.topBar_.classList.remove('fade-in');
this.topBar_.classList.remove('fade-out');
this.topBar_.classList.remove('show');
this.topBar_.classList.add('hidden');
if (!this.container_.hasAttribute('gallery-view')) {
this.descriptionBox_.classList.remove('fade-in');
this.descriptionBox_.classList.remove('fade-out');
this.descriptionBox_.classList.remove('show');
this.descriptionBox_.classList.add('hidden');
}

this.controlsMode_ = LightboxControlsModes.CONTROLS_HIDDEN;
}

/**
Expand All @@ -519,9 +560,9 @@ export class AmpLightboxGallery extends AMP.BaseElement {
*/
setupEventListeners_() {
dev().assert(this.container_);
const toggleControls = this.toggleControls_.bind(this);
const onToggleControls = this.onToggleControls_.bind(this);
this.unlistenClick_ = listen(dev().assertElement(this.container_),
'click', toggleControls);
'click', onToggleControls);
}

/**
Expand Down Expand Up @@ -612,6 +653,7 @@ export class AmpLightboxGallery extends AMP.BaseElement {
opacity: 0,
display: '',
});
this.hideControls_();
});
}).then(() => {
this.getViewport().enterLightboxMode();
Expand All @@ -631,27 +673,31 @@ export class AmpLightboxGallery extends AMP.BaseElement {
this.setupEventListeners_();

return this.carousel_.signals().whenSignal(CommonSignals.LOAD_END);
}).then(() => this.openLightboxForElement_(element));
}).then(() => this.openLightboxForElement_(element))
.then(() => this.showControls_());
}

/**
* Given a single lightbox element, opens the internal carousel slide
* associated with said element, updates the description, and initializes
* the image viewer if the element is an amp-img.
* @param {!Element} element
* @returns {!Promise}
* @private
*/
openLightboxForElement_(element) {
this.currentElemId_ = element.lightboxItemId;
dev().assert(this.carousel_).getImpl()
.then(carousel => carousel.showSlideWhenReady(this.currentElemId_));
const tagName = this.getCurrentElement_().tagName;
this.updateDescriptionBox_();
if (ELIGIBLE_TAP_TAGS[tagName]) {
this.getCurrentElement_().imageViewer.signals()
return this.getCurrentElement_().imageViewer.signals()
.whenSignal(CommonSignals.LOAD_END)
.then(() => this.enter_());
} else {
return Promise.resolve();
}
this.updateDescriptionBox_();
}

/**
Expand Down Expand Up @@ -806,6 +852,10 @@ export class AmpLightboxGallery extends AMP.BaseElement {
return anim.start(duration).thenAlways(() => {
return this.vsync_.mutatePromise(() => {
st.setStyles(this.element, {opacity: ''});
if (endOpacity == 0) {
toggle(dev().assertElement(this.carousel_), false);
toggle(this.element, false);
}
});
});
}
Expand All @@ -821,9 +871,9 @@ export class AmpLightboxGallery extends AMP.BaseElement {
return this.shouldAnimate_(sourceElement)
.then(shouldAnimate => {
if (shouldAnimate) {
this.transitionIn_(sourceElement);
return this.transitionIn_(sourceElement);
} else {
this.fade_(0, 1);
return this.fade_(0, 1);
}
});
}
Expand Down Expand Up @@ -918,6 +968,8 @@ export class AmpLightboxGallery extends AMP.BaseElement {
st.setStyles(dev().assertElement(this.carousel_), {
opacity: '',
});
toggle(dev().assertElement(this.carousel_), false);
toggle(this.element, false);
this.element.ownerDocument.body.removeChild(transLayer);
});
});
Expand Down Expand Up @@ -1004,16 +1056,6 @@ export class AmpLightboxGallery extends AMP.BaseElement {

this.maybeSyncSourceCarousel_();

this.vsync_.mutate(() => {
// If there's gallery, set gallery to display none
this.container_.removeAttribute('gallery-view');

if (this.gallery_) {
this.gallery_.classList.add('i-amphtml-lbg-gallery-hidden');
this.gallery_ = null;
}
});

this.win.document.documentElement.removeEventListener(
'keydown', this.boundOnKeyDown_);

Expand All @@ -1023,13 +1065,24 @@ export class AmpLightboxGallery extends AMP.BaseElement {
const gestures = Gestures.get(dev().assertElement(this.carousel_));
gestures.cleanup();

return this.exit_().then(() => {
toggle(dev().assertElement(this.carousel_), false);
toggle(this.element, false);
this.carousel_ = null;
this.getViewport().leaveLightboxMode();
this.schedulePause(dev().assertElement(this.container_));
});
return this.vsync_.mutatePromise(() => {
// If there's gallery, set gallery to display none
this.container_.removeAttribute('gallery-view');

if (this.gallery_) {
this.gallery_.classList.add('i-amphtml-lbg-gallery-hidden');
this.gallery_ = null;
}
// Toggle description overflow to hidden
this.descriptionBox_./*OK*/scrollTop = 0;
this.descriptionBox_.classList.remove('overflow');
this.descriptionBox_.classList.add('standard');
}).then(() => this.exit_())
.then(() => {
this.getViewport().leaveLightboxMode();
this.schedulePause(dev().assertElement(this.container_));
this.carousel_ = null;
});
}

/**
Expand Down Expand Up @@ -1082,7 +1135,6 @@ export class AmpLightboxGallery extends AMP.BaseElement {
this.findOrBuildGallery_();
}
this.container_.setAttribute('gallery-view', '');
this.topBar_.classList.add('fullscreen');
toggle(dev().assertElement(this.carousel_), false);
toggle(dev().assertElement(this.descriptionBox_), false);
}
Expand Down

0 comments on commit 84a316e

Please sign in to comment.