Skip to content

Commit

Permalink
fix(select): Don't scroll page when select's menu is open (#1500)
Browse files Browse the repository at this point in the history
Resolves #879.
  • Loading branch information
roncapat authored and lynnmercier committed Nov 20, 2017
1 parent 476c81f commit bddd747
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/mdc-select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ within `componentDidUpdate`.
| --- | --- |
| `addClass(className: string) => void` | Adds a class to the root element. |
| `removeClass(className: string) => void` | Removes a class from the root element. |
| `addBodyClass(className: string) => void` | Adds a class to the body. |
| `removeBodyClass(className: string) => void` | Removes a class from the body. |
| `setAttr(attr: string, value: string) => void` | Sets attribute `attr` to value `value` on the root element. |
| `rmAttr(attr: string) => void` | Removes attribute `attr` from the root element. |
| `computeBoundingRect() => {left: number, top: number}` | Returns an object with a shape similar to a `ClientRect` object, with a `left` and `top` property specifying the element's position on the page relative to the viewport. The easiest way to achieve this is by calling `getBoundingClientRect()` on the root element. |
Expand Down
1 change: 1 addition & 0 deletions packages/mdc-select/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const cssClasses = {
ROOT: 'mdc-select',
OPEN: 'mdc-select--open',
DISABLED: 'mdc-select--disabled',
SCROLL_LOCK: 'mdc-select-scroll-lock',
};

export const strings = {
Expand Down
12 changes: 12 additions & 0 deletions packages/mdc-select/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export default class MDCSelectFoundation extends MDCFoundation {
return {
addClass: (/* className: string */) => {},
removeClass: (/* className: string */) => {},
addBodyClass: (/* className: string */) => {},
removeBodyClass: (/* className: string */) => {},
setAttr: (/* attr: string, value: string */) => {},
rmAttr: (/* attr: string */) => {},
computeBoundingRect: () => /* {left: number, top: number} */ ({left: 0, top: 0}),
Expand Down Expand Up @@ -183,6 +185,7 @@ export default class MDCSelectFoundation extends MDCFoundation {
}

open_() {
this.disableScroll_();
const {OPEN} = MDCSelectFoundation.cssClasses;
const focusIndex = this.selectedIndex_ < 0 ? 0 : this.selectedIndex_;

Expand Down Expand Up @@ -220,6 +223,7 @@ export default class MDCSelectFoundation extends MDCFoundation {
const {OPEN} = MDCSelectFoundation.cssClasses;
this.adapter_.removeClass(OPEN);
this.adapter_.focus();
this.enableScroll_();
}

handleDisplayViaKeyboard_(evt) {
Expand All @@ -243,5 +247,13 @@ export default class MDCSelectFoundation extends MDCFoundation {
this.displayHandler_(evt);
}
}

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

enableScroll_() {
this.adapter_.removeBodyClass(cssClasses.SCROLL_LOCK);
}
}

2 changes: 2 additions & 0 deletions packages/mdc-select/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export class MDCSelect extends MDCComponent {
deregisterMenuInteractionHandler: (type, handler) => this.menu_.unlisten(type, handler),
notifyChange: () => this.emit(MDCSelectFoundation.strings.CHANGE_EVENT, this),
getWindowInnerHeight: () => window.innerHeight,
addBodyClass: (className) => document.body.classList.add(className),
removeBodyClass: (className) => document.body.classList.remove(className),
});
}

Expand Down
4 changes: 4 additions & 0 deletions packages/mdc-select/mdc-select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,7 @@
// with CSS. Use the font-size rule instead.

// postcss-bem-linter: end

.mdc-select-scroll-lock {
overflow: hidden;
}
2 changes: 1 addition & 1 deletion test/unit/mdc-select/foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ test('default adapter returns a complete adapter implementation', () => {
'isMenuOpen', 'setSelectedTextContent', 'getNumberOfOptions', 'getTextForOptionAtIndex',
'setAttrForOptionAtIndex', 'rmAttrForOptionAtIndex', 'getOffsetTopForOptionAtIndex',
'registerMenuInteractionHandler', 'deregisterMenuInteractionHandler', 'notifyChange',
'getWindowInnerHeight', 'getValueForOptionAtIndex',
'getWindowInnerHeight', 'getValueForOptionAtIndex', 'addBodyClass', 'removeBodyClass',
]);

const renderingContext = MDCSelectFoundation.defaultAdapter.create2dRenderingContext();
Expand Down
15 changes: 15 additions & 0 deletions test/unit/mdc-select/mdc-select.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,18 @@ test('adapter#getValueForOptionAtIndex returns the textContent of the option at
const {component} = setupTest();
assert.equal(component.getDefaultFoundation().adapter_.getValueForOptionAtIndex(3), 'Item 4 no id');
});

test('adapter#addBodyClass adds a class to the body', () => {
const {component} = setupTest();
component.getDefaultFoundation().adapter_.addBodyClass('mdc-select-scroll-lock');
assert.isOk(document.querySelector('body').classList.contains('mdc-select-scroll-lock'));
});

test('adapter#removeBodyClass remove a class from the body', () => {
const {component} = setupTest();
const body = document.querySelector('body');

body.classList.add('mdc-select-scroll-lock');
component.getDefaultFoundation().adapter_.removeBodyClass('mdc-select-scroll-lock');
assert.isNotOk(body.classList.contains('mdc-select-scroll-lock'));
});

0 comments on commit bddd747

Please sign in to comment.