Skip to content

Commit

Permalink
feat(select): Initial Implementation
Browse files Browse the repository at this point in the history
* Remove restriction on menu roles. Simply look for any `mdl-list-item`
  with a `role` attribute when querying for menu items.
* Implement select UI with MDL simple menu.
* Implement Pure CSS version on top of browser's select element
* Bump up karma timeouts in a blind effort to decrease TravisCI
  flakiness

NOTE: Auto-positioning the select menu still needs to be done.

Part of #4475
[Delivers #126819221]
  • Loading branch information
traviskaufman committed Nov 16, 2016
1 parent db5544b commit 7c614b5
Show file tree
Hide file tree
Showing 21 changed files with 1,803 additions and 57 deletions.
1 change: 1 addition & 0 deletions demos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<li><a href="fab.html">FAB</a></li>
<li><a href="icon-toggle.html">Icon Toggle</a></li>
<li><a href="list.html">List</a></li>
<li><a href="select.html">Select</a></li>
<li><a href="simple-menu.html">Menu (simple)</a></li>
<li><a href="radio.html">Radio</a></li>
<li><a href="ripple.html">Ripple</a></li>
Expand Down
143 changes: 143 additions & 0 deletions demos/select.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<!DOCTYPE html>
<!--
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
https://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.
See the License for the specific language governing permissions and
limitations under the License
-->
<html class="mdl-typography">
<head>
<meta charset="utf-8">
<title>MDL Select Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="assets/material-design-lite.css.js" charset="utf-8"></script>
<style type="text/css">
.mdl-theme--dark {
background-color: #303030;
}

#demo-wrapper {
padding: 4px;
padding-left: 0;
}

