From 3effc35bd2f5a6dea080c8ff0b7d49b4594cc989 Mon Sep 17 00:00:00 2001 From: Travis Kaufman Date: Mon, 13 Feb 2017 13:04:22 -0500 Subject: [PATCH] fix(checkbox): Disable transitions when using mdc-checkbox-anim* classes (#285) - Adds a mdc-checkbox--upgraded mod class which is attached by the foundation when a JS checkbox is used. - Disables all transitions when the animation classes are used. Fixes an issue in Safari where the the paint/compositing looked janky/broken due to animations and transitions conflicting with one another. - (tech debt) Removed template strings from cssClasses object. This will be required in order for our internal infra to work correctly. Fixes #205 --- packages/mdc-checkbox/constants.js | 20 ++++++++++---------- packages/mdc-checkbox/foundation.js | 1 + packages/mdc-checkbox/mdc-checkbox.scss | 21 +++++++++++++++++---- test/unit/mdc-checkbox/foundation.test.js | 14 ++++++++++++-- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/packages/mdc-checkbox/constants.js b/packages/mdc-checkbox/constants.js index 53380c7f3c6..3f923ada3dc 100644 --- a/packages/mdc-checkbox/constants.js +++ b/packages/mdc-checkbox/constants.js @@ -15,18 +15,18 @@ */ const ROOT = 'mdc-checkbox'; -const ANIM = `${ROOT}--anim`; export const cssClasses = { - ROOT, - CHECKED: `${ROOT}--checked`, - INDETERMINATE: `${ROOT}--indeterminate`, - ANIM_UNCHECKED_CHECKED: `${ANIM}-unchecked-checked`, - ANIM_UNCHECKED_INDETERMINATE: `${ANIM}-unchecked-indeterminate`, - ANIM_CHECKED_UNCHECKED: `${ANIM}-checked-unchecked`, - ANIM_CHECKED_INDETERMINATE: `${ANIM}-checked-indeterminate`, - ANIM_INDETERMINATE_CHECKED: `${ANIM}-indeterminate-checked`, - ANIM_INDETERMINATE_UNCHECKED: `${ANIM}-indeterminate-unchecked`, + ROOT: 'mdc-checkbox', + UPGRADED: 'mdc-checkbox--upgraded', + CHECKED: 'mdc-checkbox--checked', + INDETERMINATE: 'mdc-checkbox--indeterminate', + ANIM_UNCHECKED_CHECKED: 'mdc-checkbox--anim-unchecked-checked', + ANIM_UNCHECKED_INDETERMINATE: 'mdc-checkbox--anim-unchecked-indeterminate', + ANIM_CHECKED_UNCHECKED: 'mdc-checkbox--anim-checked-unchecked', + ANIM_CHECKED_INDETERMINATE: 'mdc-checkbox--anim-checked-indeterminate', + ANIM_INDETERMINATE_CHECKED: 'mdc-checkbox--anim-indeterminate-checked', + ANIM_INDETERMINATE_UNCHECKED: 'mdc-checkbox--anim-indeterminate-unchecked', }; export const strings = { diff --git a/packages/mdc-checkbox/foundation.js b/packages/mdc-checkbox/foundation.js index d681ad3d974..f3319ae483b 100644 --- a/packages/mdc-checkbox/foundation.js +++ b/packages/mdc-checkbox/foundation.js @@ -63,6 +63,7 @@ export default class MDCCheckboxFoundation extends MDCFoundation { } init() { + this.adapter_.addClass(cssClasses.UPGRADED); this.adapter_.registerChangeHandler(this.changeHandler_); this.installPropertyChangeHooks_(); } diff --git a/packages/mdc-checkbox/mdc-checkbox.scss b/packages/mdc-checkbox/mdc-checkbox.scss index 54e3f7531cc..20c398d2bbe 100644 --- a/packages/mdc-checkbox/mdc-checkbox.scss +++ b/packages/mdc-checkbox/mdc-checkbox.scss @@ -1,12 +1,12 @@ -// +// // Copyright 2016 Google Inc. All Rights Reserved. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -235,6 +235,19 @@ fieldset:disabled .mdc-checkbox__native-control, } } +.mdc-checkbox--upgraded { + .mdc-checkbox__background, + .mdc-checkbox__checkmark, + .mdc-checkbox__checkmark__path, + .mdc-checkbox__mixedmark { + // Due to the myriad of selector combos used to properly style a CSS-only checkbox, all of + // which have varying selector precedence and make use of transitions, it is cleaner and more + // efficient here to simply use !important, since the mdc-checkbox--anim-* classes will take + // over from here. + transition: none !important; + } +} + .mdc-checkbox--anim { $_mdc-checkbox-indeterminate-change-duration: 500ms; diff --git a/test/unit/mdc-checkbox/foundation.test.js b/test/unit/mdc-checkbox/foundation.test.js index 9569adc69b6..29e78851816 100644 --- a/test/unit/mdc-checkbox/foundation.test.js +++ b/test/unit/mdc-checkbox/foundation.test.js @@ -123,6 +123,14 @@ test('defaultAdapter returns a complete adapter implementation', (t) => { t.end(); }); +test('#init adds the upgraded class to the root element', (t) => { + const {foundation, mockAdapter} = setupTest(); + + foundation.init(); + t.doesNotThrow(() => td.verify(mockAdapter.addClass(cssClasses.UPGRADED))); + t.end(); +}); + test('#init calls adapter.registerChangeHandler() with a change handler function', (t) => { const {foundation, mockAdapter} = setupTest(); const {isA} = td.matchers; @@ -406,19 +414,21 @@ test('change handler triggers layout for changes within the same frame to correc test('change handler does not add animation classes when isAttachedToDOM() is falsy', (t) => { const {mockAdapter, change} = setupChangeHandlerTest(); + const animClassArg = td.matchers.argThat((cls) => cls.indexOf('mdc-checkbox--anim') >= 0); td.when(mockAdapter.isAttachedToDOM()).thenReturn(false); change({checked: true, indeterminate: false}); - t.doesNotThrow(() => td.verify(mockAdapter.addClass(td.matchers.anything()), {times: 0})); + t.doesNotThrow(() => td.verify(mockAdapter.addClass(animClassArg), {times: 0})); t.end(); }); test('change handler does not add animation classes for bogus changes (init -> unchecked)', (t) => { const {mockAdapter, change} = setupChangeHandlerTest(); + const animClassArg = td.matchers.argThat((cls) => cls.indexOf('mdc-checkbox--anim') >= 0); change({checked: false, indeterminate: false}); - t.doesNotThrow(() => td.verify(mockAdapter.addClass(td.matchers.anything()), {times: 0})); + t.doesNotThrow(() => td.verify(mockAdapter.addClass(animClassArg), {times: 0})); t.end(); });