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

feat(tab-indicator): Remove transitionend event handling #3337

Merged
merged 4 commits into from
Aug 14, 2018
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
2 changes: 0 additions & 2 deletions packages/mdc-tab-indicator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ Method Signature | Description
--- | ---
`addClass(className: string) => void` | Adds a class to the root element.
`removeClass(className: string) => void` | Removes a class from the root element.
`registerEventHandler(evtType: string, handler: EventListener) => void` | Registers an event listener on the root element.
`deregisterEventHandler(evtType: string, handler: EventListener) => void` | Deregisters an event listener on the root element.
`setContentStyleProp(property: string, value: string) => void` | Sets the style property of the content element.
`computeContentClientRect() => ClientRect` | Returns the content element's bounding client rect.

Expand Down
14 changes: 0 additions & 14 deletions packages/mdc-tab-indicator/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,6 @@
* @record
*/
class MDCTabIndicatorAdapter {
/**
* Registers an event listener on the root element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
registerEventHandler(evtType, handler) {}

/**
* Deregisters an event listener on the root element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
deregisterEventHandler(evtType, handler) {}

/**
* Adds the given className to the root element.
* @param {string} className The className to add
Expand Down
4 changes: 1 addition & 3 deletions packages/mdc-tab-indicator/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
const cssClasses = {
ACTIVE: 'mdc-tab-indicator--active',
FADE: 'mdc-tab-indicator--fade',
FADING_ACTIVATE: 'mdc-tab-indicator--fading-activate',
FADING_DEACTIVATE: 'mdc-tab-indicator--fading-deactivate',
SLIDING_ACTIVATE: 'mdc-tab-indicator--sliding-activate',
NO_TRANSITION: 'mdc-tab-indicator--no-transition',
};

/** @enum {string} */
Expand Down
19 changes: 0 additions & 19 deletions packages/mdc-tab-indicator/fading-foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,11 @@ import MDCTabIndicatorFoundation from './foundation';
* @final
*/
class MDCFadingTabIndicatorFoundation extends MDCTabIndicatorFoundation {
/** @param {...?} args */
constructor(...args) {
super(...args);

/** @private {function(?Event): undefined} */
this.handleTransitionEnd_ = () => this.handleTransitionEnd();
}

/** Handles the transitionend event */
handleTransitionEnd() {
this.adapter_.deregisterEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.FADING_ACTIVATE);
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE);
}

activate() {
this.adapter_.registerEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.FADING_ACTIVATE);
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);
}