/* Hack to work around style-loader asynchronously loading styles. */
/* Equivalent to using mdl-typography's subheading2, which is used in the sass file. */
.mdl-select {
font-family: Roboto, sans-serif;
font-size: 1rem;
font-weight: 400;
letter-spacing: .04em;
}
</style>
</head>
<body>
<main>
<h1>MDL select</h1>
<section>
<h2>Fully-Featured Component</h2>
<section id="demo-wrapper">
<div id="js-select" class="mdl-select" role="listbox" tabindex="0">
<span class="mdl-select__selected-text">Pick a food group</span>
<div class="mdl-simple-menu mdl-select__menu">
<ul class="mdl-list mdl-simple-menu__items">
<li class="mdl-list-item" role="option" id="grains" tabindex="0">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdl-list-item" role="option" id="vegetables" tabindex="0">
Vegetables
</li>
<li class="mdl-list-item" role="option" id="fruit" tabindex="0">
Fruit
</li>
<li class="mdl-list-item" role="option" id="dairy" tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdl-list-item" role="option" id="meat" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdl-list-item" role="option" id="fats" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
</section>
<p>Currently selected: <span id="currently-selected">(none)</span></p>
<div>
<input type="checkbox" id="dark-theme">
<label for="dark-mode">Dark Theme</label>
</div>
<div>
<input type="checkbox" id="rtl">
<label for="rtl">RTL</label>
</div>
<div>
<input type="checkbox" id="disabled">
<label for="disabled">Disabled</label>
</div>
</section>
<section>
<h2>CSS Only</h2>
<select class="mdl-select">
<option value="" default selected>Pick a food group</option>
<option value="grains">Bread, Cereal, Rice, and Pasta</option>
<option value="vegetables">Vegetables</option>
<option value="fruit">Fruit</option>
<option value="dairy">Milk, Yogurt, and Cheese</option>
<option value="meat">Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts</option>
<option value="fats">Fats, Oils, and Sweets</option>
</select>
</section>
<section>
<h2>Custom Menu + Native Menu on mobile</h2>
<em>
TODO: Present both, maybe have a wrapper element that switches between both and
keeps them in sync?
</em>
</section>
</main>
<script src="assets/material-design-lite.js"></script>
<script>
(function() {
var MDLSelect = mdl.select.MDLSelect;
var root = document.getElementById('js-select');
var currentlySelected = document.getElementById('currently-selected');
var select = MDLSelect.attachTo(root);
root.addEventListener('MDLSelect:change', function() {
var item = select.selectedOptions[0];
var index = select.selectedIndex;
currentlySelected.textContent = '"' + item.textContent + '" at index ' + index;
});

var demoWrapper = document.getElementById('demo-wrapper');
var darkThemeCb = document.getElementById('dark-theme');
var rtlCb = document.getElementById('rtl');
var disabledCb = document.getElementById('disabled');

darkThemeCb.addEventListener('change', function() {
demoWrapper.classList[darkThemeCb.checked ? 'add' : 'remove']('mdl-theme--dark');
});
rtlCb.addEventListener('change', function() {
if (rtlCb.checked) {
demoWrapper.setAttribute('dir', 'rtl');
} else {
demoWrapper.removeAttribute('dir');
}
});
disabledCb.addEventListener('change', function() {
select.disabled = disabledCb.checked;
});
})();
</script>
</body>
</html>
6 changes: 3 additions & 3 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ module.exports = function(config) {
colors: true,
logLevel: config.LOG_INFO,
browsers: determineBrowsers(),
browserDisconnectTimeout: 20000,
browserNoActivityTimeout: 240000,
captureTimeout: 120000,
browserDisconnectTimeout: 40000,
browserNoActivityTimeout: 480000,
captureTimeout: 240000,
concurrency: USING_SL ? 4 : Infinity,
customLaunchers: SL_LAUNCHERS,

Expand Down
3 changes: 3 additions & 0 deletions packages/material-design-lite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as drawer from 'mdl-drawer';
import * as textfield from 'mdl-textfield';
import * as snackbar from 'mdl-snackbar';
import * as menu from 'mdl-menu';
import * as select from 'mdl-select';
import autoInit from 'mdl-auto-init';

// Register all components
Expand All @@ -34,6 +35,7 @@ autoInit.register('MDLRadio', radio.MDLRadio);
autoInit.register('MDLSnackbar', snackbar.MDLSnackbar);
autoInit.register('MDLTextfield', textfield.MDLTextfield);
autoInit.register('MDLSimpleMenu', menu.MDLSimpleMenu);
autoInit.register('MDLSelect', select.MDLSelect);

// Export all components.
export {
Expand All @@ -46,5 +48,6 @@ export {
drawer,
textfield,
menu,
select,
autoInit
};
1 change: 1 addition & 0 deletions packages/material-design-lite/material-design-lite.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@import "mdl-menu/mdl-menu";
@import "mdl-radio/mdl-radio";
@import "mdl-ripple/mdl-ripple";
@import "mdl-select/mdl-select";
@import "mdl-snackbar/mdl-snackbar";
@import "mdl-textfield/mdl-textfield";
@import "mdl-theme/mdl-theme";
Expand Down
1 change: 1 addition & 0 deletions packages/material-design-lite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"mdl-menu": "^1.0.0",
"mdl-radio": "^1.0.0",
"mdl-ripple": "^1.0.0",
"mdl-select": "^1.0.0",
"mdl-snackbar": "^1.0.0",
"mdl-textfield": "^1.0.0",
"mdl-theme": "^1.0.0",
Expand Down
7 changes: 1 addition & 6 deletions packages/mdl-menu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ A simple menu is usually closed, appearing when opened. It is appropriate for an
focused instead, remove `tabindex="-1"` from the root element.

```js
let menu = new mdl.SimpleMenu(document.querySelector('.mdl-simple-menu'));
let menu = new mdl.menu.SimpleMenu(document.querySelector('.mdl-simple-menu'));
// Add event listener to some button to toggle the menu on and off.
document.querySelector('.some-button').addEventListener('click', () => menu.open = !menu.open);
```
Expand Down Expand Up @@ -109,11 +109,6 @@ classes:

### Using the JS Component

> **N.B.**: The use of `role` on both the menu's internal items list, as well as on each item, is
> _mandatory_. You may either use the role of `menu` on the list with a role of `menuitem` on each
> list item, or a role of `listbox` on the list with a role of `option` on each list item. Further
> composite roles may be supported in the future.
MDL Simple Menu ships with a Component / Foundation combo which allows for frameworks to richly integrate the
correct menu behaviors into idiomatic components.

Expand Down
10 changes: 0 additions & 10 deletions packages/mdl-menu/simple/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,3 @@ export const numbers = {
TRANSITION_X2: 0.2,
TRANSITION_Y2: 1
};

// Mapping between composite aria roles supported by the simple menu to roles owned
// by that composite role. This should be used in order to query for DOM elements within
// the menu that represent actual menu items, e.g. `[role="menuitem"]` for a simple menu with
// role="menu", or `[role="option"]` for a simple menu with role="listbox". For more information
// see https://www.w3.org/TR/wai-aria/roles#composite.
export const PARENT_CHILD_ROLES = {
menu: 'menuitem',
listbox: 'option'
};
10 changes: 7 additions & 3 deletions packages/mdl-menu/simple/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export default class MDLSimpleMenuFoundation extends MDLFoundation {
const isTab = key === 'Tab' || keyCode === 9;
const isArrowUp = key === 'ArrowUp' || keyCode === 38;
const isArrowDown = key === 'ArrowDown' || keyCode === 40;
const isSpace = key === 'Space' || keyCode === 32;

const focusedItemIndex = this.adapter_.getFocusedItemIndex();
const lastItemIndex = this.adapter_.getNumberOfItems() - 1;
Expand All @@ -247,15 +248,18 @@ export default class MDLSimpleMenuFoundation extends MDLFoundation {
return false;
}

// Ensure Arrow{Up,Down} and space do not cause inadvertent scrolling
if (isArrowUp || isArrowDown || isSpace) {
evt.preventDefault();
}

if (isArrowUp) {
if (focusedItemIndex === 0 || this.adapter_.isFocused()) {
this.adapter_.focusItemAtIndex(lastItemIndex);
} else {
this.adapter_.focusItemAtIndex(focusedItemIndex - 1);
}
}

if (isArrowDown) {
} else if (isArrowDown) {
if (focusedItemIndex === lastItemIndex || this.adapter_.isFocused()) {
this.adapter_.focusItemAtIndex(0);
} else {
Expand Down
22 changes: 1 addition & 21 deletions packages/mdl-menu/simple/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import {MDLComponent} from 'mdl-base';
import {PARENT_CHILD_ROLES} from './constants';
import MDLSimpleMenuFoundation from './foundation';
import {getTransformPropertyName} from '../util';

Expand Down Expand Up @@ -57,8 +56,7 @@ export class MDLSimpleMenu extends MDLComponent {
*/
get items() {
const {itemsContainer_: itemsContainer} = this;
const childRole = PARENT_CHILD_ROLES[itemsContainer.getAttribute('role')];
return [].slice.call(itemsContainer.querySelectorAll(`[role="${childRole}"]`));
return [].slice.call(itemsContainer.querySelectorAll('.mdl-list-item[role]'));
}

getDefaultFoundation() {
Expand Down Expand Up @@ -123,22 +121,4 @@ export class MDLSimpleMenu extends MDLComponent {
}
});
}

initialSyncWithDOM() {
this.validateRole_();
}

validateRole_() {
const VALID_ROLES = Object.keys(PARENT_CHILD_ROLES);
const role = this.itemsContainer_.getAttribute('role');
if (!role) {
throw new Error(
'Missing "role" attribute on menu items list element. A "role" attribute is needed for the menu to ' +
`function properly. Please choose one of ${VALID_ROLES}`
);
}
if (VALID_ROLES.indexOf(role) < 0) {
throw new Error(`Invalid menu items list role "${role}." Please choose one of ${VALID_ROLES}`);
}
}
}
Loading

0 comments on commit 7c614b5

Please sign in to comment.