Skip to content

Commit

Permalink
fix(drawer): Page content can be scrolled even if drawer is open
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Adapter API for drawers contains two new methods: `addBodyClass` and
`removeBodyClass`.

Closes material-components#777
  • Loading branch information
vinhlh committed Jun 9, 2017
1 parent a9d46ab commit 0fbf1e7
Show file tree
Hide file tree
Showing 11 changed files with 64 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/mdc-drawer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ The adapter for persistent drawers must provide the following functions, with co
| `addClass(className: string) => void` | Adds a class to the root element. |
| `removeClass(className: string) => void` | Removes a class from the root element. |
| `hasClass(className: string) => boolean` | Returns boolean indicating whether element has a given class. |
| `addBodyClass(className: string) => void` | Adds a class to the body. |
| `removeBodyClass(className: string) => void` | Removes a class from the body. |
| `hasNecessaryDom() => boolean` | Returns boolean indicating whether the necessary DOM is present (namely, the `mdc-persistent-drawer__drawer` drawer container). |
| `registerInteractionHandler(evt: string, handler: EventListener) => void` | Adds an event listener to the root element, for the specified event name. |
| `deregisterInteractionHandler(evt: string, handler: EventListener) => void` | Removes an event listener from the root element, for the specified event name. |
Expand Down
7 changes: 7 additions & 0 deletions packages/mdc-drawer/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,10 @@
@include mdc-drawer-header_;
@include mdc-drawer-list_;
}

@mixin mdl-drawer-scroll-lock_() {
.mdc-drawer-scroll-lock {
height: 100vh;
overflow: hidden;
}
}
2 changes: 2 additions & 0 deletions packages/mdc-drawer/persistent/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export class MDCPersistentDrawer extends MDCComponent {
addClass: (className) => this.root_.classList.add(className),
removeClass: (className) => this.root_.classList.remove(className),
hasClass: (className) => this.root_.classList.contains(className),
addBodyClass: (className) => document.body.classList.add(className),
removeBodyClass: (className) => document.body.classList.remove(className),
hasNecessaryDom: () => Boolean(this.drawer),
registerInteractionHandler: (evt, handler) =>
this.root_.addEventListener(util.remapEvent(evt), handler, util.applyPassive()),
Expand Down
2 changes: 2 additions & 0 deletions packages/mdc-drawer/persistent/mdc-persistent-drawer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,5 @@ $mdc-persistent-drawer-dark-theme-bg-color: #212121 !default;
}
}
}

@include mdl-drawer-scroll-lock_;
4 changes: 4 additions & 0 deletions packages/mdc-drawer/slidable/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
export const FOCUSABLE_ELEMENTS =
'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), ' +
'button:not([disabled]), iframe, object, embed, [tabindex], [contenteditable]';

export const cssClasses = {
SCROLL_LOCK: 'mdc-drawer-scroll-lock',
};
17 changes: 17 additions & 0 deletions packages/mdc-drawer/slidable/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {MDCFoundation} from '@material/base';
import {cssClasses} from './constants';

export class MDCSlidableDrawerFoundation extends MDCFoundation {

Expand All @@ -23,6 +24,8 @@ export class MDCSlidableDrawerFoundation extends MDCFoundation {
addClass: (/* className: string */) => {},
removeClass: (/* className: string */) => {},
hasClass: (/* className: string */) => {},
addBodyClass: (/* className: string */) => {},
removeBodyClass: (/* className: string */) => {},
hasNecessaryDom: () => /* boolean */ false,
registerInteractionHandler: (/* evt: string, handler: EventListener */) => {},
deregisterInteractionHandler: (/* evt: string, handler: EventListener */) => {},
Expand Down Expand Up @@ -56,6 +59,10 @@ export class MDCSlidableDrawerFoundation extends MDCFoundation {
this.adapter_.removeClass(this.animatingCssClass_);
this.adapter_.deregisterTransitionEndHandler(this.transitionEndHandler_);
}

if (!this.isOpen_) {
this.enableScroll_();
}
};

this.inert_ = false;
Expand Down Expand Up @@ -103,6 +110,7 @@ export class MDCSlidableDrawerFoundation extends MDCFoundation {
this.adapter_.deregisterInteractionHandler('touchend', this.componentTouchEndHandler_);
// Deregister the document keydown handler just in case the component is destroyed while the menu is open.
this.adapter_.deregisterDocumentKeydownHandler(this.documentKeydownHandler_);
this.enableScroll_();
}

open() {
Expand All @@ -116,6 +124,7 @@ export class MDCSlidableDrawerFoundation extends MDCFoundation {
this.adapter_.notifyOpen();
}
this.isOpen_ = true;
this.disableScroll_();
}

close() {
Expand Down Expand Up @@ -239,4 +248,12 @@ export class MDCSlidableDrawerFoundation extends MDCFoundation {
// if the event target is the root event target currently transitioning.
return false;
}

disableScroll_() {
this.adapter_.addBodyClass(cssClasses.SCROLL_LOCK);
}

enableScroll_() {
this.adapter_.removeBodyClass(cssClasses.SCROLL_LOCK);
}
}
2 changes: 2 additions & 0 deletions packages/mdc-drawer/temporary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export class MDCTemporaryDrawer extends MDCComponent {
addClass: (className) => this.root_.classList.add(className),
removeClass: (className) => this.root_.classList.remove(className),
hasClass: (className) => this.root_.classList.contains(className),
addBodyClass: (className) => document.body.classList.add(className),
removeBodyClass: (className) => document.body.classList.remove(className),
hasNecessaryDom: () => Boolean(this.drawer),
registerInteractionHandler: (evt, handler) =>
this.root_.addEventListener(util.remapEvent(evt), handler, util.applyPassive()),
Expand Down
2 changes: 2 additions & 0 deletions packages/mdc-drawer/temporary/mdc-temporary-drawer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,5 @@
}
}
}

