From b7217c66addcf53644eb7ecf42a4a8c002acd152 Mon Sep 17 00:00:00 2001 From: Justin Holdstock Date: Tue, 6 Jun 2017 10:08:24 -0700 Subject: [PATCH] Animate annotation dialog (#161) --- src/lib/annotations/AnnotationDialog.js | 6 ++ src/lib/annotations/MobileAnnotator.scss | 57 ++++++++++++++++++- .../__tests__/AnnotationDialog-test.js | 17 ++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/lib/annotations/AnnotationDialog.js b/src/lib/annotations/AnnotationDialog.js index 3263925c1..a10567395 100644 --- a/src/lib/annotations/AnnotationDialog.js +++ b/src/lib/annotations/AnnotationDialog.js @@ -6,6 +6,8 @@ import { CLASS_ACTIVE, CLASS_HIDDEN } from '../constants'; import { decodeKeydown } from '../util'; import { ICON_CLOSE, ICON_DELETE } from '../icons/icons'; +const CLASS_ANIMATE_DIALOG = 'bp-animate-show-dialog'; + @autobind class AnnotationDialog extends EventEmitter { //-------------------------------------------------------------------------- // Typedef @@ -80,6 +82,8 @@ import { ICON_CLOSE, ICON_DELETE } from '../icons/icons'; const dialogCloseButtonEl = this.element.querySelector('.bp-annotation-dialog-close'); dialogCloseButtonEl.addEventListener('click', this.hideMobileDialog); + this.element.classList.add(CLASS_ANIMATE_DIALOG); + this.bindDOMListeners(); } @@ -133,6 +137,8 @@ import { ICON_CLOSE, ICON_DELETE } from '../icons/icons'; return; } + this.element.classList.remove(CLASS_ANIMATE_DIALOG); + // Clear annotations from dialog this.element.innerHTML = `
diff --git a/src/lib/annotations/MobileAnnotator.scss b/src/lib/annotations/MobileAnnotator.scss index 9b65621f7..69dd68e01 100644 --- a/src/lib/annotations/MobileAnnotator.scss +++ b/src/lib/annotations/MobileAnnotator.scss @@ -1,9 +1,64 @@ +$tablet: "(min-width: 768px)"; + .bp-mobile-annotation-dialog { background: white; border-top: 0; height: 100%; + position: absolute; top: 0; - width: 100%; // Hard-coded width to solve layout issues + width: 100%; + + &.bp-animate-show-dialog { + &:not(.bp-plain-highlight) { + animation: show-dialog-small; + animation-duration: .2s; + animation-fill-mode: forwards; + + @media #{$tablet} { + animation: show-dialog-tablet; + animation-duration: .2s; + animation-fill-mode: forwards; + border-left: solid 1px #ccc; + width: 450px; + } + } + + &.bp-plain-highlight { + animation: show-highlight-dialog; + animation-duration: .2s; + animation-fill-mode: forwards; + } + } +} + +@keyframes show-dialog-small { + 0% { + top: 100%; + } + + 100% { + top: 0%; + } +} + +@keyframes show-dialog-tablet { + 0% { + right: -50%; + } + + 100% { + right: 0%; + } +} + +@keyframes show-highlight-dialog { + 0% { + top: -48px; + } + + 100% { + top: 1px; + } } .bp-mobile-annotation-dialog.bp-annotation-dialog { diff --git a/src/lib/annotations/__tests__/AnnotationDialog-test.js b/src/lib/annotations/__tests__/AnnotationDialog-test.js index d85c23a5c..6f5b1d990 100644 --- a/src/lib/annotations/__tests__/AnnotationDialog-test.js +++ b/src/lib/annotations/__tests__/AnnotationDialog-test.js @@ -5,6 +5,8 @@ import * as annotatorUtil from '../annotatorUtil'; import * as constants from '../annotationConstants'; import { CLASS_ACTIVE, CLASS_HIDDEN } from '../../constants'; +const CLASS_ANIMATE_DIALOG = 'bp-animate-show-dialog'; + let dialog; const sandbox = sinon.sandbox.create(); let stubs = {}; @@ -147,6 +149,14 @@ describe('lib/annotations/AnnotationDialog', () => { expect(stubs.show).to.be.calledWith(dialog.element); expect(stubs.bind).to.be.called; expect(dialog.position).to.not.be.called; + expect(dialog.element.classList.contains(CLASS_ANIMATE_DIALOG)).to.be.true; + }); + + it('should add the animation class to the the mobile dialog if using a mobile browser', () => { + dialog.isMobile = true; + + dialog.show(); + expect(dialog.element.classList.contains(CLASS_ANIMATE_DIALOG)).to.be.true; }); it('should hide the mobile header if a plain highlight', () => { @@ -174,6 +184,13 @@ describe('lib/annotations/AnnotationDialog', () => { stubs.hide = sandbox.stub(annotatorUtil, 'hideElement'); dialog.hideMobileDialog(); expect(stubs.hide).to.be.called; + expect(dialog.element.classList.contains(CLASS_ANIMATE_DIALOG)).to.be.false; + }); + + it('should remove the animation class', () => { + dialog.element = document.querySelector('.bp-mobile-annotation-dialog'); + dialog.hideMobileDialog(); + expect(dialog.element.classList.contains(CLASS_ANIMATE_DIALOG)).to.be.false; }); });