deactivate() {
this.adapter_.registerEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE);
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);
}
}
Expand Down
2 changes: 0 additions & 2 deletions packages/mdc-tab-indicator/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ class MDCTabIndicatorFoundation extends MDCFoundation {
*/
static get defaultAdapter() {
return /** @type {!MDCTabIndicatorAdapter} */ ({
registerEventHandler: () => {},
deregisterEventHandler: () => {},
addClass: () => {},
removeClass: () => {},
computeContentClientRect: () => {},
Expand Down
2 changes: 0 additions & 2 deletions packages/mdc-tab-indicator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ class MDCTabIndicator extends MDCComponent {
*/
getDefaultFoundation() {
const adapter = /** @type {!MDCTabIndicatorAdapter} */ (Object.assign({
registerEventHandler: (evtType, handler) => this.root_.addEventListener(evtType, handler),
deregisterEventHandler: (evtType, handler) => this.root_.removeEventListener(evtType, handler),
addClass: (className) => this.root_.classList.add(className),
removeClass: (className) => this.root_.classList.remove(className),
computeContentClientRect: () => this.content_.getBoundingClientRect(),
Expand Down
14 changes: 9 additions & 5 deletions packages/mdc-tab-indicator/mdc-tab-indicator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,20 @@
opacity: 1;
}

.mdc-tab-indicator--sliding-activate > .mdc-tab-indicator__content {
// Slide by default
.mdc-tab-indicator > .mdc-tab-indicator__content {
transition: 250ms transform $mdc-animation-standard-curve-timing-function;
}

.mdc-tab-indicator--fading-activate > .mdc-tab-indicator__content,
.mdc-tab-indicator--fading-deactivate > .mdc-tab-indicator__content {
// --no-transition is applied in cases where styles need to be applied immediately to set up a transition
.mdc-tab-indicator--no-transition > .mdc-tab-indicator__content {
transition: none;
}

.mdc-tab-indicator--fade > .mdc-tab-indicator__content {
transition: 150ms opacity linear;
}

.mdc-tab-indicator--fading-activate > .mdc-tab-indicator__content {
.mdc-tab-indicator--active.mdc-tab-indicator--fade > .mdc-tab-indicator__content {
transition-delay: 100ms;
}

34 changes: 6 additions & 28 deletions packages/mdc-tab-indicator/sliding-foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,12 @@ import MDCTabIndicatorFoundation from './foundation';
* @final
*/
class MDCSlidingTabIndicatorFoundation extends MDCTabIndicatorFoundation {
/** @param {...?} args */
constructor(...args) {
super(...args);

/** @private {function(?Event): undefined} */
this.handleTransitionEnd_ = () => this.handleTransitionEnd();
}

/** Handles the transitionend event */
handleTransitionEnd() {
this.adapter_.deregisterEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.SLIDING_ACTIVATE);
}

/** @param {!ClientRect=} previousIndicatorClientRect */
activate(previousIndicatorClientRect) {
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);

// Early exit if no indicator is present to handle cases where an indicator
// may be activated without a prior indicator state
if (!previousIndicatorClientRect) {
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);
return;
}

Expand All @@ -53,26 +38,19 @@ class MDCSlidingTabIndicatorFoundation extends MDCTabIndicatorFoundation {
const currentClientRect = this.computeContentClientRect();
const widthDelta = previousIndicatorClientRect.width / currentClientRect.width;
const xPosition = previousIndicatorClientRect.left - currentClientRect.left;
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.NO_TRANSITION);
this.adapter_.setContentStyleProperty('transform', `translateX(${xPosition}px) scaleX(${widthDelta})`);

// Force repaint
// Force repaint before updating classes and transform to ensure the transform properly takes effect
this.computeContentClientRect();

// Add animating class and remove transformation in a new frame
requestAnimationFrame(() => {
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.SLIDING_ACTIVATE);
this.adapter_.setContentStyleProperty('transform', '');
});

this.adapter_.registerEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.NO_TRANSITION);
this.adapter_.addClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);
this.adapter_.setContentStyleProperty('transform', '');
}

deactivate() {
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.ACTIVE);
// We remove the animating class in deactivate in case the Tab is deactivated before the animation completes and
// the "transitionend" handler isn't called.
this.adapter_.removeClass(MDCTabIndicatorFoundation.cssClasses.SLIDING_ACTIVATE);
this.adapter_.deregisterEventHandler('transitionend', this.handleTransitionEnd_);
}
}

Expand Down
49 changes: 0 additions & 49 deletions test/unit/mdc-tab-indicator/fading-foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,21 @@

import td from 'testdouble';

import {captureHandlers} from '../helpers/foundation';
import {setupFoundationTest} from '../helpers/setup';
import MDCFadingTabIndicatorFoundation from '../../../packages/mdc-tab-indicator/fading-foundation';

suite('MDCFadingTabIndicatorFoundation');

const setupTest = () => setupFoundationTest(MDCFadingTabIndicatorFoundation);

test('#activate registers a transitionend handler', () => {
const {foundation, mockAdapter} = setupTest();
foundation.activate();
td.verify(mockAdapter.registerEventHandler('transitionend', td.matchers.isA(Function)));
});

test(`#activate adds the ${MDCFadingTabIndicatorFoundation.cssClasses.ACTIVE} class`, () => {
const {foundation, mockAdapter} = setupTest();
foundation.activate();
td.verify(mockAdapter.addClass(MDCFadingTabIndicatorFoundation.cssClasses.ACTIVE));
});

test(`#activate adds the ${MDCFadingTabIndicatorFoundation.cssClasses.FADING_ACTIVATE} class`, () => {
const {foundation, mockAdapter} = setupTest();
foundation.activate();
td.verify(mockAdapter.addClass(MDCFadingTabIndicatorFoundation.cssClasses.FADING_ACTIVATE));
});

test('#deactivate registers a transitionend handler', () => {
const {foundation, mockAdapter} = setupTest();
foundation.deactivate();
td.verify(mockAdapter.registerEventHandler('transitionend', td.matchers.isA(Function)));
});

test(`#deactivate removes the ${MDCFadingTabIndicatorFoundation.cssClasses.ACTIVE} class`, () => {
const {foundation, mockAdapter} = setupTest();
foundation.deactivate();
td.verify(mockAdapter.removeClass(MDCFadingTabIndicatorFoundation.cssClasses.ACTIVE));
});

test(`#deactivate adds the ${MDCFadingTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE} class`, () => {
const {foundation, mockAdapter} = setupTest();
foundation.deactivate();
td.verify(mockAdapter.addClass(MDCFadingTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE));
});

test('on transitionend, deregister the transitionend handler', () => {
const {foundation, mockAdapter} = setupTest();
const handlers = captureHandlers(mockAdapter, 'registerEventHandler');
foundation.activate();
handlers.transitionend();
td.verify(mockAdapter.deregisterEventHandler('transitionend', td.matchers.isA(Function)));
});

test(`on transitionend, remove the ${MDCFadingTabIndicatorFoundation.cssClasses.FADING_ACTIVATE} class`, () => {
const {foundation, mockAdapter} = setupTest();
const handlers = captureHandlers(mockAdapter, 'registerEventHandler');
foundation.activate();
handlers.transitionend();
td.verify(mockAdapter.removeClass(MDCFadingTabIndicatorFoundation.cssClasses.FADING_ACTIVATE));
});

test(`on transitionend, remove the ${MDCFadingTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE} class`, () => {
const {foundation, mockAdapter} = setupTest();
const handlers = captureHandlers(mockAdapter, 'registerEventHandler');
foundation.activate();
handlers.transitionend();
td.verify(mockAdapter.removeClass(MDCFadingTabIndicatorFoundation.cssClasses.FADING_DEACTIVATE));
});
9 changes: 4 additions & 5 deletions test/unit/mdc-tab-indicator/foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ test('exports strings', () => {

test('defaultAdapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCTabIndicatorFoundation, [
'registerEventHandler', 'deregisterEventHandler',
'addClass', 'removeClass',
'setContentStyleProperty',
'computeContentClientRect',
Expand All @@ -52,13 +51,13 @@ test('#computeContentClientRect returns the client rect', () => {
test('#activate is abstract and does nothing', () => {
const {foundation, mockAdapter} = setupTest();
foundation.activate();
td.verify(mockAdapter.addClass, {times: 0});
td.verify(mockAdapter.removeClass, {times: 0});
td.verify(mockAdapter.addClass(td.matchers.isA(String)), {times: 0});
td.verify(mockAdapter.removeClass(td.matchers.isA(String)), {times: 0});
});

test('#deactivate is abstract and does nothing', () => {
const {foundation, mockAdapter} = setupTest();
foundation.deactivate();
td.verify(mockAdapter.addClass, {times: 0});
td.verify(mockAdapter.removeClass, {times: 0});
td.verify(mockAdapter.addClass(td.matchers.isA(String)), {times: 0});
td.verify(mockAdapter.removeClass(td.matchers.isA(String)), {times: 0});
});
18 changes: 0 additions & 18 deletions test/unit/mdc-tab-indicator/mdc-tab-indicator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import bel from 'bel';
import {assert} from 'chai';
import td from 'testdouble';
import domEvents from 'dom-events';

import {
MDCTabIndicator,
Expand Down Expand Up @@ -69,23 +68,6 @@ test('#adapter.removeClass removes a class to the root element', () => {
assert.isFalse(root.classList.contains('foo'));
});

test('#adapter.registerEventHandler adds an event listener on the root element', () => {
const {root, component} = setupTest();
const handler = td.func('transitionend handler');
component.getDefaultFoundation().adapter_.registerEventHandler('transitionend', handler);
domEvents.emit(root, 'transitionend');
td.verify(handler(td.matchers.anything()));
});

test('#adapter.deregisterEventHandler remoes an event listener from the root element', () => {
const {root, component} = setupTest();
const handler = td.func('transitionend handler');
root.addEventListener('transitionend', handler);
component.getDefaultFoundation().adapter_.deregisterEventHandler('transitionend', handler);
domEvents.emit(root, 'transitionend');
td.verify(handler(td.matchers.anything()), {times: 0});
});

test('#adapter.computeContentClientRect returns the root element client rect', () => {
const {component, root, content} = setupTest();
document.body.appendChild(root);
Expand Down
Loading