From 4a3ce421374c2bc500f7e8efaab73037191631fb Mon Sep 17 00:00:00 2001 From: paulocfjunior Date: Tue, 30 Apr 2019 15:11:31 -0300 Subject: [PATCH] Updates Dropdown to have fade in and out transitions (#147) Closes #147 --- packages/marble-dropdown/src/Dropdown.js | 34 ++++++++++++++++++-- packages/marble-dropdown/src/Dropdown.soy | 3 +- packages/marble-dropdown/src/Dropdown.soy.js | 8 +++-- packages/marble-dropdown/test/Dropdown.js | 13 +++++--- packages/marble/src/_animations.scss | 10 ++++++ packages/marble/src/_dropdowns.scss | 5 +++ 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/packages/marble-dropdown/src/Dropdown.js b/packages/marble-dropdown/src/Dropdown.js index 1574ea6..1a622f2 100644 --- a/packages/marble-dropdown/src/Dropdown.js +++ b/packages/marble-dropdown/src/Dropdown.js @@ -133,8 +133,28 @@ class Dropdown extends Component { * Toggles the dropdown, closing it when open or opening it when closed. */ toggle() { - this.expanded = !this.expanded; - this.hideConfirmation(); + if (this.expanded) { + this.hiding = true; + + this.callAsync_(() => { + this.expanded = !this.expanded; + this.hiding = false; + this.hideConfirmation(); + }, 300); + } else { + this.expanded = !this.expanded; + this.hideConfirmation(); + } + } + + /** + * @param {!function()} fn + * @param {number} delay + * @private + */ + callAsync_(fn, delay) { + clearTimeout(this.delay_); + this.delay_ = setTimeout(fn.bind(this), delay); } /** @@ -280,6 +300,16 @@ Dropdown.STATE = { internal: true, }, + /** + * Flag indicating if the dropdown is hiding or not. + * @type {boolean} + * @default false + */ + hiding: { + value: false, + internal: true, + }, + /** * The position of the dropdown (either 'up', 'down' or any of the position * constants available in `Align`). diff --git a/packages/marble-dropdown/src/Dropdown.soy b/packages/marble-dropdown/src/Dropdown.soy index 087e21b..1de1e87 100644 --- a/packages/marble-dropdown/src/Dropdown.soy +++ b/packages/marble-dropdown/src/Dropdown.soy @@ -5,6 +5,7 @@ * @param? classMap * @param? elementClasses * @param? expanded + * @param? hiding * @param? position * @param? positionClassOnMenu * @param? showConfirmationBody @@ -17,7 +18,7 @@ {let $classes: $classMap ? $classMap : ['dropup', 'dropup', 'dropright', 'dropdown', 'dropdown', 'dropdown', 'dropleft', 'dropup'] /} {let $currentPosition: isNonnull($alignedPosition) ? $alignedPosition : $position /} {let $positionClass: isNonnull($currentPosition) ? $classes[$currentPosition] : 'dropdown' /} -
+
{if $header} {$header} {/if} diff --git a/packages/marble-dropdown/src/Dropdown.soy.js b/packages/marble-dropdown/src/Dropdown.soy.js index 7218ecb..8a7c99f 100644 --- a/packages/marble-dropdown/src/Dropdown.soy.js +++ b/packages/marble-dropdown/src/Dropdown.soy.js @@ -27,6 +27,7 @@ var soyIdom = goog.require('soy.idom'); * classMap: (?), * elementClasses: (?), * expanded: (?), + * hiding: (?), * position: (?), * positionClassOnMenu: (?), * showConfirmationBody: (?), @@ -52,7 +53,7 @@ function $render(opt_data, opt_ijData, opt_ijData_deprecated) { var currentPosition__soy9 = (opt_data.alignedPosition != null) ? opt_data.alignedPosition : opt_data.position; var positionClass__soy11 = (currentPosition__soy9 != null) ? classes__soy7[currentPosition__soy9] : 'dropdown'; incrementalDom.elementOpenStart('div'); - incrementalDom.attr('class', (opt_data.positionClassOnMenu ? 'dropdown' : positionClass__soy11) + (opt_data.elementClasses ? ' ' + opt_data.elementClasses : '') + (opt_data.expanded ? ' open' : '')); + incrementalDom.attr('class', (opt_data.positionClassOnMenu ? 'dropdown' : positionClass__soy11) + (opt_data.elementClasses ? ' ' + opt_data.elementClasses : '') + (opt_data.expanded ? ' open' : '') + (opt_data.hiding ? ' hiding' : '')); incrementalDom.elementOpenEnd(); if (header) { header(); @@ -81,6 +82,7 @@ exports.render = $render; * classMap: (?), * elementClasses: (?), * expanded: (?), + * hiding: (?), * position: (?), * positionClassOnMenu: (?), * showConfirmationBody: (?), @@ -94,8 +96,8 @@ if (goog.DEBUG) { $render.soyTemplateName = 'Dropdown.render'; } -exports.render.params = ["body","confirmationBody","header","alignedPosition","classMap","elementClasses","expanded","position","positionClassOnMenu","showConfirmationBody"]; -exports.render.types = {"body":"html","confirmationBody":"html","header":"html","alignedPosition":"any","classMap":"any","elementClasses":"any","expanded":"any","position":"any","positionClassOnMenu":"any","showConfirmationBody":"any"}; +exports.render.params = ["body","confirmationBody","header","alignedPosition","classMap","elementClasses","expanded","hiding","position","positionClassOnMenu","showConfirmationBody"]; +exports.render.types = {"body":"html","confirmationBody":"html","header":"html","alignedPosition":"any","classMap":"any","elementClasses":"any","expanded":"any","hiding":"any","position":"any","positionClassOnMenu":"any","showConfirmationBody":"any"}; templates = exports; return exports; diff --git a/packages/marble-dropdown/test/Dropdown.js b/packages/marble-dropdown/test/Dropdown.js index e66b50e..a6859f9 100644 --- a/packages/marble-dropdown/test/Dropdown.js +++ b/packages/marble-dropdown/test/Dropdown.js @@ -88,10 +88,15 @@ describe('Dropdown', () => { expect(dom.hasClass(component.element, 'open')).toBeTruthy(); component.toggle(); component.once('stateChanged', () => { - expect(!component.expanded).toBeTruthy(); - expect(!dom.hasClass(component.element, 'open')).toBeTruthy(); - component.dispose(); - done(); + expect(component.hiding).toBeTruthy(); + expect(dom.hasClass(component.element, 'hiding')).toBeTruthy(); + component.once('stateChanged', () => { + expect(!component.expanded).toBeTruthy(); + expect(!component.hiding).toBeTruthy(); + expect(!dom.hasClass(component.element, 'open')).toBeTruthy(); + component.dispose(); + done(); + }); }); }); }); diff --git a/packages/marble/src/_animations.scss b/packages/marble/src/_animations.scss index ae5d898..7472ceb 100644 --- a/packages/marble/src/_animations.scss +++ b/packages/marble/src/_animations.scss @@ -12,6 +12,16 @@ } } +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + @keyframes fadeInToRight { 0% { opacity: 0; diff --git a/packages/marble/src/_dropdowns.scss b/packages/marble/src/_dropdowns.scss index cf48403..9e24c98 100644 --- a/packages/marble/src/_dropdowns.scss +++ b/packages/marble/src/_dropdowns.scss @@ -45,9 +45,14 @@ } .open .dropdown-menu { + animation: fadeIn 300ms cubic-bezier(0.455, 0.03, 0.515, 0.955) forwards; display: inline-block; } +.hiding .dropdown-menu { + animation: fadeOut 300ms cubic-bezier(0.455, 0.03, 0.515, 0.955) forwards; +} + .dropdown-section-title { color: rgba($white, 0.4); display: block;