@include mdl-drawer-scroll-lock_;
3 changes: 2 additions & 1 deletion test/unit/mdc-drawer/persistent.foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ test('exports cssClasses', () => {

test('defaultAdapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCPersistentDrawerFoundation, [
'addClass', 'removeClass', 'hasClass', 'hasNecessaryDom', 'registerInteractionHandler',
'addClass', 'removeClass', 'hasClass', 'addBodyClass', 'removeBodyClass',
'hasNecessaryDom', 'registerInteractionHandler',
'deregisterInteractionHandler', 'registerDrawerInteractionHandler', 'deregisterDrawerInteractionHandler',
'registerTransitionEndHandler', 'deregisterTransitionEndHandler', 'registerDocumentKeydownHandler',
'deregisterDocumentKeydownHandler', 'setTranslateX', 'getFocusableElements',
Expand Down
23 changes: 22 additions & 1 deletion test/unit/mdc-drawer/slidable.foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import {assert} from 'chai';
import td from 'testdouble';

import {cssClasses} from '../../../packages/mdc-drawer/slidable/constants';
import {captureHandlers, verifyDefaultAdapter} from '../helpers/foundation';
import {createMockRaf} from '../helpers/raf';
import {MDCSlidableDrawerFoundation} from '../../../packages/mdc-drawer/slidable';
Expand Down Expand Up @@ -44,7 +45,8 @@ suite('MDCSlidableDrawerFoundation');

test('defaultAdapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCSlidableDrawerFoundation, [
'addClass', 'removeClass', 'hasClass', 'hasNecessaryDom', 'registerInteractionHandler',
'addClass', 'removeClass', 'hasClass', 'addBodyClass', 'removeBodyClass',
'hasNecessaryDom', 'registerInteractionHandler',
'deregisterInteractionHandler', 'registerDrawerInteractionHandler', 'deregisterDrawerInteractionHandler',
'registerTransitionEndHandler', 'deregisterTransitionEndHandler', 'registerDocumentKeydownHandler',
'deregisterDocumentKeydownHandler', 'setTranslateX', 'getFocusableElements',
Expand Down Expand Up @@ -780,3 +782,22 @@ test('isRootTransitioningEventTarget_ returns false', () => {
{times: 0}
);
});

test('#open adds scroll lock class to the body', () => {
const {foundation, mockAdapter} = setupTest();

foundation.open();

td.verify(mockAdapter.addBodyClass(cssClasses.SCROLL_LOCK));
});

test('#close removes the scroll lock class from the body', () => {
const {foundation, mockAdapter} = setupTest();

td.when(mockAdapter.registerTransitionEndHandler(td.callback)).thenCallback({target: {}});
foundation.open();
td.when(mockAdapter.registerTransitionEndHandler(td.callback)).thenCallback({target: {}});
foundation.close();

td.verify(mockAdapter.removeBodyClass(cssClasses.SCROLL_LOCK));
});
3 changes: 2 additions & 1 deletion test/unit/mdc-drawer/temporary.foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ test('exports cssClasses', () => {

test('defaultAdapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCTemporaryDrawerFoundation, [
'addClass', 'removeClass', 'hasClass', 'hasNecessaryDom', 'registerInteractionHandler',
'addClass', 'removeClass', 'hasClass', 'addBodyClass', 'removeBodyClass',
'hasNecessaryDom', 'registerInteractionHandler',
'deregisterInteractionHandler', 'registerDrawerInteractionHandler', 'deregisterDrawerInteractionHandler',
'registerTransitionEndHandler', 'deregisterTransitionEndHandler', 'registerDocumentKeydownHandler',
'deregisterDocumentKeydownHandler', 'setTranslateX', 'getFocusableElements',
Expand Down

0 comments on commit 0fbf1e7

Please sign in to comment.